MDL-54682 message: fix eslint issues
[moodle.git] / message / amd / src / message_area_messages.js
blob59843232a933e548543fd1cf09c831a085e1d0a2
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.
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/>.
16 /**
17  * This module handles the message area of the messaging area.
18  *
19  * @module     core_message/message_area_messages
20  * @package    core_message
21  * @copyright  2016 Mark Nelson <markn@moodle.com>
22  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23  */
24 define(['jquery', 'core/ajax', 'core/templates', 'core/notification', 'core/custom_interaction_events',
25         'core/auto_rows', 'core_message/message_area_actions', 'core/modal_factory', 'core/modal_events',
26         'core/str', 'core_message/message_area_events'],
27     function($, Ajax, Templates, Notification, CustomEvents, AutoRows, Actions, ModalFactory, ModalEvents, Str, Events) {
29         /** @type {int} The message area default height. */
30         var MESSAGES_AREA_DEFAULT_HEIGHT = 500;
32         /** @type {int} The response default height. */
33         var MESSAGES_RESPONSE_DEFAULT_HEIGHT = 50;
35         /** @type {Object} The list of selectors for the message area. */
36         var SELECTORS = {
37             BLOCKTIME: "[data-region='blocktime']",
38             CANCELDELETEMESSAGES: "[data-action='cancel-delete-messages']",
39             CONTACT: "[data-region='contact']",
40             CONVERSATIONS: "[data-region='contacts'][data-region-content='conversations']",
41             DELETEALLMESSAGES: "[data-action='delete-all-messages']",
42             DELETEMESSAGES: "[data-action='delete-messages']",
43             LOADINGICON: '.loading-icon',
44             MESSAGE: "[data-region='message']",
45             MESSAGERESPONSE: "[data-region='response']",
46             MESSAGES: "[data-region='messages']",
47             MESSAGESAREA: "[data-region='messages-area']",
48             MESSAGINGAREA: "[data-region='messaging-area']",
49             SENDMESSAGE: "[data-action='send-message']",
50             SENDMESSAGETEXT: "[data-region='send-message-txt']",
51             SHOWCONTACTS: "[data-action='show-contacts']",
52             STARTDELETEMESSAGES: "[data-action='start-delete-messages']"
53         };
55         /**
56          * Messages class.
57          *
58          * @param {Messagearea} messageArea The messaging area object.
59          */
60         function Messages(messageArea) {
61             this.messageArea = messageArea;
62             this._init();
63         }
65         /** @type {Boolean} checks if we are sending a message */
66         Messages.prototype._isSendingMessage = false;
68         /** @type {Boolean} checks if we are currently loading messages */
69         Messages.prototype._isLoadingMessages = false;
71         /** @type {int} the number of messagess displayed */
72         Messages.prototype._numMessagesDisplayed = 0;
74         /** @type {int} the number of messages to retrieve */
75         Messages.prototype._numMessagesToRetrieve = 20;
77         /** @type {Modal} the confirmation modal */
78         Messages.prototype._confirmationModal = null;
80         /** @type {Messagearea} The messaging area object. */
81         Messages.prototype.messageArea = null;
83         /**
84          * Initialise the event listeners.
85          *
86          * @private
87          */
88         Messages.prototype._init = function() {
89             CustomEvents.define(this.messageArea.node, [
90                 CustomEvents.events.activate,
91                 CustomEvents.events.up,
92                 CustomEvents.events.down,
93                 CustomEvents.events.enter,
94             ]);
96             AutoRows.init(this.messageArea.node);
98             this.messageArea.onCustomEvent(Events.CONVERSATIONSELECTED, this._viewMessages.bind(this));
99             this.messageArea.onCustomEvent(Events.SENDMESSAGE, this._viewMessages.bind(this));
100             this.messageArea.onCustomEvent(Events.CHOOSEMESSAGESTODELETE, this._chooseMessagesToDelete.bind(this));
101             this.messageArea.onCustomEvent(Events.CANCELDELETEMESSAGES, this._hideDeleteAction.bind(this));
102             this.messageArea.onDelegateEvent(CustomEvents.events.activate, SELECTORS.SENDMESSAGE,
103                 this._sendMessage.bind(this));
104             this.messageArea.onDelegateEvent(CustomEvents.events.activate, SELECTORS.STARTDELETEMESSAGES,
105                 this._startDeleting.bind(this));
106             this.messageArea.onDelegateEvent(CustomEvents.events.activate, SELECTORS.DELETEMESSAGES,
107                 this._deleteMessages.bind(this));
108             this.messageArea.onDelegateEvent(CustomEvents.events.activate, SELECTORS.DELETEALLMESSAGES,
109                 this._deleteAllMessages.bind(this));
110             this.messageArea.onDelegateEvent(CustomEvents.events.activate, SELECTORS.CANCELDELETEMESSAGES,
111                 this._triggerCancelMessagesToDelete.bind(this));
112             this.messageArea.onDelegateEvent(CustomEvents.events.activate, SELECTORS.MESSAGE,
113                 this._toggleMessage.bind(this));
114             this.messageArea.onDelegateEvent(CustomEvents.events.activate, SELECTORS.SHOWCONTACTS,
115                 this._hideMessagingArea.bind(this));
117             this.messageArea.onDelegateEvent(CustomEvents.events.up, SELECTORS.MESSAGE,
118                 this._selectPreviousMessage.bind(this));
119             this.messageArea.onDelegateEvent(CustomEvents.events.down, SELECTORS.MESSAGE,
120                 this._selectNextMessage.bind(this));
122             this.messageArea.onDelegateEvent('focus', SELECTORS.SENDMESSAGETEXT, this._setMessaging.bind(this));
123             this.messageArea.onDelegateEvent('blur', SELECTORS.SENDMESSAGETEXT, this._clearMessaging.bind(this));
125             this.messageArea.onDelegateEvent(CustomEvents.events.enter, SELECTORS.SENDMESSAGETEXT,
126                 this._sendMessageHandler.bind(this));
128             $(document).on(AutoRows.events.ROW_CHANGE, this._adjustMessagesAreaHeight.bind(this));
130             // Check if any messages have been displayed on page load.
131             var messages = this.messageArea.find(SELECTORS.MESSAGES);
132             if (messages.length) {
133                 this._addScrollEventListener(messages.find(SELECTORS.MESSAGE).length);
134             }
135         };
137         /**
138          * View the message panel.
139          *
140          * @param {Event} event
141          * @param {int} userid
142          * @return {Promise} The promise resolved when the messages have been loaded.
143          * @private
144          */
145         Messages.prototype._viewMessages = function(event, userid) {
146             // We are viewing another user, or re-loading the panel, so set number of messages displayed to 0.
147             this._numMessagesDisplayed = 0;
149             // Mark all the messages as read.
150             var markMessagesAsRead = Ajax.call([{
151                 methodname: 'core_message_mark_all_messages_as_read',
152                 args: {
153                     useridto: this.messageArea.getCurrentUserId(),
154                     useridfrom: userid
155                 }
156             }]);
158             // Keep track of the number of messages received.
159             var numberreceived = 0;
160             // Show loading template.
161             return Templates.render('core/loading', {}).then(function(html, js) {
162                 Templates.replaceNodeContents(this.messageArea.find(SELECTORS.MESSAGESAREA), html, js);
163                 return markMessagesAsRead[0];
164             }.bind(this)).then(function() {
165                 var conversationnode = this.messageArea.find(SELECTORS.CONVERSATIONS + " " +
166                     SELECTORS.CONTACT + "[data-userid='" + userid + "']");
167                 if (conversationnode.hasClass('unread')) {
168                     // Remove the class.
169                     conversationnode.removeClass('unread');
170                     // Trigger an event letting the notification popover (and whoever else) know.
171                     $(document).trigger('messagearea:conversationselected', userid);
172                 }
173                 return this._getMessages(userid);
174             }.bind(this)).then(function(data) {
175                 numberreceived = data.messages.length;
176                 // We have the data - lets render the template with it.
177                 return Templates.render('core_message/message_area_messages_area', data);
178             }).then(function(html, js) {
179                 Templates.replaceNodeContents(this.messageArea.find(SELECTORS.MESSAGESAREA), html, js);
180                 this._addScrollEventListener(numberreceived);
181             }.bind(this)).fail(Notification.exception);
182         };
184         /**
185          * Loads messages while scrolling.
186          *
187          * @return {Promise|boolean} The promise resolved when the messages have been loaded.
188          * @private
189          */
190         Messages.prototype._loadMessages = function() {
191             if (this._isLoadingMessages) {
192                 return false;
193             }
195             this._isLoadingMessages = true;
197             // Keep track of the number of messages received.
198             var numberreceived = 0;
199             // Show loading template.
200             return Templates.render('core/loading', {}).then(function(html, js) {
201                 Templates.prependNodeContents(this.messageArea.find(SELECTORS.MESSAGES),
202                     "<div style='text-align:center'>" + html + "</div>", js);
203                 return this._getMessages(this._getUserId());
204             }.bind(this)).then(function(data) {
205                 numberreceived = data.messages.length;
206                 // We have the data - lets render the template with it.
207                 return Templates.render('core_message/message_area_messages', data);
208             }).then(function(html, js) {
209                 // Remove the loading icon.
210                 this.messageArea.find(SELECTORS.MESSAGES + " " +
211                     SELECTORS.LOADINGICON).remove();
212                 // Check if we got something to do.
213                 if (numberreceived > 0) {
214                     // Let's check if we can remove the block time.
215                     // First, get the block time that is currently being displayed.
216                     var blocktime = this.messageArea.node.find(SELECTORS.BLOCKTIME + ":first");
217                     var newblocktime = $(html).find(SELECTORS.BLOCKTIME + ":first").addBack();
218                     if (blocktime.html() == newblocktime.html()) {
219                         // Remove the block time as it's present above.
220                         blocktime.remove();
221                     }
222                     // Get height before we add the messages.
223                     var oldheight = this.messageArea.find(SELECTORS.MESSAGES)[0].scrollHeight;
224                     // Show the new content.
225                     Templates.prependNodeContents(this.messageArea.find(SELECTORS.MESSAGES), html, js);
226                     // Get height after we add the messages.
227                     var newheight = this.messageArea.find(SELECTORS.MESSAGES)[0].scrollHeight;
228                     // Make sure scroll bar is at the location before we loaded more messages.
229                     this.messageArea.find(SELECTORS.MESSAGES).scrollTop(newheight - oldheight);
230                     // Increment the number of messages displayed.
231                     this._numMessagesDisplayed += numberreceived;
232                 }
233                 // Mark that we are no longer busy loading data.
234                 this._isLoadingMessages = false;
235             }.bind(this)).fail(Notification.exception);
236         };
238         /**
239          * Handles returning a list of messages to display.
240          *
241          * @param {int} userid
242          * @return {Promise} The promise resolved when the contact area has been rendered
243          * @private
244          */
245         Messages.prototype._getMessages = function(userid) {
246             // Call the web service to get our data.
247             var promises = Ajax.call([{
248                 methodname: 'core_message_data_for_messagearea_messages',
249                 args: {
250                     currentuserid: this.messageArea.getCurrentUserId(),
251                     otheruserid: userid,
252                     limitfrom: this._numMessagesDisplayed,
253                     limitnum: this._numMessagesToRetrieve,
254                     newest: true
255                 }
256             }]);
258             // Do stuff when we get data back.
259             return promises[0];
260         };
262         /**
263          * Handles sending a message.
264          *
265          * @return {Promise|boolean} The promise resolved once the message has been sent.
266          * @private
267          */
268         Messages.prototype._sendMessage = function() {
269             var element = this.messageArea.find(SELECTORS.SENDMESSAGETEXT);
270             var text = element.val();
272             // Do not do anything if it is empty.
273             if (text.trim() === '') {
274                 return false;
275             }
277             // If we are sending a message, don't do anything, be patient!
278             if (this._isSendingMessage) {
279                 return false;
280             }
282             // Ok, mark that we are sending a message.
283             this._isSendingMessage = true;
285             // Call the web service to save our message.
286             var promises = Ajax.call([{
287                 methodname: 'core_message_send_instant_messages',
288                 args: {
289                     messages: [
290                         {
291                             touserid: this._getUserId(),
292                             text: text
293                         }
294                     ]
295                 }
296             }]);
298             element.prop('disabled', true);
300             // Update the DOM when we get some data back.
301             return promises[0].then(function(response) {
302                 if (response.length < 0) {
303                     // Even errors should return valid data.
304                     throw new Error('Invalid response');
305                 }
306                 if (response[0].errormessage) {
307                     throw new Error(response[0].errormessage);
308                 }
309                 // Fire an event to say the message was sent.
310                 this.messageArea.trigger(Events.MESSAGESENT, [this._getUserId(), text]);
311                 // Update the messaging area.
312                 return this._addMessageToDom();
313             }.bind(this)).then(function() {
314                 // Ok, we are no longer sending a message.
315                 this._isSendingMessage = false;
316             }.bind(this)).always(function() {
317                 element.prop('disabled', false);
318             }).fail(Notification.exception);
319         };
321         /**
322          * Handles selecting messages to delete.
323          *
324          * @private
325          */
326         Messages.prototype._chooseMessagesToDelete = function() {
327             this.messageArea.find(SELECTORS.MESSAGESAREA).addClass('editing');
328             this.messageArea.find(SELECTORS.MESSAGE)
329                 .attr('role', 'checkbox')
330                 .attr('aria-checked', 'false');
331         };
333         /**
334          * Handles deleting messages.
335          *
336          * @private
337          */
338         Messages.prototype._deleteMessages = function() {
339             var userid = this.messageArea.getCurrentUserId();
340             var checkboxes = this.messageArea.find(SELECTORS.MESSAGE + "[aria-checked='true']");
341             var requests = [];
342             var messagestoremove = [];
344             // Go through all the checked checkboxes and prepare them for deletion.
345             checkboxes.each(function(id, element) {
346                 var node = $(element);
347                 var messageid = node.data('messageid');
348                 var isread = node.data('messageread') ? 1 : 0;
349                 messagestoremove.push(node);
350                 requests.push({
351                     methodname: 'core_message_delete_message',
352                     args: {
353                         messageid: messageid,
354                         userid: userid,
355                         read: isread
356                     }
357                 });
358             });
360             if (requests.length > 0) {
361                 Ajax.call(requests)[requests.length - 1].then(function() {
362                     // Store the last message on the page, and the last message being deleted.
363                     var updatemessage = null;
364                     var messages = this.messageArea.find(SELECTORS.MESSAGE);
365                     var lastmessage = messages.last();
366                     var lastremovedmessage = messagestoremove[messagestoremove.length - 1];
367                     // Remove the messages from the DOM.
368                     $.each(messagestoremove, function(key, message) {
369                         // Remove the message.
370                         message.remove();
371                     });
372                     // If the last message was deleted then we need to provide the new last message.
373                     if (lastmessage.data('id') === lastremovedmessage.data('id')) {
374                         updatemessage = this.messageArea.find(SELECTORS.MESSAGE).last();
375                     }
376                     // Now we have removed all the messages from the DOM lets remove any block times we may need to as well.
377                     $.each(messagestoremove, function(key, message) {
378                         // First - let's make sure there are no more messages in that time block.
379                         var blocktime = message.data('blocktime');
380                         if (this.messageArea.find(SELECTORS.MESSAGE +
381                             "[data-blocktime='" + blocktime + "']").length === 0) {
382                             this.messageArea.find(SELECTORS.BLOCKTIME +
383                                 "[data-blocktime='" + blocktime + "']").remove();
384                         }
385                     }.bind(this));
387                     // If there are no messages at all, then remove conversation panel.
388                     if (this.messageArea.find(SELECTORS.MESSAGE).length === 0) {
389                         this.messageArea.find(SELECTORS.CONVERSATIONS + " " +
390                             SELECTORS.CONTACT + "[data-userid='" + this._getUserId() + "']").remove();
391                     }
393                     // Trigger event letting other modules know messages were deleted.
394                     this.messageArea.trigger(Events.MESSAGESDELETED, [this._getUserId(), updatemessage]);
395                 }.bind(this), Notification.exception);
396             } else {
397                 // Trigger event letting other modules know messages were deleted.
398                 this.messageArea.trigger(Events.MESSAGESDELETED, this._getUserId());
399             }
401             // Hide the items responsible for deleting messages.
402             this._hideDeleteAction();
403         };
405         /**
406          * Handles adding a scrolling event listener.
407          *
408          * @param {int} numberreceived The number of messages received
409          * @private
410          */
411         Messages.prototype._addScrollEventListener = function(numberreceived) {
412             // Scroll to the bottom.
413             this._scrollBottom();
414             // Set the number of messages displayed.
415             this._numMessagesDisplayed = numberreceived;
416             // Now enable the ability to infinitely scroll through messages.
417             CustomEvents.define(this.messageArea.find(SELECTORS.MESSAGES), [
418                 CustomEvents.events.scrollTop
419             ]);
420             // Assign the event for scrolling.
421             this.messageArea.onCustomEvent(CustomEvents.events.scrollTop, this._loadMessages.bind(this));
422         };
424         /**
425          * Handles deleting a conversation.
426          *
427          * @private
428          */
429         Messages.prototype._deleteAllMessages = function() {
430             // Create the confirmation modal if we haven't already.
431             if (!this._confirmationModal) {
432                 ModalFactory.create({
433                     type: ModalFactory.types.CONFIRM,
434                     body: Str.get_string('deleteallconfirm', 'message'),
435                 }, this.messageArea.find(SELECTORS.DELETEALLMESSAGES))
436                 .done(function(modal) {
437                     this._confirmationModal = modal;
439                     // Only delete the conversation if the user agreed in the confirmation modal.
440                     modal.getRoot().on(ModalEvents.yes, function() {
441                         var otherUserId = this._getUserId();
442                         var request = {
443                             methodname: 'core_message_delete_conversation',
444                             args: {
445                                 userid: this.messageArea.getCurrentUserId(),
446                                 otheruserid: otherUserId
447                             }
448                         };
450                         // Delete the conversation.
451                         Ajax.call([request])[0].then(function() {
452                             // Clear the message area.
453                             this.messageArea.find(SELECTORS.MESSAGESAREA).empty();
454                             // Let the app know a conversation was deleted.
455                             this.messageArea.trigger(Events.CONVERSATIONDELETED, otherUserId);
456                             this._hideDeleteAction();
457                         }.bind(this), Notification.exeption);
458                     }.bind(this));
460                     // Display the confirmation.
461                     modal.show();
462                 }.bind(this));
463             } else {
464                 // Otherwise just show the existing modal.
465                 this._confirmationModal.show();
466             }
467         };
469         /**
470          * Handles hiding the delete checkboxes and replacing the response area.
471          *
472          * @private
473          */
474         Messages.prototype._hideDeleteAction = function() {
475             this.messageArea.find(SELECTORS.MESSAGE)
476                 .removeAttr('role')
477                 .removeAttr('aria-checked');
478             this.messageArea.find(SELECTORS.MESSAGESAREA).removeClass('editing');
479         };
481         /**
482          * Triggers the CANCELDELETEMESSAGES event.
483          *
484          * @private
485          */
486         Messages.prototype._triggerCancelMessagesToDelete = function() {
487             // Trigger event letting other modules know message deletion was canceled.
488             this.messageArea.trigger(Events.CANCELDELETEMESSAGES);
489         };
491         /**
492          * Handles adding messages to the DOM.
493          *
494          * @return {Promise} The promise resolved when the message has been added to the DOM.
495          * @private
496          */
497         Messages.prototype._addMessageToDom = function() {
498             // Call the web service to return how the message should look.
499             var promises = Ajax.call([{
500                 methodname: 'core_message_data_for_messagearea_get_most_recent_message',
501                 args: {
502                     currentuserid: this.messageArea.getCurrentUserId(),
503                     otheruserid: this._getUserId()
504                 }
505             }]);
507             // Add the message.
508             return promises[0].then(function(data) {
509                 return Templates.render('core_message/message_area_message', data);
510             }).then(function(html, js) {
511                 Templates.appendNodeContents(this.messageArea.find(SELECTORS.MESSAGES), html, js);
512                 // Empty the response text area.
513                 this.messageArea.find(SELECTORS.SENDMESSAGETEXT).val('').trigger('input');
514                 // Scroll down.
515                 this._scrollBottom();
516             }.bind(this)).fail(Notification.exception);
517         };
519         /**
520          * Returns the ID of the other user in the conversation.
521          *
522          * @return {int} The user id
523          * @private
524          */
525         Messages.prototype._getUserId = function() {
526             return this.messageArea.find(SELECTORS.MESSAGES).data('userid');
527         };
529         /**
530          * Scrolls to the bottom of the messages.
531          *
532          * @private
533          */
534         Messages.prototype._scrollBottom = function() {
535             // Scroll to the bottom.
536             var messages = this.messageArea.find(SELECTORS.MESSAGES);
537             if (messages.length !== 0) {
538                 messages.scrollTop(messages[0].scrollHeight);
539             }
540         };
542         /**
543          * Select the previous message in the list.
544          *
545          * @param {event} e The jquery event
546          * @param {object} data Extra event data
547          * @private
548          */
549         Messages.prototype._selectPreviousMessage = function(e, data) {
550             var currentMessage = $(e.target).closest(SELECTORS.MESSAGE);
552             do {
553                 currentMessage = currentMessage.prev();
554             } while (currentMessage.length && !currentMessage.is(SELECTORS.MESSAGE));
556             currentMessage.focus();
558             data.originalEvent.preventDefault();
559             data.originalEvent.stopPropagation();
560         };
562         /**
563          * Select the next message in the list.
564          *
565          * @param {event} e The jquery event
566          * @param {object} data Extra event data
567          * @private
568          */
569         Messages.prototype._selectNextMessage = function(e, data) {
570             var currentMessage = $(e.target).closest(SELECTORS.MESSAGE);
572             do {
573                 currentMessage = currentMessage.next();
574             } while (currentMessage.length && !currentMessage.is(SELECTORS.MESSAGE));
576             currentMessage.focus();
578             data.originalEvent.preventDefault();
579             data.originalEvent.stopPropagation();
580         };
582         /**
583          * Flag the response area as messaging.
584          *
585          * @param {event} e The jquery event
586          * @private
587          */
588         Messages.prototype._setMessaging = function(e) {
589             $(e.target).closest(SELECTORS.MESSAGERESPONSE).addClass('messaging');
590         };
592         /**
593          * Clear the response area as messaging flag.
594          *
595          * @param {event} e The jquery event
596          * @private
597          */
598         Messages.prototype._clearMessaging = function(e) {
599             $(e.target).closest(SELECTORS.MESSAGERESPONSE).removeClass('messaging');
600         };
602         /**
603          * Turn on delete message mode.
604          *
605          * @param {event} e The jquery event
606          * @private
607          */
608         Messages.prototype._startDeleting = function(e) {
609             var actions = new Actions(this.messageArea);
610             actions.chooseMessagesToDelete();
612             e.preventDefault();
613         };
615         /**
616          * Check if the message area is in editing mode.
617          *
618          * @return {bool}
619          * @private
620          */
621         Messages.prototype._isEditing = function() {
622             return this.messageArea.find(SELECTORS.MESSAGESAREA).hasClass('editing');
623         };
625         /**
626          * Check or uncheck the message if the message area is in editing mode.
627          *
628          * @param {event} e The jquery event
629          * @private
630          */
631         Messages.prototype._toggleMessage = function(e) {
632             if (!this._isEditing()) {
633                 return;
634             }
636             var message = $(e.target).closest(SELECTORS.MESSAGE);
638             if (message.attr('aria-checked') === 'true') {
639                 message.attr('aria-checked', 'false');
640             } else {
641                 message.attr('aria-checked', 'true');
642             }
643         };
645         /**
646          * Adjust the height of the messages area to match the changed height of
647          * the response area.
648          *
649          * @private
650          */
651         Messages.prototype._adjustMessagesAreaHeight = function() {
652             var messagesArea = this.messageArea.find(SELECTORS.MESSAGES);
653             var messagesResponse = this.messageArea.find(SELECTORS.MESSAGERESPONSE);
655             var currentMessageResponseHeight = messagesResponse.outerHeight();
656             var diffResponseHeight = currentMessageResponseHeight - MESSAGES_RESPONSE_DEFAULT_HEIGHT;
657             var newMessagesAreaHeight = MESSAGES_AREA_DEFAULT_HEIGHT - diffResponseHeight;
659             messagesArea.outerHeight(newMessagesAreaHeight);
660         };
662         /**
663          * Handle the event that triggers sending a message from the messages area.
664          *
665          * @param {event} e The jquery event
666          * @param {object} data Additional event data
667          * @private
668          */
669         Messages.prototype._sendMessageHandler = function(e, data) {
670             data.originalEvent.preventDefault();
672             this._sendMessage();
673         };
675         /**
676          * Hide the messaging area. This only applies on smaller screen resolutions.
677          */
678         Messages.prototype._hideMessagingArea = function() {
679             this.messageArea.find(SELECTORS.MESSAGINGAREA)
680                 .removeClass('show-messages')
681                 .addClass('hide-messages');
682         };
684         return Messages;
685     }