From 1a1fe233a51dcbebba6a0e307722bf48407b412f Mon Sep 17 00:00:00 2001 From: DorraJaouad Date: Thu, 25 Apr 2024 14:32:54 +0200 Subject: [PATCH] fix(MessagesList): handle special case when last read message is collapsed Signed-off-by: DorraJaouad --- src/components/MessagesList/MessagesList.vue | 20 ++++++++++++++------ src/store/messagesStore.js | 12 ++++++++++++ 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/src/components/MessagesList/MessagesList.vue b/src/components/MessagesList/MessagesList.vue index 8936409138c..b66b968407d 100644 --- a/src/components/MessagesList/MessagesList.vue +++ b/src/components/MessagesList/MessagesList.vue @@ -621,18 +621,21 @@ export default { } if (!isFocused) { - // Safeguard: scroll to before last read message + // Safeguard 1: scroll to first visible message before the read marker const fallbackLastReadMessageId = this.$store.getters.getFirstDisplayableMessageIdBeforeReadMarker(this.token, this.visualLastReadMessageId) if (fallbackLastReadMessageId) { isFocused = this.focusMessage(fallbackLastReadMessageId, false, false) + } + + if (!isFocused) { + // Safeguard 2: in case the fallback message is not found too + // scroll to bottom + this.scrollToBottom({ force: true }) + } else { this.$store.dispatch('setVisualLastReadMessageId', { token: this.token, id: fallbackLastReadMessageId, }) - } else { - // This is an ultimate safeguard in case the fallback message is not found too - // scroll to bottom - this.scrollToBottom({ force: true, smooth: true }) } } @@ -1083,7 +1086,7 @@ export default { * @return {boolean} true if element was found, false otherwise */ focusMessage(messageId, smooth = true, highlightAnimation = true) { - const element = document.getElementById(`message_${messageId}`) + let element = document.getElementById(`message_${messageId}`) if (!element) { // Message id doesn't exist // TODO: in some cases might need to trigger a scroll up if this is an older message @@ -1092,6 +1095,11 @@ export default { return false // element not found } + if (element.offsetParent === null) { + console.debug('Message to focus is hidden, scrolling to its nearest visible parent', messageId) + element = element.closest('ul[style="display: none;"]').parentElement + } + console.debug('Scrolling to a focused message programmatically') this.isFocusingMessage = true diff --git a/src/store/messagesStore.js b/src/store/messagesStore.js index 995b52f8d5d..470d2c28ceb 100644 --- a/src/store/messagesStore.js +++ b/src/store/messagesStore.js @@ -89,6 +89,17 @@ function hasMentionToSelf(context, message) { return false } +/** + * Returns whether the given message is presented in DOM and visible (none of the ancestors has `display: none`) + * + * @param {string} messageId store context + * @return {boolean} whether the message is visible in the UI + */ +function isMessageVisible(messageId) { + const element = document.getElementById(`message_${messageId}`) + return element !== null && element.offsetParent !== null +} + const state = { /** * Map of conversation token to message list @@ -243,6 +254,7 @@ const getters = { return getters.messagesList(token).findLast(message => { return message.id < readMessageId + && isMessageVisible(message.id) && !String(message.id).startsWith('temp-') && message.systemMessage !== 'reaction' && message.systemMessage !== 'reaction_deleted'