diff options
author | csilv@chromium.org <csilv@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-12-06 22:14:44 +0000 |
---|---|---|
committer | csilv@chromium.org <csilv@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-12-06 22:14:44 +0000 |
commit | d65b92c23ff555d478f92d86af5c7c1c65de4965 (patch) | |
tree | eb05728311afa1dd53a602e39ad792e3e8f744c4 | |
parent | 2d0863d1a274b39d6ce9570fe054c0def60319b5 (diff) | |
download | chromium_src-d65b92c23ff555d478f92d86af5c7c1c65de4965.zip chromium_src-d65b92c23ff555d478f92d86af5c7c1c65de4965.tar.gz chromium_src-d65b92c23ff555d478f92d86af5c7c1c65de4965.tar.bz2 |
dom-ui settings:
- Implement search capability for top level panels.
- Code cleanups for options_page.js
BUG=59267
TEST=Verify search field presents results based on user input.
Review URL: http://codereview.chromium.org/5538002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@68390 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | chrome/browser/resources/options.html | 3 | ||||
-rw-r--r-- | chrome/browser/resources/options/options_page.js | 78 | ||||
-rw-r--r-- | chrome/browser/resources/options/search_page.css | 3 | ||||
-rw-r--r-- | chrome/browser/resources/options/search_page.html | 2 | ||||
-rw-r--r-- | chrome/browser/resources/options/search_page.js | 182 |
5 files changed, 223 insertions, 45 deletions
diff --git a/chrome/browser/resources/options.html b/chrome/browser/resources/options.html index eb6448c..92b3b12 100644 --- a/chrome/browser/resources/options.html +++ b/chrome/browser/resources/options.html @@ -28,6 +28,7 @@ <link rel="stylesheet" href="options/personal_options.css"> <link rel="stylesheet" href="options/import_data_overlay.css"> <link rel="stylesheet" href="options/search_engine_manager.css"> +<link rel="stylesheet" href="options/search_page.css"> <link rel="stylesheet" href="options/subpages_tab_controls.css"> <if expr="pp_ifdef('chromeos')"> <link rel="stylesheet" href="options/about_page.css"> @@ -316,7 +317,7 @@ window.onpopstate = function(e) { </ul> </div> <div id="mainview"> - <div class="hidden" id="managed-prefs-banner"> + <div id="managed-prefs-banner" class="hidden"> <span id="managed-prefs-icon"></span> <span id="managed-prefs-text" i18n-content="managedPrefsBannerText"></span> diff --git a/chrome/browser/resources/options/options_page.js b/chrome/browser/resources/options/options_page.js index 18b700e..8b360eb 100644 --- a/chrome/browser/resources/options/options_page.js +++ b/chrome/browser/resources/options/options_page.js @@ -24,20 +24,27 @@ cr.define('options', function() { this.managed = false; } - OptionsPage.registeredPages_ = {}; + /** + * Main level option pages. + * @protected + */ + OptionsPage.registeredPages = {}; /** - * Pages which are nested under a main page. + * Pages which are nested under a main level page. + * @protected */ - OptionsPage.registeredSubPages_ = {}; + OptionsPage.registeredSubPages = {}; /** * Pages which are meant to behave like modal dialogs. + * @protected */ - OptionsPage.registeredOverlayPages_ = {}; + OptionsPage.registeredOverlayPages = {}; /** * Whether or not |initialize| has been called. + * @private */ OptionsPage.initialized_ = false; @@ -46,17 +53,34 @@ cr.define('options', function() { * @param {string} pageName Page name. */ OptionsPage.showPageByName = function(pageName) { - for (var name in OptionsPage.registeredPages_) { - var page = OptionsPage.registeredPages_[name]; + // Notify main pages if they will be hidden. + for (var name in this.registeredPages) { + var page = this.registeredPages[name]; + if (name != pageName && page.willHidePage) + page.willHidePage(); + } + + // Update the visibility attribute for main pages. + for (var name in this.registeredPages) { + var page = this.registeredPages[name]; page.visible = name == pageName; } - for (var name in OptionsPage.registeredSubPages_) { - var pageInfo = OptionsPage.registeredSubPages_[name]; + + // Update the visibility attribute for sub-pages. + for (var name in this.registeredSubPages) { + var pageInfo = this.registeredSubPages[name]; var match = name == pageName; if (match) pageInfo.parentPage.visible = true; pageInfo.page.visible = match; } + + // Notify main pages if they were shown. + for (var name in this.registeredPages) { + var page = this.registeredPages[name]; + if (name == pageName && page.didShowPage) + page.didShowPage(); + } }; /** @@ -66,9 +90,9 @@ cr.define('options', function() { * @param {string} hash The value of the hash component of the URL. */ OptionsPage.handleHashForPage = function(pageName, hash) { - var page = OptionsPage.registeredPages_[pageName]; + var page = this.registeredPages[pageName]; if (!page) { - page = OptionsPage.registeredSubPages_[pageName].page; + page = this.registeredSubPages[pageName].page; } page.handleHash(hash); }; @@ -78,8 +102,8 @@ cr.define('options', function() { * @param {string} overlayName Page name. */ OptionsPage.showOverlay = function(overlayName) { - if (OptionsPage.registeredOverlayPages_[overlayName]) { - OptionsPage.registeredOverlayPages_[overlayName].visible = true; + if (this.registeredOverlayPages[overlayName]) { + this.registeredOverlayPages[overlayName].visible = true; } }; @@ -87,20 +111,20 @@ cr.define('options', function() { * Clears overlays (i.e. hide all overlays). */ OptionsPage.clearOverlays = function() { - for (var name in OptionsPage.registeredOverlayPages_) { - var page = OptionsPage.registeredOverlayPages_[name]; + for (var name in this.registeredOverlayPages) { + var page = this.registeredOverlayPages[name]; page.visible = false; } }; /** - * Clears overlays if the key event is ESC. + * Handle 'keydown' events. * @param {Event} e Key event. * @private */ - OptionsPage.clearOverlaysOnEsc_ = function(e) { + OptionsPage.onKeyDown_ = function(e) { if (e.keyCode == 27) { // Esc - OptionsPage.clearOverlays(); + this.clearOverlays(); } }; @@ -108,8 +132,8 @@ cr.define('options', function() { * Closes any currently-open subpage. */ OptionsPage.closeSubPage = function() { - for (var name in OptionsPage.registeredSubPages_) { - var pageInfo = OptionsPage.registeredSubPages_[name]; + for (var name in this.registeredSubPages) { + var pageInfo = this.registeredSubPages[name]; if (pageInfo.page.visible) { pageInfo.page.visible = false; // Since the managed pref banner lives outside the overlay, and the @@ -149,7 +173,7 @@ cr.define('options', function() { * @param {OptionsPage} page Page to register. */ OptionsPage.register = function(page) { - OptionsPage.registeredPages_[page.name] = page; + this.registeredPages[page.name] = page; // Create and add new page <li> element to navbar. var pageNav = document.createElement('li'); pageNav.id = page.name + 'PageNav'; @@ -177,7 +201,7 @@ cr.define('options', function() { * @param {OptionsPage} page Page to register. */ OptionsPage.registerSubPage = function(subPage, parentPage) { - OptionsPage.registeredSubPages_[subPage.name] = { + this.registeredSubPages[subPage.name] = { page: subPage, parentPage: parentPage }; subPage.tab = undefined; subPage.isSubPageSheet = true; @@ -190,7 +214,7 @@ cr.define('options', function() { * OptionsPage. */ OptionsPage.registerOverlay = function(page) { - OptionsPage.registeredOverlayPages_[page.name] = page; + this.registeredOverlayPages[page.name] = page; page.tab = undefined; page.isOverlay = true; page.initializePage(); @@ -202,7 +226,7 @@ cr.define('options', function() { */ OptionsPage.setState = function(data) { if (data && data.pageName) { - OptionsPage.showPageByName(data.pageName); + this.showPageByName(data.pageName); } }; @@ -218,7 +242,7 @@ cr.define('options', function() { // should close the overlay, not fall through to the parent page. $('subpage-sheet-container').onclick = function(event) { if (!$('subpage-sheet').contains(event.target)) - OptionsPage.closeSubPage(); + this.closeSubPage(); event.stopPropagation(); } }; @@ -284,8 +308,7 @@ cr.define('options', function() { this.pageDiv.classList.remove('hidden'); if (this.isOverlay) { $('overlay').classList.remove('hidden'); - document.addEventListener('keydown', - OptionsPage.clearOverlaysOnEsc_); + document.addEventListener('keydown', OptionsPage.onKeyDown_); } else { if (this.isSubPageSheet) $('subpage-sheet-container').classList.remove('hidden'); @@ -302,8 +325,7 @@ cr.define('options', function() { this.pageDiv.classList.add('hidden'); if (this.isOverlay) { $('overlay').classList.add('hidden'); - document.removeEventListener('keydown', - OptionsPage.clearOverlaysOnEsc_); + document.removeEventListener('keydown', OptionsPage.onKeyDown_); } else if (this.isSubPageSheet) { $('subpage-sheet-container').classList.add('hidden'); } diff --git a/chrome/browser/resources/options/search_page.css b/chrome/browser/resources/options/search_page.css new file mode 100644 index 0000000..03a775e --- /dev/null +++ b/chrome/browser/resources/options/search_page.css @@ -0,0 +1,3 @@ +.search-hidden { + display: none; +} diff --git a/chrome/browser/resources/options/search_page.html b/chrome/browser/resources/options/search_page.html index 413ce56..9c12cf2 100644 --- a/chrome/browser/resources/options/search_page.html +++ b/chrome/browser/resources/options/search_page.html @@ -3,7 +3,7 @@ <div id="searchPageInfo"> <p i18n-content="searchPageInfo"></p> </div> - <div id="searchPageNoMatches" class="hidden"> + <div id="searchPageNoMatches"> <p i18n-content="searchPageNoMatches"></p> <p><span i18n-content="searchPageHelpLabel"></span> <a target=_blank" i18n-content="searchPageHelpTitle" diff --git a/chrome/browser/resources/options/search_page.js b/chrome/browser/resources/options/search_page.js index 1951f8f..feec95a 100644 --- a/chrome/browser/resources/options/search_page.js +++ b/chrome/browser/resources/options/search_page.js @@ -7,9 +7,11 @@ cr.define('options', function() { /** * Encapsulated handling of the search page. + * @constructor */ function SearchPage() { OptionsPage.call(this, 'search', templateData.searchPage, 'searchPage'); + this.searchActive = false; } cr.addSingletonGetter(SearchPage); @@ -18,37 +20,187 @@ cr.define('options', function() { // Inherit SearchPage from OptionsPage. __proto__: OptionsPage.prototype, - // Initialize SearchPage. + /** + * Initialize the page. + */ initializePage: function() { // Call base class implementation to start preference initialization. OptionsPage.prototype.initializePage.call(this); + var self = this; + // Create a search field element. var searchField = document.createElement('input'); searchField.id = 'searchField'; searchField.type = 'search'; searchField.setAttribute('autosave', 'org.chromium.options.search'); searchField.setAttribute('results', '10'); + searchField.setAttribute('incremental', 'true'); // Replace the contents of the navigation tab with the search field. - this.tab.textContent = ''; - this.tab.appendChild(searchField); + self.tab.textContent = ''; + self.tab.appendChild(searchField); + + // Handle search events. (No need to throttle, WebKit's search field + // will do that automatically.) + searchField.onsearch = function(e) { + self.setSearchText_(this.value); + }; }, - }; - SearchPage.updateForEmptySearch = function() { - $('searchPageInfo').classList.remove('hidden'); - $('searchPageNoMatches').classList.add('hidden'); - }; + /** + * Called after this page has shown. + */ + didShowPage: function() { + // This method is called by the Options page after all pages have + // had their visibilty attribute set. At this point we can perform the + // search specific DOM manipulation. + this.setSearchActive_(true); + }, - SearchPage.updateForNoSearchResults = function(message) { - $('searchPageInfo').classList.add('hidden'); - $('searchPageNoMatches').classList.remove('hidden'); - }; + /** + * Called before this page will be hidden. + */ + willHidePage: function() { + // This method is called by the Options page before all pages have + // their visibilty attribute set. Before that happens, we need to + // undo the search specific DOM manipulation that was performed in + // didShowPage. + this.setSearchActive_(false); + }, + + /** + * Update the UI to reflect whether we are in a search state. + * @param {boolean} active True if we are on the search page. + * @private + */ + setSearchActive_: function(active) { + // It's fine to exit if search wasn't active and we're not going to + // activate it now. + if (!this.searchActive_ && !active) + return; + + if (this.searchActive_ != active) { + this.searchActive_ = active; + if (active) { + // Reset the search criteria, effectively hiding all the sections. + this.setSearchText_(''); + } else { + // Just wipe out any active search text since it's no longer relevant. + $('searchField').value = ''; + } + } + + var page, length, childDiv; + for (var name in OptionsPage.registeredPages) { + if (name == this.name) + continue; + + // 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]; + if (childDiv.nodeType == 1) { + if (active) { + if (childDiv.nodeName.toLowerCase() != 'section') + childDiv.classList.add('search-hidden'); + } else { + childDiv.classList.remove('search-hidden'); + } + } + } + + // Toggle the visibility state of the page. + if (active) { + // 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; + } + } + }, + + /** + * Set the current search criteria. + * @param {string} text Search text. + * @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]); + } + + // Hide all sections. If the search string matches a title page, show + // all sections of that page. + for (var key in pagesToSearch) { + var page = pagesToSearch[key]; + var pageTitle = page.title.toLowerCase(); + // Hide non-sections in each page. + 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) { + childDiv.classList.remove('search-hidden'); + foundMatches = true; + } else { + childDiv.classList.add('search-hidden'); + } + } + } + } + + // Now search all sections for anchored string matches. + if (!foundMatches && searchText.length) { + var searchRegEx = new RegExp('\\b' + searchText, 'i'); + 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; + } + } + } + } + } - SearchPage.updateForSuccessfulSearch = function(enable) { - $('searchPageInfo').classList.add('hidden'); - $('searchPageNoMatches').classList.add('hidden'); + // Configure elements on the search results page based on search results. + if (searchText.length == 0) { + $('searchPageInfo').classList.remove('search-hidden'); + $('searchPageNoMatches').classList.add('search-hidden'); + } else if (foundMatches) { + $('searchPageInfo').classList.add('search-hidden'); + $('searchPageNoMatches').classList.add('search-hidden'); + } else { + $('searchPageInfo').classList.add('search-hidden'); + $('searchPageNoMatches').classList.remove('search-hidden'); + } + } }; // Export |