Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / ui / webui / resources / js / cr / ui / page_manager / page_manager.js
index 0fd4a18..8220c2c 100644 (file)
@@ -44,7 +44,7 @@ cr.define('cr.ui.pageManager', function() {
 
     /**
      * Observers will be notified when opening and closing overlays.
-     * @type {!Array.<!PageManager.Observer>}
+     * @type {!Array.<!cr.ui.pageManager.PageManager.Observer>}
      */
     observers_: [],
 
@@ -76,7 +76,7 @@ cr.define('cr.ui.pageManager', function() {
 
     /**
      * Registers new page.
-     * @param {cr.ui.page_manager.Page} page Page to register.
+     * @param {!cr.ui.pageManager.Page} page Page to register.
      */
     register: function(page) {
       this.registeredPages[page.name.toLowerCase()] = page;
@@ -85,8 +85,8 @@ cr.define('cr.ui.pageManager', function() {
 
     /**
      * Registers a new Overlay page.
-     * @param {cr.ui.page_manager.Page} overlay Overlay to register.
-     * @param {cr.ui.page_manager.Page} parentPage Associated parent page for
+     * @param {!cr.ui.pageManager.Page} overlay Overlay to register.
+     * @param {cr.ui.pageManager.Page} parentPage Associated parent page for
      *     this overlay.
      * @param {Array} associatedControls Array of control elements associated
      *     with this page.
@@ -112,12 +112,7 @@ cr.define('cr.ui.pageManager', function() {
       overlay.tab = undefined;
       overlay.isOverlay = true;
 
-      // Reverse the button strip for Windows and CrOS. See the documentation of
-      // cr.ui.pageManager.Page.reverseButtonStrip() for an explanation of why
-      // this is done.
-      if (cr.isWindows || cr.isChromeOS)
-        overlay.reverseButtonStrip();
-
+      overlay.reverseButtonStrip();
       overlay.initializePage();
     },
 
@@ -139,6 +134,7 @@ cr.define('cr.ui.pageManager', function() {
      *     showing the page (defaults to true).
      * @param {Object=} opt_propertyBag An optional bag of properties including
      *     replaceState (if history state should be replaced instead of pushed).
+     *     hash (a hash state to attach to the page).
      */
     showPageByName: function(pageName,
                              opt_updateHistory,
@@ -163,7 +159,8 @@ cr.define('cr.ui.pageManager', function() {
       var targetPage = this.registeredPages[pageName.toLowerCase()];
       if (!targetPage || !targetPage.canShowPage()) {
         // If it's not a page, try it as an overlay.
-        if (!targetPage && this.showOverlay_(pageName, rootPage)) {
+        var hash = opt_propertyBag.hash || '';
+        if (!targetPage && this.showOverlay_(pageName, hash, rootPage)) {
           if (opt_updateHistory)
             this.updateHistoryState_(!!opt_propertyBag.replaceState);
           this.updateTitle_();
@@ -181,34 +178,20 @@ cr.define('cr.ui.pageManager', function() {
       var isRootPageLocked =
           rootPage && rootPage.sticky && targetPage.parentPage;
 
-      var allPageNames = Array.prototype.concat.call(
-          Object.keys(this.registeredPages),
-          Object.keys(this.registeredOverlayPages));
-
       // Notify pages if they will be hidden.
-      // TODO(michaelpg): Resolve code duplication.
-      for (var i = 0; i < allPageNames.length; ++i) {
-        var name = allPageNames[i];
-        var page = this.registeredPages[name] ||
-                   this.registeredOverlayPages[name];
-        if (!page.parentPage && isRootPageLocked)
-          continue;
-        if (page.willHidePage && name != pageName &&
-            !this.isAncestorOfPage(page, targetPage)) {
+      this.forEachPage_(!isRootPageLocked, function(page) {
+        if (page.name != pageName && !this.isAncestorOfPage(page, targetPage))
           page.willHidePage();
-        }
-      }
+      });
+
+      // Update the page's hash.
+      targetPage.hash = opt_propertyBag.hash || '';
 
       // Update visibilities to show only the hierarchy of the target page.
-      for (var i = 0; i < allPageNames.length; ++i) {
-        var name = allPageNames[i];
-        var page = this.registeredPages[name] ||
-                   this.registeredOverlayPages[name];
-        if (!page.parentPage && isRootPageLocked)
-          continue;
-        page.visible = name == pageName ||
+      this.forEachPage_(!isRootPageLocked, function(page) {
+        page.visible = page.name == pageName ||
                        this.isAncestorOfPage(page, targetPage);
-      }
+      });
 
       // Update the history and current location.
       if (opt_updateHistory)
@@ -222,17 +205,18 @@ cr.define('cr.ui.pageManager', function() {
       }
 
       // Notify pages if they were shown.
-      for (var i = 0; i < allPageNames.length; ++i) {
-        var name = allPageNames[i];
-        var page = this.registeredPages[name] ||
-                   this.registeredOverlayPages[name];
-        if (!page.parentPage && isRootPageLocked)
-          continue;
-        if (!targetPageWasVisible && page.didShowPage &&
-            (name == pageName || this.isAncestorOfPage(page, targetPage))) {
+      this.forEachPage_(!isRootPageLocked, function(page) {
+        if (!targetPageWasVisible &&
+            (page.name == pageName ||
+             this.isAncestorOfPage(page, targetPage))) {
           page.didShowPage();
         }
-      }
+      });
+
+      // If the target page was already visible, notify it that its hash
+      // changed externally.
+      if (targetPageWasVisible)
+        targetPage.didChangeHash();
 
       // Update the document title. Do this after didShowPage was called, in
       // case a page decides to change its title.
@@ -313,6 +297,16 @@ cr.define('cr.ui.pageManager', function() {
     },
 
     /**
+     * Called when a page's hash changes. If the page is the topmost visible
+     * page, the history state is updated.
+     * @param {cr.ui.pageManager.Page} page The page whose hash has changed.
+     */
+    onPageHashChanged: function(page) {
+      if (page == this.getTopmostVisiblePage())
+        this.updateHistoryState_(false);
+    },
+
+    /**
      * Returns the topmost visible page, or null if no page is visible.
      * @return {cr.ui.pageManager.Page} The topmost visible page.
      */
@@ -332,10 +326,9 @@ cr.define('cr.ui.pageManager', function() {
         return;
 
       overlay.visible = false;
+      overlay.didClosePage();
 
-      if (overlay.didClosePage)
-        overlay.didClosePage();
-      this.updateHistoryState_(false, {ignoreHash: true});
+      this.updateHistoryState_(false);
       this.updateTitle_();
 
       this.restoreLastFocusedElement_();
@@ -400,7 +393,7 @@ cr.define('cr.ui.pageManager', function() {
 
     /**
      * Returns the currently visible bubble, or null if no bubble is visible.
-     * @return {AutoCloseBubble} The bubble currently being shown.
+     * @return {cr.ui.AutoCloseBubble} The bubble currently being shown.
      */
     getVisibleBubble: function() {
       var bubble = this.bubble_;
@@ -410,9 +403,10 @@ cr.define('cr.ui.pageManager', function() {
     /**
      * Callback for window.onpopstate to handle back/forward navigations.
      * @param {string} pageName The current page name.
+     * @param {string} hash The hash to pass into the page.
      * @param {Object} data State data pushed into history.
      */
-    setState: function(pageName, data) {
+    setState: function(pageName, hash, data) {
       var currentOverlay = this.getVisibleOverlay_();
       var lowercaseName = pageName.toLowerCase();
       var newPage = this.registeredPages[lowercaseName] ||
@@ -420,9 +414,9 @@ cr.define('cr.ui.pageManager', function() {
                     this.defaultPage_;
       if (currentOverlay && !this.isAncestorOfPage(currentOverlay, newPage)) {
         currentOverlay.visible = false;
-        if (currentOverlay.didClosePage) currentOverlay.didClosePage();
+        currentOverlay.didClosePage();
       }
-      this.showPageByName(pageName, false);
+      this.showPageByName(pageName, false, {hash: hash});
     },
 
 
@@ -440,7 +434,7 @@ cr.define('cr.ui.pageManager', function() {
      */
     willClose: function() {
       var overlay = this.getVisibleOverlay_();
-      if (overlay && overlay.didClosePage)
+      if (overlay)
         overlay.didClosePage();
     },
 
@@ -463,7 +457,8 @@ cr.define('cr.ui.pageManager', function() {
     },
 
     /**
-     * @param {PageManager.Observer} observer The observer to register.
+     * @param {!cr.ui.pageManager.PageManager.Observer} observer The observer to
+     *     register.
      */
     addObserver: function(observer) {
       this.observers_.push(observer);
@@ -472,12 +467,13 @@ cr.define('cr.ui.pageManager', function() {
     /**
      * Shows a registered overlay page. Does not update history.
      * @param {string} overlayName Page name.
+     * @param {string} hash The hash state to associate with the overlay.
      * @param {cr.ui.pageManager.Page} rootPage The currently visible root-level
      *     page.
      * @return {boolean} Whether we showed an overlay.
      * @private
      */
-    showOverlay_: function(overlayName, rootPage) {
+    showOverlay_: function(overlayName, hash, rootPage) {
       var overlay = this.registeredOverlayPages[overlayName.toLowerCase()];
       if (!overlay || !overlay.canShowPage())
         return false;
@@ -493,10 +489,12 @@ cr.define('cr.ui.pageManager', function() {
         this.showPageByName(overlay.parentPage.name, false);
       }
 
+      overlay.hash = hash;
       if (!overlay.visible) {
         overlay.visible = true;
-        if (overlay.didShowPage)
-          overlay.didShowPage();
+        overlay.didShowPage();
+      } else {
+        overlay.didChangeHash();
       }
 
       // Change focus to the overlay if any other control was focused by
@@ -602,11 +600,9 @@ cr.define('cr.ui.pageManager', function() {
      * to update the history.
      * @param {boolean} replace If true, handlers should replace the current
      *     history event rather than create new ones.
-     * @param {object=} opt_params A bag of optional params, including:
-     *     {boolean} ignoreHash Whether to include the hash or not.
      * @private
      */
-    updateHistoryState_: function(replace, opt_params) {
+    updateHistoryState_: function(replace) {
       if (this.isDialog)
         return;
 
@@ -619,9 +615,7 @@ cr.define('cr.ui.pageManager', function() {
 
       // If the page is already in history (the user may have clicked the same
       // link twice, or this is the initial load), do nothing.
-      var hash = opt_params && opt_params.ignoreHash ?
-          '' : window.location.hash;
-      var newPath = (page == this.defaultPage_ ? '' : page.name) + hash;
+      var newPath = (page == this.defaultPage_ ? '' : page.name) + page.hash;
       if (path == newPath)
         return;
 
@@ -642,8 +636,8 @@ cr.define('cr.ui.pageManager', function() {
 
     /**
      * Find an enclosing section for an element if it exists.
-     * @param {Element} element Element to search.
-     * @return {Element} The section element, or null.
+     * @param {Node} node Element to search.
+     * @return {Node} The section element, or null.
      * @private
      */
     findSectionForNode_: function(node) {
@@ -714,6 +708,24 @@ cr.define('cr.ui.pageManager', function() {
         e.style.left = this.horizontalOffset - scrollLeft + 'px';
       }
     },
+
+    /**
+     * Calls the given callback with each registered page.
+     * @param {boolean} includeRootPages Whether the callback should be called
+     *     for the root pages.
+     * @param {function(cr.ui.pageManager.Page)} callback The callback.
+     * @private
+     */
+    forEachPage_: function(includeRootPages, callback) {
+      var pageNames = Object.keys(this.registeredOverlayPages);
+      if (includeRootPages)
+        pageNames = Object.keys(this.registeredPages).concat(pageNames);
+
+      pageNames.forEach(function(name) {
+        callback.call(this, this.registeredOverlayPages[name] ||
+                            this.registeredPages[name]);
+      }, this);
+    },
   };
 
   /**