From e94f36e778da0729283771f22eff5a08f12c988b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Du=C5=A1an=20Simi=C4=87?= Date: Sat, 27 Jun 2020 15:11:48 +0200 Subject: [PATCH] Fix autoscroll on new messages (#1382) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Franco Co-authored-by: Sindre Sorhus Co-authored-by: Dušan Simić --- source/browser.ts | 55 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/source/browser.ts b/source/browser.ts index 3d88639b0..a27541ea0 100644 --- a/source/browser.ts +++ b/source/browser.ts @@ -542,6 +542,58 @@ function insertionListener(event: AnimationEvent): void { } } +async function observeAutoscroll(): Promise { + const mainElement = await elementReady('._4sp8', {stopOnDomReady: false}); + if (!mainElement) { + return; + } + + const scrollToBottom = (): void => { + const scrollableElement: HTMLElement | null = document.querySelector('[role=presentation] .scrollable'); + if (scrollableElement) { + scrollableElement.scroll({ + top: Number.MAX_SAFE_INTEGER, + behavior: 'smooth' + }); + } + } + + const hookMessageObserver = async (): Promise => { + const chatElement = await elementReady( + '[role=presentation] .scrollable [role = region] > div[id ^= "js_"]', {stopOnDomReady: false} + ); + + if (chatElement) { + // Scroll to the bottom when opening different conversation + scrollToBottom(); + + const messageObserver = new MutationObserver((record: MutationRecord[]) => { + const newMessages: MutationRecord[] = record.filter(record => { + // The mutation is an addition + return record.addedNodes.length > 0 && + // ... of a div (skip the "seen" status change) + (record.addedNodes[0] as HTMLElement).tagName === 'DIV' && + // ... on the last child (skip previous messages added when scrolling up) + chatElement.lastChild!.contains(record.target); + }); + + if (newMessages.length > 0) { + // Scroll to the bottom when there are new messages + scrollToBottom(); + } + }); + + messageObserver.observe(chatElement, {childList: true, subtree: true}); + } + }; + + hookMessageObserver(); + + // Hook it again if conversation changes + const conversationObserver = new MutationObserver(hookMessageObserver); + conversationObserver.observe(mainElement, {childList: true}); +} + // Listen for emoji element dom insertion document.addEventListener('animationstart', insertionListener, false); @@ -580,6 +632,9 @@ document.addEventListener('DOMContentLoaded', async () => { // Disable autoplay if set in settings toggleVideoAutoplay(); + + // Hook auto-scroll observer + observeAutoscroll(); }); // Handle title bar double-click.