15f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
25f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// found in the LICENSE file.
45f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
55f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)cr.define('cr.ui.pageManager', function() {
65f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  var PageManager = cr.ui.pageManager.PageManager;
75f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
85f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  /**
95f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * Base class for pages that can be shown and hidden by PageManager. Each Page
105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * is like a node in a forest, corresponding to a particular div. At any
115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * point, one root Page is visible, and any visible Page can show a child Page
125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * as an overlay. The host of the root Page(s) should provide a container div
135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * for each nested level to enforce the stack order of overlays.
145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * @constructor
155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * @param {string} name Page name.
165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * @param {string} title Page title, used for history.
175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   * @param {string} pageDivName ID of the div corresponding to the page.
181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci   * @extends {cr.EventTarget}
195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)   */
205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  function Page(name, title, pageDivName) {
215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    this.name = name;
225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    this.title = title;
235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    this.pageDivName = pageDivName;
245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    this.pageDiv = $(this.pageDivName);
255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    // |pageDiv.page| is set to the page object (this) when the page is visible
265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    // to track which page is being shown when multiple pages can share the same
275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    // underlying div.
285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    this.pageDiv.page = null;
295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    this.tab = null;
305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    this.lastFocusedElement = null;
311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    this.hash = '';
325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  Page.prototype = {
355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    __proto__: cr.EventTarget.prototype,
365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    /**
385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)     * The parent page of this page, or null for root pages.
391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci     * @type {cr.ui.pageManager.Page}
405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)     */
415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    parentPage: null,
425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    /**
445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)     * The section on the parent page that is associated with this page.
455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)     * Can be null.
465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)     * @type {Element}
475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)     */
485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    associatedSection: null,
495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    /**
515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)     * An array of controls that are associated with this page. The first
525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)     * control should be located on a root page.
535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)     * @type {Array.<Element>}
545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)     */
555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    associatedControls: null,
565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    /**
585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)     * If true, this page should always be considered the top-most page when
595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)     * visible.
605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)     * @type {boolean}
615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)     */
625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    alwaysOnTop_: false,
635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    /**
655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)     * Initializes page content.
665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)     */
675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    initializePage: function() {},
685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    /**
701320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci     * Called by the PageManager when this.hash changes while the page is
711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci     * already visible. This is analogous to the hashchange DOM event.
721320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci     */
731320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    didChangeHash: function() {},
741320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    /**
765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)     * Sets focus on the first focusable element. Override for a custom focus
775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)     * strategy.
785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)     */
795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    focus: function() {
805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      // Do not change focus if any control on this page is already focused.
815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      if (this.pageDiv.contains(document.activeElement))
825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        return;
835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      var elements = this.pageDiv.querySelectorAll(
855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          'input, list, select, textarea, button');
865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      for (var i = 0; i < elements.length; i++) {
875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        var element = elements[i];
885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        // Try to focus. If fails, then continue.
895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        element.focus();
905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        if (document.activeElement == element)
915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          return;
925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      }
935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    },
945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    /**
965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)     * Reverses the child elements of this overlay's button strip if it hasn't
975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)     * already been reversed. This is necessary because WebKit does not alter
985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)     * the tab order for elements that are visually reversed using
995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)     * flex-direction: reverse, and the button order is reversed for views.
1005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)     * See http://webk.it/62664 for more information.
1015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)     */
1025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    reverseButtonStrip: function() {
1035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      assert(this.isOverlay);
1045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      var buttonStrips =
1055f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          this.pageDiv.querySelectorAll('.button-strip:not([reversed])');
1065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      // Reverse all button-strips in the overlay.
1085f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      for (var j = 0; j < buttonStrips.length; j++) {
1095f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        var buttonStrip = buttonStrips[j];
1105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        var childNodes = buttonStrip.childNodes;
1125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        for (var i = childNodes.length - 1; i >= 0; i--)
1135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          buttonStrip.appendChild(childNodes[i]);
1145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        buttonStrip.setAttribute('reversed', '');
1165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      }
1175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    },
1185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    /**
1205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)     * Whether it should be possible to show the page.
1215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)     * @return {boolean} True if the page should be shown.
1225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)     */
1235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    canShowPage: function() {
1245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      return true;
1255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    },
1265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    /**
1281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci     * Updates the hash of the current page. If the page is topmost, the history
1291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci     * state is updated.
1301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci     * @param {string} hash The new hash value. Like location.hash, this
1311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci     *     should include the leading '#' if not empty.
1321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci     */
1331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    setHash: function(hash) {
1341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      if (this.hash == hash)
1351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        return;
1361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      this.hash = hash;
1371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      PageManager.onPageHashChanged(this);
1381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    },
1391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    /**
1411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci     * Called after the page has been shown.
1421320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci     */
1431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    didShowPage: function() {},
1441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    /**
1461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci     * Called before the page will be hidden, e.g., when a different root page
1471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci     * will be shown.
1481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci     */
1491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    willHidePage: function() {},
1501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    /**
1521320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci     * Called after the overlay has been closed.
1531320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci     */
1541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    didClosePage: function() {},
1551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    /**
1575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)     * Gets the container div for this page if it is an overlay.
1585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)     * @type {HTMLDivElement}
1595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)     */
1605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    get container() {
1615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      assert(this.isOverlay);
1625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      return this.pageDiv.parentNode;
1635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    },
1645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    /**
1665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)     * Gets page visibility state.
1675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)     * @type {boolean}
1685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)     */
1695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    get visible() {
1705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      // If this is an overlay dialog it is no longer considered visible while
1715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      // the overlay is fading out. See http://crbug.com/118629.
1725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      if (this.isOverlay &&
1735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          this.container.classList.contains('transparent')) {
1745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        return false;
1755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      }
1765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      if (this.pageDiv.hidden)
1775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        return false;
1785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      return this.pageDiv.page == this;
1795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    },
1805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    /**
1825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)     * Sets page visibility.
1835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)     * @type {boolean}
1845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)     */
1855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    set visible(visible) {
1865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      if ((this.visible && visible) || (!this.visible && !visible))
1875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        return;
1885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      // If using an overlay, the visibility of the dialog is toggled at the
1905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      // same time as the overlay to show the dialog's out transition. This
1915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      // is handled in setOverlayVisible.
1925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      if (this.isOverlay) {
1935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        this.setOverlayVisible_(visible);
1945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      } else {
1955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        this.pageDiv.page = this;
1965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        this.pageDiv.hidden = !visible;
1975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        PageManager.onPageVisibilityChanged(this);
1985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      }
1995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
2005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      cr.dispatchPropertyChange(this, 'visible', visible, !visible);
2015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    },
2025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
2035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    /**
2045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)     * Whether the page is considered 'sticky', such that it will remain a root
2055f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)     * page even if sub-pages change.
2065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)     * @type {boolean} True if this page is sticky.
2075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)     */
2085f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    get sticky() {
2095f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      return false;
2105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    },
2115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
2125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    /**
2135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)     * @type {boolean} True if this page should always be considered the
2145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)     *     top-most page when visible.
2155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)     */
2165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    get alwaysOnTop() {
2175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      return this.alwaysOnTop_;
2185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    },
2195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
2205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    /**
2215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)     * @type {boolean} True if this page should always be considered the
2225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)     *     top-most page when visible. Only overlays can be always on top.
2235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)     */
2245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    set alwaysOnTop(value) {
2255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      assert(this.isOverlay);
2265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      this.alwaysOnTop_ = value;
2275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    },
2285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
2295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    /**
2305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)     * Shows or hides an overlay (including any visible dialog).
2315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)     * @param {boolean} visible Whether the overlay should be visible or not.
2325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)     * @private
2335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)     */
2345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    setOverlayVisible_: function(visible) {
2355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      assert(this.isOverlay);
2365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      var pageDiv = this.pageDiv;
2375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      var container = this.container;
2385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
2395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      if (container.hidden != visible) {
2405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        if (visible) {
2415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          // If the container is set hidden and then immediately set visible
2425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          // again, the fadeCompleted_ callback would cause it to be erroneously
2435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          // hidden again. Removing the transparent tag avoids that.
2445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          container.classList.remove('transparent');
2455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
2465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          // Hide all dialogs in this container since a different one may have
2475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          // been previously visible before fading out.
2485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          var pages = container.querySelectorAll('.page');
2495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          for (var i = 0; i < pages.length; i++)
2505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            pages[i].hidden = true;
2515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          // Show the new dialog.
2525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          pageDiv.hidden = false;
2535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          pageDiv.page = this;
2545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        }
2555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        return;
2565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      }
2575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
2585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      var self = this;
2595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      var loading = PageManager.isLoading();
2605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      if (!loading) {
2615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        // TODO(flackr): Use an event delegate to avoid having to subscribe and
2625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        // unsubscribe for webkitTransitionEnd events.
2635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        container.addEventListener('webkitTransitionEnd', function f(e) {
2645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            var propName = e.propertyName;
2655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            if (e.target != e.currentTarget ||
2665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                (propName && propName != 'opacity')) {
2675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)              return;
2685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            }
2695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            container.removeEventListener('webkitTransitionEnd', f);
2705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            self.fadeCompleted_();
2715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        });
2725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        // -webkit-transition is 200ms. Let's wait for 400ms.
2735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        ensureTransitionEndEvent(container, 400);
2745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      }
2755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
2765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      if (visible) {
2775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        container.hidden = false;
2785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        pageDiv.hidden = false;
2795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        pageDiv.page = this;
2805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        // NOTE: This is a hacky way to force the container to layout which
2815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        // will allow us to trigger the webkit transition.
2821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        /** @suppress {uselessCode} */
2835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        container.scrollTop;
2845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
2855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        this.pageDiv.removeAttribute('aria-hidden');
2865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        if (this.parentPage) {
2875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          this.parentPage.pageDiv.parentElement.setAttribute('aria-hidden',
2885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                                             true);
2895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        }
2905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        container.classList.remove('transparent');
2915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        PageManager.onPageVisibilityChanged(this);
2925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      } else {
2935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        // Kick change events for text fields.
2945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        if (pageDiv.contains(document.activeElement))
2955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          document.activeElement.blur();
2965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        container.classList.add('transparent');
2975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      }
2985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
2995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      if (loading)
3005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        this.fadeCompleted_();
3015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    },
3025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    /**
3045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)     * Called when a container opacity transition finishes.
3055f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)     * @private
3065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)     */
3075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    fadeCompleted_: function() {
3085f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      if (this.container.classList.contains('transparent')) {
3095f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        this.pageDiv.hidden = true;
3105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        this.container.hidden = true;
3115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        if (this.parentPage)
3135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          this.parentPage.pageDiv.parentElement.removeAttribute('aria-hidden');
3145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        PageManager.onPageVisibilityChanged(this);
3165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      }
3175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    },
3185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  };
3195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Export
3215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return {
3225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    Page: Page
3235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  };
3245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)});
325