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

Don't render hidden chats

JC Brand 4 éve
szülő
commit
4646956922

+ 3 - 0
CHANGES.md

@@ -32,6 +32,9 @@ Removed events:
 * `bookmarkViewsInitialized`
 * `rosterGroupsFetched`
 
+The `chatBoxMaximized` and `chatBoxMinimized` events now have the `model` as
+payload and not the `view` since it might not be exist at that time.
+
 ## 7.0.5 (Unreleased)
 
 - #2377: The @converse/headless NPM package is missing the dist directory, causing import errors

+ 12 - 10
spec/chatbox.js

@@ -119,6 +119,7 @@ describe("Chatboxes", function () {
             await new Promise(resolve => _converse.api.listen.once('chatBoxViewInitialized', resolve));
             await u.waitUntil(() => message_promise);
             expect(_converse.chatboxviews.keys().length).toBe(2);
+            expect(_converse.chatboxviews.keys().pop()).toBe(sender_jid);
             done();
         }));
 
@@ -198,6 +199,7 @@ describe("Chatboxes", function () {
                 mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) {
 
             await mock.waitForRoster(_converse, 'current');
+            await mock.openControlBox(_converse);
             const contact_jid = mock.cur_names[7].replace(/ /g,'.').toLowerCase() + '@montague.lit';
             const rosterview = document.querySelector('converse-roster');
             await u.waitUntil(() => rosterview.querySelectorAll('.roster-group').length);
@@ -372,8 +374,8 @@ describe("Chatboxes", function () {
                     u.waitUntil(() => rosterview.querySelectorAll('.roster-group').length);
                     spyOn(_converse.connection, 'send');
                     await mock.openChatBoxFor(_converse, contact_jid);
-                    const view = _converse.chatboxviews.get(contact_jid);
-                    expect(view.model.get('chat_state')).toBe('active');
+                    const model = _converse.chatboxes.get(contact_jid);
+                    expect(model.get('chat_state')).toBe('active');
                     expect(_converse.connection.send).toHaveBeenCalled();
                     const stanza = _converse.connection.send.calls.argsFor(0)[0].tree();
                     expect(stanza.getAttribute('to')).toBe(contact_jid);
@@ -394,12 +396,12 @@ describe("Chatboxes", function () {
                     const rosterview = document.querySelector('converse-roster');
                     await u.waitUntil(() => rosterview.querySelectorAll('.roster-group').length);
                     await mock.openChatBoxFor(_converse, contact_jid);
-                    const view = _converse.chatboxviews.get(contact_jid);
-                    _converse.minimize.minimize(view.model);
-                    expect(view.model.get('chat_state')).toBe('inactive');
+                    const model = _converse.chatboxes.get(contact_jid);
+                    _converse.minimize.minimize(model);
+                    expect(model.get('chat_state')).toBe('inactive');
                     spyOn(_converse.connection, 'send');
-                    _converse.minimize.maximize(view.model);
-                    await u.waitUntil(() => view.model.get('chat_state') === 'active', 1000);
+                    _converse.minimize.maximize(model);
+                    await u.waitUntil(() => model.get('chat_state') === 'active', 1000);
                     expect(_converse.connection.send).toHaveBeenCalled();
                     const calls = _.filter(_converse.connection.send.calls.all(), function (call) {
                         return call.args[0] instanceof Strophe.Builder;
@@ -427,7 +429,7 @@ describe("Chatboxes", function () {
                     const rosterview = document.querySelector('converse-roster');
                     await u.waitUntil(() => rosterview.querySelectorAll('.roster-group').length);
                     await mock.openChatBoxFor(_converse, contact_jid);
-                    var view = _converse.chatboxviews.get(contact_jid);
+                    const view = _converse.chatboxviews.get(contact_jid);
                     expect(view.model.get('chat_state')).toBe('active');
                     spyOn(_converse.connection, 'send');
                     spyOn(_converse.api, "trigger").and.callThrough();
@@ -468,7 +470,7 @@ describe("Chatboxes", function () {
                     const rosterview = document.querySelector('converse-roster');
                     await u.waitUntil(() => rosterview.querySelectorAll('.roster-group').length);
                     await mock.openChatBoxFor(_converse, contact_jid);
-                    var view = _converse.chatboxviews.get(contact_jid);
+                    const view = _converse.chatboxviews.get(contact_jid);
                     expect(view.model.get('chat_state')).toBe('active');
                     spyOn(_converse.connection, 'send');
                     spyOn(_converse.api, "trigger").and.callThrough();
@@ -1162,7 +1164,7 @@ describe("Chatboxes", function () {
             _converse.handleMessageStanza(msgFactory());
             await u.waitUntil(() => chatbox.messages.length > 1);
             expect(select_msgs_indicator().textContent).toBe('2');
-            _converse.minimize.minimize(view.model);
+            _converse.minimize.maximize(view.model);
             u.waitUntil(() => typeof select_msgs_indicator() === 'undefined');
             done();
         }));

+ 2 - 1
spec/controlbox.js

@@ -227,7 +227,7 @@ describe("The 'Add Contact' widget", function () {
             mock.initConverse([], {'autocomplete_add_contact': false}, async function (done, _converse) {
 
         await mock.waitForRoster(_converse, 'all', 0);
-        mock.openControlBox(_converse);
+        await mock.openControlBox(_converse);
         const cbview = _converse.chatboxviews.get('controlbox');
         cbview.querySelector('.add-contact').click()
         const modal = _converse.api.modal.get('add-contact-modal');
@@ -274,6 +274,7 @@ describe("The 'Add Contact' widget", function () {
         const XMLHttpRequestBackup = window.XMLHttpRequest;
         window.XMLHttpRequest = MockXHR;
 
+        await mock.openControlBox(_converse);
         const cbview = _converse.chatboxviews.get('controlbox');
         cbview.querySelector('.add-contact').click()
         const modal = _converse.api.modal.get('add-contact-modal');

+ 7 - 10
spec/minchats.js

@@ -70,7 +70,7 @@ describe("A chat message", function () {
 
 });
 
-describe("A Groupcaht", function () {
+describe("A Groupchat", function () {
 
     it("can be minimized by clicking a DOM element with class 'toggle-chatbox-button'",
             mock.initConverse(['chatBoxesFetched'], {}, async function (done, _converse) {
@@ -117,7 +117,7 @@ describe("A Chatbox", function () {
         expect(_converse.api.trigger.calls.count(), 2);
         expect(u.isVisible(chatview)).toBeFalsy();
         expect(chatview.model.get('minimized')).toBeTruthy();
-        chatview.querySelector('.toggle-chatbox-button').click();
+        document.querySelector('converse-minimized-chat').click();
 
         await u.waitUntil(() => _converse.chatboxviews.keys().length);
         const minimized_chats = document.querySelector("converse-minimized-chat")
@@ -135,8 +135,7 @@ describe("A Chatbox", function () {
         expect(u.isVisible(minimized_chats.firstElementChild)).toBe(false);
         await _converse.api.chats.create(sender_jid, {'minimized': true});
         await u.waitUntil(() => _converse.chatboxes.length > 1);
-        const view  = _converse.chatboxviews.get(sender_jid);
-        expect(u.isVisible(view)).toBeFalsy();
+        expect(_converse.chatboxviews.get(sender_jid)).toBe(undefined);
         expect(u.isVisible(minimized_chats.firstElementChild)).toBe(true);
         expect(minimized_chats.firstElementChild.querySelectorAll('converse-minimized-chat').length).toBe(1);
         expect(_converse.chatboxes.filter('minimized').length).toBe(1);
@@ -149,7 +148,6 @@ describe("A Chatbox", function () {
         await mock.waitForRoster(_converse, 'current');
         await mock.openControlBox(_converse);
 
-        let jid, chatboxview;
         // openControlBox was called earlier, so the controlbox is
         // visible, but no other chat boxes have been created.
         expect(_converse.chatboxes.length).toEqual(1);
@@ -170,12 +168,11 @@ describe("A Chatbox", function () {
 
         for (i=0; i<online_contacts.length; i++) {
             const el = online_contacts[i];
-            jid = el.textContent.trim().replace(/ /g,'.').toLowerCase() + '@montague.lit';
-            chatboxview = _converse.chatboxviews.get(jid);
-            chatboxview.model.set({'minimized': true});
+            const jid = el.textContent.trim().replace(/ /g,'.').toLowerCase() + '@montague.lit';
+            const model = _converse.chatboxes.get(jid);
+            model.set({'minimized': true});
         }
-        await u.waitUntil(() => _converse.chatboxviews.keys().length);
-        spyOn(_converse.minimize, 'maximize').and.callThrough();
+        await u.waitUntil(() => _converse.chatboxviews.keys().length === 1);
         const minimized_chats = document.querySelector("converse-minimized-chats")
         minimized_chats.querySelector("a.restore-chat").click();
         expect(_converse.minimize.trimChats.calls.count()).toBe(17);

+ 4 - 4
spec/muc-mentions.js

@@ -25,10 +25,10 @@ describe("MUC Mention Notfications", function () {
         await mock.receiveOwnMUCPresence(_converse, muc_jid, nick);
         await muc_creation_promise;
 
-        const view = api.chatviews.get(muc_jid);
-        await u.waitUntil(() => (view.model.session.get('connection_status') === converse.ROOMSTATUS.ENTERED));
-        expect(view.model.get('hidden')).toBe(true);
-        await u.waitUntil(() => view.model.session.get('connection_status') === converse.ROOMSTATUS.DISCONNECTED);
+        const model = _converse.chatboxes.get(muc_jid);
+        await u.waitUntil(() => (model.session.get('connection_status') === converse.ROOMSTATUS.ENTERED));
+        expect(model.get('hidden')).toBe(true);
+        await u.waitUntil(() => model.session.get('connection_status') === converse.ROOMSTATUS.DISCONNECTED);
 
         const room_el = await u.waitUntil(() => document.querySelector("converse-rooms-list .available-chatroom"));
         expect(Array.from(room_el.classList).includes('unread-msgs')).toBeFalsy();

+ 1 - 0
spec/muclist.js

@@ -267,6 +267,7 @@ describe("A groupchat shown in the groupchats list", function () {
         await mock.openChatRoom(_converse, 'lounge', 'conference.shakespeare.lit', 'JC');
         expect(_converse.chatboxes.length).toBe(2);
 
+        await mock.openControlBox(_converse);
         const controlbox = _converse.chatboxviews.get('controlbox');
         const lview = controlbox.querySelector('converse-rooms-list');
         await u.waitUntil(() => lview.querySelectorAll(".open-room").length);

+ 6 - 6
spec/rai.js

@@ -133,9 +133,9 @@ describe("XEP-0437 Room Activity Indicators", function () {
         await mock.receiveOwnMUCPresence(_converse, muc_jid, nick);
         await muc_creation_promise;
 
-        const view = api.chatviews.get(muc_jid);
-        await u.waitUntil(() => (view.model.session.get('connection_status') === converse.ROOMSTATUS.ENTERED));
-        expect(view.model.get('hidden')).toBe(true);
+        const model = _converse.chatboxes.get(muc_jid);
+        await u.waitUntil(() => (model.session.get('connection_status') === converse.ROOMSTATUS.ENTERED));
+        expect(model.get('hidden')).toBe(true);
 
 
         const getSentPresences = () => sent_stanzas.filter(s => s.nodeName === 'presence');
@@ -156,8 +156,8 @@ describe("XEP-0437 Room Activity Indicators", function () {
             `</presence>`
         );
 
-        await u.waitUntil(() => view.model.session.get('connection_status') === converse.ROOMSTATUS.DISCONNECTED);
-        expect(view.model.get('has_activity')).toBe(false);
+        await u.waitUntil(() => model.session.get('connection_status') === converse.ROOMSTATUS.DISCONNECTED);
+        expect(model.get('has_activity')).toBe(false);
 
         const room_el = await u.waitUntil(() => document.querySelector("converse-rooms-list .available-chatroom"));
         expect(Array.from(room_el.classList).includes('unread-msgs')).toBeFalsy();
@@ -171,7 +171,7 @@ describe("XEP-0437 Room Activity Indicators", function () {
         `);
         _converse.connection._dataRecv(mock.createRequest(activity_stanza));
 
-        await u.waitUntil(() => view.model.get('has_activity'));
+        await u.waitUntil(() => model.get('has_activity'));
         expect(Array.from(room_el.classList).includes('unread-msgs')).toBeTruthy();
         done();
     }));

+ 5 - 5
spec/roster.js

@@ -322,7 +322,7 @@ describe("The Contacts Roster", function () {
             _converse.roster.get(jid).presence.set('show', 'online');
             jid = mock.cur_names[4].replace(/ /g,'.').toLowerCase() + '@montague.lit';
             _converse.roster.get(jid).presence.set('show', 'dnd');
-            mock.openControlBox(_converse);
+            await mock.openControlBox(_converse);
             const rosterview = document.querySelector('converse-roster');
             const button = rosterview.querySelector('span[data-type="state"]');
             button.click();
@@ -488,7 +488,7 @@ describe("The Contacts Roster", function () {
 
             await mock.waitForRoster(_converse, 'current', 0);
             const groups = ['Colleagues', 'friends'];
-            mock.openControlBox(_converse);
+            await mock.openControlBox(_converse);
             for (let i=0; i<mock.cur_names.length; i++) {
                 _converse.roster.create({
                     jid: mock.cur_names[i].replace(/ /g,'.').toLowerCase() + '@montague.lit',
@@ -514,7 +514,7 @@ describe("The Contacts Roster", function () {
                 mock.initConverse([], {}, async function (done, _converse) {
 
             await mock.waitForRoster(_converse, 'current', 0);
-            mock.openControlBox(_converse);
+            await mock.openControlBox(_converse);
 
             let i=0, j=0;
             const groups = {
@@ -568,8 +568,8 @@ describe("The Contacts Roster", function () {
                 async function (done, _converse) {
 
             await mock.waitForRoster(_converse, 'all', 0);
-            const rosterview = document.querySelector('converse-roster');
             await mock.openControlBox(_converse);
+            const rosterview = document.querySelector('converse-roster');
             _converse.roster.create({
                 jid: mock.pend_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit',
                 subscription: 'none',
@@ -1072,7 +1072,7 @@ describe("The Contacts Roster", function () {
                 async function (done, _converse) {
 
             await mock.waitForRoster(_converse, "current", 0);
-            mock.openControlBox(_converse);
+            await mock.openControlBox(_converse);
             let names = [];
             const addName = function (item) {
                 if (!u.hasClass('request-actions', item)) {

+ 11 - 4
src/plugins/chatboxviews/templates/chats.js

@@ -2,6 +2,13 @@ import { html } from 'lit-html';
 import { repeat } from 'lit-html/directives/repeat.js';
 import { _converse, api } from '@converse/headless/core';
 
+
+function shouldShowChat (c) {
+    const { CONTROLBOX_TYPE } = _converse;
+    return c.get('type') === CONTROLBOX_TYPE || !(c.get('hidden') || c.get('minimized'));
+}
+
+
 export default () => {
     const { chatboxes, CONTROLBOX_TYPE, CHATROOMS_TYPE, HEADLINES_TYPE } = _converse;
     const view_mode = api.settings.get('view_mode');
@@ -9,7 +16,7 @@ export default () => {
     const logged_out = !connection?.connected || !connection?.authenticated || connection?.disconnecting;
     return html`
         ${view_mode === 'overlayed' ? html`<converse-minimized-chats></converse-minimized-chats>` : ''}
-        ${repeat(chatboxes, m => m.get('jid'), m => {
+        ${repeat(chatboxes.filter(shouldShowChat), m => m.get('jid'), m => {
             if (m.get('type') === CONTROLBOX_TYPE) {
                 return html`
                     ${view_mode === 'overlayed' ? html`<converse-controlbox-toggle class="${!m.get('closed') ? 'hidden' : ''}"></converse-controlbox-toggle>` : ''}
@@ -20,15 +27,15 @@ export default () => {
                 `;
             } else if (m.get('type') === CHATROOMS_TYPE) {
                 return html`
-                    <converse-muc jid="${m.get('jid')}" class="chatbox chatroom ${(m.get('hidden') || m.get('minimized')) ? 'hidden' : ''}"></converse-muc>
+                    <converse-muc jid="${m.get('jid')}" class="chatbox chatroom"></converse-muc>
                 `;
             } else if (m.get('type') === HEADLINES_TYPE) {
                 return html`
-                    <converse-headlines jid="${m.get('jid')}" class="chatbox headlines ${(m.get('hidden') || m.get('minimized')) ? 'hidden' : ''}"></converse-headlines>
+                    <converse-headlines jid="${m.get('jid')}" class="chatbox headlines"></converse-headlines>
                 `;
             } else {
                 return html`
-                    <converse-chat jid="${m.get('jid')}" class="chatbox ${(m.get('hidden') || m.get('minimized')) ? 'hidden' : ''}"></converse-chat>
+                    <converse-chat jid="${m.get('jid')}" class="chatbox"></converse-chat>
                 `;
             }
         })}

+ 6 - 6
src/plugins/minimize/index.js

@@ -118,17 +118,17 @@ converse.plugins.add('converse-minimize', {
         _converse.minimize.minimize = minimize;
         _converse.minimize.maximize = maximize;
 
+        function onChatInitialized (model) {
+            model.on( 'change:minimized', () => onMinimizedChanged(model));
+        }
+
         /************************ BEGIN Event Handlers ************************/
         api.listen.on('chatBoxViewInitialized', view => _converse.minimize.trimChats(view));
         api.listen.on('chatRoomViewInitialized', view => _converse.minimize.trimChats(view));
         api.listen.on('chatBoxMaximized', view => _converse.minimize.trimChats(view));
         api.listen.on('controlBoxOpened', view => _converse.minimize.trimChats(view));
-        api.listen.on('chatBoxViewInitialized', v => v.listenTo(v.model, 'change:minimized', () => onMinimizedChanged(v)));
-
-        api.listen.on('chatRoomViewInitialized', view => {
-            view.listenTo(view.model, 'change:minimized', () => onMinimizedChanged(view));
-            view.model.get('minimized') && view.hide();
-        });
+        api.listen.on('chatBoxInitialized', onChatInitialized);
+        api.listen.on('chatRoomInitialized', onChatInitialized);
 
         api.listen.on('getHeadingButtons', (view, buttons) => {
             if (view.model.get('type') === _converse.CHATROOMS_TYPE) {

+ 24 - 25
src/plugins/minimize/utils.js

@@ -145,13 +145,23 @@ export function maximize (ev, chatbox) {
     });
 }
 
-export function minimize (ev, chatbox) {
+export function minimize (ev, model) {
     if (ev?.preventDefault) {
         ev.preventDefault();
     } else {
-        chatbox = ev;
+        model = ev;
     }
-    u.safeSave(chatbox, {
+    // save the scroll position to restore it on maximize
+    const view = _converse.chatboxviews.get(model.get('jid'));
+    const content = view.querySelector('.chat-content__messages');
+    const scroll = content.scrollTop;
+    if (model.collection && model.collection.browserStorage) {
+        model.save({ scroll });
+    } else {
+        model.set({ scroll });
+    }
+    model.setChatState(_converse.INACTIVE);
+    u.safeSave(model, {
         'hidden': true,
         'minimized': true,
         'time_minimized': new Date().toISOString()
@@ -165,20 +175,18 @@ export function minimize (ev, chatbox) {
  * Will trigger {@link _converse#chatBoxMaximized}
  * @returns {_converse.ChatBoxView|_converse.ChatRoomView}
  */
-function onMaximized (view) {
-    if (!view.model.isScrolledUp()) {
-        view.model.clearUnreadMsgCounter();
+function onMaximized (model) {
+    if (!model.isScrolledUp()) {
+        model.clearUnreadMsgCounter();
     }
-    view.model.setChatState(_converse.ACTIVE);
-    view.show();
+    model.setChatState(_converse.ACTIVE);
     /**
      * Triggered when a previously minimized chat gets maximized
      * @event _converse#chatBoxMaximized
      * @type { _converse.ChatBoxView }
      * @example _converse.api.listen.on('chatBoxMaximized', view => { ... });
      */
-    api.trigger('chatBoxMaximized', view);
-    return view;
+    api.trigger('chatBoxMaximized', model);
 }
 
 /**
@@ -188,29 +196,20 @@ function onMaximized (view) {
  * Will trigger {@link _converse#chatBoxMinimized}
  * @returns {_converse.ChatBoxView|_converse.ChatRoomView}
  */
-function onMinimized (view) {
-    // save the scroll position to restore it on maximize
-    const content = view.querySelector('.chat-content__messages');
-    if (view.model.collection && view.model.collection.browserStorage) {
-        view.model.save({ 'scroll': content.scrollTop });
-    } else {
-        view.model.set({ 'scroll': content.scrollTop });
-    }
-    view.model.setChatState(_converse.INACTIVE);
+function onMinimized (model) {
     /**
      * Triggered when a previously maximized chat gets Minimized
      * @event _converse#chatBoxMinimized
      * @type { _converse.ChatBoxView }
      * @example _converse.api.listen.on('chatBoxMinimized', view => { ... });
      */
-    api.trigger('chatBoxMinimized', view);
-    return view;
+    api.trigger('chatBoxMinimized', model);
 }
 
-export function onMinimizedChanged (view) {
-    if (view.model.get('minimized')) {
-        onMinimized(view);
+export function onMinimizedChanged (model) {
+    if (model.get('minimized')) {
+        onMinimized(model);
     } else {
-        onMaximized(view);
+        onMaximized(model);
     }
 }

+ 7 - 1
src/shared/chat/baseview.js

@@ -13,6 +13,12 @@ export default class BaseChatView extends ElementView {
         this.debouncedScrollDown = debounce(this.scrollDown, 100);
     }
 
+    disconnectedCallback () {
+        super.disconnectedCallback();
+        const jid = this.getAttribute('jid');
+        _converse.chatboxviews.remove(jid, this);
+    }
+
     hideNewMessagesIndicator () {
         const new_msgs_indicator = this.querySelector('.new-msgs-indicator');
         if (new_msgs_indicator !== null) {
@@ -195,7 +201,7 @@ export default class BaseChatView extends ElementView {
                 'scrollTop': null
             });
         }
-        this.querySelector('.chat-content__messages').scrollDown();
+        this.querySelector('.chat-content__messages')?.scrollDown();
         this.onScrolledDown();
     }