Index: chrome/browser/resources/options/options_page.js |
=================================================================== |
--- chrome/browser/resources/options/options_page.js (revision 84868) |
+++ chrome/browser/resources/options/options_page.js (working copy) |
@@ -1,996 +0,0 @@ |
-// Copyright (c) 2011 The Chromium Authors. All rights reserved. |
-// Use of this source code is governed by a BSD-style license that can be |
-// found in the LICENSE file. |
- |
-cr.define('options', function() { |
- ///////////////////////////////////////////////////////////////////////////// |
- // OptionsPage class: |
- |
- /** |
- * Base class for options page. |
- * @constructor |
- * @param {string} name Options page name, also defines id of the div element |
- * containing the options view and the name of options page navigation bar |
- * item as name+'PageNav'. |
- * @param {string} title Options page title, used for navigation bar |
- * @extends {EventTarget} |
- */ |
- function OptionsPage(name, title, pageDivName) { |
- this.name = name; |
- this.title = title; |
- this.pageDivName = pageDivName; |
- this.pageDiv = $(this.pageDivName); |
- this.tab = null; |
- this.managed = false; |
- } |
- |
- const SUBPAGE_SHEET_COUNT = 2; |
- |
- /** |
- * Main level option pages. |
- * @protected |
- */ |
- OptionsPage.registeredPages = {}; |
- |
- /** |
- * Pages which are meant to behave like modal dialogs. |
- * @protected |
- */ |
- OptionsPage.registeredOverlayPages = {}; |
- |
- /** |
- * Whether or not |initialize| has been called. |
- * @private |
- */ |
- OptionsPage.initialized_ = false; |
- |
- /** |
- * Gets the default page (to be shown on initial load). |
- */ |
- OptionsPage.getDefaultPage = function() { |
- return BrowserOptions.getInstance(); |
- }; |
- |
- /** |
- * Shows the default page. |
- */ |
- OptionsPage.showDefaultPage = function() { |
- this.navigateToPage(this.getDefaultPage().name); |
- }; |
- |
- /** |
- * "Navigates" to a page, meaning that the page will be shown and the |
- * appropriate entry is placed in the history. |
- * @param {string} pageName Page name. |
- */ |
- OptionsPage.navigateToPage = function(pageName) { |
- this.showPageByName(pageName, true); |
- }; |
- |
- /** |
- * Shows a registered page. This handles both top-level pages and sub-pages. |
- * @param {string} pageName Page name. |
- * @param {boolean} updateHistory True if we should update the history after |
- * showing the page. |
- * @private |
- */ |
- OptionsPage.showPageByName = function(pageName, updateHistory) { |
- // Find the currently visible root-level page. |
- var rootPage = null; |
- for (var name in this.registeredPages) { |
- var page = this.registeredPages[name]; |
- if (page.visible && !page.parentPage) { |
- rootPage = page; |
- break; |
- } |
- } |
- |
- // Find the target page. |
- var targetPage = this.registeredPages[pageName]; |
- if (!targetPage || !targetPage.canShowPage()) { |
- // If it's not a page, try it as an overlay. |
- if (!targetPage && this.showOverlay_(pageName, rootPage)) { |
- if (updateHistory) |
- this.updateHistoryState_(); |
- return; |
- } else { |
- targetPage = this.getDefaultPage(); |
- } |
- } |
- |
- pageName = targetPage.name; |
- |
- // Determine if the root page is 'sticky', meaning that it |
- // shouldn't change when showing a sub-page. This can happen for special |
- // pages like Search. |
- var isRootPageLocked = |
- rootPage && rootPage.sticky && targetPage.parentPage; |
- |
- // Notify pages if they will be hidden. |
- for (var name in this.registeredPages) { |
- var page = this.registeredPages[name]; |
- if (!page.parentPage && isRootPageLocked) |
- continue; |
- if (page.willHidePage && name != pageName && |
- !page.isAncestorOfPage(targetPage)) |
- page.willHidePage(); |
- } |
- |
- // Update visibilities to show only the hierarchy of the target page. |
- for (var name in this.registeredPages) { |
- var page = this.registeredPages[name]; |
- if (!page.parentPage && isRootPageLocked) |
- continue; |
- page.visible = name == pageName || |
- (!document.documentElement.classList.contains('hide-menu') && |
- page.isAncestorOfPage(targetPage)); |
- } |
- |
- // Update the history and current location. |
- if (updateHistory) |
- this.updateHistoryState_(); |
- |
- // Always update the page title. |
- document.title = targetPage.title; |
- |
- // Notify pages if they were shown. |
- for (var name in this.registeredPages) { |
- var page = this.registeredPages[name]; |
- if (!page.parentPage && isRootPageLocked) |
- continue; |
- if (page.didShowPage && (name == pageName || |
- page.isAncestorOfPage(targetPage))) |
- page.didShowPage(); |
- } |
- }; |
- |
- /** |
- * Updates the visibility and stacking order of the subpage backdrop |
- * according to which subpage is topmost and visible. |
- * @private |
- */ |
- OptionsPage.updateSubpageBackdrop_ = function () { |
- var topmostPage = this.getTopmostVisibleNonOverlayPage_(); |
- var nestingLevel = topmostPage ? topmostPage.nestingLevel : 0; |
- |
- var subpageBackdrop = $('subpage-backdrop'); |
- if (nestingLevel > 0) { |
- var container = $('subpage-sheet-container-' + nestingLevel); |
- subpageBackdrop.style.zIndex = |
- parseInt(window.getComputedStyle(container).zIndex) - 1; |
- subpageBackdrop.hidden = false; |
- } else { |
- subpageBackdrop.hidden = true; |
- } |
- }; |
- |
- /** |
- * Pushes the current page onto the history stack, overriding the last page |
- * if it is the generic chrome://settings/. |
- * @private |
- */ |
- OptionsPage.updateHistoryState_ = function() { |
- var page = this.getTopmostVisiblePage(); |
- var path = location.pathname; |
- if (path) |
- path = path.slice(1); |
- // The page is already in history (the user may have clicked the same link |
- // twice). Do nothing. |
- if (path == page.name) |
- return; |
- |
- // If there is no path, the current location is chrome://settings/. |
- // Override this with the new page. |
- var historyFunction = path ? window.history.pushState : |
- window.history.replaceState; |
- historyFunction.call(window.history, |
- {pageName: page.name}, |
- page.title, |
- '/' + page.name); |
- // Update tab title. |
- document.title = page.title; |
- }; |
- |
- /** |
- * Shows a registered Overlay page. Does not update history. |
- * @param {string} overlayName Page name. |
- * @param {OptionPage} rootPage The currently visible root-level page. |
- * @return {boolean} whether we showed an overlay. |
- */ |
- OptionsPage.showOverlay_ = function(overlayName, rootPage) { |
- var overlay = this.registeredOverlayPages[overlayName]; |
- if (!overlay || !overlay.canShowPage()) |
- return false; |
- |
- if ((!rootPage || !rootPage.sticky) && overlay.parentPage) |
- this.showPageByName(overlay.parentPage.name, false); |
- |
- overlay.visible = true; |
- if (overlay.didShowPage) overlay.didShowPage(); |
- return true; |
- }; |
- |
- /** |
- * Returns whether or not an overlay is visible. |
- * @return {boolean} True if an overlay is visible. |
- * @private |
- */ |
- OptionsPage.isOverlayVisible_ = function() { |
- return this.getVisibleOverlay_() != null; |
- }; |
- |
- /** |
- * @return {boolean} True if the visible overlay should be closed. |
- * @private |
- */ |
- OptionsPage.shouldCloseOverlay_ = function() { |
- var overlay = this.getVisibleOverlay_(); |
- return overlay && overlay.shouldClose(); |
- }; |
- |
- /** |
- * Returns the currently visible overlay, or null if no page is visible. |
- * @return {OptionPage} The visible overlay. |
- */ |
- OptionsPage.getVisibleOverlay_ = function() { |
- for (var name in this.registeredOverlayPages) { |
- var page = this.registeredOverlayPages[name]; |
- if (page.visible) |
- return page; |
- } |
- return null; |
- }; |
- |
- /** |
- * Closes the visible overlay. Updates the history state after closing the |
- * overlay. |
- */ |
- OptionsPage.closeOverlay = function() { |
- var overlay = this.getVisibleOverlay_(); |
- if (!overlay) |
- return; |
- |
- overlay.visible = false; |
- if (overlay.didClosePage) overlay.didClosePage(); |
- this.updateHistoryState_(); |
- }; |
- |
- /** |
- * Hides the visible overlay. Does not affect the history state. |
- * @private |
- */ |
- OptionsPage.hideOverlay_ = function() { |
- var overlay = this.getVisibleOverlay_(); |
- if (overlay) |
- overlay.visible = false; |
- }; |
- |
- /** |
- * Returns the topmost visible page (overlays excluded). |
- * @return {OptionPage} The topmost visible page aside any overlay. |
- * @private |
- */ |
- OptionsPage.getTopmostVisibleNonOverlayPage_ = function() { |
- var topPage = null; |
- for (var name in this.registeredPages) { |
- var page = this.registeredPages[name]; |
- if (page.visible && |
- (!topPage || page.nestingLevel > topPage.nestingLevel)) |
- topPage = page; |
- } |
- |
- return topPage; |
- }; |
- |
- /** |
- * Returns the topmost visible page, or null if no page is visible. |
- * @return {OptionPage} The topmost visible page. |
- */ |
- OptionsPage.getTopmostVisiblePage = function() { |
- // Check overlays first since they're top-most if visible. |
- return this.getVisibleOverlay_() || this.getTopmostVisibleNonOverlayPage_(); |
- }; |
- |
- /** |
- * Closes the topmost open subpage, if any. |
- * @private |
- */ |
- OptionsPage.closeTopSubPage_ = function() { |
- var topPage = this.getTopmostVisiblePage(); |
- if (topPage && !topPage.isOverlay && topPage.parentPage) |
- topPage.visible = false; |
- |
- this.updateHistoryState_(); |
- }; |
- |
- /** |
- * Closes all subpages below the given level. |
- * @param {number} level The nesting level to close below. |
- */ |
- OptionsPage.closeSubPagesToLevel = function(level) { |
- var topPage = this.getTopmostVisiblePage(); |
- while (topPage && topPage.nestingLevel > level) { |
- topPage.visible = false; |
- topPage = topPage.parentPage; |
- } |
- |
- this.updateHistoryState_(); |
- }; |
- |
- /** |
- * Updates managed banner visibility state based on the topmost page. |
- */ |
- OptionsPage.updateManagedBannerVisibility = function() { |
- var topPage = this.getTopmostVisiblePage(); |
- if (topPage) |
- topPage.updateManagedBannerVisibility(); |
- }; |
- |
- /** |
- * Shows the tab contents for the given navigation tab. |
- * @param {!Element} tab The tab that the user clicked. |
- */ |
- OptionsPage.showTab = function(tab) { |
- // Search parents until we find a tab, or the nav bar itself. This allows |
- // tabs to have child nodes, e.g. labels in separately-styled spans. |
- while (tab && !tab.classList.contains('subpages-nav-tabs') && |
- !tab.classList.contains('tab')) { |
- tab = tab.parentNode; |
- } |
- if (!tab || !tab.classList.contains('tab')) |
- return; |
- |
- if (this.activeNavTab != null) { |
- this.activeNavTab.classList.remove('active-tab'); |
- $(this.activeNavTab.getAttribute('tab-contents')).classList. |
- remove('active-tab-contents'); |
- } |
- |
- tab.classList.add('active-tab'); |
- $(tab.getAttribute('tab-contents')).classList.add('active-tab-contents'); |
- this.activeNavTab = tab; |
- }; |
- |
- /** |
- * Registers new options page. |
- * @param {OptionsPage} page Page to register. |
- */ |
- OptionsPage.register = function(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'; |
- pageNav.className = 'navbar-item'; |
- pageNav.setAttribute('pageName', page.name); |
- pageNav.textContent = page.pageDiv.querySelector('h1').textContent; |
- pageNav.tabIndex = 0; |
- pageNav.onclick = function(event) { |
- OptionsPage.navigateToPage(this.getAttribute('pageName')); |
- }; |
- pageNav.onkeypress = function(event) { |
- // Enter or space |
- if (event.keyCode == 13 || event.keyCode == 32) { |
- OptionsPage.navigateToPage(this.getAttribute('pageName')); |
- } |
- }; |
- var navbar = $('navbar'); |
- navbar.appendChild(pageNav); |
- page.tab = pageNav; |
- page.initializePage(); |
- }; |
- |
- /** |
- * Find an enclosing section for an element if it exists. |
- * @param {Element} element Element to search. |
- * @return {OptionPage} The section element, or null. |
- * @private |
- */ |
- OptionsPage.findSectionForNode_ = function(node) { |
- while (node = node.parentNode) { |
- if (node.nodeName == 'SECTION') |
- return node; |
- } |
- return null; |
- }; |
- |
- /** |
- * Registers a new Sub-page. |
- * @param {OptionsPage} subPage Sub-page to register. |
- * @param {OptionsPage} parentPage Associated parent page for this page. |
- * @param {Array} associatedControls Array of control elements that lead to |
- * this sub-page. The first item is typically a button in a root-level |
- * page. There may be additional buttons for nested sub-pages. |
- */ |
- OptionsPage.registerSubPage = function(subPage, |
- parentPage, |
- associatedControls) { |
- this.registeredPages[subPage.name] = subPage; |
- subPage.parentPage = parentPage; |
- if (associatedControls) { |
- subPage.associatedControls = associatedControls; |
- if (associatedControls.length) { |
- subPage.associatedSection = |
- this.findSectionForNode_(associatedControls[0]); |
- } |
- } |
- subPage.tab = undefined; |
- subPage.initializePage(); |
- }; |
- |
- /** |
- * Registers a new Overlay page. |
- * @param {OptionsPage} overlay Overlay to register. |
- * @param {OptionsPage} parentPage Associated parent page for this overlay. |
- * @param {Array} associatedControls Array of control elements associated with |
- * this page. |
- */ |
- OptionsPage.registerOverlay = function(overlay, |
- parentPage, |
- associatedControls) { |
- this.registeredOverlayPages[overlay.name] = overlay; |
- overlay.parentPage = parentPage; |
- if (associatedControls) { |
- overlay.associatedControls = associatedControls; |
- if (associatedControls.length) { |
- overlay.associatedSection = |
- this.findSectionForNode_(associatedControls[0]); |
- } |
- } |
- overlay.tab = undefined; |
- overlay.isOverlay = true; |
- overlay.initializePage(); |
- }; |
- |
- /** |
- * Callback for window.onpopstate. |
- * @param {Object} data State data pushed into history. |
- */ |
- OptionsPage.setState = function(data) { |
- if (data && data.pageName) { |
- // It's possible an overlay may be the last top-level page shown. |
- if (this.isOverlayVisible_() && |
- this.registeredOverlayPages[data.pageName] == undefined) { |
- this.hideOverlay_(); |
- } |
- |
- this.showPageByName(data.pageName, false); |
- } |
- }; |
- |
- /** |
- * Freezes/unfreezes the scroll position of given level's page container. |
- * @param {boolean} freeze Whether the page should be frozen. |
- * @param {number} level The level to freeze/unfreeze. |
- * @private |
- */ |
- OptionsPage.setPageFrozenAtLevel_ = function(freeze, level) { |
- var container = level == 0 ? $('toplevel-page-container') |
- : $('subpage-sheet-container-' + level); |
- |
- if (container.classList.contains('frozen') == freeze) |
- return; |
- |
- if (freeze) { |
- var scrollPosition = document.body.scrollTop; |
- // Lock the width, since auto width computation may change. |
- container.style.width = window.getComputedStyle(container).width; |
- container.classList.add('frozen'); |
- container.style.top = -scrollPosition + 'px'; |
- this.updateFrozenElementHorizontalPosition_(container); |
- } else { |
- var scrollPosition = - parseInt(container.style.top, 10); |
- container.classList.remove('frozen'); |
- container.style.top = ''; |
- container.style.left = ''; |
- container.style.right = ''; |
- container.style.width = ''; |
- // Restore the scroll position. |
- if (!container.hidden) |
- window.scroll(document.body.scrollLeft, scrollPosition); |
- } |
- }; |
- |
- /** |
- * Freezes/unfreezes the scroll position of visible pages based on the current |
- * page stack. |
- */ |
- OptionsPage.updatePageFreezeStates = function() { |
- var topPage = OptionsPage.getTopmostVisiblePage(); |
- if (!topPage) |
- return; |
- var nestingLevel = topPage.isOverlay ? 100 : topPage.nestingLevel; |
- for (var i = 0; i <= SUBPAGE_SHEET_COUNT; i++) { |
- this.setPageFrozenAtLevel_(i < nestingLevel, i); |
- } |
- }; |
- |
- /** |
- * Initializes the complete options page. This will cause all C++ handlers to |
- * be invoked to do final setup. |
- */ |
- OptionsPage.initialize = function() { |
- chrome.send('coreOptionsInitialize'); |
- this.initialized_ = true; |
- |
- document.addEventListener('scroll', this.handleScroll_.bind(this)); |
- window.addEventListener('resize', this.handleResize_.bind(this)); |
- |
- if (!document.documentElement.classList.contains('hide-menu')) { |
- // Close subpages if the user clicks on the html body. Listen in the |
- // capturing phase so that we can stop the click from doing anything. |
- document.body.addEventListener('click', |
- this.bodyMouseEventHandler_.bind(this), |
- true); |
- // We also need to cancel mousedowns on non-subpage content. |
- document.body.addEventListener('mousedown', |
- this.bodyMouseEventHandler_.bind(this), |
- true); |
- |
- var self = this; |
- // Hook up the close buttons. |
- subpageCloseButtons = document.querySelectorAll('.close-subpage'); |
- for (var i = 0; i < subpageCloseButtons.length; i++) { |
- subpageCloseButtons[i].onclick = function() { |
- self.closeTopSubPage_(); |
- }; |
- }; |
- |
- // Install handler for key presses. |
- document.addEventListener('keydown', |
- this.keyDownEventHandler_.bind(this)); |
- |
- document.addEventListener('focus', this.manageFocusChange_.bind(this), |
- true); |
- } |
- |
- // Calculate and store the horizontal locations of elements that may be |
- // frozen later. |
- var sidebarWidth = |
- parseInt(window.getComputedStyle($('mainview')).webkitPaddingStart, 10); |
- $('toplevel-page-container').horizontalOffset = sidebarWidth + |
- parseInt(window.getComputedStyle( |
- $('mainview-content')).webkitPaddingStart, 10); |
- for (var level = 1; level <= SUBPAGE_SHEET_COUNT; level++) { |
- var containerId = 'subpage-sheet-container-' + level; |
- $(containerId).horizontalOffset = sidebarWidth; |
- } |
- $('subpage-backdrop').horizontalOffset = sidebarWidth; |
- // Trigger the resize handler manually to set the initial state. |
- this.handleResize_(null); |
- }; |
- |
- /** |
- * Does a bounds check for the element on the given x, y client coordinates. |
- * @param {Element} e The DOM element. |
- * @param {number} x The client X to check. |
- * @param {number} y The client Y to check. |
- * @return {boolean} True if the point falls within the element's bounds. |
- * @private |
- */ |
- OptionsPage.elementContainsPoint_ = function(e, x, y) { |
- var clientRect = e.getBoundingClientRect(); |
- return x >= clientRect.left && x <= clientRect.right && |
- y >= clientRect.top && y <= clientRect.bottom; |
- }; |
- |
- /** |
- * Called when focus changes; ensures that focus doesn't move outside |
- * the topmost subpage/overlay. |
- * @param {Event} e The focus change event. |
- * @private |
- */ |
- OptionsPage.manageFocusChange_ = function(e) { |
- var focusableItemsRoot; |
- var topPage = this.getTopmostVisiblePage(); |
- if (!topPage) |
- return; |
- |
- if (topPage.isOverlay) { |
- // If an overlay is visible, that defines the tab loop. |
- focusableItemsRoot = topPage.pageDiv; |
- } else { |
- // If a subpage is visible, use its parent as the tab loop constraint. |
- // (The parent is used because it contains the close button.) |
- if (topPage.nestingLevel > 0) |
- focusableItemsRoot = topPage.pageDiv.parentNode; |
- } |
- |
- if (focusableItemsRoot && !focusableItemsRoot.contains(e.target)) |
- topPage.focusFirstElement(); |
- }; |
- |
- /** |
- * Called when the page is scrolled; moves elements that are position:fixed |
- * but should only behave as if they are fixed for vertical scrolling. |
- * @param {Event} e The scroll event. |
- * @private |
- */ |
- OptionsPage.handleScroll_ = function(e) { |
- var scrollHorizontalOffset = document.body.scrollLeft; |
- // position:fixed doesn't seem to work for horizontal scrolling in RTL mode, |
- // so only adjust in LTR mode (where scroll values will be positive). |
- if (scrollHorizontalOffset >= 0) { |
- $('navbar-container').style.left = -scrollHorizontalOffset + 'px'; |
- var subpageBackdrop = $('subpage-backdrop'); |
- subpageBackdrop.style.left = subpageBackdrop.horizontalOffset - |
- scrollHorizontalOffset + 'px'; |
- this.updateAllFrozenElementPositions_(); |
- } |
- }; |
- |
- /** |
- * Updates all frozen pages to match the horizontal scroll position. |
- * @private |
- */ |
- OptionsPage.updateAllFrozenElementPositions_ = function() { |
- var frozenElements = document.querySelectorAll('.frozen'); |
- for (var i = 0; i < frozenElements.length; i++) { |
- this.updateFrozenElementHorizontalPosition_(frozenElements[i]); |
- } |
- }; |
- |
- /** |
- * Updates the given frozen element to match the horizontal scroll position. |
- * @param {HTMLElement} e The frozen element to update |
- * @private |
- */ |
- OptionsPage.updateFrozenElementHorizontalPosition_ = function(e) { |
- if (document.documentElement.dir == 'rtl') |
- e.style.right = e.horizontalOffset + 'px'; |
- else |
- e.style.left = e.horizontalOffset - document.body.scrollLeft + 'px'; |
- }; |
- |
- /** |
- * Called when the page is resized; adjusts the size of elements that depend |
- * on the veiwport. |
- * @param {Event} e The resize event. |
- * @private |
- */ |
- OptionsPage.handleResize_ = function(e) { |
- // Set an explicit height equal to the viewport on all the subpage |
- // containers shorter than the viewport. This is used instead of |
- // min-height: 100% so that there is an explicit height for the subpages' |
- // min-height: 100%. |
- var viewportHeight = document.documentElement.clientHeight; |
- var subpageContainers = |
- document.querySelectorAll('.subpage-sheet-container'); |
- for (var i = 0; i < subpageContainers.length; i++) { |
- if (subpageContainers[i].scrollHeight > viewportHeight) |
- subpageContainers[i].style.removeProperty('height'); |
- else |
- subpageContainers[i].style.height = viewportHeight + 'px'; |
- } |
- }; |
- |
- /** |
- * A function to handle mouse events (mousedown or click) on the html body by |
- * closing subpages and/or stopping event propagation. |
- * @return {Event} a mousedown or click event. |
- * @private |
- */ |
- OptionsPage.bodyMouseEventHandler_ = function(event) { |
- // Do nothing if a subpage isn't showing. |
- var topPage = this.getTopmostVisiblePage(); |
- if (!topPage || topPage.isOverlay || !topPage.parentPage) |
- return; |
- |
- // Do nothing if the client coordinates are not within the source element. |
- // This situation is indicative of a Webkit bug where clicking on a |
- // radio/checkbox label span will generate an event with client coordinates |
- // of (-scrollX, -scrollY). |
- // See https://bugs.webkit.org/show_bug.cgi?id=56606 |
- if (event.clientX == -document.body.scrollLeft && |
- event.clientY == -document.body.scrollTop) { |
- return; |
- } |
- |
- // Don't interfere with navbar clicks. |
- if ($('navbar').contains(event.target)) |
- return; |
- |
- // Figure out which page the click happened in. |
- for (var level = topPage.nestingLevel; level >= 0; level--) { |
- var clickIsWithinLevel = level == 0 ? true : |
- OptionsPage.elementContainsPoint_( |
- $('subpage-sheet-' + level), event.clientX, event.clientY); |
- |
- if (!clickIsWithinLevel) |
- continue; |
- |
- // Event was within the topmost page; do nothing. |
- if (topPage.nestingLevel == level) |
- return; |
- |
- // Block propgation of both clicks and mousedowns, but only close subpages |
- // on click. |
- if (event.type == 'click') |
- this.closeSubPagesToLevel(level); |
- event.stopPropagation(); |
- event.preventDefault(); |
- return; |
- } |
- }; |
- |
- /** |
- * A function to handle key press events. |
- * @return {Event} a keydown event. |
- * @private |
- */ |
- OptionsPage.keyDownEventHandler_ = function(event) { |
- // Close the top overlay or sub-page on esc. |
- if (event.keyCode == 27) { // Esc |
- if (this.isOverlayVisible_()) { |
- if (this.shouldCloseOverlay_()) |
- this.closeOverlay(); |
- } else { |
- this.closeTopSubPage_(); |
- } |
- } |
- }; |
- |
- OptionsPage.setClearPluginLSODataEnabled = function(enabled) { |
- if (enabled) { |
- document.documentElement.setAttribute( |
- 'flashPluginSupportsClearSiteData', ''); |
- } else { |
- document.documentElement.removeAttribute( |
- 'flashPluginSupportsClearSiteData'); |
- } |
- }; |
- |
- /** |
- * Re-initializes the C++ handlers if necessary. This is called if the |
- * handlers are torn down and recreated but the DOM may not have been (in |
- * which case |initialize| won't be called again). If |initialize| hasn't been |
- * called, this does nothing (since it will be later, once the DOM has |
- * finished loading). |
- */ |
- OptionsPage.reinitializeCore = function() { |
- if (this.initialized_) |
- chrome.send('coreOptionsInitialize'); |
- } |
- |
- OptionsPage.prototype = { |
- __proto__: cr.EventTarget.prototype, |
- |
- /** |
- * The parent page of this option page, or null for top-level pages. |
- * @type {OptionsPage} |
- */ |
- parentPage: null, |
- |
- /** |
- * The section on the parent page that is associated with this page. |
- * Can be null. |
- * @type {Element} |
- */ |
- associatedSection: null, |
- |
- /** |
- * An array of controls that are associated with this page. The first |
- * control should be located on a top-level page. |
- * @type {OptionsPage} |
- */ |
- associatedControls: null, |
- |
- /** |
- * Initializes page content. |
- */ |
- initializePage: function() {}, |
- |
- /** |
- * Sets managed banner visibility state. |
- */ |
- setManagedBannerVisibility: function(visible) { |
- this.managed = visible; |
- if (this.visible) { |
- this.updateManagedBannerVisibility(); |
- } |
- }, |
- |
- /** |
- * Updates managed banner visibility state. This function iterates over |
- * all input fields of a window and if any of these is marked as managed |
- * it triggers the managed banner to be visible. The banner can be enforced |
- * being on through the managed flag of this class but it can not be forced |
- * being off if managed items exist. |
- */ |
- updateManagedBannerVisibility: function() { |
- var bannerDiv = $('managed-prefs-banner'); |
- |
- var hasManaged = this.managed; |
- if (!hasManaged) { |
- var inputElements = this.pageDiv.querySelectorAll('input'); |
- for (var i = 0, len = inputElements.length; i < len; i++) { |
- if (inputElements[i].managed) { |
- hasManaged = true; |
- break; |
- } |
- } |
- } |
- if (hasManaged) { |
- bannerDiv.hidden = false; |
- var height = window.getComputedStyle($('managed-prefs-banner')).height; |
- $('subpage-backdrop').style.top = height; |
- } else { |
- bannerDiv.hidden = true; |
- $('subpage-backdrop').style.top = '0'; |
- } |
- }, |
- |
- /** |
- * Gets page visibility state. |
- */ |
- get visible() { |
- var page = $(this.pageDivName); |
- return page && page.ownerDocument.defaultView.getComputedStyle( |
- page).display == 'block'; |
- }, |
- |
- /** |
- * Sets page visibility. |
- */ |
- set visible(visible) { |
- if ((this.visible && visible) || (!this.visible && !visible)) |
- return; |
- |
- this.setContainerVisibility_(visible); |
- if (visible) { |
- this.pageDiv.classList.remove('hidden'); |
- |
- if (this.tab) |
- this.tab.classList.add('navbar-item-selected'); |
- } else { |
- this.pageDiv.classList.add('hidden'); |
- |
- if (this.tab) |
- this.tab.classList.remove('navbar-item-selected'); |
- } |
- |
- OptionsPage.updatePageFreezeStates(); |
- |
- // A subpage was shown or hidden. |
- if (!this.isOverlay && this.nestingLevel > 0) { |
- OptionsPage.updateSubpageBackdrop_(); |
- if (visible) { |
- // Scroll to the top of the newly-opened subpage. |
- window.scroll(document.body.scrollLeft, 0) |
- } |
- } |
- |
- // The managed prefs banner is global, so after any visibility change |
- // update it based on the topmost page, not necessarily this page |
- // (e.g., if an ancestor is made visible after a child). |
- OptionsPage.updateManagedBannerVisibility(); |
- |
- cr.dispatchPropertyChange(this, 'visible', visible, !visible); |
- }, |
- |
- /** |
- * Shows or hides this page's container. |
- * @param {boolean} visible Whether the container should be visible or not. |
- * @private |
- */ |
- setContainerVisibility_: function(visible) { |
- var container = null; |
- if (this.isOverlay) { |
- container = $('overlay'); |
- } else { |
- var nestingLevel = this.nestingLevel; |
- if (nestingLevel > 0) |
- container = $('subpage-sheet-container-' + nestingLevel); |
- } |
- var isSubpage = !this.isOverlay; |
- |
- if (!container || container.hidden != visible) |
- return; |
- |
- if (visible) { |
- container.hidden = false; |
- if (isSubpage) { |
- var computedStyle = window.getComputedStyle(container); |
- container.style.WebkitPaddingStart = |
- parseInt(computedStyle.WebkitPaddingStart, 10) + 100 + 'px'; |
- } |
- // Separate animating changes from the removal of display:none. |
- window.setTimeout(function() { |
- container.classList.remove('transparent'); |
- if (isSubpage) |
- container.style.WebkitPaddingStart = ''; |
- }); |
- } else { |
- var self = this; |
- container.addEventListener('webkitTransitionEnd', function f(e) { |
- if (e.propertyName != 'opacity') |
- return; |
- container.removeEventListener('webkitTransitionEnd', f); |
- self.fadeCompleted_(container); |
- }); |
- container.classList.add('transparent'); |
- } |
- }, |
- |
- /** |
- * Called when a container opacity transition finishes. |
- * @param {HTMLElement} container The container element. |
- * @private |
- */ |
- fadeCompleted_: function(container) { |
- if (container.classList.contains('transparent')) |
- container.hidden = true; |
- }, |
- |
- /** |
- * Focuses the first control on the page. |
- */ |
- focusFirstElement: function() { |
- // Sets focus on the first interactive element in the page. |
- var focusElement = |
- this.pageDiv.querySelector('button, input, list, select'); |
- if (focusElement) |
- focusElement.focus(); |
- }, |
- |
- /** |
- * The nesting level of this page. |
- * @type {number} The nesting level of this page (0 for top-level page) |
- */ |
- get nestingLevel() { |
- var level = 0; |
- var parent = this.parentPage; |
- while (parent) { |
- level++; |
- parent = parent.parentPage; |
- } |
- return level; |
- }, |
- |
- /** |
- * Whether the page is considered 'sticky', such that it will |
- * remain a top-level page even if sub-pages change. |
- * @type {boolean} True if this page is sticky. |
- */ |
- get sticky() { |
- return false; |
- }, |
- |
- /** |
- * Checks whether this page is an ancestor of the given page in terms of |
- * subpage nesting. |
- * @param {OptionsPage} page |
- * @return {boolean} True if this page is nested under |page| |
- */ |
- isAncestorOfPage: function(page) { |
- var parent = page.parentPage; |
- while (parent) { |
- if (parent == this) |
- return true; |
- parent = parent.parentPage; |
- } |
- return false; |
- }, |
- |
- /** |
- * Whether it should be possible to show the page. |
- * @return {boolean} True if the page should be shown |
- */ |
- canShowPage: function() { |
- return true; |
- }, |
- |
- /** |
- * Whether an overlay should be closed. Used by overlay implementation to |
- * handle special closing behaviors. |
- * @return {boolean} True if the overlay should be closed. |
- */ |
- shouldClose: function() { |
- return true; |
- }, |
- }; |
- |
- // Export |
- return { |
- OptionsPage: OptionsPage |
- }; |
-}); |