Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(114)

Unified Diff: chrome/browser/resources/options/options_page.js

Issue 7003007: Apply content-security-policy to the HTML options page. This is a (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: '' Created 9 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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
- };
-});

Powered by Google App Engine
This is Rietveld 408576698