diff --git a/src/converse-chatview.js b/src/converse-chatview.js index 7933f9775..de1daf2ae 100644 --- a/src/converse-chatview.js +++ b/src/converse-chatview.js @@ -118,7 +118,7 @@ } _converse.api.listen.on('windowStateChanged', onWindowStateChanged); - _converse.EmojiPicker = Backbone.Model.extend({ + _converse.EmojiPicker = Backbone.Model.extend({ defaults: { 'current_category': 'people', 'current_skintone': '', @@ -385,23 +385,24 @@ ); }, - insertDayIndicator (date, prepend) { - /* Appends (or prepends if "prepend" is truthy) an indicator + insertDayIndicator (date, insert_method) { + /* Inserts an indicator * into the chat area, showing the day as given by the * passed in date. * * Parameters: * (String) date - An ISO8601 date string. + * (Function) insert_method - The method to be used to + * insert the indicator */ const day_date = moment(date).startOf('day'); - const insert = prepend ? $(this.content).prepend: $(this.content).append; - insert.call($(this.content), tpl_new_day({ + insert_method(tpl_new_day({ isodate: day_date.format(), datestring: day_date.format("dddd MMM Do YYYY") })); }, - insertMessage (attrs, prepend) { + insertMessage (attrs, insert_method) { /* Helper method which appends a message (or prepends if the * 2nd parameter is set to true) to the end of the chat box's * content area. @@ -409,15 +410,35 @@ * Parameters: * (Object) attrs: An object containing the message attributes. */ - const insert = prepend ? $(this.content).prepend : $(this.content).append; _.flow(($el) => { - insert.call($(this.content), $el); + insert_method($el[0]); return $el; }, this.scrollDown.bind(this) )(this.renderMessage(attrs)); }, + getLastMessageDate (cutoff) { + /* Return the ISO8601 format date of the latest message. + * + * Parameters: + * (Object) cutoff: Moment Date cutoff date. The last + * message received cutoff this date will be returned. + */ + if (!cutoff) { + const last_msg = this.content.lastElementChild; + return last_msg ? last_msg.getAttribute('data-isodate') : null + } + const msg_dates = _.invokeMap( + this.content.querySelector('.message'), + Element.prototype.getAttribute, + 'data-isodate' + ) + msg_dates.push(cutoff.format()); + msg_dates.sort(); + return msg_dates[msg_dates.indexOf(cutoff)-1]; + }, + showMessage (attrs) { /* Inserts a chat message into the content area of the chat box. * Will also insert a new day indicator if the message is on a @@ -430,62 +451,52 @@ * (Object) attrs: An object containing the message * attributes. */ - let current_msg_date = moment(attrs.time) || moment; - const first_msg_el = this.content.firstElementChild, - first_msg_date = first_msg_el ? first_msg_el.getAttribute('data-isodate') : null; + const current_msg_date = moment(attrs.time) || moment, + first_msg_el = this.content.firstElementChild, + first_msg_date = first_msg_el ? first_msg_el.getAttribute('data-isodate') : null, + append_element = _.bind(this.content.insertAdjacentElement, this.content, 'beforeend'), + append_html = _.bind(this.content.insertAdjacentHTML, this.content, 'beforeend'); if (!first_msg_date) { // This is the first received message, so we insert a // date indicator before it. - this.insertDayIndicator(current_msg_date); - this.insertMessage(attrs); + this.insertDayIndicator(current_msg_date, append_html); + this.insertMessage(attrs, append_element); return; } - const last_msg_el = this.content.lastElementChild, - last_msg_date = last_msg_el.getAttribute('data-isodate'); + const last_msg_date = this.getLastMessageDate(); if (current_msg_date.isAfter(last_msg_date) || current_msg_date.isSame(last_msg_date)) { // The new message is after the last message if (current_msg_date.isAfter(last_msg_date, 'day')) { // Append a new day indicator - this.insertDayIndicator(current_msg_date); + this.insertDayIndicator(current_msg_date, append_html); } - this.insertMessage(attrs); + this.insertMessage(attrs, append_element); return; } + if (current_msg_date.isBefore(first_msg_date) || current_msg_date.isSame(first_msg_date)) { // The message is before the first, but on the same day. // We need to prepend the message immediately before the // first message (so that it'll still be after the day // indicator). - this.insertMessage(attrs, 'prepend'); + const prepend_element = _.bind(this.content.insertAdjacentElement, this.content, 'afterbegin'); + this.insertMessage(attrs, prepend_element); if (current_msg_date.isBefore(first_msg_date, 'day')) { // This message is also on a different day, so // we prepend a day indicator. - this.insertDayIndicator(current_msg_date, 'prepend'); + this.insertDayIndicator(current_msg_date, append_html); } return; } - // Find the correct place to position the message - current_msg_date = current_msg_date.format(); - const msg_dates = _.invokeMap( - this.content.querySelector('.message'), - Element.prototype.getAttribute, - 'data-isodate' - ) - msg_dates.push(current_msg_date); - msg_dates.sort(); - - const idx = msg_dates.indexOf(current_msg_date)-1; - const latest_msg_el = this.content.querySelector(`.message[data-isodate="${msg_dates[idx]}"]`); - _.flow(($el) => { - $el.insertAfter(latest_msg_el); - return $el; - }, - this.scrollDown.bind(this) - )(this.renderMessage(attrs)); + const previous_msg_date = this.getLastMessageDate(current_msg_date); + const previous_msg_el = this.content.querySelector( + `.message[data-isodate="${previous_msg_date}"]`); + this.insertMessage( + attrs, _.bind(previous_msg_el.insertAdjacentElement, previous_msg_el, 'afterend')); }, getExtraMessageTemplateAttributes () {