Merge pull request #15871 from nextcloud/fix/noid/focus-no-highlight

This commit is contained in:
Maksim Sukharev 2025-09-10 09:20:16 +02:00 committed by GitHub
commit 8756d8e4fe
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 19 additions and 16 deletions

View file

@ -565,20 +565,20 @@ export default {
let isFocused = null
if (focusMessageId) {
// scroll to message in URL anchor
this.focusMessage(focusMessageId, false)
this.focusMessage({ messageId: focusMessageId, smooth: false, highlight: true })
return
}
if (this.visualLastReadMessageId) {
// scroll to last read message if visible in the current pages
isFocused = this.focusMessage(this.visualLastReadMessageId, false, false)
isFocused = this.focusMessage({ messageId: this.visualLastReadMessageId, smooth: false, highlight: false })
}
if (!isFocused) {
// 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)
isFocused = this.focusMessage({ messageId: fallbackLastReadMessageId, smooth: false, highlight: false })
}
if (!isFocused) {
@ -909,12 +909,13 @@ export default {
/**
* Temporarily highlight the given message id with a fade out effect.
*
* @param {number} messageId message id
* @param {boolean} smooth true to smooth scroll, false to jump directly
* @param {boolean} highlightAnimation true to highlight and set focus to the message
* @param payload function payload
* @param payload.messageId message id
* @param payload.smooth true to smooth scroll, false to jump directly
* @param payload.highlight true to highlight and set focus to the message
* @return {boolean} true if element was found, false otherwise
*/
focusMessage(messageId, smooth = true, highlightAnimation = true) {
focusMessage({ messageId, smooth = true, highlight = true }) {
const element = document.getElementById(`message_${messageId}`)
if (!element) {
// Message id doesn't exist
@ -927,7 +928,8 @@ export default {
let scrollElement = element
if (this.isChatVisible && scrollElement.offsetParent === null) {
console.debug('Message to focus is hidden, scrolling to its nearest visible parent', messageId)
scrollElement = scrollElement.closest('ul[style="display: none;"]').parentElement
const closestParent = scrollElement.closest('ul[style="display: none;"]') ?? scrollElement.closest('ul')
scrollElement = closestParent.parentElement
}
console.debug('Scrolling to a focused message programmatically')
@ -963,7 +965,7 @@ export default {
this.checkChatNotScrollable()
if (highlightAnimation && scrollElement === element) {
if (highlight && scrollElement === element) {
// element is visible, highlight it
element.classList.add('message--highlighted')
}

View file

@ -137,7 +137,7 @@ function handleQuoteClick() {
if (route.hash === hash.value) {
// Already on this message route, just trigger highlight
EventBus.emit('focus-message', message.id)
EventBus.emit('focus-message', { messageId: message.id })
}
}
</script>

View file

@ -76,7 +76,7 @@ const active = computed(() => {
function handleResultClick() {
if (route.hash === '#message_' + props.messageId) {
// Already on this message route, just trigger highlight
EventBus.emit('focus-message', props.messageId)
EventBus.emit('focus-message', { messageId: props.messageId })
}
}
</script>

View file

@ -244,7 +244,7 @@ export function useGetMessagesProvider() {
: conversationLastMessageId.value
}
await checkContextAndFocusMessage(to.params.token, contextMessageId.value, contextThreadId.value)
await checkContextAndFocusMessage(to.params.token, contextMessageId.value, contextThreadId.value, focusMessageId !== null)
}
/**
@ -253,8 +253,9 @@ export function useGetMessagesProvider() {
* @param token
* @param messageId
* @param threadId
* @param highlight
*/
async function checkContextAndFocusMessage(token: string, messageId: number, threadId: number) {
async function checkContextAndFocusMessage(token: string, messageId: number, threadId: number, highlight: boolean = false) {
if (!chatStore.hasMessage(token, { messageId, threadId })) {
// message not found in the list, need to fetch it first
await getMessageContext(token, messageId, threadId)
@ -268,7 +269,7 @@ export function useGetMessagesProvider() {
// need some delay (next tick is too short) to be able to run
// after the browser's native "scroll to anchor" from the hash
window.setTimeout(() => {
EventBus.emit('focus-message', messageId)
EventBus.emit('focus-message', { messageId, highlight })
}, 2)
}
@ -316,7 +317,7 @@ export function useGetMessagesProvider() {
return
}
} else {
await checkContextAndFocusMessage(token, contextMessageId.value, contextThreadId.value)
await checkContextAndFocusMessage(token, contextMessageId.value, contextThreadId.value, focusMessageId !== null)
}
isInitialisingMessages.value = false

View file

@ -28,7 +28,7 @@ export type Events = {
'editing-message': void
'editing-message-processing': { messageId: number, value: boolean }
'focus-chat-input': void
'focus-message': number // TODO: listener method can receive ...[messageId, smooth, highlightAnimation]
'focus-message': { messageId: number, smooth?: boolean, highlight?: boolean }
'forbidden-route': { error: string }
'joined-conversation': { token: string }
'poll-drafts-open': { token: string, selector?: string }