Current Path : C:/xampp/htdocs/moodle/message/amd/src/ |
Current File : C:/xampp/htdocs/moodle/message/amd/src/message_drawer_view_search.js |
// This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see <http://www.gnu.org/licenses/>. /** * Controls the search page of the message drawer. * * @module core_message/message_drawer_view_search * @copyright 2018 Ryan Wyllie <ryan@moodle.com> * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ define( [ 'jquery', 'core/custom_interaction_events', 'core/notification', 'core/pubsub', 'core/str', 'core/templates', 'core_message/message_repository', 'core_message/message_drawer_events', ], function( $, CustomEvents, Notification, PubSub, Str, Templates, Repository, Events ) { var MESSAGE_SEARCH_LIMIT = 50; var USERS_SEARCH_LIMIT = 50; var USERS_INITIAL_SEARCH_LIMIT = 3; var SELECTORS = { BLOCK_ICON_CONTAINER: '[data-region="block-icon-container"]', CANCEL_SEARCH_BUTTON: '[data-action="cancel-search"]', CONTACTS_CONTAINER: '[data-region="contacts-container"]', CONTACTS_LIST: '[data-region="contacts-container"] [data-region="list"]', EMPTY_MESSAGE_CONTAINER: '[data-region="empty-message-container"]', LIST: '[data-region="list"]', LOADING_ICON_CONTAINER: '[data-region="loading-icon-container"]', LOADING_PLACEHOLDER: '[data-region="loading-placeholder"]', MESSAGES_LIST: '[data-region="messages-container"] [data-region="list"]', MESSAGES_CONTAINER: '[data-region="messages-container"]', NON_CONTACTS_CONTAINER: '[data-region="non-contacts-container"]', NON_CONTACTS_LIST: '[data-region="non-contacts-container"] [data-region="list"]', SEARCH_ICON_CONTAINER: '[data-region="search-icon-container"]', SEARCH_ACTION: '[data-action="search"]', SEARCH_INPUT: '[data-region="search-input"]', SEARCH_RESULTS_CONTAINER: '[data-region="search-results-container"]', LOAD_MORE_USERS: '[data-action="load-more-users"]', LOAD_MORE_MESSAGES: '[data-action="load-more-messages"]', BUTTON_TEXT: '[data-region="button-text"]', NO_RESULTS_CONTAINTER: '[data-region="no-results-container"]', ALL_CONTACTS_CONTAINER: '[data-region="all-contacts-container"]' }; var TEMPLATES = { CONTACTS_LIST: 'core_message/message_drawer_contacts_list', NON_CONTACTS_LIST: 'core_message/message_drawer_non_contacts_list', MESSAGES_LIST: 'core_message/message_drawer_messages_list' }; /** * Get the logged in user id. * * @param {Object} body Search body container element. * @return {Number} User id. */ var getLoggedInUserId = function(body) { return body.attr('data-user-id'); }; /** * Show the no messages container element. * * @param {Object} body Search body container element. * @return {Object} No messages container element. */ var getEmptyMessageContainer = function(body) { return body.find(SELECTORS.EMPTY_MESSAGE_CONTAINER); }; /** * Get the search loading icon. * * @param {Object} header Search header container element. * @return {Object} Loading icon element. */ var getLoadingIconContainer = function(header) { return header.find(SELECTORS.LOADING_ICON_CONTAINER); }; /** * Get the loading container element. * * @param {Object} body Search body container element. * @return {Object} Loading container element. */ var getLoadingPlaceholder = function(body) { return body.find(SELECTORS.LOADING_PLACEHOLDER); }; /** * Get the search icon container. * * @param {Object} header Search header container element. * @return {Object} Search icon container. */ var getSearchIconContainer = function(header) { return header.find(SELECTORS.SEARCH_ICON_CONTAINER); }; /** * Get the search input container. * * @param {Object} header Search header container element. * @return {Object} Search input container. */ var getSearchInput = function(header) { return header.find(SELECTORS.SEARCH_INPUT); }; /** * Get the search results container. * * @param {Object} body Search body container element. * @return {Object} Search results container. */ var getSearchResultsContainer = function(body) { return body.find(SELECTORS.SEARCH_RESULTS_CONTAINER); }; /** * Get the search contacts container. * * @param {Object} body Search body container element. * @return {Object} Search contacts container. */ var getContactsContainer = function(body) { return body.find(SELECTORS.CONTACTS_CONTAINER); }; /** * Get the search non contacts container. * * @param {Object} body Search body container element. * @return {Object} Search non contacts container. */ var getNonContactsContainer = function(body) { return body.find(SELECTORS.NON_CONTACTS_CONTAINER); }; /** * Get the search messages container. * * @param {Object} body Search body container element. * @return {Object} Search messages container. */ var getMessagesContainer = function(body) { return body.find(SELECTORS.MESSAGES_CONTAINER); }; /** * Show the messages empty container. * * @param {Object} body Search body container element. */ var showEmptyMessage = function(body) { getEmptyMessageContainer(body).removeClass('hidden'); }; /** * Hide the messages empty container. * * @param {Object} body Search body container element. */ var hideEmptyMessage = function(body) { getEmptyMessageContainer(body).addClass('hidden'); }; /** * Show the loading icon. * * @param {Object} header Search header container element. */ var showLoadingIcon = function(header) { getLoadingIconContainer(header).removeClass('hidden'); }; /** * Hide the loading icon. * * @param {Object} header Search header container element. */ var hideLoadingIcon = function(header) { getLoadingIconContainer(header).addClass('hidden'); }; /** * Show loading placeholder. * * @param {Object} body Search body container element. */ var showLoadingPlaceholder = function(body) { getLoadingPlaceholder(body).removeClass('hidden'); }; /** * Hide loading placeholder. * * @param {Object} body Search body container element. */ var hideLoadingPlaceholder = function(body) { getLoadingPlaceholder(body).addClass('hidden'); }; /** * Show search icon. * * @param {Object} header Search header container element. */ var showSearchIcon = function(header) { getSearchIconContainer(header).removeClass('hidden'); }; /** * Hide search icon. * * @param {Object} header Search header container element. */ var hideSearchIcon = function(header) { getSearchIconContainer(header).addClass('hidden'); }; /** * Show search results. * * @param {Object} body Search body container element. */ var showSearchResults = function(body) { getSearchResultsContainer(body).removeClass('hidden'); }; /** * Hide search results. * * @param {Object} body Search body container element. */ var hideSearchResults = function(body) { getSearchResultsContainer(body).addClass('hidden'); }; /** * Show the no search results message. * * @param {Object} body Search body container element. */ var showNoSearchResults = function(body) { var container = getSearchResultsContainer(body); container.find(SELECTORS.ALL_CONTACTS_CONTAINER).addClass('hidden'); container.find(SELECTORS.MESSAGES_CONTAINER).addClass('hidden'); container.find(SELECTORS.NO_RESULTS_CONTAINTER).removeClass('hidden'); }; /** * Hide the no search results message. * * @param {Object} body Search body container element. */ var hideNoSearchResults = function(body) { var container = getSearchResultsContainer(body); container.find(SELECTORS.ALL_CONTACTS_CONTAINER).removeClass('hidden'); container.find(SELECTORS.MESSAGES_CONTAINER).removeClass('hidden'); container.find(SELECTORS.NO_RESULTS_CONTAINTER).addClass('hidden'); }; /** * Show the whole contacts results area. * * @param {Object} body Search body container element. */ var showAllContactsSearchResults = function(body) { var container = getSearchResultsContainer(body); container.find(SELECTORS.ALL_CONTACTS_CONTAINER).removeClass('hidden'); }; /** * Hide the whole contacts results area. * * @param {Object} body Search body container element. */ var hideAllContactsSearchResults = function(body) { var container = getSearchResultsContainer(body); container.find(SELECTORS.ALL_CONTACTS_CONTAINER).addClass('hidden'); }; /** * Show the contacts results. * * @param {Object} body Search body container element. */ var showContactsSearchResults = function(body) { var container = getSearchResultsContainer(body); container.find(SELECTORS.CONTACTS_CONTAINER).removeClass('hidden'); }; /** * Hide the contacts results. * * @param {Object} body Search body container element. */ var hideContactsSearchResults = function(body) { var container = getSearchResultsContainer(body); container.find(SELECTORS.CONTACTS_CONTAINER).addClass('hidden'); }; /** * Show the non contacts results. * * @param {Object} body Search body container element. */ var showNonContactsSearchResults = function(body) { var container = getSearchResultsContainer(body); container.find(SELECTORS.NON_CONTACTS_CONTAINER).removeClass('hidden'); }; /** * Hide the non contacts results. * * @param {Object} body Search body container element. */ var hideNonContactsSearchResults = function(body) { var container = getSearchResultsContainer(body); container.find(SELECTORS.NON_CONTACTS_CONTAINER).addClass('hidden'); }; /** * Show the messages results. * * @param {Object} body Search body container element. */ var showMessagesSearchResults = function(body) { var container = getSearchResultsContainer(body); container.find(SELECTORS.MESSAGES_CONTAINER).removeClass('hidden'); }; /** * Hide the messages results. * * @param {Object} body Search body container element. */ var hideMessagesSearchResults = function(body) { var container = getSearchResultsContainer(body); container.find(SELECTORS.MESSAGES_CONTAINER).addClass('hidden'); }; /** * Disable the search input. * * @param {Object} header Search header container element. */ var disableSearchInput = function(header) { getSearchInput(header).prop('disabled', true); }; /** * Enable the search input. * * @param {Object} header Search header container element. */ var enableSearchInput = function(header) { getSearchInput(header).prop('disabled', false); }; /** * Clear the search input. * * @param {Object} header Search header container element. */ var clearSearchInput = function(header) { getSearchInput(header).val(''); }; /** * Clear all search results * * @param {Object} body Search body container element. */ var clearAllSearchResults = function(body) { body.find(SELECTORS.CONTACTS_LIST).empty(); body.find(SELECTORS.NON_CONTACTS_LIST).empty(); body.find(SELECTORS.MESSAGES_LIST).empty(); hideNoSearchResults(body); showAllContactsSearchResults(body); showContactsSearchResults(body); showNonContactsSearchResults(body); showMessagesSearchResults(body); showLoadMoreUsersButton(body); showLoadMoreMessagesButton(body); }; /** * Update the body and header to indicate the search is loading. * * @param {Object} header Search header container element. * @param {Object} body Search body container element. */ var startLoading = function(header, body) { hideSearchIcon(header); hideEmptyMessage(body); hideSearchResults(body); showLoadingIcon(header); showLoadingPlaceholder(body); disableSearchInput(header); }; /** * Update the body and header to indicate the search has stopped loading. * * @param {Object} header Search header container element. * @param {Object} body Search body container element. */ var stopLoading = function(header, body) { showSearchIcon(header); hideEmptyMessage(body); showSearchResults(body); hideLoadingIcon(header); hideLoadingPlaceholder(body); enableSearchInput(header); }; /** * Show the more users loading icon. * * @param {Object} root The more users container element. */ var showUsersLoadingIcon = function(root) { var button = root.find(SELECTORS.LOAD_MORE_USERS); button.prop('disabled', true); button.find(SELECTORS.BUTTON_TEXT).addClass('hidden'); button.find(SELECTORS.LOADING_ICON_CONTAINER).removeClass('hidden'); }; /** * Hide the more users loading icon. * * @param {Object} root The more users container element. */ var hideUsersLoadingIcon = function(root) { var button = root.find(SELECTORS.LOAD_MORE_USERS); button.prop('disabled', false); button.find(SELECTORS.BUTTON_TEXT).removeClass('hidden'); button.find(SELECTORS.LOADING_ICON_CONTAINER).addClass('hidden'); }; /** * Show the load more users button. * * @param {Object} root The users container element. */ var showLoadMoreUsersButton = function(root) { root.find(SELECTORS.LOAD_MORE_USERS).removeClass('hidden'); }; /** * Hide the load more users button. * * @param {Object} root The users container element. */ var hideLoadMoreUsersButton = function(root) { root.find(SELECTORS.LOAD_MORE_USERS).addClass('hidden'); }; /** * Show the messages are loading icon. * * @param {Object} root Messages root element. */ var showMessagesLoadingIcon = function(root) { var button = root.find(SELECTORS.LOAD_MORE_MESSAGES); button.prop('disabled', true); button.find(SELECTORS.BUTTON_TEXT).addClass('hidden'); button.find(SELECTORS.LOADING_ICON_CONTAINER).removeClass('hidden'); }; /** * Hide the messages are loading icon. * * @param {Object} root Messages root element. */ var hideMessagesLoadingIcon = function(root) { var button = root.find(SELECTORS.LOAD_MORE_MESSAGES); button.prop('disabled', false); button.find(SELECTORS.BUTTON_TEXT).removeClass('hidden'); button.find(SELECTORS.LOADING_ICON_CONTAINER).addClass('hidden'); }; /** * Show the load more messages button. * * @param {Object} root The messages container element. */ var showLoadMoreMessagesButton = function(root) { root.find(SELECTORS.LOAD_MORE_MESSAGES).removeClass('hidden'); }; /** * Hide the load more messages button. * * @param {Object} root The messages container element. */ var hideLoadMoreMessagesButton = function(root) { root.find(SELECTORS.LOAD_MORE_MESSAGES).addClass('hidden'); }; /** * Find a contact in the search results. * * @param {Object} root Search results container element. * @param {Number} userId User id. * @return {Object} User container element. */ var findContact = function(root, userId) { return root.find('[data-contact-user-id="' + userId + '"]'); }; /** * Add a contact to the search results. * * @param {Object} root Search results container. * @param {Object} contact User in contacts list. */ var addContact = function(root, contact) { var nonContactsContainer = getNonContactsContainer(root); var nonContact = findContact(nonContactsContainer, contact.userid); if (nonContact.length) { nonContact.remove(); var contactsContainer = getContactsContainer(root); contactsContainer.removeClass('hidden'); contactsContainer.find(SELECTORS.LIST).append(nonContact); } if (!nonContactsContainer.find(SELECTORS.LIST).children().length) { nonContactsContainer.addClass('hidden'); } }; /** * Remove a contact from the contacts results. * * @param {Object} root Search results container. * @param {Object} userId Contact user id. */ var removeContact = function(root, userId) { var contactsContainer = getContactsContainer(root); var contact = findContact(contactsContainer, userId); if (contact.length) { contact.remove(); var nonContactsContainer = getNonContactsContainer(root); nonContactsContainer.removeClass('hidden'); nonContactsContainer.find(SELECTORS.LIST).append(contact); } if (!contactsContainer.find(SELECTORS.LIST).children().length) { contactsContainer.addClass('hidden'); } }; /** * Show the contact is blocked icon. * * @param {Object} root Search results container. * @param {Object} userId Contact user id. */ var blockContact = function(root, userId) { var contact = findContact(root, userId); if (contact.length) { contact.find(SELECTORS.BLOCK_ICON_CONTAINER).removeClass('hidden'); } }; /** * Hide the contact is blocked icon. * * @param {Object} root Search results container. * @param {Object} userId Contact user id. */ var unblockContact = function(root, userId) { var contact = findContact(root, userId); if (contact.length) { contact.find(SELECTORS.BLOCK_ICON_CONTAINER).addClass('hidden'); } }; /** * Highlight words in search results. * * @param {String} content HTML to search. * @param {String} searchText Search text. * @return {String} searchText with search wrapped in matchtext span. */ var highlightSearch = function(content, searchText) { if (!content) { return ''; } var regex = new RegExp('(' + searchText + ')', 'gi'); return content.replace(regex, '<span class="matchtext">$1</span>'); }; /** * Render contacts in the contacts search results. * * @param {Object} root Search results container. * @param {Array} contacts List of contacts. * @return {Promise} Renderer promise. */ var renderContacts = function(root, contacts) { var container = getContactsContainer(root); var frompanel = root.attr('data-in-panel'); var list = container.find(SELECTORS.LIST); return Templates.render(TEMPLATES.CONTACTS_LIST, {contacts: contacts, frompanel: frompanel}) .then(function(html) { list.append(html); return html; }); }; /** * Render non contacts in the contacts search results. * * @param {Object} root Search results container. * @param {Array} nonContacts List of non contacts. * @return {Promise} Renderer promise. */ var renderNonContacts = function(root, nonContacts) { var container = getNonContactsContainer(root); var frompanel = root.attr('data-in-panel'); var list = container.find(SELECTORS.LIST); return Templates.render(TEMPLATES.NON_CONTACTS_LIST, {noncontacts: nonContacts, frompanel: frompanel}) .then(function(html) { list.append(html); return html; }); }; /** * Render messages in the messages search results. * * @param {Object} root Search results container. * @param {Array} messages List of messages. * @return {Promise} Renderer promise. */ var renderMessages = function(root, messages) { var container = getMessagesContainer(root); var frompanel = root.attr('data-in-panel'); var list = container.find(SELECTORS.LIST); return Templates.render(TEMPLATES.MESSAGES_LIST, {messages: messages, frompanel: frompanel}) .then(function(html) { list.append(html); return html; }); }; /** * Load more users from the repository and render the results into the users search results. * * @param {Object} root Search results container. * @param {Number} loggedInUserId Current logged in user. * @param {String} text Search text. * @param {Number} limit Number of users to get. * @param {Number} offset Load users from * @return {Object} jQuery promise */ var loadMoreUsers = function(root, loggedInUserId, text, limit, offset) { var loadedAll = false; showUsersLoadingIcon(root); return Repository.searchUsers(loggedInUserId, text, limit + 1, offset) .then(function(results) { var contacts = results.contacts; var noncontacts = results.noncontacts; if (contacts.length <= limit && noncontacts.length <= limit) { loadedAll = true; return { contacts: contacts, noncontacts: noncontacts }; } else { return { contacts: contacts.slice(0, limit), noncontacts: noncontacts.slice(0, limit) }; } }) .then(function(results) { var contactsCount = results.contacts.length; var nonContactsCount = results.noncontacts.length; if (contactsCount) { results.contacts.forEach(function(contact) { contact.highlight = highlightSearch(contact.fullname, text); }); } if (nonContactsCount) { results.noncontacts.forEach(function(contact) { contact.highlight = highlightSearch(contact.fullname, text); }); } return $.when( contactsCount ? renderContacts(root, results.contacts) : true, nonContactsCount ? renderNonContacts(root, results.noncontacts) : true ) .then(function() { return { contactsCount: contactsCount, nonContactsCount: nonContactsCount }; }); }) .then(function(counts) { hideUsersLoadingIcon(root); if (loadedAll) { hideLoadMoreUsersButton(root); } return counts; }) .catch(function(error) { hideUsersLoadingIcon(root); // Rethrow error for other handlers. throw error; }); }; /** * Load more messages from the repository and render the results into the messages search results. * * @param {Object} root Search results container. * @param {Number} loggedInUserId Current logged in user. * @param {String} text Search text. * @param {Number} limit Number of messages to get. * @param {Number} offset Load messages from * @return {Object} jQuery promise */ var loadMoreMessages = function(root, loggedInUserId, text, limit, offset) { var loadedAll = false; showMessagesLoadingIcon(root); return Repository.searchMessages(loggedInUserId, text, limit + 1, offset) .then(function(results) { var messages = results.contacts; if (messages.length <= limit) { loadedAll = true; return messages; } else { return messages.slice(0, limit); } }) .then(function(messages) { if (messages.length) { messages.forEach(function(message) { message.lastmessage = highlightSearch(message.lastmessage, text); }); return renderMessages(root, messages) .then(function() { return messages.length; }); } else { return messages.length; } }) .then(function(count) { hideMessagesLoadingIcon(root); if (loadedAll) { hideLoadMoreMessagesButton(root); } return count; }) .catch(function(error) { hideMessagesLoadingIcon(root); // Rethrow error for other handlers. throw error; }); }; /** * Search for users and messages. * * @param {Object} header Search header container element. * @param {Object} body Search body container element. * @param {String} searchText Search text. * @param {Number} usersLimit The users limit. * @param {Number} usersOffset The users offset. * @param {Number} messagesLimit The message limit. * @param {Number} messagesOffset The message offset. * @return {Object} jQuery promise */ var search = function(header, body, searchText, usersLimit, usersOffset, messagesLimit, messagesOffset) { var loggedInUserId = getLoggedInUserId(body); startLoading(header, body); clearAllSearchResults(body); return $.when( loadMoreUsers(body, loggedInUserId, searchText, usersLimit, usersOffset), loadMoreMessages(body, loggedInUserId, searchText, messagesLimit, messagesOffset) ) .then(function(userCounts, messagesCount) { var contactsCount = userCounts.contactsCount; var nonContactsCount = userCounts.nonContactsCount; stopLoading(header, body); if (!contactsCount && !nonContactsCount && !messagesCount) { showNoSearchResults(body); } else { if (!contactsCount && !nonContactsCount) { hideAllContactsSearchResults(body); } else { if (!contactsCount) { hideContactsSearchResults(body); } if (!nonContactsCount) { hideNonContactsSearchResults(body); } } if (!messagesCount) { hideMessagesSearchResults(body); } } return; }); }; /** * Listen to and handle events for searching. * * @param {Object} header Search header container element. * @param {Object} body Search body container element. */ var registerEventListeners = function(header, body) { var loggedInUserId = getLoggedInUserId(body); var searchInput = getSearchInput(header); var searchText = ''; var messagesOffset = 0; var usersOffset = 0; var searchEventHandler = function(e, data) { searchText = searchInput.val().trim(); if (searchText !== '') { messagesOffset = 0; usersOffset = 0; search( header, body, searchText, USERS_INITIAL_SEARCH_LIMIT, usersOffset, MESSAGE_SEARCH_LIMIT, messagesOffset ) .then(function() { searchInput.focus(); usersOffset = usersOffset + USERS_INITIAL_SEARCH_LIMIT; messagesOffset = messagesOffset + MESSAGE_SEARCH_LIMIT; return; }) .catch(Notification.exception); } data.originalEvent.preventDefault(); }; CustomEvents.define(searchInput, [CustomEvents.events.enter]); CustomEvents.define(header, [CustomEvents.events.activate]); CustomEvents.define(body, [CustomEvents.events.activate]); searchInput.on(CustomEvents.events.enter, searchEventHandler); header.on(CustomEvents.events.activate, SELECTORS.SEARCH_ACTION, searchEventHandler); body.on(CustomEvents.events.activate, SELECTORS.LOAD_MORE_MESSAGES, function(e, data) { if (searchText !== '') { loadMoreMessages(body, loggedInUserId, searchText, MESSAGE_SEARCH_LIMIT, messagesOffset) .then(function() { messagesOffset = messagesOffset + MESSAGE_SEARCH_LIMIT; return; }) .catch(Notification.exception); } data.originalEvent.preventDefault(); }); body.on(CustomEvents.events.activate, SELECTORS.LOAD_MORE_USERS, function(e, data) { if (searchText !== '') { loadMoreUsers(body, loggedInUserId, searchText, USERS_SEARCH_LIMIT, usersOffset) .then(function() { usersOffset = usersOffset + USERS_SEARCH_LIMIT; return; }) .catch(Notification.exception); } data.originalEvent.preventDefault(); }); header.on(CustomEvents.events.activate, SELECTORS.CANCEL_SEARCH_BUTTON, function() { clearSearchInput(header); showEmptyMessage(body); showSearchIcon(header); hideSearchResults(body); hideLoadingIcon(header); hideLoadingPlaceholder(body); usersOffset = 0; messagesOffset = 0; }); PubSub.subscribe(Events.CONTACT_ADDED, function(userId) { addContact(body, userId); }); PubSub.subscribe(Events.CONTACT_REMOVED, function(userId) { removeContact(body, userId); }); PubSub.subscribe(Events.CONTACT_BLOCKED, function(userId) { blockContact(body, userId); }); PubSub.subscribe(Events.CONTACT_UNBLOCKED, function(userId) { unblockContact(body, userId); }); }; /** * Setup the search page. * * @param {string} namespace The route namespace. * @param {Object} header Contacts header container element. * @param {Object} body Contacts body container element. * @return {Object} jQuery promise */ var show = function(namespace, header, body) { if (!body.attr('data-init')) { registerEventListeners(header, body); body.attr('data-init', true); } var searchInput = getSearchInput(header); searchInput.focus(); return $.Deferred().resolve().promise(); }; /** * String describing this page used for aria-labels. * * @param {string} namespace The route namespace. * @param {Object} header Contacts header container element. * @return {Object} jQuery promise */ var description = function(namespace, header) { if (typeof header !== 'object') { return Str.get_string('messagedrawerviewsearch', 'core_message'); } var searchInput = getSearchInput(header); var searchText = searchInput.val().trim(); return Str.get_string('messagedrawerviewsearch', 'core_message', searchText); }; return { show: show, description: description }; });