Commit 8a857e39 authored by JC Brand's avatar JC Brand

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.
parent 6de07c5c
......@@ -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",
......
......@@ -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);
......
/*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();
}));
});
});
......@@ -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
......
......@@ -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);
}
......
......@@ -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 ************************/
......
......@@ -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 {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment