[FIX] mail: chatter autoloading loads more messages too quickly

if you check on any chatter with a lot of messages, you will see that it starts
loading all the messages as soon as you scroll down even just 1 pixel.
This makes a lot of loading of the messages for no reason unnecessarily.
What should happen instead is that it should load more message only when
scrolling all the way down to the bottom.This works fine in chatwindow & discuss.

With this commit, resolved this issue by providing the exact scrollable element
to the message list from parent component to the child. so with proper element
we can have proper scrollable heights and other dimensions as well to handle
load more messages properly.

Task : 2382735

closes odoo/odoo#68430

X-original-commit: 63b15e23d95b310a12bdbc30c983081ed84187a3
Related: odoo/enterprise#17335
Signed-off-by: Sébastien Theys (seb) <seb@odoo.com>
This commit is contained in:
Dhruv Patel
2021-03-26 20:34:16 +00:00
committed by Sébastien Theys
parent a86382ffa2
commit 0faeb2b769
5 changed files with 65 additions and 19 deletions
@@ -47,10 +47,16 @@ class Chatter extends Component {
* Reference of the composer. Useful to focus it.
*/
this._composerRef = useRef('composer');
/**
* Reference of the scroll Panel (Real scroll element). Useful to pass the Scroll element to
* child component to handle proper scrollable element.
*/
this._scrollPanelRef = useRef('scrollPanel');
/**
* Reference of the message list. Useful to trigger the scroll event on it.
*/
this._threadRef = useRef('thread');
this.getScrollableElement = this.getScrollableElement.bind(this);
}
//--------------------------------------------------------------------------
@@ -64,6 +70,16 @@ class Chatter extends Component {
return this.env.models['mail.chatter'].get(this.props.chatterLocalId);
}
/**
* @returns {Element|undefined} Scrollable Element
*/
getScrollableElement() {
if (!this._scrollPanelRef.el) {
return;
}
return this._scrollPanelRef.el;
}
//--------------------------------------------------------------------------
// Private
//--------------------------------------------------------------------------
@@ -24,7 +24,7 @@
/>
</t>
</div>
<div class="o_Chatter_scrollPanel" t-on-scroll="_onScrollPanelScroll">
<div class="o_Chatter_scrollPanel" t-on-scroll="_onScrollPanelScroll" t-ref="scrollPanel">
<t t-if="chatter.isAttachmentBoxVisible">
<AttachmentBox
class="o_Chatter_attachmentBox"
@@ -40,6 +40,7 @@
<t t-if="chatter.threadView">
<ThreadView
class="o_Chatter_thread"
getScrollableElement="getScrollableElement"
hasComposer="false"
hasScrollAdjust="chatter.hasMessageListScrollAdjust"
order="'desc'"
@@ -100,8 +100,8 @@ class MessageList extends Component {
isLastMessageVisible:
lastMessageRef &&
lastMessageRef.isBottomVisible({ offset: 10 }),
scrollHeight: this.el.scrollHeight,
scrollTop: this.el.scrollTop,
scrollHeight: this._getScrollableElement().scrollHeight,
scrollTop: this._getScrollableElement().scrollTop,
};
}
@@ -190,14 +190,14 @@ class MessageList extends Component {
* @returns {integer}
*/
getScrollHeight() {
return this.el.scrollHeight;
return this._getScrollableElement().scrollHeight;
}
/**
* @returns {integer}
*/
getScrollTop() {
return this.el.scrollTop;
return this._getScrollableElement().scrollTop;
}
/**
@@ -278,11 +278,11 @@ class MessageList extends Component {
* @param {integer} value
*/
setScrollTop(value) {
if (this.el.scrollTop === value) {
if (this._getScrollableElement().scrollTop === value) {
return;
}
this._isLastScrollProgrammatic = true;
this.el.scrollTop = value;
this._getScrollableElement().scrollTop = value;
}
/**
@@ -356,13 +356,13 @@ class MessageList extends Component {
hasScrollAdjust,
order,
} = this._lastRenderedValues();
if (!this.el || !hasScrollAdjust) {
if (!this._getScrollableElement() || !hasScrollAdjust) {
return;
}
if (!hasAutoScrollOnMessageReceived) {
if (order === 'desc' && this._willPatchSnapshot) {
const { scrollHeight, scrollTop } = this._willPatchSnapshot;
this.setScrollTop(this.el.scrollHeight - scrollHeight + scrollTop);
this.setScrollTop(this._getScrollableElement().scrollHeight - scrollHeight + scrollTop);
}
return;
}
@@ -378,7 +378,7 @@ class MessageList extends Component {
order,
} = this._lastRenderedValues();
if (
!this.el ||
!this._getScrollableElement() ||
!hasScrollAdjust ||
!this._willPatchSnapshot ||
order === 'desc'
@@ -386,7 +386,7 @@ class MessageList extends Component {
return;
}
const { scrollHeight, scrollTop } = this._willPatchSnapshot;
this.setScrollTop(this.el.scrollHeight - scrollHeight + scrollTop);
this.setScrollTop(this._getScrollableElement().scrollHeight - scrollHeight + scrollTop);
}
/**
@@ -398,12 +398,12 @@ class MessageList extends Component {
threadCacheInitialScrollHeight,
threadCacheInitialScrollPosition,
} = this._lastRenderedValues();
if (!this.el || !hasScrollAdjust) {
if (!this._getScrollableElement() || !hasScrollAdjust) {
return;
}
if (
threadCacheInitialScrollPosition !== undefined &&
this.el.scrollHeight === threadCacheInitialScrollHeight
this._getScrollableElement().scrollHeight === threadCacheInitialScrollHeight
) {
this.setScrollTop(threadCacheInitialScrollPosition);
return;
@@ -434,6 +434,18 @@ class MessageList extends Component {
}
}
/**
* @private
* @returns {Element|undefined} Scrollable Element
*/
_getScrollableElement() {
if (this.props.getScrollableElement) {
return this.props.getScrollableElement();
} else {
return this.el;
}
}
/**
* @private
* @returns {boolean}
@@ -444,7 +456,7 @@ class MessageList extends Component {
return false;
}
const loadMoreRect = loadMore.getBoundingClientRect();
const elRect = this.el.getBoundingClientRect();
const elRect = this._getScrollableElement().getBoundingClientRect();
const isInvisible = loadMoreRect.top > elRect.bottom || loadMoreRect.bottom < elRect.top;
return !isInvisible;
}
@@ -467,7 +479,7 @@ class MessageList extends Component {
*/
_scrollToEnd() {
const { order } = this._lastRenderedValues();
this.setScrollTop(order === 'asc' ? this.el.scrollHeight - this.el.clientHeight : 0);
this.setScrollTop(order === 'asc' ? this._getScrollableElement().scrollHeight - this._getScrollableElement().clientHeight : 0);
}
/**
@@ -526,11 +538,11 @@ class MessageList extends Component {
threadView,
threadViewer,
} = this._lastRenderedValues();
if (!this.el) {
if (!this._getScrollableElement()) {
// could be unmounted in the meantime (due to throttled behavior)
return;
}
const scrollTop = this.el.scrollTop;
const scrollTop = this._getScrollableElement().scrollTop;
this.env.messagingBus.trigger('o-component-message-list-scrolled', {
orderedMessages,
scrollTop,
@@ -544,12 +556,12 @@ class MessageList extends Component {
// Automatically scroll to new received messages only when the list is
// currently fully scrolled.
const hasAutoScrollOnMessageReceived = (order === 'asc')
? scrollTop >= this.el.scrollHeight - this.el.clientHeight - margin
? scrollTop >= this._getScrollableElement().scrollHeight - this._getScrollableElement().clientHeight - margin
: scrollTop <= margin;
threadView.update({ hasAutoScrollOnMessageReceived });
}
if (threadViewer && threadViewer.exists()) {
threadViewer.saveThreadCacheScrollHeightAsInitial(this.el.scrollHeight, threadCache);
threadViewer.saveThreadCacheScrollHeightAsInitial(this._getScrollableElement().scrollHeight, threadCache);
threadViewer.saveThreadCacheScrollPositionsAsInitial(scrollTop, threadCache);
}
if (!this._isLastScrollProgrammatic && this._isLoadMoreVisible()) {
@@ -572,6 +584,14 @@ Object.assign(MessageList, {
order: 'asc',
},
props: {
/**
* Function returns the exact scrollable element from the parent
* to manage proper scroll heights which affects the load more messages.
*/
getScrollableElement: {
type: Function,
optional: true,
},
hasMessageCheckbox: Boolean,
hasSquashCloseMessages: Boolean,
haveMessagesMarkAsReadIcon: Boolean,
@@ -182,6 +182,14 @@ Object.assign(ThreadView, {
type: String,
validate: prop => ['auto', 'card', 'hover', 'none'].includes(prop),
},
/**
* Function returns the exact scrollable element from the parent
* to manage proper scroll heights which affects the load more messages.
*/
getScrollableElement: {
type: Function,
optional: true,
},
hasComposer: Boolean,
hasComposerCurrentPartnerAvatar: {
type: Boolean,
@@ -12,6 +12,7 @@
<t t-elif="threadView.threadCache.isLoaded or threadView.thread.isTemporary">
<MessageList
class="o_ThreadView_messageList"
getScrollableElement= "props.getScrollableElement"
hasMessageCheckbox="props.hasMessageCheckbox"
hasScrollAdjust="props.hasScrollAdjust"
hasSquashCloseMessages="props.hasSquashCloseMessages"