From 5d778a7646dc27d94cfd683704232cec5868a284 Mon Sep 17 00:00:00 2001 From: Paul Holden Date: Tue, 13 Oct 2020 00:08:54 +0100 Subject: [PATCH] MDL-65135 message: use full date in messaging drawer for old messages. Messages sent in previous years will now include the year portion of the date string. --- ...e_drawer_view_conversation_renderer.min.js | 2 +- ...awer_view_conversation_renderer.min.js.map | 2 +- ...ssage_drawer_view_conversation_renderer.js | 2 ++ ...drawer_view_conversation_body_day.mustache | 21 ++++++++++++++----- 4 files changed, 20 insertions(+), 7 deletions(-) diff --git a/message/amd/build/message_drawer_view_conversation_renderer.min.js b/message/amd/build/message_drawer_view_conversation_renderer.min.js index 9c3f4f9da17..2db09223307 100644 --- a/message/amd/build/message_drawer_view_conversation_renderer.min.js +++ b/message/amd/build/message_drawer_view_conversation_renderer.min.js @@ -1,2 +1,2 @@ -define ("core_message/message_drawer_view_conversation_renderer",["jquery","core/notification","core/str","core/templates","core/user_date","core_message/message_drawer_view_conversation_constants","core/aria"],function(a,b,c,d,e,f,g){var h=f.SELECTORS,i=f.TEMPLATES,j=f.CONVERSATION_TYPES,k=function(a){return a.find(h.CONTENT_MESSAGES_CONTAINER)},l=function(a){k(a).removeClass("hidden")},m=function(a){k(a).addClass("hidden")},n=function(a){return a.find(h.SELF_CONVERSATION_MESSAGE_CONTAINER)},o=function(a){return n(a).addClass("hidden")},p=function(a){return a.find(h.CONTACT_REQUEST_SENT_MESSAGE_CONTAINER)},q=function(a){return p(a).addClass("hidden")},r=function(a){return a.find(h.CONTENT_MESSAGES_FOOTER_CONTAINER)},s=function(a){r(a).removeClass("hidden")},t=function(a){r(a).addClass("hidden")},u=function(a){return a.find(h.CONTENT_MESSAGES_FOOTER_EDIT_MODE_CONTAINER)},v=function(a){u(a).removeClass("hidden")},w=function(a){u(a).addClass("hidden")},x=function(a){return a.find(h.PLACEHOLDER_CONTAINER)},y=function(a){x(a).removeClass("hidden")},z=function(a){x(a).addClass("hidden")},A=function(a){return a.find(h.CONTENT_MESSAGES_FOOTER_REQUIRE_CONTACT_CONTAINER)},B=function(a){A(a).removeClass("hidden")},C=function(a){A(a).addClass("hidden")},D=function(a){return a.find(h.CONTENT_MESSAGES_FOOTER_REQUIRE_UNBLOCK_CONTAINER)},E=function(a){D(a).removeClass("hidden")},F=function(a){D(a).addClass("hidden")},G=function(a){return a.find(h.CONTENT_MESSAGES_FOOTER_UNABLE_TO_MESSAGE_CONTAINER)},H=function(a){G(a).removeClass("hidden")},I=function(a){G(a).addClass("hidden")},J=function(a){Q(a);T(a);W(a)},K=function(a){t(a);w(a);z(a);C(a);F(a);I(a)},L=function(a){return a.find(h.CONTENT_PLACEHOLDER_CONTAINER)},M=function(a){L(a).removeClass("hidden")},N=function(a){L(a).addClass("hidden")},O=function(a){return a.find(h.HEADER)},P=function(a){O(a).removeClass("hidden")},Q=function(a){O(a).addClass("hidden")},R=function(a){return a.find(h.HEADER_EDIT_MODE)},S=function(a){R(a).removeClass("hidden")},T=function(a){R(a).addClass("hidden")},U=function(a){return a.find(h.HEADER_PLACEHOLDER_CONTAINER)},V=function(a){U(a).removeClass("hidden")},W=function(a){U(a).addClass("hidden")},X=function(a){return a.find(h.EMOJI_PICKER_CONTAINER)},Y=function(a){return a.find(h.EMOJI_AUTO_COMPLETE_CONTAINER)},Z=function(a,b){var c=k(a);return c.find("[data-message-id=\""+b+"\"]")},$=function(a,b){var c=k(a);return c.find("[data-day-id=\""+b+"\"]")},_=function(a){return a.find(h.MORE_MESSAGES_LOADING_ICON_CONTAINER)},aa=function(a){_(a).removeClass("hidden")},ba=function(a){_(a).addClass("hidden")},ca=function(a){return a.find(h.CONFIRM_DIALOGUE_CONTAINER)},da=function(a){var b=ca(a),c=b.siblings(":not(.hidden)");g.hide(c.get());c.attr("data-confirm-dialogue-hidden",!0);b.removeClass("hidden")},ea=function(a){var b=ca(a),c=b.siblings("[data-confirm-dialogue-hidden=\"true\"]");g.unhide(c.get());c.removeAttr("data-confirm-dialogue-hidden");b.addClass("hidden")},fa=function(a,b){R(a).find(h.MESSAGES_SELECTED_COUNT).text(b)},ga=function(a,b){return a.map(function(a){return{id:a.id,isread:a.isRead,fromloggedinuser:a.fromLoggedInUser,userfrom:a.userFrom,text:a.text,formattedtime:a.timeCreated?b[a.timeCreated]:null}})},ha=function(b,c,e,f,g){var h=k(c),j=f.map(function(a){return d.render(i.DAY,{timestamp:a.value.timestamp,messages:ga(a.value.messages,g)})});return a.when.apply(a,j).then(function(){f.forEach(function(b,d){j[d].then(function(d){if(b.before){var e=$(c,b.before.timestamp);return a(d).insertBefore(e)}else{return h.append(d)}}).catch(function(){})})})},ia=function(b,c,e,f,g){var j=f.map(function(a){return a.value}),k=ga(j,g);return d.render(i.MESSAGES,{messages:k}).then(function(b){var d=a(b);f.forEach(function(a){var b=d.find("[data-message-id=\""+a.value.id+"\"]");if(a.before){var e=Z(c,a.before.id);return b.insertBefore(e)}else{var f=$(c,a.day.timestamp),g=f.find(h.DAY_MESSAGES_CONTAINER);return g.append(b)}})})},ja=function(a,b,c,d,e){d.forEach(function(a){var c=a.before,d=a.after,f=Z(b,c.id);if(c.id!=d.id){f.attr("data-message-id",d.id)}if(c.timeCreated!=d.timeCreated){var i=e[d.timeCreated];f.find(h.LOADING_ICON_CONTAINER).addClass("hidden");f.find(h.TIME_CREATED).text(i).removeClass("hidden")}if(c.sendState!=d.sendState){var j=f.find(h.LOADING_ICON_CONTAINER),k=f.find(h.TIME_CREATED),l=f.find(h.RETRY_SEND);j.addClass("hidden");g.hide(j.get());k.addClass("hidden");g.hide(k.get());l.addClass("hidden");g.hide(l.get());f.removeClass("border border-danger");switch(d.sendState){case"pending":j.removeClass("hidden");g.unhide(j.get());break;case"error":l.removeClass("hidden");g.unhide(l.get());f.addClass("border border-danger");break;case"sent":k.removeClass("hidden");g.unhide(k.get());break;}}if(c.text!=d.text){f.find(h.TEXT_CONTAINER).html(d.text)}if(c.errorMessage!=d.errorMessage){var m=f.find(h.ERROR_MESSAGE_CONTAINER),a=m.find(h.ERROR_MESSAGE);if(d.errorMessage){m.removeClass("hidden");g.unhide(m.get());a.text(d.errorMessage)}else{m.addClass("hidden");g.unhide(m.get());a.text("")}}})},ka=function(a,b){b.forEach(function(b){$(a,b.timestamp).remove()})},la=function(a,b){b.forEach(function(b){Z(a,b.id).remove()})},ma=function(b,d,f,g){var h=[],i=0");q.text(g);var r=l.find(h.CONFIRM_DIALOGUE);r.prepend(q)}else if(q.length){q.remove()}m.forEach(function(a){a.removeClass("hidden")});p.text(f);da(d);da(c);if(!j){da(b)}l.find(h.CAN_RECEIVE_FOCUS).filter(":visible").first().focus()},wa=function(a,b,c){var d=ca(b),e=d.find(h.CONFIRM_DIALOGUE_CANCEL_BUTTON),f=d.find(h.CONFIRM_DIALOGUE_OKAY_BUTTON),g=d.find(h.CONFIRM_DIALOGUE_TEXT),i=d.find(h.CONFIRM_DIALOGUE_HEADER);Fa(b);ea(b);ea(c);ea(a);d.find("button").addClass("hidden");e.removeClass("hidden");f.removeClass("hidden");g.text("");if(i.length){i.remove()}a.find(h.CAN_RECEIVE_FOCUS).first().focus();return!0},xa=function(a,b,d,e){if(e){if(e.canmessageevenifblocked){return c.get_string("cantblockuser","core_message",e.fullname).then(function(c){return va(a,b,d,[],c,"",!1,!1,!0)})}else{return c.get_string("blockuserconfirm","core_message",e.fullname).then(function(c){return va(a,b,d,[h.ACTION_CONFIRM_BLOCK],c,"",!0,!1)})}}else{return wa(a,b,d)}},ya=function(a,b,d,e){if(e){return c.get_string("unblockuserconfirm","core_message",e.fullname).then(function(c){return va(a,b,d,[h.ACTION_CONFIRM_UNBLOCK],c,"",!0,!1)})}else{return wa(a,b,d)}},za=function(a,b,d,e){if(e){return c.get_string("addcontactconfirm","core_message",e.fullname).then(function(c){return va(a,b,d,[h.ACTION_CONFIRM_ADD_CONTACT],c,"",!0,!1)})}else{return wa(a,b,d)}},Aa=function(a,b,d,e){if(e){return c.get_string("removecontactconfirm","core_message",e.fullname).then(function(c){return va(a,b,d,[h.ACTION_CONFIRM_REMOVE_CONTACT],c,"",!0,!1)})}else{return wa(a,b,d)}},Ba=function(a,b,d,e){var f=null;if(e.type==j.SELF){f="deleteselectedmessagesconfirmselfconversation"}else{if(e.canDeleteMessagesForAllUsers){Ea(b);f="deleteforeveryoneselectedmessagesconfirm"}else{f="deleteselectedmessagesconfirm"}}if(e.show){return c.get_string(f,"core_message").then(function(c){return va(a,b,d,[h.ACTION_CONFIRM_DELETE_SELECTED_MESSAGES],c,"",!0,!1)})}else{return wa(a,b,d)}},Ca=function(a,b,d,e){var f=null;if(e==j.SELF){f="deleteallselfconfirm"}else if(e){f="deleteallconfirm"}if(f){return c.get_string(f,"core_message").then(function(c){return va(a,b,d,[h.ACTION_CONFIRM_DELETE_CONVERSATION],c,"",!0,!1)})}else{return wa(a,b,d)}},Da=function(a,b,d,e){if(e){return c.get_string("userwouldliketocontactyou","core_message",e.fullname).then(function(c){var e=[h.ACTION_ACCEPT_CONTACT_REQUEST,h.ACTION_DECLINE_CONTACT_REQUEST];return va(a,b,d,e,c,"",!1,!0)})}else{return wa(a,b,d)}},Ea=function(a){var b=ca(a),c=b.find(h.DELETE_MESSAGES_FOR_ALL_USERS_TOGGLE_CONTAINER);c.removeClass("hidden")},Fa=function(a){var b=ca(a),c=b.find(h.DELETE_MESSAGES_FOR_ALL_USERS_TOGGLE_CONTAINER),d=b.find(h.DELETE_MESSAGES_FOR_ALL_USERS_TOGGLE);d.prop("checked",!1);c.addClass("hidden")},Ga=function(a,b,c,d){if(d){a.find(h.ACTION_REQUEST_BLOCK).addClass("hidden");a.find(h.ACTION_REQUEST_UNBLOCK).removeClass("hidden")}else{a.find(h.ACTION_REQUEST_BLOCK).removeClass("hidden");a.find(h.ACTION_REQUEST_UNBLOCK).addClass("hidden")}},Ha=function(a,b,c,d){var e=a.find(h.FAVOURITE_ICON_CONTAINER),f=a.find(h.ACTION_CONFIRM_FAVOURITE),g=a.find(h.ACTION_CONFIRM_UNFAVOURITE);switch(d){case"hide":e.addClass("hidden");f.addClass("hidden");g.addClass("hidden");break;case"show-add":e.addClass("hidden");f.removeClass("hidden");g.addClass("hidden");break;case"show-remove":e.removeClass("hidden");f.addClass("hidden");g.removeClass("hidden");break;}},Ia=function(a,b,c,d){var e=a.find(h.MUTED_ICON_CONTAINER),f=a.find(h.ACTION_CONFIRM_MUTE),g=a.find(h.ACTION_CONFIRM_UNMUTE);switch(d){case"hide":e.addClass("hidden");f.addClass("hidden");g.addClass("hidden");break;case"show-mute":e.addClass("hidden");f.removeClass("hidden");g.addClass("hidden");break;case"show-unmute":e.removeClass("hidden");f.addClass("hidden");g.removeClass("hidden");break;}},Ja=function(a,b,c,d){var e=a.find(h.ACTION_REQUEST_ADD_CONTACT),f=a.find(h.ACTION_REQUEST_REMOVE_CONTACT);switch(d){case"pending-contact":e.addClass("hidden");f.addClass("hidden");break;case"contact":e.addClass("hidden");f.removeClass("hidden");break;case"non-contact":e.removeClass("hidden");f.addClass("hidden");break;}},Ka=function(a,b,c,d){var e=ca(b),f=e.find("button"),g=e.find(h.CONFIRM_DIALOGUE_BUTTON_TEXT),i=e.find(h.LOADING_ICON_CONTAINER);if(d){f.prop("disabled",!0);g.addClass("hidden");i.removeClass("hidden")}else{f.prop("disabled",!1);g.removeClass("hidden");i.addClass("hidden")}},La=function(a,b,c,d){var e=null;if(d){e=b.find(h.MESSAGE_NOT_SELECTED);e.find(h.MESSAGE_NOT_SELECTED_ICON).removeClass("hidden");Q(a);S(a)}else{e=k(b);e.find(h.MESSAGE_NOT_SELECTED_ICON).addClass("hidden");e.find(h.MESSAGE_SELECTED_ICON).addClass("hidden");P(a);T(a)}},Ma=function(a,b,c,d){var e=0");q.text(g);var r=l.find(h.CONFIRM_DIALOGUE);r.prepend(q)}else if(q.length){q.remove()}m.forEach(function(a){a.removeClass("hidden")});p.text(f);da(d);da(c);if(!j){da(b)}l.find(h.CAN_RECEIVE_FOCUS).filter(":visible").first().focus()},wa=function(a,b,c){var d=ca(b),e=d.find(h.CONFIRM_DIALOGUE_CANCEL_BUTTON),f=d.find(h.CONFIRM_DIALOGUE_OKAY_BUTTON),g=d.find(h.CONFIRM_DIALOGUE_TEXT),i=d.find(h.CONFIRM_DIALOGUE_HEADER);Fa(b);ea(b);ea(c);ea(a);d.find("button").addClass("hidden");e.removeClass("hidden");f.removeClass("hidden");g.text("");if(i.length){i.remove()}a.find(h.CAN_RECEIVE_FOCUS).first().focus();return!0},xa=function(a,b,d,e){if(e){if(e.canmessageevenifblocked){return c.get_string("cantblockuser","core_message",e.fullname).then(function(c){return va(a,b,d,[],c,"",!1,!1,!0)})}else{return c.get_string("blockuserconfirm","core_message",e.fullname).then(function(c){return va(a,b,d,[h.ACTION_CONFIRM_BLOCK],c,"",!0,!1)})}}else{return wa(a,b,d)}},ya=function(a,b,d,e){if(e){return c.get_string("unblockuserconfirm","core_message",e.fullname).then(function(c){return va(a,b,d,[h.ACTION_CONFIRM_UNBLOCK],c,"",!0,!1)})}else{return wa(a,b,d)}},za=function(a,b,d,e){if(e){return c.get_string("addcontactconfirm","core_message",e.fullname).then(function(c){return va(a,b,d,[h.ACTION_CONFIRM_ADD_CONTACT],c,"",!0,!1)})}else{return wa(a,b,d)}},Aa=function(a,b,d,e){if(e){return c.get_string("removecontactconfirm","core_message",e.fullname).then(function(c){return va(a,b,d,[h.ACTION_CONFIRM_REMOVE_CONTACT],c,"",!0,!1)})}else{return wa(a,b,d)}},Ba=function(a,b,d,e){var f=null;if(e.type==j.SELF){f="deleteselectedmessagesconfirmselfconversation"}else{if(e.canDeleteMessagesForAllUsers){Ea(b);f="deleteforeveryoneselectedmessagesconfirm"}else{f="deleteselectedmessagesconfirm"}}if(e.show){return c.get_string(f,"core_message").then(function(c){return va(a,b,d,[h.ACTION_CONFIRM_DELETE_SELECTED_MESSAGES],c,"",!0,!1)})}else{return wa(a,b,d)}},Ca=function(a,b,d,e){var f=null;if(e==j.SELF){f="deleteallselfconfirm"}else if(e){f="deleteallconfirm"}if(f){return c.get_string(f,"core_message").then(function(c){return va(a,b,d,[h.ACTION_CONFIRM_DELETE_CONVERSATION],c,"",!0,!1)})}else{return wa(a,b,d)}},Da=function(a,b,d,e){if(e){return c.get_string("userwouldliketocontactyou","core_message",e.fullname).then(function(c){var e=[h.ACTION_ACCEPT_CONTACT_REQUEST,h.ACTION_DECLINE_CONTACT_REQUEST];return va(a,b,d,e,c,"",!1,!0)})}else{return wa(a,b,d)}},Ea=function(a){var b=ca(a),c=b.find(h.DELETE_MESSAGES_FOR_ALL_USERS_TOGGLE_CONTAINER);c.removeClass("hidden")},Fa=function(a){var b=ca(a),c=b.find(h.DELETE_MESSAGES_FOR_ALL_USERS_TOGGLE_CONTAINER),d=b.find(h.DELETE_MESSAGES_FOR_ALL_USERS_TOGGLE);d.prop("checked",!1);c.addClass("hidden")},Ga=function(a,b,c,d){if(d){a.find(h.ACTION_REQUEST_BLOCK).addClass("hidden");a.find(h.ACTION_REQUEST_UNBLOCK).removeClass("hidden")}else{a.find(h.ACTION_REQUEST_BLOCK).removeClass("hidden");a.find(h.ACTION_REQUEST_UNBLOCK).addClass("hidden")}},Ha=function(a,b,c,d){var e=a.find(h.FAVOURITE_ICON_CONTAINER),f=a.find(h.ACTION_CONFIRM_FAVOURITE),g=a.find(h.ACTION_CONFIRM_UNFAVOURITE);switch(d){case"hide":e.addClass("hidden");f.addClass("hidden");g.addClass("hidden");break;case"show-add":e.addClass("hidden");f.removeClass("hidden");g.addClass("hidden");break;case"show-remove":e.removeClass("hidden");f.addClass("hidden");g.removeClass("hidden");break;}},Ia=function(a,b,c,d){var e=a.find(h.MUTED_ICON_CONTAINER),f=a.find(h.ACTION_CONFIRM_MUTE),g=a.find(h.ACTION_CONFIRM_UNMUTE);switch(d){case"hide":e.addClass("hidden");f.addClass("hidden");g.addClass("hidden");break;case"show-mute":e.addClass("hidden");f.removeClass("hidden");g.addClass("hidden");break;case"show-unmute":e.removeClass("hidden");f.addClass("hidden");g.removeClass("hidden");break;}},Ja=function(a,b,c,d){var e=a.find(h.ACTION_REQUEST_ADD_CONTACT),f=a.find(h.ACTION_REQUEST_REMOVE_CONTACT);switch(d){case"pending-contact":e.addClass("hidden");f.addClass("hidden");break;case"contact":e.addClass("hidden");f.removeClass("hidden");break;case"non-contact":e.removeClass("hidden");f.addClass("hidden");break;}},Ka=function(a,b,c,d){var e=ca(b),f=e.find("button"),g=e.find(h.CONFIRM_DIALOGUE_BUTTON_TEXT),i=e.find(h.LOADING_ICON_CONTAINER);if(d){f.prop("disabled",!0);g.addClass("hidden");i.removeClass("hidden")}else{f.prop("disabled",!1);g.removeClass("hidden");i.addClass("hidden")}},La=function(a,b,c,d){var e=null;if(d){e=b.find(h.MESSAGE_NOT_SELECTED);e.find(h.MESSAGE_NOT_SELECTED_ICON).removeClass("hidden");Q(a);S(a)}else{e=k(b);e.find(h.MESSAGE_NOT_SELECTED_ICON).addClass("hidden");e.find(h.MESSAGE_SELECTED_ICON).addClass("hidden");P(a);T(a)}},Ma=function(a,b,c,d){var e=0.\n\n/**\n * This module updates the UI for the conversation page in the message\n * drawer.\n *\n * The module will take a patch from the message_drawer_view_conversation_patcher\n * module and update the UI to reflect the changes.\n *\n * This is the only module that ever modifies the UI of the conversation page.\n *\n * @module core_message/message_drawer_view_conversation_renderer\n * @copyright 2018 Ryan Wyllie \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\ndefine(\n[\n 'jquery',\n 'core/notification',\n 'core/str',\n 'core/templates',\n 'core/user_date',\n 'core_message/message_drawer_view_conversation_constants',\n 'core/aria',\n],\nfunction(\n $,\n Notification,\n Str,\n Templates,\n UserDate,\n Constants,\n Aria\n) {\n var SELECTORS = Constants.SELECTORS;\n var TEMPLATES = Constants.TEMPLATES;\n var CONVERSATION_TYPES = Constants.CONVERSATION_TYPES;\n\n /**\n * Get the messages container element.\n *\n * @param {Object} body Conversation body container element.\n * @return {Object} The messages container element.\n */\n var getMessagesContainer = function(body) {\n return body.find(SELECTORS.CONTENT_MESSAGES_CONTAINER);\n };\n\n /**\n * Show the messages container element.\n *\n * @param {Object} body Conversation body container element.\n */\n var showMessagesContainer = function(body) {\n getMessagesContainer(body).removeClass('hidden');\n };\n\n /**\n * Hide the messages container element.\n *\n * @param {Object} body Conversation body container element.\n */\n var hideMessagesContainer = function(body) {\n getMessagesContainer(body).addClass('hidden');\n };\n\n /**\n * Get the self-conversation message container element.\n *\n * @param {Object} body Conversation body container element.\n * @return {Object} The messages container element.\n */\n var getSelfConversationMessageContainer = function(body) {\n return body.find(SELECTORS.SELF_CONVERSATION_MESSAGE_CONTAINER);\n };\n\n /**\n * Hide the self-conversation message container element.\n *\n * @param {Object} body Conversation body container element.\n * @return {Object} The messages container element.\n */\n var hideSelfConversationMessageContainer = function(body) {\n return getSelfConversationMessageContainer(body).addClass('hidden');\n };\n\n /**\n * Get the contact request sent container element.\n *\n * @param {Object} body Conversation body container element.\n * @return {Object} The messages container element.\n */\n var getContactRequestSentContainer = function(body) {\n return body.find(SELECTORS.CONTACT_REQUEST_SENT_MESSAGE_CONTAINER);\n };\n\n /**\n * Hide the contact request sent container element.\n *\n * @param {Object} body Conversation body container element.\n * @return {Object} The messages container element.\n */\n var hideContactRequestSentContainer = function(body) {\n return getContactRequestSentContainer(body).addClass('hidden');\n };\n\n /**\n * Get the footer container element.\n *\n * @param {Object} footer Conversation footer container element.\n * @return {Object} The footer container element.\n */\n var getFooterContentContainer = function(footer) {\n return footer.find(SELECTORS.CONTENT_MESSAGES_FOOTER_CONTAINER);\n };\n\n /**\n * Show the footer container element.\n *\n * @param {Object} footer Conversation footer container element.\n */\n var showFooterContent = function(footer) {\n getFooterContentContainer(footer).removeClass('hidden');\n };\n\n /**\n * Hide the footer container element.\n *\n * @param {Object} footer Conversation footer container element.\n */\n var hideFooterContent = function(footer) {\n getFooterContentContainer(footer).addClass('hidden');\n };\n\n /**\n * Get the footer edit mode container element.\n *\n * @param {Object} footer Conversation footer container element.\n * @return {Object} The footer container element.\n */\n var getFooterEditModeContainer = function(footer) {\n return footer.find(SELECTORS.CONTENT_MESSAGES_FOOTER_EDIT_MODE_CONTAINER);\n };\n\n /**\n * Show the footer edit mode container element.\n *\n * @param {Object} footer Conversation footer container element.\n */\n var showFooterEditMode = function(footer) {\n getFooterEditModeContainer(footer).removeClass('hidden');\n };\n\n /**\n * Hide the footer edit mode container element.\n *\n * @param {Object} footer Conversation footer container element.\n */\n var hideFooterEditMode = function(footer) {\n getFooterEditModeContainer(footer).addClass('hidden');\n };\n\n /**\n * Get the footer placeholder.\n *\n * @param {Object} footer Conversation footer container element.\n * @return {Object} The footer placeholder container element.\n */\n var getFooterPlaceholderContainer = function(footer) {\n return footer.find(SELECTORS.PLACEHOLDER_CONTAINER);\n };\n\n /**\n * Show the footer placeholder\n *\n * @param {Object} footer Conversation footer container element.\n */\n var showFooterPlaceholder = function(footer) {\n getFooterPlaceholderContainer(footer).removeClass('hidden');\n };\n\n /**\n * Hide the footer placeholder\n *\n * @param {Object} footer Conversation footer container element.\n */\n var hideFooterPlaceholder = function(footer) {\n getFooterPlaceholderContainer(footer).addClass('hidden');\n };\n\n /**\n * Get the footer Require add as contact container element.\n *\n * @param {Object} footer Conversation footer container element.\n * @return {Object} The footer Require add as contact container element.\n */\n var getFooterRequireContactContainer = function(footer) {\n return footer.find(SELECTORS.CONTENT_MESSAGES_FOOTER_REQUIRE_CONTACT_CONTAINER);\n };\n\n /**\n * Show the footer add as contact dialogue.\n *\n * @param {Object} footer Conversation footer container element.\n */\n var showFooterRequireContact = function(footer) {\n getFooterRequireContactContainer(footer).removeClass('hidden');\n };\n\n /**\n * Hide the footer add as contact dialogue.\n *\n * @param {Object} footer Conversation footer container element.\n */\n var hideFooterRequireContact = function(footer) {\n getFooterRequireContactContainer(footer).addClass('hidden');\n };\n\n /**\n * Get the footer Required to unblock contact container element.\n *\n * @param {Object} footer Conversation footer container element.\n * @return {Object} The footer Required to unblock contact container element.\n */\n var getFooterRequireUnblockContainer = function(footer) {\n return footer.find(SELECTORS.CONTENT_MESSAGES_FOOTER_REQUIRE_UNBLOCK_CONTAINER);\n };\n\n /**\n * Show the footer Required to unblock contact container element.\n *\n * @param {Object} footer Conversation footer container element.\n */\n var showFooterRequireUnblock = function(footer) {\n getFooterRequireUnblockContainer(footer).removeClass('hidden');\n };\n\n /**\n * Hide the footer Required to unblock contact container element.\n *\n * @param {Object} footer Conversation footer container element.\n */\n var hideFooterRequireUnblock = function(footer) {\n getFooterRequireUnblockContainer(footer).addClass('hidden');\n };\n\n /**\n * Get the footer Unable to message contact container element.\n *\n * @param {Object} footer Conversation footer container element.\n * @return {Object} The footer Unable to message contact container element.\n */\n var getFooterUnableToMessageContainer = function(footer) {\n return footer.find(SELECTORS.CONTENT_MESSAGES_FOOTER_UNABLE_TO_MESSAGE_CONTAINER);\n };\n\n /**\n * Show the footer Unable to message contact container element.\n *\n * @param {Object} footer Conversation footer container element.\n */\n var showFooterUnableToMessage = function(footer) {\n getFooterUnableToMessageContainer(footer).removeClass('hidden');\n };\n\n /**\n * Hide the footer Unable to message contact container element.\n *\n * @param {Object} footer Conversation footer container element.\n */\n var hideFooterUnableToMessage = function(footer) {\n getFooterUnableToMessageContainer(footer).addClass('hidden');\n };\n\n /**\n * Hide all header elements.\n *\n * @param {Object} header Conversation header container element.\n */\n var hideAllHeaderElements = function(header) {\n hideHeaderContent(header);\n hideHeaderEditMode(header);\n hideHeaderPlaceholder(header);\n };\n\n /**\n * Hide all footer dialogues and messages.\n *\n * @param {Object} footer Conversation footer container element.\n */\n var hideAllFooterElements = function(footer) {\n hideFooterContent(footer);\n hideFooterEditMode(footer);\n hideFooterPlaceholder(footer);\n hideFooterRequireContact(footer);\n hideFooterRequireUnblock(footer);\n hideFooterUnableToMessage(footer);\n };\n\n /**\n * Get the content placeholder container element.\n *\n * @param {Object} body Conversation body container element.\n * @return {Object} The body placeholder container element.\n */\n var getContentPlaceholderContainer = function(body) {\n return body.find(SELECTORS.CONTENT_PLACEHOLDER_CONTAINER);\n };\n\n /**\n * Show the content placeholder.\n *\n * @param {Object} body Conversation body container element.\n */\n var showContentPlaceholder = function(body) {\n getContentPlaceholderContainer(body).removeClass('hidden');\n };\n\n /**\n * Hide the content placeholder.\n *\n * @param {Object} body Conversation body container element.\n */\n var hideContentPlaceholder = function(body) {\n getContentPlaceholderContainer(body).addClass('hidden');\n };\n\n /**\n * Get the header content container element.\n *\n * @param {Object} header Conversation header container element.\n * @return {Object} The header content container element.\n */\n var getHeaderContent = function(header) {\n return header.find(SELECTORS.HEADER);\n };\n\n /**\n * Show the header content.\n *\n * @param {Object} header Conversation header container element.\n */\n var showHeaderContent = function(header) {\n getHeaderContent(header).removeClass('hidden');\n };\n\n /**\n * Hide the header content.\n *\n * @param {Object} header Conversation header container element.\n */\n var hideHeaderContent = function(header) {\n getHeaderContent(header).addClass('hidden');\n };\n\n /**\n * Get the header edit mode container element.\n *\n * @param {Object} header Conversation header container element.\n * @return {Object} The header content container element.\n */\n var getHeaderEditMode = function(header) {\n return header.find(SELECTORS.HEADER_EDIT_MODE);\n };\n\n /**\n * Show the header edit mode container.\n *\n * @param {Object} header Conversation header container element.\n */\n var showHeaderEditMode = function(header) {\n getHeaderEditMode(header).removeClass('hidden');\n };\n\n /**\n * Hide the header edit mode container.\n *\n * @param {Object} header Conversation header container element.\n */\n var hideHeaderEditMode = function(header) {\n getHeaderEditMode(header).addClass('hidden');\n };\n\n /**\n * Get the header placeholder container element.\n *\n * @param {Object} header Conversation header container element.\n * @return {Object} The header placeholder container element.\n */\n var getHeaderPlaceholderContainer = function(header) {\n return header.find(SELECTORS.HEADER_PLACEHOLDER_CONTAINER);\n };\n\n /**\n * Show the header placeholder.\n *\n * @param {Object} header Conversation header container element.\n */\n var showHeaderPlaceholder = function(header) {\n getHeaderPlaceholderContainer(header).removeClass('hidden');\n };\n\n /**\n * Hide the header placeholder.\n *\n * @param {Object} header Conversation header container element.\n */\n var hideHeaderPlaceholder = function(header) {\n getHeaderPlaceholderContainer(header).addClass('hidden');\n };\n\n /**\n * Get the emoji picker container element.\n *\n * @param {Object} footer Conversation footer container element.\n * @return {Object} The emoji picker container element.\n */\n var getEmojiPickerContainer = function(footer) {\n return footer.find(SELECTORS.EMOJI_PICKER_CONTAINER);\n };\n\n /**\n * Get the emoji picker container element.\n *\n * @param {Object} footer Conversation footer container element.\n * @return {Object} The emoji picker container element.\n */\n var getEmojiAutoCompleteContainer = function(footer) {\n return footer.find(SELECTORS.EMOJI_AUTO_COMPLETE_CONTAINER);\n };\n\n /**\n * Get a message element.\n *\n * @param {Object} body Conversation body container element.\n * @param {Number} messageId the Message id.\n * @return {Object} A message element from the conversation.\n */\n var getMessageElement = function(body, messageId) {\n var messagesContainer = getMessagesContainer(body);\n return messagesContainer.find('[data-message-id=\"' + messageId + '\"]');\n };\n\n /**\n * Get the day container element. The day container element holds a list of messages for that day.\n *\n * @param {Object} body Conversation body container element.\n * @param {Number} dayTimeCreated Midnight timestamp for the day.\n * @return {Object} jQuery object\n */\n var getDayElement = function(body, dayTimeCreated) {\n var messagesContainer = getMessagesContainer(body);\n return messagesContainer.find('[data-day-id=\"' + dayTimeCreated + '\"]');\n };\n\n /**\n * Get the more messages loading icon container element.\n *\n * @param {Object} body Conversation body container element.\n * @return {Object} The more messages loading container element.\n */\n var getMoreMessagesLoadingIconContainer = function(body) {\n return body.find(SELECTORS.MORE_MESSAGES_LOADING_ICON_CONTAINER);\n };\n\n /**\n * Show the more messages loading icon.\n *\n * @param {Object} body Conversation body container element.\n */\n var showMoreMessagesLoadingIcon = function(body) {\n getMoreMessagesLoadingIconContainer(body).removeClass('hidden');\n };\n\n /**\n * Hide the more messages loading icon.\n *\n * @param {Object} body Conversation body container element.\n */\n var hideMoreMessagesLoadingIcon = function(body) {\n getMoreMessagesLoadingIconContainer(body).addClass('hidden');\n };\n\n /**\n * Get the confirm dialogue container element.\n *\n * @param {Object} root The container element to search.\n * @return {Object} The confirm dialogue container element.\n */\n var getConfirmDialogueContainer = function(root) {\n return root.find(SELECTORS.CONFIRM_DIALOGUE_CONTAINER);\n };\n\n /**\n * Show the confirm dialogue container element.\n *\n * @param {Object} root The container element containing a dialogue.\n */\n var showConfirmDialogueContainer = function(root) {\n var container = getConfirmDialogueContainer(root);\n var siblings = container.siblings(':not(.hidden)');\n Aria.hide(siblings.get());\n siblings.attr('data-confirm-dialogue-hidden', true);\n\n container.removeClass('hidden');\n };\n\n /**\n * Hide the confirm dialogue container element.\n *\n * @param {Object} root The container element containing a dialogue.\n */\n var hideConfirmDialogueContainer = function(root) {\n var container = getConfirmDialogueContainer(root);\n var siblings = container.siblings('[data-confirm-dialogue-hidden=\"true\"]');\n Aria.unhide(siblings.get());\n siblings.removeAttr('data-confirm-dialogue-hidden');\n\n container.addClass('hidden');\n };\n\n /**\n * Set the number of selected messages.\n *\n * @param {Object} header The header container element.\n * @param {Number} value The new number to display.\n */\n var setMessagesSelectedCount = function(header, value) {\n getHeaderEditMode(header).find(SELECTORS.MESSAGES_SELECTED_COUNT).text(value);\n };\n\n /**\n * Format message for the mustache template, transform camelCase properties to lowercase properties.\n *\n * @param {Array} messages Array of message objects.\n * @param {Object} datesCache Cache timestamps and their formatted date string.\n * @return {Array} Messages formated for mustache template.\n */\n var formatMessagesForTemplate = function(messages, datesCache) {\n return messages.map(function(message) {\n return {\n id: message.id,\n isread: message.isRead,\n fromloggedinuser: message.fromLoggedInUser,\n userfrom: message.userFrom,\n text: message.text,\n formattedtime: message.timeCreated ? datesCache[message.timeCreated] : null\n };\n });\n };\n\n /**\n * Create rendering promises for each day containing messages.\n *\n * @param {Object} header The header container element.\n * @param {Object} body The body container element.\n * @param {Object} footer The footer container element.\n * @param {Array} days Array of days containing messages.\n * @param {Object} datesCache Cache timestamps and their formatted date string.\n * @return {Promise} Days rendering promises.\n */\n var renderAddDays = function(header, body, footer, days, datesCache) {\n var messagesContainer = getMessagesContainer(body);\n var daysRenderPromises = days.map(function(data) {\n return Templates.render(TEMPLATES.DAY, {\n timestamp: data.value.timestamp,\n messages: formatMessagesForTemplate(data.value.messages, datesCache)\n });\n });\n\n return $.when.apply($, daysRenderPromises).then(function() {\n // Wait until all of the rendering is done for each of the days\n // to ensure they are added to the page in the correct order.\n days.forEach(function(data, index) {\n daysRenderPromises[index]\n .then(function(html) {\n if (data.before) {\n var element = getDayElement(body, data.before.timestamp);\n return $(html).insertBefore(element);\n } else {\n return messagesContainer.append(html);\n }\n })\n .catch(function() {\n // Fail silently.\n });\n });\n\n return;\n });\n };\n\n /**\n * Add (more) messages to day containers.\n *\n * @param {Object} header The header container element.\n * @param {Object} body The body container element.\n * @param {Object} footer The footer container element.\n * @param {Array} messages List of messages.\n * @param {Object} datesCache Cache timestamps and their formatted date string.\n * @return {Promise} Messages rendering promises.\n */\n var renderAddMessages = function(header, body, footer, messages, datesCache) {\n var messagesData = messages.map(function(data) {\n return data.value;\n });\n var formattedMessages = formatMessagesForTemplate(messagesData, datesCache);\n\n return Templates.render(TEMPLATES.MESSAGES, {messages: formattedMessages})\n .then(function(html) {\n var messageList = $(html);\n messages.forEach(function(data) {\n var messageHtml = messageList.find('[data-message-id=\"' + data.value.id + '\"]');\n if (data.before) {\n var element = getMessageElement(body, data.before.id);\n return messageHtml.insertBefore(element);\n } else {\n var dayContainer = getDayElement(body, data.day.timestamp);\n var dayMessagesContainer = dayContainer.find(SELECTORS.DAY_MESSAGES_CONTAINER);\n return dayMessagesContainer.append(messageHtml);\n }\n });\n\n return;\n });\n };\n\n /**\n * Update existing messages.\n *\n * @param {Object} header The header container element.\n * @param {Object} body The body container element.\n * @param {Object} footer The footer container element.\n * @param {Array} messages List of messages.\n * @param {Object} datesCache Cache timestamps and their formatted date string.\n */\n var renderUpdateMessages = function(header, body, footer, messages, datesCache) {\n messages.forEach(function(message) {\n var before = message.before;\n var after = message.after;\n var element = getMessageElement(body, before.id);\n\n if (before.id != after.id) {\n element.attr('data-message-id', after.id);\n }\n\n if (before.timeCreated != after.timeCreated) {\n var formattedTime = datesCache[after.timeCreated];\n element.find(SELECTORS.LOADING_ICON_CONTAINER).addClass('hidden');\n element.find(SELECTORS.TIME_CREATED).text(formattedTime).removeClass('hidden');\n }\n\n if (before.sendState != after.sendState) {\n var loading = element.find(SELECTORS.LOADING_ICON_CONTAINER);\n var time = element.find(SELECTORS.TIME_CREATED);\n var retry = element.find(SELECTORS.RETRY_SEND);\n\n loading.addClass('hidden');\n Aria.hide(loading.get());\n\n time.addClass('hidden');\n Aria.hide(time.get());\n\n retry.addClass('hidden');\n Aria.hide(retry.get());\n\n element.removeClass('border border-danger');\n\n switch (after.sendState) {\n case 'pending':\n loading.removeClass('hidden');\n Aria.unhide(loading.get());\n break;\n case 'error':\n retry.removeClass('hidden');\n Aria.unhide(retry.get());\n element.addClass('border border-danger');\n break;\n case 'sent':\n time.removeClass('hidden');\n Aria.unhide(time.get());\n break;\n }\n }\n\n if (before.text != after.text) {\n element.find(SELECTORS.TEXT_CONTAINER).html(after.text);\n }\n\n if (before.errorMessage != after.errorMessage) {\n var messageContainer = element.find(SELECTORS.ERROR_MESSAGE_CONTAINER);\n var message = messageContainer.find(SELECTORS.ERROR_MESSAGE);\n\n if (after.errorMessage) {\n messageContainer.removeClass('hidden');\n Aria.unhide(messageContainer.get());\n message.text(after.errorMessage);\n } else {\n messageContainer.addClass('hidden');\n Aria.unhide(messageContainer.get());\n message.text('');\n }\n }\n });\n };\n\n /**\n * Remove days from conversation.\n *\n * @param {Object} body The body container element.\n * @param {Array} days Array of days to be removed.\n */\n var renderRemoveDays = function(body, days) {\n days.forEach(function(data) {\n getDayElement(body, data.timestamp).remove();\n });\n };\n\n /**\n * Remove messages from conversation.\n *\n * @param {Object} body The body container element.\n * @param {Array} messages Array of messages to be removed.\n */\n var renderRemoveMessages = function(body, messages) {\n messages.forEach(function(data) {\n getMessageElement(body, data.id).remove();\n });\n };\n\n /**\n * Render the full conversation base on input from the statemanager.\n *\n * This will pre-load all of the formatted timestamps for each message that\n * needs to render to reduce the number of networks requests.\n *\n * @param {Object} header The header container element.\n * @param {Object} body The body container element.\n * @param {Object} footer The footer container element.\n * @param {Object} data The conversation diff.\n * @return {Object} jQuery promise.\n */\n var renderConversation = function(header, body, footer, data) {\n var renderingPromises = [];\n var hasAddDays = data.days.add.length > 0;\n var hasAddMessages = data.messages.add.length > 0;\n var hasUpdateMessages = data.messages.update.length > 0;\n var timestampsToFormat = [];\n var datesCachePromise = $.Deferred().resolve({}).promise();\n\n if (hasAddDays) {\n // Search for all of the timeCreated values in all of the messages in all of\n // the days that we need to render.\n timestampsToFormat = timestampsToFormat.concat(data.days.add.reduce(function(carry, day) {\n return carry.concat(day.value.messages.reduce(function(timestamps, message) {\n if (message.timeCreated) {\n timestamps.push(message.timeCreated);\n }\n return timestamps;\n }, []));\n }, []));\n }\n\n if (hasAddMessages) {\n // Search for all of the timeCreated values in all of the messages that we\n // need to render.\n timestampsToFormat = timestampsToFormat.concat(data.messages.add.reduce(function(timestamps, message) {\n if (message.value.timeCreated) {\n timestamps.push(message.value.timeCreated);\n }\n return timestamps;\n }, []));\n }\n\n if (hasUpdateMessages) {\n timestampsToFormat = timestampsToFormat.concat(data.messages.update.reduce(function(timestamps, message) {\n if (message.before.timeCreated != message.after.timeCreated) {\n timestamps.push(message.after.timeCreated);\n }\n return timestamps;\n }, []));\n }\n\n if (timestampsToFormat.length) {\n // If we have timestamps then pre-load the formatted version of each of them\n // in a single request to the server. This saves the templates doing multiple\n // individual requests.\n datesCachePromise = Str.get_string('strftimetime24', 'core_langconfig')\n .then(function(format) {\n var requests = timestampsToFormat.map(function(timestamp) {\n return {\n timestamp: timestamp,\n format: format\n };\n });\n\n return UserDate.get(requests);\n })\n .then(function(formattedTimes) {\n return timestampsToFormat.reduce(function(carry, timestamp, index) {\n carry[timestamp] = formattedTimes[index];\n return carry;\n }, {});\n });\n }\n\n if (hasAddDays) {\n renderingPromises.push(datesCachePromise.then(function(datesCache) {\n return renderAddDays(header, body, footer, data.days.add, datesCache);\n }));\n }\n\n if (hasAddMessages) {\n renderingPromises.push(datesCachePromise.then(function(datesCache) {\n return renderAddMessages(header, body, footer, data.messages.add, datesCache);\n }));\n }\n\n if (hasUpdateMessages) {\n renderingPromises.push(datesCachePromise.then(function(datesCache) {\n return renderUpdateMessages(header, body, footer, data.messages.update, datesCache);\n }));\n }\n\n if (data.days.remove.length > 0) {\n renderRemoveDays(body, data.days.remove);\n }\n\n if (data.messages.remove.length > 0) {\n renderRemoveMessages(body, data.messages.remove);\n }\n\n return $.when.apply($, renderingPromises);\n };\n\n /**\n * Render the conversation header.\n *\n * @param {Object} header The header container element.\n * @param {Object} body The body container element.\n * @param {Object} footer The footer container element.\n * @param {Object} data Data for header.\n * @return {Object} jQuery promise\n */\n var renderHeader = function(header, body, footer, data) {\n var headerContainer = getHeaderContent(header);\n var template = TEMPLATES.HEADER_PUBLIC;\n data.context.showrouteback = (header.attr('data-from-panel') === \"false\");\n if (data.type == CONVERSATION_TYPES.PRIVATE) {\n template = data.showControls ? TEMPLATES.HEADER_PRIVATE : TEMPLATES.HEADER_PRIVATE_NO_CONTROLS;\n } else if (data.type == CONVERSATION_TYPES.SELF) {\n template = TEMPLATES.HEADER_SELF;\n }\n\n return Templates.render(template, data.context)\n .then(function(html, js) {\n Templates.replaceNodeContents(headerContainer, html, js);\n return;\n });\n };\n\n /**\n * Render the conversation footer.\n *\n * @param {Object} header The header container element.\n * @param {Object} body The body container element.\n * @param {Object} footer The footer container element.\n * @param {Object} data Data for footer.\n * @return {Object} jQuery promise.\n */\n var renderFooter = function(header, body, footer, data) {\n hideAllFooterElements(footer);\n\n switch (data.type) {\n case 'placeholder':\n return showFooterPlaceholder(footer);\n case 'add-contact':\n return Str.get_strings([\n {\n key: 'requirecontacttomessage',\n component: 'core_message',\n param: data.user.fullname\n },\n {\n key: 'isnotinyourcontacts',\n component: 'core_message',\n param: data.user.fullname\n }\n ])\n .then(function(strings) {\n var title = strings[1];\n var text = strings[0];\n var footerContainer = getFooterRequireContactContainer(footer);\n footerContainer.find(SELECTORS.TITLE).text(title);\n footerContainer.find(SELECTORS.TEXT).text(text);\n showFooterRequireContact(footer);\n return strings;\n });\n case 'edit-mode':\n return showFooterEditMode(footer);\n case 'content':\n return showFooterContent(footer);\n case 'unblock':\n return showFooterRequireUnblock(footer);\n case 'unable-to-message':\n return showFooterUnableToMessage(footer);\n }\n\n return true;\n };\n\n /**\n * Scroll to a message in the conversation.\n *\n * @param {Object} header The header container element.\n * @param {Object} body The body container element.\n * @param {Object} footer The footer container element.\n * @param {Number} messageId Message id.\n */\n var renderScrollToMessage = function(header, body, footer, messageId) {\n var messagesContainer = getMessagesContainer(body);\n var messageElement = getMessageElement(body, messageId);\n var position = messageElement.position();\n // Scroll the message container down to the top of the message element.\n if (position) {\n var scrollTop = messagesContainer.scrollTop() + position.top;\n messagesContainer.scrollTop(scrollTop);\n }\n };\n\n /**\n * Hide or show the conversation header.\n *\n * @param {Object} header The header container element.\n * @param {Object} body The body container element.\n * @param {Object} footer The footer container element.\n * @param {Bool} isLoadingMembers Members loading.\n */\n var renderLoadingMembers = function(header, body, footer, isLoadingMembers) {\n if (isLoadingMembers) {\n hideHeaderContent(header);\n showHeaderPlaceholder(header);\n } else {\n showHeaderContent(header);\n hideHeaderPlaceholder(header);\n }\n };\n\n /**\n * Hide or show loading conversation messages.\n *\n * @param {Object} header The header container element.\n * @param {Object} body The body container element.\n * @param {Object} footer The footer container element.\n * @param {Bool} isLoadingFirstMessages Messages loading.\n */\n var renderLoadingFirstMessages = function(header, body, footer, isLoadingFirstMessages) {\n if (isLoadingFirstMessages) {\n hideMessagesContainer(body);\n showContentPlaceholder(body);\n } else {\n showMessagesContainer(body);\n hideContentPlaceholder(body);\n }\n };\n\n /**\n * Hide or show loading more messages.\n *\n * @param {Object} header The header container element.\n * @param {Object} body The body container element.\n * @param {Object} footer The footer container element.\n * @param {Bool} isLoading Messages loading.\n */\n var renderLoadingMessages = function(header, body, footer, isLoading) {\n if (isLoading) {\n showMoreMessagesLoadingIcon(body);\n } else {\n hideMoreMessagesLoadingIcon(body);\n }\n };\n\n /**\n * Hide or show the emoji picker.\n *\n * @param {Object} header The header container element.\n * @param {Object} body The body container element.\n * @param {Object} footer The footer container element.\n * @param {Bool} show Should the emoji picker be visible.\n */\n var renderShowEmojiPicker = function(header, body, footer, show) {\n var container = getEmojiPickerContainer(footer);\n\n if (show) {\n container.removeClass('hidden');\n Aria.unhide(container.get());\n container.find(SELECTORS.EMOJI_PICKER_SEARCH_INPUT).focus();\n } else {\n container.addClass('hidden');\n Aria.hide(container.get());\n }\n };\n\n /**\n * Hide or show the emoji auto complete.\n *\n * @param {Object} header The header container element.\n * @param {Object} body The body container element.\n * @param {Object} footer The footer container element.\n * @param {Bool} show Should the emoji picker be visible.\n */\n var renderShowEmojiAutoComplete = function(header, body, footer, show) {\n var container = getEmojiAutoCompleteContainer(footer);\n\n if (show) {\n container.removeClass('hidden');\n Aria.unhide(container.get());\n } else {\n container.addClass('hidden');\n Aria.hide(container.get());\n }\n };\n\n /**\n * Show a confirmation dialogue\n *\n * @param {Object} header The header container element.\n * @param {Object} body The body container element.\n * @param {Object} footer The footer container element.\n * @param {String} buttonSelectors Selectors for the buttons to show.\n * @param {String} bodyText Text to show in dialogue.\n * @param {String} headerText Text to show in dialogue header.\n * @param {Bool} canCancel Can this dialogue be cancelled.\n * @param {Bool} skipHeader Skip blanking out the header\n * @param {Bool} showOk Show an 'Okay' button for a dialogue which will close it\n */\n var showConfirmDialogue = function(\n header,\n body,\n footer,\n buttonSelectors,\n bodyText,\n headerText,\n canCancel,\n skipHeader,\n showOk\n ) {\n var dialogue = getConfirmDialogueContainer(body);\n var buttons = buttonSelectors.map(function(selector) {\n return dialogue.find(selector);\n });\n var cancelButton = dialogue.find(SELECTORS.CONFIRM_DIALOGUE_CANCEL_BUTTON);\n var okayButton = dialogue.find(SELECTORS.CONFIRM_DIALOGUE_OKAY_BUTTON);\n var text = dialogue.find(SELECTORS.CONFIRM_DIALOGUE_TEXT);\n var dialogueHeader = dialogue.find(SELECTORS.CONFIRM_DIALOGUE_HEADER);\n\n dialogue.find('button').addClass('hidden');\n\n if (canCancel) {\n cancelButton.removeClass('hidden');\n } else {\n cancelButton.addClass('hidden');\n }\n\n if (showOk) {\n okayButton.removeClass('hidden');\n } else {\n okayButton.addClass('hidden');\n }\n\n if (headerText) {\n // Create the dialogue header.\n dialogueHeader = $('

');\n dialogueHeader.text(headerText);\n // Prepend it to the confirmation body.\n var confirmDialogue = dialogue.find(SELECTORS.CONFIRM_DIALOGUE);\n confirmDialogue.prepend(dialogueHeader);\n } else if (dialogueHeader.length) {\n // Header text is empty but dialogue header is present, so remove it.\n dialogueHeader.remove();\n }\n\n buttons.forEach(function(button) {\n button.removeClass('hidden');\n });\n text.text(bodyText);\n showConfirmDialogueContainer(footer);\n showConfirmDialogueContainer(body);\n\n if (!skipHeader) {\n showConfirmDialogueContainer(header);\n }\n\n dialogue.find(SELECTORS.CAN_RECEIVE_FOCUS).filter(':visible').first().focus();\n };\n\n /**\n * Hide the dialogue\n *\n * @param {Object} header The header container element.\n * @param {Object} body The body container element.\n * @param {Object} footer The footer container element.\n * @return {Bool} always true.\n */\n var hideConfirmDialogue = function(header, body, footer) {\n var dialogue = getConfirmDialogueContainer(body);\n var cancelButton = dialogue.find(SELECTORS.CONFIRM_DIALOGUE_CANCEL_BUTTON);\n var okayButton = dialogue.find(SELECTORS.CONFIRM_DIALOGUE_OKAY_BUTTON);\n var text = dialogue.find(SELECTORS.CONFIRM_DIALOGUE_TEXT);\n var dialogueHeader = dialogue.find(SELECTORS.CONFIRM_DIALOGUE_HEADER);\n\n hideCheckDeleteDialogue(body);\n hideConfirmDialogueContainer(body);\n hideConfirmDialogueContainer(footer);\n hideConfirmDialogueContainer(header);\n dialogue.find('button').addClass('hidden');\n cancelButton.removeClass('hidden');\n okayButton.removeClass('hidden');\n text.text('');\n\n // Remove dialogue header if present.\n if (dialogueHeader.length) {\n dialogueHeader.remove();\n }\n\n header.find(SELECTORS.CAN_RECEIVE_FOCUS).first().focus();\n return true;\n };\n\n /**\n * Render the confirm block user dialogue.\n *\n * @param {Object} header The header container element.\n * @param {Object} body The body container element.\n * @param {Object} footer The footer container element.\n * @param {Object} user User to block.\n * @return {Object} jQuery promise\n */\n var renderConfirmBlockUser = function(header, body, footer, user) {\n if (user) {\n if (user.canmessageevenifblocked) {\n return Str.get_string('cantblockuser', 'core_message', user.fullname)\n .then(function(string) {\n return showConfirmDialogue(header, body, footer, [], string, '', false, false, true);\n });\n } else {\n return Str.get_string('blockuserconfirm', 'core_message', user.fullname)\n .then(function(string) {\n return showConfirmDialogue(header, body, footer, [SELECTORS.ACTION_CONFIRM_BLOCK], string, '', true, false);\n });\n }\n } else {\n return hideConfirmDialogue(header, body, footer);\n }\n };\n\n /**\n * Render the confirm unblock user dialogue.\n *\n * @param {Object} header The header container element.\n * @param {Object} body The body container element.\n * @param {Object} footer The footer container element.\n * @param {Object} user User to unblock.\n * @return {Object} jQuery promise\n */\n var renderConfirmUnblockUser = function(header, body, footer, user) {\n if (user) {\n return Str.get_string('unblockuserconfirm', 'core_message', user.fullname)\n .then(function(string) {\n return showConfirmDialogue(header, body, footer, [SELECTORS.ACTION_CONFIRM_UNBLOCK], string, '', true, false);\n });\n } else {\n return hideConfirmDialogue(header, body, footer);\n }\n };\n\n /**\n * Render the add user as contact dialogue.\n *\n * @param {Object} header The header container element.\n * @param {Object} body The body container element.\n * @param {Object} footer The footer container element.\n * @param {Object} user User to add as contact.\n * @return {Object} jQuery promise\n */\n var renderConfirmAddContact = function(header, body, footer, user) {\n if (user) {\n return Str.get_string('addcontactconfirm', 'core_message', user.fullname)\n .then(function(string) {\n return showConfirmDialogue(\n header,\n body,\n footer,\n [SELECTORS.ACTION_CONFIRM_ADD_CONTACT],\n string,\n '',\n true,\n false\n );\n });\n } else {\n return hideConfirmDialogue(header, body, footer);\n }\n };\n\n /**\n * Render the remove user from contacts dialogue.\n *\n * @param {Object} header The header container element.\n * @param {Object} body The body container element.\n * @param {Object} footer The footer container element.\n * @param {Object} user User to remove from contacts.\n * @return {Object} jQuery promise\n */\n var renderConfirmRemoveContact = function(header, body, footer, user) {\n if (user) {\n return Str.get_string('removecontactconfirm', 'core_message', user.fullname)\n .then(function(string) {\n return showConfirmDialogue(\n header,\n body,\n footer,\n [SELECTORS.ACTION_CONFIRM_REMOVE_CONTACT],\n string,\n '',\n true,\n false\n );\n });\n } else {\n return hideConfirmDialogue(header, body, footer);\n }\n };\n\n /**\n * Render the delete selected messages dialogue.\n *\n * @param {Object} header The header container element.\n * @param {Object} body The body container element.\n * @param {Object} footer The footer container element.\n * @param {Object} data If the dialogue should show and checkbox shows to delete message for all users.\n * @return {Object} jQuery promise\n */\n var renderConfirmDeleteSelectedMessages = function(header, body, footer, data) {\n var showmessage = null;\n if (data.type == CONVERSATION_TYPES.SELF) {\n // Message displayed to self-conversations is slighly different.\n showmessage = 'deleteselectedmessagesconfirmselfconversation';\n } else {\n // This other message should be displayed.\n if (data.canDeleteMessagesForAllUsers) {\n showCheckDeleteDialogue(body);\n showmessage = 'deleteforeveryoneselectedmessagesconfirm';\n } else {\n showmessage = 'deleteselectedmessagesconfirm';\n }\n }\n\n if (data.show) {\n return Str.get_string(showmessage, 'core_message')\n .then(function(string) {\n return showConfirmDialogue(\n header,\n body,\n footer,\n [SELECTORS.ACTION_CONFIRM_DELETE_SELECTED_MESSAGES],\n string,\n '',\n true,\n false\n );\n });\n } else {\n return hideConfirmDialogue(header, body, footer);\n }\n };\n\n /**\n * Render the confirm delete conversation dialogue.\n *\n * @param {Object} header The header container element.\n * @param {Object} body The body container element.\n * @param {Object} footer The footer container element.\n * @param {int|Null} type The conversation type to be removed.\n * @return {Object} jQuery promise\n */\n var renderConfirmDeleteConversation = function(header, body, footer, type) {\n var showmessage = null;\n if (type == CONVERSATION_TYPES.SELF) {\n // Message displayed to self-conversations is slighly different.\n showmessage = 'deleteallselfconfirm';\n } else if (type) {\n // This other message should be displayed.\n showmessage = 'deleteallconfirm';\n }\n\n if (showmessage) {\n return Str.get_string(showmessage, 'core_message')\n .then(function(string) {\n return showConfirmDialogue(\n header,\n body,\n footer,\n [SELECTORS.ACTION_CONFIRM_DELETE_CONVERSATION],\n string,\n '',\n true,\n false\n );\n });\n } else {\n return hideConfirmDialogue(header, body, footer);\n }\n };\n\n /**\n * Render the confirm delete conversation dialogue.\n *\n * @param {Object} header The header container element.\n * @param {Object} body The body container element.\n * @param {Object} footer The footer container element.\n * @param {Bool} user The other user object.\n * @return {Object} jQuery promise\n */\n var renderConfirmContactRequest = function(header, body, footer, user) {\n if (user) {\n return Str.get_string('userwouldliketocontactyou', 'core_message', user.fullname)\n .then(function(string) {\n var buttonSelectors = [\n SELECTORS.ACTION_ACCEPT_CONTACT_REQUEST,\n SELECTORS.ACTION_DECLINE_CONTACT_REQUEST\n ];\n return showConfirmDialogue(header, body, footer, buttonSelectors, string, '', false, true);\n });\n } else {\n return hideConfirmDialogue(header, body, footer);\n }\n };\n\n /**\n * Show the checkbox to allow delete message for all.\n *\n * @param {Object} body The body container element.\n */\n var showCheckDeleteDialogue = function(body) {\n var dialogue = getConfirmDialogueContainer(body);\n var checkboxRegion = dialogue.find(SELECTORS.DELETE_MESSAGES_FOR_ALL_USERS_TOGGLE_CONTAINER);\n checkboxRegion.removeClass('hidden');\n };\n\n /**\n * Hide the checkbox to allow delete message for all.\n *\n * @param {Object} body The body container element.\n */\n var hideCheckDeleteDialogue = function(body) {\n var dialogue = getConfirmDialogueContainer(body);\n var checkboxRegion = dialogue.find(SELECTORS.DELETE_MESSAGES_FOR_ALL_USERS_TOGGLE_CONTAINER);\n var checkbox = dialogue.find(SELECTORS.DELETE_MESSAGES_FOR_ALL_USERS_TOGGLE);\n checkbox.prop('checked', false);\n checkboxRegion.addClass('hidden');\n };\n\n /**\n * Show or hide the block / unblock option in the header dropdown menu.\n *\n * @param {Object} header The header container element.\n * @param {Object} body The body container element.\n * @param {Object} footer The footer container element.\n * @param {Bool} isBlocked is user blocked.\n */\n var renderIsBlocked = function(header, body, footer, isBlocked) {\n if (isBlocked) {\n header.find(SELECTORS.ACTION_REQUEST_BLOCK).addClass('hidden');\n header.find(SELECTORS.ACTION_REQUEST_UNBLOCK).removeClass('hidden');\n } else {\n header.find(SELECTORS.ACTION_REQUEST_BLOCK).removeClass('hidden');\n header.find(SELECTORS.ACTION_REQUEST_UNBLOCK).addClass('hidden');\n }\n };\n\n /**\n * Show or hide the favourite / unfavourite option in the header dropdown menu\n * and the favourite star in the header title.\n *\n * @param {Object} header The header container element.\n * @param {Object} body The body container element.\n * @param {Object} footer The footer container element.\n * @param {Bool} isFavourite is this conversation a favourite.\n */\n var renderIsFavourite = function(header, body, footer, state) {\n var favouriteIcon = header.find(SELECTORS.FAVOURITE_ICON_CONTAINER);\n var addFavourite = header.find(SELECTORS.ACTION_CONFIRM_FAVOURITE);\n var removeFavourite = header.find(SELECTORS.ACTION_CONFIRM_UNFAVOURITE);\n\n switch (state) {\n case 'hide':\n favouriteIcon.addClass('hidden');\n addFavourite.addClass('hidden');\n removeFavourite.addClass('hidden');\n break;\n case 'show-add':\n favouriteIcon.addClass('hidden');\n addFavourite.removeClass('hidden');\n removeFavourite.addClass('hidden');\n break;\n case 'show-remove':\n favouriteIcon.removeClass('hidden');\n addFavourite.addClass('hidden');\n removeFavourite.removeClass('hidden');\n break;\n }\n };\n\n /**\n * Show or hide the mute / unmute option in the header dropdown menu\n * and the muted icon in the header title.\n *\n * @param {Object} header The header container element.\n * @param {Object} body The body container element.\n * @param {Object} footer The footer container element.\n * @param {string} state The state of the conversation as defined by the patcher.\n */\n var renderIsMuted = function(header, body, footer, state) {\n var muteIcon = header.find(SELECTORS.MUTED_ICON_CONTAINER);\n var setMuted = header.find(SELECTORS.ACTION_CONFIRM_MUTE);\n var unsetMuted = header.find(SELECTORS.ACTION_CONFIRM_UNMUTE);\n\n switch (state) {\n case 'hide':\n muteIcon.addClass('hidden');\n setMuted.addClass('hidden');\n unsetMuted.addClass('hidden');\n break;\n case 'show-mute':\n muteIcon.addClass('hidden');\n setMuted.removeClass('hidden');\n unsetMuted.addClass('hidden');\n break;\n case 'show-unmute':\n muteIcon.removeClass('hidden');\n setMuted.addClass('hidden');\n unsetMuted.removeClass('hidden');\n break;\n }\n };\n\n /**\n * Show or hide the add / remove user as contact option in the header dropdown menu.\n *\n * @param {Object} header The header container element.\n * @param {Object} body The body container element.\n * @param {Object} footer The footer container element.\n * @param {Bool} state the contact state.\n */\n var renderIsContact = function(header, body, footer, state) {\n var addContact = header.find(SELECTORS.ACTION_REQUEST_ADD_CONTACT);\n var removeContact = header.find(SELECTORS.ACTION_REQUEST_REMOVE_CONTACT);\n\n switch (state) {\n case 'pending-contact':\n addContact.addClass('hidden');\n removeContact.addClass('hidden');\n break;\n case 'contact':\n addContact.addClass('hidden');\n removeContact.removeClass('hidden');\n break;\n case 'non-contact':\n addContact.removeClass('hidden');\n removeContact.addClass('hidden');\n break;\n }\n };\n\n /**\n * Show or hide confirm action from confirm dialogue is loading.\n *\n * @param {Object} header The header container element.\n * @param {Object} body The body container element.\n * @param {Object} footer The footer container element.\n * @param {Bool} isLoading confirm action is loading.\n */\n var renderLoadingConfirmAction = function(header, body, footer, isLoading) {\n var dialogue = getConfirmDialogueContainer(body);\n var buttons = dialogue.find('button');\n var buttonText = dialogue.find(SELECTORS.CONFIRM_DIALOGUE_BUTTON_TEXT);\n var loadingIcon = dialogue.find(SELECTORS.LOADING_ICON_CONTAINER);\n\n if (isLoading) {\n buttons.prop('disabled', true);\n buttonText.addClass('hidden');\n loadingIcon.removeClass('hidden');\n } else {\n buttons.prop('disabled', false);\n buttonText.removeClass('hidden');\n loadingIcon.addClass('hidden');\n }\n };\n\n /**\n * Show or hide the header and footer content for edit mode.\n *\n * @param {Object} header The header container element.\n * @param {Object} body The body container element.\n * @param {Object} footer The footer container element.\n * @param {Bool} inEditMode In edit mode or not.\n */\n var renderInEditMode = function(header, body, footer, inEditMode) {\n var messages = null;\n\n if (inEditMode) {\n messages = body.find(SELECTORS.MESSAGE_NOT_SELECTED);\n messages.find(SELECTORS.MESSAGE_NOT_SELECTED_ICON).removeClass('hidden');\n hideHeaderContent(header);\n showHeaderEditMode(header);\n } else {\n messages = getMessagesContainer(body);\n messages.find(SELECTORS.MESSAGE_NOT_SELECTED_ICON).addClass('hidden');\n messages.find(SELECTORS.MESSAGE_SELECTED_ICON).addClass('hidden');\n showHeaderContent(header);\n hideHeaderEditMode(header);\n }\n };\n\n /**\n * Select or unselect messages.\n *\n * @param {Object} header The header container element.\n * @param {Object} body The body container element.\n * @param {Object} footer The footer container element.\n * @param {Object} data The messages to select or unselect.\n */\n var renderSelectedMessages = function(header, body, footer, data) {\n var hasSelectedMessages = data.count > 0;\n\n if (data.add.length) {\n data.add.forEach(function(messageId) {\n var message = getMessageElement(body, messageId);\n message.find(SELECTORS.MESSAGE_NOT_SELECTED_ICON).addClass('hidden');\n message.find(SELECTORS.MESSAGE_SELECTED_ICON).removeClass('hidden');\n message.attr('aria-checked', true);\n });\n }\n\n if (data.remove.length) {\n data.remove.forEach(function(messageId) {\n var message = getMessageElement(body, messageId);\n\n if (hasSelectedMessages) {\n message.find(SELECTORS.MESSAGE_NOT_SELECTED_ICON).removeClass('hidden');\n }\n\n message.find(SELECTORS.MESSAGE_SELECTED_ICON).addClass('hidden');\n message.attr('aria-checked', false);\n });\n }\n\n setMessagesSelectedCount(header, data.count);\n };\n\n /**\n * Show or hide the require add contact panel.\n *\n * @param {Object} header The header container element.\n * @param {Object} body The body container element.\n * @param {Object} footer The footer container element.\n * @param {Object} data Whether the user has to be added a a contact.\n * @return {Object} jQuery promise\n */\n var renderRequireAddContact = function(header, body, footer, data) {\n if (data.show && !data.hasMessages) {\n return Str.get_strings([\n {\n key: 'requirecontacttomessage',\n component: 'core_message',\n param: data.user.fullname\n },\n {\n key: 'isnotinyourcontacts',\n component: 'core_message',\n param: data.user.fullname\n }\n ])\n .then(function(strings) {\n var title = strings[1];\n var text = strings[0];\n return showConfirmDialogue(\n header,\n body,\n footer,\n [SELECTORS.ACTION_REQUEST_ADD_CONTACT],\n text,\n title,\n false,\n true\n );\n });\n } else {\n return hideConfirmDialogue(header, body, footer);\n }\n };\n\n /**\n * Show or hide the self-conversation message.\n *\n * @param {Object} header The header container element.\n * @param {Object} body The body container element.\n * @param {Object} footer The footer container element.\n * @param {Object} displayMessage should the message be displayed?.\n * @return {Object|true} jQuery promise\n */\n var renderSelfConversationMessage = function(header, body, footer, displayMessage) {\n var container = getSelfConversationMessageContainer(body);\n if (displayMessage) {\n container.removeClass('hidden');\n } else {\n container.addClass('hidden');\n }\n return true;\n };\n\n /**\n * Show or hide the require add contact panel.\n *\n * @param {Object} header The header container element.\n * @param {Object} body The body container element.\n * @param {Object} footer The footer container element.\n * @param {Object} userFullName Full name of the other user.\n * @return {Object|true} jQuery promise\n */\n var renderContactRequestSent = function(header, body, footer, userFullName) {\n var container = getContactRequestSentContainer(body);\n if (userFullName) {\n return Str.get_string('yourcontactrequestpending', 'core_message', userFullName)\n .then(function(string) {\n container.find(SELECTORS.TEXT).text(string);\n container.removeClass('hidden');\n return string;\n });\n } else {\n container.addClass('hidden');\n return true;\n }\n };\n\n /**\n * Reset the UI to the initial state.\n *\n * @param {Object} header The header container element.\n * @param {Object} body The body container element.\n * @param {Object} footer The footer container element.\n * @return {Bool}\n */\n var renderReset = function(header, body, footer) {\n hideConfirmDialogue(header, body, footer);\n hideContactRequestSentContainer(body);\n hideSelfConversationMessageContainer(body);\n hideAllHeaderElements(header);\n showHeaderPlaceholder(header);\n hideAllFooterElements(footer);\n showFooterPlaceholder(footer);\n return true;\n };\n\n var render = function(header, body, footer, patch) {\n var configs = [\n {\n // Resetting the UI needs to come first, if it's required.\n reset: renderReset\n },\n {\n // Any async rendering (stuff that requires templates, strings etc) should\n // go in here.\n conversation: renderConversation,\n header: renderHeader,\n footer: renderFooter,\n confirmBlockUser: renderConfirmBlockUser,\n confirmUnblockUser: renderConfirmUnblockUser,\n confirmAddContact: renderConfirmAddContact,\n confirmRemoveContact: renderConfirmRemoveContact,\n confirmDeleteSelectedMessages: renderConfirmDeleteSelectedMessages,\n confirmDeleteConversation: renderConfirmDeleteConversation,\n confirmContactRequest: renderConfirmContactRequest,\n requireAddContact: renderRequireAddContact,\n selfConversationMessage: renderSelfConversationMessage,\n contactRequestSent: renderContactRequestSent\n },\n {\n loadingMembers: renderLoadingMembers,\n loadingFirstMessages: renderLoadingFirstMessages,\n loadingMessages: renderLoadingMessages,\n isBlocked: renderIsBlocked,\n isContact: renderIsContact,\n isFavourite: renderIsFavourite,\n isMuted: renderIsMuted,\n loadingConfirmAction: renderLoadingConfirmAction,\n inEditMode: renderInEditMode,\n showEmojiPicker: renderShowEmojiPicker,\n showEmojiAutoComplete: renderShowEmojiAutoComplete,\n },\n {\n // Scrolling should be last to make sure everything\n // on the page is visible.\n scrollToMessage: renderScrollToMessage,\n selectedMessages: renderSelectedMessages\n }\n ];\n // Helper function to process each of the configs above.\n var processConfig = function(config) {\n var results = [];\n\n for (var key in patch) {\n if (config.hasOwnProperty(key)) {\n var renderFunc = config[key];\n var patchValue = patch[key];\n results.push(renderFunc(header, body, footer, patchValue));\n }\n }\n\n return results;\n };\n\n // The first config is special because it resets the UI.\n var renderingPromises = processConfig(configs[0]);\n // The second config is special because it contains async rendering.\n renderingPromises = renderingPromises.concat(processConfig(configs[1]));\n\n // Wait for the async rendering to complete before processing the\n // rest of the configs, in order.\n return $.when.apply($, renderingPromises)\n .then(function() {\n for (var i = 2; i < configs.length; i++) {\n processConfig(configs[i]);\n }\n\n return;\n })\n .catch(Notification.exception);\n };\n\n return {\n render: render,\n };\n});\n"],"file":"message_drawer_view_conversation_renderer.min.js"} \ No newline at end of file +{"version":3,"sources":["../src/message_drawer_view_conversation_renderer.js"],"names":["define","$","Notification","Str","Templates","UserDate","Constants","Aria","SELECTORS","TEMPLATES","CONVERSATION_TYPES","getMessagesContainer","body","find","CONTENT_MESSAGES_CONTAINER","showMessagesContainer","removeClass","hideMessagesContainer","addClass","getSelfConversationMessageContainer","SELF_CONVERSATION_MESSAGE_CONTAINER","hideSelfConversationMessageContainer","getContactRequestSentContainer","CONTACT_REQUEST_SENT_MESSAGE_CONTAINER","hideContactRequestSentContainer","getFooterContentContainer","footer","CONTENT_MESSAGES_FOOTER_CONTAINER","showFooterContent","hideFooterContent","getFooterEditModeContainer","CONTENT_MESSAGES_FOOTER_EDIT_MODE_CONTAINER","showFooterEditMode","hideFooterEditMode","getFooterPlaceholderContainer","PLACEHOLDER_CONTAINER","showFooterPlaceholder","hideFooterPlaceholder","getFooterRequireContactContainer","CONTENT_MESSAGES_FOOTER_REQUIRE_CONTACT_CONTAINER","showFooterRequireContact","hideFooterRequireContact","getFooterRequireUnblockContainer","CONTENT_MESSAGES_FOOTER_REQUIRE_UNBLOCK_CONTAINER","showFooterRequireUnblock","hideFooterRequireUnblock","getFooterUnableToMessageContainer","CONTENT_MESSAGES_FOOTER_UNABLE_TO_MESSAGE_CONTAINER","showFooterUnableToMessage","hideFooterUnableToMessage","hideAllHeaderElements","header","hideHeaderContent","hideHeaderEditMode","hideHeaderPlaceholder","hideAllFooterElements","getContentPlaceholderContainer","CONTENT_PLACEHOLDER_CONTAINER","showContentPlaceholder","hideContentPlaceholder","getHeaderContent","HEADER","showHeaderContent","getHeaderEditMode","HEADER_EDIT_MODE","showHeaderEditMode","getHeaderPlaceholderContainer","HEADER_PLACEHOLDER_CONTAINER","showHeaderPlaceholder","getEmojiPickerContainer","EMOJI_PICKER_CONTAINER","getEmojiAutoCompleteContainer","EMOJI_AUTO_COMPLETE_CONTAINER","getMessageElement","messageId","messagesContainer","getDayElement","dayTimeCreated","getMoreMessagesLoadingIconContainer","MORE_MESSAGES_LOADING_ICON_CONTAINER","showMoreMessagesLoadingIcon","hideMoreMessagesLoadingIcon","getConfirmDialogueContainer","root","CONFIRM_DIALOGUE_CONTAINER","showConfirmDialogueContainer","container","siblings","hide","get","attr","hideConfirmDialogueContainer","unhide","removeAttr","setMessagesSelectedCount","value","MESSAGES_SELECTED_COUNT","text","formatMessagesForTemplate","messages","datesCache","map","message","id","isread","isRead","fromloggedinuser","fromLoggedInUser","userfrom","userFrom","formattedtime","timeCreated","renderAddDays","days","daysRenderPromises","data","timestampDate","Date","timestamp","render","DAY","currentyear","getFullYear","when","apply","then","forEach","index","html","before","element","insertBefore","append","catch","renderAddMessages","messagesData","formattedMessages","MESSAGES","messageList","messageHtml","dayContainer","day","dayMessagesContainer","DAY_MESSAGES_CONTAINER","renderUpdateMessages","after","formattedTime","LOADING_ICON_CONTAINER","TIME_CREATED","sendState","loading","time","retry","RETRY_SEND","TEXT_CONTAINER","errorMessage","messageContainer","ERROR_MESSAGE_CONTAINER","ERROR_MESSAGE","renderRemoveDays","remove","renderRemoveMessages","renderConversation","renderingPromises","hasAddDays","add","length","hasAddMessages","hasUpdateMessages","update","timestampsToFormat","datesCachePromise","Deferred","resolve","promise","concat","reduce","carry","timestamps","push","get_string","format","requests","formattedTimes","renderHeader","headerContainer","template","HEADER_PUBLIC","context","showrouteback","type","PRIVATE","showControls","HEADER_PRIVATE","HEADER_PRIVATE_NO_CONTROLS","SELF","HEADER_SELF","js","replaceNodeContents","renderFooter","get_strings","key","component","param","user","fullname","strings","title","footerContainer","TITLE","TEXT","renderScrollToMessage","messageElement","position","scrollTop","top","renderLoadingMembers","isLoadingMembers","renderLoadingFirstMessages","isLoadingFirstMessages","renderLoadingMessages","isLoading","renderShowEmojiPicker","show","EMOJI_PICKER_SEARCH_INPUT","focus","renderShowEmojiAutoComplete","showConfirmDialogue","buttonSelectors","bodyText","headerText","canCancel","skipHeader","showOk","dialogue","buttons","selector","cancelButton","CONFIRM_DIALOGUE_CANCEL_BUTTON","okayButton","CONFIRM_DIALOGUE_OKAY_BUTTON","CONFIRM_DIALOGUE_TEXT","dialogueHeader","CONFIRM_DIALOGUE_HEADER","confirmDialogue","CONFIRM_DIALOGUE","prepend","button","CAN_RECEIVE_FOCUS","filter","first","hideConfirmDialogue","hideCheckDeleteDialogue","renderConfirmBlockUser","canmessageevenifblocked","string","ACTION_CONFIRM_BLOCK","renderConfirmUnblockUser","ACTION_CONFIRM_UNBLOCK","renderConfirmAddContact","ACTION_CONFIRM_ADD_CONTACT","renderConfirmRemoveContact","ACTION_CONFIRM_REMOVE_CONTACT","renderConfirmDeleteSelectedMessages","showmessage","canDeleteMessagesForAllUsers","showCheckDeleteDialogue","ACTION_CONFIRM_DELETE_SELECTED_MESSAGES","renderConfirmDeleteConversation","ACTION_CONFIRM_DELETE_CONVERSATION","renderConfirmContactRequest","ACTION_ACCEPT_CONTACT_REQUEST","ACTION_DECLINE_CONTACT_REQUEST","checkboxRegion","DELETE_MESSAGES_FOR_ALL_USERS_TOGGLE_CONTAINER","checkbox","DELETE_MESSAGES_FOR_ALL_USERS_TOGGLE","prop","renderIsBlocked","isBlocked","ACTION_REQUEST_BLOCK","ACTION_REQUEST_UNBLOCK","renderIsFavourite","state","favouriteIcon","FAVOURITE_ICON_CONTAINER","addFavourite","ACTION_CONFIRM_FAVOURITE","removeFavourite","ACTION_CONFIRM_UNFAVOURITE","renderIsMuted","muteIcon","MUTED_ICON_CONTAINER","setMuted","ACTION_CONFIRM_MUTE","unsetMuted","ACTION_CONFIRM_UNMUTE","renderIsContact","addContact","ACTION_REQUEST_ADD_CONTACT","removeContact","ACTION_REQUEST_REMOVE_CONTACT","renderLoadingConfirmAction","buttonText","CONFIRM_DIALOGUE_BUTTON_TEXT","loadingIcon","renderInEditMode","inEditMode","MESSAGE_NOT_SELECTED","MESSAGE_NOT_SELECTED_ICON","MESSAGE_SELECTED_ICON","renderSelectedMessages","hasSelectedMessages","count","renderRequireAddContact","hasMessages","renderSelfConversationMessage","displayMessage","renderContactRequestSent","userFullName","renderReset","patch","configs","reset","conversation","confirmBlockUser","confirmUnblockUser","confirmAddContact","confirmRemoveContact","confirmDeleteSelectedMessages","confirmDeleteConversation","confirmContactRequest","requireAddContact","selfConversationMessage","contactRequestSent","loadingMembers","loadingFirstMessages","loadingMessages","isContact","isFavourite","isMuted","loadingConfirmAction","showEmojiPicker","showEmojiAutoComplete","scrollToMessage","selectedMessages","processConfig","config","results","hasOwnProperty","renderFunc","patchValue","i","exception"],"mappings":"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","sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * This module updates the UI for the conversation page in the message\n * drawer.\n *\n * The module will take a patch from the message_drawer_view_conversation_patcher\n * module and update the UI to reflect the changes.\n *\n * This is the only module that ever modifies the UI of the conversation page.\n *\n * @module core_message/message_drawer_view_conversation_renderer\n * @copyright 2018 Ryan Wyllie \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\ndefine(\n[\n 'jquery',\n 'core/notification',\n 'core/str',\n 'core/templates',\n 'core/user_date',\n 'core_message/message_drawer_view_conversation_constants',\n 'core/aria',\n],\nfunction(\n $,\n Notification,\n Str,\n Templates,\n UserDate,\n Constants,\n Aria\n) {\n var SELECTORS = Constants.SELECTORS;\n var TEMPLATES = Constants.TEMPLATES;\n var CONVERSATION_TYPES = Constants.CONVERSATION_TYPES;\n\n /**\n * Get the messages container element.\n *\n * @param {Object} body Conversation body container element.\n * @return {Object} The messages container element.\n */\n var getMessagesContainer = function(body) {\n return body.find(SELECTORS.CONTENT_MESSAGES_CONTAINER);\n };\n\n /**\n * Show the messages container element.\n *\n * @param {Object} body Conversation body container element.\n */\n var showMessagesContainer = function(body) {\n getMessagesContainer(body).removeClass('hidden');\n };\n\n /**\n * Hide the messages container element.\n *\n * @param {Object} body Conversation body container element.\n */\n var hideMessagesContainer = function(body) {\n getMessagesContainer(body).addClass('hidden');\n };\n\n /**\n * Get the self-conversation message container element.\n *\n * @param {Object} body Conversation body container element.\n * @return {Object} The messages container element.\n */\n var getSelfConversationMessageContainer = function(body) {\n return body.find(SELECTORS.SELF_CONVERSATION_MESSAGE_CONTAINER);\n };\n\n /**\n * Hide the self-conversation message container element.\n *\n * @param {Object} body Conversation body container element.\n * @return {Object} The messages container element.\n */\n var hideSelfConversationMessageContainer = function(body) {\n return getSelfConversationMessageContainer(body).addClass('hidden');\n };\n\n /**\n * Get the contact request sent container element.\n *\n * @param {Object} body Conversation body container element.\n * @return {Object} The messages container element.\n */\n var getContactRequestSentContainer = function(body) {\n return body.find(SELECTORS.CONTACT_REQUEST_SENT_MESSAGE_CONTAINER);\n };\n\n /**\n * Hide the contact request sent container element.\n *\n * @param {Object} body Conversation body container element.\n * @return {Object} The messages container element.\n */\n var hideContactRequestSentContainer = function(body) {\n return getContactRequestSentContainer(body).addClass('hidden');\n };\n\n /**\n * Get the footer container element.\n *\n * @param {Object} footer Conversation footer container element.\n * @return {Object} The footer container element.\n */\n var getFooterContentContainer = function(footer) {\n return footer.find(SELECTORS.CONTENT_MESSAGES_FOOTER_CONTAINER);\n };\n\n /**\n * Show the footer container element.\n *\n * @param {Object} footer Conversation footer container element.\n */\n var showFooterContent = function(footer) {\n getFooterContentContainer(footer).removeClass('hidden');\n };\n\n /**\n * Hide the footer container element.\n *\n * @param {Object} footer Conversation footer container element.\n */\n var hideFooterContent = function(footer) {\n getFooterContentContainer(footer).addClass('hidden');\n };\n\n /**\n * Get the footer edit mode container element.\n *\n * @param {Object} footer Conversation footer container element.\n * @return {Object} The footer container element.\n */\n var getFooterEditModeContainer = function(footer) {\n return footer.find(SELECTORS.CONTENT_MESSAGES_FOOTER_EDIT_MODE_CONTAINER);\n };\n\n /**\n * Show the footer edit mode container element.\n *\n * @param {Object} footer Conversation footer container element.\n */\n var showFooterEditMode = function(footer) {\n getFooterEditModeContainer(footer).removeClass('hidden');\n };\n\n /**\n * Hide the footer edit mode container element.\n *\n * @param {Object} footer Conversation footer container element.\n */\n var hideFooterEditMode = function(footer) {\n getFooterEditModeContainer(footer).addClass('hidden');\n };\n\n /**\n * Get the footer placeholder.\n *\n * @param {Object} footer Conversation footer container element.\n * @return {Object} The footer placeholder container element.\n */\n var getFooterPlaceholderContainer = function(footer) {\n return footer.find(SELECTORS.PLACEHOLDER_CONTAINER);\n };\n\n /**\n * Show the footer placeholder\n *\n * @param {Object} footer Conversation footer container element.\n */\n var showFooterPlaceholder = function(footer) {\n getFooterPlaceholderContainer(footer).removeClass('hidden');\n };\n\n /**\n * Hide the footer placeholder\n *\n * @param {Object} footer Conversation footer container element.\n */\n var hideFooterPlaceholder = function(footer) {\n getFooterPlaceholderContainer(footer).addClass('hidden');\n };\n\n /**\n * Get the footer Require add as contact container element.\n *\n * @param {Object} footer Conversation footer container element.\n * @return {Object} The footer Require add as contact container element.\n */\n var getFooterRequireContactContainer = function(footer) {\n return footer.find(SELECTORS.CONTENT_MESSAGES_FOOTER_REQUIRE_CONTACT_CONTAINER);\n };\n\n /**\n * Show the footer add as contact dialogue.\n *\n * @param {Object} footer Conversation footer container element.\n */\n var showFooterRequireContact = function(footer) {\n getFooterRequireContactContainer(footer).removeClass('hidden');\n };\n\n /**\n * Hide the footer add as contact dialogue.\n *\n * @param {Object} footer Conversation footer container element.\n */\n var hideFooterRequireContact = function(footer) {\n getFooterRequireContactContainer(footer).addClass('hidden');\n };\n\n /**\n * Get the footer Required to unblock contact container element.\n *\n * @param {Object} footer Conversation footer container element.\n * @return {Object} The footer Required to unblock contact container element.\n */\n var getFooterRequireUnblockContainer = function(footer) {\n return footer.find(SELECTORS.CONTENT_MESSAGES_FOOTER_REQUIRE_UNBLOCK_CONTAINER);\n };\n\n /**\n * Show the footer Required to unblock contact container element.\n *\n * @param {Object} footer Conversation footer container element.\n */\n var showFooterRequireUnblock = function(footer) {\n getFooterRequireUnblockContainer(footer).removeClass('hidden');\n };\n\n /**\n * Hide the footer Required to unblock contact container element.\n *\n * @param {Object} footer Conversation footer container element.\n */\n var hideFooterRequireUnblock = function(footer) {\n getFooterRequireUnblockContainer(footer).addClass('hidden');\n };\n\n /**\n * Get the footer Unable to message contact container element.\n *\n * @param {Object} footer Conversation footer container element.\n * @return {Object} The footer Unable to message contact container element.\n */\n var getFooterUnableToMessageContainer = function(footer) {\n return footer.find(SELECTORS.CONTENT_MESSAGES_FOOTER_UNABLE_TO_MESSAGE_CONTAINER);\n };\n\n /**\n * Show the footer Unable to message contact container element.\n *\n * @param {Object} footer Conversation footer container element.\n */\n var showFooterUnableToMessage = function(footer) {\n getFooterUnableToMessageContainer(footer).removeClass('hidden');\n };\n\n /**\n * Hide the footer Unable to message contact container element.\n *\n * @param {Object} footer Conversation footer container element.\n */\n var hideFooterUnableToMessage = function(footer) {\n getFooterUnableToMessageContainer(footer).addClass('hidden');\n };\n\n /**\n * Hide all header elements.\n *\n * @param {Object} header Conversation header container element.\n */\n var hideAllHeaderElements = function(header) {\n hideHeaderContent(header);\n hideHeaderEditMode(header);\n hideHeaderPlaceholder(header);\n };\n\n /**\n * Hide all footer dialogues and messages.\n *\n * @param {Object} footer Conversation footer container element.\n */\n var hideAllFooterElements = function(footer) {\n hideFooterContent(footer);\n hideFooterEditMode(footer);\n hideFooterPlaceholder(footer);\n hideFooterRequireContact(footer);\n hideFooterRequireUnblock(footer);\n hideFooterUnableToMessage(footer);\n };\n\n /**\n * Get the content placeholder container element.\n *\n * @param {Object} body Conversation body container element.\n * @return {Object} The body placeholder container element.\n */\n var getContentPlaceholderContainer = function(body) {\n return body.find(SELECTORS.CONTENT_PLACEHOLDER_CONTAINER);\n };\n\n /**\n * Show the content placeholder.\n *\n * @param {Object} body Conversation body container element.\n */\n var showContentPlaceholder = function(body) {\n getContentPlaceholderContainer(body).removeClass('hidden');\n };\n\n /**\n * Hide the content placeholder.\n *\n * @param {Object} body Conversation body container element.\n */\n var hideContentPlaceholder = function(body) {\n getContentPlaceholderContainer(body).addClass('hidden');\n };\n\n /**\n * Get the header content container element.\n *\n * @param {Object} header Conversation header container element.\n * @return {Object} The header content container element.\n */\n var getHeaderContent = function(header) {\n return header.find(SELECTORS.HEADER);\n };\n\n /**\n * Show the header content.\n *\n * @param {Object} header Conversation header container element.\n */\n var showHeaderContent = function(header) {\n getHeaderContent(header).removeClass('hidden');\n };\n\n /**\n * Hide the header content.\n *\n * @param {Object} header Conversation header container element.\n */\n var hideHeaderContent = function(header) {\n getHeaderContent(header).addClass('hidden');\n };\n\n /**\n * Get the header edit mode container element.\n *\n * @param {Object} header Conversation header container element.\n * @return {Object} The header content container element.\n */\n var getHeaderEditMode = function(header) {\n return header.find(SELECTORS.HEADER_EDIT_MODE);\n };\n\n /**\n * Show the header edit mode container.\n *\n * @param {Object} header Conversation header container element.\n */\n var showHeaderEditMode = function(header) {\n getHeaderEditMode(header).removeClass('hidden');\n };\n\n /**\n * Hide the header edit mode container.\n *\n * @param {Object} header Conversation header container element.\n */\n var hideHeaderEditMode = function(header) {\n getHeaderEditMode(header).addClass('hidden');\n };\n\n /**\n * Get the header placeholder container element.\n *\n * @param {Object} header Conversation header container element.\n * @return {Object} The header placeholder container element.\n */\n var getHeaderPlaceholderContainer = function(header) {\n return header.find(SELECTORS.HEADER_PLACEHOLDER_CONTAINER);\n };\n\n /**\n * Show the header placeholder.\n *\n * @param {Object} header Conversation header container element.\n */\n var showHeaderPlaceholder = function(header) {\n getHeaderPlaceholderContainer(header).removeClass('hidden');\n };\n\n /**\n * Hide the header placeholder.\n *\n * @param {Object} header Conversation header container element.\n */\n var hideHeaderPlaceholder = function(header) {\n getHeaderPlaceholderContainer(header).addClass('hidden');\n };\n\n /**\n * Get the emoji picker container element.\n *\n * @param {Object} footer Conversation footer container element.\n * @return {Object} The emoji picker container element.\n */\n var getEmojiPickerContainer = function(footer) {\n return footer.find(SELECTORS.EMOJI_PICKER_CONTAINER);\n };\n\n /**\n * Get the emoji picker container element.\n *\n * @param {Object} footer Conversation footer container element.\n * @return {Object} The emoji picker container element.\n */\n var getEmojiAutoCompleteContainer = function(footer) {\n return footer.find(SELECTORS.EMOJI_AUTO_COMPLETE_CONTAINER);\n };\n\n /**\n * Get a message element.\n *\n * @param {Object} body Conversation body container element.\n * @param {Number} messageId the Message id.\n * @return {Object} A message element from the conversation.\n */\n var getMessageElement = function(body, messageId) {\n var messagesContainer = getMessagesContainer(body);\n return messagesContainer.find('[data-message-id=\"' + messageId + '\"]');\n };\n\n /**\n * Get the day container element. The day container element holds a list of messages for that day.\n *\n * @param {Object} body Conversation body container element.\n * @param {Number} dayTimeCreated Midnight timestamp for the day.\n * @return {Object} jQuery object\n */\n var getDayElement = function(body, dayTimeCreated) {\n var messagesContainer = getMessagesContainer(body);\n return messagesContainer.find('[data-day-id=\"' + dayTimeCreated + '\"]');\n };\n\n /**\n * Get the more messages loading icon container element.\n *\n * @param {Object} body Conversation body container element.\n * @return {Object} The more messages loading container element.\n */\n var getMoreMessagesLoadingIconContainer = function(body) {\n return body.find(SELECTORS.MORE_MESSAGES_LOADING_ICON_CONTAINER);\n };\n\n /**\n * Show the more messages loading icon.\n *\n * @param {Object} body Conversation body container element.\n */\n var showMoreMessagesLoadingIcon = function(body) {\n getMoreMessagesLoadingIconContainer(body).removeClass('hidden');\n };\n\n /**\n * Hide the more messages loading icon.\n *\n * @param {Object} body Conversation body container element.\n */\n var hideMoreMessagesLoadingIcon = function(body) {\n getMoreMessagesLoadingIconContainer(body).addClass('hidden');\n };\n\n /**\n * Get the confirm dialogue container element.\n *\n * @param {Object} root The container element to search.\n * @return {Object} The confirm dialogue container element.\n */\n var getConfirmDialogueContainer = function(root) {\n return root.find(SELECTORS.CONFIRM_DIALOGUE_CONTAINER);\n };\n\n /**\n * Show the confirm dialogue container element.\n *\n * @param {Object} root The container element containing a dialogue.\n */\n var showConfirmDialogueContainer = function(root) {\n var container = getConfirmDialogueContainer(root);\n var siblings = container.siblings(':not(.hidden)');\n Aria.hide(siblings.get());\n siblings.attr('data-confirm-dialogue-hidden', true);\n\n container.removeClass('hidden');\n };\n\n /**\n * Hide the confirm dialogue container element.\n *\n * @param {Object} root The container element containing a dialogue.\n */\n var hideConfirmDialogueContainer = function(root) {\n var container = getConfirmDialogueContainer(root);\n var siblings = container.siblings('[data-confirm-dialogue-hidden=\"true\"]');\n Aria.unhide(siblings.get());\n siblings.removeAttr('data-confirm-dialogue-hidden');\n\n container.addClass('hidden');\n };\n\n /**\n * Set the number of selected messages.\n *\n * @param {Object} header The header container element.\n * @param {Number} value The new number to display.\n */\n var setMessagesSelectedCount = function(header, value) {\n getHeaderEditMode(header).find(SELECTORS.MESSAGES_SELECTED_COUNT).text(value);\n };\n\n /**\n * Format message for the mustache template, transform camelCase properties to lowercase properties.\n *\n * @param {Array} messages Array of message objects.\n * @param {Object} datesCache Cache timestamps and their formatted date string.\n * @return {Array} Messages formated for mustache template.\n */\n var formatMessagesForTemplate = function(messages, datesCache) {\n return messages.map(function(message) {\n return {\n id: message.id,\n isread: message.isRead,\n fromloggedinuser: message.fromLoggedInUser,\n userfrom: message.userFrom,\n text: message.text,\n formattedtime: message.timeCreated ? datesCache[message.timeCreated] : null\n };\n });\n };\n\n /**\n * Create rendering promises for each day containing messages.\n *\n * @param {Object} header The header container element.\n * @param {Object} body The body container element.\n * @param {Object} footer The footer container element.\n * @param {Array} days Array of days containing messages.\n * @param {Object} datesCache Cache timestamps and their formatted date string.\n * @return {Promise} Days rendering promises.\n */\n var renderAddDays = function(header, body, footer, days, datesCache) {\n var messagesContainer = getMessagesContainer(body);\n var daysRenderPromises = days.map(function(data) {\n var timestampDate = new Date(data.value.timestamp * 1000);\n return Templates.render(TEMPLATES.DAY, {\n timestamp: data.value.timestamp,\n currentyear: timestampDate.getFullYear() === (new Date()).getFullYear(),\n messages: formatMessagesForTemplate(data.value.messages, datesCache)\n });\n });\n\n return $.when.apply($, daysRenderPromises).then(function() {\n // Wait until all of the rendering is done for each of the days\n // to ensure they are added to the page in the correct order.\n days.forEach(function(data, index) {\n daysRenderPromises[index]\n .then(function(html) {\n if (data.before) {\n var element = getDayElement(body, data.before.timestamp);\n return $(html).insertBefore(element);\n } else {\n return messagesContainer.append(html);\n }\n })\n .catch(function() {\n // Fail silently.\n });\n });\n\n return;\n });\n };\n\n /**\n * Add (more) messages to day containers.\n *\n * @param {Object} header The header container element.\n * @param {Object} body The body container element.\n * @param {Object} footer The footer container element.\n * @param {Array} messages List of messages.\n * @param {Object} datesCache Cache timestamps and their formatted date string.\n * @return {Promise} Messages rendering promises.\n */\n var renderAddMessages = function(header, body, footer, messages, datesCache) {\n var messagesData = messages.map(function(data) {\n return data.value;\n });\n var formattedMessages = formatMessagesForTemplate(messagesData, datesCache);\n\n return Templates.render(TEMPLATES.MESSAGES, {messages: formattedMessages})\n .then(function(html) {\n var messageList = $(html);\n messages.forEach(function(data) {\n var messageHtml = messageList.find('[data-message-id=\"' + data.value.id + '\"]');\n if (data.before) {\n var element = getMessageElement(body, data.before.id);\n return messageHtml.insertBefore(element);\n } else {\n var dayContainer = getDayElement(body, data.day.timestamp);\n var dayMessagesContainer = dayContainer.find(SELECTORS.DAY_MESSAGES_CONTAINER);\n return dayMessagesContainer.append(messageHtml);\n }\n });\n\n return;\n });\n };\n\n /**\n * Update existing messages.\n *\n * @param {Object} header The header container element.\n * @param {Object} body The body container element.\n * @param {Object} footer The footer container element.\n * @param {Array} messages List of messages.\n * @param {Object} datesCache Cache timestamps and their formatted date string.\n */\n var renderUpdateMessages = function(header, body, footer, messages, datesCache) {\n messages.forEach(function(message) {\n var before = message.before;\n var after = message.after;\n var element = getMessageElement(body, before.id);\n\n if (before.id != after.id) {\n element.attr('data-message-id', after.id);\n }\n\n if (before.timeCreated != after.timeCreated) {\n var formattedTime = datesCache[after.timeCreated];\n element.find(SELECTORS.LOADING_ICON_CONTAINER).addClass('hidden');\n element.find(SELECTORS.TIME_CREATED).text(formattedTime).removeClass('hidden');\n }\n\n if (before.sendState != after.sendState) {\n var loading = element.find(SELECTORS.LOADING_ICON_CONTAINER);\n var time = element.find(SELECTORS.TIME_CREATED);\n var retry = element.find(SELECTORS.RETRY_SEND);\n\n loading.addClass('hidden');\n Aria.hide(loading.get());\n\n time.addClass('hidden');\n Aria.hide(time.get());\n\n retry.addClass('hidden');\n Aria.hide(retry.get());\n\n element.removeClass('border border-danger');\n\n switch (after.sendState) {\n case 'pending':\n loading.removeClass('hidden');\n Aria.unhide(loading.get());\n break;\n case 'error':\n retry.removeClass('hidden');\n Aria.unhide(retry.get());\n element.addClass('border border-danger');\n break;\n case 'sent':\n time.removeClass('hidden');\n Aria.unhide(time.get());\n break;\n }\n }\n\n if (before.text != after.text) {\n element.find(SELECTORS.TEXT_CONTAINER).html(after.text);\n }\n\n if (before.errorMessage != after.errorMessage) {\n var messageContainer = element.find(SELECTORS.ERROR_MESSAGE_CONTAINER);\n var message = messageContainer.find(SELECTORS.ERROR_MESSAGE);\n\n if (after.errorMessage) {\n messageContainer.removeClass('hidden');\n Aria.unhide(messageContainer.get());\n message.text(after.errorMessage);\n } else {\n messageContainer.addClass('hidden');\n Aria.unhide(messageContainer.get());\n message.text('');\n }\n }\n });\n };\n\n /**\n * Remove days from conversation.\n *\n * @param {Object} body The body container element.\n * @param {Array} days Array of days to be removed.\n */\n var renderRemoveDays = function(body, days) {\n days.forEach(function(data) {\n getDayElement(body, data.timestamp).remove();\n });\n };\n\n /**\n * Remove messages from conversation.\n *\n * @param {Object} body The body container element.\n * @param {Array} messages Array of messages to be removed.\n */\n var renderRemoveMessages = function(body, messages) {\n messages.forEach(function(data) {\n getMessageElement(body, data.id).remove();\n });\n };\n\n /**\n * Render the full conversation base on input from the statemanager.\n *\n * This will pre-load all of the formatted timestamps for each message that\n * needs to render to reduce the number of networks requests.\n *\n * @param {Object} header The header container element.\n * @param {Object} body The body container element.\n * @param {Object} footer The footer container element.\n * @param {Object} data The conversation diff.\n * @return {Object} jQuery promise.\n */\n var renderConversation = function(header, body, footer, data) {\n var renderingPromises = [];\n var hasAddDays = data.days.add.length > 0;\n var hasAddMessages = data.messages.add.length > 0;\n var hasUpdateMessages = data.messages.update.length > 0;\n var timestampsToFormat = [];\n var datesCachePromise = $.Deferred().resolve({}).promise();\n\n if (hasAddDays) {\n // Search for all of the timeCreated values in all of the messages in all of\n // the days that we need to render.\n timestampsToFormat = timestampsToFormat.concat(data.days.add.reduce(function(carry, day) {\n return carry.concat(day.value.messages.reduce(function(timestamps, message) {\n if (message.timeCreated) {\n timestamps.push(message.timeCreated);\n }\n return timestamps;\n }, []));\n }, []));\n }\n\n if (hasAddMessages) {\n // Search for all of the timeCreated values in all of the messages that we\n // need to render.\n timestampsToFormat = timestampsToFormat.concat(data.messages.add.reduce(function(timestamps, message) {\n if (message.value.timeCreated) {\n timestamps.push(message.value.timeCreated);\n }\n return timestamps;\n }, []));\n }\n\n if (hasUpdateMessages) {\n timestampsToFormat = timestampsToFormat.concat(data.messages.update.reduce(function(timestamps, message) {\n if (message.before.timeCreated != message.after.timeCreated) {\n timestamps.push(message.after.timeCreated);\n }\n return timestamps;\n }, []));\n }\n\n if (timestampsToFormat.length) {\n // If we have timestamps then pre-load the formatted version of each of them\n // in a single request to the server. This saves the templates doing multiple\n // individual requests.\n datesCachePromise = Str.get_string('strftimetime24', 'core_langconfig')\n .then(function(format) {\n var requests = timestampsToFormat.map(function(timestamp) {\n return {\n timestamp: timestamp,\n format: format\n };\n });\n\n return UserDate.get(requests);\n })\n .then(function(formattedTimes) {\n return timestampsToFormat.reduce(function(carry, timestamp, index) {\n carry[timestamp] = formattedTimes[index];\n return carry;\n }, {});\n });\n }\n\n if (hasAddDays) {\n renderingPromises.push(datesCachePromise.then(function(datesCache) {\n return renderAddDays(header, body, footer, data.days.add, datesCache);\n }));\n }\n\n if (hasAddMessages) {\n renderingPromises.push(datesCachePromise.then(function(datesCache) {\n return renderAddMessages(header, body, footer, data.messages.add, datesCache);\n }));\n }\n\n if (hasUpdateMessages) {\n renderingPromises.push(datesCachePromise.then(function(datesCache) {\n return renderUpdateMessages(header, body, footer, data.messages.update, datesCache);\n }));\n }\n\n if (data.days.remove.length > 0) {\n renderRemoveDays(body, data.days.remove);\n }\n\n if (data.messages.remove.length > 0) {\n renderRemoveMessages(body, data.messages.remove);\n }\n\n return $.when.apply($, renderingPromises);\n };\n\n /**\n * Render the conversation header.\n *\n * @param {Object} header The header container element.\n * @param {Object} body The body container element.\n * @param {Object} footer The footer container element.\n * @param {Object} data Data for header.\n * @return {Object} jQuery promise\n */\n var renderHeader = function(header, body, footer, data) {\n var headerContainer = getHeaderContent(header);\n var template = TEMPLATES.HEADER_PUBLIC;\n data.context.showrouteback = (header.attr('data-from-panel') === \"false\");\n if (data.type == CONVERSATION_TYPES.PRIVATE) {\n template = data.showControls ? TEMPLATES.HEADER_PRIVATE : TEMPLATES.HEADER_PRIVATE_NO_CONTROLS;\n } else if (data.type == CONVERSATION_TYPES.SELF) {\n template = TEMPLATES.HEADER_SELF;\n }\n\n return Templates.render(template, data.context)\n .then(function(html, js) {\n Templates.replaceNodeContents(headerContainer, html, js);\n return;\n });\n };\n\n /**\n * Render the conversation footer.\n *\n * @param {Object} header The header container element.\n * @param {Object} body The body container element.\n * @param {Object} footer The footer container element.\n * @param {Object} data Data for footer.\n * @return {Object} jQuery promise.\n */\n var renderFooter = function(header, body, footer, data) {\n hideAllFooterElements(footer);\n\n switch (data.type) {\n case 'placeholder':\n return showFooterPlaceholder(footer);\n case 'add-contact':\n return Str.get_strings([\n {\n key: 'requirecontacttomessage',\n component: 'core_message',\n param: data.user.fullname\n },\n {\n key: 'isnotinyourcontacts',\n component: 'core_message',\n param: data.user.fullname\n }\n ])\n .then(function(strings) {\n var title = strings[1];\n var text = strings[0];\n var footerContainer = getFooterRequireContactContainer(footer);\n footerContainer.find(SELECTORS.TITLE).text(title);\n footerContainer.find(SELECTORS.TEXT).text(text);\n showFooterRequireContact(footer);\n return strings;\n });\n case 'edit-mode':\n return showFooterEditMode(footer);\n case 'content':\n return showFooterContent(footer);\n case 'unblock':\n return showFooterRequireUnblock(footer);\n case 'unable-to-message':\n return showFooterUnableToMessage(footer);\n }\n\n return true;\n };\n\n /**\n * Scroll to a message in the conversation.\n *\n * @param {Object} header The header container element.\n * @param {Object} body The body container element.\n * @param {Object} footer The footer container element.\n * @param {Number} messageId Message id.\n */\n var renderScrollToMessage = function(header, body, footer, messageId) {\n var messagesContainer = getMessagesContainer(body);\n var messageElement = getMessageElement(body, messageId);\n var position = messageElement.position();\n // Scroll the message container down to the top of the message element.\n if (position) {\n var scrollTop = messagesContainer.scrollTop() + position.top;\n messagesContainer.scrollTop(scrollTop);\n }\n };\n\n /**\n * Hide or show the conversation header.\n *\n * @param {Object} header The header container element.\n * @param {Object} body The body container element.\n * @param {Object} footer The footer container element.\n * @param {Bool} isLoadingMembers Members loading.\n */\n var renderLoadingMembers = function(header, body, footer, isLoadingMembers) {\n if (isLoadingMembers) {\n hideHeaderContent(header);\n showHeaderPlaceholder(header);\n } else {\n showHeaderContent(header);\n hideHeaderPlaceholder(header);\n }\n };\n\n /**\n * Hide or show loading conversation messages.\n *\n * @param {Object} header The header container element.\n * @param {Object} body The body container element.\n * @param {Object} footer The footer container element.\n * @param {Bool} isLoadingFirstMessages Messages loading.\n */\n var renderLoadingFirstMessages = function(header, body, footer, isLoadingFirstMessages) {\n if (isLoadingFirstMessages) {\n hideMessagesContainer(body);\n showContentPlaceholder(body);\n } else {\n showMessagesContainer(body);\n hideContentPlaceholder(body);\n }\n };\n\n /**\n * Hide or show loading more messages.\n *\n * @param {Object} header The header container element.\n * @param {Object} body The body container element.\n * @param {Object} footer The footer container element.\n * @param {Bool} isLoading Messages loading.\n */\n var renderLoadingMessages = function(header, body, footer, isLoading) {\n if (isLoading) {\n showMoreMessagesLoadingIcon(body);\n } else {\n hideMoreMessagesLoadingIcon(body);\n }\n };\n\n /**\n * Hide or show the emoji picker.\n *\n * @param {Object} header The header container element.\n * @param {Object} body The body container element.\n * @param {Object} footer The footer container element.\n * @param {Bool} show Should the emoji picker be visible.\n */\n var renderShowEmojiPicker = function(header, body, footer, show) {\n var container = getEmojiPickerContainer(footer);\n\n if (show) {\n container.removeClass('hidden');\n Aria.unhide(container.get());\n container.find(SELECTORS.EMOJI_PICKER_SEARCH_INPUT).focus();\n } else {\n container.addClass('hidden');\n Aria.hide(container.get());\n }\n };\n\n /**\n * Hide or show the emoji auto complete.\n *\n * @param {Object} header The header container element.\n * @param {Object} body The body container element.\n * @param {Object} footer The footer container element.\n * @param {Bool} show Should the emoji picker be visible.\n */\n var renderShowEmojiAutoComplete = function(header, body, footer, show) {\n var container = getEmojiAutoCompleteContainer(footer);\n\n if (show) {\n container.removeClass('hidden');\n Aria.unhide(container.get());\n } else {\n container.addClass('hidden');\n Aria.hide(container.get());\n }\n };\n\n /**\n * Show a confirmation dialogue\n *\n * @param {Object} header The header container element.\n * @param {Object} body The body container element.\n * @param {Object} footer The footer container element.\n * @param {String} buttonSelectors Selectors for the buttons to show.\n * @param {String} bodyText Text to show in dialogue.\n * @param {String} headerText Text to show in dialogue header.\n * @param {Bool} canCancel Can this dialogue be cancelled.\n * @param {Bool} skipHeader Skip blanking out the header\n * @param {Bool} showOk Show an 'Okay' button for a dialogue which will close it\n */\n var showConfirmDialogue = function(\n header,\n body,\n footer,\n buttonSelectors,\n bodyText,\n headerText,\n canCancel,\n skipHeader,\n showOk\n ) {\n var dialogue = getConfirmDialogueContainer(body);\n var buttons = buttonSelectors.map(function(selector) {\n return dialogue.find(selector);\n });\n var cancelButton = dialogue.find(SELECTORS.CONFIRM_DIALOGUE_CANCEL_BUTTON);\n var okayButton = dialogue.find(SELECTORS.CONFIRM_DIALOGUE_OKAY_BUTTON);\n var text = dialogue.find(SELECTORS.CONFIRM_DIALOGUE_TEXT);\n var dialogueHeader = dialogue.find(SELECTORS.CONFIRM_DIALOGUE_HEADER);\n\n dialogue.find('button').addClass('hidden');\n\n if (canCancel) {\n cancelButton.removeClass('hidden');\n } else {\n cancelButton.addClass('hidden');\n }\n\n if (showOk) {\n okayButton.removeClass('hidden');\n } else {\n okayButton.addClass('hidden');\n }\n\n if (headerText) {\n // Create the dialogue header.\n dialogueHeader = $('

');\n dialogueHeader.text(headerText);\n // Prepend it to the confirmation body.\n var confirmDialogue = dialogue.find(SELECTORS.CONFIRM_DIALOGUE);\n confirmDialogue.prepend(dialogueHeader);\n } else if (dialogueHeader.length) {\n // Header text is empty but dialogue header is present, so remove it.\n dialogueHeader.remove();\n }\n\n buttons.forEach(function(button) {\n button.removeClass('hidden');\n });\n text.text(bodyText);\n showConfirmDialogueContainer(footer);\n showConfirmDialogueContainer(body);\n\n if (!skipHeader) {\n showConfirmDialogueContainer(header);\n }\n\n dialogue.find(SELECTORS.CAN_RECEIVE_FOCUS).filter(':visible').first().focus();\n };\n\n /**\n * Hide the dialogue\n *\n * @param {Object} header The header container element.\n * @param {Object} body The body container element.\n * @param {Object} footer The footer container element.\n * @return {Bool} always true.\n */\n var hideConfirmDialogue = function(header, body, footer) {\n var dialogue = getConfirmDialogueContainer(body);\n var cancelButton = dialogue.find(SELECTORS.CONFIRM_DIALOGUE_CANCEL_BUTTON);\n var okayButton = dialogue.find(SELECTORS.CONFIRM_DIALOGUE_OKAY_BUTTON);\n var text = dialogue.find(SELECTORS.CONFIRM_DIALOGUE_TEXT);\n var dialogueHeader = dialogue.find(SELECTORS.CONFIRM_DIALOGUE_HEADER);\n\n hideCheckDeleteDialogue(body);\n hideConfirmDialogueContainer(body);\n hideConfirmDialogueContainer(footer);\n hideConfirmDialogueContainer(header);\n dialogue.find('button').addClass('hidden');\n cancelButton.removeClass('hidden');\n okayButton.removeClass('hidden');\n text.text('');\n\n // Remove dialogue header if present.\n if (dialogueHeader.length) {\n dialogueHeader.remove();\n }\n\n header.find(SELECTORS.CAN_RECEIVE_FOCUS).first().focus();\n return true;\n };\n\n /**\n * Render the confirm block user dialogue.\n *\n * @param {Object} header The header container element.\n * @param {Object} body The body container element.\n * @param {Object} footer The footer container element.\n * @param {Object} user User to block.\n * @return {Object} jQuery promise\n */\n var renderConfirmBlockUser = function(header, body, footer, user) {\n if (user) {\n if (user.canmessageevenifblocked) {\n return Str.get_string('cantblockuser', 'core_message', user.fullname)\n .then(function(string) {\n return showConfirmDialogue(header, body, footer, [], string, '', false, false, true);\n });\n } else {\n return Str.get_string('blockuserconfirm', 'core_message', user.fullname)\n .then(function(string) {\n return showConfirmDialogue(header, body, footer, [SELECTORS.ACTION_CONFIRM_BLOCK], string, '', true, false);\n });\n }\n } else {\n return hideConfirmDialogue(header, body, footer);\n }\n };\n\n /**\n * Render the confirm unblock user dialogue.\n *\n * @param {Object} header The header container element.\n * @param {Object} body The body container element.\n * @param {Object} footer The footer container element.\n * @param {Object} user User to unblock.\n * @return {Object} jQuery promise\n */\n var renderConfirmUnblockUser = function(header, body, footer, user) {\n if (user) {\n return Str.get_string('unblockuserconfirm', 'core_message', user.fullname)\n .then(function(string) {\n return showConfirmDialogue(header, body, footer, [SELECTORS.ACTION_CONFIRM_UNBLOCK], string, '', true, false);\n });\n } else {\n return hideConfirmDialogue(header, body, footer);\n }\n };\n\n /**\n * Render the add user as contact dialogue.\n *\n * @param {Object} header The header container element.\n * @param {Object} body The body container element.\n * @param {Object} footer The footer container element.\n * @param {Object} user User to add as contact.\n * @return {Object} jQuery promise\n */\n var renderConfirmAddContact = function(header, body, footer, user) {\n if (user) {\n return Str.get_string('addcontactconfirm', 'core_message', user.fullname)\n .then(function(string) {\n return showConfirmDialogue(\n header,\n body,\n footer,\n [SELECTORS.ACTION_CONFIRM_ADD_CONTACT],\n string,\n '',\n true,\n false\n );\n });\n } else {\n return hideConfirmDialogue(header, body, footer);\n }\n };\n\n /**\n * Render the remove user from contacts dialogue.\n *\n * @param {Object} header The header container element.\n * @param {Object} body The body container element.\n * @param {Object} footer The footer container element.\n * @param {Object} user User to remove from contacts.\n * @return {Object} jQuery promise\n */\n var renderConfirmRemoveContact = function(header, body, footer, user) {\n if (user) {\n return Str.get_string('removecontactconfirm', 'core_message', user.fullname)\n .then(function(string) {\n return showConfirmDialogue(\n header,\n body,\n footer,\n [SELECTORS.ACTION_CONFIRM_REMOVE_CONTACT],\n string,\n '',\n true,\n false\n );\n });\n } else {\n return hideConfirmDialogue(header, body, footer);\n }\n };\n\n /**\n * Render the delete selected messages dialogue.\n *\n * @param {Object} header The header container element.\n * @param {Object} body The body container element.\n * @param {Object} footer The footer container element.\n * @param {Object} data If the dialogue should show and checkbox shows to delete message for all users.\n * @return {Object} jQuery promise\n */\n var renderConfirmDeleteSelectedMessages = function(header, body, footer, data) {\n var showmessage = null;\n if (data.type == CONVERSATION_TYPES.SELF) {\n // Message displayed to self-conversations is slighly different.\n showmessage = 'deleteselectedmessagesconfirmselfconversation';\n } else {\n // This other message should be displayed.\n if (data.canDeleteMessagesForAllUsers) {\n showCheckDeleteDialogue(body);\n showmessage = 'deleteforeveryoneselectedmessagesconfirm';\n } else {\n showmessage = 'deleteselectedmessagesconfirm';\n }\n }\n\n if (data.show) {\n return Str.get_string(showmessage, 'core_message')\n .then(function(string) {\n return showConfirmDialogue(\n header,\n body,\n footer,\n [SELECTORS.ACTION_CONFIRM_DELETE_SELECTED_MESSAGES],\n string,\n '',\n true,\n false\n );\n });\n } else {\n return hideConfirmDialogue(header, body, footer);\n }\n };\n\n /**\n * Render the confirm delete conversation dialogue.\n *\n * @param {Object} header The header container element.\n * @param {Object} body The body container element.\n * @param {Object} footer The footer container element.\n * @param {int|Null} type The conversation type to be removed.\n * @return {Object} jQuery promise\n */\n var renderConfirmDeleteConversation = function(header, body, footer, type) {\n var showmessage = null;\n if (type == CONVERSATION_TYPES.SELF) {\n // Message displayed to self-conversations is slighly different.\n showmessage = 'deleteallselfconfirm';\n } else if (type) {\n // This other message should be displayed.\n showmessage = 'deleteallconfirm';\n }\n\n if (showmessage) {\n return Str.get_string(showmessage, 'core_message')\n .then(function(string) {\n return showConfirmDialogue(\n header,\n body,\n footer,\n [SELECTORS.ACTION_CONFIRM_DELETE_CONVERSATION],\n string,\n '',\n true,\n false\n );\n });\n } else {\n return hideConfirmDialogue(header, body, footer);\n }\n };\n\n /**\n * Render the confirm delete conversation dialogue.\n *\n * @param {Object} header The header container element.\n * @param {Object} body The body container element.\n * @param {Object} footer The footer container element.\n * @param {Bool} user The other user object.\n * @return {Object} jQuery promise\n */\n var renderConfirmContactRequest = function(header, body, footer, user) {\n if (user) {\n return Str.get_string('userwouldliketocontactyou', 'core_message', user.fullname)\n .then(function(string) {\n var buttonSelectors = [\n SELECTORS.ACTION_ACCEPT_CONTACT_REQUEST,\n SELECTORS.ACTION_DECLINE_CONTACT_REQUEST\n ];\n return showConfirmDialogue(header, body, footer, buttonSelectors, string, '', false, true);\n });\n } else {\n return hideConfirmDialogue(header, body, footer);\n }\n };\n\n /**\n * Show the checkbox to allow delete message for all.\n *\n * @param {Object} body The body container element.\n */\n var showCheckDeleteDialogue = function(body) {\n var dialogue = getConfirmDialogueContainer(body);\n var checkboxRegion = dialogue.find(SELECTORS.DELETE_MESSAGES_FOR_ALL_USERS_TOGGLE_CONTAINER);\n checkboxRegion.removeClass('hidden');\n };\n\n /**\n * Hide the checkbox to allow delete message for all.\n *\n * @param {Object} body The body container element.\n */\n var hideCheckDeleteDialogue = function(body) {\n var dialogue = getConfirmDialogueContainer(body);\n var checkboxRegion = dialogue.find(SELECTORS.DELETE_MESSAGES_FOR_ALL_USERS_TOGGLE_CONTAINER);\n var checkbox = dialogue.find(SELECTORS.DELETE_MESSAGES_FOR_ALL_USERS_TOGGLE);\n checkbox.prop('checked', false);\n checkboxRegion.addClass('hidden');\n };\n\n /**\n * Show or hide the block / unblock option in the header dropdown menu.\n *\n * @param {Object} header The header container element.\n * @param {Object} body The body container element.\n * @param {Object} footer The footer container element.\n * @param {Bool} isBlocked is user blocked.\n */\n var renderIsBlocked = function(header, body, footer, isBlocked) {\n if (isBlocked) {\n header.find(SELECTORS.ACTION_REQUEST_BLOCK).addClass('hidden');\n header.find(SELECTORS.ACTION_REQUEST_UNBLOCK).removeClass('hidden');\n } else {\n header.find(SELECTORS.ACTION_REQUEST_BLOCK).removeClass('hidden');\n header.find(SELECTORS.ACTION_REQUEST_UNBLOCK).addClass('hidden');\n }\n };\n\n /**\n * Show or hide the favourite / unfavourite option in the header dropdown menu\n * and the favourite star in the header title.\n *\n * @param {Object} header The header container element.\n * @param {Object} body The body container element.\n * @param {Object} footer The footer container element.\n * @param {Bool} isFavourite is this conversation a favourite.\n */\n var renderIsFavourite = function(header, body, footer, state) {\n var favouriteIcon = header.find(SELECTORS.FAVOURITE_ICON_CONTAINER);\n var addFavourite = header.find(SELECTORS.ACTION_CONFIRM_FAVOURITE);\n var removeFavourite = header.find(SELECTORS.ACTION_CONFIRM_UNFAVOURITE);\n\n switch (state) {\n case 'hide':\n favouriteIcon.addClass('hidden');\n addFavourite.addClass('hidden');\n removeFavourite.addClass('hidden');\n break;\n case 'show-add':\n favouriteIcon.addClass('hidden');\n addFavourite.removeClass('hidden');\n removeFavourite.addClass('hidden');\n break;\n case 'show-remove':\n favouriteIcon.removeClass('hidden');\n addFavourite.addClass('hidden');\n removeFavourite.removeClass('hidden');\n break;\n }\n };\n\n /**\n * Show or hide the mute / unmute option in the header dropdown menu\n * and the muted icon in the header title.\n *\n * @param {Object} header The header container element.\n * @param {Object} body The body container element.\n * @param {Object} footer The footer container element.\n * @param {string} state The state of the conversation as defined by the patcher.\n */\n var renderIsMuted = function(header, body, footer, state) {\n var muteIcon = header.find(SELECTORS.MUTED_ICON_CONTAINER);\n var setMuted = header.find(SELECTORS.ACTION_CONFIRM_MUTE);\n var unsetMuted = header.find(SELECTORS.ACTION_CONFIRM_UNMUTE);\n\n switch (state) {\n case 'hide':\n muteIcon.addClass('hidden');\n setMuted.addClass('hidden');\n unsetMuted.addClass('hidden');\n break;\n case 'show-mute':\n muteIcon.addClass('hidden');\n setMuted.removeClass('hidden');\n unsetMuted.addClass('hidden');\n break;\n case 'show-unmute':\n muteIcon.removeClass('hidden');\n setMuted.addClass('hidden');\n unsetMuted.removeClass('hidden');\n break;\n }\n };\n\n /**\n * Show or hide the add / remove user as contact option in the header dropdown menu.\n *\n * @param {Object} header The header container element.\n * @param {Object} body The body container element.\n * @param {Object} footer The footer container element.\n * @param {Bool} state the contact state.\n */\n var renderIsContact = function(header, body, footer, state) {\n var addContact = header.find(SELECTORS.ACTION_REQUEST_ADD_CONTACT);\n var removeContact = header.find(SELECTORS.ACTION_REQUEST_REMOVE_CONTACT);\n\n switch (state) {\n case 'pending-contact':\n addContact.addClass('hidden');\n removeContact.addClass('hidden');\n break;\n case 'contact':\n addContact.addClass('hidden');\n removeContact.removeClass('hidden');\n break;\n case 'non-contact':\n addContact.removeClass('hidden');\n removeContact.addClass('hidden');\n break;\n }\n };\n\n /**\n * Show or hide confirm action from confirm dialogue is loading.\n *\n * @param {Object} header The header container element.\n * @param {Object} body The body container element.\n * @param {Object} footer The footer container element.\n * @param {Bool} isLoading confirm action is loading.\n */\n var renderLoadingConfirmAction = function(header, body, footer, isLoading) {\n var dialogue = getConfirmDialogueContainer(body);\n var buttons = dialogue.find('button');\n var buttonText = dialogue.find(SELECTORS.CONFIRM_DIALOGUE_BUTTON_TEXT);\n var loadingIcon = dialogue.find(SELECTORS.LOADING_ICON_CONTAINER);\n\n if (isLoading) {\n buttons.prop('disabled', true);\n buttonText.addClass('hidden');\n loadingIcon.removeClass('hidden');\n } else {\n buttons.prop('disabled', false);\n buttonText.removeClass('hidden');\n loadingIcon.addClass('hidden');\n }\n };\n\n /**\n * Show or hide the header and footer content for edit mode.\n *\n * @param {Object} header The header container element.\n * @param {Object} body The body container element.\n * @param {Object} footer The footer container element.\n * @param {Bool} inEditMode In edit mode or not.\n */\n var renderInEditMode = function(header, body, footer, inEditMode) {\n var messages = null;\n\n if (inEditMode) {\n messages = body.find(SELECTORS.MESSAGE_NOT_SELECTED);\n messages.find(SELECTORS.MESSAGE_NOT_SELECTED_ICON).removeClass('hidden');\n hideHeaderContent(header);\n showHeaderEditMode(header);\n } else {\n messages = getMessagesContainer(body);\n messages.find(SELECTORS.MESSAGE_NOT_SELECTED_ICON).addClass('hidden');\n messages.find(SELECTORS.MESSAGE_SELECTED_ICON).addClass('hidden');\n showHeaderContent(header);\n hideHeaderEditMode(header);\n }\n };\n\n /**\n * Select or unselect messages.\n *\n * @param {Object} header The header container element.\n * @param {Object} body The body container element.\n * @param {Object} footer The footer container element.\n * @param {Object} data The messages to select or unselect.\n */\n var renderSelectedMessages = function(header, body, footer, data) {\n var hasSelectedMessages = data.count > 0;\n\n if (data.add.length) {\n data.add.forEach(function(messageId) {\n var message = getMessageElement(body, messageId);\n message.find(SELECTORS.MESSAGE_NOT_SELECTED_ICON).addClass('hidden');\n message.find(SELECTORS.MESSAGE_SELECTED_ICON).removeClass('hidden');\n message.attr('aria-checked', true);\n });\n }\n\n if (data.remove.length) {\n data.remove.forEach(function(messageId) {\n var message = getMessageElement(body, messageId);\n\n if (hasSelectedMessages) {\n message.find(SELECTORS.MESSAGE_NOT_SELECTED_ICON).removeClass('hidden');\n }\n\n message.find(SELECTORS.MESSAGE_SELECTED_ICON).addClass('hidden');\n message.attr('aria-checked', false);\n });\n }\n\n setMessagesSelectedCount(header, data.count);\n };\n\n /**\n * Show or hide the require add contact panel.\n *\n * @param {Object} header The header container element.\n * @param {Object} body The body container element.\n * @param {Object} footer The footer container element.\n * @param {Object} data Whether the user has to be added a a contact.\n * @return {Object} jQuery promise\n */\n var renderRequireAddContact = function(header, body, footer, data) {\n if (data.show && !data.hasMessages) {\n return Str.get_strings([\n {\n key: 'requirecontacttomessage',\n component: 'core_message',\n param: data.user.fullname\n },\n {\n key: 'isnotinyourcontacts',\n component: 'core_message',\n param: data.user.fullname\n }\n ])\n .then(function(strings) {\n var title = strings[1];\n var text = strings[0];\n return showConfirmDialogue(\n header,\n body,\n footer,\n [SELECTORS.ACTION_REQUEST_ADD_CONTACT],\n text,\n title,\n false,\n true\n );\n });\n } else {\n return hideConfirmDialogue(header, body, footer);\n }\n };\n\n /**\n * Show or hide the self-conversation message.\n *\n * @param {Object} header The header container element.\n * @param {Object} body The body container element.\n * @param {Object} footer The footer container element.\n * @param {Object} displayMessage should the message be displayed?.\n * @return {Object|true} jQuery promise\n */\n var renderSelfConversationMessage = function(header, body, footer, displayMessage) {\n var container = getSelfConversationMessageContainer(body);\n if (displayMessage) {\n container.removeClass('hidden');\n } else {\n container.addClass('hidden');\n }\n return true;\n };\n\n /**\n * Show or hide the require add contact panel.\n *\n * @param {Object} header The header container element.\n * @param {Object} body The body container element.\n * @param {Object} footer The footer container element.\n * @param {Object} userFullName Full name of the other user.\n * @return {Object|true} jQuery promise\n */\n var renderContactRequestSent = function(header, body, footer, userFullName) {\n var container = getContactRequestSentContainer(body);\n if (userFullName) {\n return Str.get_string('yourcontactrequestpending', 'core_message', userFullName)\n .then(function(string) {\n container.find(SELECTORS.TEXT).text(string);\n container.removeClass('hidden');\n return string;\n });\n } else {\n container.addClass('hidden');\n return true;\n }\n };\n\n /**\n * Reset the UI to the initial state.\n *\n * @param {Object} header The header container element.\n * @param {Object} body The body container element.\n * @param {Object} footer The footer container element.\n * @return {Bool}\n */\n var renderReset = function(header, body, footer) {\n hideConfirmDialogue(header, body, footer);\n hideContactRequestSentContainer(body);\n hideSelfConversationMessageContainer(body);\n hideAllHeaderElements(header);\n showHeaderPlaceholder(header);\n hideAllFooterElements(footer);\n showFooterPlaceholder(footer);\n return true;\n };\n\n var render = function(header, body, footer, patch) {\n var configs = [\n {\n // Resetting the UI needs to come first, if it's required.\n reset: renderReset\n },\n {\n // Any async rendering (stuff that requires templates, strings etc) should\n // go in here.\n conversation: renderConversation,\n header: renderHeader,\n footer: renderFooter,\n confirmBlockUser: renderConfirmBlockUser,\n confirmUnblockUser: renderConfirmUnblockUser,\n confirmAddContact: renderConfirmAddContact,\n confirmRemoveContact: renderConfirmRemoveContact,\n confirmDeleteSelectedMessages: renderConfirmDeleteSelectedMessages,\n confirmDeleteConversation: renderConfirmDeleteConversation,\n confirmContactRequest: renderConfirmContactRequest,\n requireAddContact: renderRequireAddContact,\n selfConversationMessage: renderSelfConversationMessage,\n contactRequestSent: renderContactRequestSent\n },\n {\n loadingMembers: renderLoadingMembers,\n loadingFirstMessages: renderLoadingFirstMessages,\n loadingMessages: renderLoadingMessages,\n isBlocked: renderIsBlocked,\n isContact: renderIsContact,\n isFavourite: renderIsFavourite,\n isMuted: renderIsMuted,\n loadingConfirmAction: renderLoadingConfirmAction,\n inEditMode: renderInEditMode,\n showEmojiPicker: renderShowEmojiPicker,\n showEmojiAutoComplete: renderShowEmojiAutoComplete,\n },\n {\n // Scrolling should be last to make sure everything\n // on the page is visible.\n scrollToMessage: renderScrollToMessage,\n selectedMessages: renderSelectedMessages\n }\n ];\n // Helper function to process each of the configs above.\n var processConfig = function(config) {\n var results = [];\n\n for (var key in patch) {\n if (config.hasOwnProperty(key)) {\n var renderFunc = config[key];\n var patchValue = patch[key];\n results.push(renderFunc(header, body, footer, patchValue));\n }\n }\n\n return results;\n };\n\n // The first config is special because it resets the UI.\n var renderingPromises = processConfig(configs[0]);\n // The second config is special because it contains async rendering.\n renderingPromises = renderingPromises.concat(processConfig(configs[1]));\n\n // Wait for the async rendering to complete before processing the\n // rest of the configs, in order.\n return $.when.apply($, renderingPromises)\n .then(function() {\n for (var i = 2; i < configs.length; i++) {\n processConfig(configs[i]);\n }\n\n return;\n })\n .catch(Notification.exception);\n };\n\n return {\n render: render,\n };\n});\n"],"file":"message_drawer_view_conversation_renderer.min.js"} \ No newline at end of file diff --git a/message/amd/src/message_drawer_view_conversation_renderer.js b/message/amd/src/message_drawer_view_conversation_renderer.js index ed6d1b78342..92c128ca993 100644 --- a/message/amd/src/message_drawer_view_conversation_renderer.js +++ b/message/amd/src/message_drawer_view_conversation_renderer.js @@ -575,8 +575,10 @@ function( var renderAddDays = function(header, body, footer, days, datesCache) { var messagesContainer = getMessagesContainer(body); var daysRenderPromises = days.map(function(data) { + var timestampDate = new Date(data.value.timestamp * 1000); return Templates.render(TEMPLATES.DAY, { timestamp: data.value.timestamp, + currentyear: timestampDate.getFullYear() === (new Date()).getFullYear(), messages: formatMessagesForTemplate(data.value.messages, datesCache) }); }); diff --git a/message/templates/message_drawer_view_conversation_body_day.mustache b/message/templates/message_drawer_view_conversation_body_day.mustache index c4c8e5ac7a4..311dff9f860 100644 --- a/message/templates/message_drawer_view_conversation_body_day.mustache +++ b/message/templates/message_drawer_view_conversation_body_day.mustache @@ -27,14 +27,25 @@ * All data attributes are required Context variables required for this template: - * userid The logged in user id - * urls The URLs for the popover + * timestamp + * currentyear + * messages Example context (json): - {} - + { + "timestamp": 946684800, + "currentyear": false, + "messages": [] + } }}
-
{{#userdate}} {{timestamp}}, {{#str}} strftimedateshort, core_langconfig {{/str}} {{/userdate}}
+
+ {{#currentyear}} + {{#userdate}} {{timestamp}}, {{#str}} strftimedateshort, core_langconfig {{/str}} {{/userdate}} + {{/currentyear}} + {{^currentyear}} + {{#userdate}} {{timestamp}}, {{#str}} strftimedate, core_langconfig {{/str}} {{/userdate}} + {{/currentyear}} +
{{> core_message/message_drawer_view_conversation_body_messages }}
\ No newline at end of file