From ea97fa3ac6f51eb982d97812a6082616fff6e167 Mon Sep 17 00:00:00 2001 From: dbh Date: Mon, 5 Feb 2018 15:27:21 +0530 Subject: [PATCH] [IMP] mail: Discuss: load older messages automatically After this rev., in Discuss, messages are automatically loaded when the user scrolls to the top of the channel. Task 33958 Co-authored-by: Aaron Bohy --- addons/mail/static/src/js/discuss.js | 28 +++++++- addons/mail/static/src/js/thread.js | 2 + addons/mail/static/src/xml/thread.xml | 9 ++- addons/mail/static/tests/discuss_tests.js | 82 +++++++++++++++++++++++ 4 files changed, 117 insertions(+), 4 deletions(-) diff --git a/addons/mail/static/src/js/discuss.js b/addons/mail/static/src/js/discuss.js index f70cec0116c..7f297f76298 100644 --- a/addons/mail/static/src/js/discuss.js +++ b/addons/mail/static/src/js/discuss.js @@ -184,6 +184,11 @@ var Discuss = AbstractAction.extend(ControlPanelMixin, { .then(function () { self._startListening(); self.thread.$el.on("scroll", null, _.debounce(function () { + if (self.thread.get_scrolltop() < 20 && + !self.thread.$('.o_mail_no_content').length && + !self.call('chat_manager', 'isAllHistoryLoaded', self.channel, self.domain)) { + self._loadMoreMessages(); + } if (self.thread.is_at_bottom()) { self.call('chat_manager', 'markChannelAsSeen', self.channel); } @@ -218,6 +223,7 @@ var Discuss = AbstractAction.extend(ControlPanelMixin, { if (this.channel) { this.thread.scroll_to({offset: this.channelsScrolltop[this.channel.id]}); } + this._loadEnoughMessages(); }, /** * @override @@ -243,6 +249,7 @@ var Discuss = AbstractAction.extend(ControlPanelMixin, { }).then(function (messages) { self.thread.render(messages, self._getThreadRenderingOptions(messages)); self._updateButtonStatus(messages.length === 0); + return self._loadEnoughMessages(); }); }, /** @@ -274,6 +281,23 @@ var Discuss = AbstractAction.extend(ControlPanelMixin, { display_reply_icon: true, }; }, + /** + * Ensures that enough messages have been loaded to fill the entire screen + * (this is particularily important because remaining messages can only be + * loaded when scrolling to the top, so they can't be loaded if there is no + * scrollbar) + * + * @returns {Deferred} resolved when there are enough messages to fill the + * screen, or when there is no more message to fetch + */ + _loadEnoughMessages: function () { + var loadMoreMessages = this.thread.el.clientHeight && + this.thread.el.clientHeight === this.thread.el.scrollHeight && + !this.call('chat_manager', 'isAllHistoryLoaded', this.channel, this.domain); + if (loadMoreMessages) { + return this._loadMoreMessages().then(this._loadEnoughMessages.bind(this)); + } + }, /** * Load more messages for the current thread * @@ -429,7 +453,7 @@ var Discuss = AbstractAction.extend(ControlPanelMixin, { */ _renderThread: function () { var self = this; - this.thread = new ChatThread(this, {display_help: true}); + this.thread = new ChatThread(this, {display_help: true, loadMoreOnScroll: true}); this.thread.on('redirect', this, function (resModel, resID) { self.call('chat_manager', 'redirect', resModel, resID, self._setChannel.bind(self)); @@ -615,7 +639,7 @@ var Discuss = AbstractAction.extend(ControlPanelMixin, { */ _unselectMessage: function () { this.basicComposer.do_toggle(this.channel.type !== 'static' && !this.channel.mass_mailing); - this.extendedComposer.do_toggle(this.channel.type !== 'static' && this.channel.mass_mailing); + this.extendedComposer.do_toggle(this.channel.type !== 'static' && !!this.channel.mass_mailing); if (!config.device.touch) { var composer = this.channel.mass_mailing ? this.extendedComposer : this.basicComposer; diff --git a/addons/mail/static/src/js/thread.js b/addons/mail/static/src/js/thread.js index 97b6bf4906f..8e08ecfa73a 100644 --- a/addons/mail/static/src/js/thread.js +++ b/addons/mail/static/src/js/thread.js @@ -83,6 +83,7 @@ var Thread = Widget.extend({ squash_close_messages: true, display_email_icon: true, display_reply_icon: false, + loadMoreOnScroll: false, }); this.disabledOptions = { display_order: this.enabledOptions.display_order, @@ -93,6 +94,7 @@ var Thread = Widget.extend({ squash_close_messages: false, display_email_icon: false, display_reply_icon: false, + loadMoreOnScroll: this.enabledOptions.loadMoreOnScroll, }; this.expanded_msg_ids = []; this.selected_id = null; diff --git a/addons/mail/static/src/xml/thread.xml b/addons/mail/static/src/xml/thread.xml index e1c0b843482..803e7d6563b 100644 --- a/addons/mail/static/src/xml/thread.xml +++ b/addons/mail/static/src/xml/thread.xml @@ -332,8 +332,13 @@ -
- +
+ + Loading older messages... + + + +
diff --git a/addons/mail/static/tests/discuss_tests.js b/addons/mail/static/tests/discuss_tests.js index 6990a04efba..862b643abb4 100644 --- a/addons/mail/static/tests/discuss_tests.js +++ b/addons/mail/static/tests/discuss_tests.js @@ -293,5 +293,87 @@ QUnit.test('no crash focusout emoji button', function (assert) { }); }); +QUnit.test('older messages are loaded on scroll', function (assert) { + assert.expect(4); + var done = assert.async(); + + // remove throttling + testUtils.patch(BasicComposer, {MENTION_THROTTLE: 0}); + testUtils.patch(ChatManager, {CHANNEL_SEEN_THROTTLE: 0}); + + this.data.initMessaging = { + channel_slots: { + channel_channel: [{ + id: 1, + channel_type: "channel", + name: "general", + static: true, + }], + }, + }; + + var limit; + var loadDef = $.Deferred(); + var loadedMessages; + var msgData = []; + for (var i = 0; i < 35; i++) { + msgData.push({ + author_id: ['1', 'Me'], + body: '

test ' + i + '

', + channel_ids: [1], + id: i, + }); + } + msgData.reverse(); + + createDiscuss({ + context: {}, + data: this.data, + params: {}, + services: [ChatManager, createBusService()], + mockRPC: function (route, args) { + if (args.method === 'message_fetch') { + limit = args.kwargs.limit; + loadedMessages += limit; + var message = msgData.slice(0, loadedMessages); + if (loadedMessages >= msgData.length) { + loadDef.resolve(); + } + return $.when(message); + } + return this._super.apply(this, arguments); + }, + }).then(function (discuss) { + var $general = discuss.$('.o_mail_chat_channel_item[data-channel-id=1]'); + assert.strictEqual($general.length, 1, + "should have a channel item with id 1"); + + // switch to 'general' + loadedMessages = 0; + $general.click(); + + assert.ok(limit < 35, "there should be more messages than the limit"); + assert.strictEqual(discuss.$('.o_thread_message').length, limit, + "should display the 'limit' first messages"); + + // simulate a scroll to top to load more messages + discuss.$('.o_mail_thread').scrollTop(0); + + loadDef + .then(concurrency.delay.bind(concurrency, 0)) + .then(function () { + assert.strictEqual(discuss.$('.o_thread_message').length, 35, + "all messages should now be loaded"); + + // restore throttling + testUtils.unpatch(BasicComposer); + testUtils.unpatch(ChatManager); + + discuss.destroy(); + done(); + }); + }); +}); + }); });