Maintain scroll position when re-inserting #conversejs element
This commit is contained in:
parent
867f80e95e
commit
4927d561a5
@ -176,6 +176,10 @@ converse.plugins.add('converse-chatboxviews', {
|
||||
const el = _converse.chatboxviews?.el;
|
||||
if (el && !container.contains(el)) {
|
||||
container.insertAdjacentElement('afterBegin', el);
|
||||
api.chatviews.get()
|
||||
.filter(v => v.model.get('id') !== 'controlbox')
|
||||
.forEach(v => v.maintainScrollTop());
|
||||
|
||||
} else if (!el) {
|
||||
throw new Error("Cannot insert non-existing #conversejs element into the DOM");
|
||||
}
|
||||
|
@ -208,7 +208,7 @@ converse.plugins.add('converse-chatview', {
|
||||
this.listenTo(this.model.messages, 'add', this.onMessageAdded);
|
||||
this.listenTo(this.model.messages, 'change', this.renderChatHistory);
|
||||
this.listenTo(this.model.messages, 'remove', this.renderChatHistory);
|
||||
this.listenTo(this.model.messages, 'rendered', this.maybeScrollDownOnMessage);
|
||||
this.listenTo(this.model.messages, 'rendered', this.maybeScrollDown);
|
||||
this.listenTo(this.model.messages, 'reset', this.renderChatHistory);
|
||||
this.listenTo(this.model.notifications, 'change', this.renderNotifications);
|
||||
this.listenTo(this.model, 'change:show_help_messages', this.renderHelpMessages);
|
||||
@ -241,7 +241,7 @@ converse.plugins.add('converse-chatview', {
|
||||
|
||||
render () {
|
||||
const result = tpl_chatbox(
|
||||
Object.assign(this.model.toJSON(), {'markScrolled': () => this.markScrolled()})
|
||||
Object.assign(this.model.toJSON(), {'markScrolled': ev => this.markScrolled(ev)})
|
||||
);
|
||||
render(result, this.el);
|
||||
this.content = this.el.querySelector('.chat-content');
|
||||
@ -486,19 +486,35 @@ converse.plugins.add('converse-chatview', {
|
||||
api.trigger('afterMessagesFetched', this.model);
|
||||
},
|
||||
|
||||
maybeScrollDownOnMessage (message) {
|
||||
if (message.get('sender') === 'me' || !this.model.get('scrolled')) {
|
||||
/**
|
||||
* Scrolls the chat down, *if* appropriate.
|
||||
*
|
||||
* Will only scroll down if we have received a message from
|
||||
* ourselves, or if the chat was scrolled down before (i.e. the
|
||||
* `scrolled` flag is `false`);
|
||||
* @param { _converse.Message|_converse.ChatRoomMessage } [message]
|
||||
* - An optional message that serves as the cause for needing to scroll down.
|
||||
*/
|
||||
maybeScrollDown (message) {
|
||||
if (message?.get('sender') === 'me' || !this.model.get('scrolled')) {
|
||||
this.debouncedScrollDown();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Scrolls the chat down.
|
||||
*
|
||||
* This method will always scroll the chat down, regardless of
|
||||
* whether the user scrolled up manually or not.
|
||||
* @param { Event } [ev] - An optional event that is the cause for needing to scroll down.
|
||||
*/
|
||||
scrollDown (ev) {
|
||||
ev?.preventDefault?.();
|
||||
ev?.stopPropagation?.();
|
||||
if (this.model.get('scrolled')) {
|
||||
u.safeSave(this.model, {
|
||||
'scrolled': false,
|
||||
'top_visible_message': null,
|
||||
'scrollTop': null,
|
||||
});
|
||||
}
|
||||
if (this.msgs_container.scrollTo) {
|
||||
@ -510,6 +526,19 @@ converse.plugins.add('converse-chatview', {
|
||||
this.onScrolledDown();
|
||||
},
|
||||
|
||||
/**
|
||||
* Scroll to the previously saved scrollTop position, or scroll
|
||||
* down if it wasn't set.
|
||||
*/
|
||||
maintainScrollTop () {
|
||||
const pos = this.model.get('scrollTop');
|
||||
if (pos) {
|
||||
this.msgs_container.scrollTop = pos;
|
||||
} else {
|
||||
this.scrollDown();
|
||||
}
|
||||
},
|
||||
|
||||
insertIntoDOM () {
|
||||
_converse.chatboxviews.insertRowColumn(this.el);
|
||||
/**
|
||||
@ -537,28 +566,6 @@ converse.plugins.add('converse-chatview', {
|
||||
this.content.querySelectorAll('.spinner').forEach(u.removeElement);
|
||||
},
|
||||
|
||||
setScrollPosition (message_el) {
|
||||
/* Given a newly inserted message, determine whether we
|
||||
* should keep the scrollbar in place (so as to not scroll
|
||||
* up when using infinite scroll).
|
||||
*/
|
||||
if (this.model.get('scrolled')) {
|
||||
const next_msg_el = u.getNextElement(message_el, ".chat-msg");
|
||||
if (next_msg_el) {
|
||||
// The currently received message is not new, there
|
||||
// are newer messages after it. So let's see if we
|
||||
// should maintain our current scroll position.
|
||||
if (this.content.scrollTop === 0 || this.model.get('top_visible_message')) {
|
||||
const top_visible_message = this.model.get('top_visible_message') || next_msg_el;
|
||||
this.model.set('top_visible_message', top_visible_message);
|
||||
this.content.scrollTop = top_visible_message.offsetTop - 30;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
this.scrollDown();
|
||||
}
|
||||
},
|
||||
|
||||
onStatusMessageChanged (item) {
|
||||
this.renderHeading();
|
||||
/**
|
||||
@ -1091,8 +1098,9 @@ converse.plugins.add('converse-chatview', {
|
||||
* which debounces this method by 100ms.
|
||||
* @private
|
||||
*/
|
||||
_markScrolled: function () {
|
||||
_markScrolled: function (ev) {
|
||||
let scrolled = true;
|
||||
let scrollTop = null;
|
||||
const is_at_bottom =
|
||||
(this.msgs_container.scrollTop + this.msgs_container.clientHeight) >=
|
||||
this.msgs_container.scrollHeight - 62; // sigh...
|
||||
@ -1108,15 +1116,14 @@ converse.plugins.add('converse-chatview', {
|
||||
* @example _converse.api.listen.on('chatBoxScrolledUp', obj => { ... });
|
||||
*/
|
||||
api.trigger('chatBoxScrolledUp', this);
|
||||
} else {
|
||||
scrollTop = ev.target.scrollTop;
|
||||
}
|
||||
u.safeSave(this.model, {
|
||||
'scrolled': scrolled,
|
||||
'top_visible_message': null
|
||||
});
|
||||
u.safeSave(this.model, { scrolled, scrollTop });
|
||||
},
|
||||
|
||||
viewUnreadMessages () {
|
||||
this.model.save({'scrolled': false, 'top_visible_message': null});
|
||||
this.model.save({'scrolled': false, 'scrollTop': null});
|
||||
this.scrollDown();
|
||||
},
|
||||
|
||||
|
@ -190,7 +190,7 @@ converse.plugins.add('converse-muc-views', {
|
||||
this.listenTo(this.model, 'show', this.show);
|
||||
this.listenTo(this.model.features, 'change:moderated', this.renderBottomPanel);
|
||||
this.listenTo(this.model.features, 'change:open', this.renderHeading);
|
||||
this.listenTo(this.model.messages, 'rendered', this.maybeScrollDownOnMessage);
|
||||
this.listenTo(this.model.messages, 'rendered', this.maybeScrollDown);
|
||||
this.listenTo(this.model.session, 'change:connection_status', this.onConnectionStatusChanged);
|
||||
|
||||
// Bind so that we can pass it to addEventListener and removeEventListener
|
||||
|
@ -168,12 +168,12 @@ class MessageBodyRenderer {
|
||||
// image loads, it triggers 'scroll' and the chat will be marked as scrolled,
|
||||
// which is technically true, but not what we want because the user
|
||||
// didn't initiate the scrolling.
|
||||
this.scrolled = this.chatview.model.get('scrolled');
|
||||
this.was_scrolled_up = this.chatview.model.get('scrolled');
|
||||
this.text = this.component.model.getMessageText();
|
||||
}
|
||||
|
||||
scrollDownOnImageLoad () {
|
||||
if (!this.scrolled) {
|
||||
if (!this.was_scrolled_up) {
|
||||
this.chatview.scrollDown();
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user