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 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 42 self.tab.appendChild(searchField); | 42 self.tab.appendChild(searchField); |
| 43 | 43 |
| 44 // Handle search events. (No need to throttle, WebKit's search field | 44 // Handle search events. (No need to throttle, WebKit's search field |
| 45 // will do that automatically.) | 45 // will do that automatically.) |
| 46 searchField.onsearch = function(e) { | 46 searchField.onsearch = function(e) { |
| 47 self.setSearchText_(this.value); | 47 self.setSearchText_(this.value); |
| 48 }; | 48 }; |
| 49 }, | 49 }, |
| 50 | 50 |
| 51 /** | 51 /** |
| 52 * @inheritDoc | |
| 53 */ | |
| 54 get sticky() { | |
| 55 return true; | |
| 56 }, | |
| 57 | |
| 58 /** | |
| 52 * Called after this page has shown. | 59 * Called after this page has shown. |
| 53 */ | 60 */ |
| 54 didShowPage: function() { | 61 didShowPage: function() { |
| 55 // This method is called by the Options page after all pages have | 62 // This method is called by the Options page after all pages have |
| 56 // had their visibilty attribute set. At this point we can perform the | 63 // had their visibilty attribute set. At this point we can perform the |
| 57 // search specific DOM manipulation. | 64 // search specific DOM manipulation. |
| 58 this.setSearchActive_(true); | 65 this.setSearchActive_(true); |
| 59 }, | 66 }, |
| 60 | 67 |
| 61 /** | 68 /** |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 84 this.searchActive_ = active; | 91 this.searchActive_ = active; |
| 85 if (active) { | 92 if (active) { |
| 86 // Reset the search criteria, effectively hiding all the sections. | 93 // Reset the search criteria, effectively hiding all the sections. |
| 87 this.setSearchText_(''); | 94 this.setSearchText_(''); |
| 88 } else { | 95 } else { |
| 89 // Just wipe out any active search text since it's no longer relevant. | 96 // Just wipe out any active search text since it's no longer relevant. |
| 90 $('search-field').value = ''; | 97 $('search-field').value = ''; |
| 91 } | 98 } |
| 92 } | 99 } |
| 93 | 100 |
| 94 var page, length, childDiv; | 101 var page, key, length, childDiv, i; |
|
James Hawkins
2010/12/23 19:29:44
Why did you pull these out of scope?
csilv
2010/12/23 19:56:24
Attempts to re-use variables. There's no benefit
| |
| 95 var pagesToSearch = this.getSearchablePages_(); | 102 var pagesToSearch = this.getSearchablePages_(); |
| 96 for (var key in pagesToSearch) { | 103 for (key in pagesToSearch) { |
| 97 var page = pagesToSearch[key]; | 104 page = pagesToSearch[key]; |
| 98 | 105 |
| 99 if (!active) { | 106 if (!active) |
| 100 page.visible = false; | 107 page.visible = false; |
| 101 this.unhighlightMatches_(page.tab); | |
| 102 this.unhighlightMatches_(page.pageDiv); | |
| 103 } | |
| 104 | 108 |
| 105 // Update the visible state of all top-level elements that are not | 109 // Update the visible state of all top-level elements that are not |
| 106 // sections (ie titles, button strips). We do this before changing | 110 // sections (ie titles, button strips). We do this before changing |
| 107 // the page visibility to avoid excessive re-draw. | 111 // the page visibility to avoid excessive re-draw. |
| 108 length = page.pageDiv.childNodes.length; | 112 length = page.pageDiv.childNodes.length; |
| 109 for (var i = 0; i < length; i++) { | 113 for (i = 0; i < length; i++) { |
| 110 childDiv = page.pageDiv.childNodes[i]; | 114 childDiv = page.pageDiv.childNodes[i]; |
| 111 if (childDiv.nodeType == document.ELEMENT_NODE) { | 115 if (childDiv.nodeType == document.ELEMENT_NODE) { |
| 112 if (active) { | 116 if (active) { |
| 113 if (childDiv.nodeName.toLowerCase() != 'section') | 117 if (childDiv.nodeName.toLowerCase() != 'section') |
| 114 childDiv.classList.add('search-hidden'); | 118 childDiv.classList.add('search-hidden'); |
| 115 } else { | 119 } else { |
| 116 childDiv.classList.remove('search-hidden'); | 120 childDiv.classList.remove('search-hidden'); |
| 117 } | 121 } |
| 118 } | 122 } |
| 119 } | 123 } |
| 120 | 124 |
| 121 // Toggle the visibility state of the page. | |
| 122 if (active) { | 125 if (active) { |
| 123 // When search is active, remove the 'hidden' tag. This tag may have | 126 // When search is active, remove the 'hidden' tag. This tag may have |
| 124 // been added by the OptionsPage. | 127 // been added by the OptionsPage. |
| 125 page.pageDiv.classList.remove('hidden'); | 128 page.pageDiv.classList.remove('hidden'); |
| 126 } | 129 } |
| 127 } | 130 } |
| 131 | |
| 132 // After hiding all page content, remove any highlighted matches. | |
| 133 if (!active) | |
| 134 this.unhighlightMatches_(); | |
| 128 }, | 135 }, |
| 129 | 136 |
| 130 /** | 137 /** |
| 131 * Set the current search criteria. | 138 * Set the current search criteria. |
| 132 * @param {string} text Search text. | 139 * @param {string} text Search text. |
| 133 * @private | 140 * @private |
| 134 */ | 141 */ |
| 135 setSearchText_: function(text) { | 142 setSearchText_: function(text) { |
| 136 var foundMatches = false; | 143 var foundMatches = false; |
| 137 | 144 |
| 145 // Remove any highlighted matches. | |
| 146 this.unhighlightMatches_(); | |
| 147 | |
| 138 // Generate search text by applying lowercase and escaping any characters | 148 // Generate search text by applying lowercase and escaping any characters |
| 139 // that would be problematic for regular expressions. | 149 // that would be problematic for regular expressions. |
| 140 var searchText = | 150 var searchText = |
| 141 text.toLowerCase().replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&'); | 151 text.toLowerCase().replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&'); |
| 142 | 152 |
| 143 // Generate a regular expression and replace string for hilighting | 153 // Generate a regular expression and replace string for hilighting |
| 144 // search terms. | 154 // search terms. |
| 145 var regEx = new RegExp('(\\b' + searchText + ')', 'ig'); | 155 var regEx = new RegExp('(\\b' + searchText + ')', 'ig'); |
| 146 var replaceString = '<span class="search-highlighted">$1</span>'; | 156 var replaceString = '<span class="search-highlighted">$1</span>'; |
| 147 | 157 |
| 148 // Initialize all sections. If the search string matches a title page, | 158 // Initialize all sections. If the search string matches a title page, |
| 149 // show sections for that page. | 159 // show sections for that page. |
| 160 var page, key, pageMatch, childDiv, i; | |
| 150 var pagesToSearch = this.getSearchablePages_(); | 161 var pagesToSearch = this.getSearchablePages_(); |
| 151 for (var key in pagesToSearch) { | 162 for (key in pagesToSearch) { |
| 152 var page = pagesToSearch[key]; | 163 page = pagesToSearch[key]; |
| 153 this.unhighlightMatches_(page.tab); | 164 pageMatch = false; |
| 154 this.unhighlightMatches_(page.pageDiv); | |
| 155 var pageMatch = false; | |
| 156 if (searchText.length) { | 165 if (searchText.length) { |
| 157 pageMatch = this.performReplace_(regEx, replaceString, page.tab); | 166 pageMatch = this.performReplace_(regEx, replaceString, page.tab); |
| 158 } | 167 } |
| 159 if (pageMatch) | 168 if (pageMatch) |
| 160 foundMatches = true; | 169 foundMatches = true; |
| 161 for (var i = 0; i < page.pageDiv.childNodes.length; i++) { | 170 for (i = 0; i < page.pageDiv.childNodes.length; i++) { |
| 162 var childDiv = page.pageDiv.childNodes[i]; | 171 childDiv = page.pageDiv.childNodes[i]; |
| 163 if (childDiv.nodeType == document.ELEMENT_NODE && | 172 if (childDiv.nodeType == document.ELEMENT_NODE && |
| 164 childDiv.nodeName.toLowerCase() == 'section') { | 173 childDiv.nodeName.toLowerCase() == 'section') { |
| 165 if (pageMatch) { | 174 if (pageMatch) { |
| 166 childDiv.classList.remove('search-hidden'); | 175 childDiv.classList.remove('search-hidden'); |
| 167 } else { | 176 } else { |
| 168 childDiv.classList.add('search-hidden'); | 177 childDiv.classList.add('search-hidden'); |
| 169 } | 178 } |
| 170 } | 179 } |
| 171 } | 180 } |
| 172 } | 181 } |
| 173 | 182 |
| 174 // Search all sections for anchored string matches. | |
| 175 if (searchText.length) { | 183 if (searchText.length) { |
| 176 for (var key in pagesToSearch) { | 184 // Search all sub-pages, generating an array of top-level sections that |
| 177 var page = pagesToSearch[key]; | 185 // we need to make visible. |
| 178 for (var i = 0; i < page.pageDiv.childNodes.length; i++) { | 186 var subPagesToSearch = this.getSearchableSubPages_(); |
| 179 var childDiv = page.pageDiv.childNodes[i]; | 187 var control, node; |
| 188 for (key in subPagesToSearch) { | |
| 189 page = subPagesToSearch[key]; | |
| 190 if (this.performReplace_(regEx, replaceString, page.pageDiv)) { | |
| 191 section = page.associatedSection; | |
| 192 if (section) | |
| 193 section.classList.remove('search-hidden'); | |
| 194 controls = page.associatedControls; | |
| 195 if (controls) { | |
| 196 // TODO(csilv): highlight each control. | |
| 197 } | |
| 198 | |
| 199 foundMatches = true; | |
| 200 } | |
| 201 } | |
| 202 | |
| 203 // Search all top-level sections for anchored string matches. | |
| 204 for (key in pagesToSearch) { | |
| 205 page = pagesToSearch[key]; | |
| 206 for (i = 0; i < page.pageDiv.childNodes.length; i++) { | |
| 207 childDiv = page.pageDiv.childNodes[i]; | |
| 180 if (childDiv.nodeType == document.ELEMENT_NODE && | 208 if (childDiv.nodeType == document.ELEMENT_NODE && |
| 181 childDiv.nodeName.toLowerCase() == 'section' && | 209 childDiv.nodeName.toLowerCase() == 'section' && |
| 182 this.performReplace_(regEx, replaceString, childDiv)) { | 210 this.performReplace_(regEx, replaceString, childDiv)) { |
| 183 childDiv.classList.remove('search-hidden'); | 211 childDiv.classList.remove('search-hidden'); |
| 184 foundMatches = true; | 212 foundMatches = true; |
| 185 } | 213 } |
| 186 } | 214 } |
| 187 } | 215 } |
| 188 } | 216 } |
| 189 | 217 |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 245 tmp.parentNode.removeChild(tmp); | 273 tmp.parentNode.removeChild(tmp); |
| 246 } else { | 274 } else { |
| 247 node = walker.nextNode(); | 275 node = walker.nextNode(); |
| 248 } | 276 } |
| 249 } | 277 } |
| 250 | 278 |
| 251 return found; | 279 return found; |
| 252 }, | 280 }, |
| 253 | 281 |
| 254 /** | 282 /** |
| 255 * Removes all search highlight tags from a container element. | 283 * Removes all search highlight tags from the document. |
| 256 * @param {Element} element An HTML container element. | |
| 257 * @private | 284 * @private |
| 258 */ | 285 */ |
| 259 unhighlightMatches_: function(element) { | 286 unhighlightMatches_: function() { |
| 260 // Find all search highlight elements. | 287 // Find all search highlight elements. |
| 261 var elements = element.querySelectorAll('.search-highlighted'); | 288 var elements = document.querySelectorAll('.search-highlighted'); |
| 262 | 289 |
| 263 // For each element, remove the highlighting. | 290 // For each element, remove the highlighting. |
| 264 var node, parent, i, length = elements.length; | 291 var node, parent, i, length = elements.length; |
| 265 for (i = 0; i < length; i++) { | 292 for (i = 0; i < length; i++) { |
| 266 node = elements[i]; | 293 node = elements[i]; |
| 267 parent = node.parentNode; | 294 parent = node.parentNode; |
| 268 | 295 |
| 269 // Replace the highlight element with the first child (the text node). | 296 // Replace the highlight element with the first child (the text node). |
| 270 parent.replaceChild(node.firstChild, node); | 297 parent.replaceChild(node.firstChild, node); |
| 271 | 298 |
| 272 // Normalize the parent so that multiple text nodes will be combined. | 299 // Normalize the parent so that multiple text nodes will be combined. |
| 273 parent.normalize(); | 300 parent.normalize(); |
| 274 } | 301 } |
| 275 }, | 302 }, |
| 276 | 303 |
| 277 /** | 304 /** |
| 278 * Builds a list of pages to search. Omits the search page. | 305 * Builds a list of top-level pages to search. Omits the search page and |
| 306 * all sub-pages. | |
| 279 * @returns {Array} An array of pages to search. | 307 * @returns {Array} An array of pages to search. |
| 280 * @private | 308 * @private |
| 281 */ | 309 */ |
| 282 getSearchablePages_: function() { | 310 getSearchablePages_: function() { |
| 283 var pages = []; | 311 var name, page, pages = []; |
| 284 for (var name in OptionsPage.registeredPages) { | 312 for (name in OptionsPage.registeredPages) { |
| 285 if (name != this.name) | 313 if (name != this.name) { |
| 286 pages.push(OptionsPage.registeredPages[name]); | 314 page = OptionsPage.registeredPages[name]; |
| 315 if (!page.parentPage) | |
| 316 pages.push(page); | |
| 317 } | |
| 318 } | |
| 319 return pages; | |
| 320 }, | |
| 321 | |
| 322 /** | |
| 323 * Builds a list of sub-pages (and overlay pages) to search. Ignore pages | |
| 324 * that have no associated controls. | |
| 325 * @returns {Array} An array of pages to search. | |
| 326 * @private | |
| 327 */ | |
| 328 getSearchableSubPages_: function() { | |
| 329 var name, pageInfo, page, pages = []; | |
| 330 for (name in OptionsPage.registeredPages) { | |
| 331 page = OptionsPage.registeredPages[name]; | |
| 332 if (page.parentPage && page.associatedSection) | |
| 333 pages.push(page); | |
| 334 } | |
| 335 for (name in OptionsPage.registeredOverlayPages) { | |
| 336 page = OptionsPage.registeredOverlayPages[name]; | |
| 337 if (page.associatedSection && page.pageDiv != undefined) | |
| 338 pages.push(page); | |
| 287 } | 339 } |
| 288 return pages; | 340 return pages; |
| 289 } | 341 } |
| 290 }; | 342 }; |
| 291 | 343 |
| 292 // Export | 344 // Export |
| 293 return { | 345 return { |
| 294 SearchPage: SearchPage | 346 SearchPage: SearchPage |
| 295 }; | 347 }; |
| 296 | 348 |
| 297 }); | 349 }); |
| OLD | NEW |