diff --git a/apps/communications/contacts/test/unit/views/list_test.js b/apps/communications/contacts/test/unit/views/list_test.js index 6b8d5eb3b194..df6bc9103684 100755 --- a/apps/communications/contacts/test/unit/views/list_test.js +++ b/apps/communications/contacts/test/unit/views/list_test.js @@ -1270,6 +1270,27 @@ suite('Render contacts list', function() { }); }); + test('Search for contacts with middle names', function(done) { + mockContacts = new MockContactsList(); + var contactIndex = Math.floor(Math.random() * mockContacts.length); + var contact = mockContacts[contactIndex]; + mockContacts[contactIndex].givenName[0] = contact.givenName[0] + ' Juan'; + + doLoad(subject, mockContacts, function() { + contacts.List.initSearch(function onInit() { + searchBox.value = contact.givenName[0][0] + ' ' + + contact.familyName[0][0]; + contacts.Search.search(function search_finished() { + contacts.Search.invalidateCache(); + done(function() { + assert.isTrue(noResults.classList.contains('hide')); + assertContactFound(contact); + }); + }); + }); + }); + }); + test('Search phrase highlightded correctly for first letter', function(done) { mockContacts = new MockContactsList(); diff --git a/shared/js/contacts/search.js b/shared/js/contacts/search.js index 48e412b33468..e73ae440c6f6 100644 --- a/shared/js/contacts/search.js +++ b/shared/js/contacts/search.js @@ -22,6 +22,7 @@ contacts.Search = (function() { // On the steady state holds the list result of the current search searchableNodes = null, currentTextToSearch = '', + currentSearchTerms = [], prevTextToSearch = '', // Pointer to the nodes which are currently on the result list currentSet = {}, @@ -153,11 +154,14 @@ contacts.Search = (function() { // This regexp match against everything except HTML tags // 'currentTextToSearch' should be relatively safe from // regex symbols getting passed through since it was previously normalized - var hRegEx = new RegExp('(' + currentTextToSearch + ')(?=[^>]*<)', 'gi'); - node.innerHTML = node.innerHTML.replace( - hRegEx, - '$1' - ); + for (var i=0, l=currentSearchTerms.length; i]*<)', + 'gi'); + node.innerHTML = node.innerHTML.replace( + hRegEx, + '$1' + ); + } }; var updateSearchList = function updateSearchList(cb) { @@ -216,6 +220,7 @@ contacts.Search = (function() { function resetState() { prevTextToSearch = ''; currentTextToSearch = ''; + currentSearchTerms = []; searchableNodes = null; canReuseSearchables = false; currentSet = {}; @@ -365,10 +370,11 @@ contacts.Search = (function() { // Search the next chunk of contacts var end = from + CHUNK_SIZE; + currentSearchTerms = pattern.source.split(/\s+/); for (var c = from; c < end && c < contacts.length; c++) { var contact = contacts[c].node || contacts[c]; var contactText = contacts[c].text || getSearchText(contacts[c]); - if (!pattern.test(contactText)) { + if (!checkContactMatch(currentSearchTerms, contactText)) { if (contact.dataset.uuid in currentSet) { searchList.removeChild(currentSet[contact.dataset.uuid]); delete currentSet[contact.dataset.uuid]; @@ -475,11 +481,10 @@ contacts.Search = (function() { // If we have a current search then we need to determine whether the // new nodes should show up in that search. - var pattern = new RegExp(currentTextToSearch, 'i'); for (var i = 0, n = nodes.length; i < n; ++i) { var node = nodes[i]; var nodeText = getSearchText(node); - if (pattern.test(nodeText)) { + if (!checkContactMatch(currentSearchTerms, nodeText)) { searchableNodes.push({ node: node, text: nodeText @@ -488,6 +493,15 @@ contacts.Search = (function() { } }; + var checkContactMatch = function checkContactMatch(searchTerms, text) { + for (var i=0, m=searchTerms.length; i < m; i++){ + if (!RegExp(searchTerms[i], 'i').test(text)) { + return false; + } + } + return true; + }; + var search = function performSearch(searchDoneCb) { prevTextToSearch = currentTextToSearch;