Forráskód Böngészése

Bugfix. Sometimes when trimming chats, minimized chats go off screen

JC Brand 6 éve
szülő
commit
38d1e4e3d2

+ 3 - 3
spec/chatbox.js

@@ -273,14 +273,14 @@
 
             it("can be saved to, and retrieved from, browserStorage",
                 mock.initConverse(
-                    null, ['rosterGroupsFetched', 'chatBoxesFetched',], {},
+                    null, ['rosterGroupsFetched'], {},
                     async function (done, _converse) {
 
+                spyOn(_converse.ChatBoxViews.prototype, 'trimChats');
                 await test_utils.waitForRoster(_converse, 'current');
                 test_utils.openControlBox();
 
                 spyOn(_converse.api, "trigger");
-                spyOn(_converse.chatboxviews, 'trimChats');
                 test_utils.openControlBox();
 
                 test_utils.openChatBoxes(_converse, 6);
@@ -386,11 +386,11 @@
                     null, ['rosterGroupsFetched', 'chatBoxesFetched'], {},
                     async function (done, _converse) {
 
+                spyOn(_converse.ChatBoxViews.prototype, 'trimChats');
                 await test_utils.waitForRoster(_converse, 'current');
                 test_utils.openControlBox();
                 await u.waitUntil(() => _converse.rosterview.el.querySelectorAll('.roster-group').length);
                 spyOn(_converse.api, "trigger");
-                spyOn(_converse.chatboxviews, 'trimChats');
                 _converse.chatboxes.browserStorage._clear();
 
                 test_utils.closeControlBox();

+ 7 - 4
src/converse-chatview.js

@@ -555,11 +555,14 @@ converse.plugins.add('converse-chatview', {
             },
 
             insertIntoDOM () {
-                /* This method gets overridden in src/converse-controlbox.js
-                 * as well as src/converse-muc.js (if those plugins are
-                 * enabled).
-                 */
                 _converse.chatboxviews.insertRowColumn(this.el);
+                /**
+                 * Triggered once the _converse.ChatBoxView has been inserted into the DOM
+                 * @event _converse#chatBoxInsertedIntoDOM
+                 * @type { _converse.ChatBoxView | _converse.HeadlinesBoxView }
+                 * @example _converse.api.listen.on('chatBoxInsertedIntoDOM', view => { ... });
+                 */
+                _converse.api.trigger('chatBoxInsertedIntoDOM', this);
                 return this;
             },
 

+ 5 - 0
src/converse-controlbox.js

@@ -344,6 +344,11 @@ converse.plugins.add('converse-controlbox', {
             onControlBoxToggleHidden () {
                 this.model.set('closed', false);
                 this.el.classList.remove('hidden');
+                /**
+                 * Triggered once the controlbox has been opened
+                 * @event _converse#controlBoxOpened
+                 * @type {_converse.ControlBox}
+                 */
                 _converse.api.trigger('controlBoxOpened', this);
             },
 

+ 37 - 36
src/converse-minimize.js

@@ -88,12 +88,6 @@ converse.plugins.add('converse-minimize', {
                 }
             },
 
-            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);
@@ -301,23 +295,37 @@ converse.plugins.add('converse-minimize', {
                 );
             },
 
-            trimChats: _.debounce(async function (newchat) {
-                /* This method is called when a newly created chat box will
-                 * be shown.
-                 *
-                 * It checks whether there is enough space on the page to show
-                 * another chat box. Otherwise it minimizes the oldest chat box
-                 * to create space.
-                 */
-                if (!_converse.connection.connected || _converse.view_mode !== 'overlayed') {
+            getMinimizedWidth () {
+                const minimized_el = _.get(_converse.minimized_chats, 'el');
+                return _.includes(this.model.pluck('minimized'), true) ?
+                    u.getOuterWidth(minimized_el, true) : 0;
+            },
+
+            getBoxesWidth (newchat) {
+                const new_id = newchat ? newchat.model.get('id') : null;
+                const newchat_width = newchat ? u.getOuterWidth(newchat.el, true) : 0;
+                return Object.values(this.xget(new_id))
+                    .reduce((memo, view) => memo + this.getChatBoxWidth(view), newchat_width);
+            },
+
+            /**
+             * This method is called when a newly created chat box will be shown.
+             * It checks whether there is enough space on the page to show
+             * another chat box. Otherwise it minimizes the oldest chat box
+             * to create space.
+             * @private
+             * @method _converse.ChatBoxViews#trimChats
+             * @param { [ChatBoxView|ChatRoomView|ControlBoxView|HeadlinesBoxView] } newchat
+             */
+            async trimChats (newchat) {
+                if (_converse.no_trimming || !_converse.connection.connected || _converse.view_mode !== 'overlayed') {
                     return;
                 }
                 const shown_chats = this.getShownChats();
-                const body_width = u.getOuterWidth(document.querySelector('body'), true);
-
-                if (_converse.no_trimming || shown_chats.length <= 1) {
+                if (shown_chats.length <= 1) {
                     return;
                 }
+                const body_width = u.getOuterWidth(document.querySelector('body'), true);
                 if (this.getChatBoxWidth(shown_chats[0]) === body_width) {
                     // If the chats shown are the same width as the body,
                     // then we're in responsive mode and the chats are
@@ -325,19 +333,10 @@ converse.plugins.add('converse-minimize', {
                     return;
                 }
                 await _converse.api.waitUntil('minimizedChatsInitialized');
-                const minimized_el = _.get(_converse.minimized_chats, 'el'),
-                      new_id = newchat ? newchat.model.get('id') : null;
-
+                const minimized_el = _.get(_converse.minimized_chats, 'el');
                 if (minimized_el) {
-                    const minimized_width = _.includes(this.model.pluck('minimized'), true) ?
-                        u.getOuterWidth(minimized_el, true) : 0;
-
-                    const boxes_width = _.reduce(
-                        this.xget(new_id),
-                        (memo, view) => memo + this.getChatBoxWidth(view),
-                        newchat ? u.getOuterWidth(newchat.el, true) : 0
-                    );
-                    if ((minimized_width + boxes_width) > body_width) {
+                    while ((this.getMinimizedWidth() + this.getBoxesWidth(newchat)) > body_width) {
+                        const new_id = newchat ? newchat.model.get('id') : null;
                         const oldest_chat = this.getOldestMaximizedChat([new_id]);
                         if (oldest_chat) {
                             // We hide the chat immediately, because waiting
@@ -349,10 +348,12 @@ converse.plugins.add('converse-minimize', {
                                 view.hide();
                             }
                             oldest_chat.minimize();
+                        } else {
+                            break;
                         }
                     }
                 }
-            }, 100),
+            },
 
             getOldestMaximizedChat (exclude_ids) {
                 // Get oldest view (if its id is not excluded)
@@ -452,7 +453,6 @@ converse.plugins.add('converse-minimize', {
                     this.el.classList.add('hidden');
                 } else if (this.keys().length > 0 && !u.isVisible(this.el)) {
                     this.el.classList.remove('hidden');
-                    _converse.chatboxviews.trimChats();
                 }
                 return this.el;
             },
@@ -570,10 +570,11 @@ converse.plugins.add('converse-minimize', {
         }).catch(_.partial(_converse.log, _, Strophe.LogLevel.FATAL));
 
 
-        const trimChats = () => _converse.chatboxviews.trimChats();
-        _converse.api.listen.on('controlBoxOpened', trimChats);
-        _converse.api.listen.on('registeredGlobalEventHandlers', () => window.addEventListener("resize", trimChats));
-        _converse.api.listen.on('unregisteredGlobalEventHandlers', () => window.removeEventListener("resize", trimChats));
+        const debouncedTrimChats = _.debounce(() => _converse.chatboxviews.trimChats(), 250);
+        _converse.api.listen.on('chatBoxInsertedIntoDOM', view => _converse.chatboxviews.trimChats(view));
+        _converse.api.listen.on('controlBoxOpened', view => _converse.chatboxviews.trimChats(view));
+        _converse.api.listen.on('registeredGlobalEventHandlers', () => window.addEventListener("resize", debouncedTrimChats));
+        _converse.api.listen.on('unregisteredGlobalEventHandlers', () => window.removeEventListener("resize", debouncedTrimChats));
         /************************ END Event Handlers ************************/
     }
 });

+ 4 - 3
src/headless/utils/core.js

@@ -199,12 +199,13 @@ u.stringToNode = function (s) {
 };
 
 u.getOuterWidth = function (el, include_margin=false) {
-    var width = el.offsetWidth;
+    let width = el.offsetWidth;
     if (!include_margin) {
         return width;
     }
-    var style = window.getComputedStyle(el);
-    width += parseInt(style.marginLeft, 10) + parseInt(style.marginRight, 10);
+    const style = window.getComputedStyle(el);
+    width += parseInt(style.marginLeft ? style.marginLeft : 0, 10) +
+             parseInt(style.marginRight ? style.marginRight : 0, 10);
     return width;
 };
 

+ 4 - 4
tests/utils.js

@@ -108,10 +108,10 @@
     };
 
     utils.openChatBoxes = function (converse, amount) {
-        var i = 0, jid, views = [];
-        for (i; i<amount; i++) {
-            jid = mock.cur_names[i].replace(/ /g,'.').toLowerCase() + '@montague.lit';
-            views[i] = converse.roster.get(jid).trigger("open");
+        const views = [];
+        for (let i=0; i<amount; i++) {
+            const jid = mock.cur_names[i].replace(/ /g,'.').toLowerCase() + '@montague.lit';
+            views.push(converse.roster.get(jid).trigger("open"));
         }
         return views;
     };