Some refactoring of the code that collapses leave/join messages

Mostly to match any previous leave/join message from the same user

Fixes #1062
This commit is contained in:
JC Brand 2018-10-13 13:23:55 +02:00
parent 7b9c97dfd3
commit 7270abb08b
5 changed files with 159 additions and 168 deletions

View File

@ -2,9 +2,10 @@
## 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
- #537 Render `xmpp:` URI as link
- #1062 Collapse multiple join/leave messages into one
- #1063 URLs in the topic / subject are not clickable - #1063 URLs in the topic / subject are not clickable
- #1140 Add support for destroyed chatrooms - #1140 Add support for destroyed chatrooms
- #1169 Non-joined participants display an unwanted status message - #1169 Non-joined participants display an unwanted status message

View File

@ -10770,7 +10770,9 @@ body.reset {
font-style: italic; } font-style: italic; }
#conversejs .message.chat-info.chat-event { #conversejs .message.chat-info.chat-event {
clear: left; clear: left;
font-style: italic; } font-style: italic;
font-size: 90%;
padding: 0.17rem 1rem; }
#conversejs .message.chat-info.chat-error { #conversejs .message.chat-info.chat-error {
color: #D24E2B; color: #D24E2B;
font-weight: bold; } font-weight: bold; }

156
dist/converse.js vendored
View File

@ -70015,6 +70015,31 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
} }
}, },
getPreviousJoinOrLeaveNotification(el, nick) {
/* Working backwards, get the first join/leave notification
* from the same user, on the same day and BEFORE any chat
* messages were received.
*/
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")) {
el = el.previousElementSibling;
continue;
}
if (data.join === nick || data.leave === nick || data.leavejoin === nick || data.joinleave === nick) {
return el;
}
el = el.previousElementSibling;
}
},
showJoinNotification(occupant) { showJoinNotification(occupant) {
if (this.model.get('connection_status') !== converse.ROOMSTATUS.ENTERED) { if (this.model.get('connection_status') !== converse.ROOMSTATUS.ENTERED) {
return; return;
@ -70022,21 +70047,30 @@ 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_leave_el = this.getImmediateNotification(this.content.lastElementChild, nick, 'leave'); prev_info_el = this.getPreviousJoinOrLeaveNotification(this.content.lastElementChild, nick),
data = _.get(prev_info_el, 'dataset', {});
if (_.includes(_.get(last_leave_el, 'classList', []), 'chat-info') && _.get(last_leave_el, 'dataset', {}).leave === nick) { if (data.leave === nick) {
let el = this.content.lastElementChild; let message;
el.insertAdjacentElement('afterend', last_leave_el);
last_leave_el.outerHTML = tpl_info({ if (_.isNil(stat)) {
message = __('%1$s has left and re-entered the groupchat', nick);
} else {
message = __('%1$s has left and re-entered the groupchat. "%2$s"', nick, stat);
}
const data = {
'data_name': 'leavejoin', 'data_name': 'leavejoin',
'data_value': nick, 'data_value': nick,
'isodate': moment().format(), 'isodate': moment().format(),
'extra_classes': 'chat-event', 'extra_classes': 'chat-event',
'message': __('%1$s has left and re-entered the groupchat', nick) 'message': message
}); };
el = this.content.lastElementChild; this.content.removeChild(prev_info_el);
this.content.insertAdjacentHTML('beforeend', tpl_info(data));
const 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), 5500);
} else { } else {
let message; let message;
@ -70054,45 +70088,18 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
'message': message 'message': message
}; };
if (_.includes(_.get(last_leave_el, 'classList', []), 'chat-info') && _.get(last_leave_el, 'dataset', {}).joinleave === nick) { if (prev_info_el) {
last_leave_el.outerHTML = tpl_info(data); this.content.removeChild(prev_info_el);
this.content.insertAdjacentHTML('beforeend', tpl_info(data));
} else { } else {
const el = u.stringToElement(tpl_info(data)); this.content.insertAdjacentHTML('beforeend', tpl_info(data));
this.content.insertAdjacentElement('beforeend', el); this.insertDayIndicator(this.content.lastElementChild);
this.insertDayIndicator(el);
} }
} }
this.scrollDown(); this.scrollDown();
}, },
getImmediateNotification(el, nick, type = 'join') {
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")) {
el = el.previousElementSibling;
continue;
}
if (type === 'join') {
if (data.join === nick || data.leavejoin === nick) {
return el;
}
} else {
if (data.leave === nick || data.joinleave === 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;
@ -70100,46 +70107,30 @@ 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_join_el = this.getImmediateNotification(this.content.lastElementChild, nick, 'join'), prev_info_el = this.getPreviousJoinOrLeaveNotification(this.content.lastElementChild, nick),
data = _.get(last_join_el, 'dataset', {}); dataset = _.get(prev_info_el, 'dataset', {});
if (last_join_el) { if (dataset.join === nick) {
let message; let message;
if (data.join === nick) { if (_.isNil(stat)) {
if (_.isNil(stat)) { message = __('%1$s has entered and left the groupchat', nick);
message = __('%1$s has entered and left the groupchat', nick); } 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);
}
let el = this.content.lastElementChild;
el.insertAdjacentElement('afterend', last_join_el);
last_join_el.outerHTML = tpl_info({
'data_name': 'joinleave',
'data_value': nick,
'isodate': moment().format(),
'extra_classes': 'chat-event',
'message': message
});
el = this.content.lastElementChild;
setTimeout(() => u.addClass('fade-out', el), 5000);
setTimeout(() => el.parentElement && el.parentElement.removeChild(el), 5250);
} else if (data.leavejoin === nick) {
if (_.isNil(stat)) {
message = __('%1$s has left the groupchat', nick);
} else {
message = __('%1$s has left the groupchat. "%2$s"', nick, stat);
}
last_join_el.outerHTML = tpl_info({
'data_name': 'leave',
'data_value': nick,
'isodate': moment().format(),
'extra_classes': 'chat-event',
'message': message
});
} }
const data = {
'data_name': 'joinleave',
'data_value': nick,
'isodate': moment().format(),
'extra_classes': 'chat-event',
'message': message
};
this.content.removeChild(prev_info_el);
this.content.insertAdjacentHTML('beforeend', tpl_info(data));
const el = this.content.lastElementChild;
setTimeout(() => u.addClass('fade-out', el), 5000);
setTimeout(() => el.parentElement && el.parentElement.removeChild(el), 5500);
} else { } else {
let message; let message;
@ -70156,9 +70147,14 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_
'data_name': 'leave', 'data_name': 'leave',
'data_value': nick 'data_value': nick
}; };
const el = u.stringToElement(tpl_info(data));
this.content.insertAdjacentElement('beforeend', el); if (prev_info_el) {
this.insertDayIndicator(el); this.content.removeChild(prev_info_el);
this.content.insertAdjacentHTML('beforeend', tpl_info(data));
} else {
this.content.insertAdjacentHTML('beforeend', tpl_info(data));
this.insertDayIndicator(this.content.lastElementChild);
}
} }
this.scrollDown(); this.scrollDown();

View File

@ -48,6 +48,8 @@
&.chat-event { &.chat-event {
clear: left; clear: left;
font-style: italic; font-style: italic;
font-size: 90%;
padding: 0.17rem 1rem
} }
&.chat-error { &.chat-error {
color: $warning-color; color: $warning-color;

View File

@ -1498,32 +1498,60 @@
} }
}, },
getPreviousJoinOrLeaveNotification (el, nick) {
/* Working backwards, get the first join/leave notification
* from the same user, on the same day and BEFORE any chat
* messages were received.
*/
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")) {
el = el.previousElementSibling;
continue;
}
if (data.join === nick ||
data.leave === nick ||
data.leavejoin === nick ||
data.joinleave === nick) {
return el;
}
el = el.previousElementSibling;
}
},
showJoinNotification (occupant) { showJoinNotification (occupant) {
if (this.model.get('connection_status') !== converse.ROOMSTATUS.ENTERED) { if (this.model.get('connection_status') !== converse.ROOMSTATUS.ENTERED) {
return; return;
} }
const nick = occupant.get('nick'), const nick = occupant.get('nick'),
stat = occupant.get('status'), stat = occupant.get('status'),
last_leave_el = this.getImmediateNotification(this.content.lastElementChild, nick, 'leave'); prev_info_el = this.getPreviousJoinOrLeaveNotification(this.content.lastElementChild, nick),
data = _.get(prev_info_el, 'dataset', {});
if (_.includes(_.get(last_leave_el, 'classList', []), 'chat-info') && if (data.leave === nick) {
_.get(last_leave_el, 'dataset', {}).leave === nick) { let message;
if (_.isNil(stat)) {
let el = this.content.lastElementChild; message = __('%1$s has left and re-entered the groupchat', nick);
el.insertAdjacentElement('afterend', last_leave_el); } else {
last_leave_el.outerHTML = message = __('%1$s has left and re-entered the groupchat. "%2$s"', nick, stat);
tpl_info({ }
'data_name': 'leavejoin', const data = {
'data_value': nick, 'data_name': 'leavejoin',
'isodate': moment().format(), 'data_value': nick,
'extra_classes': 'chat-event', 'isodate': moment().format(),
'message': __('%1$s has left and re-entered the groupchat', nick) 'extra_classes': 'chat-event',
}); 'message': message
el = this.content.lastElementChild; };
this.content.removeChild(prev_info_el);
this.content.insertAdjacentHTML('beforeend', tpl_info(data));
const 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), 5500);
} else { } else {
let message; let message;
if (_.isNil(stat)) { if (_.isNil(stat)) {
message = __('%1$s has entered the groupchat', nick); message = __('%1$s has entered the groupchat', nick);
} else { } else {
@ -1536,87 +1564,45 @@
'extra_classes': 'chat-event', 'extra_classes': 'chat-event',
'message': message 'message': message
}; };
if (_.includes(_.get(last_leave_el, 'classList', []), 'chat-info') && if (prev_info_el) {
_.get(last_leave_el, 'dataset', {}).joinleave === nick) { this.content.removeChild(prev_info_el);
this.content.insertAdjacentHTML('beforeend', tpl_info(data));
last_leave_el.outerHTML = tpl_info(data);
} else { } else {
const el = u.stringToElement(tpl_info(data)); this.content.insertAdjacentHTML('beforeend', tpl_info(data));
this.content.insertAdjacentElement('beforeend', el); this.insertDayIndicator(this.content.lastElementChild);
this.insertDayIndicator(el);
} }
} }
this.scrollDown(); this.scrollDown();
}, },
getImmediateNotification (el, nick, type='join') {
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")) {
el = el.previousElementSibling;
continue;
}
if (type === 'join') {
if (data.join === nick || data.leavejoin === nick) {
return el;
}
} else {
if (data.leave === nick || data.joinleave === 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_join_el = this.getImmediateNotification(this.content.lastElementChild, nick, 'join'), prev_info_el = this.getPreviousJoinOrLeaveNotification(this.content.lastElementChild, nick),
data = _.get(last_join_el, 'dataset', {}); dataset = _.get(prev_info_el, 'dataset', {});
if (last_join_el) { if (dataset.join === nick) {
let message; let message;
if (data.join === nick) { if (_.isNil(stat)) {
if (_.isNil(stat)) { message = __('%1$s has entered and left the groupchat', nick);
message = __('%1$s has entered and left the groupchat', nick); } 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);
}
let el = this.content.lastElementChild;
el.insertAdjacentElement('afterend', last_join_el);
last_join_el.outerHTML =
tpl_info({
'data_name': 'joinleave',
'data_value': nick,
'isodate': moment().format(),
'extra_classes': 'chat-event',
'message': message
});
el = this.content.lastElementChild;
setTimeout(() => u.addClass('fade-out', el), 5000);
setTimeout(() => el.parentElement && el.parentElement.removeChild(el), 5250);
} else if (data.leavejoin === nick) {
if (_.isNil(stat)) {
message = __('%1$s has left the groupchat', nick);
} else {
message = __('%1$s has left the groupchat. "%2$s"', nick, stat);
}
last_join_el.outerHTML =
tpl_info({
'data_name': 'leave',
'data_value': nick,
'isodate': moment().format(),
'extra_classes': 'chat-event',
'message': message
});
} }
const data = {
'data_name': 'joinleave',
'data_value': nick,
'isodate': moment().format(),
'extra_classes': 'chat-event',
'message': message
};
this.content.removeChild(prev_info_el);
this.content.insertAdjacentHTML('beforeend', tpl_info(data));
const el = this.content.lastElementChild;
setTimeout(() => u.addClass('fade-out', el), 5000);
setTimeout(() => el.parentElement && el.parentElement.removeChild(el), 5500);
} else { } else {
let message; let message;
if (_.isNil(stat)) { if (_.isNil(stat)) {
@ -1631,9 +1617,13 @@
'data_name': 'leave', 'data_name': 'leave',
'data_value': nick 'data_value': nick
} }
const el = u.stringToElement(tpl_info(data)); if (prev_info_el) {
this.content.insertAdjacentElement('beforeend', el); this.content.removeChild(prev_info_el);
this.insertDayIndicator(el); this.content.insertAdjacentHTML('beforeend', tpl_info(data));
} else {
this.content.insertAdjacentHTML('beforeend', tpl_info(data));
this.insertDayIndicator(this.content.lastElementChild);
}
} }
this.scrollDown(); this.scrollDown();
}, },