浏览代码

Stop debouncing `show`

Instead optimize in other ways.

Also:
- Don't fade in when `animate` is false.
- `trimChats` now gets called in `afterShown`.
- Add now event `beforeShowingChatView`
JC Brand 6 年之前
父节点
当前提交
2849adf857
共有 6 个文件被更改,包括 102 次插入90 次删除
  1. 42 29
      spec/chatbox.js
  2. 21 10
      src/converse-chatview.js
  3. 5 9
      src/converse-dragresize.js
  4. 11 7
      src/converse-minimize.js
  5. 0 13
      src/converse-muc-views.js
  6. 23 22
      src/converse-uniview.js

+ 42 - 29
spec/chatbox.js

@@ -939,9 +939,10 @@
                             null, ['rosterGroupsFetched', 'chatBoxesFetched'], {},
                             async function (done, _converse) {
 
+                        const sent_stanzas = _converse.connection.sent_stanzas;
                         // Make the timeouts shorter so that we can test
-                        _converse.TIMEOUTS.PAUSED = 200;
-                        _converse.TIMEOUTS.INACTIVE = 200;
+                        _converse.TIMEOUTS.PAUSED = 100;
+                        _converse.TIMEOUTS.INACTIVE = 100;
 
                         await test_utils.waitForRoster(_converse, 'current');
                         const contact_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
@@ -949,38 +950,50 @@
                         await u.waitUntil(() => _converse.rosterview.el.querySelectorAll('.roster-group').length, 1000);
                         await test_utils.openChatBoxFor(_converse, contact_jid);
                         const view = _converse.chatboxviews.get(contact_jid);
-                        await u.waitUntil(() => view.model.get('chat_state') === 'active', 1000);
-                        console.log('chat_state set to active');
+                        await u.waitUntil(() => view.model.get('chat_state') === 'active');
+                        let messages = await u.waitUntil(() => sent_stanzas.filter(s => s.matches('message')));
+                        expect(messages.length).toBe(1);
                         expect(view.model.get('chat_state')).toBe('active');
                         view.onKeyDown({
                             target: view.el.querySelector('textarea.chat-textarea'),
                             keyCode: 1
                         });
-                        await u.waitUntil(() => view.model.get('chat_state') === 'composing', 500);
-                        console.log('chat_state set to composing');
-                        expect(view.model.get('chat_state')).toBe('composing');
-                        spyOn(_converse.connection, 'send');
-                        await u.waitUntil(() => view.model.get('chat_state') === 'paused', 1000);
-                        await u.waitUntil(() => view.model.get('chat_state') === 'inactive', 1000);
-                        console.log('chat_state set to inactive');
-                        expect(_converse.connection.send).toHaveBeenCalled();
-                        var calls = _.filter(_converse.connection.send.calls.all(), function (call) {
-                            return call.args[0] instanceof Strophe.Builder;
-                        });
-                        expect(calls.length).toBe(2);
-                        var stanza = calls[0].args[0].tree();
-                        expect(stanza.getAttribute('to')).toBe(contact_jid);
-                        expect(stanza.children.length).toBe(3);
-                        expect(stanza.children[0].tagName).toBe('paused');
-                        expect(stanza.children[1].tagName).toBe('no-store');
-                        expect(stanza.children[2].tagName).toBe('no-permanent-store');
-
-                        stanza = _converse.connection.send.calls.mostRecent().args[0].tree();
-                        expect(stanza.getAttribute('to')).toBe(contact_jid);
-                        expect(stanza.children.length).toBe(3);
-                        expect(stanza.children[0].tagName).toBe('inactive');
-                        expect(stanza.children[1].tagName).toBe('no-store');
-                        expect(stanza.children[2].tagName).toBe('no-permanent-store');
+                        await u.waitUntil(() => view.model.get('chat_state') === 'composing', 600);
+                        messages = sent_stanzas.filter(s => s.matches('message'));
+                        expect(messages.length).toBe(2);
+
+                        await u.waitUntil(() => view.model.get('chat_state') === 'paused', 600);
+                        messages = sent_stanzas.filter(s => s.matches('message'));
+                        expect(messages.length).toBe(3);
+
+                        await u.waitUntil(() => view.model.get('chat_state') === 'inactive', 600);
+                        messages = sent_stanzas.filter(s => s.matches('message'));
+                        expect(messages.length).toBe(4);
+
+                        expect(Strophe.serialize(messages[0])).toBe(
+                            `<message id="${messages[0].getAttribute('id')}" to="mercutio@montague.lit" type="chat" xmlns="jabber:client">`+
+                                `<active xmlns="http://jabber.org/protocol/chatstates"/>`+
+                                `<no-store xmlns="urn:xmpp:hints"/>`+
+                                `<no-permanent-store xmlns="urn:xmpp:hints"/>`+
+                            `</message>`);
+                        expect(Strophe.serialize(messages[1])).toBe(
+                            `<message id="${messages[1].getAttribute('id')}" to="mercutio@montague.lit" type="chat" xmlns="jabber:client">`+
+                                `<composing xmlns="http://jabber.org/protocol/chatstates"/>`+
+                                `<no-store xmlns="urn:xmpp:hints"/>`+
+                                `<no-permanent-store xmlns="urn:xmpp:hints"/>`+
+                            `</message>`);
+                        expect(Strophe.serialize(messages[2])).toBe(
+                            `<message id="${messages[2].getAttribute('id')}" to="mercutio@montague.lit" type="chat" xmlns="jabber:client">`+
+                                `<paused xmlns="http://jabber.org/protocol/chatstates"/>`+
+                                `<no-store xmlns="urn:xmpp:hints"/>`+
+                                `<no-permanent-store xmlns="urn:xmpp:hints"/>`+
+                            `</message>`);
+                        expect(Strophe.serialize(messages[3])).toBe(
+                            `<message id="${messages[3].getAttribute('id')}" to="mercutio@montague.lit" type="chat" xmlns="jabber:client">`+
+                                `<inactive xmlns="http://jabber.org/protocol/chatstates"/>`+
+                                `<no-store xmlns="urn:xmpp:hints"/>`+
+                                `<no-permanent-store xmlns="urn:xmpp:hints"/>`+
+                            `</message>`);
                         done();
                     }));
 

+ 21 - 10
src/converse-chatview.js

@@ -374,7 +374,6 @@ converse.plugins.add('converse-chatview', {
             initDebounced () {
                 this.scrollDown = _.debounce(this._scrollDown, 100);
                 this.markScrolled = _.debounce(this._markScrolled, 100);
-                this.show = _.debounce(this._show, 500, {'leading': true});
             },
 
             render () {
@@ -1280,7 +1279,7 @@ converse.plugins.add('converse-chatview', {
                 }
             },
 
-            emitFocused: _.debounce(() => {
+            emitFocused () {
                 /**
                  * Triggered when the focus has been moved to a particular chat.
                  * @event _converse#chatBoxFocused
@@ -1288,11 +1287,11 @@ converse.plugins.add('converse-chatview', {
                  * @example _converse.api.listen.on('chatBoxFocused', view => { ... });
                  */
                 _converse.api.trigger('chatBoxFocused', this);
-            }, 25, {'leading': true}),
+            },
 
             focus () {
-                const textarea_el = this.el.querySelector('.chat-textarea');
-                if (!_.isNull(textarea_el)) {
+                const textarea_el = this.el.getElementsByClassName('chat-textarea')[0];
+                if (textarea_el && document.activeElement !== textarea_el) {
                     textarea_el.focus();
                     this.emitFocused();
                 }
@@ -1311,18 +1310,30 @@ converse.plugins.add('converse-chatview', {
                 if (_converse.auto_focus) {
                     this.focus();
                 }
-                this.focus();
             },
 
-            _show () {
-                /* Inner show method that gets debounced */
+            show () {
                 if (u.isVisible(this.el)) {
                     if (_converse.auto_focus) {
                         this.focus();
                     }
                     return;
                 }
-                u.fadeIn(this.el, _.bind(this.afterShown, this));
+                /**
+                 * Triggered just before a {@link _converse.ChatBoxView} or {@link _converse.ChatRoomView}
+                 * will be shown.
+                 * @event _converse#beforeShowingChatView
+                 * @type {object}
+                 * @property { _converse.ChatBoxView | _converse.ChatRoomView } view
+                 */
+                _converse.api.trigger('beforeShowingChatView', this);
+
+                if (_converse.animate) {
+                    u.fadeIn(this.el, () => this.afterShown());
+                } else {
+                    u.showElement(this.el);
+                    this.afterShown();
+                }
             },
 
             showNewMessagesIndicator () {
@@ -1395,7 +1406,7 @@ converse.plugins.add('converse-chatview', {
             onWindowStateChanged (state) {
                 if (state === 'visible') {
                     if (!this.model.isHidden()) {
-                        this.model.setChatState(_converse.ACTIVE);
+                        // this.model.setChatState(_converse.ACTIVE);
                         if (this.model.get('num_unread', 0)) {
                             this.model.clearUnreadMsgCounter();
                         }

+ 5 - 9
src/converse-dragresize.js

@@ -72,11 +72,6 @@ converse.plugins.add('converse-dragresize', {
                 renderDragResizeHandles(this.__super__._converse, this);
                 this.setWidth();
                 return result;
-            },
-
-            _show () {
-                this.initDragResize().setDimensions();
-                this.__super__._show.apply(this, arguments);
             }
         },
 
@@ -155,12 +150,12 @@ converse.plugins.add('converse-dragresize', {
                 /* Determine and store the default box size.
                  * We need this information for the drag-resizing feature.
                  */
-                const flyout = this.el.querySelector('.box-flyout'),
-                      style = window.getComputedStyle(flyout);
+                const flyout = this.el.querySelector('.box-flyout');
+                const style = window.getComputedStyle(flyout);
 
                 if (_.isUndefined(this.model.get('height'))) {
-                    const height = parseInt(style.height.replace(/px$/, ''), 10),
-                          width = parseInt(style.width.replace(/px$/, ''), 10);
+                    const height = parseInt(style.height.replace(/px$/, ''), 10);
+                    const width = parseInt(style.width.replace(/px$/, ''), 10);
                     this.model.set('height', height);
                     this.model.set('default_height', height);
                     this.model.set('width', width);
@@ -341,6 +336,7 @@ converse.plugins.add('converse-dragresize', {
         }
         _converse.api.listen.on('registeredGlobalEventHandlers', registerGlobalEventHandlers);
 
+        _converse.api.listen.on('beforeShowingChatView', view => view.initDragResize().setDimensions());
 
         _converse.api.listen.on('chatBoxInitialized', view => {
             window.addEventListener('resize', _.debounce(() => view.setDimensions(), 100));

+ 11 - 7
src/converse-minimize.js

@@ -78,18 +78,22 @@ converse.plugins.add('converse-minimize', {
                 return this.__super__.initialize.apply(this, arguments);
             },
 
-            _show () {
+            show () {
                 const { _converse } = this.__super__;
-                if (_converse.view_mode !== 'overlayed') {
-                    return this.__super__._show.apply(this, arguments);
-                } else if (!this.model.get('minimized')) {
-                    this.__super__._show.apply(this, arguments);
-                    _converse.chatboxviews.trimChats(this);
-                } else {
+                if (_converse.view_mode === 'overlayed' && this.model.get('minimized')) {
                     this.model.minimize();
+                    return this;
+                } else {
+                    return this.__super__.show.apply(this, arguments);
                 }
             },
 
+            afterShown () {
+                const { _converse } = this.__super__;
+                this.__super__.afterShown.apply(this, arguments);
+                _converse.chatboxviews.trimChats(this);
+            },
+
             isNewMessageHidden () {
                 return this.model.get('minimized') ||
                     this.__super__.isNewMessageHidden.apply(this, arguments);

+ 0 - 13
src/converse-muc-views.js

@@ -701,19 +701,6 @@ converse.plugins.add('converse-muc-views', {
                 this.renderEmojiPicker();
             },
 
-            show () {
-                if (u.isVisible(this.el)) {
-                    if (_converse.auto_focus) {
-                        this.focus();
-                    }
-                    return;
-                }
-                // Override from converse-chatview in order to not use
-                // "fadeIn", which causes flashing.
-                u.showElement(this.el);
-                this.afterShown();
-            },
-
             onConnectionStatusChanged () {
                 const conn_status = this.model.get('connection_status');
                 if (conn_status === converse.ROOMSTATUS.NICKNAME_REQUIRED) {

+ 23 - 22
src/converse-uniview.js

@@ -75,31 +75,32 @@ converse.plugins.add('converse-uniview', {
                 } else {
                     return this.__super__.shouldShowOnTextMessage.apply(this, arguments);
                 }
-            },
-
-            _show (focus) {
-                /* We only have one chat visible at any one
-                 * time. So before opening a chat, we make sure all other
-                 * chats are hidden.
-                 */
-                const { _converse } = this.__super__;
-                if (_converse.isUniView()) {
-                    _.each(this.__super__._converse.chatboxviews.xget(this.model.get('id')), hideChat);
-                    u.safeSave(this.model, {'hidden': false});
-                }
-                return this.__super__._show.apply(this, arguments);
             }
-        },
+        }
+    },
 
-        ChatRoomView: {
-            show (focus) {
-                const { _converse } = this.__super__;
-                if (_converse.isUniView()) {
-                    _.each(this.__super__._converse.chatboxviews.xget(this.model.get('id')), hideChat);
-                    u.safeSave(this.model, {'hidden': false});
+    initialize () {
+        /* The initialize function gets called as soon as the plugin is
+         * loaded by converse.js's plugin machinery.
+         */
+        const { _converse } = this;
+
+        /************************ BEGIN Event Handlers ************************/
+        _converse.api.listen.on('beforeShowingChatView', (view) => {
+            /* We only have one chat visible at any one
+             * time. So before opening a chat, we make sure all other
+             * chats are hidden.
+             */
+            if (_converse.isUniView()) {
+                Object.values(_converse.chatboxviews.xget(view.model.get('id')))
+                    .filter(v => !v.model.get('hidden'))
+                    .forEach(hideChat);
+
+                if (view.model.get('hidden')) {
+                    u.safeSave(view.model, {'hidden': false});
                 }
-                return this.__super__.show.apply(this, arguments);
             }
-        }
+        });
+        /************************ END Event Handlers ************************/
     }
 });