Pārlūkot izejas kodu

Move tab update to notification plugin

Updating tab notifications is not something that should be done in the headless part of Converse.
Don't update the tab title, having a favicon is enough.
JC Brand 4 gadi atpakaļ
vecāks
revīzija
8a857e39f4

+ 12 - 5
package-lock.json

@@ -3144,7 +3144,8 @@
 			"dependencies": {
 				"filesize": {
 					"version": "6.1.0",
-					"resolved": false
+					"resolved": "https://registry.npmjs.org/filesize/-/filesize-6.1.0.tgz",
+					"integrity": "sha512-LpCHtPQ3sFx67z+uh2HnSyWSLLu5Jxo21795uRDuar/EOuYWXib5EmPaGIBuSnRqH2IODiKA2k5re/K9OnN/Yg=="
 				},
 				"fs-extra": {
 					"version": "8.1.0",
@@ -3200,20 +3201,22 @@
 				},
 				"localforage": {
 					"version": "1.7.3",
-					"resolved": false,
+					"resolved": "https://registry.npmjs.org/localforage/-/localforage-1.7.3.tgz",
+					"integrity": "sha512-1TulyYfc4udS7ECSBT2vwJksWbkwwTX8BzeUIiq8Y07Riy7bDAAnxDaPU/tWyOVmQAcWJIEIFP9lPfBGqVoPgQ==",
 					"requires": {
 						"lie": "3.1.1"
 					}
 				},
 				"pluggable.js": {
 					"version": "2.0.1",
-					"resolved": false,
+					"resolved": "https://registry.npmjs.org/pluggable.js/-/pluggable.js-2.0.1.tgz",
+					"integrity": "sha512-SBt6v6Tbp20Jf8hU0cpcc/+HBHGMY8/Q+yA6Ih0tBQE8tfdZ6U4PRG0iNvUUjLx/hVyOP53n0UfGBymlfaaXCg==",
 					"requires": {
 						"lodash": "^4.17.11"
 					}
 				},
 				"skeletor.js": {
-					"version": "0.0.1",
+					"version": "github:skeletorjs/skeletor#bf6d9c86f9fcf224fa9d9af5a25380b77aa4b561",
 					"from": "github:skeletorjs/skeletor#bf6d9c86f9fcf224fa9d9af5a25380b77aa4b561",
 					"requires": {
 						"lodash": "^4.17.14"
@@ -3221,7 +3224,11 @@
 				},
 				"strophe.js": {
 					"version": "github:strophe/strophejs#c4a94e59877c06dc2395f4ccbd26f3fee67a4c9f",
-					"from": "strophe.js@github:strophe/strophejs#c4a94e59877c06dc2395f4ccbd26f3fee67a4c9f"
+					"from": "strophe.js@github:strophe/strophejs#c4a94e59877c06dc2395f4ccbd26f3fee67a4c9f",
+					"requires": {
+						"abab": "^2.0.3",
+						"xmldom": "^0.1.27"
+					}
 				},
 				"twemoji": {
 					"version": "12.1.5",

+ 2 - 139
spec/chatbox.js

@@ -1047,143 +1047,6 @@ describe("Chatboxes", function () {
         }));
     });
 
-    describe("A Message Counter", function () {
-
-        it("is incremented when the message is received and the window is not focused",
-                mock.initConverse(
-                    ['rosterGroupsFetched'], {},
-                    async function (done, _converse) {
-
-            await mock.waitForRoster(_converse, 'current');
-            await mock.openControlBox(_converse);
-
-            expect(document.title).toBe('Converse Tests');
-            
-            _converse.api.settings.set('update_title', false);
-            const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
-            const previous_state = _converse.windowState;
-            const msg = $msg({
-                    from: sender_jid,
-                    to: _converse.connection.jid,
-                    type: 'chat',
-                    id: u.getUniqueId()
-                }).c('body').t('This message will increment the message counter').up()
-                  .c('active', {'xmlns': Strophe.NS.CHATSTATES}).tree();
-            _converse.windowState = 'hidden';
-
-            spyOn(_converse.api, "trigger").and.callThrough();
-            spyOn(_converse, 'incrementMsgCounter').and.callThrough();
-            spyOn(_converse, 'clearMsgCounter').and.callThrough();
-
-            await _converse.handleMessageStanza(msg);
-            expect(_converse.incrementMsgCounter).toHaveBeenCalled();
-            expect(_converse.clearMsgCounter).not.toHaveBeenCalled();
-            expect(document.title).toBe('Converse Tests');
-            expect(_converse.api.trigger).toHaveBeenCalledWith('message', jasmine.any(Object));
-            
-            _converse.api.settings.set('update_title', true);
-            const msg2 = $msg({
-                    from: sender_jid,
-                    to: _converse.connection.jid,
-                    type: 'chat',
-                    id: u.getUniqueId()
-                }).c('body').t('This message increment the message counter AND update the page title').up()
-                  .c('active', {'xmlns': Strophe.NS.CHATSTATES}).tree();
-
-            await _converse.handleMessageStanza(msg2);
-            expect(document.title).toBe('Messages (2) Converse Tests');
-
-            _converse.windowSate = previous_state;
-            done();
-        }));
-
-        it("is cleared when the window is focused",
-            mock.initConverse(
-                ['rosterGroupsFetched'], {},
-                async function (done, _converse) {
-
-            await mock.waitForRoster(_converse, 'current');
-            await mock.openControlBox(_converse);
-            _converse.windowState = 'hidden';
-            spyOn(_converse, 'clearMsgCounter').and.callThrough();
-            _converse.saveWindowState(null, 'focus');
-            _converse.saveWindowState(null, 'blur');
-            expect(_converse.clearMsgCounter).toHaveBeenCalled();
-            done();
-        }));
-
-        it("is not incremented when the message is received and the window is focused",
-            mock.initConverse(
-                ['rosterGroupsFetched'], {},
-                async function (done, _converse) {
-
-            await mock.waitForRoster(_converse, 'current');
-            await mock.openControlBox(_converse);
-
-            expect(document.title).toBe('Converse Tests');
-            spyOn(_converse, 'incrementMsgCounter').and.callThrough();
-            _converse.saveWindowState(null, 'focus');
-            const message = 'This message will not increment the message counter';
-            const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit',
-                msg = $msg({
-                    from: sender_jid,
-                    to: _converse.connection.jid,
-                    type: 'chat',
-                    id: u.getUniqueId()
-                }).c('body').t(message).up()
-                  .c('active', {'xmlns': Strophe.NS.CHATSTATES}).tree();
-            await _converse.handleMessageStanza(msg);
-            expect(_converse.incrementMsgCounter).not.toHaveBeenCalled();
-            expect(document.title).toBe('Converse Tests');
-            done();
-        }));
-
-        it("is incremented from zero when chatbox was closed after viewing previously received messages and the window is not focused now",
-            mock.initConverse(
-                ['rosterGroupsFetched'], {},
-                async function (done, _converse) {
-
-            await mock.waitForRoster(_converse, 'current');
-            // initial state
-            expect(document.title).toBe('Converse Tests');
-            const message = 'This message will always increment the message counter from zero',
-                sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit',
-                msgFactory = function () {
-                    return $msg({
-                        from: sender_jid,
-                        to: _converse.connection.jid,
-                        type: 'chat',
-                        id: u.getUniqueId()
-                    })
-                    .c('body').t(message).up()
-                    .c('active', {'xmlns': Strophe.NS.CHATSTATES})
-                    .tree();
-             };
-
-            // leave converse-chat page
-            _converse.windowState = 'hidden';
-            await _converse.handleMessageStanza(msgFactory());
-            let view = _converse.chatboxviews.get(sender_jid);
-            expect(document.title).toBe('Messages (1) Converse Tests');
-
-            // come back to converse-chat page
-            _converse.saveWindowState(null, 'focus');
-            await u.waitUntil(() => u.isVisible(view.el));
-            expect(document.title).toBe('Converse Tests');
-
-            // close chatbox and leave converse-chat page again
-            view.close();
-            _converse.windowState = 'hidden';
-
-            // check that msg_counter is incremented from zero again
-            await _converse.handleMessageStanza(msgFactory());
-            view = _converse.chatboxviews.get(sender_jid);
-            await u.waitUntil(() => u.isVisible(view.el));
-            expect(document.title).toBe('Messages (1) Converse Tests');
-            done();
-        }));
-    });
-
     describe("A ChatBox's Unread Message Count", function () {
 
         it("is incremented when the message is received and ChatBoxView is scrolled up",
@@ -1307,7 +1170,7 @@ describe("Chatboxes", function () {
             expect(chatbox.get('first_unread_id')).toBe(msgid);
             await u.waitUntil(() => chatbox.sendMarker.calls.count() === 1);
             expect(sent_stanzas[0].nodeTree.querySelector('received')).toBeDefined();
-            _converse.saveWindowState(null, 'focus');
+            _converse.saveWindowState({'type': 'focus'});
             expect(chatbox.get('num_unread')).toBe(0);
             await u.waitUntil(() => chatbox.sendMarker.calls.count() === 2);
             expect(sent_stanzas[1].nodeTree.querySelector('displayed')).toBeDefined();
@@ -1337,7 +1200,7 @@ describe("Chatboxes", function () {
             expect(chatbox.get('first_unread_id')).toBe(msgid);
             await u.waitUntil(() => chatbox.sendMarker.calls.count() === 1);
             expect(sent_stanzas[0].nodeTree.querySelector('received')).toBeDefined();
-            _converse.saveWindowState(null, 'focus');
+            _converse.saveWindowState({'type': 'focus'});
             await u.waitUntil(() => chatbox.get('num_unread') === 1);
             expect(chatbox.get('first_unread_id')).toBe(msgid);
             await u.waitUntil(() => chatbox.sendMarker.calls.count() === 1);

+ 143 - 1
spec/notification.js

@@ -1,6 +1,6 @@
 /*global mock, converse */
 
-const _ = converse.env._;
+const { Strophe, _ } = converse.env;
 const $msg = converse.env.$msg;
 const u = converse.env.utils;
 
@@ -222,4 +222,146 @@ describe("Notifications", function () {
             }));
         });
     });
+
+
+    describe("A Favicon Message Counter", function () {
+
+        it("is incremented when the message is received and the window is not focused",
+                mock.initConverse(
+                    ['rosterGroupsFetched'], {'update_title': false},
+                    async function (done, _converse) {
+
+            await mock.waitForRoster(_converse, 'current');
+            await mock.openControlBox(_converse);
+
+            const favico = jasmine.createSpyObj('favico', ['badge']);
+            spyOn(converse.env, 'Favico').and.returnValue(favico);
+
+            const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
+            const previous_state = _converse.windowState;
+            const msg = $msg({
+                    from: sender_jid,
+                    to: _converse.connection.jid,
+                    type: 'chat',
+                    id: u.getUniqueId()
+                }).c('body').t('This message will increment the message counter').up()
+                  .c('active', {'xmlns': Strophe.NS.CHATSTATES}).tree();
+            _converse.windowState = 'hidden';
+
+            spyOn(_converse.api, "trigger").and.callThrough();
+
+            await _converse.handleMessageStanza(msg);
+            expect(_converse.api.trigger).toHaveBeenCalledWith('message', jasmine.any(Object));
+
+            expect(favico.badge.calls.count()).toBe(0);
+
+            _converse.api.settings.set('update_title', true);
+            const msg2 = $msg({
+                    from: sender_jid,
+                    to: _converse.connection.jid,
+                    type: 'chat',
+                    id: u.getUniqueId()
+                }).c('body').t('This message increment the message counter AND update the page title').up()
+                  .c('active', {'xmlns': Strophe.NS.CHATSTATES}).tree();
+
+            await _converse.handleMessageStanza(msg2);
+            await u.waitUntil(() => favico.badge.calls.count() === 1);
+            expect(favico.badge.calls.mostRecent().args.pop()).toBe(2);
+
+            const view = _converse.chatboxviews.get(sender_jid);
+            expect(view.model.get('num_unread')).toBe(2);
+
+            // Check that it's cleared when the window is focused
+            _converse.windowState = 'hidden';
+            _converse.saveWindowState({'type': 'focus'});
+            await u.waitUntil(() => favico.badge.calls.count() === 2);
+            expect(favico.badge.calls.mostRecent().args.pop()).toBe(0);
+
+            expect(view.model.get('num_unread')).toBe(0);
+            _converse.windowSate = previous_state;
+            done();
+        }));
+
+        it("is not incremented when the message is received and the window is focused",
+            mock.initConverse(
+                ['rosterGroupsFetched'], {},
+                async function (done, _converse) {
+
+            await mock.waitForRoster(_converse, 'current');
+            await mock.openControlBox(_converse);
+
+            const favico = jasmine.createSpyObj('favico', ['badge']);
+            spyOn(converse.env, 'Favico').and.returnValue(favico);
+
+            _converse.saveWindowState({'type': 'focus'});
+            const message = 'This message will not increment the message counter';
+            const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit',
+                msg = $msg({
+                    from: sender_jid,
+                    to: _converse.connection.jid,
+                    type: 'chat',
+                    id: u.getUniqueId()
+                }).c('body').t(message).up()
+                  .c('active', {'xmlns': Strophe.NS.CHATSTATES}).tree();
+            await _converse.handleMessageStanza(msg);
+
+            setTimeout(() => {
+                const view = _converse.chatboxviews.get(sender_jid);
+                expect(view.model.get('num_unread')).toBe(0);
+                expect(favico.badge.calls.count()).toBe(0);
+                done();
+            }, 500);
+        }));
+
+        it("is incremented from zero when chatbox was closed after viewing previously received messages and the window is not focused now",
+            mock.initConverse(
+                ['rosterGroupsFetched'], {},
+                async function (done, _converse) {
+
+            await mock.waitForRoster(_converse, 'current');
+
+            const favico = jasmine.createSpyObj('favico', ['badge']);
+            spyOn(converse.env, 'Favico').and.returnValue(favico);
+
+            const message = 'This message will always increment the message counter from zero';
+            const sender_jid = mock.cur_names[0].replace(/ /g,'.').toLowerCase() + '@montague.lit';
+            const msgFactory = function () {
+                    return $msg({
+                        from: sender_jid,
+                        to: _converse.connection.jid,
+                        type: 'chat',
+                        id: u.getUniqueId()
+                    })
+                    .c('body').t(message).up()
+                    .c('active', {'xmlns': Strophe.NS.CHATSTATES})
+                    .tree();
+             };
+
+            // leave converse-chat page
+            _converse.windowState = 'hidden';
+            await _converse.handleMessageStanza(msgFactory());
+            let view = _converse.chatboxviews.get(sender_jid);
+            await u.waitUntil(() => favico.badge.calls.count() === 1, 1000);
+            expect(favico.badge.calls.mostRecent().args.pop()).toBe(1);
+
+            // come back to converse-chat page
+            _converse.saveWindowState({'type': 'focus'});
+            await u.waitUntil(() => u.isVisible(view.el));
+            await u.waitUntil(() => favico.badge.calls.count() === 2);
+            expect(favico.badge.calls.mostRecent().args.pop()).toBe(0);
+
+            // close chatbox and leave converse-chat page again
+            view.close();
+            _converse.windowState = 'hidden';
+
+            // check that msg_counter is incremented from zero again
+            await _converse.handleMessageStanza(msgFactory());
+            view = _converse.chatboxviews.get(sender_jid);
+            await u.waitUntil(() => u.isVisible(view.el));
+            await u.waitUntil(() => favico.badge.calls.count() === 3);
+            expect(favico.badge.calls.mostRecent().args.pop()).toBe(1);
+            done();
+        }));
+    });
+
 });

+ 21 - 0
src/converse-notification.js

@@ -3,6 +3,7 @@
  * @copyright 2020, the Converse.js contributors
  * @license Mozilla Public License (MPLv2)
  */
+import Favico from 'favico.js-slevomat';
 import log from "@converse/headless/log";
 import { __ } from './i18n';
 import { _converse, api, converse } from "@converse/headless/converse-core";
@@ -12,6 +13,18 @@ const u = converse.env.utils;
 
 const supports_html5_notification = "Notification" in window;
 
+converse.env.Favico = Favico;
+let favicon;
+
+function updateUnreadFavicon () {
+    if (api.settings.get('update_title')) {
+        favicon = favicon ?? new converse.env.Favico({type: 'circle', animation: 'pop'});
+        const chats = _converse.chatboxes.models;
+        const num_unread = chats.reduce((acc, chat) => (acc + (chat.get('num_unread') || 0)), 0);
+        favicon.badge(num_unread);
+    }
+}
+
 
 converse.plugins.add('converse-notification', {
 
@@ -23,6 +36,7 @@ converse.plugins.add('converse-notification', {
          */
 
         api.settings.extend({
+            update_title: true,
             notify_all_room_messages: false,
             show_desktop_notifications: true,
             show_chat_state_notifications: false,
@@ -298,6 +312,13 @@ converse.plugins.add('converse-notification', {
             }
         };
 
+        /************************ BEGIN Event Handlers ************************/
+
+        api.listen.on('clearSession', () => (favicon = null)); // Needed for tests
+
+        api.waitUntil('chatBoxesInitialized').then(
+            () => _converse.chatboxes.on('change:num_unread', updateUnreadFavicon));
+
         api.listen.on('pluginsInitialized', function () {
             // We only register event handlers after all plugins are
             // registered, because other plugins might override some of our

+ 0 - 1
src/headless/converse-chat.js

@@ -1205,7 +1205,6 @@ converse.plugins.add('converse-chat', {
                             settings['first_unread_id'] = message.get('id');
                         }
                         this.save(settings);
-                        _converse.incrementMsgCounter();
                     } else {
                         this.sendMarkerForMessage(message);
                     }

+ 2 - 42
src/headless/converse-chatboxes.js

@@ -7,7 +7,6 @@ import "./converse-emoji";
 import { Collection } from "@converse/skeletor/src/collection";
 import { _converse, api, converse } from "./converse-core";
 import log from "./log";
-import Favico from 'favico.js-slevomat';
 
 const { Strophe } = converse.env;
 
@@ -32,44 +31,6 @@ converse.plugins.add('converse-chatboxes', {
             'privateChatsAutoJoined'
         ]);
 
-        api.settings.extend({
-            'update_title': true
-        });
-
-        let msg_counter = 0;
-        const favicon = new Favico({type : 'circle', position: 'up', animation: 'none'});
-
-        _converse.incrementMsgCounter = function () {
-            msg_counter += 1;
-            favicon.badge(msg_counter);
-            if (api.settings.get('update_title')) {
-                const title = document.title;
-                if (!title) {
-                    return;
-                }
-                if (title.search(/^Messages \(\d+\) /) === -1) {
-                    document.title = `Messages (${msg_counter}) ${title}`;
-                } else {
-                    document.title = title.replace(/^Messages \(\d+\) /, `Messages (${msg_counter}) `);
-                }
-            }
-        };
-
-        _converse.clearMsgCounter = function () {
-            msg_counter = 0;
-            favicon.badge(msg_counter);
-            if (api.settings.get('update_title')) {
-                const title = document.title;
-                if (!title) {
-                    return;
-                }
-                if (title.search(/^Messages \(\d+\) /) !== -1) {
-                    document.title = title.replace(/^Messages \(\d+\) /, "");
-                }
-            }
-        };
-
-
         _converse.ChatBoxes = Collection.extend({
             comparator: 'time_opened',
 
@@ -80,12 +41,12 @@ converse.plugins.add('converse-chatboxes', {
             onChatBoxesFetched (collection) {
                 collection.filter(c => !c.isValid()).forEach(c => c.destroy());
                 /**
-                 * Triggered when a message stanza is been received and processed.
+                 * Triggered once all chat boxes have been recreated from the browser cache
                  * @event _converse#chatBoxesFetched
                  * @type { object }
                  * @property { _converse.ChatBox | _converse.ChatRoom } chatbox
                  * @property { XMLElement } stanza
-                 * @example _converse.api.listen.on('message', obj => { ... });
+                 * @example _converse.api.listen.on('chatBoxesFetched', obj => { ... });
                  * @example _converse.api.waitUntil('chatBoxesFetched').then(() => { ... });
                  */
                 api.trigger('chatBoxesFetched');
@@ -141,7 +102,6 @@ converse.plugins.add('converse-chatboxes', {
 
         api.listen.on('presencesInitialized', (reconnecting) => _converse.chatboxes.onConnected(reconnecting));
         api.listen.on('reconnected', () => _converse.chatboxes.forEach(m => m.onReconnection()));
-        api.listen.on('windowStateChanged', d => (d.state === 'visible') && _converse.clearMsgCounter());
         /************************ END Event Handlers ************************/
 
 

+ 1 - 2
src/headless/converse-muc.js

@@ -1143,7 +1143,7 @@ converse.plugins.add('converse-muc', {
              */
             getDiscoInfo () {
                 return api.disco.getIdentity('conference', 'text', this.get('jid'))
-                    .then(identity => this.save({'name': identity && identity.get('name')}))
+                    .then(identity => this.save({'name': identity?.get('name')}))
                     .then(() => this.getDiscoInfoFields())
                     .then(() => this.getDiscoInfoFeatures())
                     .catch(e => log.error(e));
@@ -2428,7 +2428,6 @@ converse.plugins.add('converse-muc', {
                         }
                         if (this.isUserMentioned(message)) {
                             settings.num_unread = this.get('num_unread') + 1;
-                            _converse.incrementMsgCounter();
                         }
                         this.save(settings);
                     } else {