browser/metro/base/content/ContextUI.js

Wed, 31 Dec 2014 06:55:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:55:50 +0100
changeset 2
7e26c7da4463
permissions
-rw-r--r--

Added tag UPSTREAM_283F7C6 for changeset ca08bd8f51b2

     1 /* This Source Code Form is subject to the terms of the Mozilla Public
     2  * License, v. 2.0. If a copy of the MPL was not distributed with this
     3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     5 // Fired when the tabtray is displayed
     6 const kContextUITabsShowEvent = "MozContextUITabsShow";
     7 // add more as needed...
     9 /*
    10  * Manages context UI (navbar, tabbar, appbar) and track visibility. Also
    11  * tracks events that summon and hide the context UI.
    12  */
    13 var ContextUI = {
    14   _expandable: true,
    15   _hidingId: 0,
    17   /*******************************************
    18    * init
    19    */
    21   init: function init() {
    22     Elements.browsers.addEventListener('URLChanged', this, true);
    23     Elements.browsers.addEventListener("AlertActive", this, true);
    24     Elements.browsers.addEventListener("AlertClose", this, true);
    25     Elements.tabList.addEventListener('TabSelect', this, true);
    26     Elements.panelUI.addEventListener('ToolPanelShown', this, false);
    27     Elements.panelUI.addEventListener('ToolPanelHidden', this, false);
    29     Elements.tray.addEventListener("mousemove", this, false);
    30     Elements.tray.addEventListener("mouseleave", this, false);
    32     window.addEventListener("touchstart", this, true);
    33     window.addEventListener("mousedown", this, true);
    34     window.addEventListener("MozEdgeUIStarted", this, true);
    35     window.addEventListener("MozEdgeUICanceled", this, true);
    36     window.addEventListener("MozEdgeUICompleted", this, true);
    37     window.addEventListener("keypress", this, true);
    38     window.addEventListener("KeyboardChanged", this, false);
    39     window.addEventListener("MozFlyoutPanelShowing", this, false);
    41     Elements.tray.addEventListener("transitionend", this, true);
    43     Appbar.init();
    44   },
    46   /*******************************************
    47    * Context UI state getters & setters
    48    */
    50   // any visiblilty
    51   get isVisible() {
    52     return this.navbarVisible || this.tabbarVisible || this.contextAppbarVisible;
    53   },
    55   // navbar visiblilty
    56   get navbarVisible() {
    57     return (Elements.navbar.hasAttribute("visible") ||
    58             Elements.navbar.hasAttribute("startpage"));
    59   },
    61   // tabbar visiblilty
    62   get tabbarVisible() {
    63     return Elements.tray.hasAttribute("expanded");
    64   },
    66   // appbar visiblilty
    67   get contextAppbarVisible() {
    68     return Elements.contextappbar.isShowing;
    69   },
    71   // currently not in use, for the always show tabs feature
    72   get isExpandable() { return this._expandable; },
    73   set isExpandable(aFlag) {
    74     this._expandable = aFlag;
    75     if (!this._expandable)
    76       this.dismiss();
    77   },
    79   /*******************************************
    80    * Public api
    81    */
    83   /*
    84    * Toggle the current nav UI state. Fires context ui events.
    85    */
    86   toggleNavUI: function () {
    87     // The navbar is forced open when the start page is visible. appbar.js
    88     // controls the "visible" property, and browser-ui controls the "startpage"
    89     // property. Hence we rely on the tabbar for current toggle state.
    90     if (this.tabbarVisible) {
    91       this.dismiss();
    92     } else {
    93       this.displayNavUI();
    94     }
    95   },
    97   /*
    98    * Show the nav and tabs bar. Returns true if any non-visible UI
    99    * was shown. Fires context ui events.
   100    */
   101   displayNavUI: function () {
   102     let shown = false;
   104     if (!this.navbarVisible) {
   105       BrowserUI.updateURI();
   106       this.displayNavbar();
   107       shown = true;
   108     }
   110     if (!this.tabbarVisible) {
   111       this.displayTabs();
   112       shown = true;
   113     }
   115     if (shown) {
   116       ContentAreaObserver.updateContentArea();
   117     }
   119     return shown;
   120   },
   122   /*
   123    * Dismiss any context UI currently visible. Returns true if any
   124    * visible UI was dismissed. Fires context ui events.
   125    */
   126   dismiss: function () {
   127     let dismissed = false;
   129     this._clearDelayedTimeout();
   131     // No assurances this will hide the nav bar. It may have the
   132     // 'startpage' property set. This removes the 'visible' property.
   133     if (this.navbarVisible) {
   134       BrowserUI.blurNavBar();
   135       this.dismissNavbar();
   136       dismissed = true;
   137     }
   138     if (this.tabbarVisible) {
   139       this.dismissTabs();
   140       dismissed = true;
   141     }
   142     if (Elements.contextappbar.isShowing) {
   143       this.dismissContextAppbar();
   144       dismissed = true;
   145     }
   147     if (dismissed) {
   148       ContentAreaObserver.updateContentArea();
   149     }
   151     return dismissed;
   152   },
   154   /*
   155    * Briefly show the tab bar and then hide it. Fires context ui events.
   156    */
   157   peekTabs: function peekTabs(aDelay) {
   158     if (!this.tabbarVisible)
   159       this.displayTabs();
   161     ContextUI.dismissTabsWithDelay(aDelay);
   162   },
   164   /*
   165    * Dismiss tab bar after a delay. Fires context ui events.
   166    */
   167   dismissTabsWithDelay: function (aDelay) {
   168     aDelay = aDelay || kForegroundTabAnimationDelay;
   169     this._clearDelayedTimeout();
   170     this._lastTimeoutDelay = aDelay;
   171     this._hidingId = setTimeout(function () {
   172         ContextUI.dismissTabs();
   173       }, aDelay);
   174   },
   176   /*
   177    * Display the nav bar.
   178    *
   179    * @return false if we were already visible, and didn't do anything.
   180    */
   181   displayNavbar: function () {
   182     if (Elements.chromeState.getAttribute("navbar") == "visible") {
   183       return false;
   184     }
   186     Elements.navbar.show();
   187     Elements.chromeState.setAttribute("navbar", "visible");
   188     ContentAreaObserver.updateContentArea();
   189     return true;
   190   },
   192   // Display the tab tray
   193   displayTabs: function () {
   194     this._clearDelayedTimeout();
   195     this._setIsExpanded(true);
   196   },
   198   // Dismiss the navbar if visible.
   199   dismissNavbar: function dismissNavbar() {
   200     if (!BrowserUI.isStartTabVisible) {
   201       Elements.autocomplete.closePopup();
   202       Elements.navbar.dismiss();
   203       Elements.chromeState.removeAttribute("navbar");
   204       ContentAreaObserver.updateContentArea();
   205     }
   206   },
   208   // Dismiss the tabstray if visible.
   209   dismissTabs: function dimissTabs() {
   210     this._clearDelayedTimeout();
   211     this._setIsExpanded(false);
   212   },
   214   // Dismiss the appbar if visible.
   215   dismissContextAppbar: function dismissContextAppbar() {
   216     Elements.contextappbar.dismiss();
   217   },
   219   /*******************************************
   220    * Internal utils
   221    */
   223   // tabtray state
   224   _setIsExpanded: function _setIsExpanded(aFlag, setSilently) {
   225     // if the tray can't be expanded, don't expand it.
   226     if (!this.isExpandable || this.tabbarVisible == aFlag)
   227       return;
   229     if (aFlag)
   230       Elements.tray.setAttribute("expanded", "true");
   231     else
   232       Elements.tray.removeAttribute("expanded");
   234     if (!setSilently)
   235       this._fire(kContextUITabsShowEvent);
   236   },
   238   _clearDelayedTimeout: function _clearDelayedTimeout() {
   239     if (this._hidingId) {
   240       clearTimeout(this._hidingId);
   241       this._hidingId = 0;
   242       this._delayedHide = false;
   243     }
   244   },
   246   _resetDelayedTimeout: function () {
   247     this._hidingId = setTimeout(function () {
   248         ContextUI.dismissTabs();
   249       }, this._lastTimeoutDelay);
   250   },
   252   /*******************************************
   253    * Events
   254    */
   256   _onEdgeUIStarted: function(aEvent) {
   257     this._hasEdgeSwipeStarted = true;
   258     this._clearDelayedTimeout();
   259     this.toggleNavUI();
   260   },
   262   _onEdgeUICanceled: function(aEvent) {
   263     this._hasEdgeSwipeStarted = false;
   264     this.dismiss();
   265   },
   267   _onEdgeUICompleted: function(aEvent) {
   268     if (this._hasEdgeSwipeStarted) {
   269       this._hasEdgeSwipeStarted = false;
   270       return;
   271     }
   273     this._clearDelayedTimeout();
   274     this.toggleNavUI();
   275   },
   277   onDownInput: function onDownInput(aEvent) {
   278     if (!this.isVisible) {
   279       return;
   280     }
   282     // Various ui element containers we do not update context ui for.
   283     let whitelist = [
   284       // Clicks on tab bar elements should not close the tab bar. the tabbar
   285       // handles this.
   286       Elements.tabs,
   287       // Don't let a click on an infobar button dismiss the appbar or navbar.
   288       // Note the notification box should always hover above these other two
   289       // bars.
   290       Browser.getNotificationBox()
   291     ];
   293     if (whitelist.some(elem => elem.contains(aEvent.target))) {
   294       return;
   295     }
   297     // If a start tab is visible only dismiss the tab bar.
   298     if (BrowserUI.isStartTabVisible) {
   299       ContextUI.dismissTabs();
   300       return;
   301     }
   303     // content, dismiss anything visible
   304     if (aEvent.target.ownerDocument.defaultView.top == getBrowser().contentWindow) {
   305       this.dismiss();
   306       return;
   307     }
   309     // dismiss tabs and context app bar if visible
   310     this.dismissTabs();
   311     this.dismissContextAppbar();
   312   },
   314   onMouseMove: function (aEvent) {
   315     if (this._hidingId) {
   316       this._clearDelayedTimeout();
   317       this._delayedHide = true;
   318     }
   319   },
   321   onMouseLeave: function (aEvent) {
   322     if (this._delayedHide) {
   323       this._delayedHide = false;
   324       this._resetDelayedTimeout();
   325     }
   326   },
   328   handleEvent: function handleEvent(aEvent) {
   329     switch (aEvent.type) {
   330       case "URLChanged":
   331         // "aEvent.detail" is a boolean value that indicates whether actual URL
   332         // has changed ignoring URL fragment changes.
   333         if (aEvent.target == Browser.selectedBrowser && aEvent.detail) {
   334           this.displayNavbar();
   335         }
   336         break;
   337       case "MozEdgeUIStarted":
   338         this._onEdgeUIStarted(aEvent);
   339         break;
   340       case "MozEdgeUICanceled":
   341         this._onEdgeUICanceled(aEvent);
   342         break;
   343       case "MozEdgeUICompleted":
   344         this._onEdgeUICompleted(aEvent);
   345         break;
   346       case "keypress":
   347         if (String.fromCharCode(aEvent.which) == "z" &&
   348             aEvent.getModifierState("Win"))
   349           this.toggleNavUI();
   350         break;
   351       case "transitionend":
   352         setTimeout(function () {
   353           ContentAreaObserver.updateContentArea();
   354         }, 0);
   355         break;
   356       case "KeyboardChanged":
   357         this.dismissTabs();
   358         break;
   359       case "mousedown":
   360         if (aEvent.button != 0) {
   361           break;
   362         }
   363         this.onDownInput(aEvent);
   364         break;
   365       case "mousemove":
   366         this.onMouseMove(aEvent);
   367         break;
   368       case "mouseleave":
   369         this.onMouseLeave(aEvent);
   370         break;
   371       case "touchstart":
   372         this.onDownInput(aEvent);
   373         break;
   374       case "ToolPanelShown":
   375       case "ToolPanelHidden":
   376         this.dismiss();
   377         break;
   378       case "AlertActive":
   379       case "AlertClose":
   380       case "TabSelect":
   381         ContentAreaObserver.updateContentArea();
   382         break;
   383       case "MozFlyoutPanelShowing":
   384         if (BrowserUI.isStartTabVisible) {
   385           this.dismissTabs();
   386           this.dismissContextAppbar();
   387         } else {
   388           this.dismiss();
   389         }
   390         break;
   391     }
   392   },
   394   _fire: function (name) {
   395     let event = document.createEvent("Events");
   396     event.initEvent(name, true, true);
   397     window.dispatchEvent(event);
   398   }
   399 };

mercurial