Browse Source

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 years ago
parent
commit
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 {