172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file.
4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
53345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickcr.define('options', function() {
63345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  /////////////////////////////////////////////////////////////////////////////
73345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // OptionsPage class:
83345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
93345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  /**
103345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick   * Base class for options page.
113345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick   * @constructor
123345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick   * @param {string} name Options page name, also defines id of the div element
133345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick   *     containing the options view and the name of options page navigation bar
143345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick   *     item as name+'PageNav'.
153345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick   * @param {string} title Options page title, used for navigation bar
163345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick   * @extends {EventTarget}
173345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick   */
183345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  function OptionsPage(name, title, pageDivName) {
193345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    this.name = name;
203345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    this.title = title;
213345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    this.pageDivName = pageDivName;
223345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    this.pageDiv = $(this.pageDivName);
233345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    this.tab = null;
243345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    this.managed = false;
25c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
263345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
27dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  const SUBPAGE_SHEET_COUNT = 2;
28dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
29c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  /**
3021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen   * Main level option pages.
3121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen   * @protected
32c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch   */
3321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  OptionsPage.registeredPages = {};
34c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
35c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  /**
36513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch   * Pages which are meant to behave like modal dialogs.
3721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen   * @protected
38c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch   */
3921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  OptionsPage.registeredOverlayPages = {};
403345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
413345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  /**
42201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch   * Whether or not |initialize| has been called.
4321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen   * @private
44201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch   */
45201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  OptionsPage.initialized_ = false;
46201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
47201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  /**
4872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen   * Gets the default page (to be shown on initial load).
4972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen   */
5072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  OptionsPage.getDefaultPage = function() {
5172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    return BrowserOptions.getInstance();
5272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  };
5372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
5472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  /**
5572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen   * Shows the default page.
5672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen   */
5772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  OptionsPage.showDefaultPage = function() {
5872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    this.navigateToPage(this.getDefaultPage().name);
5972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  };
6072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
6172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  /**
6272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen   * "Navigates" to a page, meaning that the page will be shown and the
6372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen   * appropriate entry is placed in the history.
6472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen   * @param {string} pageName Page name.
6572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen   */
6672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  OptionsPage.navigateToPage = function(pageName) {
6772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    this.showPageByName(pageName, true);
6872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  };
6972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
7072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  /**
714a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch   * Shows a registered page. This handles both top-level pages and sub-pages.
723345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick   * @param {string} pageName Page name.
7372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen   * @param {boolean} updateHistory True if we should update the history after
7472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen   *     showing the page.
7572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen   * @private
763345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick   */
7772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  OptionsPage.showPageByName = function(pageName, updateHistory) {
78dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    // Find the currently visible root-level page.
79dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    var rootPage = null;
80dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    for (var name in this.registeredPages) {
81dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      var page = this.registeredPages[name];
82dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      if (page.visible && !page.parentPage) {
83dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        rootPage = page;
84dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        break;
85dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      }
86dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    }
87dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
88dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    // Find the target page.
8921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    var targetPage = this.registeredPages[pageName];
9072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    if (!targetPage || !targetPage.canShowPage()) {
9172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      // If it's not a page, try it as an overlay.
92dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      if (!targetPage && this.showOverlay_(pageName, rootPage)) {
9372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        if (updateHistory)
9472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen          this.updateHistoryState_();
9572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        return;
9672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      } else {
9772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        targetPage = this.getDefaultPage();
9872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      }
9972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    }
10072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
10172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    pageName = targetPage.name;
10221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
10321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    // Determine if the root page is 'sticky', meaning that it
10421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    // shouldn't change when showing a sub-page.  This can happen for special
10521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    // pages like Search.
10621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    var isRootPageLocked =
10721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen        rootPage && rootPage.sticky && targetPage.parentPage;
10821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
10921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    // Notify pages if they will be hidden.
11021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    for (var name in this.registeredPages) {
11121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      var page = this.registeredPages[name];
11221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      if (!page.parentPage && isRootPageLocked)
11321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen        continue;
11421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      if (page.willHidePage && name != pageName &&
11521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen          !page.isAncestorOfPage(targetPage))
11621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen        page.willHidePage();
11721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    }
11821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
11921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    // Update visibilities to show only the hierarchy of the target page.
12021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    for (var name in this.registeredPages) {
12121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      var page = this.registeredPages[name];
12221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      if (!page.parentPage && isRootPageLocked)
12321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen        continue;
12421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      page.visible = name == pageName ||
125dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen          (!document.documentElement.classList.contains('hide-menu') &&
12621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen           page.isAncestorOfPage(targetPage));
12721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    }
12821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
12972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    // Update the history and current location.
13072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    if (updateHistory)
13172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      this.updateHistoryState_();
13272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
133dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    // Always update the page title.
134dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    document.title = targetPage.title;
135dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
13621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    // Notify pages if they were shown.
13721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    for (var name in this.registeredPages) {
13821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      var page = this.registeredPages[name];
13921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      if (!page.parentPage && isRootPageLocked)
14021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen        continue;
14121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      if (page.didShowPage && (name == pageName ||
14221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen          page.isAncestorOfPage(targetPage)))
14321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen        page.didShowPage();
1444a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    }
1453345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  };
1463345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1473345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  /**
148dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen   * Updates the visibility and stacking order of the subpage backdrop
149dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen   * according to which subpage is topmost and visible.
150dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen   * @private
151dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen   */
152dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  OptionsPage.updateSubpageBackdrop_ = function () {
153dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    var topmostPage = this.getTopmostVisibleNonOverlayPage_();
154dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    var nestingLevel = topmostPage ? topmostPage.nestingLevel : 0;
155dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
156dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    var subpageBackdrop = $('subpage-backdrop');
157dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    if (nestingLevel > 0) {
158dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      var container = $('subpage-sheet-container-' + nestingLevel);
159dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      subpageBackdrop.style.zIndex =
160dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen          parseInt(window.getComputedStyle(container).zIndex) - 1;
161dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      subpageBackdrop.hidden = false;
162dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    } else {
163dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      subpageBackdrop.hidden = true;
164dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    }
165dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  };
166dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
167dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  /**
16872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen   * Pushes the current page onto the history stack, overriding the last page
16972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen   * if it is the generic chrome://settings/.
17072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen   * @private
1713345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick   */
17272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  OptionsPage.updateHistoryState_ = function() {
17372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    var page = this.getTopmostVisiblePage();
17472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    var path = location.pathname;
17572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    if (path)
17672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      path = path.slice(1);
17772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    // The page is already in history (the user may have clicked the same link
17872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    // twice). Do nothing.
17972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    if (path == page.name)
18072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      return;
18172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
18272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    // If there is no path, the current location is chrome://settings/.
18372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    // Override this with the new page.
18472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    var historyFunction = path ? window.history.pushState :
18572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen                                 window.history.replaceState;
18672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    historyFunction.call(window.history,
18772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen                         {pageName: page.name},
18872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen                         page.title,
18972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen                         '/' + page.name);
19072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    // Update tab title.
19172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    document.title = page.title;
1923345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  };
193c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
194c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  /**
19572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen   * Shows a registered Overlay page. Does not update history.
1963345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick   * @param {string} overlayName Page name.
197dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen   * @param {OptionPage} rootPage The currently visible root-level page.
19872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen   * @return {boolean} whether we showed an overlay.
199c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch   */
200dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  OptionsPage.showOverlay_ = function(overlayName, rootPage) {
20172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    var overlay = this.registeredOverlayPages[overlayName];
20272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    if (!overlay || !overlay.canShowPage())
20372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      return false;
20472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
205dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    if ((!rootPage || !rootPage.sticky) && overlay.parentPage)
20672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      this.showPageByName(overlay.parentPage.name, false);
20772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
208ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    overlay.visible = true;
209ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (overlay.didShowPage) overlay.didShowPage();
21072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    return true;
21121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  };
21221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
21321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  /**
21421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen   * Returns whether or not an overlay is visible.
21521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen   * @return {boolean} True if an overlay is visible.
21621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen   * @private
21721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen   */
21821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  OptionsPage.isOverlayVisible_ = function() {
21972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    return this.getVisibleOverlay_() != null;
22072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  };
22172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
22272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  /**
223ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen   * @return {boolean} True if the visible overlay should be closed.
224ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen   * @private
225ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen   */
226ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  OptionsPage.shouldCloseOverlay_ = function() {
227ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    var overlay = this.getVisibleOverlay_();
228ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return overlay && overlay.shouldClose();
229ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  };
230ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
231ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  /**
23272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen   * Returns the currently visible overlay, or null if no page is visible.
23372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen   * @return {OptionPage} The visible overlay.
23472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen   */
23572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  OptionsPage.getVisibleOverlay_ = function() {
23621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    for (var name in this.registeredOverlayPages) {
23772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      var page = this.registeredOverlayPages[name];
23872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      if (page.visible)
23972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        return page;
2403345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    }
24172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    return null;
2423345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  };
2433345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
244513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  /**
24572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen   * Closes the visible overlay. Updates the history state after closing the
24672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen   * overlay.
247513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch   */
24872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  OptionsPage.closeOverlay = function() {
24972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    var overlay = this.getVisibleOverlay_();
25072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    if (!overlay)
25172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      return;
25272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
25372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    overlay.visible = false;
254ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (overlay.didClosePage) overlay.didClosePage();
25572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    this.updateHistoryState_();
25672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  };
25772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
25872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  /**
25972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen   * Hides the visible overlay. Does not affect the history state.
26072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen   * @private
26172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen   */
26272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  OptionsPage.hideOverlay_ = function() {
26372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    var overlay = this.getVisibleOverlay_();
26472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    if (overlay)
26572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      overlay.visible = false;
2663345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  };
2673345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
2683345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  /**
269dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen   * Returns the topmost visible page (overlays excluded).
270dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen   * @return {OptionPage} The topmost visible page aside any overlay.
271dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen   * @private
272513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch   */
273dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  OptionsPage.getTopmostVisibleNonOverlayPage_ = function() {
27421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    var topPage = null;
27521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    for (var name in this.registeredPages) {
27621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      var page = this.registeredPages[name];
27721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      if (page.visible &&
27821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen          (!topPage || page.nestingLevel > topPage.nestingLevel))
27921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen        topPage = page;
280513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    }
28172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
28221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    return topPage;
28372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  };
28421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
28521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  /**
286dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen   * Returns the topmost visible page, or null if no page is visible.
287dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen   * @return {OptionPage} The topmost visible page.
288dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen   */
289dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  OptionsPage.getTopmostVisiblePage = function() {
290dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    // Check overlays first since they're top-most if visible.
291dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    return this.getVisibleOverlay_() || this.getTopmostVisibleNonOverlayPage_();
292dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  };
293dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
294dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  /**
29521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen   * Closes the topmost open subpage, if any.
29672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen   * @private
29721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen   */
29872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  OptionsPage.closeTopSubPage_ = function() {
29921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    var topPage = this.getTopmostVisiblePage();
30072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    if (topPage && !topPage.isOverlay && topPage.parentPage)
30121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      topPage.visible = false;
30272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
30372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    this.updateHistoryState_();
304513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  };
305513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
306513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  /**
30721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen   * Closes all subpages below the given level.
30821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen   * @param {number} level The nesting level to close below.
3094a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch   */
31021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  OptionsPage.closeSubPagesToLevel = function(level) {
31121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    var topPage = this.getTopmostVisiblePage();
31221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    while (topPage && topPage.nestingLevel > level) {
31321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      topPage.visible = false;
31421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      topPage = topPage.parentPage;
3154a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    }
31672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
31772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    this.updateHistoryState_();
3184a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  };
3194a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
3204a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  /**
32121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen   * Updates managed banner visibility state based on the topmost page.
32221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen   */
32321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  OptionsPage.updateManagedBannerVisibility = function() {
32421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    var topPage = this.getTopmostVisiblePage();
32521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    if (topPage)
32621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      topPage.updateManagedBannerVisibility();
32721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  };
32821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
32921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  /**
3303345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  * Shows the tab contents for the given navigation tab.
3313345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  * @param {!Element} tab The tab that the user clicked.
3323345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  */
3333345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  OptionsPage.showTab = function(tab) {
3344a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    // Search parents until we find a tab, or the nav bar itself. This allows
3354a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    // tabs to have child nodes, e.g. labels in separately-styled spans.
3364a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    while (tab && !tab.classList.contains('subpages-nav-tabs') &&
33772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen           !tab.classList.contains('tab')) {
3384a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch      tab = tab.parentNode;
3394a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    }
34072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    if (!tab || !tab.classList.contains('tab'))
341c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return;
342c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
3433345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    if (this.activeNavTab != null) {
3443345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      this.activeNavTab.classList.remove('active-tab');
3453345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      $(this.activeNavTab.getAttribute('tab-contents')).classList.
3463345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick          remove('active-tab-contents');
3473345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    }
3483345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
3493345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    tab.classList.add('active-tab');
3503345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    $(tab.getAttribute('tab-contents')).classList.add('active-tab-contents');
3513345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    this.activeNavTab = tab;
3524a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  };
3533345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
3543345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  /**
3553345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick   * Registers new options page.
3563345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick   * @param {OptionsPage} page Page to register.
3573345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick   */
3583345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  OptionsPage.register = function(page) {
35921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    this.registeredPages[page.name] = page;
3603345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    // Create and add new page <li> element to navbar.
3613345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    var pageNav = document.createElement('li');
3623345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    pageNav.id = page.name + 'PageNav';
3633345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    pageNav.className = 'navbar-item';
3643345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    pageNav.setAttribute('pageName', page.name);
36572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    pageNav.textContent = page.pageDiv.querySelector('h1').textContent;
3663345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    pageNav.tabIndex = 0;
3673345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    pageNav.onclick = function(event) {
36872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      OptionsPage.navigateToPage(this.getAttribute('pageName'));
3693345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    };
3703345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    pageNav.onkeypress = function(event) {
3713345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      // Enter or space
3723345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      if (event.keyCode == 13 || event.keyCode == 32) {
37372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        OptionsPage.navigateToPage(this.getAttribute('pageName'));
374c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
3753345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    };
3763345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    var navbar = $('navbar');
3773345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    navbar.appendChild(pageNav);
3783345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    page.tab = pageNav;
3793345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    page.initializePage();
3803345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  };
3813345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
3823345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  /**
38321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen   * Find an enclosing section for an element if it exists.
38421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen   * @param {Element} element Element to search.
38521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen   * @return {OptionPage} The section element, or null.
38621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen   * @private
3873345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick   */
38821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  OptionsPage.findSectionForNode_ = function(node) {
38921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    while (node = node.parentNode) {
39021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      if (node.nodeName == 'SECTION')
39121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen        return node;
39221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    }
39321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    return null;
39421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  };
39521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
39621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  /**
39721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen   * Registers a new Sub-page.
39821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen   * @param {OptionsPage} subPage Sub-page to register.
39921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen   * @param {OptionsPage} parentPage Associated parent page for this page.
40021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen   * @param {Array} associatedControls Array of control elements that lead to
40172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen   *     this sub-page. The first item is typically a button in a root-level
40272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen   *     page. There may be additional buttons for nested sub-pages.
40321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen   */
40421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  OptionsPage.registerSubPage = function(subPage,
40521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen                                         parentPage,
40621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen                                         associatedControls) {
40721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    this.registeredPages[subPage.name] = subPage;
40821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    subPage.parentPage = parentPage;
40921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    if (associatedControls) {
41021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      subPage.associatedControls = associatedControls;
41121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      if (associatedControls.length) {
41221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen        subPage.associatedSection =
41321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen            this.findSectionForNode_(associatedControls[0]);
41421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      }
41521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    }
4164a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    subPage.tab = undefined;
4174a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    subPage.initializePage();
4183345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  };
4193345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
4203345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  /**
4213345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick   * Registers a new Overlay page.
42272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen   * @param {OptionsPage} overlay Overlay to register.
42372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen   * @param {OptionsPage} parentPage Associated parent page for this overlay.
42421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen   * @param {Array} associatedControls Array of control elements associated with
42521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen   *   this page.
4263345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick   */
42772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  OptionsPage.registerOverlay = function(overlay,
42872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen                                         parentPage,
42921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen                                         associatedControls) {
43072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    this.registeredOverlayPages[overlay.name] = overlay;
43172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    overlay.parentPage = parentPage;
43221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    if (associatedControls) {
43372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      overlay.associatedControls = associatedControls;
43421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      if (associatedControls.length) {
43572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        overlay.associatedSection =
43621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen            this.findSectionForNode_(associatedControls[0]);
43721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      }
43821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    }
43972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    overlay.tab = undefined;
44072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    overlay.isOverlay = true;
44172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    overlay.initializePage();
4423345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  };
4433345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
4443345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  /**
4453345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick   * Callback for window.onpopstate.
4463345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick   * @param {Object} data State data pushed into history.
4473345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick   */
4483345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  OptionsPage.setState = function(data) {
4493345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    if (data && data.pageName) {
45072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      // It's possible an overlay may be the last top-level page shown.
451ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      if (this.isOverlayVisible_() &&
452ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          this.registeredOverlayPages[data.pageName] == undefined) {
45372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        this.hideOverlay_();
454ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      }
45572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
45672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      this.showPageByName(data.pageName, false);
4573345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    }
4583345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  };
4593345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
4603345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  /**
461ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen   * Callback for window.onbeforeunload. Used to notify overlays that they will
462ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen   * be closed.
463ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen   */
464ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  OptionsPage.willClose = function() {
465ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    var overlay = this.getVisibleOverlay_();
466ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (overlay && overlay.didClosePage)
467ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      overlay.didClosePage();
468ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  };
469ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
470ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  /**
471dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen   * Freezes/unfreezes the scroll position of given level's page container.
472dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen   * @param {boolean} freeze Whether the page should be frozen.
473dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen   * @param {number} level The level to freeze/unfreeze.
474dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen   * @private
475dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen   */
476dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  OptionsPage.setPageFrozenAtLevel_ = function(freeze, level) {
477dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    var container = level == 0 ? $('toplevel-page-container')
478dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen                               : $('subpage-sheet-container-' + level);
479dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
480dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    if (container.classList.contains('frozen') == freeze)
481dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      return;
482dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
483dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    if (freeze) {
484dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      var scrollPosition = document.body.scrollTop;
485dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      // Lock the width, since auto width computation may change.
486dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      container.style.width = window.getComputedStyle(container).width;
487dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      container.classList.add('frozen');
488dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      container.style.top = -scrollPosition + 'px';
489dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      this.updateFrozenElementHorizontalPosition_(container);
490dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    } else {
491dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      var scrollPosition = - parseInt(container.style.top, 10);
492dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      container.classList.remove('frozen');
493dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      container.style.top = '';
494dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      container.style.left = '';
495dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      container.style.right = '';
496dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      container.style.width = '';
497dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      // Restore the scroll position.
498dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      if (!container.hidden)
499dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        window.scroll(document.body.scrollLeft, scrollPosition);
500dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    }
501dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  };
502dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
503dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  /**
504dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen   * Freezes/unfreezes the scroll position of visible pages based on the current
505dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen   * page stack.
506dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen   */
507dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  OptionsPage.updatePageFreezeStates = function() {
508dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    var topPage = OptionsPage.getTopmostVisiblePage();
509dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    if (!topPage)
510dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      return;
511dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    var nestingLevel = topPage.isOverlay ? 100 : topPage.nestingLevel;
512dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    for (var i = 0; i <= SUBPAGE_SHEET_COUNT; i++) {
513dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      this.setPageFrozenAtLevel_(i < nestingLevel, i);
514dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    }
515dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  };
516dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
517dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  /**
51872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen   * Initializes the complete options page.  This will cause all C++ handlers to
51972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen   * be invoked to do final setup.
5203345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick   */
5213345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  OptionsPage.initialize = function() {
5223345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    chrome.send('coreOptionsInitialize');
523201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    this.initialized_ = true;
5244a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
525ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    document.addEventListener('scroll', this.handleScroll_.bind(this));
526ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    window.addEventListener('resize', this.handleResize_.bind(this));
52721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
528ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (!document.documentElement.classList.contains('hide-menu')) {
529ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      // Close subpages if the user clicks on the html body. Listen in the
530ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      // capturing phase so that we can stop the click from doing anything.
531ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      document.body.addEventListener('click',
532ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                     this.bodyMouseEventHandler_.bind(this),
533ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                     true);
534ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      // We also need to cancel mousedowns on non-subpage content.
535ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      document.body.addEventListener('mousedown',
536ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                     this.bodyMouseEventHandler_.bind(this),
537ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                     true);
538ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
539ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      var self = this;
540ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      // Hook up the close buttons.
541ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      subpageCloseButtons = document.querySelectorAll('.close-subpage');
542ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      for (var i = 0; i < subpageCloseButtons.length; i++) {
543ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        subpageCloseButtons[i].onclick = function() {
544ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          self.closeTopSubPage_();
545ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        };
546ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      };
54772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
548ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      // Install handler for key presses.
549ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      document.addEventListener('keydown',
550ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                this.keyDownEventHandler_.bind(this));
551dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
552ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      document.addEventListener('focus', this.manageFocusChange_.bind(this),
553ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                true);
554ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    }
555dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
556dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    // Calculate and store the horizontal locations of elements that may be
557dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    // frozen later.
558dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    var sidebarWidth =
559dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        parseInt(window.getComputedStyle($('mainview')).webkitPaddingStart, 10);
560dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    $('toplevel-page-container').horizontalOffset = sidebarWidth +
561dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        parseInt(window.getComputedStyle(
562dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen            $('mainview-content')).webkitPaddingStart, 10);
563dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    for (var level = 1; level <= SUBPAGE_SHEET_COUNT; level++) {
564dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      var containerId = 'subpage-sheet-container-' + level;
565dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      $(containerId).horizontalOffset = sidebarWidth;
566dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    }
567dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    $('subpage-backdrop').horizontalOffset = sidebarWidth;
568dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    // Trigger the resize handler manually to set the initial state.
569dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    this.handleResize_(null);
57021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  };
57121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
57221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  /**
573dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen   * Does a bounds check for the element on the given x, y client coordinates.
574dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen   * @param {Element} e The DOM element.
575dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen   * @param {number} x The client X to check.
576dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen   * @param {number} y The client Y to check.
577dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen   * @return {boolean} True if the point falls within the element's bounds.
57821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen   * @private
57921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen   */
580dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  OptionsPage.elementContainsPoint_ = function(e, x, y) {
581dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    var clientRect = e.getBoundingClientRect();
582dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    return x >= clientRect.left && x <= clientRect.right &&
583dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        y >= clientRect.top && y <= clientRect.bottom;
5843345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  };
5853345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
586201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  /**
58772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen   * Called when focus changes; ensures that focus doesn't move outside
58872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen   * the topmost subpage/overlay.
58972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen   * @param {Event} e The focus change event.
59072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen   * @private
59172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen   */
59272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  OptionsPage.manageFocusChange_ = function(e) {
59372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    var focusableItemsRoot;
59472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    var topPage = this.getTopmostVisiblePage();
59572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    if (!topPage)
59672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      return;
59772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
59872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    if (topPage.isOverlay) {
59972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      // If an overlay is visible, that defines the tab loop.
60072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      focusableItemsRoot = topPage.pageDiv;
60172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    } else {
60272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      // If a subpage is visible, use its parent as the tab loop constraint.
60372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      // (The parent is used because it contains the close button.)
60472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      if (topPage.nestingLevel > 0)
60572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        focusableItemsRoot = topPage.pageDiv.parentNode;
60672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    }
60772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
60872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    if (focusableItemsRoot && !focusableItemsRoot.contains(e.target))
60972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      topPage.focusFirstElement();
61072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  };
61172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
61272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  /**
613dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen   * Called when the page is scrolled; moves elements that are position:fixed
614dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen   * but should only behave as if they are fixed for vertical scrolling.
615dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen   * @param {Event} e The scroll event.
616dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen   * @private
617dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen   */
618dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  OptionsPage.handleScroll_ = function(e) {
619dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    var scrollHorizontalOffset = document.body.scrollLeft;
620dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    // position:fixed doesn't seem to work for horizontal scrolling in RTL mode,
621dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    // so only adjust in LTR mode (where scroll values will be positive).
622dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    if (scrollHorizontalOffset >= 0) {
623dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      $('navbar-container').style.left = -scrollHorizontalOffset + 'px';
624dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      var subpageBackdrop = $('subpage-backdrop');
625dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      subpageBackdrop.style.left = subpageBackdrop.horizontalOffset -
626dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen          scrollHorizontalOffset + 'px';
627dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      this.updateAllFrozenElementPositions_();
628dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    }
629dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  };
630dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
631dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  /**
632dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen   * Updates all frozen pages to match the horizontal scroll position.
633dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen   * @private
634dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen   */
635dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  OptionsPage.updateAllFrozenElementPositions_ = function() {
636dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    var frozenElements = document.querySelectorAll('.frozen');
637dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    for (var i = 0; i < frozenElements.length; i++) {
638dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      this.updateFrozenElementHorizontalPosition_(frozenElements[i]);
639dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    }
640dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  };
641dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
642dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  /**
643dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen   * Updates the given frozen element to match the horizontal scroll position.
644dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen   * @param {HTMLElement} e The frozen element to update
645dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen   * @private
646dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen   */
647dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  OptionsPage.updateFrozenElementHorizontalPosition_ = function(e) {
648dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    if (document.documentElement.dir == 'rtl')
649dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      e.style.right = e.horizontalOffset + 'px';
650dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    else
651dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      e.style.left = e.horizontalOffset - document.body.scrollLeft + 'px';
652dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  };
653dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
654dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  /**
655dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen   * Called when the page is resized; adjusts the size of elements that depend
656dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen   * on the veiwport.
657dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen   * @param {Event} e The resize event.
658dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen   * @private
659dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen   */
660dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  OptionsPage.handleResize_ = function(e) {
661dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    // Set an explicit height equal to the viewport on all the subpage
662dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    // containers shorter than the viewport. This is used instead of
663dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    // min-height: 100% so that there is an explicit height for the subpages'
664dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    // min-height: 100%.
665dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    var viewportHeight = document.documentElement.clientHeight;
666dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    var subpageContainers =
667dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        document.querySelectorAll('.subpage-sheet-container');
668dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    for (var i = 0; i < subpageContainers.length; i++) {
669dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      if (subpageContainers[i].scrollHeight > viewportHeight)
670dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        subpageContainers[i].style.removeProperty('height');
671dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      else
672dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        subpageContainers[i].style.height = viewportHeight + 'px';
673dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    }
674dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  };
675dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
676dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  /**
67772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen   * A function to handle mouse events (mousedown or click) on the html body by
67872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen   * closing subpages and/or stopping event propagation.
67972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen   * @return {Event} a mousedown or click event.
68072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen   * @private
68172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen   */
68272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  OptionsPage.bodyMouseEventHandler_ = function(event) {
68372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    // Do nothing if a subpage isn't showing.
68472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    var topPage = this.getTopmostVisiblePage();
68572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    if (!topPage || topPage.isOverlay || !topPage.parentPage)
68672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      return;
68772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
688ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // Do nothing if the client coordinates are not within the source element.
689ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // This situation is indicative of a Webkit bug where clicking on a
690ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // radio/checkbox label span will generate an event with client coordinates
691ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // of (-scrollX, -scrollY).
692ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // See https://bugs.webkit.org/show_bug.cgi?id=56606
693ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (event.clientX == -document.body.scrollLeft &&
694ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        event.clientY == -document.body.scrollTop) {
695ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      return;
696ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    }
697ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
69872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    // Don't interfere with navbar clicks.
69972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    if ($('navbar').contains(event.target))
70072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      return;
70172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
702dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    // Figure out which page the click happened in.
703dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    for (var level = topPage.nestingLevel; level >= 0; level--) {
704dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      var clickIsWithinLevel = level == 0 ? true :
705dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen          OptionsPage.elementContainsPoint_(
706dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen              $('subpage-sheet-' + level), event.clientX, event.clientY);
707dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
708dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      if (!clickIsWithinLevel)
709dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        continue;
71072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
711dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      // Event was within the topmost page; do nothing.
712dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      if (topPage.nestingLevel == level)
713dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        return;
71472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
715dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      // Block propgation of both clicks and mousedowns, but only close subpages
716dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      // on click.
717dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      if (event.type == 'click')
718dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        this.closeSubPagesToLevel(level);
719dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      event.stopPropagation();
720dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      event.preventDefault();
721dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      return;
722dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    }
72372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  };
72472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
72572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  /**
72672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen   * A function to handle key press events.
72772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen   * @return {Event} a keydown event.
72872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen   * @private
72972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen   */
73072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  OptionsPage.keyDownEventHandler_ = function(event) {
73172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    // Close the top overlay or sub-page on esc.
73272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    if (event.keyCode == 27) {  // Esc
733ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      if (this.isOverlayVisible_()) {
734ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        if (this.shouldCloseOverlay_())
735ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          this.closeOverlay();
736ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      } else {
73772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        this.closeTopSubPage_();
738ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      }
739ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    }
740ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  };
741ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
742ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  OptionsPage.setClearPluginLSODataEnabled = function(enabled) {
743ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (enabled) {
744ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      document.documentElement.setAttribute(
745ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          'flashPluginSupportsClearSiteData', '');
746ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    } else {
747ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      document.documentElement.removeAttribute(
748ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          'flashPluginSupportsClearSiteData');
74972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    }
75072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  };
75172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
75272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  /**
753201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch   * Re-initializes the C++ handlers if necessary. This is called if the
754201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch   * handlers are torn down and recreated but the DOM may not have been (in
755201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch   * which case |initialize| won't be called again). If |initialize| hasn't been
756201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch   * called, this does nothing (since it will be later, once the DOM has
757201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch   * finished loading).
758201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch   */
759201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  OptionsPage.reinitializeCore = function() {
760201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    if (this.initialized_)
761201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      chrome.send('coreOptionsInitialize');
762201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  }
763201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch
7643345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  OptionsPage.prototype = {
7653345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    __proto__: cr.EventTarget.prototype,
7663345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
7673345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    /**
76821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen     * The parent page of this option page, or null for top-level pages.
76921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen     * @type {OptionsPage}
77021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen     */
77121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    parentPage: null,
77221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
77321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    /**
77421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen     * The section on the parent page that is associated with this page.
77521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen     * Can be null.
77621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen     * @type {Element}
77721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen     */
77821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    associatedSection: null,
77921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
78021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    /**
78121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen     * An array of controls that are associated with this page.  The first
78221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen     * control should be located on a top-level page.
78321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen     * @type {OptionsPage}
78421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen     */
78521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    associatedControls: null,
78621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
78721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    /**
7883345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick     * Initializes page content.
7893345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick     */
7903345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    initializePage: function() {},
7913345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
7923345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    /**
7933345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick     * Sets managed banner visibility state.
7943345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick     */
7953345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    setManagedBannerVisibility: function(visible) {
7963345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      this.managed = visible;
7973345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      if (this.visible) {
7984a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch        this.updateManagedBannerVisibility();
7994a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch      }
8004a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    },
8014a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
8024a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    /**
80372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen     * Updates managed banner visibility state. This function iterates over
80472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen     * all input fields of a window and if any of these is marked as managed
80572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen     * it triggers the managed banner to be visible. The banner can be enforced
80672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen     * being on through the managed flag of this class but it can not be forced
80772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen     * being off if managed items exist.
8084a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch     */
8094a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    updateManagedBannerVisibility: function() {
81072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      var bannerDiv = $('managed-prefs-banner');
81172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
81272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      var hasManaged = this.managed;
81372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      if (!hasManaged) {
81472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        var inputElements = this.pageDiv.querySelectorAll('input');
81572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        for (var i = 0, len = inputElements.length; i < len; i++) {
81672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen          if (inputElements[i].managed) {
81772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen            hasManaged = true;
81872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen            break;
81972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen          }
82072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        }
82172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      }
82272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      if (hasManaged) {
823dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        bannerDiv.hidden = false;
82472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        var height = window.getComputedStyle($('managed-prefs-banner')).height;
82572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        $('subpage-backdrop').style.top = height;
8264a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch      } else {
827dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        bannerDiv.hidden = true;
82872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        $('subpage-backdrop').style.top = '0';
829c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
8303345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    },
8313345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
8323345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    /**
8333345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick     * Gets page visibility state.
8343345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick     */
8353345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    get visible() {
8363345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      var page = $(this.pageDivName);
8373345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      return page && page.ownerDocument.defaultView.getComputedStyle(
8383345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick          page).display == 'block';
8393345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    },
8403345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
8413345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    /**
8423345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick     * Sets page visibility.
8433345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick     */
8443345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    set visible(visible) {
8453345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      if ((this.visible && visible) || (!this.visible && !visible))
8463345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        return;
8473345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
848dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      this.setContainerVisibility_(visible);
8493345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      if (visible) {
8504a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch        this.pageDiv.classList.remove('hidden');
85172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
852dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        if (this.tab)
8533345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick          this.tab.classList.add('navbar-item-selected');
8543345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      } else {
8554a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch        this.pageDiv.classList.add('hidden');
85672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
857dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        if (this.tab)
8583345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick          this.tab.classList.remove('navbar-item-selected');
859dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      }
860dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
861dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      OptionsPage.updatePageFreezeStates();
862dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
863dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      // A subpage was shown or hidden.
864dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      if (!this.isOverlay && this.nestingLevel > 0) {
865dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        OptionsPage.updateSubpageBackdrop_();
866dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        if (visible) {
867dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen          // Scroll to the top of the newly-opened subpage.
868dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen          window.scroll(document.body.scrollLeft, 0)
8693345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        }
870c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
871c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
87272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      // The managed prefs banner is global, so after any visibility change
87372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      // update it based on the topmost page, not necessarily this page
87472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      // (e.g., if an ancestor is made visible after a child).
87572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      OptionsPage.updateManagedBannerVisibility();
87672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
8773345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      cr.dispatchPropertyChange(this, 'visible', visible, !visible);
8783345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    },
8793345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
8803345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    /**
881dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen     * Shows or hides this page's container.
882dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen     * @param {boolean} visible Whether the container should be visible or not.
883dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen     * @private
884dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen     */
885dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    setContainerVisibility_: function(visible) {
886dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      var container = null;
887dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      if (this.isOverlay) {
888dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        container = $('overlay');
889dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      } else {
890dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        var nestingLevel = this.nestingLevel;
891dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        if (nestingLevel > 0)
892dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen          container = $('subpage-sheet-container-' + nestingLevel);
893dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      }
894dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      var isSubpage = !this.isOverlay;
895dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
896dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      if (!container || container.hidden != visible)
897dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        return;
898dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
899dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      if (visible) {
900dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        container.hidden = false;
901dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        if (isSubpage) {
902dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen          var computedStyle = window.getComputedStyle(container);
903dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen          container.style.WebkitPaddingStart =
904dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen              parseInt(computedStyle.WebkitPaddingStart, 10) + 100 + 'px';
905dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        }
906dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        // Separate animating changes from the removal of display:none.
907dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        window.setTimeout(function() {
908dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen          container.classList.remove('transparent');
909dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen          if (isSubpage)
910dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen            container.style.WebkitPaddingStart = '';
911dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        });
912dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      } else {
913dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        var self = this;
914dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        container.addEventListener('webkitTransitionEnd', function f(e) {
915dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen          if (e.propertyName != 'opacity')
916dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen            return;
917dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen          container.removeEventListener('webkitTransitionEnd', f);
918dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen          self.fadeCompleted_(container);
919dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        });
920dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        container.classList.add('transparent');
921dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      }
922dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    },
923dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
924dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    /**
925dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen     * Called when a container opacity transition finishes.
926dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen     * @param {HTMLElement} container The container element.
927dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen     * @private
928dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen     */
929dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    fadeCompleted_: function(container) {
930dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      if (container.classList.contains('transparent'))
931dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        container.hidden = true;
932dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    },
933dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
934dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    /**
93572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen     * Focuses the first control on the page.
93672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen     */
93772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    focusFirstElement: function() {
93872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      // Sets focus on the first interactive element in the page.
93972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      var focusElement =
94072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen          this.pageDiv.querySelector('button, input, list, select');
94172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      if (focusElement)
94272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        focusElement.focus();
94372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    },
94472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
94572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    /**
94621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen     * The nesting level of this page.
94721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen     * @type {number} The nesting level of this page (0 for top-level page)
94821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen     */
94921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    get nestingLevel() {
95021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      var level = 0;
95121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      var parent = this.parentPage;
95221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      while (parent) {
95321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen        level++;
95421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen        parent = parent.parentPage;
95521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      }
95621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      return level;
95721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    },
95821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
95921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    /**
96021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen     * Whether the page is considered 'sticky', such that it will
96121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen     * remain a top-level page even if sub-pages change.
96221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen     * @type {boolean} True if this page is sticky.
96321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen     */
96421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    get sticky() {
96521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      return false;
96621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    },
96721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
96821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    /**
96921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen     * Checks whether this page is an ancestor of the given page in terms of
97021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen     * subpage nesting.
97121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen     * @param {OptionsPage} page
97221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen     * @return {boolean} True if this page is nested under |page|
97321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen     */
97421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    isAncestorOfPage: function(page) {
97521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      var parent = page.parentPage;
97621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      while (parent) {
97721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen        if (parent == this)
97821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen          return true;
97921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen        parent = parent.parentPage;
98021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      }
98121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      return false;
98221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    },
98321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
98421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    /**
98572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen     * Whether it should be possible to show the page.
98672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen     * @return {boolean} True if the page should be shown
9873345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick     */
98872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    canShowPage: function() {
98972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      return true;
9903345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    },
991ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
992ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    /**
993ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     * Whether an overlay should be closed. Used by overlay implementation to
994ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     * handle special closing behaviors.
995ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     * @return {boolean} True if the overlay should be closed.
996ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen     */
997ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    shouldClose: function() {
998ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      return true;
999ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    },
10003345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  };
10013345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
10023345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Export
10033345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  return {
10043345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    OptionsPage: OptionsPage
10053345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  };
10063345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick});
1007