Ver código fonte

Don't smooth-scroll upon first appearance of the chat

it's annoying in overlayed view-mode where the user might be navigating
around the site.

Fixes #2091
JC Brand 5 anos atrás
pai
commit
f8efd94249

+ 0 - 4
sass/_core.scss

@@ -100,10 +100,6 @@ body.converse-fullscreen {
         background-color: #EEE !important;
     }
 
-    .smooth-scroll {
-        scroll-behavior: smooth !important;
-    }
-
     .nopadding {
         padding: 0 !important;
     }

+ 5 - 6
spec/chatbox.js

@@ -1322,7 +1322,7 @@ describe("Chatboxes", function () {
                 ['rosterGroupsFetched', 'chatBoxesFetched'], {},
                 async function (done, _converse) {
 
-            await mock.waitForRoster(_converse, 'current');
+            await mock.waitForRoster(_converse, 'current', 1);
             const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit',
                   msg = mock.createChatMessage(_converse, sender_jid, 'This message will be unread');
 
@@ -1347,10 +1347,9 @@ describe("Chatboxes", function () {
                 ['rosterGroupsFetched', 'chatBoxesFetched'], {},
                 async function (done, _converse) {
 
-            await mock.waitForRoster(_converse, 'current');
-
-            const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit',
-                  msg = mock.createChatMessage(_converse, sender_jid, 'This message will be read');
+            await mock.waitForRoster(_converse, 'current', 1);
+            const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
+            const msg = mock.createChatMessage(_converse, sender_jid, 'This message will be read');
             const sent_stanzas = [];
             spyOn(_converse.connection, 'send').and.callFake(s => sent_stanzas.push(s));
             await mock.openChatBoxFor(_converse, sender_jid);
@@ -1470,7 +1469,7 @@ describe("Chatboxes", function () {
             await u.waitUntil(() => chatbox.sendMarker.calls.count() === 1);
             expect(sent_stanzas[0].nodeTree.querySelector('received')).toBeDefined();
             _converse.saveWindowState(null, 'focus');
-            expect(chatbox.get('num_unread')).toBe(1);
+            await u.waitUntil(() => chatbox.get('num_unread') === 1);
             expect(chatbox.get('first_unread_id')).toBe(msgid);
             await u.waitUntil(() => chatbox.sendMarker.calls.count() === 1);
             expect(sent_stanzas[0].nodeTree.querySelector('received')).toBeDefined();

+ 9 - 26
spec/messages.js

@@ -1743,6 +1743,9 @@ describe("A Chat Message", function () {
             const view = _converse.api.chatviews.get(sender_jid);
             // Create enough messages so that there's a scrollbar.
             const promises = [];
+            view.content.scrollTop = 0;
+            view.model.set('scrolled', true);
+
             for (let i=0; i<20; i++) {
                 _converse.handleMessageStanza($msg({
                         from: sender_jid,
@@ -1754,35 +1757,15 @@ describe("A Chat Message", function () {
                 promises.push(new Promise(resolve => view.model.messages.once('rendered', resolve)));
             }
             await Promise.all(promises);
-            // XXX Fails on Travis
-            // await u.waitUntil(() => view.content.scrollTop, 1000)
-            await u.waitUntil(() => !view.model.get('auto_scrolled'), 500);
-            view.content.scrollTop = 0;
-            // XXX Fails on Travis
-            // await u.waitUntil(() => view.model.get('scrolled'), 900);
-            view.model.set('scrolled', true);
 
-            const message = 'This message is received while the chat area is scrolled up';
-            _converse.handleMessageStanza($msg({
-                    from: sender_jid,
-                    to: _converse.connection.jid,
-                    type: 'chat',
-                    id: u.getUniqueId()
-                }).c('body').t(message).up()
-                .c('active', {'xmlns': 'http://jabber.org/protocol/chatstates'}).tree());
-            await new Promise(resolve => view.model.messages.once('rendered', resolve));
-            await u.waitUntil(() => view.model.messages.length > 20, 1000);
-            // Now check that the message appears inside the chatbox in the DOM
-            const  msg_txt = sizzle('.chat-content .chat-msg:last .chat-msg__text', view.el).pop().textContent;
-            expect(msg_txt).toEqual(message);
-            await u.waitUntil(() => u.isVisible(view.el.querySelector('.new-msgs-indicator')), 900);
+            const indicator_el = view.el.querySelector('.new-msgs-indicator');
+            expect(u.isVisible(indicator_el)).toBeTruthy();
+
             expect(view.model.get('scrolled')).toBe(true);
             expect(view.content.scrollTop).toBe(0);
-            expect(u.isVisible(view.el.querySelector('.new-msgs-indicator'))).toBeTruthy();
-            // Scroll down again
-            view.content.scrollTop = view.content.scrollHeight;
-            // XXX Fails on Travis
-            // await u.waitUntil(() => !u.isVisible(view.el.querySelector('.new-msgs-indicator')), 900);
+            indicator_el.click();
+            expect(u.isVisible(indicator_el)).toBeFalsy();
+            expect(view.model.get('scrolled')).toBe(false);
             done();
         }));
 

+ 0 - 10
src/components/chat_content.js

@@ -25,16 +25,6 @@ class ChatContent extends CustomElement {
             <div class="chat-content__notifications">${unsafeHTML(notifications)}</div>
         `;
     }
-
-    scrollDown () {
-        if (!this.chatview.model.get('scrolled')) {
-            this.parentElement.scrollTop = this.parentElement.scrollHeight;
-        }
-    }
-
-    updated () {
-        this.scrollDown();
-    }
 }
 
 customElements.define('converse-chat-content', ChatContent);

+ 25 - 4
src/converse-chatview.js

@@ -211,6 +211,7 @@ converse.plugins.add('converse-chatview', {
                 // Need to be registered after render has been called.
                 this.listenTo(this.model.messages, 'add', this.onMessageAdded);
                 this.listenTo(this.model.messages, 'change', this.renderChatHistory);
+                this.listenTo(this.model.messages, 'rendered', this.maybeScrollDownOnMessage);
                 this.listenTo(this.model.messages, 'reset', this.renderChatHistory);
                 this.listenTo(this.model.notifications, 'change', this.renderNotifications);
                 this.listenTo(this.model, 'change:show_help_messages', this.renderHelpMessages);
@@ -228,6 +229,8 @@ converse.plugins.add('converse-chatview', {
 
             initDebounced () {
                 this.markScrolled = debounce(this._markScrolled, 100);
+                this.debouncedScrollDown = debounce(this.scrollDown, 100);
+
                 // For tests that use Jasmine.Clock we want to turn of
                 // debouncing, since setTimeout breaks.
                 if (api.settings.get('debounced_content_rendering')) {
@@ -552,9 +555,28 @@ converse.plugins.add('converse-chatview', {
                 api.trigger('afterMessagesFetched', this.model);
             },
 
-            scrollDown () {
-                const el = this.msgs_container.firstElementChild;
-                el && el.scrollDown();
+            maybeScrollDownOnMessage (message) {
+                if (message.get('sender') !== 'me' && !this.model.get('scrolled')) {
+                    this.debouncedScrollDown();
+                }
+            },
+
+            scrollDown (ev) {
+                ev?.preventDefault?.();
+                ev?.stopPropagation?.();
+                if (this.model.get('scrolled')) {
+                    u.safeSave(this.model, {
+                        'scrolled': false,
+                        'top_visible_message': null,
+                    });
+                }
+                if (this.msgs_container.scrollTo) {
+                    const behavior = this.msgs_container.scrollTop ? 'smooth' : 'auto';
+                    this.msgs_container.scrollTo({'top': this.msgs_container.scrollHeight, behavior});
+                } else {
+                    this.msgs_container.scrollTop = this.msgs_container.scrollHeight;
+                }
+                this.onScrolledDown();
             },
 
             insertIntoDOM () {
@@ -597,7 +619,6 @@ converse.plugins.add('converse-chatview', {
                         // should maintain our current scroll position.
                         if (this.content.scrollTop === 0 || this.model.get('top_visible_message')) {
                             const top_visible_message = this.model.get('top_visible_message') || next_msg_el;
-
                             this.model.set('top_visible_message', top_visible_message);
                             this.content.scrollTop = top_visible_message.offsetTop - 30;
                         }

+ 1 - 1
src/converse-muc-views.js

@@ -466,7 +466,7 @@ converse.plugins.add('converse-muc-views', {
                 this.listenTo(this.model, 'show', this.show);
                 this.listenTo(this.model.features, 'change:moderated', this.renderBottomPanel);
                 this.listenTo(this.model.features, 'change:open', this.renderHeading);
-                this.listenTo(this.model.messages, 'rendered', this.scrollDown);
+                this.listenTo(this.model.messages, 'rendered', this.maybeScrollDownOnMessage);
                 this.listenTo(this.model.session, 'change:connection_status', this.onConnectionStatusChanged);
 
                 // Bind so that we can pass it to addEventListener and removeEventListener

+ 1 - 1
src/templates/chatbox.js

@@ -5,7 +5,7 @@ export default (o) => html`
         <div class="chat-head chat-head-chatbox row no-gutters"></div>
         <div class="chat-body">
             <div class="chat-content ${ o.show_send_button ? 'chat-content-sendbutton' : '' }" aria-live="polite">
-                <div class="chat-content__messages smooth-scroll" @scroll=${o.markScrolled}></div>
+                <div class="chat-content__messages" @scroll=${o.markScrolled}></div>
                 <div class="chat-content__help"></div>
             </div>
             <div class="bottom-panel">

+ 1 - 1
src/templates/chatroom.js

@@ -6,7 +6,7 @@ export default (o) => html`
         <div class="chat-body chatroom-body row no-gutters">
             <div class="chat-area col">
                 <div class="chat-content ${ o.show_send_button ? 'chat-content-sendbutton' : '' }" aria-live="polite">
-                    <div class="chat-content__messages smooth-scroll" @scroll=${o.markScrolled}></div>
+                    <div class="chat-content__messages" @scroll=${o.markScrolled}></div>
                     <div class="chat-content__help"></div>
                 </div>
                 <div class="bottom-panel"></div>