Commit d9c5867f authored by JC Brand's avatar JC Brand

Check references when incrementing unread messages counter

parent b7eb19e2
...@@ -2168,14 +2168,14 @@ ...@@ -2168,14 +2168,14 @@
expect(references.length).toBe(1); expect(references.length).toBe(1);
expect(text).toBe('hello z3r0'); expect(text).toBe('hello z3r0');
expect(JSON.stringify(references)) expect(JSON.stringify(references))
.toBe('[{"begin":6,"end":10,"type":"mention","uri":"xmpp:z3r0@localhost"}]'); .toBe('[{"begin":6,"end":10,"value":"z3r0","type":"mention","uri":"xmpp:z3r0@localhost"}]');
[text, references] = view.model.parseTextForReferences('hello @some1 @z3r0 @gibson @mr.robot, how are you?') [text, references] = view.model.parseTextForReferences('hello @some1 @z3r0 @gibson @mr.robot, how are you?')
expect(text).toBe('hello @some1 z3r0 gibson mr.robot, how are you?'); expect(text).toBe('hello @some1 z3r0 gibson mr.robot, how are you?');
expect(JSON.stringify(references)) expect(JSON.stringify(references))
.toBe('[{"begin":13,"end":17,"type":"mention","uri":"xmpp:z3r0@localhost"},'+ .toBe('[{"begin":13,"end":17,"value":"z3r0","type":"mention","uri":"xmpp:z3r0@localhost"},'+
'{"begin":18,"end":24,"type":"mention","uri":"xmpp:gibson@localhost"},'+ '{"begin":18,"end":24,"value":"gibson","type":"mention","uri":"xmpp:gibson@localhost"},'+
'{"begin":25,"end":33,"type":"mention","uri":"xmpp:mr.robot@localhost"}]'); '{"begin":25,"end":33,"value":"mr.robot","type":"mention","uri":"xmpp:mr.robot@localhost"}]');
[text, references] = view.model.parseTextForReferences('yo @gib') [text, references] = view.model.parseTextForReferences('yo @gib')
expect(text).toBe('yo @gib'); expect(text).toBe('yo @gib');
...@@ -2189,7 +2189,7 @@ ...@@ -2189,7 +2189,7 @@
expect(text).toBe('gibson'); expect(text).toBe('gibson');
expect(references.length).toBe(1); expect(references.length).toBe(1);
expect(JSON.stringify(references)) expect(JSON.stringify(references))
.toBe('[{"begin":0,"end":6,"type":"mention","uri":"xmpp:gibson@localhost"}]'); .toBe('[{"begin":0,"end":6,"value":"gibson","type":"mention","uri":"xmpp:gibson@localhost"}]');
done(); done();
return; return;
......
...@@ -2,8 +2,9 @@ ...@@ -2,8 +2,9 @@
define(["jquery", "jasmine", "mock", "test-utils"], factory); define(["jquery", "jasmine", "mock", "test-utils"], factory);
} (this, function ($, jasmine, mock, test_utils) { } (this, function ($, jasmine, mock, test_utils) {
"use strict"; "use strict";
var _ = converse.env._; const Strophe = converse.env.Strophe,
var $msg = converse.env.$msg; _ = converse.env._,
$msg = converse.env.$msg;
describe("Notifications", function () { describe("Notifications", function () {
// Implement the protocol defined in https://xmpp.org/extensions/xep-0313.html#config // Implement the protocol defined in https://xmpp.org/extensions/xep-0313.html#config
...@@ -74,7 +75,7 @@ ...@@ -74,7 +75,7 @@
delete window.Notification; delete window.Notification;
} }
done(); done();
}); }).catch(_.partial(_converse.log, _, Strophe.LogLevel.FATAL));
})); }));
it("is shown for headline messages", it("is shown for headline messages",
......
...@@ -224,69 +224,64 @@ ...@@ -224,69 +224,64 @@
})); }));
it("shows unread messages directed at the user", mock.initConverseWithAsync( it("shows unread messages directed at the user", mock.initConverseWithAsync(
{ whitelisted_plugins: ['converse-roomslist'], { whitelisted_plugins: ['converse-roomslist'],
allow_bookmarks: false // Makes testing easier, otherwise we allow_bookmarks: false // Makes testing easier, otherwise we
// have to mock stanza traffic. // have to mock stanza traffic.
}, function (done, _converse) { }, function (done, _converse) {
test_utils.waitUntil(function () { test_utils.waitUntil(() => !_.isUndefined(_converse.rooms_list_view), 500)
return !_.isUndefined(_converse.rooms_list_view) .then(() => test_utils.openAndEnterChatRoom(_converse, 'kitchen', 'conference.shakespeare.lit', 'romeo'))
}, 500) .then(() => {
.then(function () { const room_jid = 'kitchen@conference.shakespeare.lit';
var room_jid = 'kitchen@conference.shakespeare.lit'; const view = _converse.chatboxviews.get(room_jid);
test_utils.openAndEnterChatRoom( view.model.set({'minimized': true});
_converse, 'kitchen', 'conference.shakespeare.lit', 'romeo').then(function () { const contact_jid = mock.cur_names[5].replace(/ /g,'.').toLowerCase() + '@localhost';
const nick = mock.chatroom_names[0];
var view = _converse.chatboxviews.get(room_jid); view.model.onMessage(
view.model.set({'minimized': true}); $msg({
var contact_jid = mock.cur_names[5].replace(/ /g,'.').toLowerCase() + '@localhost'; from: room_jid+'/'+nick,
var nick = mock.chatroom_names[0]; id: (new Date()).getTime(),
view.model.onMessage( to: 'dummy@localhost',
$msg({ type: 'groupchat'
from: room_jid+'/'+nick, }).c('body').t('foo').tree());
id: (new Date()).getTime(),
to: 'dummy@localhost',
type: 'groupchat'
}).c('body').t('foo').tree());
// If the user isn't mentioned, the counter doesn't get incremented, but the text of the groupchat is bold // If the user isn't mentioned, the counter doesn't get incremented, but the text of the groupchat is bold
var room_el = _converse.rooms_list_view.el.querySelector( var room_el = _converse.rooms_list_view.el.querySelector(
".available-chatroom" ".available-chatroom"
); );
expect(_.includes(room_el.classList, 'unread-msgs')); expect(_.includes(room_el.classList, 'unread-msgs'));
// If the user is mentioned, the counter also gets updated // If the user is mentioned, the counter also gets updated
view.model.onMessage( view.model.onMessage(
$msg({ $msg({
from: room_jid+'/'+nick, from: room_jid+'/'+nick,
id: (new Date()).getTime(), id: (new Date()).getTime(),
to: 'dummy@localhost', to: 'dummy@localhost',
type: 'groupchat' type: 'groupchat'
}).c('body').t('romeo: Your attention is required').tree() }).c('body').t('romeo: Your attention is required').tree()
); );
var indicator_el = _converse.rooms_list_view.el.querySelector(".msgs-indicator"); var indicator_el = _converse.rooms_list_view.el.querySelector(".msgs-indicator");
expect(indicator_el.textContent).toBe('1'); expect(indicator_el.textContent).toBe('1');
view.model.onMessage( view.model.onMessage(
$msg({ $msg({
from: room_jid+'/'+nick, from: room_jid+'/'+nick,
id: (new Date()).getTime(), id: (new Date()).getTime(),
to: 'dummy@localhost', to: 'dummy@localhost',
type: 'groupchat' type: 'groupchat'
}).c('body').t('romeo: and another thing...').tree() }).c('body').t('romeo: and another thing...').tree()
); );
indicator_el = _converse.rooms_list_view.el.querySelector(".msgs-indicator"); indicator_el = _converse.rooms_list_view.el.querySelector(".msgs-indicator");
expect(indicator_el.textContent).toBe('2'); expect(indicator_el.textContent).toBe('2');
// When the chat gets maximized again, the unread indicators are removed // When the chat gets maximized again, the unread indicators are removed
view.model.set({'minimized': false}); view.model.set({'minimized': false});
indicator_el = _converse.rooms_list_view.el.querySelector(".msgs-indicator"); indicator_el = _converse.rooms_list_view.el.querySelector(".msgs-indicator");
expect(_.isNull(indicator_el)); expect(_.isNull(indicator_el));
room_el = _converse.rooms_list_view.el.querySelector(".available-chatroom"); room_el = _converse.rooms_list_view.el.querySelector(".available-chatroom");
expect(_.includes(room_el.classList, 'unread-msgs')).toBeFalsy(); expect(_.includes(room_el.classList, 'unread-msgs')).toBeFalsy();
done(); done();
}); }).catch(_.partial(_converse.log, _, Strophe.LogLevel.FATAL));
});
})); }));
}); });
})); }));
...@@ -461,11 +461,15 @@ ...@@ -461,11 +461,15 @@
}, },
getReferencesFromStanza (stanza) { getReferencesFromStanza (stanza) {
const text = _.propertyOf(stanza.querySelector('body'))('textContent');
return sizzle(`reference[xmlns="${Strophe.NS.REFERENCE}"]`, stanza).map(ref => { return sizzle(`reference[xmlns="${Strophe.NS.REFERENCE}"]`, stanza).map(ref => {
const begin = ref.getAttribute('begin'),
end = ref.getAttribute('end');
return { return {
'begin': ref.getAttribute('begin'), 'begin': begin,
'end': ref.getAttribute('end'), 'end': end,
'type': ref.getAttribute('type'), 'type': ref.getAttribute('type'),
'value': text.slice(begin, end),
'uri': ref.getAttribute('uri') 'uri': ref.getAttribute('uri')
}; };
}); });
...@@ -494,6 +498,8 @@ ...@@ -494,6 +498,8 @@
stanza.getElementsByTagName(_converse.ACTIVE).length && _converse.ACTIVE || stanza.getElementsByTagName(_converse.ACTIVE).length && _converse.ACTIVE ||
stanza.getElementsByTagName(_converse.GONE).length && _converse.GONE; stanza.getElementsByTagName(_converse.GONE).length && _converse.GONE;
const attrs = { const attrs = {
'chat_state': chat_state, 'chat_state': chat_state,
'is_archived': !_.isNil(archive), 'is_archived': !_.isNil(archive),
...@@ -561,14 +567,13 @@ ...@@ -561,14 +567,13 @@
_converse.windowState === 'hidden'; _converse.windowState === 'hidden';
}, },
incrementUnreadMsgCounter (stanza) { incrementUnreadMsgCounter (message) {
/* Given a newly received message, update the unread counter if /* Given a newly received message, update the unread counter if
* necessary. * necessary.
*/ */
if (_.isNull(stanza.querySelector('body'))) { if (!message) { return; }
return; // The message has no text if (_.isNil(message.get('message'))) { return; }
} if (utils.isNewMessage(message) && this.isHidden()) {
if (utils.isNewMessage(stanza) && this.isHidden()) {
this.save({'num_unread': this.get('num_unread') + 1}); this.save({'num_unread': this.get('num_unread') + 1});
_converse.incrementMsgCounter(); _converse.incrementMsgCounter();
} }
...@@ -719,10 +724,8 @@ ...@@ -719,10 +724,8 @@
if (chatbox && !chatbox.handleMessageCorrection(stanza)) { if (chatbox && !chatbox.handleMessageCorrection(stanza)) {
const msgid = stanza.getAttribute('id'), const msgid = stanza.getAttribute('id'),
message = msgid && chatbox.messages.findWhere({msgid}); message = msgid && chatbox.messages.findWhere({msgid});
if (!message) { if (!message) { // Only create the message when we're sure it's not a duplicate
// Only create the message when we're sure it's not a duplicate chatbox.incrementUnreadMsgCounter(chatbox.createMessage(stanza, original_stanza));
chatbox.incrementUnreadMsgCounter(original_stanza);
chatbox.createMessage(stanza, original_stanza);
} }
} }
_converse.emit('message', {'stanza': original_stanza, 'chatbox': chatbox}); _converse.emit('message', {'stanza': original_stanza, 'chatbox': chatbox});
......
...@@ -260,7 +260,7 @@ ...@@ -260,7 +260,7 @@
getExtraMessageClasses () { getExtraMessageClasses () {
let extra_classes = this.model.get('is_delayed') && 'delayed' || ''; let extra_classes = this.model.get('is_delayed') && 'delayed' || '';
if (this.model.get('type') === 'groupchat' && this.model.get('sender') === 'them') { if (this.model.get('type') === 'groupchat' && this.model.get('sender') === 'them') {
if (this.model.collection.chatbox.isUserMentioned(this.model.get('message'))) { if (this.model.collection.chatbox.isUserMentioned(this.model)) {
// Add special class to mark groupchat messages // Add special class to mark groupchat messages
// in which we are mentioned. // in which we are mentioned.
extra_classes += ' mentioned'; extra_classes += ' mentioned';
......
...@@ -326,6 +326,7 @@ ...@@ -326,6 +326,7 @@
const obj = { const obj = {
'begin': index, 'begin': index,
'end': index + longest_match.length, 'end': index + longest_match.length,
'value': longest_match,
'type': 'mention' 'type': 'mention'
}; };
if (occupant.get('jid')) { if (occupant.get('jid')) {
...@@ -921,8 +922,7 @@ ...@@ -921,8 +922,7 @@
if (sender === '') { if (sender === '') {
return; return;
} }
this.incrementUnreadMsgCounter(original_stanza); this.incrementUnreadMsgCounter(this.createMessage(stanza, original_stanza));
this.createMessage(stanza, original_stanza);
} }
if (sender !== this.get('nick')) { if (sender !== this.get('nick')) {
// We only emit an event if it's not our own message // We only emit an event if it's not our own message
...@@ -1001,23 +1001,28 @@ ...@@ -1001,23 +1001,28 @@
* Parameters: * Parameters:
* (String): The text message * (String): The text message
*/ */
return (new RegExp(`\\b${this.get('nick')}\\b`)).test(message); const nick = this.get('nick');
if (message.get('references').length) {
const mentions = message.get('references').filter(ref => (ref.type === 'mention')).map(ref => ref.value);
return _.includes(mentions, nick);
} else {
return (new RegExp(`\\b${nick}\\b`)).test(message.get('message'));
}
}, },
incrementUnreadMsgCounter (stanza) { incrementUnreadMsgCounter (message) {
/* Given a newly received message, update the unread counter if /* Given a newly received message, update the unread counter if
* necessary. * necessary.
* *
* Parameters: * Parameters:
* (XMLElement): The <messsage> stanza * (XMLElement): The <messsage> stanza
*/ */
const body = stanza.querySelector('body'); if (!message) { return; }
if (_.isNull(body)) { const body = message.get('message');
return; // The message has no text if (_.isNil(body)) { return; }
} if (u.isNewMessage(message) && this.isHidden()) {
if (u.isNewMessage(stanza) && this.isHidden()) {
const settings = {'num_unread_general': this.get('num_unread_general') + 1}; const settings = {'num_unread_general': this.get('num_unread_general') + 1};
if (this.isUserMentioned(body.textContent)) { if (this.isUserMentioned(message)) {
settings.num_unread = this.get('num_unread') + 1; settings.num_unread = this.get('num_unread') + 1;
_converse.incrementMsgCounter(); _converse.incrementMsgCounter();
} }
......
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