| 1 | efrain | 1 | // This file is part of Moodle - http://moodle.org/
 | 
        
           |  |  | 2 | //
 | 
        
           |  |  | 3 | // Moodle is free software: you can redistribute it and/or modify
 | 
        
           |  |  | 4 | // it under the terms of the GNU General Public License as published by
 | 
        
           |  |  | 5 | // the Free Software Foundation, either version 3 of the License, or
 | 
        
           |  |  | 6 | // (at your option) any later version.
 | 
        
           |  |  | 7 | //
 | 
        
           |  |  | 8 | // Moodle is distributed in the hope that it will be useful,
 | 
        
           |  |  | 9 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
        
           |  |  | 10 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
        
           |  |  | 11 | // GNU General Public License for more details.
 | 
        
           |  |  | 12 | //
 | 
        
           |  |  | 13 | // You should have received a copy of the GNU General Public License
 | 
        
           |  |  | 14 | // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
 | 
        
           |  |  | 15 |   | 
        
           |  |  | 16 | /**
 | 
        
           |  |  | 17 |  * This module updates the UI for the conversation page in the message
 | 
        
           |  |  | 18 |  * drawer.
 | 
        
           |  |  | 19 |  *
 | 
        
           |  |  | 20 |  * The module will take a patch from the message_drawer_view_conversation_patcher
 | 
        
           |  |  | 21 |  * module and update the UI to reflect the changes.
 | 
        
           |  |  | 22 |  *
 | 
        
           |  |  | 23 |  * This is the only module that ever modifies the UI of the conversation page.
 | 
        
           |  |  | 24 |  *
 | 
        
           |  |  | 25 |  * @module     core_message/message_drawer_view_conversation_renderer
 | 
        
           |  |  | 26 |  * @copyright  2018 Ryan Wyllie <ryan@moodle.com>
 | 
        
           |  |  | 27 |  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 | 
        
           |  |  | 28 |  */
 | 
        
           |  |  | 29 | define(
 | 
        
           |  |  | 30 | [
 | 
        
           |  |  | 31 |     'jquery',
 | 
        
           |  |  | 32 |     'core/notification',
 | 
        
           |  |  | 33 |     'core/str',
 | 
        
           |  |  | 34 |     'core/templates',
 | 
        
           |  |  | 35 |     'core/user_date',
 | 
        
           |  |  | 36 |     'core_message/message_drawer_view_conversation_constants',
 | 
        
           |  |  | 37 |     'core/aria',
 | 
        
           | 1441 | ariadna | 38 |     'core/truncate',
 | 
        
           | 1 | efrain | 39 | ],
 | 
        
           |  |  | 40 | function(
 | 
        
           |  |  | 41 |     $,
 | 
        
           |  |  | 42 |     Notification,
 | 
        
           |  |  | 43 |     Str,
 | 
        
           |  |  | 44 |     Templates,
 | 
        
           |  |  | 45 |     UserDate,
 | 
        
           |  |  | 46 |     Constants,
 | 
        
           | 1441 | ariadna | 47 |     Aria,
 | 
        
           |  |  | 48 |     Truncate,
 | 
        
           | 1 | efrain | 49 | ) {
 | 
        
           |  |  | 50 |     var SELECTORS = Constants.SELECTORS;
 | 
        
           |  |  | 51 |     var TEMPLATES = Constants.TEMPLATES;
 | 
        
           |  |  | 52 |     var CONVERSATION_TYPES = Constants.CONVERSATION_TYPES;
 | 
        
           |  |  | 53 |   | 
        
           |  |  | 54 |     /**
 | 
        
           |  |  | 55 |      * Get the messages container element.
 | 
        
           |  |  | 56 |      *
 | 
        
           |  |  | 57 |      * @param  {Object} body Conversation body container element.
 | 
        
           |  |  | 58 |      * @return {Object} The messages container element.
 | 
        
           |  |  | 59 |      */
 | 
        
           |  |  | 60 |     var getMessagesContainer = function(body) {
 | 
        
           |  |  | 61 |         return body.find(SELECTORS.CONTENT_MESSAGES_CONTAINER);
 | 
        
           |  |  | 62 |     };
 | 
        
           |  |  | 63 |   | 
        
           |  |  | 64 |     /**
 | 
        
           |  |  | 65 |      * Show the messages container element.
 | 
        
           |  |  | 66 |      *
 | 
        
           |  |  | 67 |      * @param  {Object} body Conversation body container element.
 | 
        
           |  |  | 68 |      */
 | 
        
           |  |  | 69 |     var showMessagesContainer = function(body) {
 | 
        
           |  |  | 70 |         getMessagesContainer(body).removeClass('hidden');
 | 
        
           |  |  | 71 |     };
 | 
        
           |  |  | 72 |   | 
        
           |  |  | 73 |     /**
 | 
        
           |  |  | 74 |      * Hide the messages container element.
 | 
        
           |  |  | 75 |      *
 | 
        
           |  |  | 76 |      * @param  {Object} body Conversation body container element.
 | 
        
           |  |  | 77 |      */
 | 
        
           |  |  | 78 |     var hideMessagesContainer = function(body) {
 | 
        
           |  |  | 79 |         getMessagesContainer(body).addClass('hidden');
 | 
        
           |  |  | 80 |     };
 | 
        
           |  |  | 81 |   | 
        
           |  |  | 82 |     /**
 | 
        
           |  |  | 83 |      * Get the self-conversation message container element.
 | 
        
           |  |  | 84 |      *
 | 
        
           |  |  | 85 |      * @param  {Object} body Conversation body container element.
 | 
        
           |  |  | 86 |      * @return {Object} The messages container element.
 | 
        
           |  |  | 87 |      */
 | 
        
           |  |  | 88 |     var getSelfConversationMessageContainer = function(body) {
 | 
        
           |  |  | 89 |         return body.find(SELECTORS.SELF_CONVERSATION_MESSAGE_CONTAINER);
 | 
        
           |  |  | 90 |     };
 | 
        
           |  |  | 91 |   | 
        
           |  |  | 92 |     /**
 | 
        
           |  |  | 93 |      * Hide the self-conversation message container element.
 | 
        
           |  |  | 94 |      *
 | 
        
           |  |  | 95 |      * @param  {Object} body Conversation body container element.
 | 
        
           |  |  | 96 |      * @return {Object} The messages container element.
 | 
        
           |  |  | 97 |      */
 | 
        
           |  |  | 98 |     var hideSelfConversationMessageContainer = function(body) {
 | 
        
           |  |  | 99 |         return getSelfConversationMessageContainer(body).addClass('hidden');
 | 
        
           |  |  | 100 |     };
 | 
        
           |  |  | 101 |   | 
        
           |  |  | 102 |     /**
 | 
        
           |  |  | 103 |      * Get the contact request sent container element.
 | 
        
           |  |  | 104 |      *
 | 
        
           |  |  | 105 |      * @param  {Object} body Conversation body container element.
 | 
        
           |  |  | 106 |      * @return {Object} The messages container element.
 | 
        
           |  |  | 107 |      */
 | 
        
           |  |  | 108 |     var getContactRequestSentContainer = function(body) {
 | 
        
           |  |  | 109 |         return body.find(SELECTORS.CONTACT_REQUEST_SENT_MESSAGE_CONTAINER);
 | 
        
           |  |  | 110 |     };
 | 
        
           |  |  | 111 |   | 
        
           |  |  | 112 |     /**
 | 
        
           |  |  | 113 |      * Hide the contact request sent container element.
 | 
        
           |  |  | 114 |      *
 | 
        
           |  |  | 115 |      * @param  {Object} body Conversation body container element.
 | 
        
           |  |  | 116 |      * @return {Object} The messages container element.
 | 
        
           |  |  | 117 |      */
 | 
        
           |  |  | 118 |     var hideContactRequestSentContainer = function(body) {
 | 
        
           |  |  | 119 |         return getContactRequestSentContainer(body).addClass('hidden');
 | 
        
           |  |  | 120 |     };
 | 
        
           |  |  | 121 |   | 
        
           |  |  | 122 |     /**
 | 
        
           |  |  | 123 |      * Get the footer container element.
 | 
        
           |  |  | 124 |      *
 | 
        
           |  |  | 125 |      * @param  {Object} footer Conversation footer container element.
 | 
        
           |  |  | 126 |      * @return {Object} The footer container element.
 | 
        
           |  |  | 127 |      */
 | 
        
           |  |  | 128 |     var getFooterContentContainer = function(footer) {
 | 
        
           |  |  | 129 |         return footer.find(SELECTORS.CONTENT_MESSAGES_FOOTER_CONTAINER);
 | 
        
           |  |  | 130 |     };
 | 
        
           |  |  | 131 |   | 
        
           |  |  | 132 |     /**
 | 
        
           |  |  | 133 |      * Show the footer container element.
 | 
        
           |  |  | 134 |      *
 | 
        
           |  |  | 135 |      * @param  {Object} footer Conversation footer container element.
 | 
        
           |  |  | 136 |      */
 | 
        
           |  |  | 137 |     var showFooterContent = function(footer) {
 | 
        
           |  |  | 138 |         getFooterContentContainer(footer).removeClass('hidden');
 | 
        
           |  |  | 139 |     };
 | 
        
           |  |  | 140 |   | 
        
           |  |  | 141 |     /**
 | 
        
           |  |  | 142 |      * Hide the footer container element.
 | 
        
           |  |  | 143 |      *
 | 
        
           |  |  | 144 |      * @param  {Object} footer Conversation footer container element.
 | 
        
           |  |  | 145 |      */
 | 
        
           |  |  | 146 |     var hideFooterContent = function(footer) {
 | 
        
           |  |  | 147 |         getFooterContentContainer(footer).addClass('hidden');
 | 
        
           |  |  | 148 |     };
 | 
        
           |  |  | 149 |   | 
        
           |  |  | 150 |     /**
 | 
        
           |  |  | 151 |      * Get the footer edit mode container element.
 | 
        
           |  |  | 152 |      *
 | 
        
           |  |  | 153 |      * @param  {Object} footer Conversation footer container element.
 | 
        
           |  |  | 154 |      * @return {Object} The footer container element.
 | 
        
           |  |  | 155 |      */
 | 
        
           |  |  | 156 |     var getFooterEditModeContainer = function(footer) {
 | 
        
           |  |  | 157 |         return footer.find(SELECTORS.CONTENT_MESSAGES_FOOTER_EDIT_MODE_CONTAINER);
 | 
        
           |  |  | 158 |     };
 | 
        
           |  |  | 159 |   | 
        
           |  |  | 160 |     /**
 | 
        
           |  |  | 161 |      * Show the footer edit mode container element.
 | 
        
           |  |  | 162 |      *
 | 
        
           |  |  | 163 |      * @param  {Object} footer Conversation footer container element.
 | 
        
           |  |  | 164 |      */
 | 
        
           |  |  | 165 |     var showFooterEditMode = function(footer) {
 | 
        
           |  |  | 166 |         getFooterEditModeContainer(footer).removeClass('hidden');
 | 
        
           |  |  | 167 |     };
 | 
        
           |  |  | 168 |   | 
        
           |  |  | 169 |     /**
 | 
        
           |  |  | 170 |      * Hide the footer edit mode container element.
 | 
        
           |  |  | 171 |      *
 | 
        
           |  |  | 172 |      * @param  {Object} footer Conversation footer container element.
 | 
        
           |  |  | 173 |      */
 | 
        
           |  |  | 174 |     var hideFooterEditMode = function(footer) {
 | 
        
           |  |  | 175 |         getFooterEditModeContainer(footer).addClass('hidden');
 | 
        
           |  |  | 176 |     };
 | 
        
           |  |  | 177 |   | 
        
           |  |  | 178 |     /**
 | 
        
           |  |  | 179 |      * Get the footer placeholder.
 | 
        
           |  |  | 180 |      *
 | 
        
           |  |  | 181 |      * @param  {Object} footer Conversation footer container element.
 | 
        
           |  |  | 182 |      * @return {Object} The footer placeholder container element.
 | 
        
           |  |  | 183 |      */
 | 
        
           |  |  | 184 |     var getFooterPlaceholderContainer = function(footer) {
 | 
        
           |  |  | 185 |         return footer.find(SELECTORS.PLACEHOLDER_CONTAINER);
 | 
        
           |  |  | 186 |     };
 | 
        
           |  |  | 187 |   | 
        
           |  |  | 188 |     /**
 | 
        
           |  |  | 189 |      * Show the footer placeholder
 | 
        
           |  |  | 190 |      *
 | 
        
           |  |  | 191 |      * @param  {Object} footer Conversation footer container element.
 | 
        
           |  |  | 192 |      */
 | 
        
           |  |  | 193 |     var showFooterPlaceholder = function(footer) {
 | 
        
           |  |  | 194 |         getFooterPlaceholderContainer(footer).removeClass('hidden');
 | 
        
           |  |  | 195 |     };
 | 
        
           |  |  | 196 |   | 
        
           |  |  | 197 |     /**
 | 
        
           |  |  | 198 |      * Hide the footer placeholder
 | 
        
           |  |  | 199 |      *
 | 
        
           |  |  | 200 |      * @param  {Object} footer Conversation footer container element.
 | 
        
           |  |  | 201 |      */
 | 
        
           |  |  | 202 |     var hideFooterPlaceholder = function(footer) {
 | 
        
           |  |  | 203 |         getFooterPlaceholderContainer(footer).addClass('hidden');
 | 
        
           |  |  | 204 |     };
 | 
        
           |  |  | 205 |   | 
        
           |  |  | 206 |     /**
 | 
        
           |  |  | 207 |      * Get the footer Require add as contact container element.
 | 
        
           |  |  | 208 |      *
 | 
        
           |  |  | 209 |      * @param  {Object} footer Conversation footer container element.
 | 
        
           |  |  | 210 |      * @return {Object} The footer Require add as contact container element.
 | 
        
           |  |  | 211 |      */
 | 
        
           |  |  | 212 |     var getFooterRequireContactContainer = function(footer) {
 | 
        
           |  |  | 213 |         return footer.find(SELECTORS.CONTENT_MESSAGES_FOOTER_REQUIRE_CONTACT_CONTAINER);
 | 
        
           |  |  | 214 |     };
 | 
        
           |  |  | 215 |   | 
        
           |  |  | 216 |     /**
 | 
        
           |  |  | 217 |      * Show the footer add as contact dialogue.
 | 
        
           |  |  | 218 |      *
 | 
        
           |  |  | 219 |      * @param  {Object} footer Conversation footer container element.
 | 
        
           |  |  | 220 |      */
 | 
        
           |  |  | 221 |     var showFooterRequireContact = function(footer) {
 | 
        
           |  |  | 222 |         getFooterRequireContactContainer(footer).removeClass('hidden');
 | 
        
           |  |  | 223 |     };
 | 
        
           |  |  | 224 |   | 
        
           |  |  | 225 |     /**
 | 
        
           |  |  | 226 |      * Hide the footer add as contact dialogue.
 | 
        
           |  |  | 227 |      *
 | 
        
           |  |  | 228 |      * @param  {Object} footer Conversation footer container element.
 | 
        
           |  |  | 229 |      */
 | 
        
           |  |  | 230 |     var hideFooterRequireContact = function(footer) {
 | 
        
           |  |  | 231 |         getFooterRequireContactContainer(footer).addClass('hidden');
 | 
        
           |  |  | 232 |     };
 | 
        
           |  |  | 233 |   | 
        
           |  |  | 234 |     /**
 | 
        
           |  |  | 235 |      * Get the footer Required to unblock contact container element.
 | 
        
           |  |  | 236 |      *
 | 
        
           |  |  | 237 |      * @param  {Object} footer Conversation footer container element.
 | 
        
           |  |  | 238 |      * @return {Object} The footer Required to unblock contact container element.
 | 
        
           |  |  | 239 |      */
 | 
        
           |  |  | 240 |     var getFooterRequireUnblockContainer = function(footer) {
 | 
        
           |  |  | 241 |         return footer.find(SELECTORS.CONTENT_MESSAGES_FOOTER_REQUIRE_UNBLOCK_CONTAINER);
 | 
        
           |  |  | 242 |     };
 | 
        
           |  |  | 243 |   | 
        
           |  |  | 244 |     /**
 | 
        
           |  |  | 245 |      * Show the footer Required to unblock contact container element.
 | 
        
           |  |  | 246 |      *
 | 
        
           |  |  | 247 |      * @param  {Object} footer Conversation footer container element.
 | 
        
           |  |  | 248 |      */
 | 
        
           |  |  | 249 |     var showFooterRequireUnblock = function(footer) {
 | 
        
           |  |  | 250 |         getFooterRequireUnblockContainer(footer).removeClass('hidden');
 | 
        
           |  |  | 251 |     };
 | 
        
           |  |  | 252 |   | 
        
           |  |  | 253 |     /**
 | 
        
           |  |  | 254 |      * Hide the footer Required to unblock contact container element.
 | 
        
           |  |  | 255 |      *
 | 
        
           |  |  | 256 |      * @param  {Object} footer Conversation footer container element.
 | 
        
           |  |  | 257 |      */
 | 
        
           |  |  | 258 |     var hideFooterRequireUnblock = function(footer) {
 | 
        
           |  |  | 259 |         getFooterRequireUnblockContainer(footer).addClass('hidden');
 | 
        
           |  |  | 260 |     };
 | 
        
           |  |  | 261 |   | 
        
           |  |  | 262 |     /**
 | 
        
           |  |  | 263 |      * Get the footer Unable to message contact container element.
 | 
        
           |  |  | 264 |      *
 | 
        
           |  |  | 265 |      * @param  {Object} footer Conversation footer container element.
 | 
        
           |  |  | 266 |      * @return {Object} The footer Unable to message contact container element.
 | 
        
           |  |  | 267 |      */
 | 
        
           |  |  | 268 |     var getFooterUnableToMessageContainer = function(footer) {
 | 
        
           |  |  | 269 |         return footer.find(SELECTORS.CONTENT_MESSAGES_FOOTER_UNABLE_TO_MESSAGE_CONTAINER);
 | 
        
           |  |  | 270 |     };
 | 
        
           |  |  | 271 |   | 
        
           |  |  | 272 |     /**
 | 
        
           |  |  | 273 |      * Show the footer Unable to message contact container element.
 | 
        
           |  |  | 274 |      *
 | 
        
           |  |  | 275 |      * @param  {Object} footer Conversation footer container element.
 | 
        
           |  |  | 276 |      */
 | 
        
           |  |  | 277 |     var showFooterUnableToMessage = function(footer) {
 | 
        
           |  |  | 278 |         getFooterUnableToMessageContainer(footer).removeClass('hidden');
 | 
        
           |  |  | 279 |     };
 | 
        
           |  |  | 280 |   | 
        
           |  |  | 281 |     /**
 | 
        
           |  |  | 282 |      * Hide the footer Unable to message contact container element.
 | 
        
           |  |  | 283 |      *
 | 
        
           |  |  | 284 |      * @param  {Object} footer Conversation footer container element.
 | 
        
           |  |  | 285 |      */
 | 
        
           |  |  | 286 |     var hideFooterUnableToMessage = function(footer) {
 | 
        
           |  |  | 287 |         getFooterUnableToMessageContainer(footer).addClass('hidden');
 | 
        
           |  |  | 288 |     };
 | 
        
           |  |  | 289 |   | 
        
           |  |  | 290 |     /**
 | 
        
           |  |  | 291 |      * Hide all header elements.
 | 
        
           |  |  | 292 |      *
 | 
        
           |  |  | 293 |      * @param  {Object} header Conversation header container element.
 | 
        
           |  |  | 294 |      */
 | 
        
           |  |  | 295 |     var hideAllHeaderElements = function(header) {
 | 
        
           |  |  | 296 |         hideHeaderContent(header);
 | 
        
           |  |  | 297 |         hideHeaderEditMode(header);
 | 
        
           |  |  | 298 |         hideHeaderPlaceholder(header);
 | 
        
           |  |  | 299 |     };
 | 
        
           |  |  | 300 |   | 
        
           |  |  | 301 |     /**
 | 
        
           |  |  | 302 |      * Hide all footer dialogues and messages.
 | 
        
           |  |  | 303 |      *
 | 
        
           |  |  | 304 |      * @param  {Object} footer Conversation footer container element.
 | 
        
           |  |  | 305 |      */
 | 
        
           |  |  | 306 |     var hideAllFooterElements = function(footer) {
 | 
        
           |  |  | 307 |         hideFooterContent(footer);
 | 
        
           |  |  | 308 |         hideFooterEditMode(footer);
 | 
        
           |  |  | 309 |         hideFooterPlaceholder(footer);
 | 
        
           |  |  | 310 |         hideFooterRequireContact(footer);
 | 
        
           |  |  | 311 |         hideFooterRequireUnblock(footer);
 | 
        
           |  |  | 312 |         hideFooterUnableToMessage(footer);
 | 
        
           |  |  | 313 |     };
 | 
        
           |  |  | 314 |   | 
        
           |  |  | 315 |     /**
 | 
        
           |  |  | 316 |      * Get the content placeholder container element.
 | 
        
           |  |  | 317 |      *
 | 
        
           |  |  | 318 |      * @param  {Object} body Conversation body container element.
 | 
        
           |  |  | 319 |      * @return {Object} The body placeholder container element.
 | 
        
           |  |  | 320 |      */
 | 
        
           |  |  | 321 |     var getContentPlaceholderContainer = function(body) {
 | 
        
           |  |  | 322 |         return body.find(SELECTORS.CONTENT_PLACEHOLDER_CONTAINER);
 | 
        
           |  |  | 323 |     };
 | 
        
           |  |  | 324 |   | 
        
           |  |  | 325 |     /**
 | 
        
           |  |  | 326 |      * Show the content placeholder.
 | 
        
           |  |  | 327 |      *
 | 
        
           |  |  | 328 |      * @param  {Object} body Conversation body container element.
 | 
        
           |  |  | 329 |      */
 | 
        
           |  |  | 330 |     var showContentPlaceholder = function(body) {
 | 
        
           |  |  | 331 |         getContentPlaceholderContainer(body).removeClass('hidden');
 | 
        
           |  |  | 332 |     };
 | 
        
           |  |  | 333 |   | 
        
           |  |  | 334 |     /**
 | 
        
           |  |  | 335 |      * Hide the content placeholder.
 | 
        
           |  |  | 336 |      *
 | 
        
           |  |  | 337 |      * @param  {Object} body Conversation body container element.
 | 
        
           |  |  | 338 |      */
 | 
        
           |  |  | 339 |     var hideContentPlaceholder = function(body) {
 | 
        
           |  |  | 340 |         getContentPlaceholderContainer(body).addClass('hidden');
 | 
        
           |  |  | 341 |     };
 | 
        
           |  |  | 342 |   | 
        
           |  |  | 343 |     /**
 | 
        
           |  |  | 344 |      * Get the header content container element.
 | 
        
           |  |  | 345 |      *
 | 
        
           |  |  | 346 |      * @param  {Object} header Conversation header container element.
 | 
        
           |  |  | 347 |      * @return {Object} The header content container element.
 | 
        
           |  |  | 348 |      */
 | 
        
           |  |  | 349 |     var getHeaderContent = function(header) {
 | 
        
           |  |  | 350 |         return header.find(SELECTORS.HEADER);
 | 
        
           |  |  | 351 |     };
 | 
        
           |  |  | 352 |   | 
        
           |  |  | 353 |     /**
 | 
        
           |  |  | 354 |      * Show the header content.
 | 
        
           |  |  | 355 |      *
 | 
        
           |  |  | 356 |      * @param  {Object} header Conversation header container element.
 | 
        
           |  |  | 357 |      */
 | 
        
           |  |  | 358 |     var showHeaderContent = function(header) {
 | 
        
           |  |  | 359 |         getHeaderContent(header).removeClass('hidden');
 | 
        
           |  |  | 360 |     };
 | 
        
           |  |  | 361 |   | 
        
           |  |  | 362 |     /**
 | 
        
           |  |  | 363 |      * Hide the header content.
 | 
        
           |  |  | 364 |      *
 | 
        
           |  |  | 365 |      * @param  {Object} header Conversation header container element.
 | 
        
           |  |  | 366 |      */
 | 
        
           |  |  | 367 |     var hideHeaderContent = function(header) {
 | 
        
           |  |  | 368 |         getHeaderContent(header).addClass('hidden');
 | 
        
           |  |  | 369 |     };
 | 
        
           |  |  | 370 |   | 
        
           |  |  | 371 |     /**
 | 
        
           |  |  | 372 |      * Get the header edit mode container element.
 | 
        
           |  |  | 373 |      *
 | 
        
           |  |  | 374 |      * @param  {Object} header Conversation header container element.
 | 
        
           |  |  | 375 |      * @return {Object} The header content container element.
 | 
        
           |  |  | 376 |      */
 | 
        
           |  |  | 377 |     var getHeaderEditMode = function(header) {
 | 
        
           |  |  | 378 |         return header.find(SELECTORS.HEADER_EDIT_MODE);
 | 
        
           |  |  | 379 |     };
 | 
        
           |  |  | 380 |   | 
        
           |  |  | 381 |     /**
 | 
        
           |  |  | 382 |      * Show the header edit mode container.
 | 
        
           |  |  | 383 |      *
 | 
        
           |  |  | 384 |      * @param  {Object} header Conversation header container element.
 | 
        
           |  |  | 385 |      */
 | 
        
           |  |  | 386 |     var showHeaderEditMode = function(header) {
 | 
        
           |  |  | 387 |         getHeaderEditMode(header).removeClass('hidden');
 | 
        
           |  |  | 388 |     };
 | 
        
           |  |  | 389 |   | 
        
           |  |  | 390 |     /**
 | 
        
           |  |  | 391 |      * Hide the header edit mode container.
 | 
        
           |  |  | 392 |      *
 | 
        
           |  |  | 393 |      * @param  {Object} header Conversation header container element.
 | 
        
           |  |  | 394 |      */
 | 
        
           |  |  | 395 |     var hideHeaderEditMode = function(header) {
 | 
        
           |  |  | 396 |         getHeaderEditMode(header).addClass('hidden');
 | 
        
           |  |  | 397 |     };
 | 
        
           |  |  | 398 |   | 
        
           |  |  | 399 |     /**
 | 
        
           |  |  | 400 |      * Get the header placeholder container element.
 | 
        
           |  |  | 401 |      *
 | 
        
           |  |  | 402 |      * @param  {Object} header Conversation header container element.
 | 
        
           |  |  | 403 |      * @return {Object} The header placeholder container element.
 | 
        
           |  |  | 404 |      */
 | 
        
           |  |  | 405 |     var getHeaderPlaceholderContainer = function(header) {
 | 
        
           |  |  | 406 |         return header.find(SELECTORS.HEADER_PLACEHOLDER_CONTAINER);
 | 
        
           |  |  | 407 |     };
 | 
        
           |  |  | 408 |   | 
        
           |  |  | 409 |     /**
 | 
        
           |  |  | 410 |      * Show the header placeholder.
 | 
        
           |  |  | 411 |      *
 | 
        
           |  |  | 412 |      * @param  {Object} header Conversation header container element.
 | 
        
           |  |  | 413 |      */
 | 
        
           |  |  | 414 |     var showHeaderPlaceholder = function(header) {
 | 
        
           |  |  | 415 |         getHeaderPlaceholderContainer(header).removeClass('hidden');
 | 
        
           |  |  | 416 |     };
 | 
        
           |  |  | 417 |   | 
        
           |  |  | 418 |     /**
 | 
        
           |  |  | 419 |      * Hide the header placeholder.
 | 
        
           |  |  | 420 |      *
 | 
        
           |  |  | 421 |      * @param  {Object} header Conversation header container element.
 | 
        
           |  |  | 422 |      */
 | 
        
           |  |  | 423 |     var hideHeaderPlaceholder = function(header) {
 | 
        
           |  |  | 424 |         getHeaderPlaceholderContainer(header).addClass('hidden');
 | 
        
           |  |  | 425 |     };
 | 
        
           |  |  | 426 |   | 
        
           |  |  | 427 |     /**
 | 
        
           |  |  | 428 |      * Get the emoji picker container element.
 | 
        
           |  |  | 429 |      *
 | 
        
           |  |  | 430 |      * @param  {Object} footer Conversation footer container element.
 | 
        
           |  |  | 431 |      * @return {Object} The emoji picker container element.
 | 
        
           |  |  | 432 |      */
 | 
        
           |  |  | 433 |     var getEmojiPickerContainer = function(footer) {
 | 
        
           |  |  | 434 |         return footer.find(SELECTORS.EMOJI_PICKER_CONTAINER);
 | 
        
           |  |  | 435 |     };
 | 
        
           |  |  | 436 |   | 
        
           |  |  | 437 |     /**
 | 
        
           |  |  | 438 |      * Get the emoji picker container element.
 | 
        
           |  |  | 439 |      *
 | 
        
           |  |  | 440 |      * @param  {Object} footer Conversation footer container element.
 | 
        
           |  |  | 441 |      * @return {Object} The emoji picker container element.
 | 
        
           |  |  | 442 |      */
 | 
        
           |  |  | 443 |     var getEmojiAutoCompleteContainer = function(footer) {
 | 
        
           |  |  | 444 |         return footer.find(SELECTORS.EMOJI_AUTO_COMPLETE_CONTAINER);
 | 
        
           |  |  | 445 |     };
 | 
        
           |  |  | 446 |   | 
        
           |  |  | 447 |     /**
 | 
        
           |  |  | 448 |      * Get a message element.
 | 
        
           |  |  | 449 |      *
 | 
        
           |  |  | 450 |      * @param  {Object} body Conversation body container element.
 | 
        
           |  |  | 451 |      * @param  {Number} messageId the Message id.
 | 
        
           |  |  | 452 |      * @return {Object} A message element from the conversation.
 | 
        
           |  |  | 453 |      */
 | 
        
           |  |  | 454 |     var getMessageElement = function(body, messageId) {
 | 
        
           |  |  | 455 |         var messagesContainer = getMessagesContainer(body);
 | 
        
           |  |  | 456 |         return messagesContainer.find('[data-message-id="' + messageId + '"]');
 | 
        
           |  |  | 457 |     };
 | 
        
           |  |  | 458 |   | 
        
           |  |  | 459 |     /**
 | 
        
           |  |  | 460 |      * Get the day container element. The day container element holds a list of messages for that day.
 | 
        
           |  |  | 461 |      *
 | 
        
           |  |  | 462 |      * @param  {Object} body Conversation body container element.
 | 
        
           |  |  | 463 |      * @param  {Number} dayTimeCreated Midnight timestamp for the day.
 | 
        
           |  |  | 464 |      * @return {Object} jQuery object
 | 
        
           |  |  | 465 |      */
 | 
        
           |  |  | 466 |     var getDayElement = function(body, dayTimeCreated) {
 | 
        
           |  |  | 467 |         var messagesContainer = getMessagesContainer(body);
 | 
        
           |  |  | 468 |         return messagesContainer.find('[data-day-id="' + dayTimeCreated + '"]');
 | 
        
           |  |  | 469 |     };
 | 
        
           |  |  | 470 |   | 
        
           |  |  | 471 |     /**
 | 
        
           |  |  | 472 |      * Get the more messages loading icon container element.
 | 
        
           |  |  | 473 |      *
 | 
        
           |  |  | 474 |      * @param  {Object} body Conversation body container element.
 | 
        
           |  |  | 475 |      * @return {Object} The more messages loading container element.
 | 
        
           |  |  | 476 |      */
 | 
        
           |  |  | 477 |     var getMoreMessagesLoadingIconContainer = function(body) {
 | 
        
           |  |  | 478 |         return body.find(SELECTORS.MORE_MESSAGES_LOADING_ICON_CONTAINER);
 | 
        
           |  |  | 479 |     };
 | 
        
           |  |  | 480 |   | 
        
           |  |  | 481 |     /**
 | 
        
           |  |  | 482 |      * Show the more messages loading icon.
 | 
        
           |  |  | 483 |      *
 | 
        
           |  |  | 484 |      * @param  {Object} body Conversation body container element.
 | 
        
           |  |  | 485 |      */
 | 
        
           |  |  | 486 |     var showMoreMessagesLoadingIcon = function(body) {
 | 
        
           |  |  | 487 |         getMoreMessagesLoadingIconContainer(body).removeClass('hidden');
 | 
        
           |  |  | 488 |     };
 | 
        
           |  |  | 489 |   | 
        
           |  |  | 490 |     /**
 | 
        
           |  |  | 491 |      * Hide the more messages loading icon.
 | 
        
           |  |  | 492 |      *
 | 
        
           |  |  | 493 |      * @param  {Object} body Conversation body container element.
 | 
        
           |  |  | 494 |      */
 | 
        
           |  |  | 495 |     var hideMoreMessagesLoadingIcon = function(body) {
 | 
        
           |  |  | 496 |         getMoreMessagesLoadingIconContainer(body).addClass('hidden');
 | 
        
           |  |  | 497 |     };
 | 
        
           |  |  | 498 |   | 
        
           |  |  | 499 |     /**
 | 
        
           |  |  | 500 |      * Get the confirm dialogue container element.
 | 
        
           |  |  | 501 |      *
 | 
        
           |  |  | 502 |      * @param  {Object} root The container element to search.
 | 
        
           |  |  | 503 |      * @return {Object} The confirm dialogue container element.
 | 
        
           |  |  | 504 |      */
 | 
        
           |  |  | 505 |     var getConfirmDialogueContainer = function(root) {
 | 
        
           |  |  | 506 |         return root.find(SELECTORS.CONFIRM_DIALOGUE_CONTAINER);
 | 
        
           |  |  | 507 |     };
 | 
        
           |  |  | 508 |   | 
        
           |  |  | 509 |     /**
 | 
        
           |  |  | 510 |      * Show the confirm dialogue container element.
 | 
        
           |  |  | 511 |      *
 | 
        
           |  |  | 512 |      * @param  {Object} root The container element containing a dialogue.
 | 
        
           |  |  | 513 |      */
 | 
        
           |  |  | 514 |     var showConfirmDialogueContainer = function(root) {
 | 
        
           |  |  | 515 |         var container = getConfirmDialogueContainer(root);
 | 
        
           |  |  | 516 |         var siblings = container.siblings(':not(.hidden)');
 | 
        
           |  |  | 517 |         Aria.hide(siblings.get());
 | 
        
           |  |  | 518 |         siblings.attr('data-confirm-dialogue-hidden', true);
 | 
        
           |  |  | 519 |   | 
        
           |  |  | 520 |         container.removeClass('hidden');
 | 
        
           |  |  | 521 |     };
 | 
        
           |  |  | 522 |   | 
        
           |  |  | 523 |     /**
 | 
        
           |  |  | 524 |      * Hide the confirm dialogue container element.
 | 
        
           |  |  | 525 |      *
 | 
        
           |  |  | 526 |      * @param  {Object} root The container element containing a dialogue.
 | 
        
           |  |  | 527 |      */
 | 
        
           |  |  | 528 |     var hideConfirmDialogueContainer = function(root) {
 | 
        
           |  |  | 529 |         var container = getConfirmDialogueContainer(root);
 | 
        
           |  |  | 530 |         var siblings = container.siblings('[data-confirm-dialogue-hidden="true"]');
 | 
        
           |  |  | 531 |         Aria.unhide(siblings.get());
 | 
        
           |  |  | 532 |         siblings.removeAttr('data-confirm-dialogue-hidden');
 | 
        
           |  |  | 533 |   | 
        
           |  |  | 534 |         container.addClass('hidden');
 | 
        
           |  |  | 535 |     };
 | 
        
           |  |  | 536 |   | 
        
           |  |  | 537 |     /**
 | 
        
           |  |  | 538 |      * Set the number of selected messages.
 | 
        
           |  |  | 539 |      *
 | 
        
           |  |  | 540 |      * @param {Object} header The header container element.
 | 
        
           |  |  | 541 |      * @param {Number} value The new number to display.
 | 
        
           |  |  | 542 |      */
 | 
        
           |  |  | 543 |     var setMessagesSelectedCount = function(header, value) {
 | 
        
           |  |  | 544 |         getHeaderEditMode(header).find(SELECTORS.MESSAGES_SELECTED_COUNT).text(value);
 | 
        
           |  |  | 545 |     };
 | 
        
           |  |  | 546 |   | 
        
           |  |  | 547 |     /**
 | 
        
           |  |  | 548 |      * Format message for the mustache template, transform camelCase properties to lowercase properties.
 | 
        
           |  |  | 549 |      *
 | 
        
           |  |  | 550 |      * @param  {Array} messages Array of message objects.
 | 
        
           |  |  | 551 |      * @param  {Object} datesCache Cache timestamps and their formatted date string.
 | 
        
           |  |  | 552 |      * @return {Array} Messages formated for mustache template.
 | 
        
           |  |  | 553 |      */
 | 
        
           |  |  | 554 |     var formatMessagesForTemplate = function(messages, datesCache) {
 | 
        
           |  |  | 555 |         return messages.map(function(message) {
 | 
        
           |  |  | 556 |             return {
 | 
        
           |  |  | 557 |                 id: message.id,
 | 
        
           |  |  | 558 |                 isread: message.isRead,
 | 
        
           |  |  | 559 |                 fromloggedinuser: message.fromLoggedInUser,
 | 
        
           |  |  | 560 |                 userfrom: message.userFrom,
 | 
        
           |  |  | 561 |                 text: message.text,
 | 
        
           |  |  | 562 |                 formattedtime: message.timeCreated ? datesCache[message.timeCreated] : null
 | 
        
           |  |  | 563 |             };
 | 
        
           |  |  | 564 |         });
 | 
        
           |  |  | 565 |     };
 | 
        
           |  |  | 566 |   | 
        
           |  |  | 567 |     /**
 | 
        
           |  |  | 568 |      * Create rendering promises for each day containing messages.
 | 
        
           |  |  | 569 |      *
 | 
        
           |  |  | 570 |      * @param  {Object} header The header container element.
 | 
        
           |  |  | 571 |      * @param  {Object} body The body container element.
 | 
        
           |  |  | 572 |      * @param  {Object} footer The footer container element.
 | 
        
           |  |  | 573 |      * @param  {Array} days Array of days containing messages.
 | 
        
           |  |  | 574 |      * @param  {Object} datesCache Cache timestamps and their formatted date string.
 | 
        
           |  |  | 575 |      * @return {Promise} Days rendering promises.
 | 
        
           |  |  | 576 |      */
 | 
        
           |  |  | 577 |     var renderAddDays = function(header, body, footer, days, datesCache) {
 | 
        
           |  |  | 578 |         var messagesContainer = getMessagesContainer(body);
 | 
        
           |  |  | 579 |         var daysRenderPromises = days.map(function(data) {
 | 
        
           |  |  | 580 |             var timestampDate = new Date(data.value.timestamp * 1000);
 | 
        
           |  |  | 581 |             return Templates.render(TEMPLATES.DAY, {
 | 
        
           |  |  | 582 |                 timestamp: data.value.timestamp,
 | 
        
           |  |  | 583 |                 currentyear: timestampDate.getFullYear() === (new Date()).getFullYear(),
 | 
        
           |  |  | 584 |                 messages: formatMessagesForTemplate(data.value.messages, datesCache)
 | 
        
           |  |  | 585 |             });
 | 
        
           |  |  | 586 |         });
 | 
        
           |  |  | 587 |   | 
        
           |  |  | 588 |         return $.when.apply($, daysRenderPromises).then(function() {
 | 
        
           |  |  | 589 |             // Wait until all of the rendering is done for each of the days
 | 
        
           |  |  | 590 |             // to ensure they are added to the page in the correct order.
 | 
        
           |  |  | 591 |             days.forEach(function(data, index) {
 | 
        
           |  |  | 592 |                 daysRenderPromises[index]
 | 
        
           |  |  | 593 |                     .then(function(html) {
 | 
        
           |  |  | 594 |                         if (data.before) {
 | 
        
           |  |  | 595 |                             var element = getDayElement(body, data.before.timestamp);
 | 
        
           |  |  | 596 |                             return $(html).insertBefore(element);
 | 
        
           |  |  | 597 |                         } else {
 | 
        
           |  |  | 598 |                             return messagesContainer.append(html);
 | 
        
           |  |  | 599 |                         }
 | 
        
           |  |  | 600 |                     })
 | 
        
           |  |  | 601 |                     .catch(function() {
 | 
        
           |  |  | 602 |                         // Fail silently.
 | 
        
           |  |  | 603 |                     });
 | 
        
           |  |  | 604 |             });
 | 
        
           |  |  | 605 |   | 
        
           |  |  | 606 |             return;
 | 
        
           |  |  | 607 |         });
 | 
        
           |  |  | 608 |     };
 | 
        
           |  |  | 609 |   | 
        
           |  |  | 610 |     /**
 | 
        
           |  |  | 611 |      * Add (more) messages to day containers.
 | 
        
           |  |  | 612 |      *
 | 
        
           |  |  | 613 |      * @param  {Object} header The header container element.
 | 
        
           |  |  | 614 |      * @param  {Object} body The body container element.
 | 
        
           |  |  | 615 |      * @param  {Object} footer The footer container element.
 | 
        
           |  |  | 616 |      * @param  {Array} messages List of messages.
 | 
        
           |  |  | 617 |      * @param  {Object} datesCache Cache timestamps and their formatted date string.
 | 
        
           |  |  | 618 |      * @return {Promise} Messages rendering promises.
 | 
        
           |  |  | 619 |      */
 | 
        
           |  |  | 620 |     var renderAddMessages = function(header, body, footer, messages, datesCache) {
 | 
        
           |  |  | 621 |         var messagesData = messages.map(function(data) {
 | 
        
           |  |  | 622 |             return data.value;
 | 
        
           |  |  | 623 |         });
 | 
        
           |  |  | 624 |         var formattedMessages = formatMessagesForTemplate(messagesData, datesCache);
 | 
        
           |  |  | 625 |   | 
        
           |  |  | 626 |         return Templates.render(TEMPLATES.MESSAGES, {messages: formattedMessages})
 | 
        
           |  |  | 627 |             .then(function(html) {
 | 
        
           |  |  | 628 |                 var messageList = $(html);
 | 
        
           |  |  | 629 |                 messages.forEach(function(data) {
 | 
        
           |  |  | 630 |                     var messageHtml = messageList.find('[data-message-id="' + data.value.id + '"]');
 | 
        
           |  |  | 631 |                     if (data.before) {
 | 
        
           |  |  | 632 |                         var element = getMessageElement(body, data.before.id);
 | 
        
           |  |  | 633 |                         return messageHtml.insertBefore(element);
 | 
        
           |  |  | 634 |                     } else {
 | 
        
           |  |  | 635 |                         var dayContainer = getDayElement(body, data.day.timestamp);
 | 
        
           |  |  | 636 |                         var dayMessagesContainer = dayContainer.find(SELECTORS.DAY_MESSAGES_CONTAINER);
 | 
        
           |  |  | 637 |                         return dayMessagesContainer.append(messageHtml);
 | 
        
           |  |  | 638 |                     }
 | 
        
           |  |  | 639 |                 });
 | 
        
           |  |  | 640 |   | 
        
           |  |  | 641 |                 return;
 | 
        
           |  |  | 642 |             });
 | 
        
           |  |  | 643 |     };
 | 
        
           |  |  | 644 |   | 
        
           |  |  | 645 |     /**
 | 
        
           |  |  | 646 |      * Update existing messages.
 | 
        
           |  |  | 647 |      *
 | 
        
           |  |  | 648 |      * @param  {Object} header The header container element.
 | 
        
           |  |  | 649 |      * @param  {Object} body The body container element.
 | 
        
           |  |  | 650 |      * @param  {Object} footer The footer container element.
 | 
        
           |  |  | 651 |      * @param  {Array} messages List of messages.
 | 
        
           |  |  | 652 |      * @param  {Object} datesCache Cache timestamps and their formatted date string.
 | 
        
           |  |  | 653 |      */
 | 
        
           |  |  | 654 |     var renderUpdateMessages = function(header, body, footer, messages, datesCache) {
 | 
        
           |  |  | 655 |         messages.forEach(function(message) {
 | 
        
           |  |  | 656 |             var before = message.before;
 | 
        
           |  |  | 657 |             var after = message.after;
 | 
        
           |  |  | 658 |             var element = getMessageElement(body, before.id);
 | 
        
           |  |  | 659 |   | 
        
           |  |  | 660 |             if (before.id != after.id) {
 | 
        
           |  |  | 661 |                 element.attr('data-message-id', after.id);
 | 
        
           |  |  | 662 |             }
 | 
        
           |  |  | 663 |   | 
        
           |  |  | 664 |             if (before.timeCreated != after.timeCreated) {
 | 
        
           |  |  | 665 |                 var formattedTime = datesCache[after.timeCreated];
 | 
        
           |  |  | 666 |                 element.find(SELECTORS.LOADING_ICON_CONTAINER).addClass('hidden');
 | 
        
           |  |  | 667 |                 element.find(SELECTORS.TIME_CREATED).text(formattedTime).removeClass('hidden');
 | 
        
           |  |  | 668 |             }
 | 
        
           |  |  | 669 |   | 
        
           |  |  | 670 |             if (before.sendState != after.sendState) {
 | 
        
           |  |  | 671 |                 var loading = element.find(SELECTORS.LOADING_ICON_CONTAINER);
 | 
        
           |  |  | 672 |                 var time = element.find(SELECTORS.TIME_CREATED);
 | 
        
           |  |  | 673 |                 var retry = element.find(SELECTORS.RETRY_SEND);
 | 
        
           |  |  | 674 |   | 
        
           |  |  | 675 |                 loading.addClass('hidden');
 | 
        
           |  |  | 676 |                 Aria.hide(loading.get());
 | 
        
           |  |  | 677 |   | 
        
           |  |  | 678 |                 time.addClass('hidden');
 | 
        
           |  |  | 679 |                 Aria.hide(time.get());
 | 
        
           |  |  | 680 |   | 
        
           |  |  | 681 |                 retry.addClass('hidden');
 | 
        
           |  |  | 682 |                 Aria.hide(retry.get());
 | 
        
           |  |  | 683 |   | 
        
           |  |  | 684 |                 element.removeClass('border border-danger');
 | 
        
           |  |  | 685 |   | 
        
           |  |  | 686 |                 switch (after.sendState) {
 | 
        
           |  |  | 687 |                     case 'pending':
 | 
        
           |  |  | 688 |                         loading.removeClass('hidden');
 | 
        
           |  |  | 689 |                         Aria.unhide(loading.get());
 | 
        
           |  |  | 690 |                         break;
 | 
        
           |  |  | 691 |                     case 'error':
 | 
        
           |  |  | 692 |                         retry.removeClass('hidden');
 | 
        
           |  |  | 693 |                         Aria.unhide(retry.get());
 | 
        
           |  |  | 694 |                         element.addClass('border border-danger');
 | 
        
           |  |  | 695 |                         break;
 | 
        
           |  |  | 696 |                     case 'sent':
 | 
        
           |  |  | 697 |                         time.removeClass('hidden');
 | 
        
           |  |  | 698 |                         Aria.unhide(time.get());
 | 
        
           |  |  | 699 |                         break;
 | 
        
           |  |  | 700 |                 }
 | 
        
           |  |  | 701 |             }
 | 
        
           |  |  | 702 |   | 
        
           |  |  | 703 |             if (before.text != after.text) {
 | 
        
           |  |  | 704 |                 element.find(SELECTORS.TEXT_CONTAINER).html(after.text);
 | 
        
           |  |  | 705 |             }
 | 
        
           |  |  | 706 |   | 
        
           |  |  | 707 |             if (before.errorMessage != after.errorMessage) {
 | 
        
           |  |  | 708 |                 var messageContainer = element.find(SELECTORS.ERROR_MESSAGE_CONTAINER);
 | 
        
           |  |  | 709 |                 var message = messageContainer.find(SELECTORS.ERROR_MESSAGE);
 | 
        
           |  |  | 710 |   | 
        
           |  |  | 711 |                 if (after.errorMessage) {
 | 
        
           |  |  | 712 |                     messageContainer.removeClass('hidden');
 | 
        
           |  |  | 713 |                     Aria.unhide(messageContainer.get());
 | 
        
           |  |  | 714 |                     message.text(after.errorMessage);
 | 
        
           |  |  | 715 |                 } else {
 | 
        
           |  |  | 716 |                     messageContainer.addClass('hidden');
 | 
        
           |  |  | 717 |                     Aria.unhide(messageContainer.get());
 | 
        
           |  |  | 718 |                     message.text('');
 | 
        
           |  |  | 719 |                 }
 | 
        
           |  |  | 720 |             }
 | 
        
           |  |  | 721 |         });
 | 
        
           |  |  | 722 |     };
 | 
        
           |  |  | 723 |   | 
        
           |  |  | 724 |     /**
 | 
        
           |  |  | 725 |      * Remove days from conversation.
 | 
        
           |  |  | 726 |      *
 | 
        
           |  |  | 727 |      * @param  {Object} body The body container element.
 | 
        
           |  |  | 728 |      * @param  {Array} days Array of days to be removed.
 | 
        
           |  |  | 729 |      */
 | 
        
           |  |  | 730 |     var renderRemoveDays = function(body, days) {
 | 
        
           |  |  | 731 |         days.forEach(function(data) {
 | 
        
           |  |  | 732 |             getDayElement(body, data.timestamp).remove();
 | 
        
           |  |  | 733 |         });
 | 
        
           |  |  | 734 |     };
 | 
        
           |  |  | 735 |   | 
        
           |  |  | 736 |     /**
 | 
        
           |  |  | 737 |      * Remove messages from conversation.
 | 
        
           |  |  | 738 |      *
 | 
        
           |  |  | 739 |      * @param  {Object} body The body container element.
 | 
        
           |  |  | 740 |      * @param  {Array} messages Array of messages to be removed.
 | 
        
           |  |  | 741 |      */
 | 
        
           |  |  | 742 |     var renderRemoveMessages = function(body, messages) {
 | 
        
           |  |  | 743 |         messages.forEach(function(data) {
 | 
        
           |  |  | 744 |             getMessageElement(body, data.id).remove();
 | 
        
           |  |  | 745 |         });
 | 
        
           |  |  | 746 |     };
 | 
        
           |  |  | 747 |   | 
        
           |  |  | 748 |     /**
 | 
        
           |  |  | 749 |      * Render the full conversation base on input from the statemanager.
 | 
        
           |  |  | 750 |      *
 | 
        
           |  |  | 751 |      * This will pre-load all of the formatted timestamps for each message that
 | 
        
           |  |  | 752 |      * needs to render to reduce the number of networks requests.
 | 
        
           |  |  | 753 |      *
 | 
        
           |  |  | 754 |      * @param  {Object} header The header container element.
 | 
        
           |  |  | 755 |      * @param  {Object} body The body container element.
 | 
        
           |  |  | 756 |      * @param  {Object} footer The footer container element.
 | 
        
           |  |  | 757 |      * @param  {Object} data The conversation diff.
 | 
        
           |  |  | 758 |      * @return {Object} jQuery promise.
 | 
        
           |  |  | 759 |      */
 | 
        
           |  |  | 760 |     var renderConversation = function(header, body, footer, data) {
 | 
        
           |  |  | 761 |         var renderingPromises = [];
 | 
        
           |  |  | 762 |         var hasAddDays = data.days.add.length > 0;
 | 
        
           |  |  | 763 |         var hasAddMessages = data.messages.add.length > 0;
 | 
        
           |  |  | 764 |         var hasUpdateMessages = data.messages.update.length > 0;
 | 
        
           |  |  | 765 |         var timestampsToFormat = [];
 | 
        
           |  |  | 766 |         var datesCachePromise = $.Deferred().resolve({}).promise();
 | 
        
           |  |  | 767 |   | 
        
           |  |  | 768 |         if (hasAddDays) {
 | 
        
           |  |  | 769 |             // Search for all of the timeCreated values in all of the messages in all of
 | 
        
           |  |  | 770 |             // the days that we need to render.
 | 
        
           |  |  | 771 |             timestampsToFormat = timestampsToFormat.concat(data.days.add.reduce(function(carry, day) {
 | 
        
           |  |  | 772 |                 return carry.concat(day.value.messages.reduce(function(timestamps, message) {
 | 
        
           |  |  | 773 |                     if (message.timeCreated) {
 | 
        
           |  |  | 774 |                         timestamps.push(message.timeCreated);
 | 
        
           |  |  | 775 |                     }
 | 
        
           |  |  | 776 |                     return timestamps;
 | 
        
           |  |  | 777 |                 }, []));
 | 
        
           |  |  | 778 |             }, []));
 | 
        
           |  |  | 779 |         }
 | 
        
           |  |  | 780 |   | 
        
           |  |  | 781 |         if (hasAddMessages) {
 | 
        
           |  |  | 782 |             // Search for all of the timeCreated values in all of the messages that we
 | 
        
           |  |  | 783 |             // need to render.
 | 
        
           |  |  | 784 |             timestampsToFormat = timestampsToFormat.concat(data.messages.add.reduce(function(timestamps, message) {
 | 
        
           |  |  | 785 |                 if (message.value.timeCreated) {
 | 
        
           |  |  | 786 |                     timestamps.push(message.value.timeCreated);
 | 
        
           |  |  | 787 |                 }
 | 
        
           |  |  | 788 |                 return timestamps;
 | 
        
           |  |  | 789 |             }, []));
 | 
        
           |  |  | 790 |         }
 | 
        
           |  |  | 791 |   | 
        
           |  |  | 792 |         if (hasUpdateMessages) {
 | 
        
           |  |  | 793 |             timestampsToFormat = timestampsToFormat.concat(data.messages.update.reduce(function(timestamps, message) {
 | 
        
           |  |  | 794 |                 if (message.before.timeCreated != message.after.timeCreated) {
 | 
        
           |  |  | 795 |                     timestamps.push(message.after.timeCreated);
 | 
        
           |  |  | 796 |                 }
 | 
        
           |  |  | 797 |                 return timestamps;
 | 
        
           |  |  | 798 |             }, []));
 | 
        
           |  |  | 799 |         }
 | 
        
           |  |  | 800 |   | 
        
           |  |  | 801 |         if (timestampsToFormat.length) {
 | 
        
           |  |  | 802 |             // If we have timestamps then pre-load the formatted version of each of them
 | 
        
           |  |  | 803 |             // in a single request to the server. This saves the templates doing multiple
 | 
        
           |  |  | 804 |             // individual requests.
 | 
        
           |  |  | 805 |             datesCachePromise = Str.get_string('strftimetime24', 'core_langconfig')
 | 
        
           |  |  | 806 |                 .then(function(format) {
 | 
        
           |  |  | 807 |                     var requests = timestampsToFormat.map(function(timestamp) {
 | 
        
           |  |  | 808 |                         return {
 | 
        
           |  |  | 809 |                             timestamp: timestamp,
 | 
        
           |  |  | 810 |                             format: format
 | 
        
           |  |  | 811 |                         };
 | 
        
           |  |  | 812 |                     });
 | 
        
           |  |  | 813 |   | 
        
           |  |  | 814 |                     return UserDate.get(requests);
 | 
        
           |  |  | 815 |                 })
 | 
        
           |  |  | 816 |                 .then(function(formattedTimes) {
 | 
        
           |  |  | 817 |                     return timestampsToFormat.reduce(function(carry, timestamp, index) {
 | 
        
           |  |  | 818 |                         carry[timestamp] = formattedTimes[index];
 | 
        
           |  |  | 819 |                         return carry;
 | 
        
           |  |  | 820 |                     }, {});
 | 
        
           |  |  | 821 |                 });
 | 
        
           |  |  | 822 |         }
 | 
        
           |  |  | 823 |   | 
        
           |  |  | 824 |         if (hasAddDays) {
 | 
        
           |  |  | 825 |             renderingPromises.push(datesCachePromise.then(function(datesCache) {
 | 
        
           |  |  | 826 |                 return renderAddDays(header, body, footer, data.days.add, datesCache);
 | 
        
           |  |  | 827 |             }));
 | 
        
           |  |  | 828 |         }
 | 
        
           |  |  | 829 |   | 
        
           |  |  | 830 |         if (hasAddMessages) {
 | 
        
           |  |  | 831 |             renderingPromises.push(datesCachePromise.then(function(datesCache) {
 | 
        
           |  |  | 832 |                 return renderAddMessages(header, body, footer, data.messages.add, datesCache);
 | 
        
           |  |  | 833 |             }));
 | 
        
           |  |  | 834 |         }
 | 
        
           |  |  | 835 |   | 
        
           |  |  | 836 |         if (hasUpdateMessages) {
 | 
        
           |  |  | 837 |             renderingPromises.push(datesCachePromise.then(function(datesCache) {
 | 
        
           |  |  | 838 |                 return renderUpdateMessages(header, body, footer, data.messages.update, datesCache);
 | 
        
           |  |  | 839 |             }));
 | 
        
           |  |  | 840 |         }
 | 
        
           |  |  | 841 |   | 
        
           |  |  | 842 |         if (data.days.remove.length > 0) {
 | 
        
           |  |  | 843 |             renderRemoveDays(body, data.days.remove);
 | 
        
           |  |  | 844 |         }
 | 
        
           |  |  | 845 |   | 
        
           |  |  | 846 |         if (data.messages.remove.length > 0) {
 | 
        
           |  |  | 847 |             renderRemoveMessages(body, data.messages.remove);
 | 
        
           |  |  | 848 |         }
 | 
        
           |  |  | 849 |   | 
        
           |  |  | 850 |         return $.when.apply($, renderingPromises);
 | 
        
           |  |  | 851 |     };
 | 
        
           |  |  | 852 |   | 
        
           |  |  | 853 |     /**
 | 
        
           |  |  | 854 |      * Render the conversation header.
 | 
        
           |  |  | 855 |      *
 | 
        
           |  |  | 856 |      * @param {Object} header The header container element.
 | 
        
           |  |  | 857 |      * @param {Object} body The body container element.
 | 
        
           |  |  | 858 |      * @param {Object} footer The footer container element.
 | 
        
           |  |  | 859 |      * @param {Object} data Data for header.
 | 
        
           |  |  | 860 |      * @return {Object} jQuery promise
 | 
        
           |  |  | 861 |      */
 | 
        
           |  |  | 862 |     var renderHeader = function(header, body, footer, data) {
 | 
        
           |  |  | 863 |         var headerContainer = getHeaderContent(header);
 | 
        
           |  |  | 864 |         var template = TEMPLATES.HEADER_PUBLIC;
 | 
        
           |  |  | 865 |         data.context.showrouteback = (header.attr('data-from-panel') === "false");
 | 
        
           |  |  | 866 |         if (data.type == CONVERSATION_TYPES.PRIVATE) {
 | 
        
           |  |  | 867 |             template = data.showControls ? TEMPLATES.HEADER_PRIVATE : TEMPLATES.HEADER_PRIVATE_NO_CONTROLS;
 | 
        
           |  |  | 868 |         } else if (data.type == CONVERSATION_TYPES.SELF) {
 | 
        
           |  |  | 869 |             template = TEMPLATES.HEADER_SELF;
 | 
        
           |  |  | 870 |         }
 | 
        
           |  |  | 871 |   | 
        
           |  |  | 872 |         return Templates.render(template, data.context)
 | 
        
           |  |  | 873 |             .then(function(html, js) {
 | 
        
           |  |  | 874 |                 Templates.replaceNodeContents(headerContainer, html, js);
 | 
        
           |  |  | 875 |                 return;
 | 
        
           |  |  | 876 |             });
 | 
        
           |  |  | 877 |     };
 | 
        
           |  |  | 878 |   | 
        
           |  |  | 879 |     /**
 | 
        
           |  |  | 880 |      * Render the conversation footer.
 | 
        
           |  |  | 881 |      *
 | 
        
           |  |  | 882 |      * @param {Object} header The header container element.
 | 
        
           |  |  | 883 |      * @param {Object} body The body container element.
 | 
        
           |  |  | 884 |      * @param {Object} footer The footer container element.
 | 
        
           |  |  | 885 |      * @param {Object} data Data for footer.
 | 
        
           |  |  | 886 |      * @return {Object} jQuery promise.
 | 
        
           |  |  | 887 |      */
 | 
        
           |  |  | 888 |     var renderFooter = function(header, body, footer, data) {
 | 
        
           |  |  | 889 |         hideAllFooterElements(footer);
 | 
        
           |  |  | 890 |   | 
        
           |  |  | 891 |         switch (data.type) {
 | 
        
           |  |  | 892 |             case 'placeholder':
 | 
        
           |  |  | 893 |                 return showFooterPlaceholder(footer);
 | 
        
           |  |  | 894 |             case 'add-contact':
 | 
        
           |  |  | 895 |                 return Str.get_strings([
 | 
        
           |  |  | 896 |                         {
 | 
        
           |  |  | 897 |                             key: 'requirecontacttomessage',
 | 
        
           |  |  | 898 |                             component: 'core_message',
 | 
        
           |  |  | 899 |                             param: data.user.fullname
 | 
        
           |  |  | 900 |                         },
 | 
        
           |  |  | 901 |                         {
 | 
        
           |  |  | 902 |                             key: 'isnotinyourcontacts',
 | 
        
           |  |  | 903 |                             component: 'core_message',
 | 
        
           |  |  | 904 |                             param: data.user.fullname
 | 
        
           |  |  | 905 |                         }
 | 
        
           |  |  | 906 |                     ])
 | 
        
           |  |  | 907 |                     .then(function(strings) {
 | 
        
           |  |  | 908 |                         var title = strings[1];
 | 
        
           |  |  | 909 |                         var text = strings[0];
 | 
        
           |  |  | 910 |                         var footerContainer = getFooterRequireContactContainer(footer);
 | 
        
           |  |  | 911 |                         footerContainer.find(SELECTORS.TITLE).text(title);
 | 
        
           |  |  | 912 |                         footerContainer.find(SELECTORS.TEXT).text(text);
 | 
        
           |  |  | 913 |                         showFooterRequireContact(footer);
 | 
        
           |  |  | 914 |                         return strings;
 | 
        
           |  |  | 915 |                     });
 | 
        
           |  |  | 916 |             case 'edit-mode':
 | 
        
           |  |  | 917 |                 return showFooterEditMode(footer);
 | 
        
           |  |  | 918 |             case 'content':
 | 
        
           |  |  | 919 |                 return showFooterContent(footer);
 | 
        
           |  |  | 920 |             case 'unblock':
 | 
        
           |  |  | 921 |                 return showFooterRequireUnblock(footer);
 | 
        
           |  |  | 922 |             case 'unable-to-message':
 | 
        
           |  |  | 923 |                 return showFooterUnableToMessage(footer);
 | 
        
           |  |  | 924 |         }
 | 
        
           |  |  | 925 |   | 
        
           |  |  | 926 |         return true;
 | 
        
           |  |  | 927 |     };
 | 
        
           |  |  | 928 |   | 
        
           |  |  | 929 |     /**
 | 
        
           |  |  | 930 |      * Scroll to a message in the conversation.
 | 
        
           |  |  | 931 |      *
 | 
        
           |  |  | 932 |      * @param {Object} header The header container element.
 | 
        
           |  |  | 933 |      * @param {Object} body The body container element.
 | 
        
           |  |  | 934 |      * @param {Object} footer The footer container element.
 | 
        
           |  |  | 935 |      * @param {Number} messageId Message id.
 | 
        
           |  |  | 936 |      */
 | 
        
           |  |  | 937 |     var renderScrollToMessage = function(header, body, footer, messageId) {
 | 
        
           |  |  | 938 |         var messagesContainer = getMessagesContainer(body);
 | 
        
           |  |  | 939 |         var messageElement = getMessageElement(body, messageId);
 | 
        
           |  |  | 940 |         var position = messageElement.position();
 | 
        
           |  |  | 941 |         // Scroll the message container down to the top of the message element.
 | 
        
           |  |  | 942 |         if (position) {
 | 
        
           |  |  | 943 |             var scrollTop = messagesContainer.scrollTop() + position.top;
 | 
        
           |  |  | 944 |             messagesContainer.scrollTop(scrollTop);
 | 
        
           |  |  | 945 |         }
 | 
        
           |  |  | 946 |     };
 | 
        
           |  |  | 947 |   | 
        
           |  |  | 948 |     /**
 | 
        
           |  |  | 949 |      * Hide or show the conversation header.
 | 
        
           |  |  | 950 |      *
 | 
        
           |  |  | 951 |      * @param {Object} header The header container element.
 | 
        
           |  |  | 952 |      * @param {Object} body The body container element.
 | 
        
           |  |  | 953 |      * @param {Object} footer The footer container element.
 | 
        
           |  |  | 954 |      * @param {Bool} isLoadingMembers Members loading.
 | 
        
           |  |  | 955 |      */
 | 
        
           |  |  | 956 |     var renderLoadingMembers = function(header, body, footer, isLoadingMembers) {
 | 
        
           |  |  | 957 |         if (isLoadingMembers) {
 | 
        
           |  |  | 958 |             hideHeaderContent(header);
 | 
        
           |  |  | 959 |             showHeaderPlaceholder(header);
 | 
        
           |  |  | 960 |         } else {
 | 
        
           |  |  | 961 |             showHeaderContent(header);
 | 
        
           |  |  | 962 |             hideHeaderPlaceholder(header);
 | 
        
           |  |  | 963 |         }
 | 
        
           |  |  | 964 |     };
 | 
        
           |  |  | 965 |   | 
        
           |  |  | 966 |     /**
 | 
        
           |  |  | 967 |      * Hide or show loading conversation messages.
 | 
        
           |  |  | 968 |      *
 | 
        
           |  |  | 969 |      * @param {Object} header The header container element.
 | 
        
           |  |  | 970 |      * @param {Object} body The body container element.
 | 
        
           |  |  | 971 |      * @param {Object} footer The footer container element.
 | 
        
           |  |  | 972 |      * @param {Bool} isLoadingFirstMessages Messages loading.
 | 
        
           |  |  | 973 |      */
 | 
        
           |  |  | 974 |     var renderLoadingFirstMessages = function(header, body, footer, isLoadingFirstMessages) {
 | 
        
           |  |  | 975 |         if (isLoadingFirstMessages) {
 | 
        
           |  |  | 976 |             hideMessagesContainer(body);
 | 
        
           |  |  | 977 |             showContentPlaceholder(body);
 | 
        
           |  |  | 978 |         } else {
 | 
        
           |  |  | 979 |             showMessagesContainer(body);
 | 
        
           |  |  | 980 |             hideContentPlaceholder(body);
 | 
        
           |  |  | 981 |         }
 | 
        
           |  |  | 982 |     };
 | 
        
           |  |  | 983 |   | 
        
           |  |  | 984 |     /**
 | 
        
           |  |  | 985 |      * Hide or show loading more messages.
 | 
        
           |  |  | 986 |      *
 | 
        
           |  |  | 987 |      * @param {Object} header The header container element.
 | 
        
           |  |  | 988 |      * @param {Object} body The body container element.
 | 
        
           |  |  | 989 |      * @param {Object} footer The footer container element.
 | 
        
           |  |  | 990 |      * @param {Bool} isLoading Messages loading.
 | 
        
           |  |  | 991 |      */
 | 
        
           |  |  | 992 |     var renderLoadingMessages = function(header, body, footer, isLoading) {
 | 
        
           |  |  | 993 |         if (isLoading) {
 | 
        
           |  |  | 994 |             showMoreMessagesLoadingIcon(body);
 | 
        
           |  |  | 995 |         } else {
 | 
        
           |  |  | 996 |             hideMoreMessagesLoadingIcon(body);
 | 
        
           |  |  | 997 |         }
 | 
        
           |  |  | 998 |     };
 | 
        
           |  |  | 999 |   | 
        
           |  |  | 1000 |     /**
 | 
        
           |  |  | 1001 |      * Hide or show the emoji picker.
 | 
        
           |  |  | 1002 |      *
 | 
        
           |  |  | 1003 |      * @param {Object} header The header container element.
 | 
        
           |  |  | 1004 |      * @param {Object} body The body container element.
 | 
        
           |  |  | 1005 |      * @param {Object} footer The footer container element.
 | 
        
           |  |  | 1006 |      * @param {Bool} show Should the emoji picker be visible.
 | 
        
           |  |  | 1007 |      */
 | 
        
           |  |  | 1008 |     var renderShowEmojiPicker = function(header, body, footer, show) {
 | 
        
           |  |  | 1009 |         var container = getEmojiPickerContainer(footer);
 | 
        
           |  |  | 1010 |   | 
        
           |  |  | 1011 |         if (show) {
 | 
        
           |  |  | 1012 |             container.removeClass('hidden');
 | 
        
           |  |  | 1013 |             Aria.unhide(container.get());
 | 
        
           |  |  | 1014 |             container.find(SELECTORS.EMOJI_PICKER_SEARCH_INPUT).focus();
 | 
        
           |  |  | 1015 |         } else {
 | 
        
           |  |  | 1016 |             container.addClass('hidden');
 | 
        
           |  |  | 1017 |             Aria.hide(container.get());
 | 
        
           |  |  | 1018 |         }
 | 
        
           |  |  | 1019 |     };
 | 
        
           |  |  | 1020 |   | 
        
           |  |  | 1021 |     /**
 | 
        
           |  |  | 1022 |      * Hide or show the emoji auto complete.
 | 
        
           |  |  | 1023 |      *
 | 
        
           |  |  | 1024 |      * @param {Object} header The header container element.
 | 
        
           |  |  | 1025 |      * @param {Object} body The body container element.
 | 
        
           |  |  | 1026 |      * @param {Object} footer The footer container element.
 | 
        
           |  |  | 1027 |      * @param {Bool} show Should the emoji picker be visible.
 | 
        
           |  |  | 1028 |      */
 | 
        
           |  |  | 1029 |     var renderShowEmojiAutoComplete = function(header, body, footer, show) {
 | 
        
           |  |  | 1030 |         var container = getEmojiAutoCompleteContainer(footer);
 | 
        
           |  |  | 1031 |   | 
        
           |  |  | 1032 |         if (show) {
 | 
        
           |  |  | 1033 |             container.removeClass('hidden');
 | 
        
           |  |  | 1034 |             Aria.unhide(container.get());
 | 
        
           |  |  | 1035 |         } else {
 | 
        
           |  |  | 1036 |             container.addClass('hidden');
 | 
        
           |  |  | 1037 |             Aria.hide(container.get());
 | 
        
           |  |  | 1038 |         }
 | 
        
           |  |  | 1039 |     };
 | 
        
           |  |  | 1040 |   | 
        
           |  |  | 1041 |     /**
 | 
        
           |  |  | 1042 |      * Show a confirmation dialogue
 | 
        
           |  |  | 1043 |      *
 | 
        
           |  |  | 1044 |      * @param {Object} header The header container element.
 | 
        
           |  |  | 1045 |      * @param {Object} body The body container element.
 | 
        
           |  |  | 1046 |      * @param {Object} footer The footer container element.
 | 
        
           |  |  | 1047 |      * @param {String} buttonSelectors Selectors for the buttons to show.
 | 
        
           |  |  | 1048 |      * @param {String} bodyText Text to show in dialogue.
 | 
        
           |  |  | 1049 |      * @param {String} headerText Text to show in dialogue header.
 | 
        
           |  |  | 1050 |      * @param {Bool} canCancel Can this dialogue be cancelled.
 | 
        
           |  |  | 1051 |      * @param {Bool} skipHeader Skip blanking out the header
 | 
        
           |  |  | 1052 |      * @param {Bool} showOk Show an 'Okay' button for a dialogue which will close it
 | 
        
           |  |  | 1053 |      */
 | 
        
           |  |  | 1054 |     var showConfirmDialogue = function(
 | 
        
           |  |  | 1055 |         header,
 | 
        
           |  |  | 1056 |         body,
 | 
        
           |  |  | 1057 |         footer,
 | 
        
           |  |  | 1058 |         buttonSelectors,
 | 
        
           |  |  | 1059 |         bodyText,
 | 
        
           |  |  | 1060 |         headerText,
 | 
        
           |  |  | 1061 |         canCancel,
 | 
        
           |  |  | 1062 |         skipHeader,
 | 
        
           |  |  | 1063 |         showOk
 | 
        
           |  |  | 1064 |     ) {
 | 
        
           |  |  | 1065 |         var dialogue = getConfirmDialogueContainer(body);
 | 
        
           |  |  | 1066 |         var buttons = buttonSelectors.map(function(selector) {
 | 
        
           |  |  | 1067 |             return dialogue.find(selector);
 | 
        
           |  |  | 1068 |         });
 | 
        
           |  |  | 1069 |         var cancelButton = dialogue.find(SELECTORS.CONFIRM_DIALOGUE_CANCEL_BUTTON);
 | 
        
           |  |  | 1070 |         var okayButton = dialogue.find(SELECTORS.CONFIRM_DIALOGUE_OKAY_BUTTON);
 | 
        
           |  |  | 1071 |         var text = dialogue.find(SELECTORS.CONFIRM_DIALOGUE_TEXT);
 | 
        
           |  |  | 1072 |         var dialogueHeader = dialogue.find(SELECTORS.CONFIRM_DIALOGUE_HEADER);
 | 
        
           |  |  | 1073 |   | 
        
           |  |  | 1074 |         dialogue.find('button').addClass('hidden');
 | 
        
           |  |  | 1075 |   | 
        
           |  |  | 1076 |         if (canCancel) {
 | 
        
           |  |  | 1077 |             cancelButton.removeClass('hidden');
 | 
        
           |  |  | 1078 |         } else {
 | 
        
           |  |  | 1079 |             cancelButton.addClass('hidden');
 | 
        
           |  |  | 1080 |         }
 | 
        
           |  |  | 1081 |   | 
        
           |  |  | 1082 |         if (showOk) {
 | 
        
           |  |  | 1083 |             okayButton.removeClass('hidden');
 | 
        
           |  |  | 1084 |         } else {
 | 
        
           |  |  | 1085 |             okayButton.addClass('hidden');
 | 
        
           |  |  | 1086 |         }
 | 
        
           |  |  | 1087 |   | 
        
           |  |  | 1088 |         if (headerText) {
 | 
        
           |  |  | 1089 |             // Create the dialogue header.
 | 
        
           |  |  | 1090 |             dialogueHeader = $('<h3 class="h6" data-region="dialogue-header"></h3>');
 | 
        
           |  |  | 1091 |             dialogueHeader.text(headerText);
 | 
        
           |  |  | 1092 |             // Prepend it to the confirmation body.
 | 
        
           |  |  | 1093 |             var confirmDialogue = dialogue.find(SELECTORS.CONFIRM_DIALOGUE);
 | 
        
           |  |  | 1094 |             confirmDialogue.prepend(dialogueHeader);
 | 
        
           |  |  | 1095 |         } else if (dialogueHeader.length) {
 | 
        
           |  |  | 1096 |             // Header text is empty but dialogue header is present, so remove it.
 | 
        
           |  |  | 1097 |             dialogueHeader.remove();
 | 
        
           |  |  | 1098 |         }
 | 
        
           |  |  | 1099 |   | 
        
           |  |  | 1100 |         buttons.forEach(function(button) {
 | 
        
           |  |  | 1101 |             button.removeClass('hidden');
 | 
        
           |  |  | 1102 |         });
 | 
        
           |  |  | 1103 |         text.text(bodyText);
 | 
        
           |  |  | 1104 |         showConfirmDialogueContainer(footer);
 | 
        
           |  |  | 1105 |         showConfirmDialogueContainer(body);
 | 
        
           |  |  | 1106 |   | 
        
           |  |  | 1107 |         if (!skipHeader) {
 | 
        
           |  |  | 1108 |             showConfirmDialogueContainer(header);
 | 
        
           |  |  | 1109 |         }
 | 
        
           |  |  | 1110 |   | 
        
           |  |  | 1111 |         dialogue.find(SELECTORS.CAN_RECEIVE_FOCUS).filter(':visible').first().focus();
 | 
        
           |  |  | 1112 |     };
 | 
        
           |  |  | 1113 |   | 
        
           |  |  | 1114 |     /**
 | 
        
           |  |  | 1115 |      * Hide the dialogue
 | 
        
           |  |  | 1116 |      *
 | 
        
           |  |  | 1117 |      * @param {Object} header The header container element.
 | 
        
           |  |  | 1118 |      * @param {Object} body The body container element.
 | 
        
           |  |  | 1119 |      * @param {Object} footer The footer container element.
 | 
        
           |  |  | 1120 |      * @return {Bool} always true.
 | 
        
           |  |  | 1121 |      */
 | 
        
           |  |  | 1122 |     var hideConfirmDialogue = function(header, body, footer) {
 | 
        
           |  |  | 1123 |         var dialogue = getConfirmDialogueContainer(body);
 | 
        
           |  |  | 1124 |         var cancelButton = dialogue.find(SELECTORS.CONFIRM_DIALOGUE_CANCEL_BUTTON);
 | 
        
           |  |  | 1125 |         var okayButton = dialogue.find(SELECTORS.CONFIRM_DIALOGUE_OKAY_BUTTON);
 | 
        
           |  |  | 1126 |         var text = dialogue.find(SELECTORS.CONFIRM_DIALOGUE_TEXT);
 | 
        
           |  |  | 1127 |         var dialogueHeader = dialogue.find(SELECTORS.CONFIRM_DIALOGUE_HEADER);
 | 
        
           |  |  | 1128 |   | 
        
           |  |  | 1129 |         hideCheckDeleteDialogue(body);
 | 
        
           |  |  | 1130 |         hideConfirmDialogueContainer(body);
 | 
        
           |  |  | 1131 |         hideConfirmDialogueContainer(footer);
 | 
        
           |  |  | 1132 |         hideConfirmDialogueContainer(header);
 | 
        
           |  |  | 1133 |         dialogue.find('button').addClass('hidden');
 | 
        
           |  |  | 1134 |         cancelButton.removeClass('hidden');
 | 
        
           |  |  | 1135 |         okayButton.removeClass('hidden');
 | 
        
           |  |  | 1136 |         text.text('');
 | 
        
           |  |  | 1137 |   | 
        
           |  |  | 1138 |         // Remove dialogue header if present.
 | 
        
           |  |  | 1139 |         if (dialogueHeader.length) {
 | 
        
           |  |  | 1140 |             dialogueHeader.remove();
 | 
        
           |  |  | 1141 |         }
 | 
        
           |  |  | 1142 |   | 
        
           |  |  | 1143 |         header.find(SELECTORS.CAN_RECEIVE_FOCUS).first().focus();
 | 
        
           |  |  | 1144 |         return true;
 | 
        
           |  |  | 1145 |     };
 | 
        
           |  |  | 1146 |   | 
        
           |  |  | 1147 |     /**
 | 
        
           |  |  | 1148 |      * Render the confirm block user dialogue.
 | 
        
           |  |  | 1149 |      *
 | 
        
           |  |  | 1150 |      * @param {Object} header The header container element.
 | 
        
           |  |  | 1151 |      * @param {Object} body The body container element.
 | 
        
           |  |  | 1152 |      * @param {Object} footer The footer container element.
 | 
        
           |  |  | 1153 |      * @param {Object} user User to block.
 | 
        
           |  |  | 1154 |      * @return {Object} jQuery promise
 | 
        
           |  |  | 1155 |      */
 | 
        
           |  |  | 1156 |     var renderConfirmBlockUser = function(header, body, footer, user) {
 | 
        
           |  |  | 1157 |         if (user) {
 | 
        
           | 1441 | ariadna | 1158 |             const username = truncateUsername(user.fullname);
 | 
        
           | 1 | efrain | 1159 |             if (user.canmessageevenifblocked) {
 | 
        
           | 1441 | ariadna | 1160 |                 return Str.get_string('cantblockuser', 'core_message', username)
 | 
        
           | 1 | efrain | 1161 |                     .then(function(string) {
 | 
        
           |  |  | 1162 |                         return showConfirmDialogue(header, body, footer, [], string, '', false, false, true);
 | 
        
           |  |  | 1163 |                     });
 | 
        
           |  |  | 1164 |             } else {
 | 
        
           | 1441 | ariadna | 1165 |                 return Str.get_string('blockuserconfirm', 'core_message', username)
 | 
        
           | 1 | efrain | 1166 |                     .then(function(string) {
 | 
        
           |  |  | 1167 |                         return showConfirmDialogue(header, body, footer, [SELECTORS.ACTION_CONFIRM_BLOCK], string, '', true, false);
 | 
        
           |  |  | 1168 |                     });
 | 
        
           |  |  | 1169 |             }
 | 
        
           |  |  | 1170 |         } else {
 | 
        
           |  |  | 1171 |             return hideConfirmDialogue(header, body, footer);
 | 
        
           |  |  | 1172 |         }
 | 
        
           |  |  | 1173 |     };
 | 
        
           |  |  | 1174 |   | 
        
           |  |  | 1175 |     /**
 | 
        
           |  |  | 1176 |      * Render the confirm unblock user dialogue.
 | 
        
           |  |  | 1177 |      *
 | 
        
           |  |  | 1178 |      * @param {Object} header The header container element.
 | 
        
           |  |  | 1179 |      * @param {Object} body The body container element.
 | 
        
           |  |  | 1180 |      * @param {Object} footer The footer container element.
 | 
        
           |  |  | 1181 |      * @param {Object} user User to unblock.
 | 
        
           |  |  | 1182 |      * @return {Object} jQuery promise
 | 
        
           |  |  | 1183 |      */
 | 
        
           |  |  | 1184 |     var renderConfirmUnblockUser = function(header, body, footer, user) {
 | 
        
           |  |  | 1185 |         if (user) {
 | 
        
           | 1441 | ariadna | 1186 |             return Str.get_string('unblockuserconfirm', 'core_message', truncateUsername(user.fullname))
 | 
        
           | 1 | efrain | 1187 |                 .then(function(string) {
 | 
        
           |  |  | 1188 |                     return showConfirmDialogue(header, body, footer, [SELECTORS.ACTION_CONFIRM_UNBLOCK], string, '', true, false);
 | 
        
           |  |  | 1189 |                 });
 | 
        
           |  |  | 1190 |         } else {
 | 
        
           |  |  | 1191 |             return hideConfirmDialogue(header, body, footer);
 | 
        
           |  |  | 1192 |         }
 | 
        
           |  |  | 1193 |     };
 | 
        
           |  |  | 1194 |   | 
        
           |  |  | 1195 |     /**
 | 
        
           |  |  | 1196 |      * Render the add user as contact dialogue.
 | 
        
           |  |  | 1197 |      *
 | 
        
           |  |  | 1198 |      * @param {Object} header The header container element.
 | 
        
           |  |  | 1199 |      * @param {Object} body The body container element.
 | 
        
           |  |  | 1200 |      * @param {Object} footer The footer container element.
 | 
        
           |  |  | 1201 |      * @param {Object} user User to add as contact.
 | 
        
           |  |  | 1202 |      * @return {Object} jQuery promise
 | 
        
           |  |  | 1203 |      */
 | 
        
           |  |  | 1204 |     var renderConfirmAddContact = function(header, body, footer, user) {
 | 
        
           |  |  | 1205 |         if (user) {
 | 
        
           | 1441 | ariadna | 1206 |             // Truncate long usernames.
 | 
        
           |  |  | 1207 |             const userFullName = Truncate.truncate(user.fullname, {
 | 
        
           |  |  | 1208 |                 length: 30,
 | 
        
           |  |  | 1209 |                 words: true,
 | 
        
           |  |  | 1210 |                 ellipsis: '...'
 | 
        
           |  |  | 1211 |             });
 | 
        
           |  |  | 1212 |             return Str.get_string('addcontactconfirm', 'core_message', userFullName)
 | 
        
           | 1 | efrain | 1213 |                 .then(function(string) {
 | 
        
           |  |  | 1214 |                     return showConfirmDialogue(
 | 
        
           |  |  | 1215 |                         header,
 | 
        
           |  |  | 1216 |                         body,
 | 
        
           |  |  | 1217 |                         footer,
 | 
        
           |  |  | 1218 |                         [SELECTORS.ACTION_CONFIRM_ADD_CONTACT],
 | 
        
           |  |  | 1219 |                         string,
 | 
        
           |  |  | 1220 |                         '',
 | 
        
           |  |  | 1221 |                         true,
 | 
        
           |  |  | 1222 |                         false
 | 
        
           |  |  | 1223 |                     );
 | 
        
           |  |  | 1224 |                 });
 | 
        
           |  |  | 1225 |         } else {
 | 
        
           |  |  | 1226 |             return hideConfirmDialogue(header, body, footer);
 | 
        
           |  |  | 1227 |         }
 | 
        
           |  |  | 1228 |     };
 | 
        
           |  |  | 1229 |   | 
        
           |  |  | 1230 |     /**
 | 
        
           |  |  | 1231 |      * Render the remove user from contacts dialogue.
 | 
        
           |  |  | 1232 |      *
 | 
        
           |  |  | 1233 |      * @param {Object} header The header container element.
 | 
        
           |  |  | 1234 |      * @param {Object} body The body container element.
 | 
        
           |  |  | 1235 |      * @param {Object} footer The footer container element.
 | 
        
           |  |  | 1236 |      * @param {Object} user User to remove from contacts.
 | 
        
           |  |  | 1237 |      * @return {Object} jQuery promise
 | 
        
           |  |  | 1238 |      */
 | 
        
           |  |  | 1239 |     var renderConfirmRemoveContact = function(header, body, footer, user) {
 | 
        
           |  |  | 1240 |         if (user) {
 | 
        
           | 1441 | ariadna | 1241 |             return Str.get_string('removecontactconfirm', 'core_message', truncateUsername(user.fullname))
 | 
        
           | 1 | efrain | 1242 |                 .then(function(string) {
 | 
        
           |  |  | 1243 |                     return showConfirmDialogue(
 | 
        
           |  |  | 1244 |                         header,
 | 
        
           |  |  | 1245 |                         body,
 | 
        
           |  |  | 1246 |                         footer,
 | 
        
           |  |  | 1247 |                         [SELECTORS.ACTION_CONFIRM_REMOVE_CONTACT],
 | 
        
           |  |  | 1248 |                         string,
 | 
        
           |  |  | 1249 |                         '',
 | 
        
           |  |  | 1250 |                         true,
 | 
        
           |  |  | 1251 |                         false
 | 
        
           |  |  | 1252 |                     );
 | 
        
           |  |  | 1253 |                 });
 | 
        
           |  |  | 1254 |         } else {
 | 
        
           |  |  | 1255 |             return hideConfirmDialogue(header, body, footer);
 | 
        
           |  |  | 1256 |         }
 | 
        
           |  |  | 1257 |     };
 | 
        
           |  |  | 1258 |   | 
        
           |  |  | 1259 |     /**
 | 
        
           |  |  | 1260 |      * Render the delete selected messages dialogue.
 | 
        
           |  |  | 1261 |      *
 | 
        
           |  |  | 1262 |      * @param {Object} header The header container element.
 | 
        
           |  |  | 1263 |      * @param {Object} body The body container element.
 | 
        
           |  |  | 1264 |      * @param {Object} footer The footer container element.
 | 
        
           |  |  | 1265 |      * @param {Object} data If the dialogue should show and checkbox shows to delete message for all users.
 | 
        
           |  |  | 1266 |      * @return {Object} jQuery promise
 | 
        
           |  |  | 1267 |      */
 | 
        
           |  |  | 1268 |     var renderConfirmDeleteSelectedMessages = function(header, body, footer, data) {
 | 
        
           |  |  | 1269 |         var showmessage = null;
 | 
        
           |  |  | 1270 |         if (data.type == CONVERSATION_TYPES.SELF) {
 | 
        
           |  |  | 1271 |             // Message displayed to self-conversations is slighly different.
 | 
        
           |  |  | 1272 |             showmessage = 'deleteselectedmessagesconfirmselfconversation';
 | 
        
           |  |  | 1273 |         } else {
 | 
        
           |  |  | 1274 |             // This other message should be displayed.
 | 
        
           |  |  | 1275 |             if (data.canDeleteMessagesForAllUsers) {
 | 
        
           |  |  | 1276 |                 showCheckDeleteDialogue(body);
 | 
        
           |  |  | 1277 |                 showmessage = 'deleteforeveryoneselectedmessagesconfirm';
 | 
        
           |  |  | 1278 |             } else {
 | 
        
           |  |  | 1279 |                 showmessage = 'deleteselectedmessagesconfirm';
 | 
        
           |  |  | 1280 |             }
 | 
        
           |  |  | 1281 |         }
 | 
        
           |  |  | 1282 |   | 
        
           |  |  | 1283 |         if (data.show) {
 | 
        
           |  |  | 1284 |             return Str.get_string(showmessage, 'core_message')
 | 
        
           |  |  | 1285 |                 .then(function(string) {
 | 
        
           |  |  | 1286 |                     return showConfirmDialogue(
 | 
        
           |  |  | 1287 |                         header,
 | 
        
           |  |  | 1288 |                         body,
 | 
        
           |  |  | 1289 |                         footer,
 | 
        
           |  |  | 1290 |                         [SELECTORS.ACTION_CONFIRM_DELETE_SELECTED_MESSAGES],
 | 
        
           |  |  | 1291 |                         string,
 | 
        
           |  |  | 1292 |                         '',
 | 
        
           |  |  | 1293 |                         true,
 | 
        
           |  |  | 1294 |                         false
 | 
        
           |  |  | 1295 |                     );
 | 
        
           |  |  | 1296 |                 });
 | 
        
           |  |  | 1297 |         } else {
 | 
        
           |  |  | 1298 |             return hideConfirmDialogue(header, body, footer);
 | 
        
           |  |  | 1299 |         }
 | 
        
           |  |  | 1300 |     };
 | 
        
           |  |  | 1301 |   | 
        
           |  |  | 1302 |     /**
 | 
        
           |  |  | 1303 |      * Render the confirm delete conversation dialogue.
 | 
        
           |  |  | 1304 |      *
 | 
        
           |  |  | 1305 |      * @param {Object} header The header container element.
 | 
        
           |  |  | 1306 |      * @param {Object} body The body container element.
 | 
        
           |  |  | 1307 |      * @param {Object} footer The footer container element.
 | 
        
           |  |  | 1308 |      * @param {int|Null} type The conversation type to be removed.
 | 
        
           |  |  | 1309 |      * @return {Object} jQuery promise
 | 
        
           |  |  | 1310 |      */
 | 
        
           |  |  | 1311 |     var renderConfirmDeleteConversation = function(header, body, footer, type) {
 | 
        
           |  |  | 1312 |         var showmessage = null;
 | 
        
           |  |  | 1313 |         if (type == CONVERSATION_TYPES.SELF) {
 | 
        
           |  |  | 1314 |             // Message displayed to self-conversations is slighly different.
 | 
        
           |  |  | 1315 |             showmessage = 'deleteallselfconfirm';
 | 
        
           |  |  | 1316 |         } else if (type) {
 | 
        
           |  |  | 1317 |             // This other message should be displayed.
 | 
        
           |  |  | 1318 |             showmessage = 'deleteallconfirm';
 | 
        
           |  |  | 1319 |         }
 | 
        
           |  |  | 1320 |   | 
        
           |  |  | 1321 |         if (showmessage) {
 | 
        
           |  |  | 1322 |             return Str.get_string(showmessage, 'core_message')
 | 
        
           |  |  | 1323 |                 .then(function(string) {
 | 
        
           |  |  | 1324 |                     return showConfirmDialogue(
 | 
        
           |  |  | 1325 |                         header,
 | 
        
           |  |  | 1326 |                         body,
 | 
        
           |  |  | 1327 |                         footer,
 | 
        
           |  |  | 1328 |                         [SELECTORS.ACTION_CONFIRM_DELETE_CONVERSATION],
 | 
        
           |  |  | 1329 |                         string,
 | 
        
           |  |  | 1330 |                         '',
 | 
        
           |  |  | 1331 |                         true,
 | 
        
           |  |  | 1332 |                         false
 | 
        
           |  |  | 1333 |                     );
 | 
        
           |  |  | 1334 |                 });
 | 
        
           |  |  | 1335 |         } else {
 | 
        
           |  |  | 1336 |             return hideConfirmDialogue(header, body, footer);
 | 
        
           |  |  | 1337 |         }
 | 
        
           |  |  | 1338 |     };
 | 
        
           |  |  | 1339 |   | 
        
           |  |  | 1340 |     /**
 | 
        
           |  |  | 1341 |      * Render the confirm delete conversation dialogue.
 | 
        
           |  |  | 1342 |      *
 | 
        
           |  |  | 1343 |      * @param {Object} header The header container element.
 | 
        
           |  |  | 1344 |      * @param {Object} body The body container element.
 | 
        
           |  |  | 1345 |      * @param {Object} footer The footer container element.
 | 
        
           | 1441 | ariadna | 1346 |      * @param {Object} user The other user object.
 | 
        
           | 1 | efrain | 1347 |      * @return {Object} jQuery promise
 | 
        
           |  |  | 1348 |      */
 | 
        
           |  |  | 1349 |     var renderConfirmContactRequest = function(header, body, footer, user) {
 | 
        
           |  |  | 1350 |         if (user) {
 | 
        
           | 1441 | ariadna | 1351 |             return Str.get_string('userwouldliketocontactyou', 'core_message', truncateUsername(user.fullname))
 | 
        
           | 1 | efrain | 1352 |                 .then(function(string) {
 | 
        
           |  |  | 1353 |                     var buttonSelectors = [
 | 
        
           |  |  | 1354 |                         SELECTORS.ACTION_ACCEPT_CONTACT_REQUEST,
 | 
        
           |  |  | 1355 |                         SELECTORS.ACTION_DECLINE_CONTACT_REQUEST
 | 
        
           |  |  | 1356 |                     ];
 | 
        
           |  |  | 1357 |                     return showConfirmDialogue(header, body, footer, buttonSelectors, string, '', false, true);
 | 
        
           |  |  | 1358 |                 });
 | 
        
           |  |  | 1359 |         } else {
 | 
        
           |  |  | 1360 |             return hideConfirmDialogue(header, body, footer);
 | 
        
           |  |  | 1361 |         }
 | 
        
           |  |  | 1362 |     };
 | 
        
           |  |  | 1363 |   | 
        
           |  |  | 1364 |     /**
 | 
        
           |  |  | 1365 |      * Show the checkbox to allow delete message for all.
 | 
        
           |  |  | 1366 |      *
 | 
        
           |  |  | 1367 |      * @param {Object} body The body container element.
 | 
        
           |  |  | 1368 |      */
 | 
        
           |  |  | 1369 |     var showCheckDeleteDialogue = function(body) {
 | 
        
           |  |  | 1370 |         var dialogue = getConfirmDialogueContainer(body);
 | 
        
           |  |  | 1371 |         var checkboxRegion = dialogue.find(SELECTORS.DELETE_MESSAGES_FOR_ALL_USERS_TOGGLE_CONTAINER);
 | 
        
           |  |  | 1372 |         checkboxRegion.removeClass('hidden');
 | 
        
           |  |  | 1373 |     };
 | 
        
           |  |  | 1374 |   | 
        
           |  |  | 1375 |     /**
 | 
        
           |  |  | 1376 |      * Hide the checkbox to allow delete message for all.
 | 
        
           |  |  | 1377 |      *
 | 
        
           |  |  | 1378 |      * @param {Object} body The body container element.
 | 
        
           |  |  | 1379 |      */
 | 
        
           |  |  | 1380 |     var hideCheckDeleteDialogue = function(body) {
 | 
        
           |  |  | 1381 |         var dialogue = getConfirmDialogueContainer(body);
 | 
        
           |  |  | 1382 |         var checkboxRegion = dialogue.find(SELECTORS.DELETE_MESSAGES_FOR_ALL_USERS_TOGGLE_CONTAINER);
 | 
        
           |  |  | 1383 |         var checkbox = dialogue.find(SELECTORS.DELETE_MESSAGES_FOR_ALL_USERS_TOGGLE);
 | 
        
           |  |  | 1384 |         checkbox.prop('checked', false);
 | 
        
           |  |  | 1385 |         checkboxRegion.addClass('hidden');
 | 
        
           |  |  | 1386 |     };
 | 
        
           |  |  | 1387 |   | 
        
           |  |  | 1388 |     /**
 | 
        
           |  |  | 1389 |      * Show or hide the block / unblock option in the header dropdown menu.
 | 
        
           |  |  | 1390 |      *
 | 
        
           |  |  | 1391 |      * @param {Object} header The header container element.
 | 
        
           |  |  | 1392 |      * @param {Object} body The body container element.
 | 
        
           |  |  | 1393 |      * @param {Object} footer The footer container element.
 | 
        
           |  |  | 1394 |      * @param {Bool} isBlocked is user blocked.
 | 
        
           |  |  | 1395 |      */
 | 
        
           |  |  | 1396 |     var renderIsBlocked = function(header, body, footer, isBlocked) {
 | 
        
           |  |  | 1397 |         if (isBlocked) {
 | 
        
           |  |  | 1398 |             header.find(SELECTORS.ACTION_REQUEST_BLOCK).addClass('hidden');
 | 
        
           |  |  | 1399 |             header.find(SELECTORS.ACTION_REQUEST_UNBLOCK).removeClass('hidden');
 | 
        
           |  |  | 1400 |         } else {
 | 
        
           |  |  | 1401 |             header.find(SELECTORS.ACTION_REQUEST_BLOCK).removeClass('hidden');
 | 
        
           |  |  | 1402 |             header.find(SELECTORS.ACTION_REQUEST_UNBLOCK).addClass('hidden');
 | 
        
           |  |  | 1403 |         }
 | 
        
           |  |  | 1404 |     };
 | 
        
           |  |  | 1405 |   | 
        
           |  |  | 1406 |     /**
 | 
        
           |  |  | 1407 |      * Show or hide the favourite / unfavourite option in the header dropdown menu
 | 
        
           |  |  | 1408 |      * and the favourite star in the header title.
 | 
        
           |  |  | 1409 |      *
 | 
        
           |  |  | 1410 |      * @param {Object} header The header container element.
 | 
        
           |  |  | 1411 |      * @param {Object} body The body container element.
 | 
        
           |  |  | 1412 |      * @param {Object} footer The footer container element.
 | 
        
           |  |  | 1413 |      * @param {Bool} state is this conversation a favourite.
 | 
        
           |  |  | 1414 |      */
 | 
        
           |  |  | 1415 |     var renderIsFavourite = function(header, body, footer, state) {
 | 
        
           |  |  | 1416 |         var favouriteIcon = header.find(SELECTORS.FAVOURITE_ICON_CONTAINER);
 | 
        
           |  |  | 1417 |         var addFavourite = header.find(SELECTORS.ACTION_CONFIRM_FAVOURITE);
 | 
        
           |  |  | 1418 |         var removeFavourite = header.find(SELECTORS.ACTION_CONFIRM_UNFAVOURITE);
 | 
        
           |  |  | 1419 |   | 
        
           |  |  | 1420 |         switch (state) {
 | 
        
           |  |  | 1421 |             case 'hide':
 | 
        
           |  |  | 1422 |                 favouriteIcon.addClass('hidden');
 | 
        
           |  |  | 1423 |                 addFavourite.addClass('hidden');
 | 
        
           |  |  | 1424 |                 removeFavourite.addClass('hidden');
 | 
        
           |  |  | 1425 |                 break;
 | 
        
           |  |  | 1426 |             case 'show-add':
 | 
        
           |  |  | 1427 |                 favouriteIcon.addClass('hidden');
 | 
        
           |  |  | 1428 |                 addFavourite.removeClass('hidden');
 | 
        
           |  |  | 1429 |                 removeFavourite.addClass('hidden');
 | 
        
           |  |  | 1430 |                 break;
 | 
        
           |  |  | 1431 |             case 'show-remove':
 | 
        
           |  |  | 1432 |                 favouriteIcon.removeClass('hidden');
 | 
        
           |  |  | 1433 |                 addFavourite.addClass('hidden');
 | 
        
           |  |  | 1434 |                 removeFavourite.removeClass('hidden');
 | 
        
           |  |  | 1435 |                 break;
 | 
        
           |  |  | 1436 |         }
 | 
        
           |  |  | 1437 |     };
 | 
        
           |  |  | 1438 |   | 
        
           |  |  | 1439 |     /**
 | 
        
           |  |  | 1440 |      * Show or hide the mute / unmute option in the header dropdown menu
 | 
        
           |  |  | 1441 |      * and the muted icon in the header title.
 | 
        
           |  |  | 1442 |      *
 | 
        
           |  |  | 1443 |      * @param {Object} header The header container element.
 | 
        
           |  |  | 1444 |      * @param {Object} body The body container element.
 | 
        
           |  |  | 1445 |      * @param {Object} footer The footer container element.
 | 
        
           |  |  | 1446 |      * @param {string} state The state of the conversation as defined by the patcher.
 | 
        
           |  |  | 1447 |      */
 | 
        
           |  |  | 1448 |     var renderIsMuted = function(header, body, footer, state) {
 | 
        
           |  |  | 1449 |         var muteIcon = header.find(SELECTORS.MUTED_ICON_CONTAINER);
 | 
        
           |  |  | 1450 |         var setMuted = header.find(SELECTORS.ACTION_CONFIRM_MUTE);
 | 
        
           |  |  | 1451 |         var unsetMuted = header.find(SELECTORS.ACTION_CONFIRM_UNMUTE);
 | 
        
           |  |  | 1452 |   | 
        
           |  |  | 1453 |         switch (state) {
 | 
        
           |  |  | 1454 |             case 'hide':
 | 
        
           |  |  | 1455 |                 muteIcon.addClass('hidden');
 | 
        
           |  |  | 1456 |                 setMuted.addClass('hidden');
 | 
        
           |  |  | 1457 |                 unsetMuted.addClass('hidden');
 | 
        
           |  |  | 1458 |                 break;
 | 
        
           |  |  | 1459 |             case 'show-mute':
 | 
        
           |  |  | 1460 |                 muteIcon.addClass('hidden');
 | 
        
           |  |  | 1461 |                 setMuted.removeClass('hidden');
 | 
        
           |  |  | 1462 |                 unsetMuted.addClass('hidden');
 | 
        
           |  |  | 1463 |                 break;
 | 
        
           |  |  | 1464 |             case 'show-unmute':
 | 
        
           |  |  | 1465 |                 muteIcon.removeClass('hidden');
 | 
        
           |  |  | 1466 |                 setMuted.addClass('hidden');
 | 
        
           |  |  | 1467 |                 unsetMuted.removeClass('hidden');
 | 
        
           |  |  | 1468 |                 break;
 | 
        
           |  |  | 1469 |         }
 | 
        
           |  |  | 1470 |     };
 | 
        
           |  |  | 1471 |   | 
        
           |  |  | 1472 |     /**
 | 
        
           |  |  | 1473 |      * Show or hide the add / remove user as contact option in the header dropdown menu.
 | 
        
           |  |  | 1474 |      *
 | 
        
           |  |  | 1475 |      * @param {Object} header The header container element.
 | 
        
           |  |  | 1476 |      * @param {Object} body The body container element.
 | 
        
           |  |  | 1477 |      * @param {Object} footer The footer container element.
 | 
        
           |  |  | 1478 |      * @param {Bool} state the contact state.
 | 
        
           |  |  | 1479 |      */
 | 
        
           |  |  | 1480 |     var renderIsContact = function(header, body, footer, state) {
 | 
        
           |  |  | 1481 |         var addContact = header.find(SELECTORS.ACTION_REQUEST_ADD_CONTACT);
 | 
        
           |  |  | 1482 |         var removeContact = header.find(SELECTORS.ACTION_REQUEST_REMOVE_CONTACT);
 | 
        
           |  |  | 1483 |   | 
        
           |  |  | 1484 |         switch (state) {
 | 
        
           |  |  | 1485 |             case 'pending-contact':
 | 
        
           |  |  | 1486 |                 addContact.addClass('hidden');
 | 
        
           |  |  | 1487 |                 removeContact.addClass('hidden');
 | 
        
           |  |  | 1488 |                 break;
 | 
        
           |  |  | 1489 |             case 'contact':
 | 
        
           |  |  | 1490 |                 addContact.addClass('hidden');
 | 
        
           |  |  | 1491 |                 removeContact.removeClass('hidden');
 | 
        
           |  |  | 1492 |                 break;
 | 
        
           |  |  | 1493 |             case 'non-contact':
 | 
        
           |  |  | 1494 |                 addContact.removeClass('hidden');
 | 
        
           |  |  | 1495 |                 removeContact.addClass('hidden');
 | 
        
           |  |  | 1496 |                 break;
 | 
        
           |  |  | 1497 |         }
 | 
        
           |  |  | 1498 |     };
 | 
        
           |  |  | 1499 |   | 
        
           |  |  | 1500 |     /**
 | 
        
           |  |  | 1501 |      * Show or hide confirm action from confirm dialogue is loading.
 | 
        
           |  |  | 1502 |      *
 | 
        
           |  |  | 1503 |      * @param {Object} header The header container element.
 | 
        
           |  |  | 1504 |      * @param {Object} body The body container element.
 | 
        
           |  |  | 1505 |      * @param {Object} footer The footer container element.
 | 
        
           |  |  | 1506 |      * @param {Bool} isLoading confirm action is loading.
 | 
        
           |  |  | 1507 |      */
 | 
        
           |  |  | 1508 |     var renderLoadingConfirmAction = function(header, body, footer, isLoading) {
 | 
        
           |  |  | 1509 |         var dialogue = getConfirmDialogueContainer(body);
 | 
        
           |  |  | 1510 |         var buttons = dialogue.find('button');
 | 
        
           |  |  | 1511 |         var buttonText = dialogue.find(SELECTORS.CONFIRM_DIALOGUE_BUTTON_TEXT);
 | 
        
           |  |  | 1512 |         var loadingIcon = dialogue.find(SELECTORS.LOADING_ICON_CONTAINER);
 | 
        
           |  |  | 1513 |   | 
        
           |  |  | 1514 |         if (isLoading) {
 | 
        
           |  |  | 1515 |             buttons.prop('disabled', true);
 | 
        
           |  |  | 1516 |             buttonText.addClass('hidden');
 | 
        
           |  |  | 1517 |             loadingIcon.removeClass('hidden');
 | 
        
           |  |  | 1518 |         } else {
 | 
        
           |  |  | 1519 |             buttons.prop('disabled', false);
 | 
        
           |  |  | 1520 |             buttonText.removeClass('hidden');
 | 
        
           |  |  | 1521 |             loadingIcon.addClass('hidden');
 | 
        
           |  |  | 1522 |         }
 | 
        
           |  |  | 1523 |     };
 | 
        
           |  |  | 1524 |   | 
        
           |  |  | 1525 |     /**
 | 
        
           |  |  | 1526 |      * Show or hide the header and footer content for edit mode.
 | 
        
           |  |  | 1527 |      *
 | 
        
           |  |  | 1528 |      * @param {Object} header The header container element.
 | 
        
           |  |  | 1529 |      * @param {Object} body The body container element.
 | 
        
           |  |  | 1530 |      * @param {Object} footer The footer container element.
 | 
        
           |  |  | 1531 |      * @param {Bool} inEditMode In edit mode or not.
 | 
        
           |  |  | 1532 |      */
 | 
        
           |  |  | 1533 |     var renderInEditMode = function(header, body, footer, inEditMode) {
 | 
        
           |  |  | 1534 |         var messages = null;
 | 
        
           |  |  | 1535 |   | 
        
           |  |  | 1536 |         if (inEditMode) {
 | 
        
           |  |  | 1537 |             messages = body.find(SELECTORS.MESSAGE_NOT_SELECTED);
 | 
        
           |  |  | 1538 |             messages.find(SELECTORS.MESSAGE_NOT_SELECTED_ICON).removeClass('hidden');
 | 
        
           |  |  | 1539 |             hideHeaderContent(header);
 | 
        
           |  |  | 1540 |             showHeaderEditMode(header);
 | 
        
           |  |  | 1541 |         } else {
 | 
        
           |  |  | 1542 |             messages = getMessagesContainer(body);
 | 
        
           |  |  | 1543 |             messages.find(SELECTORS.MESSAGE_NOT_SELECTED_ICON).addClass('hidden');
 | 
        
           |  |  | 1544 |             messages.find(SELECTORS.MESSAGE_SELECTED_ICON).addClass('hidden');
 | 
        
           |  |  | 1545 |             showHeaderContent(header);
 | 
        
           |  |  | 1546 |             hideHeaderEditMode(header);
 | 
        
           |  |  | 1547 |         }
 | 
        
           |  |  | 1548 |     };
 | 
        
           |  |  | 1549 |   | 
        
           |  |  | 1550 |     /**
 | 
        
           |  |  | 1551 |      * Select or unselect messages.
 | 
        
           |  |  | 1552 |      *
 | 
        
           |  |  | 1553 |      * @param {Object} header The header container element.
 | 
        
           |  |  | 1554 |      * @param {Object} body The body container element.
 | 
        
           |  |  | 1555 |      * @param {Object} footer The footer container element.
 | 
        
           |  |  | 1556 |      * @param {Object} data The messages to select or unselect.
 | 
        
           |  |  | 1557 |      */
 | 
        
           |  |  | 1558 |     var renderSelectedMessages = function(header, body, footer, data) {
 | 
        
           |  |  | 1559 |         var hasSelectedMessages = data.count > 0;
 | 
        
           |  |  | 1560 |   | 
        
           |  |  | 1561 |         if (data.add.length) {
 | 
        
           |  |  | 1562 |             data.add.forEach(function(messageId) {
 | 
        
           |  |  | 1563 |                 var message = getMessageElement(body, messageId);
 | 
        
           |  |  | 1564 |                 message.find(SELECTORS.MESSAGE_NOT_SELECTED_ICON).addClass('hidden');
 | 
        
           |  |  | 1565 |                 message.find(SELECTORS.MESSAGE_SELECTED_ICON).removeClass('hidden');
 | 
        
           |  |  | 1566 |                 message.attr('aria-checked', true);
 | 
        
           |  |  | 1567 |             });
 | 
        
           |  |  | 1568 |         }
 | 
        
           |  |  | 1569 |   | 
        
           |  |  | 1570 |         if (data.remove.length) {
 | 
        
           |  |  | 1571 |             data.remove.forEach(function(messageId) {
 | 
        
           |  |  | 1572 |                 var message = getMessageElement(body, messageId);
 | 
        
           |  |  | 1573 |   | 
        
           |  |  | 1574 |                 if (hasSelectedMessages) {
 | 
        
           |  |  | 1575 |                     message.find(SELECTORS.MESSAGE_NOT_SELECTED_ICON).removeClass('hidden');
 | 
        
           |  |  | 1576 |                 }
 | 
        
           |  |  | 1577 |   | 
        
           |  |  | 1578 |                 message.find(SELECTORS.MESSAGE_SELECTED_ICON).addClass('hidden');
 | 
        
           |  |  | 1579 |                 message.attr('aria-checked', false);
 | 
        
           |  |  | 1580 |             });
 | 
        
           |  |  | 1581 |         }
 | 
        
           |  |  | 1582 |   | 
        
           |  |  | 1583 |         setMessagesSelectedCount(header, data.count);
 | 
        
           |  |  | 1584 |     };
 | 
        
           |  |  | 1585 |   | 
        
           |  |  | 1586 |     /**
 | 
        
           |  |  | 1587 |      * Show or hide the require add contact panel.
 | 
        
           |  |  | 1588 |      *
 | 
        
           |  |  | 1589 |      * @param {Object} header The header container element.
 | 
        
           |  |  | 1590 |      * @param {Object} body The body container element.
 | 
        
           |  |  | 1591 |      * @param {Object} footer The footer container element.
 | 
        
           |  |  | 1592 |      * @param {Object} data Whether the user has to be added a a contact.
 | 
        
           |  |  | 1593 |      * @return {Object} jQuery promise
 | 
        
           |  |  | 1594 |      */
 | 
        
           |  |  | 1595 |     var renderRequireAddContact = function(header, body, footer, data) {
 | 
        
           |  |  | 1596 |         if (data.show && !data.hasMessages) {
 | 
        
           |  |  | 1597 |             return Str.get_strings([
 | 
        
           |  |  | 1598 |                     {
 | 
        
           |  |  | 1599 |                         key: 'requirecontacttomessage',
 | 
        
           |  |  | 1600 |                         component: 'core_message',
 | 
        
           |  |  | 1601 |                         param: data.user.fullname
 | 
        
           |  |  | 1602 |                     },
 | 
        
           |  |  | 1603 |                     {
 | 
        
           |  |  | 1604 |                         key: 'isnotinyourcontacts',
 | 
        
           |  |  | 1605 |                         component: 'core_message',
 | 
        
           |  |  | 1606 |                         param: data.user.fullname
 | 
        
           |  |  | 1607 |                     }
 | 
        
           |  |  | 1608 |                 ])
 | 
        
           |  |  | 1609 |                 .then(function(strings) {
 | 
        
           |  |  | 1610 |                     var title = strings[1];
 | 
        
           |  |  | 1611 |                     var text = strings[0];
 | 
        
           |  |  | 1612 |                     return showConfirmDialogue(
 | 
        
           |  |  | 1613 |                         header,
 | 
        
           |  |  | 1614 |                         body,
 | 
        
           |  |  | 1615 |                         footer,
 | 
        
           |  |  | 1616 |                         [SELECTORS.ACTION_REQUEST_ADD_CONTACT],
 | 
        
           |  |  | 1617 |                         text,
 | 
        
           |  |  | 1618 |                         title,
 | 
        
           |  |  | 1619 |                         false,
 | 
        
           |  |  | 1620 |                         true
 | 
        
           |  |  | 1621 |                     );
 | 
        
           |  |  | 1622 |                 });
 | 
        
           |  |  | 1623 |         } else {
 | 
        
           |  |  | 1624 |             return hideConfirmDialogue(header, body, footer);
 | 
        
           |  |  | 1625 |         }
 | 
        
           |  |  | 1626 |     };
 | 
        
           |  |  | 1627 |   | 
        
           |  |  | 1628 |     /**
 | 
        
           |  |  | 1629 |      * Show or hide the self-conversation message.
 | 
        
           |  |  | 1630 |      *
 | 
        
           |  |  | 1631 |      * @param {Object} header The header container element.
 | 
        
           |  |  | 1632 |      * @param {Object} body The body container element.
 | 
        
           |  |  | 1633 |      * @param {Object} footer The footer container element.
 | 
        
           |  |  | 1634 |      * @param {Object} displayMessage should the message be displayed?.
 | 
        
           |  |  | 1635 |      * @return {Object|true} jQuery promise
 | 
        
           |  |  | 1636 |      */
 | 
        
           |  |  | 1637 |     var renderSelfConversationMessage = function(header, body, footer, displayMessage) {
 | 
        
           |  |  | 1638 |         var container = getSelfConversationMessageContainer(body);
 | 
        
           |  |  | 1639 |         if (displayMessage) {
 | 
        
           |  |  | 1640 |             container.removeClass('hidden');
 | 
        
           |  |  | 1641 |         } else {
 | 
        
           |  |  | 1642 |             container.addClass('hidden');
 | 
        
           |  |  | 1643 |         }
 | 
        
           |  |  | 1644 |         return true;
 | 
        
           |  |  | 1645 |     };
 | 
        
           |  |  | 1646 |   | 
        
           |  |  | 1647 |     /**
 | 
        
           |  |  | 1648 |      * Show or hide the require add contact panel.
 | 
        
           |  |  | 1649 |      *
 | 
        
           |  |  | 1650 |      * @param {Object} header The header container element.
 | 
        
           |  |  | 1651 |      * @param {Object} body The body container element.
 | 
        
           |  |  | 1652 |      * @param {Object} footer The footer container element.
 | 
        
           | 1441 | ariadna | 1653 |      * @param {String} userFullName Full name of the other user.
 | 
        
           | 1 | efrain | 1654 |      * @return {Object|true} jQuery promise
 | 
        
           |  |  | 1655 |      */
 | 
        
           |  |  | 1656 |     var renderContactRequestSent = function(header, body, footer, userFullName) {
 | 
        
           |  |  | 1657 |         var container = getContactRequestSentContainer(body);
 | 
        
           |  |  | 1658 |         if (userFullName) {
 | 
        
           | 1441 | ariadna | 1659 |             return Str.get_string('yourcontactrequestpending', 'core_message', truncateUsername(userFullName))
 | 
        
           | 1 | efrain | 1660 |                 .then(function(string) {
 | 
        
           |  |  | 1661 |                     container.find(SELECTORS.TEXT).text(string);
 | 
        
           |  |  | 1662 |                     container.removeClass('hidden');
 | 
        
           |  |  | 1663 |                     return string;
 | 
        
           |  |  | 1664 |                 });
 | 
        
           |  |  | 1665 |         } else {
 | 
        
           |  |  | 1666 |             container.addClass('hidden');
 | 
        
           |  |  | 1667 |             return true;
 | 
        
           |  |  | 1668 |         }
 | 
        
           |  |  | 1669 |     };
 | 
        
           |  |  | 1670 |   | 
        
           |  |  | 1671 |     /**
 | 
        
           |  |  | 1672 |      * Reset the UI to the initial state.
 | 
        
           |  |  | 1673 |      *
 | 
        
           |  |  | 1674 |      * @param {Object} header The header container element.
 | 
        
           |  |  | 1675 |      * @param {Object} body The body container element.
 | 
        
           |  |  | 1676 |      * @param {Object} footer The footer container element.
 | 
        
           |  |  | 1677 |      * @return {Bool}
 | 
        
           |  |  | 1678 |      */
 | 
        
           |  |  | 1679 |     var renderReset = function(header, body, footer) {
 | 
        
           |  |  | 1680 |         hideConfirmDialogue(header, body, footer);
 | 
        
           |  |  | 1681 |         hideContactRequestSentContainer(body);
 | 
        
           |  |  | 1682 |         hideSelfConversationMessageContainer(body);
 | 
        
           |  |  | 1683 |         hideAllHeaderElements(header);
 | 
        
           |  |  | 1684 |         showHeaderPlaceholder(header);
 | 
        
           |  |  | 1685 |         hideAllFooterElements(footer);
 | 
        
           |  |  | 1686 |         showFooterPlaceholder(footer);
 | 
        
           |  |  | 1687 |         return true;
 | 
        
           |  |  | 1688 |     };
 | 
        
           |  |  | 1689 |   | 
        
           |  |  | 1690 |     var render = function(header, body, footer, patch) {
 | 
        
           |  |  | 1691 |         var configs = [
 | 
        
           |  |  | 1692 |             {
 | 
        
           |  |  | 1693 |                 // Resetting the UI needs to come first, if it's required.
 | 
        
           |  |  | 1694 |                 reset: renderReset
 | 
        
           |  |  | 1695 |             },
 | 
        
           |  |  | 1696 |             {
 | 
        
           |  |  | 1697 |                 // Any async rendering (stuff that requires templates, strings etc) should
 | 
        
           |  |  | 1698 |                 // go in here.
 | 
        
           |  |  | 1699 |                 conversation: renderConversation,
 | 
        
           |  |  | 1700 |                 header: renderHeader,
 | 
        
           |  |  | 1701 |                 footer: renderFooter,
 | 
        
           |  |  | 1702 |                 confirmBlockUser: renderConfirmBlockUser,
 | 
        
           |  |  | 1703 |                 confirmUnblockUser: renderConfirmUnblockUser,
 | 
        
           |  |  | 1704 |                 confirmAddContact: renderConfirmAddContact,
 | 
        
           |  |  | 1705 |                 confirmRemoveContact: renderConfirmRemoveContact,
 | 
        
           |  |  | 1706 |                 confirmDeleteSelectedMessages: renderConfirmDeleteSelectedMessages,
 | 
        
           |  |  | 1707 |                 confirmDeleteConversation: renderConfirmDeleteConversation,
 | 
        
           |  |  | 1708 |                 confirmContactRequest: renderConfirmContactRequest,
 | 
        
           |  |  | 1709 |                 requireAddContact: renderRequireAddContact,
 | 
        
           |  |  | 1710 |                 selfConversationMessage: renderSelfConversationMessage,
 | 
        
           |  |  | 1711 |                 contactRequestSent: renderContactRequestSent
 | 
        
           |  |  | 1712 |             },
 | 
        
           |  |  | 1713 |             {
 | 
        
           |  |  | 1714 |                 loadingMembers: renderLoadingMembers,
 | 
        
           |  |  | 1715 |                 loadingFirstMessages: renderLoadingFirstMessages,
 | 
        
           |  |  | 1716 |                 loadingMessages: renderLoadingMessages,
 | 
        
           |  |  | 1717 |                 isBlocked: renderIsBlocked,
 | 
        
           |  |  | 1718 |                 isContact: renderIsContact,
 | 
        
           |  |  | 1719 |                 isFavourite: renderIsFavourite,
 | 
        
           |  |  | 1720 |                 isMuted: renderIsMuted,
 | 
        
           |  |  | 1721 |                 loadingConfirmAction: renderLoadingConfirmAction,
 | 
        
           |  |  | 1722 |                 inEditMode: renderInEditMode,
 | 
        
           |  |  | 1723 |                 showEmojiPicker: renderShowEmojiPicker,
 | 
        
           |  |  | 1724 |                 showEmojiAutoComplete: renderShowEmojiAutoComplete,
 | 
        
           |  |  | 1725 |             },
 | 
        
           |  |  | 1726 |             {
 | 
        
           |  |  | 1727 |                 // Scrolling should be last to make sure everything
 | 
        
           |  |  | 1728 |                 // on the page is visible.
 | 
        
           |  |  | 1729 |                 scrollToMessage: renderScrollToMessage,
 | 
        
           |  |  | 1730 |                 selectedMessages: renderSelectedMessages
 | 
        
           |  |  | 1731 |             }
 | 
        
           |  |  | 1732 |         ];
 | 
        
           |  |  | 1733 |         // Helper function to process each of the configs above.
 | 
        
           |  |  | 1734 |         var processConfig = function(config) {
 | 
        
           |  |  | 1735 |             var results = [];
 | 
        
           |  |  | 1736 |   | 
        
           |  |  | 1737 |             for (var key in patch) {
 | 
        
           |  |  | 1738 |                 if (config.hasOwnProperty(key)) {
 | 
        
           |  |  | 1739 |                     var renderFunc = config[key];
 | 
        
           |  |  | 1740 |                     var patchValue = patch[key];
 | 
        
           |  |  | 1741 |                     results.push(renderFunc(header, body, footer, patchValue));
 | 
        
           |  |  | 1742 |                 }
 | 
        
           |  |  | 1743 |             }
 | 
        
           |  |  | 1744 |   | 
        
           |  |  | 1745 |             return results;
 | 
        
           |  |  | 1746 |         };
 | 
        
           |  |  | 1747 |   | 
        
           |  |  | 1748 |         // The first config is special because it resets the UI.
 | 
        
           |  |  | 1749 |         var renderingPromises = processConfig(configs[0]);
 | 
        
           |  |  | 1750 |         // The second config is special because it contains async rendering.
 | 
        
           |  |  | 1751 |         renderingPromises = renderingPromises.concat(processConfig(configs[1]));
 | 
        
           |  |  | 1752 |   | 
        
           |  |  | 1753 |         // Wait for the async rendering to complete before processing the
 | 
        
           |  |  | 1754 |         // rest of the configs, in order.
 | 
        
           |  |  | 1755 |         return $.when.apply($, renderingPromises)
 | 
        
           |  |  | 1756 |             .then(function() {
 | 
        
           |  |  | 1757 |                 for (var i = 2; i < configs.length; i++) {
 | 
        
           |  |  | 1758 |                     processConfig(configs[i]);
 | 
        
           |  |  | 1759 |                 }
 | 
        
           |  |  | 1760 |   | 
        
           |  |  | 1761 |                 return;
 | 
        
           |  |  | 1762 |             })
 | 
        
           |  |  | 1763 |             .catch(Notification.exception);
 | 
        
           |  |  | 1764 |     };
 | 
        
           |  |  | 1765 |   | 
        
           | 1441 | ariadna | 1766 |     /**
 | 
        
           |  |  | 1767 |      * Truncate long usernames.
 | 
        
           |  |  | 1768 |      *
 | 
        
           |  |  | 1769 |      * @param {String} username Text to truncate.
 | 
        
           |  |  | 1770 |      * @return {String} Truncated string.
 | 
        
           |  |  | 1771 |      */
 | 
        
           |  |  | 1772 |     var truncateUsername = function(username) {
 | 
        
           |  |  | 1773 |         return Truncate.truncate(username, {
 | 
        
           |  |  | 1774 |             length: 30,
 | 
        
           |  |  | 1775 |             words: true,
 | 
        
           |  |  | 1776 |             ellipsis: '...'
 | 
        
           |  |  | 1777 |         });
 | 
        
           |  |  | 1778 |     };
 | 
        
           |  |  | 1779 |   | 
        
           | 1 | efrain | 1780 |     return {
 | 
        
           |  |  | 1781 |         render: render,
 | 
        
           |  |  | 1782 |     };
 | 
        
           |  |  | 1783 | });
 |