Index: chrome/browser/resources/options/search_page.js |
=================================================================== |
--- chrome/browser/resources/options/search_page.js (revision 68621) |
+++ chrome/browser/resources/options/search_page.js (working copy) |
@@ -92,14 +92,19 @@ |
} |
var page, length, childDiv; |
- for (var name in OptionsPage.registeredPages) { |
- if (name == this.name) |
- continue; |
+ var pagesToSearch = this.getSearchablePages_(); |
+ for (var key in pagesToSearch) { |
+ var page = pagesToSearch[key]; |
+ if (!active) { |
+ page.visible = false; |
+ this.unhighlightMatches_(page.tab); |
+ this.unhighlightMatches_(page.pageDiv); |
+ } |
+ |
// Update the visible state of all top-level elements that are not |
// sections (ie titles, button strips). We do this before changing |
// the page visibility to avoid excessive re-draw. |
- page = OptionsPage.registeredPages[name]; |
length = page.pageDiv.childNodes.length; |
for (var i = 0; i < length; i++) { |
childDiv = page.pageDiv.childNodes[i]; |
@@ -108,7 +113,7 @@ |
if (childDiv.nodeName.toLowerCase() != 'section') |
childDiv.classList.add('search-hidden'); |
} else { |
- childDiv.classList.remove('search-hidden'); |
+ childDiv.classList.remove('search-hidden'); |
} |
} |
} |
@@ -118,8 +123,6 @@ |
// When search is active, remove the 'hidden' tag. This tag may have |
// been added by the OptionsPage. |
page.pageDiv.classList.remove('hidden'); |
- } else { |
- page.visible = false; |
} |
} |
}, |
@@ -130,29 +133,43 @@ |
* @private |
*/ |
setSearchText_: function(text) { |
- var searchText = text.toLowerCase(); |
var foundMatches = false; |
- // Build a list of pages to search. Omit the search page. |
- var pagesToSearch = []; |
- for (var name in OptionsPage.registeredPages) { |
- if (name != this.name) |
- pagesToSearch.push(OptionsPage.registeredPages[name]); |
- } |
+ // Generate search text by applying lowercase and escaping any characters |
+ // that would be problematic for regular expressions. |
+ var searchText = |
+ text.toLowerCase().replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&'); |
- // Hide all sections. If the search string matches a title page, show |
- // all sections of that page. |
+ // Generate a regular expression and transform string for searching the |
+ // navigation sidebar. |
+ var navRegEx = new RegExp('(\\b' + searchText + ')', 'ig'); |
+ var navTransform = '<span class="search-highlighted">$1</span>'; |
+ |
+ // Generate a regular expression and transform string for searching the |
+ // pages. |
+ var sectionRegEx = |
+ new RegExp('>([^<]*)?(\\b' + searchText + ')([^>]*)?<', 'ig'); |
+ var sectionTransform = '>$1<span class="search-highlighted">$2</span>$3<'; |
+ |
+ // Initialize all sections. If the search string matches a title page, |
+ // show sections for that page. |
+ var pagesToSearch = this.getSearchablePages_(); |
for (var key in pagesToSearch) { |
var page = pagesToSearch[key]; |
- var pageTitle = page.title.toLowerCase(); |
- // Hide non-sections in each page. |
+ this.unhighlightMatches_(page.tab); |
+ this.unhighlightMatches_(page.pageDiv); |
+ var pageMatch = false; |
+ if (searchText.length) { |
+ pageMatch = this.performReplace_(navRegEx, navTransform, page.tab); |
+ } |
+ if (pageMatch) |
+ foundMatches = true; |
for (var i = 0; i < page.pageDiv.childNodes.length; i++) { |
var childDiv = page.pageDiv.childNodes[i]; |
if (childDiv.nodeType == 1 && |
childDiv.nodeName.toLowerCase() == 'section') { |
- if (pageTitle == searchText) { |
+ if (pageMatch) { |
childDiv.classList.remove('search-hidden'); |
- foundMatches = true; |
} else { |
childDiv.classList.add('search-hidden'); |
} |
@@ -160,30 +177,18 @@ |
} |
} |
- // Now search all sections for anchored string matches. |
- if (!foundMatches && searchText.length) { |
- var searchRegEx = new RegExp('\\b' + searchText, 'i'); |
+ // Search all sections for anchored string matches. |
+ if (searchText.length) { |
for (var key in pagesToSearch) { |
var page = pagesToSearch[key]; |
for (var i = 0; i < page.pageDiv.childNodes.length; i++) { |
var childDiv = page.pageDiv.childNodes[i]; |
if (childDiv.nodeType == 1 && |
- childDiv.nodeName.toLowerCase() == 'section') { |
- var isMatch = false; |
- var sectionElements = childDiv.getElementsByTagName("*"); |
- var length = sectionElements.length; |
- var element; |
- for (var j = 0; j < length; j++) { |
- element = sectionElements[j]; |
- if (searchRegEx.test(element.textContent)) { |
- isMatch = true; |
- break; |
- } |
- } |
- if (isMatch) { |
- childDiv.classList.remove('search-hidden'); |
- foundMatches = true; |
- } |
+ childDiv.nodeName.toLowerCase() == 'section' && |
+ this.performReplace_(sectionRegEx, sectionTransform, |
+ childDiv)) { |
+ childDiv.classList.remove('search-hidden'); |
+ foundMatches = true; |
} |
} |
} |
@@ -200,6 +205,50 @@ |
$('searchPageInfo').classList.add('search-hidden'); |
$('searchPageNoMatches').classList.remove('search-hidden'); |
} |
+ }, |
+ |
+ /** |
+ * Performs a string replacement based on a regex and transform. |
+ * @param {RegEx} regex A regular expression for finding search matches. |
+ * @param {String} transform A string to apply the replace operation. |
+ * @param {Element} element An HTML container element. |
+ * @returns {Boolean} true if the element was changed. |
+ * @private |
+ */ |
+ performReplace_: function(regex, transform, element) { |
+ var originalHTML = element.innerHTML; |
+ var newHTML = originalHTML.replace(regex, transform); |
+ if (originalHTML != newHTML) { |
+ element.innerHTML = newHTML; |
+ return true; |
+ } else { |
+ return false; |
+ } |
+ }, |
+ |
+ /** |
+ * Removes all search highlight tags from a container element. |
+ * @param {Element} element An HTML container element. |
+ * @private |
+ */ |
+ unhighlightMatches_: function(element) { |
+ var regex = |
+ new RegExp('<span class="search-highlighted">(.*?)</span>', 'g'); |
+ element.innerHTML = element.innerHTML.replace(regex, '$1'); |
+ }, |
+ |
+ /** |
+ * Build a list of pages to search. Omit the search page. |
James Hawkins
2010/12/09 18:40:15
Builds
James Hawkins
2010/12/09 18:40:15
Omits
csilv
2010/12/09 18:55:10
Done.
csilv
2010/12/09 18:55:10
Done.
|
+ * @returns {Array} An array of pages to search. |
+ * @private |
+ */ |
+ getSearchablePages_: function() { |
+ var pages = []; |
+ for (var name in OptionsPage.registeredPages) { |
+ if (name != this.name) |
+ pages.push(OptionsPage.registeredPages[name]); |
+ } |
+ return pages; |
} |
}; |