Use template to render .chat-info messages

Also did some work on removing jQuery from converse-chatview
This commit is contained in:
JC Brand 2017-12-24 15:46:49 +00:00
parent f2ecf3c010
commit 334a24c938
7 changed files with 81 additions and 60 deletions

View File

@ -1616,6 +1616,7 @@
// See XEP-0085 http://xmpp.org/extensions/xep-0085.html#definitions // See XEP-0085 http://xmpp.org/extensions/xep-0085.html#definitions
spyOn(_converse, 'emit'); spyOn(_converse, 'emit');
var sender_jid = mock.cur_names[1].replace(/ /g,'.').toLowerCase() + '@localhost'; var sender_jid = mock.cur_names[1].replace(/ /g,'.').toLowerCase() + '@localhost';
test_utils.openChatBoxFor(_converse, sender_jid);
// <composing> state // <composing> state
var msg = $msg({ var msg = $msg({

View File

@ -1708,9 +1708,7 @@
.c('status', {code: '172'}); .c('status', {code: '172'});
_converse.connection._dataRecv(test_utils.createRequest(message)); _converse.connection._dataRecv(test_utils.createRequest(message));
var $chat_body = view.$('.chatroom-body'); var $chat_body = view.$('.chatroom-body');
expect($chat_body.html().trim().indexOf( expect($chat_body.find('.message:last').text()).toBe('This room is now no longer anonymous');
'<div class="message chat-info">This room is now no longer anonymous</div>'
)).not.toBe(-1);
done(); done();
}); });
})); }));

View File

@ -13,15 +13,16 @@
"converse-chatboxes", "converse-chatboxes",
"emojione", "emojione",
"xss", "xss",
"tpl!action",
"tpl!chatbox", "tpl!chatbox",
"tpl!chatbox_head", "tpl!chatbox_head",
"tpl!new_day",
"tpl!action",
"tpl!emojis", "tpl!emojis",
"tpl!message",
"tpl!help_message", "tpl!help_message",
"tpl!toolbar", "tpl!info",
"tpl!spinner" "tpl!message",
"tpl!new_day",
"tpl!spinner",
"tpl!toolbar"
], factory); ], factory);
}(this, function ( }(this, function (
$, $,
@ -29,15 +30,16 @@
dummy, dummy,
emojione, emojione,
xss, xss,
tpl_action,
tpl_chatbox, tpl_chatbox,
tpl_chatbox_head, tpl_chatbox_head,
tpl_new_day,
tpl_action,
tpl_emojis, tpl_emojis,
tpl_message,
tpl_help_message, tpl_help_message,
tpl_toolbar, tpl_info,
tpl_spinner tpl_message,
tpl_new_day,
tpl_spinner,
tpl_toolbar
) { ) {
"use strict"; "use strict";
const { $msg, Backbone, Strophe, _, b64_sha1, moment } = converse.env; const { $msg, Backbone, Strophe, _, b64_sha1, moment } = converse.env;
@ -321,9 +323,7 @@
afterMessagesFetched () { afterMessagesFetched () {
this.insertIntoDOM(); this.insertIntoDOM();
this.scrollDown(); this.scrollDown();
// We only start listening for the scroll event after this.content.addEventListener('scroll', this.markScrolled.bind(this));
// cached messages have been fetched
this.$content.on('scroll', this.markScrolled.bind(this));
_converse.emit('afterMessagesFetched', this); _converse.emit('afterMessagesFetched', this);
}, },
@ -349,18 +349,21 @@
}, },
clearStatusNotification () { clearStatusNotification () {
this.$content.find('div.chat-event').remove(); u.removeElement(this.content.querySelector('div.chat-event'));
}, },
showStatusNotification (message, keep_old, permanent) { showStatusNotification (message, keep_old, permanent) {
if (!keep_old) { if (!keep_old) {
this.clearStatusNotification(); this.clearStatusNotification();
} }
const $el = $('<div class="chat-info"></div>').text(message); this.content.insertAdjacentHTML(
if (!permanent) { 'beforeend',
$el.addClass('chat-event'); tpl_info({
} 'extra_classes': !permanent ? 'chat-event' : '',
this.content.insertAdjacentElement('beforeend', $el[0]); 'message': message,
'isodate': moment().format(),
'data': ''
}));
this.scrollDown(); this.scrollDown();
}, },
@ -391,8 +394,8 @@
* (String) date - An ISO8601 date string. * (String) date - An ISO8601 date string.
*/ */
const day_date = moment(date).startOf('day'); const day_date = moment(date).startOf('day');
const insert = prepend ? this.$content.prepend: this.$content.append; const insert = prepend ? $(this.content).prepend: $(this.content).append;
insert.call(this.$content, tpl_new_day({ insert.call($(this.content), tpl_new_day({
isodate: day_date.format(), isodate: day_date.format(),
datestring: day_date.format("dddd MMM Do YYYY") datestring: day_date.format("dddd MMM Do YYYY")
})); }));
@ -406,9 +409,9 @@
* Parameters: * Parameters:
* (Object) attrs: An object containing the message attributes. * (Object) attrs: An object containing the message attributes.
*/ */
const insert = prepend ? this.$content.prepend : this.$content.append; const insert = prepend ? $(this.content).prepend : $(this.content).append;
_.flow(($el) => { _.flow(($el) => {
insert.call(this.$content, $el); insert.call($(this.content), $el);
return $el; return $el;
}, },
this.scrollDown.bind(this) this.scrollDown.bind(this)
@ -428,8 +431,8 @@
* attributes. * attributes.
*/ */
let current_msg_date = moment(attrs.time) || moment; let current_msg_date = moment(attrs.time) || moment;
const $first_msg = this.$content.find('.chat-message:first'), const first_msg_el = this.content.firstElementChild,
first_msg_date = $first_msg.data('isodate'); first_msg_date = first_msg_el ? first_msg_el.getAttribute('data-isodate') : null;
if (!first_msg_date) { if (!first_msg_date) {
// This is the first received message, so we insert a // This is the first received message, so we insert a
@ -439,7 +442,8 @@
return; return;
} }
const last_msg_date = this.$content.find('.chat-message:last').data('isodate'); const last_msg_el = this.content.lastElementChild,
last_msg_date = last_msg_el.getAttribute('data-isodate');
if (current_msg_date.isAfter(last_msg_date) || if (current_msg_date.isAfter(last_msg_date) ||
current_msg_date.isSame(last_msg_date)) { current_msg_date.isSame(last_msg_date)) {
// The new message is after the last message // The new message is after the last message
@ -466,17 +470,18 @@
} }
// Find the correct place to position the message // Find the correct place to position the message
current_msg_date = current_msg_date.format(); current_msg_date = current_msg_date.format();
const msg_dates = _.map( const msg_dates = _.invokeMap(
this.$content.find('.chat-message'), this.content.querySelector('.message'),
(el) => $(el).data('isodate') Element.prototype.getAttribute,
); 'data-isodate'
)
msg_dates.push(current_msg_date); msg_dates.push(current_msg_date);
msg_dates.sort(); msg_dates.sort();
const idx = msg_dates.indexOf(current_msg_date)-1; const idx = msg_dates.indexOf(current_msg_date)-1;
const $latest_message = this.$content.find(`.chat-message[data-isodate="${msg_dates[idx]}"]:last`); const latest_msg_el = this.content.querySelector(`.message[data-isodate="${msg_dates[idx]}"]`);
_.flow(($el) => { _.flow(($el) => {
$el.insertAfter($latest_message); $el.insertAfter(latest_msg_el);
return $el; return $el;
}, },
this.scrollDown.bind(this) this.scrollDown.bind(this)
@ -524,7 +529,7 @@
template = tpl_message; template = tpl_message;
username = attrs.sender === 'me' && __('me') || fullname; username = attrs.sender === 'me' && __('me') || fullname;
} }
this.$content.find('div.chat-event').remove(); $(this.content).find('div.chat-event').remove();
if (text.length > 8000) { if (text.length > 8000) {
text = text.substring(0, 10) + '...'; text = text.substring(0, 10) + '...';
@ -564,9 +569,9 @@
); );
}); });
if (spinner === true) { if (spinner === true) {
this.$content.append(tpl_spinner); $(this.content).append(tpl_spinner);
} else if (spinner === false) { } else if (spinner === false) {
this.$content.find('span.spinner').remove(); $(this.content).find('span.spinner').remove();
} }
return this.scrollDown(); return this.scrollDown();
}, },
@ -589,7 +594,7 @@
this.showStatusNotification(message.get('fullname')+' '+__('has stopped typing')); this.showStatusNotification(message.get('fullname')+' '+__('has stopped typing'));
} }
} else if (_.includes([_converse.INACTIVE, _converse.ACTIVE], message.get('chat_state'))) { } else if (_.includes([_converse.INACTIVE, _converse.ACTIVE], message.get('chat_state'))) {
this.$content.find('div.chat-event').remove(); $(this.content).find('div.chat-event').remove();
} else if (message.get('chat_state') === _converse.GONE) { } else if (message.get('chat_state') === _converse.GONE) {
this.showStatusNotification(message.get('fullname')+' '+__('has gone away')); this.showStatusNotification(message.get('fullname')+' '+__('has gone away'));
} }
@ -620,9 +625,16 @@
}, },
handleErrorMessage (message) { handleErrorMessage (message) {
const $message = $(`[data-msgid=${message.get('msgid')}]`); const message_el = this.content.querySelector(`[data-msgid="${message.get('msgid')}"]`);
if ($message.length) { if (!_.isNull(message_el)) {
$message.after($('<div class="chat-info chat-error"></div>').text(message.get('message'))); message_el.insertAdjacentHTML(
'afterend',
tpl_info({
'extra_classes': 'chat-error',
'message': message.get('message'),
'isodate': moment().format(),
'data': ''
}));
this.scrollDown(); this.scrollDown();
} }
}, },
@ -799,7 +811,7 @@
if (ev && ev.preventDefault) { ev.preventDefault(); } if (ev && ev.preventDefault) { ev.preventDefault(); }
const result = confirm(__("Are you sure you want to clear the messages from this chat box?")); const result = confirm(__("Are you sure you want to clear the messages from this chat box?"));
if (result === true) { if (result === true) {
this.$content.empty(); this.content.innerHTML = '';
this.model.messages.reset(); this.model.messages.reset();
this.model.messages.browserStorage._clear(); this.model.messages.browserStorage._clear();
} }
@ -992,8 +1004,8 @@
} }
let scrolled = true; let scrolled = true;
const is_at_bottom = const is_at_bottom =
(this.$content.scrollTop() + this.$content.innerHeight()) >= ($(this.content).scrollTop() + $(this.content).innerHeight()) >=
this.$content[0].scrollHeight-10; $(this.content)[0].scrollHeight-10;
if (is_at_bottom) { if (is_at_bottom) {
scrolled = false; scrolled = false;

View File

@ -186,7 +186,7 @@
} else { } else {
width = ""; width = "";
} }
this.$el[0].style.width = width; this.el.style.width = width;
this.$el.children('.box-flyout')[0].style.width = width; this.$el.children('.box-flyout')[0].style.width = width;
}, },

View File

@ -1306,7 +1306,7 @@
container_el.insertAdjacentHTML('beforeend', tpl_chatroom_form()); container_el.insertAdjacentHTML('beforeend', tpl_chatroom_form());
const form_el = container_el.querySelector('form.chatroom-form'), const form_el = container_el.querySelector('form.chatroom-form'),
fieldset_el = form_el.querySelector('fieldset:first-child'), fieldset_el = form_el.querySelector('fieldset'),
fields = stanza.querySelectorAll('field'), fields = stanza.querySelectorAll('field'),
title = _.get(stanza.querySelector('title'), 'textContent'), title = _.get(stanza.querySelector('title'), 'textContent'),
instructions = _.get(stanza.querySelector('instructions'), 'textContent'); instructions = _.get(stanza.querySelector('instructions'), 'textContent');
@ -1817,7 +1817,13 @@
return; return;
} }
_.each(notification.messages, (message) => { _.each(notification.messages, (message) => {
this.content.insertAdjacentHTML('beforeend', tpl_info({'message': message, 'data': ''})); this.content.insertAdjacentHTML(
'beforeend',
tpl_info({
'data': '',
'isodate': moment().format(),
'message': message
}));
}); });
if (notification.reason) { if (notification.reason) {
this.showStatusNotification(__('The reason given is: "%1$s".', notification.reason), true); this.showStatusNotification(__('The reason given is: "%1$s".', notification.reason), true);
@ -1830,13 +1836,14 @@
displayJoinNotification (stanza) { displayJoinNotification (stanza) {
const nick = Strophe.getResourceFromJid(stanza.getAttribute('from')); const nick = Strophe.getResourceFromJid(stanza.getAttribute('from'));
const stat = stanza.querySelector('status'); const stat = stanza.querySelector('status');
const last_el = this.content.querySelector('.message:last-child'); const last_el = this.content.lastElementChild;
if (_.includes(_.get(last_el, 'classList', []), 'chat-info') && if (_.includes(_.get(last_el, 'classList', []), 'chat-info') &&
_.get(last_el, 'dataset', {}).leave === `"${nick}"`) { _.get(last_el, 'dataset', {}).leave === `"${nick}"`) {
last_el.outerHTML = last_el.outerHTML =
tpl_info({ tpl_info({
'message': __(nick+' has left and re-entered the room.'), 'data': `data-leavejoin="${nick}"`,
'data': `data-leavejoin="${nick}"` 'isodate': moment().format(),
'message': __(nick+' has left and re-entered the room.')
}); });
} else { } else {
let message = __(nick+' has entered the room.'); let message = __(nick+' has entered the room.');
@ -1844,8 +1851,9 @@
message = message + ' "' + stat.textContent + '"'; message = message + ' "' + stat.textContent + '"';
} }
const data = { const data = {
'message': message, 'data': `data-join="${nick}"`,
'data': `data-join="${nick}"` 'isodate': moment().format(),
'message': message
}; };
if (_.includes(_.get(last_el, 'classList', []), 'chat-info') && if (_.includes(_.get(last_el, 'classList', []), 'chat-info') &&
_.get(last_el, 'dataset', {}).joinleave === `"${nick}"`) { _.get(last_el, 'dataset', {}).joinleave === `"${nick}"`) {
@ -1861,7 +1869,7 @@
displayLeaveNotification (stanza) { displayLeaveNotification (stanza) {
const nick = Strophe.getResourceFromJid(stanza.getAttribute('from')); const nick = Strophe.getResourceFromJid(stanza.getAttribute('from'));
const stat = stanza.querySelector('status'); const stat = stanza.querySelector('status');
const last_el = this.content.querySelector(':last-child'); const last_el = this.content.lastElementChild;
if (_.includes(_.get(last_el, 'classList', []), 'chat-info') && if (_.includes(_.get(last_el, 'classList', []), 'chat-info') &&
_.get(last_el, 'dataset', {}).join === `"${nick}"`) { _.get(last_el, 'dataset', {}).join === `"${nick}"`) {
@ -1871,8 +1879,9 @@
} }
last_el.outerHTML = last_el.outerHTML =
tpl_info({ tpl_info({
'message': message, 'data': `data-joinleave="${nick}"`,
'data': `data-joinleave="${nick}"` 'isodate': moment().format(),
'message': message
}); });
} else { } else {
let message = __('%1$s has left the room.', nick); let message = __('%1$s has left the room.', nick);
@ -2078,8 +2087,9 @@
this.content.insertAdjacentHTML( this.content.insertAdjacentHTML(
'beforeend', 'beforeend',
tpl_info({ tpl_info({
'message': __('Topic set by %1$s to: %2$s', sender, subject), 'data': '',
'data': '' 'isodate': moment().format(),
'message': __('Topic set by %1$s to: %2$s', sender, subject)
})); }));
this.scrollDown(); this.scrollDown();
}, },

View File

@ -1,4 +1,4 @@
<div class="chat-message {{{o.extra_classes}}}" data-isodate="{{{o.isodate}}}"> <div class="message chat-message {{{o.extra_classes}}}" data-isodate="{{{o.isodate}}}">
<span class="chat-msg-author chat-msg-{{{o.sender}}}">{{{o.time}}} **{{{o.username}}}&nbsp;</span> <span class="chat-msg-author chat-msg-{{{o.sender}}}">{{{o.time}}} **{{{o.username}}}&nbsp;</span>
<span class="chat-msg-content chat-action"><!-- message gets added here via renderMessage --></span> <span class="chat-msg-content chat-action"><!-- message gets added here via renderMessage --></span>
</div> </div>

View File

@ -1 +1 @@
<div class="message chat-info" {{{o.data}}}>{{{o.message}}}</div> <div class="message chat-info {{{o.extra_classes}}}" data-isodate="{{{o.isodate}}}" {{{o.data}}}>{{{o.message}}}</div>