| 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 |  * Controls the search page of the message drawer.
 | 
        
           |  |  | 18 |  *
 | 
        
           |  |  | 19 |  * @module     core_message/message_drawer_view_search
 | 
        
           |  |  | 20 |  * @copyright  2018 Ryan Wyllie <ryan@moodle.com>
 | 
        
           |  |  | 21 |  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 | 
        
           |  |  | 22 |  */
 | 
        
           |  |  | 23 | define(
 | 
        
           |  |  | 24 | [
 | 
        
           |  |  | 25 |     'jquery',
 | 
        
           |  |  | 26 |     'core/custom_interaction_events',
 | 
        
           |  |  | 27 |     'core/notification',
 | 
        
           |  |  | 28 |     'core/pubsub',
 | 
        
           |  |  | 29 |     'core/str',
 | 
        
           |  |  | 30 |     'core/templates',
 | 
        
           |  |  | 31 |     'core_message/message_repository',
 | 
        
           |  |  | 32 |     'core_message/message_drawer_events',
 | 
        
           |  |  | 33 | ],
 | 
        
           |  |  | 34 | function(
 | 
        
           |  |  | 35 |     $,
 | 
        
           |  |  | 36 |     CustomEvents,
 | 
        
           |  |  | 37 |     Notification,
 | 
        
           |  |  | 38 |     PubSub,
 | 
        
           |  |  | 39 |     Str,
 | 
        
           |  |  | 40 |     Templates,
 | 
        
           |  |  | 41 |     Repository,
 | 
        
           |  |  | 42 |     Events
 | 
        
           |  |  | 43 | ) {
 | 
        
           |  |  | 44 |   | 
        
           |  |  | 45 |     var MESSAGE_SEARCH_LIMIT = 50;
 | 
        
           |  |  | 46 |     var USERS_SEARCH_LIMIT = 50;
 | 
        
           |  |  | 47 |     var USERS_INITIAL_SEARCH_LIMIT = 3;
 | 
        
           |  |  | 48 |   | 
        
           |  |  | 49 |     var SELECTORS = {
 | 
        
           |  |  | 50 |         BLOCK_ICON_CONTAINER: '[data-region="block-icon-container"]',
 | 
        
           |  |  | 51 |         CANCEL_SEARCH_BUTTON: '[data-action="cancel-search"]',
 | 
        
           |  |  | 52 |         CONTACTS_CONTAINER: '[data-region="contacts-container"]',
 | 
        
           |  |  | 53 |         CONTACTS_LIST: '[data-region="contacts-container"] [data-region="list"]',
 | 
        
           |  |  | 54 |         EMPTY_MESSAGE_CONTAINER: '[data-region="empty-message-container"]',
 | 
        
           |  |  | 55 |         LIST: '[data-region="list"]',
 | 
        
           |  |  | 56 |         LOADING_ICON_CONTAINER: '[data-region="loading-icon-container"]',
 | 
        
           |  |  | 57 |         LOADING_PLACEHOLDER: '[data-region="loading-placeholder"]',
 | 
        
           |  |  | 58 |         MESSAGES_LIST: '[data-region="messages-container"] [data-region="list"]',
 | 
        
           |  |  | 59 |         MESSAGES_CONTAINER: '[data-region="messages-container"]',
 | 
        
           |  |  | 60 |         NON_CONTACTS_CONTAINER: '[data-region="non-contacts-container"]',
 | 
        
           |  |  | 61 |         NON_CONTACTS_LIST: '[data-region="non-contacts-container"] [data-region="list"]',
 | 
        
           |  |  | 62 |         SEARCH_ICON_CONTAINER: '[data-region="search-icon-container"]',
 | 
        
           |  |  | 63 |         SEARCH_ACTION: '[data-action="search"]',
 | 
        
           |  |  | 64 |         SEARCH_INPUT: '[data-region="search-input"]',
 | 
        
           |  |  | 65 |         SEARCH_RESULTS_CONTAINER: '[data-region="search-results-container"]',
 | 
        
           |  |  | 66 |         LOAD_MORE_USERS: '[data-action="load-more-users"]',
 | 
        
           |  |  | 67 |         LOAD_MORE_MESSAGES: '[data-action="load-more-messages"]',
 | 
        
           |  |  | 68 |         BUTTON_TEXT: '[data-region="button-text"]',
 | 
        
           |  |  | 69 |         NO_RESULTS_CONTAINTER: '[data-region="no-results-container"]',
 | 
        
           |  |  | 70 |         ALL_CONTACTS_CONTAINER: '[data-region="all-contacts-container"]'
 | 
        
           |  |  | 71 |     };
 | 
        
           |  |  | 72 |   | 
        
           |  |  | 73 |     var TEMPLATES = {
 | 
        
           |  |  | 74 |         CONTACTS_LIST: 'core_message/message_drawer_contacts_list',
 | 
        
           |  |  | 75 |         NON_CONTACTS_LIST: 'core_message/message_drawer_non_contacts_list',
 | 
        
           |  |  | 76 |         MESSAGES_LIST: 'core_message/message_drawer_messages_list'
 | 
        
           |  |  | 77 |     };
 | 
        
           |  |  | 78 |   | 
        
           |  |  | 79 |     /**
 | 
        
           |  |  | 80 |      * Get the logged in user id.
 | 
        
           |  |  | 81 |      *
 | 
        
           |  |  | 82 |      * @param  {Object} body Search body container element.
 | 
        
           |  |  | 83 |      * @return {Number} User id.
 | 
        
           |  |  | 84 |      */
 | 
        
           |  |  | 85 |     var getLoggedInUserId = function(body) {
 | 
        
           |  |  | 86 |         return body.attr('data-user-id');
 | 
        
           |  |  | 87 |     };
 | 
        
           |  |  | 88 |   | 
        
           |  |  | 89 |     /**
 | 
        
           |  |  | 90 |      * Show the no messages container element.
 | 
        
           |  |  | 91 |      *
 | 
        
           |  |  | 92 |      * @param  {Object} body Search body container element.
 | 
        
           |  |  | 93 |      * @return {Object} No messages container element.
 | 
        
           |  |  | 94 |      */
 | 
        
           |  |  | 95 |     var getEmptyMessageContainer = function(body) {
 | 
        
           |  |  | 96 |         return body.find(SELECTORS.EMPTY_MESSAGE_CONTAINER);
 | 
        
           |  |  | 97 |     };
 | 
        
           |  |  | 98 |   | 
        
           |  |  | 99 |     /**
 | 
        
           |  |  | 100 |      * Get the search loading icon.
 | 
        
           |  |  | 101 |      *
 | 
        
           |  |  | 102 |      * @param  {Object} header Search header container element.
 | 
        
           |  |  | 103 |      * @return {Object} Loading icon element.
 | 
        
           |  |  | 104 |      */
 | 
        
           |  |  | 105 |     var getLoadingIconContainer = function(header) {
 | 
        
           |  |  | 106 |         return header.find(SELECTORS.LOADING_ICON_CONTAINER);
 | 
        
           |  |  | 107 |     };
 | 
        
           |  |  | 108 |   | 
        
           |  |  | 109 |     /**
 | 
        
           |  |  | 110 |      * Get the loading container element.
 | 
        
           |  |  | 111 |      *
 | 
        
           |  |  | 112 |      * @param  {Object} body Search body container element.
 | 
        
           |  |  | 113 |      * @return {Object} Loading container element.
 | 
        
           |  |  | 114 |      */
 | 
        
           |  |  | 115 |     var getLoadingPlaceholder = function(body) {
 | 
        
           |  |  | 116 |         return body.find(SELECTORS.LOADING_PLACEHOLDER);
 | 
        
           |  |  | 117 |     };
 | 
        
           |  |  | 118 |   | 
        
           |  |  | 119 |     /**
 | 
        
           |  |  | 120 |      * Get the search icon container.
 | 
        
           |  |  | 121 |      *
 | 
        
           |  |  | 122 |      * @param  {Object} header Search header container element.
 | 
        
           |  |  | 123 |      * @return {Object} Search icon container.
 | 
        
           |  |  | 124 |      */
 | 
        
           |  |  | 125 |     var getSearchIconContainer = function(header) {
 | 
        
           |  |  | 126 |         return header.find(SELECTORS.SEARCH_ICON_CONTAINER);
 | 
        
           |  |  | 127 |     };
 | 
        
           |  |  | 128 |   | 
        
           |  |  | 129 |     /**
 | 
        
           |  |  | 130 |      * Get the search input container.
 | 
        
           |  |  | 131 |      *
 | 
        
           |  |  | 132 |      * @param  {Object} header Search header container element.
 | 
        
           |  |  | 133 |      * @return {Object} Search input container.
 | 
        
           |  |  | 134 |      */
 | 
        
           |  |  | 135 |     var getSearchInput = function(header) {
 | 
        
           |  |  | 136 |         return header.find(SELECTORS.SEARCH_INPUT);
 | 
        
           |  |  | 137 |     };
 | 
        
           |  |  | 138 |   | 
        
           |  |  | 139 |     /**
 | 
        
           |  |  | 140 |      * Get the search results container.
 | 
        
           |  |  | 141 |      *
 | 
        
           |  |  | 142 |      * @param  {Object} body Search body container element.
 | 
        
           |  |  | 143 |      * @return {Object} Search results container.
 | 
        
           |  |  | 144 |      */
 | 
        
           |  |  | 145 |     var getSearchResultsContainer = function(body) {
 | 
        
           |  |  | 146 |         return body.find(SELECTORS.SEARCH_RESULTS_CONTAINER);
 | 
        
           |  |  | 147 |     };
 | 
        
           |  |  | 148 |   | 
        
           |  |  | 149 |     /**
 | 
        
           |  |  | 150 |      * Get the search contacts container.
 | 
        
           |  |  | 151 |      *
 | 
        
           |  |  | 152 |      * @param  {Object} body Search body container element.
 | 
        
           |  |  | 153 |      * @return {Object} Search contacts container.
 | 
        
           |  |  | 154 |      */
 | 
        
           |  |  | 155 |     var getContactsContainer = function(body) {
 | 
        
           |  |  | 156 |         return body.find(SELECTORS.CONTACTS_CONTAINER);
 | 
        
           |  |  | 157 |     };
 | 
        
           |  |  | 158 |   | 
        
           |  |  | 159 |     /**
 | 
        
           |  |  | 160 |      * Get the search non contacts container.
 | 
        
           |  |  | 161 |      *
 | 
        
           |  |  | 162 |      * @param  {Object} body Search body container element.
 | 
        
           |  |  | 163 |      * @return {Object} Search non contacts container.
 | 
        
           |  |  | 164 |      */
 | 
        
           |  |  | 165 |     var getNonContactsContainer = function(body) {
 | 
        
           |  |  | 166 |         return body.find(SELECTORS.NON_CONTACTS_CONTAINER);
 | 
        
           |  |  | 167 |     };
 | 
        
           |  |  | 168 |   | 
        
           |  |  | 169 |     /**
 | 
        
           |  |  | 170 |      * Get the search messages container.
 | 
        
           |  |  | 171 |      *
 | 
        
           |  |  | 172 |      * @param  {Object} body Search body container element.
 | 
        
           |  |  | 173 |      * @return {Object} Search messages container.
 | 
        
           |  |  | 174 |      */
 | 
        
           |  |  | 175 |     var getMessagesContainer = function(body) {
 | 
        
           |  |  | 176 |         return body.find(SELECTORS.MESSAGES_CONTAINER);
 | 
        
           |  |  | 177 |     };
 | 
        
           |  |  | 178 |   | 
        
           |  |  | 179 |   | 
        
           |  |  | 180 |     /**
 | 
        
           |  |  | 181 |      * Show the messages empty container.
 | 
        
           |  |  | 182 |      *
 | 
        
           |  |  | 183 |      * @param {Object} body Search body container element.
 | 
        
           |  |  | 184 |      */
 | 
        
           |  |  | 185 |     var showEmptyMessage = function(body) {
 | 
        
           |  |  | 186 |         getEmptyMessageContainer(body).removeClass('hidden');
 | 
        
           |  |  | 187 |     };
 | 
        
           |  |  | 188 |   | 
        
           |  |  | 189 |     /**
 | 
        
           |  |  | 190 |      * Hide the messages empty container.
 | 
        
           |  |  | 191 |      *
 | 
        
           |  |  | 192 |      * @param {Object} body Search body container element.
 | 
        
           |  |  | 193 |      */
 | 
        
           |  |  | 194 |     var hideEmptyMessage = function(body) {
 | 
        
           |  |  | 195 |         getEmptyMessageContainer(body).addClass('hidden');
 | 
        
           |  |  | 196 |     };
 | 
        
           |  |  | 197 |   | 
        
           |  |  | 198 |   | 
        
           |  |  | 199 |     /**
 | 
        
           |  |  | 200 |      * Show the loading icon.
 | 
        
           |  |  | 201 |      *
 | 
        
           |  |  | 202 |      * @param {Object} header Search header container element.
 | 
        
           |  |  | 203 |      */
 | 
        
           |  |  | 204 |     var showLoadingIcon = function(header) {
 | 
        
           |  |  | 205 |         getLoadingIconContainer(header).removeClass('hidden');
 | 
        
           |  |  | 206 |     };
 | 
        
           |  |  | 207 |   | 
        
           |  |  | 208 |     /**
 | 
        
           |  |  | 209 |      * Hide the loading icon.
 | 
        
           |  |  | 210 |      *
 | 
        
           |  |  | 211 |      * @param {Object} header Search header container element.
 | 
        
           |  |  | 212 |      */
 | 
        
           |  |  | 213 |     var hideLoadingIcon = function(header) {
 | 
        
           |  |  | 214 |         getLoadingIconContainer(header).addClass('hidden');
 | 
        
           |  |  | 215 |     };
 | 
        
           |  |  | 216 |   | 
        
           |  |  | 217 |     /**
 | 
        
           |  |  | 218 |      * Show loading placeholder.
 | 
        
           |  |  | 219 |      *
 | 
        
           |  |  | 220 |      * @param {Object} body Search body container element.
 | 
        
           |  |  | 221 |      */
 | 
        
           |  |  | 222 |     var showLoadingPlaceholder = function(body) {
 | 
        
           |  |  | 223 |         getLoadingPlaceholder(body).removeClass('hidden');
 | 
        
           |  |  | 224 |     };
 | 
        
           |  |  | 225 |   | 
        
           |  |  | 226 |     /**
 | 
        
           |  |  | 227 |      * Hide loading placeholder.
 | 
        
           |  |  | 228 |      *
 | 
        
           |  |  | 229 |      * @param {Object} body Search body container element.
 | 
        
           |  |  | 230 |      */
 | 
        
           |  |  | 231 |     var hideLoadingPlaceholder = function(body) {
 | 
        
           |  |  | 232 |         getLoadingPlaceholder(body).addClass('hidden');
 | 
        
           |  |  | 233 |     };
 | 
        
           |  |  | 234 |   | 
        
           |  |  | 235 |     /**
 | 
        
           |  |  | 236 |      * Show search icon.
 | 
        
           |  |  | 237 |      *
 | 
        
           |  |  | 238 |      * @param {Object} header Search header container element.
 | 
        
           |  |  | 239 |      */
 | 
        
           |  |  | 240 |     var showSearchIcon = function(header) {
 | 
        
           |  |  | 241 |         getSearchIconContainer(header).removeClass('hidden');
 | 
        
           |  |  | 242 |     };
 | 
        
           |  |  | 243 |   | 
        
           |  |  | 244 |     /**
 | 
        
           |  |  | 245 |      * Hide search icon.
 | 
        
           |  |  | 246 |      *
 | 
        
           |  |  | 247 |      * @param {Object} header Search header container element.
 | 
        
           |  |  | 248 |      */
 | 
        
           |  |  | 249 |     var hideSearchIcon = function(header) {
 | 
        
           |  |  | 250 |         getSearchIconContainer(header).addClass('hidden');
 | 
        
           |  |  | 251 |     };
 | 
        
           |  |  | 252 |   | 
        
           |  |  | 253 |     /**
 | 
        
           |  |  | 254 |      * Show search results.
 | 
        
           |  |  | 255 |      *
 | 
        
           |  |  | 256 |      * @param {Object} body Search body container element.
 | 
        
           |  |  | 257 |      */
 | 
        
           |  |  | 258 |     var showSearchResults = function(body) {
 | 
        
           |  |  | 259 |         getSearchResultsContainer(body).removeClass('hidden');
 | 
        
           |  |  | 260 |     };
 | 
        
           |  |  | 261 |   | 
        
           |  |  | 262 |     /**
 | 
        
           |  |  | 263 |      * Hide search results.
 | 
        
           |  |  | 264 |      *
 | 
        
           |  |  | 265 |      * @param {Object} body Search body container element.
 | 
        
           |  |  | 266 |      */
 | 
        
           |  |  | 267 |     var hideSearchResults = function(body) {
 | 
        
           |  |  | 268 |         getSearchResultsContainer(body).addClass('hidden');
 | 
        
           |  |  | 269 |     };
 | 
        
           |  |  | 270 |   | 
        
           |  |  | 271 |     /**
 | 
        
           |  |  | 272 |      * Show the no search results message.
 | 
        
           |  |  | 273 |      *
 | 
        
           |  |  | 274 |      * @param {Object} body Search body container element.
 | 
        
           |  |  | 275 |      */
 | 
        
           |  |  | 276 |     var showNoSearchResults = function(body) {
 | 
        
           |  |  | 277 |         var container = getSearchResultsContainer(body);
 | 
        
           |  |  | 278 |         container.find(SELECTORS.ALL_CONTACTS_CONTAINER).addClass('hidden');
 | 
        
           |  |  | 279 |         container.find(SELECTORS.MESSAGES_CONTAINER).addClass('hidden');
 | 
        
           |  |  | 280 |         container.find(SELECTORS.NO_RESULTS_CONTAINTER).removeClass('hidden');
 | 
        
           |  |  | 281 |     };
 | 
        
           |  |  | 282 |   | 
        
           |  |  | 283 |     /**
 | 
        
           |  |  | 284 |      * Hide the no search results message.
 | 
        
           |  |  | 285 |      *
 | 
        
           |  |  | 286 |      * @param {Object} body Search body container element.
 | 
        
           |  |  | 287 |      */
 | 
        
           |  |  | 288 |     var hideNoSearchResults = function(body) {
 | 
        
           |  |  | 289 |         var container = getSearchResultsContainer(body);
 | 
        
           |  |  | 290 |         container.find(SELECTORS.ALL_CONTACTS_CONTAINER).removeClass('hidden');
 | 
        
           |  |  | 291 |         container.find(SELECTORS.MESSAGES_CONTAINER).removeClass('hidden');
 | 
        
           |  |  | 292 |         container.find(SELECTORS.NO_RESULTS_CONTAINTER).addClass('hidden');
 | 
        
           |  |  | 293 |     };
 | 
        
           |  |  | 294 |   | 
        
           |  |  | 295 |     /**
 | 
        
           |  |  | 296 |      * Show the whole contacts results area.
 | 
        
           |  |  | 297 |      *
 | 
        
           |  |  | 298 |      * @param {Object} body Search body container element.
 | 
        
           |  |  | 299 |      */
 | 
        
           |  |  | 300 |     var showAllContactsSearchResults = function(body) {
 | 
        
           |  |  | 301 |         var container = getSearchResultsContainer(body);
 | 
        
           |  |  | 302 |         container.find(SELECTORS.ALL_CONTACTS_CONTAINER).removeClass('hidden');
 | 
        
           |  |  | 303 |     };
 | 
        
           |  |  | 304 |   | 
        
           |  |  | 305 |     /**
 | 
        
           |  |  | 306 |      * Hide the whole contacts results area.
 | 
        
           |  |  | 307 |      *
 | 
        
           |  |  | 308 |      * @param {Object} body Search body container element.
 | 
        
           |  |  | 309 |      */
 | 
        
           |  |  | 310 |     var hideAllContactsSearchResults = function(body) {
 | 
        
           |  |  | 311 |         var container = getSearchResultsContainer(body);
 | 
        
           |  |  | 312 |         container.find(SELECTORS.ALL_CONTACTS_CONTAINER).addClass('hidden');
 | 
        
           |  |  | 313 |     };
 | 
        
           |  |  | 314 |   | 
        
           |  |  | 315 |     /**
 | 
        
           |  |  | 316 |      * Show the contacts results.
 | 
        
           |  |  | 317 |      *
 | 
        
           |  |  | 318 |      * @param {Object} body Search body container element.
 | 
        
           |  |  | 319 |      */
 | 
        
           |  |  | 320 |     var showContactsSearchResults = function(body) {
 | 
        
           |  |  | 321 |         var container = getSearchResultsContainer(body);
 | 
        
           |  |  | 322 |         container.find(SELECTORS.CONTACTS_CONTAINER).removeClass('hidden');
 | 
        
           |  |  | 323 |     };
 | 
        
           |  |  | 324 |   | 
        
           |  |  | 325 |     /**
 | 
        
           |  |  | 326 |      * Hide the contacts results.
 | 
        
           |  |  | 327 |      *
 | 
        
           |  |  | 328 |      * @param {Object} body Search body container element.
 | 
        
           |  |  | 329 |      */
 | 
        
           |  |  | 330 |     var hideContactsSearchResults = function(body) {
 | 
        
           |  |  | 331 |         var container = getSearchResultsContainer(body);
 | 
        
           |  |  | 332 |         container.find(SELECTORS.CONTACTS_CONTAINER).addClass('hidden');
 | 
        
           |  |  | 333 |     };
 | 
        
           |  |  | 334 |   | 
        
           |  |  | 335 |     /**
 | 
        
           |  |  | 336 |      * Show the non contacts results.
 | 
        
           |  |  | 337 |      *
 | 
        
           |  |  | 338 |      * @param {Object} body Search body container element.
 | 
        
           |  |  | 339 |      */
 | 
        
           |  |  | 340 |     var showNonContactsSearchResults = function(body) {
 | 
        
           |  |  | 341 |         var container = getSearchResultsContainer(body);
 | 
        
           |  |  | 342 |         container.find(SELECTORS.NON_CONTACTS_CONTAINER).removeClass('hidden');
 | 
        
           |  |  | 343 |     };
 | 
        
           |  |  | 344 |   | 
        
           |  |  | 345 |     /**
 | 
        
           |  |  | 346 |      * Hide the non contacts results.
 | 
        
           |  |  | 347 |      *
 | 
        
           |  |  | 348 |      * @param {Object} body Search body container element.
 | 
        
           |  |  | 349 |      */
 | 
        
           |  |  | 350 |     var hideNonContactsSearchResults = function(body) {
 | 
        
           |  |  | 351 |         var container = getSearchResultsContainer(body);
 | 
        
           |  |  | 352 |         container.find(SELECTORS.NON_CONTACTS_CONTAINER).addClass('hidden');
 | 
        
           |  |  | 353 |     };
 | 
        
           |  |  | 354 |   | 
        
           |  |  | 355 |     /**
 | 
        
           |  |  | 356 |      * Show the messages results.
 | 
        
           |  |  | 357 |      *
 | 
        
           |  |  | 358 |      * @param {Object} body Search body container element.
 | 
        
           |  |  | 359 |      */
 | 
        
           |  |  | 360 |     var showMessagesSearchResults = function(body) {
 | 
        
           |  |  | 361 |         var container = getSearchResultsContainer(body);
 | 
        
           |  |  | 362 |         container.find(SELECTORS.MESSAGES_CONTAINER).removeClass('hidden');
 | 
        
           |  |  | 363 |     };
 | 
        
           |  |  | 364 |   | 
        
           |  |  | 365 |     /**
 | 
        
           |  |  | 366 |      * Hide the messages results.
 | 
        
           |  |  | 367 |      *
 | 
        
           |  |  | 368 |      * @param {Object} body Search body container element.
 | 
        
           |  |  | 369 |      */
 | 
        
           |  |  | 370 |     var hideMessagesSearchResults = function(body) {
 | 
        
           |  |  | 371 |         var container = getSearchResultsContainer(body);
 | 
        
           |  |  | 372 |         container.find(SELECTORS.MESSAGES_CONTAINER).addClass('hidden');
 | 
        
           |  |  | 373 |     };
 | 
        
           |  |  | 374 |   | 
        
           |  |  | 375 |     /**
 | 
        
           |  |  | 376 |      * Disable the search input.
 | 
        
           |  |  | 377 |      *
 | 
        
           |  |  | 378 |      * @param {Object} header Search header container element.
 | 
        
           |  |  | 379 |      */
 | 
        
           |  |  | 380 |     var disableSearchInput = function(header) {
 | 
        
           |  |  | 381 |         getSearchInput(header).prop('disabled', true);
 | 
        
           |  |  | 382 |     };
 | 
        
           |  |  | 383 |   | 
        
           |  |  | 384 |     /**
 | 
        
           |  |  | 385 |      * Enable the search input.
 | 
        
           |  |  | 386 |      *
 | 
        
           |  |  | 387 |      * @param {Object} header Search header container element.
 | 
        
           |  |  | 388 |      */
 | 
        
           |  |  | 389 |     var enableSearchInput = function(header) {
 | 
        
           |  |  | 390 |         getSearchInput(header).prop('disabled', false);
 | 
        
           |  |  | 391 |     };
 | 
        
           |  |  | 392 |   | 
        
           |  |  | 393 |     /**
 | 
        
           |  |  | 394 |      * Clear the search input.
 | 
        
           |  |  | 395 |      *
 | 
        
           |  |  | 396 |      * @param {Object} header Search header container element.
 | 
        
           |  |  | 397 |      */
 | 
        
           |  |  | 398 |     var clearSearchInput = function(header) {
 | 
        
           |  |  | 399 |         getSearchInput(header).val('');
 | 
        
           |  |  | 400 |     };
 | 
        
           |  |  | 401 |   | 
        
           |  |  | 402 |     /**
 | 
        
           |  |  | 403 |      * Clear all search results
 | 
        
           |  |  | 404 |      *
 | 
        
           |  |  | 405 |      * @param {Object} body Search body container element.
 | 
        
           |  |  | 406 |      */
 | 
        
           |  |  | 407 |     var clearAllSearchResults = function(body) {
 | 
        
           |  |  | 408 |         body.find(SELECTORS.CONTACTS_LIST).empty();
 | 
        
           |  |  | 409 |         body.find(SELECTORS.NON_CONTACTS_LIST).empty();
 | 
        
           |  |  | 410 |         body.find(SELECTORS.MESSAGES_LIST).empty();
 | 
        
           |  |  | 411 |         hideNoSearchResults(body);
 | 
        
           |  |  | 412 |         showAllContactsSearchResults(body);
 | 
        
           |  |  | 413 |         showContactsSearchResults(body);
 | 
        
           |  |  | 414 |         showNonContactsSearchResults(body);
 | 
        
           |  |  | 415 |         showMessagesSearchResults(body);
 | 
        
           |  |  | 416 |         showLoadMoreUsersButton(body);
 | 
        
           |  |  | 417 |         showLoadMoreMessagesButton(body);
 | 
        
           |  |  | 418 |     };
 | 
        
           |  |  | 419 |   | 
        
           |  |  | 420 |     /**
 | 
        
           |  |  | 421 |      * Update the body and header to indicate the search is loading.
 | 
        
           |  |  | 422 |      *
 | 
        
           |  |  | 423 |      * @param {Object} header Search header container element.
 | 
        
           |  |  | 424 |      * @param {Object} body Search body container element.
 | 
        
           |  |  | 425 |      */
 | 
        
           |  |  | 426 |     var startLoading = function(header, body) {
 | 
        
           |  |  | 427 |         hideSearchIcon(header);
 | 
        
           |  |  | 428 |         hideEmptyMessage(body);
 | 
        
           |  |  | 429 |         hideSearchResults(body);
 | 
        
           |  |  | 430 |         showLoadingIcon(header);
 | 
        
           |  |  | 431 |         showLoadingPlaceholder(body);
 | 
        
           |  |  | 432 |         disableSearchInput(header);
 | 
        
           |  |  | 433 |     };
 | 
        
           |  |  | 434 |   | 
        
           |  |  | 435 |     /**
 | 
        
           |  |  | 436 |      * Update the body and header to indicate the search has stopped loading.
 | 
        
           |  |  | 437 |      *
 | 
        
           |  |  | 438 |      * @param {Object} header Search header container element.
 | 
        
           |  |  | 439 |      * @param {Object} body Search body container element.
 | 
        
           |  |  | 440 |      */
 | 
        
           |  |  | 441 |     var stopLoading = function(header, body) {
 | 
        
           |  |  | 442 |         showSearchIcon(header);
 | 
        
           |  |  | 443 |         hideEmptyMessage(body);
 | 
        
           |  |  | 444 |         showSearchResults(body);
 | 
        
           |  |  | 445 |         hideLoadingIcon(header);
 | 
        
           |  |  | 446 |         hideLoadingPlaceholder(body);
 | 
        
           |  |  | 447 |         enableSearchInput(header);
 | 
        
           |  |  | 448 |     };
 | 
        
           |  |  | 449 |   | 
        
           |  |  | 450 |     /**
 | 
        
           |  |  | 451 |      * Show the more users loading icon.
 | 
        
           |  |  | 452 |      *
 | 
        
           |  |  | 453 |      * @param {Object} root The more users container element.
 | 
        
           |  |  | 454 |      */
 | 
        
           |  |  | 455 |     var showUsersLoadingIcon = function(root) {
 | 
        
           |  |  | 456 |         var button = root.find(SELECTORS.LOAD_MORE_USERS);
 | 
        
           |  |  | 457 |         button.prop('disabled', true);
 | 
        
           |  |  | 458 |         button.find(SELECTORS.BUTTON_TEXT).addClass('hidden');
 | 
        
           |  |  | 459 |         button.find(SELECTORS.LOADING_ICON_CONTAINER).removeClass('hidden');
 | 
        
           |  |  | 460 |     };
 | 
        
           |  |  | 461 |   | 
        
           |  |  | 462 |     /**
 | 
        
           |  |  | 463 |      * Hide the more users loading icon.
 | 
        
           |  |  | 464 |      *
 | 
        
           |  |  | 465 |      * @param {Object} root The more users container element.
 | 
        
           |  |  | 466 |      */
 | 
        
           |  |  | 467 |     var hideUsersLoadingIcon = function(root) {
 | 
        
           |  |  | 468 |         var button = root.find(SELECTORS.LOAD_MORE_USERS);
 | 
        
           |  |  | 469 |         button.prop('disabled', false);
 | 
        
           |  |  | 470 |         button.find(SELECTORS.BUTTON_TEXT).removeClass('hidden');
 | 
        
           |  |  | 471 |         button.find(SELECTORS.LOADING_ICON_CONTAINER).addClass('hidden');
 | 
        
           |  |  | 472 |     };
 | 
        
           |  |  | 473 |   | 
        
           |  |  | 474 |     /**
 | 
        
           |  |  | 475 |      * Show the load more users button.
 | 
        
           |  |  | 476 |      *
 | 
        
           |  |  | 477 |      * @param {Object} root The users container element.
 | 
        
           |  |  | 478 |      */
 | 
        
           |  |  | 479 |     var showLoadMoreUsersButton = function(root) {
 | 
        
           |  |  | 480 |         root.find(SELECTORS.LOAD_MORE_USERS).removeClass('hidden');
 | 
        
           |  |  | 481 |     };
 | 
        
           |  |  | 482 |   | 
        
           |  |  | 483 |     /**
 | 
        
           |  |  | 484 |      * Hide the load more users button.
 | 
        
           |  |  | 485 |      *
 | 
        
           |  |  | 486 |      * @param {Object} root The users container element.
 | 
        
           |  |  | 487 |      */
 | 
        
           |  |  | 488 |     var hideLoadMoreUsersButton = function(root) {
 | 
        
           |  |  | 489 |         root.find(SELECTORS.LOAD_MORE_USERS).addClass('hidden');
 | 
        
           |  |  | 490 |     };
 | 
        
           |  |  | 491 |   | 
        
           |  |  | 492 |     /**
 | 
        
           |  |  | 493 |      * Show the messages are loading icon.
 | 
        
           |  |  | 494 |      *
 | 
        
           |  |  | 495 |      * @param {Object} root Messages root element.
 | 
        
           |  |  | 496 |      */
 | 
        
           |  |  | 497 |     var showMessagesLoadingIcon = function(root) {
 | 
        
           |  |  | 498 |         var button = root.find(SELECTORS.LOAD_MORE_MESSAGES);
 | 
        
           |  |  | 499 |         button.prop('disabled', true);
 | 
        
           |  |  | 500 |         button.find(SELECTORS.BUTTON_TEXT).addClass('hidden');
 | 
        
           |  |  | 501 |         button.find(SELECTORS.LOADING_ICON_CONTAINER).removeClass('hidden');
 | 
        
           |  |  | 502 |     };
 | 
        
           |  |  | 503 |   | 
        
           |  |  | 504 |     /**
 | 
        
           |  |  | 505 |      * Hide the messages are loading icon.
 | 
        
           |  |  | 506 |      *
 | 
        
           |  |  | 507 |      * @param {Object} root Messages root element.
 | 
        
           |  |  | 508 |      */
 | 
        
           |  |  | 509 |     var hideMessagesLoadingIcon = function(root) {
 | 
        
           |  |  | 510 |         var button = root.find(SELECTORS.LOAD_MORE_MESSAGES);
 | 
        
           |  |  | 511 |         button.prop('disabled', false);
 | 
        
           |  |  | 512 |         button.find(SELECTORS.BUTTON_TEXT).removeClass('hidden');
 | 
        
           |  |  | 513 |         button.find(SELECTORS.LOADING_ICON_CONTAINER).addClass('hidden');
 | 
        
           |  |  | 514 |     };
 | 
        
           |  |  | 515 |   | 
        
           |  |  | 516 |     /**
 | 
        
           |  |  | 517 |      * Show the load more messages button.
 | 
        
           |  |  | 518 |      *
 | 
        
           |  |  | 519 |      * @param  {Object} root The messages container element.
 | 
        
           |  |  | 520 |      */
 | 
        
           |  |  | 521 |     var showLoadMoreMessagesButton = function(root) {
 | 
        
           |  |  | 522 |         root.find(SELECTORS.LOAD_MORE_MESSAGES).removeClass('hidden');
 | 
        
           |  |  | 523 |     };
 | 
        
           |  |  | 524 |   | 
        
           |  |  | 525 |     /**
 | 
        
           |  |  | 526 |      * Hide the load more messages button.
 | 
        
           |  |  | 527 |      *
 | 
        
           |  |  | 528 |      * @param  {Object} root The messages container element.
 | 
        
           |  |  | 529 |      */
 | 
        
           |  |  | 530 |     var hideLoadMoreMessagesButton = function(root) {
 | 
        
           |  |  | 531 |         root.find(SELECTORS.LOAD_MORE_MESSAGES).addClass('hidden');
 | 
        
           |  |  | 532 |     };
 | 
        
           |  |  | 533 |   | 
        
           |  |  | 534 |     /**
 | 
        
           |  |  | 535 |      * Find a contact in the search results.
 | 
        
           |  |  | 536 |      *
 | 
        
           |  |  | 537 |      * @param  {Object} root Search results container element.
 | 
        
           |  |  | 538 |      * @param  {Number} userId User id.
 | 
        
           |  |  | 539 |      * @return {Object} User container element.
 | 
        
           |  |  | 540 |      */
 | 
        
           |  |  | 541 |     var findContact = function(root, userId) {
 | 
        
           |  |  | 542 |         return root.find('[data-contact-user-id="' + userId + '"]');
 | 
        
           |  |  | 543 |     };
 | 
        
           |  |  | 544 |   | 
        
           |  |  | 545 |     /**
 | 
        
           |  |  | 546 |      * Add a contact to the search results.
 | 
        
           |  |  | 547 |      *
 | 
        
           |  |  | 548 |      * @param {Object} root Search results container.
 | 
        
           |  |  | 549 |      * @param {Object} contact User in contacts list.
 | 
        
           |  |  | 550 |      */
 | 
        
           |  |  | 551 |     var addContact = function(root, contact) {
 | 
        
           |  |  | 552 |         var nonContactsContainer = getNonContactsContainer(root);
 | 
        
           |  |  | 553 |         var nonContact = findContact(nonContactsContainer, contact.userid);
 | 
        
           |  |  | 554 |   | 
        
           |  |  | 555 |         if (nonContact.length) {
 | 
        
           |  |  | 556 |             nonContact.remove();
 | 
        
           |  |  | 557 |             var contactsContainer = getContactsContainer(root);
 | 
        
           |  |  | 558 |             contactsContainer.removeClass('hidden');
 | 
        
           |  |  | 559 |             contactsContainer.find(SELECTORS.LIST).append(nonContact);
 | 
        
           |  |  | 560 |         }
 | 
        
           |  |  | 561 |   | 
        
           |  |  | 562 |         if (!nonContactsContainer.find(SELECTORS.LIST).children().length) {
 | 
        
           |  |  | 563 |             nonContactsContainer.addClass('hidden');
 | 
        
           |  |  | 564 |         }
 | 
        
           |  |  | 565 |     };
 | 
        
           |  |  | 566 |   | 
        
           |  |  | 567 |     /**
 | 
        
           |  |  | 568 |      * Remove a contact from the contacts results.
 | 
        
           |  |  | 569 |      *
 | 
        
           |  |  | 570 |      * @param {Object} root Search results container.
 | 
        
           |  |  | 571 |      * @param {Object} userId Contact user id.
 | 
        
           |  |  | 572 |      */
 | 
        
           |  |  | 573 |     var removeContact = function(root, userId) {
 | 
        
           |  |  | 574 |         var contactsContainer = getContactsContainer(root);
 | 
        
           |  |  | 575 |         var contact = findContact(contactsContainer, userId);
 | 
        
           |  |  | 576 |   | 
        
           |  |  | 577 |         if (contact.length) {
 | 
        
           |  |  | 578 |             contact.remove();
 | 
        
           |  |  | 579 |             var nonContactsContainer = getNonContactsContainer(root);
 | 
        
           |  |  | 580 |             nonContactsContainer.removeClass('hidden');
 | 
        
           |  |  | 581 |             nonContactsContainer.find(SELECTORS.LIST).append(contact);
 | 
        
           |  |  | 582 |         }
 | 
        
           |  |  | 583 |   | 
        
           |  |  | 584 |         if (!contactsContainer.find(SELECTORS.LIST).children().length) {
 | 
        
           |  |  | 585 |             contactsContainer.addClass('hidden');
 | 
        
           |  |  | 586 |         }
 | 
        
           |  |  | 587 |     };
 | 
        
           |  |  | 588 |   | 
        
           |  |  | 589 |     /**
 | 
        
           |  |  | 590 |      * Show the contact is blocked icon.
 | 
        
           |  |  | 591 |      *
 | 
        
           |  |  | 592 |      * @param {Object} root Search results container.
 | 
        
           |  |  | 593 |      * @param {Object} userId Contact user id.
 | 
        
           |  |  | 594 |      */
 | 
        
           |  |  | 595 |     var blockContact = function(root, userId) {
 | 
        
           |  |  | 596 |         var contact = findContact(root, userId);
 | 
        
           |  |  | 597 |         if (contact.length) {
 | 
        
           |  |  | 598 |             contact.find(SELECTORS.BLOCK_ICON_CONTAINER).removeClass('hidden');
 | 
        
           |  |  | 599 |         }
 | 
        
           |  |  | 600 |     };
 | 
        
           |  |  | 601 |   | 
        
           |  |  | 602 |     /**
 | 
        
           |  |  | 603 |      * Hide the contact is blocked icon.
 | 
        
           |  |  | 604 |      *
 | 
        
           |  |  | 605 |      * @param {Object} root Search results container.
 | 
        
           |  |  | 606 |      * @param {Object} userId Contact user id.
 | 
        
           |  |  | 607 |      */
 | 
        
           |  |  | 608 |     var unblockContact = function(root, userId) {
 | 
        
           |  |  | 609 |         var contact = findContact(root, userId);
 | 
        
           |  |  | 610 |         if (contact.length) {
 | 
        
           |  |  | 611 |             contact.find(SELECTORS.BLOCK_ICON_CONTAINER).addClass('hidden');
 | 
        
           |  |  | 612 |         }
 | 
        
           |  |  | 613 |     };
 | 
        
           |  |  | 614 |   | 
        
           |  |  | 615 |     /**
 | 
        
           |  |  | 616 |      * Highlight words in search results.
 | 
        
           |  |  | 617 |      *
 | 
        
           |  |  | 618 |      * @param  {String} content HTML to search.
 | 
        
           |  |  | 619 |      * @param  {String} searchText Search text.
 | 
        
           |  |  | 620 |      * @return {String} searchText with search wrapped in matchtext span.
 | 
        
           |  |  | 621 |      */
 | 
        
           |  |  | 622 |     var highlightSearch = function(content, searchText) {
 | 
        
           |  |  | 623 |         if (!content) {
 | 
        
           |  |  | 624 |             return '';
 | 
        
           |  |  | 625 |         }
 | 
        
           |  |  | 626 |         var regex = new RegExp('(' + searchText + ')', 'gi');
 | 
        
           |  |  | 627 |         return content.replace(regex, '<span class="matchtext">$1</span>');
 | 
        
           |  |  | 628 |     };
 | 
        
           |  |  | 629 |   | 
        
           |  |  | 630 |   | 
        
           |  |  | 631 |     /**
 | 
        
           |  |  | 632 |      * Render contacts in the contacts search results.
 | 
        
           |  |  | 633 |      *
 | 
        
           |  |  | 634 |      * @param {Object} root Search results container.
 | 
        
           |  |  | 635 |      * @param {Array} contacts List of contacts.
 | 
        
           |  |  | 636 |      * @return {Promise} Renderer promise.
 | 
        
           |  |  | 637 |      */
 | 
        
           |  |  | 638 |     var renderContacts = function(root, contacts) {
 | 
        
           |  |  | 639 |         var container = getContactsContainer(root);
 | 
        
           |  |  | 640 |         var frompanel = root.attr('data-in-panel');
 | 
        
           |  |  | 641 |         var list = container.find(SELECTORS.LIST);
 | 
        
           |  |  | 642 |   | 
        
           |  |  | 643 |         return Templates.render(TEMPLATES.CONTACTS_LIST, {contacts: contacts, frompanel: frompanel})
 | 
        
           |  |  | 644 |             .then(function(html) {
 | 
        
           |  |  | 645 |                 list.append(html);
 | 
        
           |  |  | 646 |                 return html;
 | 
        
           |  |  | 647 |             });
 | 
        
           |  |  | 648 |     };
 | 
        
           |  |  | 649 |   | 
        
           |  |  | 650 |     /**
 | 
        
           |  |  | 651 |      * Render non contacts in the contacts search results.
 | 
        
           |  |  | 652 |      *
 | 
        
           |  |  | 653 |      * @param {Object} root Search results container.
 | 
        
           |  |  | 654 |      * @param {Array} nonContacts List of non contacts.
 | 
        
           |  |  | 655 |      * @return {Promise} Renderer promise.
 | 
        
           |  |  | 656 |      */
 | 
        
           |  |  | 657 |     var renderNonContacts = function(root, nonContacts) {
 | 
        
           |  |  | 658 |         var container = getNonContactsContainer(root);
 | 
        
           |  |  | 659 |         var frompanel = root.attr('data-in-panel');
 | 
        
           |  |  | 660 |         var list = container.find(SELECTORS.LIST);
 | 
        
           |  |  | 661 |   | 
        
           |  |  | 662 |         return Templates.render(TEMPLATES.NON_CONTACTS_LIST, {noncontacts: nonContacts, frompanel: frompanel})
 | 
        
           |  |  | 663 |             .then(function(html) {
 | 
        
           |  |  | 664 |                 list.append(html);
 | 
        
           |  |  | 665 |                 return html;
 | 
        
           |  |  | 666 |             });
 | 
        
           |  |  | 667 |     };
 | 
        
           |  |  | 668 |   | 
        
           |  |  | 669 |     /**
 | 
        
           |  |  | 670 |      * Render messages in the messages search results.
 | 
        
           |  |  | 671 |      *
 | 
        
           |  |  | 672 |      * @param {Object} root Search results container.
 | 
        
           |  |  | 673 |      * @param {Array} messages List of messages.
 | 
        
           |  |  | 674 |      * @return {Promise} Renderer promise.
 | 
        
           |  |  | 675 |      */
 | 
        
           |  |  | 676 |     var renderMessages = function(root, messages) {
 | 
        
           |  |  | 677 |         var container = getMessagesContainer(root);
 | 
        
           |  |  | 678 |         var frompanel = root.attr('data-in-panel');
 | 
        
           |  |  | 679 |         var list = container.find(SELECTORS.LIST);
 | 
        
           |  |  | 680 |   | 
        
           |  |  | 681 |         return Templates.render(TEMPLATES.MESSAGES_LIST, {messages: messages, frompanel: frompanel})
 | 
        
           |  |  | 682 |             .then(function(html) {
 | 
        
           |  |  | 683 |                 list.append(html);
 | 
        
           |  |  | 684 |                 return html;
 | 
        
           |  |  | 685 |             });
 | 
        
           |  |  | 686 |     };
 | 
        
           |  |  | 687 |   | 
        
           |  |  | 688 |     /**
 | 
        
           |  |  | 689 |      * Load more users from the repository and render the results into the users search results.
 | 
        
           |  |  | 690 |      *
 | 
        
           |  |  | 691 |      * @param  {Object} root Search results container.
 | 
        
           |  |  | 692 |      * @param  {Number} loggedInUserId Current logged in user.
 | 
        
           |  |  | 693 |      * @param  {String} text Search text.
 | 
        
           |  |  | 694 |      * @param  {Number} limit Number of users to get.
 | 
        
           |  |  | 695 |      * @param  {Number} offset Load users from
 | 
        
           |  |  | 696 |      * @return {Object} jQuery promise
 | 
        
           |  |  | 697 |      */
 | 
        
           |  |  | 698 |     var loadMoreUsers = function(root, loggedInUserId, text, limit, offset) {
 | 
        
           |  |  | 699 |         var loadedAll = false;
 | 
        
           |  |  | 700 |         showUsersLoadingIcon(root);
 | 
        
           |  |  | 701 |   | 
        
           |  |  | 702 |         return Repository.searchUsers(loggedInUserId, text, limit + 1, offset)
 | 
        
           |  |  | 703 |             .then(function(results) {
 | 
        
           |  |  | 704 |                 var contacts = results.contacts;
 | 
        
           |  |  | 705 |                 var noncontacts = results.noncontacts;
 | 
        
           |  |  | 706 |   | 
        
           |  |  | 707 |                 if (contacts.length <= limit && noncontacts.length <= limit) {
 | 
        
           |  |  | 708 |                     loadedAll = true;
 | 
        
           |  |  | 709 |                     return {
 | 
        
           |  |  | 710 |                         contacts: contacts,
 | 
        
           |  |  | 711 |                         noncontacts: noncontacts
 | 
        
           |  |  | 712 |                     };
 | 
        
           |  |  | 713 |                 } else {
 | 
        
           |  |  | 714 |                     return {
 | 
        
           |  |  | 715 |                         contacts: contacts.slice(0, limit),
 | 
        
           |  |  | 716 |                         noncontacts: noncontacts.slice(0, limit)
 | 
        
           |  |  | 717 |                     };
 | 
        
           |  |  | 718 |                 }
 | 
        
           |  |  | 719 |             })
 | 
        
           |  |  | 720 |             .then(function(results) {
 | 
        
           |  |  | 721 |                 var contactsCount = results.contacts.length;
 | 
        
           |  |  | 722 |                 var nonContactsCount = results.noncontacts.length;
 | 
        
           |  |  | 723 |   | 
        
           |  |  | 724 |                 if (contactsCount) {
 | 
        
           |  |  | 725 |                     results.contacts.forEach(function(contact) {
 | 
        
           |  |  | 726 |                         contact.highlight = highlightSearch(contact.fullname, text);
 | 
        
           |  |  | 727 |                     });
 | 
        
           |  |  | 728 |                 }
 | 
        
           |  |  | 729 |   | 
        
           |  |  | 730 |                 if (nonContactsCount) {
 | 
        
           |  |  | 731 |                     results.noncontacts.forEach(function(contact) {
 | 
        
           |  |  | 732 |                         contact.highlight = highlightSearch(contact.fullname, text);
 | 
        
           |  |  | 733 |                     });
 | 
        
           |  |  | 734 |                 }
 | 
        
           |  |  | 735 |   | 
        
           |  |  | 736 |                 return $.when(
 | 
        
           |  |  | 737 |                     contactsCount ? renderContacts(root, results.contacts) : true,
 | 
        
           |  |  | 738 |                     nonContactsCount ? renderNonContacts(root, results.noncontacts) : true
 | 
        
           |  |  | 739 |                 )
 | 
        
           |  |  | 740 |                 .then(function() {
 | 
        
           |  |  | 741 |                     return {
 | 
        
           |  |  | 742 |                         contactsCount: contactsCount,
 | 
        
           |  |  | 743 |                         nonContactsCount: nonContactsCount
 | 
        
           |  |  | 744 |                     };
 | 
        
           |  |  | 745 |                 });
 | 
        
           |  |  | 746 |             })
 | 
        
           |  |  | 747 |             .then(function(counts) {
 | 
        
           |  |  | 748 |                 hideUsersLoadingIcon(root);
 | 
        
           |  |  | 749 |   | 
        
           |  |  | 750 |                 if (loadedAll) {
 | 
        
           |  |  | 751 |                     hideLoadMoreUsersButton(root);
 | 
        
           |  |  | 752 |                 }
 | 
        
           |  |  | 753 |   | 
        
           |  |  | 754 |                 return counts;
 | 
        
           |  |  | 755 |             })
 | 
        
           |  |  | 756 |             .catch(function(error) {
 | 
        
           |  |  | 757 |                 hideUsersLoadingIcon(root);
 | 
        
           |  |  | 758 |                 // Rethrow error for other handlers.
 | 
        
           |  |  | 759 |                 throw error;
 | 
        
           |  |  | 760 |             });
 | 
        
           |  |  | 761 |     };
 | 
        
           |  |  | 762 |   | 
        
           |  |  | 763 |     /**
 | 
        
           |  |  | 764 |      * Load more messages from the repository and render the results into the messages search results.
 | 
        
           |  |  | 765 |      *
 | 
        
           |  |  | 766 |      * @param  {Object} root Search results container.
 | 
        
           |  |  | 767 |      * @param  {Number} loggedInUserId Current logged in user.
 | 
        
           |  |  | 768 |      * @param  {String} text Search text.
 | 
        
           |  |  | 769 |      * @param  {Number} limit Number of messages to get.
 | 
        
           |  |  | 770 |      * @param  {Number} offset Load messages from
 | 
        
           |  |  | 771 |      * @return {Object} jQuery promise
 | 
        
           |  |  | 772 |      */
 | 
        
           |  |  | 773 |     var loadMoreMessages = function(root, loggedInUserId, text, limit, offset) {
 | 
        
           |  |  | 774 |         var loadedAll = false;
 | 
        
           |  |  | 775 |         showMessagesLoadingIcon(root);
 | 
        
           |  |  | 776 |   | 
        
           |  |  | 777 |         return Repository.searchMessages(loggedInUserId, text, limit + 1, offset)
 | 
        
           |  |  | 778 |             .then(function(results) {
 | 
        
           |  |  | 779 |                 var messages = results.contacts;
 | 
        
           |  |  | 780 |   | 
        
           |  |  | 781 |                 if (messages.length <= limit) {
 | 
        
           |  |  | 782 |                     loadedAll = true;
 | 
        
           |  |  | 783 |                     return messages;
 | 
        
           |  |  | 784 |                 } else {
 | 
        
           |  |  | 785 |                     return messages.slice(0, limit);
 | 
        
           |  |  | 786 |                 }
 | 
        
           |  |  | 787 |             })
 | 
        
           |  |  | 788 |             .then(function(messages) {
 | 
        
           |  |  | 789 |                 if (messages.length) {
 | 
        
           |  |  | 790 |                     messages.forEach(function(message) {
 | 
        
           |  |  | 791 |                         message.lastmessage = highlightSearch(message.lastmessage, text);
 | 
        
           |  |  | 792 |                     });
 | 
        
           |  |  | 793 |                     return renderMessages(root, messages)
 | 
        
           |  |  | 794 |                         .then(function() {
 | 
        
           |  |  | 795 |                             return messages.length;
 | 
        
           |  |  | 796 |                         });
 | 
        
           |  |  | 797 |                 } else {
 | 
        
           |  |  | 798 |                     return messages.length;
 | 
        
           |  |  | 799 |                 }
 | 
        
           |  |  | 800 |             })
 | 
        
           |  |  | 801 |             .then(function(count) {
 | 
        
           |  |  | 802 |                 hideMessagesLoadingIcon(root);
 | 
        
           |  |  | 803 |   | 
        
           |  |  | 804 |                 if (loadedAll) {
 | 
        
           |  |  | 805 |                     hideLoadMoreMessagesButton(root);
 | 
        
           |  |  | 806 |                 }
 | 
        
           |  |  | 807 |   | 
        
           |  |  | 808 |                 return count;
 | 
        
           |  |  | 809 |             })
 | 
        
           |  |  | 810 |             .catch(function(error) {
 | 
        
           |  |  | 811 |                 hideMessagesLoadingIcon(root);
 | 
        
           |  |  | 812 |                 // Rethrow error for other handlers.
 | 
        
           |  |  | 813 |                 throw error;
 | 
        
           |  |  | 814 |             });
 | 
        
           |  |  | 815 |     };
 | 
        
           |  |  | 816 |   | 
        
           |  |  | 817 |     /**
 | 
        
           |  |  | 818 |      * Search for users and messages.
 | 
        
           |  |  | 819 |      *
 | 
        
           |  |  | 820 |      * @param {Object} header Search header container element.
 | 
        
           |  |  | 821 |      * @param {Object} body Search body container element.
 | 
        
           |  |  | 822 |      * @param {String} searchText Search text.
 | 
        
           |  |  | 823 |      * @param {Number} usersLimit The users limit.
 | 
        
           |  |  | 824 |      * @param {Number} usersOffset The users offset.
 | 
        
           |  |  | 825 |      * @param {Number} messagesLimit The message limit.
 | 
        
           |  |  | 826 |      * @param {Number} messagesOffset The message offset.
 | 
        
           |  |  | 827 |      * @return {Object} jQuery promise
 | 
        
           |  |  | 828 |      */
 | 
        
           |  |  | 829 |     var search = function(header, body, searchText, usersLimit, usersOffset, messagesLimit, messagesOffset) {
 | 
        
           |  |  | 830 |         var loggedInUserId = getLoggedInUserId(body);
 | 
        
           |  |  | 831 |         startLoading(header, body);
 | 
        
           |  |  | 832 |         clearAllSearchResults(body);
 | 
        
           |  |  | 833 |   | 
        
           |  |  | 834 |         return $.when(
 | 
        
           |  |  | 835 |             loadMoreUsers(body, loggedInUserId, searchText, usersLimit, usersOffset),
 | 
        
           |  |  | 836 |             loadMoreMessages(body, loggedInUserId, searchText, messagesLimit, messagesOffset)
 | 
        
           |  |  | 837 |         )
 | 
        
           |  |  | 838 |         .then(function(userCounts, messagesCount) {
 | 
        
           |  |  | 839 |             var contactsCount = userCounts.contactsCount;
 | 
        
           |  |  | 840 |             var nonContactsCount = userCounts.nonContactsCount;
 | 
        
           |  |  | 841 |   | 
        
           |  |  | 842 |             stopLoading(header, body);
 | 
        
           |  |  | 843 |   | 
        
           |  |  | 844 |             if (!contactsCount && !nonContactsCount && !messagesCount) {
 | 
        
           |  |  | 845 |                 showNoSearchResults(body);
 | 
        
           |  |  | 846 |             } else {
 | 
        
           |  |  | 847 |                 if (!contactsCount && !nonContactsCount) {
 | 
        
           |  |  | 848 |                     hideAllContactsSearchResults(body);
 | 
        
           |  |  | 849 |                 } else {
 | 
        
           |  |  | 850 |                     if (!contactsCount) {
 | 
        
           |  |  | 851 |                         hideContactsSearchResults(body);
 | 
        
           |  |  | 852 |                     }
 | 
        
           |  |  | 853 |   | 
        
           |  |  | 854 |                     if (!nonContactsCount) {
 | 
        
           |  |  | 855 |                         hideNonContactsSearchResults(body);
 | 
        
           |  |  | 856 |                     }
 | 
        
           |  |  | 857 |                 }
 | 
        
           |  |  | 858 |   | 
        
           |  |  | 859 |                 if (!messagesCount) {
 | 
        
           |  |  | 860 |                     hideMessagesSearchResults(body);
 | 
        
           |  |  | 861 |                 }
 | 
        
           |  |  | 862 |             }
 | 
        
           |  |  | 863 |   | 
        
           |  |  | 864 |             return;
 | 
        
           |  |  | 865 |         });
 | 
        
           |  |  | 866 |     };
 | 
        
           |  |  | 867 |   | 
        
           |  |  | 868 |   | 
        
           |  |  | 869 |     /**
 | 
        
           |  |  | 870 |      * Listen to and handle events for searching.
 | 
        
           |  |  | 871 |      *
 | 
        
           |  |  | 872 |      * @param {Object} header Search header container element.
 | 
        
           |  |  | 873 |      * @param {Object} body Search body container element.
 | 
        
           |  |  | 874 |      */
 | 
        
           |  |  | 875 |     var registerEventListeners = function(header, body) {
 | 
        
           |  |  | 876 |         var loggedInUserId = getLoggedInUserId(body);
 | 
        
           |  |  | 877 |         var searchInput = getSearchInput(header);
 | 
        
           |  |  | 878 |         var searchText = '';
 | 
        
           |  |  | 879 |         var messagesOffset = 0;
 | 
        
           |  |  | 880 |         var usersOffset = 0;
 | 
        
           |  |  | 881 |   | 
        
           |  |  | 882 |         var searchEventHandler = function(e, data) {
 | 
        
           |  |  | 883 |             searchText = searchInput.val().trim();
 | 
        
           |  |  | 884 |   | 
        
           |  |  | 885 |             if (searchText !== '') {
 | 
        
           |  |  | 886 |                 messagesOffset = 0;
 | 
        
           |  |  | 887 |                 usersOffset = 0;
 | 
        
           |  |  | 888 |                 search(
 | 
        
           |  |  | 889 |                     header,
 | 
        
           |  |  | 890 |                     body,
 | 
        
           |  |  | 891 |                     searchText,
 | 
        
           |  |  | 892 |                     USERS_INITIAL_SEARCH_LIMIT,
 | 
        
           |  |  | 893 |                     usersOffset,
 | 
        
           |  |  | 894 |                     MESSAGE_SEARCH_LIMIT,
 | 
        
           |  |  | 895 |                     messagesOffset
 | 
        
           |  |  | 896 |                 )
 | 
        
           |  |  | 897 |                 .then(function() {
 | 
        
           |  |  | 898 |                     searchInput.focus();
 | 
        
           |  |  | 899 |                     usersOffset = usersOffset + USERS_INITIAL_SEARCH_LIMIT;
 | 
        
           |  |  | 900 |                     messagesOffset = messagesOffset + MESSAGE_SEARCH_LIMIT;
 | 
        
           |  |  | 901 |                     return;
 | 
        
           |  |  | 902 |                 })
 | 
        
           |  |  | 903 |                 .catch(Notification.exception);
 | 
        
           |  |  | 904 |             }
 | 
        
           |  |  | 905 |   | 
        
           |  |  | 906 |             data.originalEvent.preventDefault();
 | 
        
           |  |  | 907 |         };
 | 
        
           |  |  | 908 |   | 
        
           |  |  | 909 |         CustomEvents.define(searchInput, [CustomEvents.events.enter]);
 | 
        
           |  |  | 910 |         CustomEvents.define(header, [CustomEvents.events.activate]);
 | 
        
           |  |  | 911 |         CustomEvents.define(body, [CustomEvents.events.activate]);
 | 
        
           |  |  | 912 |   | 
        
           |  |  | 913 |         searchInput.on(CustomEvents.events.enter, searchEventHandler);
 | 
        
           |  |  | 914 |   | 
        
           |  |  | 915 |         header.on(CustomEvents.events.activate, SELECTORS.SEARCH_ACTION, searchEventHandler);
 | 
        
           |  |  | 916 |   | 
        
           |  |  | 917 |         body.on(CustomEvents.events.activate, SELECTORS.LOAD_MORE_MESSAGES, function(e, data) {
 | 
        
           |  |  | 918 |             if (searchText !== '') {
 | 
        
           |  |  | 919 |                 loadMoreMessages(body, loggedInUserId, searchText, MESSAGE_SEARCH_LIMIT, messagesOffset)
 | 
        
           |  |  | 920 |                     .then(function() {
 | 
        
           |  |  | 921 |                         messagesOffset = messagesOffset + MESSAGE_SEARCH_LIMIT;
 | 
        
           |  |  | 922 |                         return;
 | 
        
           |  |  | 923 |                     })
 | 
        
           |  |  | 924 |                     .catch(Notification.exception);
 | 
        
           |  |  | 925 |             }
 | 
        
           |  |  | 926 |             data.originalEvent.preventDefault();
 | 
        
           |  |  | 927 |         });
 | 
        
           |  |  | 928 |   | 
        
           |  |  | 929 |         body.on(CustomEvents.events.activate, SELECTORS.LOAD_MORE_USERS, function(e, data) {
 | 
        
           |  |  | 930 |             if (searchText !== '') {
 | 
        
           |  |  | 931 |                 loadMoreUsers(body, loggedInUserId, searchText, USERS_SEARCH_LIMIT, usersOffset)
 | 
        
           |  |  | 932 |                     .then(function() {
 | 
        
           |  |  | 933 |                         usersOffset = usersOffset + USERS_SEARCH_LIMIT;
 | 
        
           |  |  | 934 |                         return;
 | 
        
           |  |  | 935 |                     })
 | 
        
           |  |  | 936 |                     .catch(Notification.exception);
 | 
        
           |  |  | 937 |             }
 | 
        
           |  |  | 938 |             data.originalEvent.preventDefault();
 | 
        
           |  |  | 939 |         });
 | 
        
           |  |  | 940 |   | 
        
           |  |  | 941 |         header.on(CustomEvents.events.activate, SELECTORS.CANCEL_SEARCH_BUTTON, function() {
 | 
        
           |  |  | 942 |             clearSearchInput(header);
 | 
        
           |  |  | 943 |             showEmptyMessage(body);
 | 
        
           |  |  | 944 |             showSearchIcon(header);
 | 
        
           |  |  | 945 |             hideSearchResults(body);
 | 
        
           |  |  | 946 |             hideLoadingIcon(header);
 | 
        
           |  |  | 947 |             hideLoadingPlaceholder(body);
 | 
        
           |  |  | 948 |             usersOffset = 0;
 | 
        
           |  |  | 949 |             messagesOffset = 0;
 | 
        
           |  |  | 950 |         });
 | 
        
           |  |  | 951 |   | 
        
           |  |  | 952 |         PubSub.subscribe(Events.CONTACT_ADDED, function(userId) {
 | 
        
           |  |  | 953 |             addContact(body, userId);
 | 
        
           |  |  | 954 |         });
 | 
        
           |  |  | 955 |   | 
        
           |  |  | 956 |         PubSub.subscribe(Events.CONTACT_REMOVED, function(userId) {
 | 
        
           |  |  | 957 |             removeContact(body, userId);
 | 
        
           |  |  | 958 |         });
 | 
        
           |  |  | 959 |   | 
        
           |  |  | 960 |         PubSub.subscribe(Events.CONTACT_BLOCKED, function(userId) {
 | 
        
           |  |  | 961 |             blockContact(body, userId);
 | 
        
           |  |  | 962 |         });
 | 
        
           |  |  | 963 |   | 
        
           |  |  | 964 |         PubSub.subscribe(Events.CONTACT_UNBLOCKED, function(userId) {
 | 
        
           |  |  | 965 |             unblockContact(body, userId);
 | 
        
           |  |  | 966 |         });
 | 
        
           |  |  | 967 |     };
 | 
        
           |  |  | 968 |   | 
        
           |  |  | 969 |     /**
 | 
        
           |  |  | 970 |      * Setup the search page.
 | 
        
           |  |  | 971 |      *
 | 
        
           |  |  | 972 |      * @param {string} namespace The route namespace.
 | 
        
           |  |  | 973 |      * @param {Object} header Contacts header container element.
 | 
        
           |  |  | 974 |      * @param {Object} body Contacts body container element.
 | 
        
           |  |  | 975 |      * @return {Object} jQuery promise
 | 
        
           |  |  | 976 |      */
 | 
        
           |  |  | 977 |     var show = function(namespace, header, body) {
 | 
        
           |  |  | 978 |         if (!body.attr('data-init')) {
 | 
        
           |  |  | 979 |             registerEventListeners(header, body);
 | 
        
           |  |  | 980 |             body.attr('data-init', true);
 | 
        
           |  |  | 981 |         }
 | 
        
           |  |  | 982 |         var searchInput = getSearchInput(header);
 | 
        
           |  |  | 983 |         searchInput.focus();
 | 
        
           |  |  | 984 |   | 
        
           |  |  | 985 |         return $.Deferred().resolve().promise();
 | 
        
           |  |  | 986 |     };
 | 
        
           |  |  | 987 |   | 
        
           |  |  | 988 |     /**
 | 
        
           |  |  | 989 |      * String describing this page used for aria-labels.
 | 
        
           |  |  | 990 |      *
 | 
        
           |  |  | 991 |      * @param {string} namespace The route namespace.
 | 
        
           |  |  | 992 |      * @param {Object} header Contacts header container element.
 | 
        
           |  |  | 993 |      * @return {Object} jQuery promise
 | 
        
           |  |  | 994 |      */
 | 
        
           |  |  | 995 |     var description = function(namespace, header) {
 | 
        
           |  |  | 996 |         if (typeof header !== 'object') {
 | 
        
           |  |  | 997 |             return Str.get_string('messagedrawerviewsearch', 'core_message');
 | 
        
           |  |  | 998 |         }
 | 
        
           |  |  | 999 |         var searchInput = getSearchInput(header);
 | 
        
           |  |  | 1000 |         var searchText = searchInput.val().trim();
 | 
        
           |  |  | 1001 |         return Str.get_string('messagedrawerviewsearch', 'core_message', searchText);
 | 
        
           |  |  | 1002 |     };
 | 
        
           |  |  | 1003 |   | 
        
           |  |  | 1004 |     return {
 | 
        
           |  |  | 1005 |         show: show,
 | 
        
           |  |  | 1006 |         description: description
 | 
        
           |  |  | 1007 |     };
 | 
        
           |  |  | 1008 | });
 |