Commit 71cc98d6 authored by JC Brand's avatar JC Brand

Reduce join/leave clutter by removing subsequent ones

Previously we checked only if the last message was a join message from
the same person.

Now instead we check the last n messages that are join or leave
notifications.
parent cf75d375
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
## 4.0.3 (Unreleased) ## 4.0.3 (Unreleased)
- Reduce join/leave clutter by removing subsequent ones (without text messages in between)
- Bugfix. Handler not triggered when submitting MUC password form 2nd time - Bugfix. Handler not triggered when submitting MUC password form 2nd time
- Bugfix. MUC features weren't being refreshed when saving the config form - Bugfix. MUC features weren't being refreshed when saving the config form
- #1063 URLs in the topic / subject are not clickable - #1063 URLs in the topic / subject are not clickable
......
...@@ -69771,6 +69771,22 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_ ...@@ -69771,6 +69771,22 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
this.scrollDown(); this.scrollDown();
}, },
getImmediateJoinNotification(el, nick) {
while (!_.isNil(el)) {
const data = _.get(el, 'dataset', {});
if (!_.includes(_.get(el, 'classList', []), 'chat-info')) {
return;
}
if (moment(el.getAttribute('data-isodate')).isSame(new Date(), "day") && (data.join === `"${nick}"` || data.leavejoin === `"${nick}"`)) {
return el;
}
el = el.previousElementSibling;
}
},
showLeaveNotification(occupant) { showLeaveNotification(occupant) {
if (_.includes(occupant.get('states'), '303') || _.includes(occupant.get('states'), '307')) { if (_.includes(occupant.get('states'), '303') || _.includes(occupant.get('states'), '307')) {
return; return;
...@@ -69778,10 +69794,10 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_ ...@@ -69778,10 +69794,10 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
const nick = occupant.get('nick'), const nick = occupant.get('nick'),
stat = occupant.get('status'), stat = occupant.get('status'),
last_el = this.content.lastElementChild, last_join_el = this.getImmediateJoinNotification(this.content.lastElementChild, nick),
data = _.get(last_el, 'dataset', {}); data = _.get(last_join_el, 'dataset', {});
if (last_el && _.includes(_.get(last_el, 'classList', []), 'chat-info') && moment(last_el.getAttribute('data-isodate')).isSame(new Date(), "day") && (data.join === `"${nick}"` || data.leavejoin === `"${nick}"`)) { if (last_join_el) {
let message; let message;
if (data.join === `"${nick}"`) { if (data.join === `"${nick}"`) {
...@@ -69791,13 +69807,15 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_ ...@@ -69791,13 +69807,15 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
message = __('%1$s has entered and left the groupchat. "%2$s"', nick, stat); message = __('%1$s has entered and left the groupchat. "%2$s"', nick, stat);
} }
last_el.outerHTML = tpl_info({ let el = this.content.lastElementChild;
el.insertAdjacentElement('afterend', last_join_el);
last_join_el.outerHTML = tpl_info({
'data': `data-joinleave="${nick}"`, 'data': `data-joinleave="${nick}"`,
'isodate': moment().format(), 'isodate': moment().format(),
'extra_classes': 'chat-event', 'extra_classes': 'chat-event',
'message': message 'message': message
}); });
const el = this.content.lastElementChild; el = this.content.lastElementChild;
setTimeout(() => u.addClass('fade-out', el), 5000); setTimeout(() => u.addClass('fade-out', el), 5000);
setTimeout(() => el.parentElement && el.parentElement.removeChild(el), 5250); setTimeout(() => el.parentElement && el.parentElement.removeChild(el), 5250);
} else if (data.leavejoin === `"${nick}"`) { } else if (data.leavejoin === `"${nick}"`) {
...@@ -69807,7 +69825,7 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_ ...@@ -69807,7 +69825,7 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
message = __('%1$s has left the groupchat. "%2$s"', nick, stat); message = __('%1$s has left the groupchat. "%2$s"', nick, stat);
} }
last_el.outerHTML = tpl_info({ last_join_el.outerHTML = tpl_info({
'data': `data-leave="${nick}"`, 'data': `data-leave="${nick}"`,
'isodate': moment().format(), 'isodate': moment().format(),
'extra_classes': 'chat-event', 'extra_classes': 'chat-event',
...@@ -69829,14 +69847,9 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_ ...@@ -69829,14 +69847,9 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
'extra_classes': 'chat-event', 'extra_classes': 'chat-event',
'data': `data-leave="${nick}"` 'data': `data-leave="${nick}"`
}; };
const el = u.stringToElement(tpl_info(data));
if (last_el && _.includes(_.get(last_el, 'classList', []), 'chat-info') && _.get(last_el, 'dataset', {}).leavejoin === `"${nick}"`) { this.content.insertAdjacentElement('beforeend', el);
last_el.outerHTML = tpl_info(data); this.insertDayIndicator(el);
} else {
const el = u.stringToElement(tpl_info(data));
this.content.insertAdjacentElement('beforeend', el);
this.insertDayIndicator(el);
}
} }
this.scrollDown(); this.scrollDown();
...@@ -422,7 +422,8 @@ ...@@ -422,7 +422,8 @@
test_utils.openChatRoom(_converse, "coven", 'chat.shakespeare.lit', 'some1') test_utils.openChatRoom(_converse, "coven", 'chat.shakespeare.lit', 'some1')
.then(() => { .then(() => {
const view = _converse.chatboxviews.get('coven@chat.shakespeare.lit'); const view = _converse.chatboxviews.get('coven@chat.shakespeare.lit');
const $chat_content = $(view.el).find('.chat-content'); const chat_content = view.el.querySelector('.chat-content');
const $chat_content = $(chat_content);
/* We don't show join/leave messages for existing occupants. We /* We don't show join/leave messages for existing occupants. We
* know about them because we receive their presences before we * know about them because we receive their presences before we
* receive our own. * receive our own.
...@@ -474,6 +475,15 @@ ...@@ -474,6 +475,15 @@
expect($chat_content[0].querySelectorAll('div.chat-info').length).toBe(2); expect($chat_content[0].querySelectorAll('div.chat-info').length).toBe(2);
expect($chat_content.find('div.chat-info:last').html()).toBe("newguy has entered the groupchat"); expect($chat_content.find('div.chat-info:last').html()).toBe("newguy has entered the groupchat");
const msg = $msg({
'from': 'coven@chat.shakespeare.lit/some1',
'id': (new Date()).getTime(),
'to': 'dummy@localhost',
'type': 'groupchat'
}).c('body').t('hello world').tree();
_converse.connection._dataRecv(test_utils.createRequest(msg));
// Add another entrant, otherwise the above message will be // Add another entrant, otherwise the above message will be
// collapsed if "newguy" leaves immediately again // collapsed if "newguy" leaves immediately again
presence = $pres({ presence = $pres({
...@@ -563,9 +573,9 @@ ...@@ -563,9 +573,9 @@
}); });
_converse.connection._dataRecv(test_utils.createRequest(presence)); _converse.connection._dataRecv(test_utils.createRequest(presence));
expect($chat_content.find('div.chat-info').length).toBe(4); expect($chat_content.find('div.chat-info').length).toBe(4);
$msg_el = $chat_content.find('div.chat-info:last'); const msg_el = sizzle('div.chat-info', chat_content).pop();
expect($msg_el.html()).toBe('newguy has left the groupchat'); expect(msg_el.textContent).toBe('newguy has left the groupchat');
expect($msg_el.data('leave')).toBe('"newguy"'); expect(msg_el.getAttribute('data-leave')).toBe('"newguy"');
presence = $pres({ presence = $pres({
to: 'dummy@localhost/_converse.js-29092160', to: 'dummy@localhost/_converse.js-29092160',
...@@ -648,13 +658,31 @@ ...@@ -648,13 +658,31 @@
'role': 'none' 'role': 'none'
}); });
_converse.connection._dataRecv(test_utils.createRequest(presence)); _converse.connection._dataRecv(test_utils.createRequest(presence));
expect($chat_content.find('div.chat-info').length).toBe(6); expect(chat_content.querySelectorAll('div.chat-info').length).toBe(6);
expect($chat_content.find('div.chat-info:last').html()).toBe( expect($chat_content.find('div.chat-info:last').html()).toBe(
'insider has entered and left the groupchat. '+ 'insider has entered and left the groupchat. '+
'"Disconnected: Replaced by new connection"'); '"Disconnected: Replaced by new connection"');
expect(view.model.occupants.length).toBe(5); expect(view.model.occupants.length).toBe(5);
expect(view.model.occupants.findWhere({'jid': 'insider@localhost'}).get('show')).toBe('offline'); expect(view.model.occupants.findWhere({'jid': 'insider@localhost'}).get('show')).toBe('offline');
// New girl leaves
presence = $pres({
'to': 'dummy@localhost/_converse.js-29092160',
'type': 'unavailable',
'from': 'coven@chat.shakespeare.lit/newgirl'
})
.c('x', {xmlns: Strophe.NS.MUC_USER})
.c('item', {
'affiliation': 'none',
'jid': 'newgirl@localhost/_converse.js-213098781',
'role': 'none'
});
_converse.connection._dataRecv(test_utils.createRequest(presence));
expect(chat_content.querySelectorAll('div.chat-info').length).toBe(6);
expect(sizzle('div.chat-info:last', chat_content).pop().textContent).toBe("newgirl has entered and left the groupchat");
expect(view.model.occupants.length).toBe(4);
done(); done();
}).catch(_.partial(_converse.log, _, Strophe.LogLevel.FATAL)) }).catch(_.partial(_converse.log, _, Strophe.LogLevel.FATAL))
})); }));
......
...@@ -1546,20 +1546,30 @@ ...@@ -1546,20 +1546,30 @@
this.scrollDown(); this.scrollDown();
}, },
getImmediateJoinNotification (el, nick) {
while (!_.isNil(el)) {
const data = _.get(el, 'dataset', {});
if (!_.includes(_.get(el, 'classList', []), 'chat-info')) {
return;
}
if (moment(el.getAttribute('data-isodate')).isSame(new Date(), "day") &&
(data.join === `"${nick}"` || data.leavejoin === `"${nick}"`)) {
return el;
}
el = el.previousElementSibling;
}
},
showLeaveNotification (occupant) { showLeaveNotification (occupant) {
if (_.includes(occupant.get('states'), '303') || _.includes(occupant.get('states'), '307')) { if (_.includes(occupant.get('states'), '303') || _.includes(occupant.get('states'), '307')) {
return; return;
} }
const nick = occupant.get('nick'), const nick = occupant.get('nick'),
stat = occupant.get('status'), stat = occupant.get('status'),
last_el = this.content.lastElementChild, last_join_el = this.getImmediateJoinNotification(this.content.lastElementChild, nick),
data = _.get(last_el, 'dataset', {}); data = _.get(last_join_el, 'dataset', {});
if (last_el &&
_.includes(_.get(last_el, 'classList', []), 'chat-info') &&
moment(last_el.getAttribute('data-isodate')).isSame(new Date(), "day") &&
(data.join === `"${nick}"` || data.leavejoin === `"${nick}"`)) {
if (last_join_el) {
let message; let message;
if (data.join === `"${nick}"`) { if (data.join === `"${nick}"`) {
if (_.isNil(stat)) { if (_.isNil(stat)) {
...@@ -1567,24 +1577,25 @@ ...@@ -1567,24 +1577,25 @@
} else { } else {
message = __('%1$s has entered and left the groupchat. "%2$s"', nick, stat); message = __('%1$s has entered and left the groupchat. "%2$s"', nick, stat);
} }
last_el.outerHTML = let el = this.content.lastElementChild;
el.insertAdjacentElement('afterend', last_join_el);
last_join_el.outerHTML =
tpl_info({ tpl_info({
'data': `data-joinleave="${nick}"`, 'data': `data-joinleave="${nick}"`,
'isodate': moment().format(), 'isodate': moment().format(),
'extra_classes': 'chat-event', 'extra_classes': 'chat-event',
'message': message 'message': message
}); });
const el = this.content.lastElementChild; el = this.content.lastElementChild;
setTimeout(() => u.addClass('fade-out', el), 5000); setTimeout(() => u.addClass('fade-out', el), 5000);
setTimeout(() => el.parentElement && el.parentElement.removeChild(el), 5250); setTimeout(() => el.parentElement && el.parentElement.removeChild(el), 5250);
} else if (data.leavejoin === `"${nick}"`) { } else if (data.leavejoin === `"${nick}"`) {
if (_.isNil(stat)) { if (_.isNil(stat)) {
message = __('%1$s has left the groupchat', nick); message = __('%1$s has left the groupchat', nick);
} else { } else {
message = __('%1$s has left the groupchat. "%2$s"', nick, stat); message = __('%1$s has left the groupchat. "%2$s"', nick, stat);
} }
last_el.outerHTML = last_join_el.outerHTML =
tpl_info({ tpl_info({
'data': `data-leave="${nick}"`, 'data': `data-leave="${nick}"`,
'isodate': moment().format(), 'isodate': moment().format(),
...@@ -1605,16 +1616,9 @@ ...@@ -1605,16 +1616,9 @@
'extra_classes': 'chat-event', 'extra_classes': 'chat-event',
'data': `data-leave="${nick}"` 'data': `data-leave="${nick}"`
} }
if (last_el && const el = u.stringToElement(tpl_info(data));
_.includes(_.get(last_el, 'classList', []), 'chat-info') && this.content.insertAdjacentElement('beforeend', el);
_.get(last_el, 'dataset', {}).leavejoin === `"${nick}"`) { this.insertDayIndicator(el);
last_el.outerHTML = tpl_info(data);
} else {
const el = u.stringToElement(tpl_info(data));
this.content.insertAdjacentElement('beforeend', el);
this.insertDayIndicator(el);
}
} }
this.scrollDown(); this.scrollDown();
}, },
......
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