diff --git a/CHANGES.md b/CHANGES.md index bc8f12845..4513a744e 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -4,6 +4,7 @@ - Bugfix. Handler not triggered when submitting MUC password form 2nd time - Bugfix. MUC features weren't being refreshed when saving the config form +- Don't show duplicate notification messages - #537 Render `xmpp:` URI as link - #1062 Collapse multiple join/leave messages into one - #1063 URLs in the topic / subject are not clickable diff --git a/dist/converse.js b/dist/converse.js index 495c10baa..d8083d66a 100644 --- a/dist/converse.js +++ b/dist/converse.js @@ -69899,6 +69899,24 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_ return; }, + getNotificationWithMessage(message) { + let el = this.content.lastElementChild; + + while (!_.isNil(el)) { + const data = _.get(el, 'dataset', {}); + + if (!_.includes(_.get(el, 'classList', []), 'chat-info')) { + return; + } + + if (el.textContent === message) { + return el; + } + + el = el.previousElementSibling; + } + }, + parseXUserElement(x, stanza, is_self) { /* Parse the passed-in * element and construct a map containing relevant @@ -69911,7 +69929,7 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_ const notification = {}; - const messages = _.reject(_.map(statuses, mapper), _.isUndefined); + const messages = _.reject(_.reject(_.map(statuses, mapper), _.isUndefined), message => this.getNotificationWithMessage(message)); if (messages.length) { notification.messages = messages; diff --git a/spec/chatroom.js b/spec/chatroom.js index 39cbec4d1..897c76e52 100644 --- a/spec/chatroom.js +++ b/spec/chatroom.js @@ -411,6 +411,67 @@ describe("A Groupchat", function () { + it("shows a notification if its not anonymous", + mock.initConverseWithPromises( + null, ['rosterGroupsFetched', 'chatBoxesFetched'], {}, + function (done, _converse) { + + test_utils.openChatRoom(_converse, "coven", 'chat.shakespeare.lit', 'some1') + .then(() => { + const view = _converse.chatboxviews.get('coven@chat.shakespeare.lit'); + const chat_content = view.el.querySelector('.chat-content'); + /* + * + * + * + * + * + * + */ + let presence = $pres({ + to: 'dummy@localhost/resource', + from: 'coven@chat.shakespeare.lit/some1' + }).c('x', {xmlns: Strophe.NS.MUC_USER}) + .c('item', { + 'affiliation': 'owner', + 'jid': 'dummy@localhost/_converse.js-29092160', + 'role': 'moderator' + }).up() + .c('status', {code: '110'}).up() + .c('status', {code: '100'}); + + _converse.connection._dataRecv(test_utils.createRequest(presence)); + expect(chat_content.querySelectorAll('.chat-info').length).toBe(2); + expect(sizzle('div.chat-info:first', chat_content).pop().textContent) + .toBe("This groupchat is not anonymous"); + expect(sizzle('div.chat-info:last', chat_content).pop().textContent) + .toBe("some1 has entered the groupchat"); + + // Check that we don't show the notification twice + presence = $pres({ + to: 'dummy@localhost/resource', + from: 'coven@chat.shakespeare.lit/some1' + }).c('x', {xmlns: Strophe.NS.MUC_USER}) + .c('item', { + 'affiliation': 'owner', + 'jid': 'dummy@localhost/_converse.js-29092160', + 'role': 'moderator' + }).up() + .c('status', {code: '110'}).up() + .c('status', {code: '100'}); + _converse.connection._dataRecv(test_utils.createRequest(presence)); + expect(chat_content.querySelectorAll('.chat-info').length).toBe(2); + expect(sizzle('div.chat-info:first', chat_content).pop().textContent) + .toBe("This groupchat is not anonymous"); + expect(sizzle('div.chat-info:last', chat_content).pop().textContent) + .toBe("some1 has entered the groupchat"); + + done(); + }).catch(_.partial(_converse.log, _, Strophe.LogLevel.FATAL)) + })); + + it("shows join/leave messages when users enter or exit a groupchat", mock.initConverseWithPromises( null, ['rosterGroupsFetched', 'chatBoxesFetched'], {}, diff --git a/src/converse-muc-views.js b/src/converse-muc-views.js index bd421c10a..1e79eb222 100644 --- a/src/converse-muc-views.js +++ b/src/converse-muc-views.js @@ -1400,6 +1400,20 @@ return; }, + getNotificationWithMessage (message) { + let el = this.content.lastElementChild; + while (!_.isNil(el)) { + const data = _.get(el, 'dataset', {}); + if (!_.includes(_.get(el, 'classList', []), 'chat-info')) { + return; + } + if (el.textContent === message) { + return el; + } + el = el.previousElementSibling; + } + }, + parseXUserElement (x, stanza, is_self) { /* Parse the passed-in * element and construct a map containing relevant @@ -1409,7 +1423,10 @@ const statuses = x.querySelectorAll('status'); const mapper = _.partial(this.getMessageFromStatus, _, stanza, is_self); const notification = {}; - const messages = _.reject(_.map(statuses, mapper), _.isUndefined); + const messages = _.reject( + _.reject(_.map(statuses, mapper), _.isUndefined), + message => this.getNotificationWithMessage(message) + ); if (messages.length) { notification.messages = messages; }