 Chromium Code Reviews
 Chromium Code Reviews| OLD | NEW | 
|---|---|
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be | 
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. | 
| 4 | 4 | 
| 5 cr.define('options', function() { | 5 cr.define('options', function() { | 
| 6 const OptionsPage = options.OptionsPage; | 6 const OptionsPage = options.OptionsPage; | 
| 7 | 7 | 
| 8 /** | 8 /** | 
| 9 * Encapsulated handling of the search page. | 9 * Encapsulated handling of the search page. | 
| 10 * @constructor | 10 * @constructor | 
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 85 if (active) { | 85 if (active) { | 
| 86 // Reset the search criteria, effectively hiding all the sections. | 86 // Reset the search criteria, effectively hiding all the sections. | 
| 87 this.setSearchText_(''); | 87 this.setSearchText_(''); | 
| 88 } else { | 88 } else { | 
| 89 // Just wipe out any active search text since it's no longer relevant. | 89 // Just wipe out any active search text since it's no longer relevant. | 
| 90 $('searchField').value = ''; | 90 $('searchField').value = ''; | 
| 91 } | 91 } | 
| 92 } | 92 } | 
| 93 | 93 | 
| 94 var page, length, childDiv; | 94 var page, length, childDiv; | 
| 95 for (var name in OptionsPage.registeredPages) { | 95 var pagesToSearch = this.getSearchablePages_(); | 
| 96 if (name == this.name) | 96 for (var key in pagesToSearch) { | 
| 97 continue; | 97 var page = pagesToSearch[key]; | 
| 98 | |
| 99 if (!active) { | |
| 100 page.visible = false; | |
| 101 this.unhighlightMatches_(page.tab); | |
| 102 this.unhighlightMatches_(page.pageDiv); | |
| 103 } | |
| 98 | 104 | 
| 99 // Update the visible state of all top-level elements that are not | 105 // Update the visible state of all top-level elements that are not | 
| 100 // sections (ie titles, button strips). We do this before changing | 106 // sections (ie titles, button strips). We do this before changing | 
| 101 // the page visibility to avoid excessive re-draw. | 107 // the page visibility to avoid excessive re-draw. | 
| 102 page = OptionsPage.registeredPages[name]; | |
| 103 length = page.pageDiv.childNodes.length; | 108 length = page.pageDiv.childNodes.length; | 
| 104 for (var i = 0; i < length; i++) { | 109 for (var i = 0; i < length; i++) { | 
| 105 childDiv = page.pageDiv.childNodes[i]; | 110 childDiv = page.pageDiv.childNodes[i]; | 
| 106 if (childDiv.nodeType == 1) { | 111 if (childDiv.nodeType == 1) { | 
| 107 if (active) { | 112 if (active) { | 
| 108 if (childDiv.nodeName.toLowerCase() != 'section') | 113 if (childDiv.nodeName.toLowerCase() != 'section') | 
| 109 childDiv.classList.add('search-hidden'); | 114 childDiv.classList.add('search-hidden'); | 
| 110 } else { | 115 } else { | 
| 111 childDiv.classList.remove('search-hidden'); | 116 childDiv.classList.remove('search-hidden'); | 
| 112 } | 117 } | 
| 113 } | 118 } | 
| 114 } | 119 } | 
| 115 | 120 | 
| 116 // Toggle the visibility state of the page. | 121 // Toggle the visibility state of the page. | 
| 117 if (active) { | 122 if (active) { | 
| 118 // When search is active, remove the 'hidden' tag. This tag may have | 123 // When search is active, remove the 'hidden' tag. This tag may have | 
| 119 // been added by the OptionsPage. | 124 // been added by the OptionsPage. | 
| 120 page.pageDiv.classList.remove('hidden'); | 125 page.pageDiv.classList.remove('hidden'); | 
| 121 } else { | |
| 122 page.visible = false; | |
| 123 } | 126 } | 
| 124 } | 127 } | 
| 125 }, | 128 }, | 
| 126 | 129 | 
| 127 /** | 130 /** | 
| 128 * Set the current search criteria. | 131 * Set the current search criteria. | 
| 129 * @param {string} text Search text. | 132 * @param {string} text Search text. | 
| 130 * @private | 133 * @private | 
| 131 */ | 134 */ | 
| 132 setSearchText_: function(text) { | 135 setSearchText_: function(text) { | 
| 133 var searchText = text.toLowerCase(); | |
| 134 var foundMatches = false; | 136 var foundMatches = false; | 
| 135 | 137 | 
| 136 // Build a list of pages to search. Omit the search page. | 138 // Generate search text is a lowercase version of the input text, with any | 
| 
James Hawkins
2010/12/08 23:30:05
Something seems grammatically off with this commen
 
csilv
2010/12/08 23:48:29
Whoops, indeed!  Done.
 | |
| 137 var pagesToSearch = []; | 139 // problematic characters escaped for use in a regular expression. | 
| 138 for (var name in OptionsPage.registeredPages) { | 140 var searchText = | 
| 139 if (name != this.name) | 141 text.toLowerCase().replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&'); | 
| 140 pagesToSearch.push(OptionsPage.registeredPages[name]); | |
| 141 } | |
| 142 | 142 | 
| 143 // Hide all sections. If the search string matches a title page, show | 143 // Generate a regular expression and transform string for searching the | 
| 144 // all sections of that page. | 144 // navigation sidebar. | 
| 145 var navRegEx = new RegExp('(\\b' + searchText + ')', 'ig'); | |
| 146 var navTransform = '<span class="search-highlighted">$1</span>'; | |
| 147 | |
| 148 // Generate a regular expression and transofmr string for searching the | |
| 
James Hawkins
2010/12/08 23:30:05
transform
 
csilv
2010/12/08 23:48:29
Done.
 | |
| 149 // pages. | |
| 150 var sectionRegEx = | |
| 151 new RegExp('>([^<]*)?(\\b' + searchText + ')([^>]*)?<', 'ig'); | |
| 152 var sectionTransform = '>$1<span class="search-highlighted">$2</span>$3<'; | |
| 153 | |
| 154 // Initialize all sections. If the search string matches a title page, | |
| 155 // show sections for that page. | |
| 156 var pagesToSearch = this.getSearchablePages_(); | |
| 145 for (var key in pagesToSearch) { | 157 for (var key in pagesToSearch) { | 
| 146 var page = pagesToSearch[key]; | 158 var page = pagesToSearch[key]; | 
| 147 var pageTitle = page.title.toLowerCase(); | 159 this.unhighlightMatches_(page.tab); | 
| 148 // Hide non-sections in each page. | 160 this.unhighlightMatches_(page.pageDiv); | 
| 161 var pageMatch = false; | |
| 162 if (searchText.length) { | |
| 163 pageMatch = this.performReplace_(navRegEx, navTransform, page.tab); | |
| 164 } | |
| 165 if (pageMatch) | |
| 166 foundMatches = true; | |
| 149 for (var i = 0; i < page.pageDiv.childNodes.length; i++) { | 167 for (var i = 0; i < page.pageDiv.childNodes.length; i++) { | 
| 150 var childDiv = page.pageDiv.childNodes[i]; | 168 var childDiv = page.pageDiv.childNodes[i]; | 
| 151 if (childDiv.nodeType == 1 && | 169 if (childDiv.nodeType == 1 && | 
| 152 childDiv.nodeName.toLowerCase() == 'section') { | 170 childDiv.nodeName.toLowerCase() == 'section') { | 
| 153 if (pageTitle == searchText) { | 171 if (pageMatch) { | 
| 154 childDiv.classList.remove('search-hidden'); | 172 childDiv.classList.remove('search-hidden'); | 
| 155 foundMatches = true; | |
| 156 } else { | 173 } else { | 
| 157 childDiv.classList.add('search-hidden'); | 174 childDiv.classList.add('search-hidden'); | 
| 158 } | 175 } | 
| 159 } | 176 } | 
| 160 } | 177 } | 
| 161 } | 178 } | 
| 162 | 179 | 
| 163 // Now search all sections for anchored string matches. | 180 // Search all sections for anchored string matches. | 
| 164 if (!foundMatches && searchText.length) { | 181 if (searchText.length) { | 
| 165 var searchRegEx = new RegExp('\\b' + searchText, 'i'); | |
| 166 for (var key in pagesToSearch) { | 182 for (var key in pagesToSearch) { | 
| 167 var page = pagesToSearch[key]; | 183 var page = pagesToSearch[key]; | 
| 168 for (var i = 0; i < page.pageDiv.childNodes.length; i++) { | 184 for (var i = 0; i < page.pageDiv.childNodes.length; i++) { | 
| 169 var childDiv = page.pageDiv.childNodes[i]; | 185 var childDiv = page.pageDiv.childNodes[i]; | 
| 170 if (childDiv.nodeType == 1 && | 186 if (childDiv.nodeType == 1 && | 
| 171 childDiv.nodeName.toLowerCase() == 'section') { | 187 childDiv.nodeName.toLowerCase() == 'section' && | 
| 172 var isMatch = false; | 188 this.performReplace_(sectionRegEx, sectionTransform, | 
| 173 var sectionElements = childDiv.getElementsByTagName("*"); | 189 childDiv)) { | 
| 174 var length = sectionElements.length; | 190 childDiv.classList.remove('search-hidden'); | 
| 175 var element; | 191 foundMatches = true; | 
| 176 for (var j = 0; j < length; j++) { | |
| 177 element = sectionElements[j]; | |
| 178 if (searchRegEx.test(element.textContent)) { | |
| 179 isMatch = true; | |
| 180 break; | |
| 181 } | |
| 182 } | |
| 183 if (isMatch) { | |
| 184 childDiv.classList.remove('search-hidden'); | |
| 185 foundMatches = true; | |
| 186 } | |
| 187 } | 192 } | 
| 188 } | 193 } | 
| 189 } | 194 } | 
| 190 } | 195 } | 
| 191 | 196 | 
| 192 // Configure elements on the search results page based on search results. | 197 // Configure elements on the search results page based on search results. | 
| 193 if (searchText.length == 0) { | 198 if (searchText.length == 0) { | 
| 194 $('searchPageInfo').classList.remove('search-hidden'); | 199 $('searchPageInfo').classList.remove('search-hidden'); | 
| 195 $('searchPageNoMatches').classList.add('search-hidden'); | 200 $('searchPageNoMatches').classList.add('search-hidden'); | 
| 196 } else if (foundMatches) { | 201 } else if (foundMatches) { | 
| 197 $('searchPageInfo').classList.add('search-hidden'); | 202 $('searchPageInfo').classList.add('search-hidden'); | 
| 198 $('searchPageNoMatches').classList.add('search-hidden'); | 203 $('searchPageNoMatches').classList.add('search-hidden'); | 
| 199 } else { | 204 } else { | 
| 200 $('searchPageInfo').classList.add('search-hidden'); | 205 $('searchPageInfo').classList.add('search-hidden'); | 
| 201 $('searchPageNoMatches').classList.remove('search-hidden'); | 206 $('searchPageNoMatches').classList.remove('search-hidden'); | 
| 202 } | 207 } | 
| 208 }, | |
| 209 | |
| 210 /** | |
| 211 * Performs a string replacement based on a regex and transform. | |
| 212 * @param {RegEx} regex A regular expression for finding search matches. | |
| 213 * @param {String} transform A string to apply the replace operation. | |
| 214 * @param {Element} element An HTML container element. | |
| 215 * @returns {Boolean} true if the element was changed. | |
| 216 * @private | |
| 217 */ | |
| 218 performReplace_: function(regex, transform, element) { | |
| 219 var originalHTML = element.innerHTML; | |
| 220 var newHTML = originalHTML.replace(regex, transform); | |
| 221 if (originalHTML != newHTML) { | |
| 222 element.innerHTML = newHTML; | |
| 223 return true; | |
| 224 } else { | |
| 225 return false; | |
| 226 } | |
| 227 }, | |
| 228 | |
| 229 /** | |
| 230 * Removes all search highlight tags from a container element. | |
| 231 * @param {Element} element An HTML container element. | |
| 232 * @private | |
| 233 */ | |
| 234 unhighlightMatches_: function(element) { | |
| 235 var regex = | |
| 236 new RegExp('<span class="search-highlighted">(.*?)</span>', 'g'); | |
| 237 element.innerHTML = element.innerHTML.replace(regex, '$1'); | |
| 238 }, | |
| 239 | |
| 240 /** | |
| 241 * Build a list of pages to search. Omit the search page. | |
| 242 * @returns {Array} An array of pages to search. | |
| 243 * @private | |
| 244 */ | |
| 245 getSearchablePages_: function() { | |
| 246 var pages = []; | |
| 247 for (var name in OptionsPage.registeredPages) { | |
| 248 if (name != this.name) | |
| 249 pages.push(OptionsPage.registeredPages[name]); | |
| 250 } | |
| 251 return pages; | |
| 203 } | 252 } | 
| 204 }; | 253 }; | 
| 205 | 254 | 
| 206 // Export | 255 // Export | 
| 207 return { | 256 return { | 
| 208 SearchPage: SearchPage | 257 SearchPage: SearchPage | 
| 209 }; | 258 }; | 
| 210 | 259 | 
| 211 }); | 260 }); | 
| OLD | NEW |