Skip to content
This repository has been archived by the owner on Nov 3, 2021. It is now read-only.

Commit

Permalink
[GAIA BUG886754] - Add highlighting to Contact Search results
Browse files Browse the repository at this point in the history
  • Loading branch information
michalbe committed Apr 30, 2014
1 parent feef477 commit 8f40d7e
Show file tree
Hide file tree
Showing 3 changed files with 99 additions and 5 deletions.
44 changes: 42 additions & 2 deletions apps/communications/contacts/js/views/search.js
Expand Up @@ -39,7 +39,8 @@ contacts.Search = (function() {
imgLoader,
searchEnabled = false,
source = null,
navigationController = null;
navigationController = null,
highlightClass = 'highlight';

// The _source argument should be an adapter object that provides access
// to the contact nodes in the app. This is done by defining the following
Expand Down Expand Up @@ -131,6 +132,34 @@ contacts.Search = (function() {
});
};

var clearHighlights = function(node) {
// We travers the DOM tree and remove highlighting spans.
// getElements instead of querySelector here because of
// performance.
var highlights = node.getElementsByClassName(highlightClass);
while(highlights.length) {
var parent = highlights[0].parentNode;
while(highlights[0].firstChild) {
parent.insertBefore(highlights[0].firstChild, highlights[0]);
}

// This removes the item from 'highlights' HTMLCollection as well
// via live DOM updating.
parent.removeChild(highlights[0]);
}
};

var highlightNode = function(node) {
// 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,
'<span class="' + highlightClass + '">$1</span>'
);
};

var updateSearchList = function updateSearchList(cb) {
if (!inSearchMode) {
if (cb) {
Expand Down Expand Up @@ -204,6 +233,7 @@ contacts.Search = (function() {
for (var i = from; i < hardLimit && i < nodes.length; i++) {
var node = nodes[i].node;
var clon = getClone(node);
highlightNode(clon);
fragment.appendChild(clon);
currentSet[node.dataset.uuid] = clon;
}
Expand Down Expand Up @@ -350,6 +380,13 @@ contacts.Search = (function() {
searchList.appendChild(clonedNode);
}

if (currentSet[contact.dataset.uuid]) {
// We clear the highlights here because parts of the node could
// been already highlighted from a previous, more general search.
clearHighlights(currentSet[contact.dataset.uuid]);
highlightNode(currentSet[contact.dataset.uuid]);
}

state.searchables.push({
node: contact,
text: contactText
Expand Down Expand Up @@ -577,6 +614,9 @@ contacts.Search = (function() {
'isInSearchMode': isInSearchMode,
'enableSearch': enableSearch,
'selectRow': selectRow,
'updateSearchList': updateSearchList
'updateSearchList': updateSearchList,
'getHighlightClass': function(){
return highlightClass;
}
};
})();
6 changes: 5 additions & 1 deletion apps/communications/contacts/style/search.css
Expand Up @@ -136,4 +136,8 @@ form.search button[type="submit"] {

#search-list label.pack-checkbox {
display: none !important;
}
}

span.highlight {
background-color: #b2f2ff;
}
54 changes: 52 additions & 2 deletions apps/communications/contacts/test/unit/views/list_test.js
Expand Up @@ -184,15 +184,31 @@ suite('Render contacts list', function() {
}

function assertContactFound(contact) {
var selectorStr = 'li';
selectorStr = 'li.contact-item';
var selectorStr = 'li.contact-item';

var showContact = searchList.querySelectorAll(selectorStr);
assert.length(showContact, 1);
assert.equal(showContact[0].dataset.uuid, contact.id);
assert.isTrue(noResults.classList.contains('hide'));
}

function assertHighlight(phrase) {
var selectorStr = 'li.contact-item';
var showContact = searchList.querySelectorAll(selectorStr);
assert.isTrue(showContact.length > 0);

var regExp = new RegExp('^' + phrase + '$', 'i');
var highlightClass = contacts.Search.getHighlightClass();
var highlightedNodes = searchList.getElementsByClassName(highlightClass);
for (var i = 0, l = highlightedNodes.length; i < l; i++) {
// we want to be non-case-sensitive so simple comparision
// of string will not work here. There could also be problems
// with different languages when using String.toLowerCase(),
// thats why we use Regular Expressions
assert.isTrue(regExp.test(highlightedNodes[i].innerHTML));
}
}

function getStringToBeOrdered(contact, orderByLastName) {
var ret = [];

Expand Down Expand Up @@ -1254,6 +1270,40 @@ suite('Render contacts list', function() {
});
});

test('Search phrase highlightded correctly for first letter',
function(done) {
mockContacts = new MockContactsList();
var contactIndex = Math.floor(Math.random() * mockContacts.length);
var contact = mockContacts[contactIndex];

doLoad(subject, mockContacts, function() {
var firstLetter = contact.givenName[0].charAt(0);
searchBox.value = firstLetter;
contacts.Search.search(function search_finished() {
assertHighlight(firstLetter);
contacts.Search.invalidateCache();
done();
});
});
});

test('Search phrase highlightded correctly for more than one letter',
function(done) {
mockContacts = new MockContactsList();
var contactIndex = Math.floor(Math.random() * mockContacts.length);
var contact = mockContacts[contactIndex];

doLoad(subject, mockContacts, function() {
var firstLetter = contact.givenName[0];
searchBox.value = firstLetter;
contacts.Search.search(function search_finished() {
assertHighlight(firstLetter);
contacts.Search.invalidateCache();
done();
});
});
});

test('Order string lazy calculated', function(done) {
mockContacts = new MockContactsList();
doLoad(subject, mockContacts, function() {
Expand Down

0 comments on commit 8f40d7e

Please sign in to comment.