From 4698ba4122c3cc2e1e6592b8a295e7f9bc7b696f Mon Sep 17 00:00:00 2001 From: rainbow napkin Date: Tue, 7 Oct 2025 03:17:16 -0400 Subject: [PATCH] Added auto-scrolling to private message panel. Fixed auto-scrolling w/ laggy assets in chat and PM. --- www/js/channel/chat.js | 10 +++ www/js/channel/panels/pmPanel.js | 118 +++++++++++++++++++++++++++++-- 2 files changed, 122 insertions(+), 6 deletions(-) diff --git a/www/js/channel/chat.js b/www/js/channel/chat.js index b9aa843..e733bdf 100644 --- a/www/js/channel/chat.js +++ b/www/js/channel/chat.js @@ -145,6 +145,12 @@ class chatBox{ */ this.showChatIcon = document.querySelector("#media-panel-show-chat-icon"); + /** + * re-occuring auto-scroll call + * cope for the fact that postprocessedMessage objects in renderMessage aren't throwing load events + */ + this.scrollInterval = setInterval(this.handleAutoScroll.bind(this), 200); + //Setup functions this.setupInput(); this.defineListeners(); @@ -567,11 +573,15 @@ class chatBox{ const bufferHeight = Math.round(bufferRect.height); const bufferWidth = Math.round(bufferRect.width); + //If last height was unset if(this.lastHeight == 0){ + //Set it based on buffer Height this.lastHeight = bufferHeight; } + //if last width is unset if(this.lastWidth == 0){ + //Set it based on buffer width this.lastWidth = bufferWidth; } diff --git a/www/js/channel/panels/pmPanel.js b/www/js/channel/panels/pmPanel.js index 92e44ef..7751d59 100644 --- a/www/js/channel/panels/pmPanel.js +++ b/www/js/channel/panels/pmPanel.js @@ -42,6 +42,32 @@ class pmPanel extends panelObj{ */ this.txSound = '/nonfree/imsend.ogg'; + /** + * Message Buffer Scroll Top on last scroll + */ + this.lastPos = 0; + + /** + * Height of Message Buffer on last scroll + */ + this.lastHeight = 0; + + /** + * Width of Message Buffer on last scroll + */ + this.lastWidth = 0; + + /** + * Whether or not auto-scroll is enabled + */ + this.autoScroll = true; + + /** + * re-occuring auto-scroll call + * cope for the fact that postprocessedMessage objects in renderMessage aren't throwing load events + */ + this.scrollInterval = setInterval(this.handleAutoScroll.bind(this), 200); + //Tell PMHandler to start tracking this panel this.client.pmHandler.panelList.set(this.uuid, null); @@ -49,20 +75,29 @@ class pmPanel extends panelObj{ } closer(){ - //Tell PMHandler to start tracking this panel + //Tell PMHandler to stop tracking this panel this.client.pmHandler.panelList.delete(this.uuid); + //Clear the scroll interval + clearInterval(this.scrollInterval); + //Run derived closer super.closer(); } - docSwitch(){ + async docSwitch(){ + //Call derived method + super.docSwitch(); + this.startSeshButton = this.panelDocument.querySelector('#pm-panel-start-sesh'); this.seshList = this.panelDocument.querySelector('#pm-panel-sesh-list'); this.seshBuffer = this.panelDocument.querySelector('#pm-panel-sesh-buffer'); this.seshPrompt = this.panelDocument.querySelector('#pm-panel-message-prompt'); this.seshSendButton = this.panelDocument.querySelector('#pm-panel-send-button'); + //reset auto-scroll + this.autoScroll = true; + this.setupInput(); this.renderSeshList(); @@ -72,9 +107,6 @@ class pmPanel extends panelObj{ //Render messages this.renderMessages(); } - - //Call derived method - super.docSwitch(); } /** @@ -92,6 +124,9 @@ class pmPanel extends panelObj{ this.startSeshButton.addEventListener('click', this.startSesh.bind(this)); this.seshPrompt.addEventListener("keydown", this.send.bind(this)); this.seshSendButton.addEventListener("click", this.send.bind(this)); + this.seshBuffer.addEventListener('scroll', this.scrollHandler.bind(this)); + this.ownerDoc.defaultView.addEventListener('resize', this.handleAutoScroll.bind(this)); + } startSesh(event){ @@ -227,6 +262,9 @@ class pmPanel extends panelObj{ //Tell PMHandler what sesh we have open for notification reasons this.client.pmHandler.readSesh(this.uuid, this.activeSesh); + //Reset auto scroll to scroll newly selected sesh down to the bottom + this.autoScroll = true; + //Re-render message buffer this.renderMessages(); @@ -255,7 +293,7 @@ class pmPanel extends panelObj{ * Renders message out to PM Panel Message Buffer * @param {Object} message - Message to render */ - renderMessage(message){ + async renderMessage(message){ //If we have an empty message if(message.msg == null || message.msg == ''){ //BAIL!! @@ -267,6 +305,74 @@ class pmPanel extends panelObj{ //Append message to buffer this.seshBuffer.appendChild(postprocessedMessage); + + //Auto-scroll buffer on content load + this.handleAutoScroll(); + } + + /** + * Handles scrolling within the message buffer + * @param {Event} event - Event passed down from Event Handler + */ + scrollHandler(event){ + //If we're just starting out + if(this.lastPos == 0){ + //Set last pos for the first time + this.lastPos = this.seshBuffer.scrollTop; + } + + //Calculate scroll delta + const deltaY = this.seshBuffer.scrollTop - this.lastPos; + + //Grab visible bounding rect so we don't have to do it again (can't use offset because someone might zoom in :P) + const bufferRect = this.seshBuffer.getBoundingClientRect(); + const bufferHeight = Math.round(bufferRect.height); + const bufferWidth = Math.round(bufferRect.width); + + //If last height was unset + if(this.lastHeight == 0){ + //Set it based on buffer Height + this.lastHeight = bufferHeight; + } + + //if last width is unset + if(this.lastWidth == 0){ + //Set it based on buffer width + this.lastWidth = bufferWidth; + } + + //If we're scrolling up + if(deltaY < 0){ + //If we have room to scroll, and we didn't resize + if(this.seshBuffer.scrollHeight > bufferHeight && (this.lastWidth == bufferWidth && this.lastHeight == bufferHeight)){ + //Disable auto scrolling + this.autoScroll = false; + //We probably resized + }else{ + this.handleAutoScroll(); + } + //Otherwise if the difference between the message buffers scroll height and offset height is equal to the scroll top + //(Because it is scrolled all the way down) + }else if((this.seshBuffer.scrollHeight - bufferHeight) == this.seshBuffer.scrollTop){ + this.autoScroll = true; + } + + //Set last post/size for next the run + this.lastPos = this.seshBuffer.scrollTop; + this.lastHeight = bufferHeight; + this.lastWidth = bufferWidth; + } + + /** + // * Auto-scrolls sesh chat buffer when new chats are entered. + */ + handleAutoScroll(){ + //If autoscroll is enabled + if(this.autoScroll){ + console.log("SCROLLME"); + //Set seshBuffer scrollTop to the difference between scrollHeight and buffer height (scroll to the bottom) + this.seshBuffer.scrollTop = this.seshBuffer.scrollHeight - Math.round(this.seshBuffer.getBoundingClientRect().height); + } } }