Skip to content

Commit

Permalink
chore: refactor scrolling to focused message
Browse files Browse the repository at this point in the history
* Last read message  (when opening the chat)
* Focuses message from URL (from Quote or Unified Search app)

Signed-off-by: DorraJaouad <dorra.jaoued7@gmail.com>
  • Loading branch information
DorraJaouad authored and Antreesy committed Mar 27, 2024
1 parent 2955434 commit 2b20dab
Showing 1 changed file with 26 additions and 74 deletions.
100 changes: 26 additions & 74 deletions src/components/MessagesList/MessagesList.vue
Original file line number Diff line number Diff line change
Expand Up @@ -165,11 +165,6 @@ export default {

isFocusingMessage: false,

/**
* Quick edit option to fall back to the loading history and then new messages
*/
loadChatInLegacyMode: getCapabilities()?.spreed?.config?.chat?.legacy || false,

destroying: false,

expirationInterval: null,
Expand Down Expand Up @@ -619,31 +614,23 @@ export default {
let isFocused = null
if (focusMessageId) {
// scroll to message in URL anchor
isFocused = this.focusMessage(focusMessageId, false)
isFocused = this.focusMessage(focusMessageId)
return
}

if (!isFocused && this.visualLastReadMessageId) {
if (this.visualLastReadMessageId) {
// scroll to last read message if visible in the current pages
isFocused = this.focusMessage(this.visualLastReadMessageId, false, false)
}

// TODO: in case the element is not in a page but does exist in the DB,
// we need to scroll up / down to the page where it would exist after
// loading said pages

if (!isFocused) {
// if no anchor was present or the message to focus on did not exist,
// This is a safeguard in case the message is not found
// scroll to bottom
this.scrollToBottom({ force: true })
this.scrollToBottom({ force: true, smooth: true })
}

// if no scrollbars, clear read marker directly as scrolling is not possible for the user to clear it
// also clear in case lastReadMessage is zero which is due to an older bug
if (this.visualLastReadMessageId === 0
|| (this.$refs.scroller && this.$refs.scroller.scrollHeight <= this.$refs.scroller.offsetHeight)) {
// clear after a delay, unless scrolling can resume in-between
this.debounceUpdateReadMarkerPosition()
}
// Update read marker in all cases except when the message is from URL anchor
this.debounceUpdateReadMarkerPosition()
},

async handleStartGettingMessagesPreconditions() {
Expand All @@ -661,7 +648,7 @@ export default {
if (this.$store.getters.getFirstKnownMessageId(this.token) === null) {
let startingMessageId = 0
// first time load, initialize important properties
if (this.loadChatInLegacyMode || focusMessageId === null) {
if (focusMessageId === null) {
// Start from unread marker
this.$store.dispatch('setFirstKnownMessageId', {
token: this.token,
Expand All @@ -685,53 +672,21 @@ export default {
})
}

if (this.loadChatInLegacyMode) {
// get history before last read message
await this.getOldMessages(true)
// at this stage, the read marker will appear at the bottom of the view port since
// we haven't fetched the messages that come after it yet
// TODO: should we still show a spinner at this stage ?

} else {
// Get chat messages before last read message and after it
await this.getMessageContext(startingMessageId)
const startingMessageFound = this.focusMessage(startingMessageId, false, focusMessageId !== null)

if (!startingMessageFound) {
const fallbackStartingMessageId = this.$store.getters.getFirstDisplayableMessageIdBeforeReadMarker(this.token, startingMessageId)
this.$store.dispatch('setVisualLastReadMessageId', {
token: this.token,
id: fallbackStartingMessageId,
})
this.focusMessage(fallbackStartingMessageId, false, false)
}
}
// Get chat messages before last read message and after it
await this.getMessageContext(startingMessageId)
}

let hasScrolled = false
if (this.loadChatInLegacyMode || focusMessageId === null) {
// if lookForNewMessages will long poll instead of returning existing messages,
// scroll right away to avoid delays
if (!this.hasMoreMessagesToLoad) {
hasScrolled = true
this.$nextTick(() => {
this.scrollToFocusedMessage()
})
}
}
this.$nextTick(() => {
// basically scrolling to either the last read message or the message in the URL anchor
// and there is a fallback to scroll to the bottom if the message is not found
this.scrollToFocusedMessage()
})

this.isInitialisingMessages = false

// get new messages
await this.lookForNewMessages()

if (this.loadChatInLegacyMode || focusMessageId === null) {
// don't scroll if lookForNewMessages was polling as we don't want
// to scroll back to the read marker after receiving new messages later
if (!hasScrolled) {
this.scrollToFocusedMessage()
}
}
} else {
this.$store.dispatch('cancelLookForNewMessages', { requestId: this.chatIdentifier })
}
Expand Down Expand Up @@ -904,16 +859,14 @@ export default {
return
}

if (!this.loadChatInLegacyMode) {
if (this.isInitialisingMessages) {
console.debug('Ignore handleScroll as we are initialising the message history')
return
}
if (this.isInitialisingMessages) {
console.debug('Ignore handleScroll as we are initialising the message history')
return
}

if (this.isFocusingMessage) {
console.debug('Ignore handleScroll as we are programmatically scrolling to focus a message')
return
}
if (this.isFocusingMessage) {
console.debug('Ignore handleScroll as we are programmatically scrolling to focus a message')
return
}

const { scrollHeight, scrollTop, clientHeight } = this.$refs.scroller
Expand Down Expand Up @@ -1141,16 +1094,15 @@ export default {
focusMessage(messageId, smooth = true, highlightAnimation = true) {
const element = document.getElementById(`message_${messageId}`)
if (!element) {
// TODO: in some cases might need to trigger a scroll up if this is an older message
// Message id doesn't exist
console.warn('Message to focus not found in DOM', messageId)
return false
return false // element not found
}

console.debug('Scrolling to a focused message programmatically')
this.isFocusingMessage = true

this.$nextTick(async () => {
// FIXME: this doesn't wait for the smooth scroll to end
element.scrollIntoView({
behavior: smooth ? 'smooth' : 'auto',
block: 'center',
Expand All @@ -1160,14 +1112,14 @@ export default {
// scroll the viewport slightly further to make sure the element is about 1/3 from the top
this.$refs.scroller.scrollTop += this.$refs.scroller.offsetHeight / 4
}

if (highlightAnimation) {
EventBus.$emit('highlight-message', messageId)
}
this.isFocusingMessage = false
await this.handleScroll()
})

return true
return true // element found
},

/**
Expand Down

0 comments on commit 2b20dab

Please sign in to comment.