1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/browser/metro/base/content/ContextUI.js Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,399 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +// Fired when the tabtray is displayed 1.9 +const kContextUITabsShowEvent = "MozContextUITabsShow"; 1.10 +// add more as needed... 1.11 + 1.12 +/* 1.13 + * Manages context UI (navbar, tabbar, appbar) and track visibility. Also 1.14 + * tracks events that summon and hide the context UI. 1.15 + */ 1.16 +var ContextUI = { 1.17 + _expandable: true, 1.18 + _hidingId: 0, 1.19 + 1.20 + /******************************************* 1.21 + * init 1.22 + */ 1.23 + 1.24 + init: function init() { 1.25 + Elements.browsers.addEventListener('URLChanged', this, true); 1.26 + Elements.browsers.addEventListener("AlertActive", this, true); 1.27 + Elements.browsers.addEventListener("AlertClose", this, true); 1.28 + Elements.tabList.addEventListener('TabSelect', this, true); 1.29 + Elements.panelUI.addEventListener('ToolPanelShown', this, false); 1.30 + Elements.panelUI.addEventListener('ToolPanelHidden', this, false); 1.31 + 1.32 + Elements.tray.addEventListener("mousemove", this, false); 1.33 + Elements.tray.addEventListener("mouseleave", this, false); 1.34 + 1.35 + window.addEventListener("touchstart", this, true); 1.36 + window.addEventListener("mousedown", this, true); 1.37 + window.addEventListener("MozEdgeUIStarted", this, true); 1.38 + window.addEventListener("MozEdgeUICanceled", this, true); 1.39 + window.addEventListener("MozEdgeUICompleted", this, true); 1.40 + window.addEventListener("keypress", this, true); 1.41 + window.addEventListener("KeyboardChanged", this, false); 1.42 + window.addEventListener("MozFlyoutPanelShowing", this, false); 1.43 + 1.44 + Elements.tray.addEventListener("transitionend", this, true); 1.45 + 1.46 + Appbar.init(); 1.47 + }, 1.48 + 1.49 + /******************************************* 1.50 + * Context UI state getters & setters 1.51 + */ 1.52 + 1.53 + // any visiblilty 1.54 + get isVisible() { 1.55 + return this.navbarVisible || this.tabbarVisible || this.contextAppbarVisible; 1.56 + }, 1.57 + 1.58 + // navbar visiblilty 1.59 + get navbarVisible() { 1.60 + return (Elements.navbar.hasAttribute("visible") || 1.61 + Elements.navbar.hasAttribute("startpage")); 1.62 + }, 1.63 + 1.64 + // tabbar visiblilty 1.65 + get tabbarVisible() { 1.66 + return Elements.tray.hasAttribute("expanded"); 1.67 + }, 1.68 + 1.69 + // appbar visiblilty 1.70 + get contextAppbarVisible() { 1.71 + return Elements.contextappbar.isShowing; 1.72 + }, 1.73 + 1.74 + // currently not in use, for the always show tabs feature 1.75 + get isExpandable() { return this._expandable; }, 1.76 + set isExpandable(aFlag) { 1.77 + this._expandable = aFlag; 1.78 + if (!this._expandable) 1.79 + this.dismiss(); 1.80 + }, 1.81 + 1.82 + /******************************************* 1.83 + * Public api 1.84 + */ 1.85 + 1.86 + /* 1.87 + * Toggle the current nav UI state. Fires context ui events. 1.88 + */ 1.89 + toggleNavUI: function () { 1.90 + // The navbar is forced open when the start page is visible. appbar.js 1.91 + // controls the "visible" property, and browser-ui controls the "startpage" 1.92 + // property. Hence we rely on the tabbar for current toggle state. 1.93 + if (this.tabbarVisible) { 1.94 + this.dismiss(); 1.95 + } else { 1.96 + this.displayNavUI(); 1.97 + } 1.98 + }, 1.99 + 1.100 + /* 1.101 + * Show the nav and tabs bar. Returns true if any non-visible UI 1.102 + * was shown. Fires context ui events. 1.103 + */ 1.104 + displayNavUI: function () { 1.105 + let shown = false; 1.106 + 1.107 + if (!this.navbarVisible) { 1.108 + BrowserUI.updateURI(); 1.109 + this.displayNavbar(); 1.110 + shown = true; 1.111 + } 1.112 + 1.113 + if (!this.tabbarVisible) { 1.114 + this.displayTabs(); 1.115 + shown = true; 1.116 + } 1.117 + 1.118 + if (shown) { 1.119 + ContentAreaObserver.updateContentArea(); 1.120 + } 1.121 + 1.122 + return shown; 1.123 + }, 1.124 + 1.125 + /* 1.126 + * Dismiss any context UI currently visible. Returns true if any 1.127 + * visible UI was dismissed. Fires context ui events. 1.128 + */ 1.129 + dismiss: function () { 1.130 + let dismissed = false; 1.131 + 1.132 + this._clearDelayedTimeout(); 1.133 + 1.134 + // No assurances this will hide the nav bar. It may have the 1.135 + // 'startpage' property set. This removes the 'visible' property. 1.136 + if (this.navbarVisible) { 1.137 + BrowserUI.blurNavBar(); 1.138 + this.dismissNavbar(); 1.139 + dismissed = true; 1.140 + } 1.141 + if (this.tabbarVisible) { 1.142 + this.dismissTabs(); 1.143 + dismissed = true; 1.144 + } 1.145 + if (Elements.contextappbar.isShowing) { 1.146 + this.dismissContextAppbar(); 1.147 + dismissed = true; 1.148 + } 1.149 + 1.150 + if (dismissed) { 1.151 + ContentAreaObserver.updateContentArea(); 1.152 + } 1.153 + 1.154 + return dismissed; 1.155 + }, 1.156 + 1.157 + /* 1.158 + * Briefly show the tab bar and then hide it. Fires context ui events. 1.159 + */ 1.160 + peekTabs: function peekTabs(aDelay) { 1.161 + if (!this.tabbarVisible) 1.162 + this.displayTabs(); 1.163 + 1.164 + ContextUI.dismissTabsWithDelay(aDelay); 1.165 + }, 1.166 + 1.167 + /* 1.168 + * Dismiss tab bar after a delay. Fires context ui events. 1.169 + */ 1.170 + dismissTabsWithDelay: function (aDelay) { 1.171 + aDelay = aDelay || kForegroundTabAnimationDelay; 1.172 + this._clearDelayedTimeout(); 1.173 + this._lastTimeoutDelay = aDelay; 1.174 + this._hidingId = setTimeout(function () { 1.175 + ContextUI.dismissTabs(); 1.176 + }, aDelay); 1.177 + }, 1.178 + 1.179 + /* 1.180 + * Display the nav bar. 1.181 + * 1.182 + * @return false if we were already visible, and didn't do anything. 1.183 + */ 1.184 + displayNavbar: function () { 1.185 + if (Elements.chromeState.getAttribute("navbar") == "visible") { 1.186 + return false; 1.187 + } 1.188 + 1.189 + Elements.navbar.show(); 1.190 + Elements.chromeState.setAttribute("navbar", "visible"); 1.191 + ContentAreaObserver.updateContentArea(); 1.192 + return true; 1.193 + }, 1.194 + 1.195 + // Display the tab tray 1.196 + displayTabs: function () { 1.197 + this._clearDelayedTimeout(); 1.198 + this._setIsExpanded(true); 1.199 + }, 1.200 + 1.201 + // Dismiss the navbar if visible. 1.202 + dismissNavbar: function dismissNavbar() { 1.203 + if (!BrowserUI.isStartTabVisible) { 1.204 + Elements.autocomplete.closePopup(); 1.205 + Elements.navbar.dismiss(); 1.206 + Elements.chromeState.removeAttribute("navbar"); 1.207 + ContentAreaObserver.updateContentArea(); 1.208 + } 1.209 + }, 1.210 + 1.211 + // Dismiss the tabstray if visible. 1.212 + dismissTabs: function dimissTabs() { 1.213 + this._clearDelayedTimeout(); 1.214 + this._setIsExpanded(false); 1.215 + }, 1.216 + 1.217 + // Dismiss the appbar if visible. 1.218 + dismissContextAppbar: function dismissContextAppbar() { 1.219 + Elements.contextappbar.dismiss(); 1.220 + }, 1.221 + 1.222 + /******************************************* 1.223 + * Internal utils 1.224 + */ 1.225 + 1.226 + // tabtray state 1.227 + _setIsExpanded: function _setIsExpanded(aFlag, setSilently) { 1.228 + // if the tray can't be expanded, don't expand it. 1.229 + if (!this.isExpandable || this.tabbarVisible == aFlag) 1.230 + return; 1.231 + 1.232 + if (aFlag) 1.233 + Elements.tray.setAttribute("expanded", "true"); 1.234 + else 1.235 + Elements.tray.removeAttribute("expanded"); 1.236 + 1.237 + if (!setSilently) 1.238 + this._fire(kContextUITabsShowEvent); 1.239 + }, 1.240 + 1.241 + _clearDelayedTimeout: function _clearDelayedTimeout() { 1.242 + if (this._hidingId) { 1.243 + clearTimeout(this._hidingId); 1.244 + this._hidingId = 0; 1.245 + this._delayedHide = false; 1.246 + } 1.247 + }, 1.248 + 1.249 + _resetDelayedTimeout: function () { 1.250 + this._hidingId = setTimeout(function () { 1.251 + ContextUI.dismissTabs(); 1.252 + }, this._lastTimeoutDelay); 1.253 + }, 1.254 + 1.255 + /******************************************* 1.256 + * Events 1.257 + */ 1.258 + 1.259 + _onEdgeUIStarted: function(aEvent) { 1.260 + this._hasEdgeSwipeStarted = true; 1.261 + this._clearDelayedTimeout(); 1.262 + this.toggleNavUI(); 1.263 + }, 1.264 + 1.265 + _onEdgeUICanceled: function(aEvent) { 1.266 + this._hasEdgeSwipeStarted = false; 1.267 + this.dismiss(); 1.268 + }, 1.269 + 1.270 + _onEdgeUICompleted: function(aEvent) { 1.271 + if (this._hasEdgeSwipeStarted) { 1.272 + this._hasEdgeSwipeStarted = false; 1.273 + return; 1.274 + } 1.275 + 1.276 + this._clearDelayedTimeout(); 1.277 + this.toggleNavUI(); 1.278 + }, 1.279 + 1.280 + onDownInput: function onDownInput(aEvent) { 1.281 + if (!this.isVisible) { 1.282 + return; 1.283 + } 1.284 + 1.285 + // Various ui element containers we do not update context ui for. 1.286 + let whitelist = [ 1.287 + // Clicks on tab bar elements should not close the tab bar. the tabbar 1.288 + // handles this. 1.289 + Elements.tabs, 1.290 + // Don't let a click on an infobar button dismiss the appbar or navbar. 1.291 + // Note the notification box should always hover above these other two 1.292 + // bars. 1.293 + Browser.getNotificationBox() 1.294 + ]; 1.295 + 1.296 + if (whitelist.some(elem => elem.contains(aEvent.target))) { 1.297 + return; 1.298 + } 1.299 + 1.300 + // If a start tab is visible only dismiss the tab bar. 1.301 + if (BrowserUI.isStartTabVisible) { 1.302 + ContextUI.dismissTabs(); 1.303 + return; 1.304 + } 1.305 + 1.306 + // content, dismiss anything visible 1.307 + if (aEvent.target.ownerDocument.defaultView.top == getBrowser().contentWindow) { 1.308 + this.dismiss(); 1.309 + return; 1.310 + } 1.311 + 1.312 + // dismiss tabs and context app bar if visible 1.313 + this.dismissTabs(); 1.314 + this.dismissContextAppbar(); 1.315 + }, 1.316 + 1.317 + onMouseMove: function (aEvent) { 1.318 + if (this._hidingId) { 1.319 + this._clearDelayedTimeout(); 1.320 + this._delayedHide = true; 1.321 + } 1.322 + }, 1.323 + 1.324 + onMouseLeave: function (aEvent) { 1.325 + if (this._delayedHide) { 1.326 + this._delayedHide = false; 1.327 + this._resetDelayedTimeout(); 1.328 + } 1.329 + }, 1.330 + 1.331 + handleEvent: function handleEvent(aEvent) { 1.332 + switch (aEvent.type) { 1.333 + case "URLChanged": 1.334 + // "aEvent.detail" is a boolean value that indicates whether actual URL 1.335 + // has changed ignoring URL fragment changes. 1.336 + if (aEvent.target == Browser.selectedBrowser && aEvent.detail) { 1.337 + this.displayNavbar(); 1.338 + } 1.339 + break; 1.340 + case "MozEdgeUIStarted": 1.341 + this._onEdgeUIStarted(aEvent); 1.342 + break; 1.343 + case "MozEdgeUICanceled": 1.344 + this._onEdgeUICanceled(aEvent); 1.345 + break; 1.346 + case "MozEdgeUICompleted": 1.347 + this._onEdgeUICompleted(aEvent); 1.348 + break; 1.349 + case "keypress": 1.350 + if (String.fromCharCode(aEvent.which) == "z" && 1.351 + aEvent.getModifierState("Win")) 1.352 + this.toggleNavUI(); 1.353 + break; 1.354 + case "transitionend": 1.355 + setTimeout(function () { 1.356 + ContentAreaObserver.updateContentArea(); 1.357 + }, 0); 1.358 + break; 1.359 + case "KeyboardChanged": 1.360 + this.dismissTabs(); 1.361 + break; 1.362 + case "mousedown": 1.363 + if (aEvent.button != 0) { 1.364 + break; 1.365 + } 1.366 + this.onDownInput(aEvent); 1.367 + break; 1.368 + case "mousemove": 1.369 + this.onMouseMove(aEvent); 1.370 + break; 1.371 + case "mouseleave": 1.372 + this.onMouseLeave(aEvent); 1.373 + break; 1.374 + case "touchstart": 1.375 + this.onDownInput(aEvent); 1.376 + break; 1.377 + case "ToolPanelShown": 1.378 + case "ToolPanelHidden": 1.379 + this.dismiss(); 1.380 + break; 1.381 + case "AlertActive": 1.382 + case "AlertClose": 1.383 + case "TabSelect": 1.384 + ContentAreaObserver.updateContentArea(); 1.385 + break; 1.386 + case "MozFlyoutPanelShowing": 1.387 + if (BrowserUI.isStartTabVisible) { 1.388 + this.dismissTabs(); 1.389 + this.dismissContextAppbar(); 1.390 + } else { 1.391 + this.dismiss(); 1.392 + } 1.393 + break; 1.394 + } 1.395 + }, 1.396 + 1.397 + _fire: function (name) { 1.398 + let event = document.createEvent("Events"); 1.399 + event.initEvent(name, true, true); 1.400 + window.dispatchEvent(event); 1.401 + } 1.402 +};