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 */ | 11 */ |
| 11 function SearchPage() { | 12 function SearchPage() { |
| 12 OptionsPage.call(this, 'search', templateData.searchPage, 'searchPage'); | 13 OptionsPage.call(this, 'search', templateData.searchPage, 'searchPage'); |
| 14 this.searchActive = false; | |
| 13 } | 15 } |
| 14 | 16 |
| 15 cr.addSingletonGetter(SearchPage); | 17 cr.addSingletonGetter(SearchPage); |
| 16 | 18 |
| 17 SearchPage.prototype = { | 19 SearchPage.prototype = { |
| 18 // Inherit SearchPage from OptionsPage. | 20 // Inherit SearchPage from OptionsPage. |
| 19 __proto__: OptionsPage.prototype, | 21 __proto__: OptionsPage.prototype, |
| 20 | 22 |
| 21 // Initialize SearchPage. | 23 /** |
| 24 * Initialize the page. | |
| 25 */ | |
| 22 initializePage: function() { | 26 initializePage: function() { |
| 23 // Call base class implementation to start preference initialization. | 27 // Call base class implementation to start preference initialization. |
| 24 OptionsPage.prototype.initializePage.call(this); | 28 OptionsPage.prototype.initializePage.call(this); |
| 25 | 29 |
| 30 var self = this; | |
| 31 | |
| 26 // Create a search field element. | 32 // Create a search field element. |
| 27 var searchField = document.createElement('input'); | 33 var searchField = document.createElement('input'); |
| 28 searchField.id = 'searchField'; | 34 searchField.id = 'searchField'; |
| 29 searchField.type = 'search'; | 35 searchField.type = 'search'; |
| 30 searchField.setAttribute('autosave', 'org.chromium.options.search'); | 36 searchField.setAttribute('autosave', 'org.chromium.options.search'); |
| 31 searchField.setAttribute('results', '10'); | 37 searchField.setAttribute('results', '10'); |
| 38 searchField.setAttribute('incremental', 'true'); | |
| 32 | 39 |
| 33 // Replace the contents of the navigation tab with the search field. | 40 // Replace the contents of the navigation tab with the search field. |
| 34 this.tab.textContent = ''; | 41 self.tab.textContent = ''; |
| 35 this.tab.appendChild(searchField); | 42 self.tab.appendChild(searchField); |
| 43 | |
| 44 // Handle search events. (No need to throttle, WebKit's search field | |
| 45 // will do that automatically.) | |
| 46 searchField.onsearch = function(e) { | |
| 47 self.setSearchText_(this.value); | |
| 48 }; | |
| 36 }, | 49 }, |
| 37 }; | |
| 38 | 50 |
| 39 SearchPage.updateForEmptySearch = function() { | 51 /** |
| 40 $('searchPageInfo').classList.remove('hidden'); | 52 * Called after this page has shown. |
| 41 $('searchPageNoMatches').classList.add('hidden'); | 53 */ |
| 42 }; | 54 didShowPage: function() { |
| 55 this.setSearchActive_(true); | |
|
James Hawkins
2010/12/02 23:11:44
It looks like setSearchActive_ is synonymous with
csilv
2010/12/02 23:40:21
setSearchActive_() performs a bunch of dom manipul
| |
| 56 }, | |
| 43 | 57 |
| 44 SearchPage.updateForNoSearchResults = function(message) { | 58 /** |
| 45 $('searchPageInfo').classList.add('hidden'); | 59 * Called before this page will be hidden. |
| 46 $('searchPageNoMatches').classList.remove('hidden'); | 60 */ |
| 47 }; | 61 willHidePage: function() { |
|
James Hawkins
2010/12/02 23:11:44
You're using willHidePage here but didShowPage abo
csilv
2010/12/02 23:40:21
The reason is that when search is made active, we
| |
| 62 this.setSearchActive_(false); | |
| 63 }, | |
| 48 | 64 |
| 49 SearchPage.updateForSuccessfulSearch = function(enable) { | 65 /** |
| 50 $('searchPageInfo').classList.add('hidden'); | 66 * Update the UI to reflect whether we are in a search state. |
| 51 $('searchPageNoMatches').classList.add('hidden'); | 67 * @param {boolean} active True if we are on the search page. |
| 68 * @private | |
| 69 */ | |
| 70 setSearchActive_: function(active) { | |
| 71 // It's fine to exit if search wasn't active and we're not going to | |
| 72 // activate it now. | |
| 73 if (!this.searchActive_ && !active) | |
| 74 return; | |
| 75 | |
| 76 if (this.searchActive_ != active) { | |
| 77 this.searchActive_ = active; | |
| 78 if (active) { | |
| 79 // Reset the search criteria, effectively hiding all the sections. | |
| 80 this.setSearchText_(''); | |
| 81 } else { | |
| 82 // Just wipe out any active search text since it's no longer relevant. | |
| 83 $('searchField').value = ''; | |
| 84 } | |
| 85 } | |
| 86 | |
| 87 var page, length, childDiv; | |
| 88 | |
| 89 for (var name in OptionsPage.registeredPages) { | |
| 90 if (name == this.name) | |
| 91 continue; | |
| 92 | |
| 93 // Update the visible state of all top-level elements that are not | |
| 94 // sections (ie titles, button strips). | |
| 95 page = OptionsPage.registeredPages[name]; | |
| 96 length = page.pageDiv.childNodes.length; | |
| 97 for (var i = 0; i < length; i++) { | |
| 98 childDiv = page.pageDiv.childNodes[i]; | |
| 99 if (childDiv.nodeType == 1) { | |
| 100 if (active) { | |
| 101 if (childDiv.nodeName.toLowerCase() != 'section') | |
| 102 childDiv.classList.add('search-hidden'); | |
| 103 } else { | |
| 104 childDiv.classList.remove('search-hidden'); | |
| 105 } | |
| 106 } | |
| 107 } | |
| 108 | |
| 109 // Toggle the visibility state of the page. | |
| 110 if (active) { | |
| 111 // When search is active, remove the 'hidden' tag. This tag may have | |
| 112 // been added by the OptionsPage. | |
| 113 page.pageDiv.classList.remove('hidden'); | |
| 114 } else { | |
| 115 page.visible = false; | |
| 116 } | |
| 117 } | |
| 118 }, | |
| 119 | |
| 120 /** | |
| 121 * Set the current search criteria. | |
| 122 * @param {string} text Search text. | |
| 123 * @private | |
| 124 */ | |
| 125 setSearchText_: function(text) { | |
| 126 if (!this.searchActive_) | |
|
James Hawkins
2010/12/02 23:11:44
When can setSearchText_() be called when search is
csilv
2010/12/02 23:40:21
Perhaps never. I need to test whether an explicit
csilv
2010/12/03 00:03:31
After testing, removed this check, it's not needed
| |
| 127 return; | |
| 128 | |
| 129 var searchText = text.toLowerCase(); | |
| 130 var foundMatches = false; | |
| 131 | |
| 132 // Build a list of pages to search. Omit the search page. | |
| 133 var pagesToSearch = []; | |
| 134 for (var name in OptionsPage.registeredPages) { | |
| 135 if (name != this.name) | |
| 136 pagesToSearch.push(OptionsPage.registeredPages[name]); | |
| 137 } | |
| 138 | |
| 139 // Hide all sections. If the search string matches a title page, show | |
| 140 // all sections of that page. | |
| 141 for (var key in pagesToSearch) { | |
| 142 var page = pagesToSearch[key]; | |
| 143 var pageTitle = page.title.toLowerCase(); | |
| 144 // Hide non-sections in each page. | |
| 145 for (var i = 0; i < page.pageDiv.childNodes.length; i++) { | |
| 146 var childDiv = page.pageDiv.childNodes[i]; | |
| 147 if (childDiv.nodeType == 1 && | |
| 148 childDiv.nodeName.toLowerCase() == 'section') { | |
| 149 if (pageTitle == searchText) { | |
| 150 childDiv.classList.remove('search-hidden'); | |
| 151 foundMatches = true; | |
| 152 } else { | |
| 153 childDiv.classList.add('search-hidden'); | |
| 154 } | |
| 155 } | |
| 156 } | |
| 157 } | |
| 158 | |
| 159 // Now search all sections for anchored string matches. | |
| 160 if (!foundMatches && searchText.length) { | |
| 161 var searchRegEx = new RegExp('\\b' + searchText, 'i'); | |
| 162 for (var key in pagesToSearch) { | |
| 163 var page = pagesToSearch[key]; | |
| 164 for (var i = 0; i < page.pageDiv.childNodes.length; i++) { | |
| 165 var childDiv = page.pageDiv.childNodes[i]; | |
| 166 if (childDiv.nodeType == 1 && | |
| 167 childDiv.nodeName.toLowerCase() == 'section') { | |
| 168 var isMatch = false; | |
| 169 var sectionElements = childDiv.getElementsByTagName("*"); | |
| 170 var length = sectionElements.length; | |
| 171 var element; | |
| 172 for (var j = 0; j < length; j++) { | |
| 173 element = sectionElements[j]; | |
| 174 if (searchRegEx.test(element.textContent)) { | |
| 175 isMatch = true; | |
| 176 break; | |
| 177 } | |
| 178 } | |
| 179 if (isMatch) { | |
| 180 childDiv.classList.remove('search-hidden'); | |
| 181 foundMatches = true; | |
| 182 } | |
| 183 } | |
| 184 } | |
| 185 } | |
| 186 } | |
| 187 | |
| 188 // Configure elements on the search results page based on search results. | |
| 189 if (searchText.length == 0) { | |
| 190 $('searchPageInfo').classList.remove('search-hidden'); | |
| 191 $('searchPageNoMatches').classList.add('search-hidden'); | |
| 192 } else if (foundMatches) { | |
| 193 $('searchPageInfo').classList.add('search-hidden'); | |
| 194 $('searchPageNoMatches').classList.add('search-hidden'); | |
| 195 } else { | |
| 196 $('searchPageInfo').classList.add('search-hidden'); | |
| 197 $('searchPageNoMatches').classList.remove('search-hidden'); | |
| 198 } | |
| 199 } | |
| 52 }; | 200 }; |
| 53 | 201 |
| 54 // Export | 202 // Export |
| 55 return { | 203 return { |
| 56 SearchPage: SearchPage | 204 SearchPage: SearchPage |
| 57 }; | 205 }; |
| 58 | 206 |
| 59 }); | 207 }); |
| OLD | NEW |