diff options
Diffstat (limited to 'webbrowser/base/content/browser-fullScreen.js')
-rw-r--r-- | webbrowser/base/content/browser-fullScreen.js | 462 |
1 files changed, 462 insertions, 0 deletions
diff --git a/webbrowser/base/content/browser-fullScreen.js b/webbrowser/base/content/browser-fullScreen.js new file mode 100644 index 0000000..e816ce5 --- /dev/null +++ b/webbrowser/base/content/browser-fullScreen.js @@ -0,0 +1,462 @@ +# -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +var FullScreen = { + _XULNS: "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul", + + toggle: function () { + var enterFS = window.fullScreen; + + // Toggle the View:FullScreen command, which controls elements like the + // fullscreen menuitem, menubars, and the appmenu. + let fullscreenCommand = document.getElementById("View:FullScreen"); + if (enterFS) { + fullscreenCommand.setAttribute("checked", enterFS); + } else { + fullscreenCommand.removeAttribute("checked"); + } + +#ifdef XP_MACOSX + // Make sure the menu items are adjusted. + document.getElementById("enterFullScreenItem").hidden = enterFS; + document.getElementById("exitFullScreenItem").hidden = !enterFS; +#endif + + if (!this._fullScrToggler) { + this._fullScrToggler = document.getElementById("fullscr-toggler"); + this._fullScrToggler.addEventListener("mouseover", this._expandCallback, false); + this._fullScrToggler.addEventListener("dragenter", this._expandCallback, false); + } + + // On OS X Lion we don't want to hide toolbars when entering fullscreen, unless + // we're entering DOM fullscreen, in which case we should hide the toolbars. + // If we're leaving fullscreen, then we'll go through the exit code below to + // make sure toolbars are made visible in the case of DOM fullscreen. + if (enterFS && this.useLionFullScreen) { + if (document.mozFullScreen) { + this.showXULChrome("toolbar", false); + } + else { + gNavToolbox.setAttribute("inFullscreen", true); + document.documentElement.setAttribute("inFullscreen", true); + } + return; + } + + // show/hide menubars, toolbars (except the full screen toolbar) + this.showXULChrome("toolbar", !enterFS); + + if (enterFS) { + document.addEventListener("keypress", this._keyToggleCallback, false); + document.addEventListener("popupshown", this._setPopupOpen, false); + document.addEventListener("popuphidden", this._setPopupOpen, false); + this._shouldAnimate = true; + if (gPrefService.getBoolPref("browser.fullscreen.autohide")) { + gBrowser.mPanelContainer.addEventListener("mousemove", + this._collapseCallback, false); + } + // We don't animate the toolbar collapse if in DOM full-screen mode, + // as the size of the content area would still be changing after the + // mozfullscreenchange event fired, which could confuse content script. + this.hideNavToolbox(document.mozFullScreen); + } + else { + this.showNavToolbox(false); + // This is needed if they use the context menu to quit fullscreen + this._isPopupOpen = false; + + document.documentElement.removeAttribute("inDOMFullscreen"); + + this.cleanup(); + } + }, + + exitDomFullScreen : function() { + document.mozCancelFullScreen(); + }, + + handleEvent: function (event) { + switch (event.type) { + case "activate": + if (document.mozFullScreen) { + this.showWarning(this.fullscreenDoc); + } + break; + case "transitionend": + if (event.propertyName == "opacity") + this.cancelWarning(); + break; + } + }, + + enterDomFullscreen : function(event) { + if (!document.mozFullScreen) + return; + + // However, if we receive a "MozDOMFullscreen:NewOrigin" event for a document + // which is not a subdocument of a currently active (ie. visible) browser + // or iframe, we know that we've switched to a different frame since the + // request to enter full-screen was made, so we should exit full-screen + // since the "full-screen document" isn't acutally visible. + if (!event.target.defaultView.QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsIWebNavigation) + .QueryInterface(Ci.nsIDocShell).isActive) { + document.mozCancelFullScreen(); + return; + } + + let focusManager = Cc["@mozilla.org/focus-manager;1"].getService(Ci.nsIFocusManager); + if (focusManager.activeWindow != window) { + // The top-level window has lost focus since the request to enter + // full-screen was made. Cancel full-screen. + document.mozCancelFullScreen(); + return; + } + + document.documentElement.setAttribute("inDOMFullscreen", true); + + if (gFindBarInitialized) + gFindBar.close(); + + this.showWarning(event.target); + + // Exit DOM full-screen mode upon open, close, or change tab. + gBrowser.tabContainer.addEventListener("TabOpen", this.exitDomFullScreen); + gBrowser.tabContainer.addEventListener("TabClose", this.exitDomFullScreen); + gBrowser.tabContainer.addEventListener("TabSelect", this.exitDomFullScreen); + + // Add listener to detect when the fullscreen window is re-focused. + // If a fullscreen window loses focus, we show a warning when the + // fullscreen window is refocused. + if (!this.useLionFullScreen) { + window.addEventListener("activate", this); + } + + // Cancel any "hide the toolbar" animation which is in progress, and make + // the toolbar hide immediately. + this.hideNavToolbox(true); + }, + + cleanup: function () { + if (!window.fullScreen) { + gBrowser.mPanelContainer.removeEventListener("mousemove", + this._collapseCallback, false); + document.removeEventListener("keypress", this._keyToggleCallback, false); + document.removeEventListener("popupshown", this._setPopupOpen, false); + document.removeEventListener("popuphidden", this._setPopupOpen, false); + + this.cancelWarning(); + gBrowser.tabContainer.removeEventListener("TabOpen", this.exitDomFullScreen); + gBrowser.tabContainer.removeEventListener("TabClose", this.exitDomFullScreen); + gBrowser.tabContainer.removeEventListener("TabSelect", this.exitDomFullScreen); + if (!this.useLionFullScreen) + window.removeEventListener("activate", this); + this.fullscreenDoc = null; + } + }, + + // Event callbacks + _expandCallback: function() + { + FullScreen.showNavToolbox(); + }, + _collapseCallback: function() + { + FullScreen.hideNavToolbox(); + }, + _keyToggleCallback: function(aEvent) + { + // if we can use the keyboard (eg Ctrl+L or Ctrl+E) to open the toolbars, we + // should provide a way to collapse them too. + if (aEvent.keyCode == aEvent.DOM_VK_ESCAPE) { + FullScreen.hideNavToolbox(true); + } + // F6 is another shortcut to the address bar, but its not covered in OpenLocation() + else if (aEvent.keyCode == aEvent.DOM_VK_F6) + FullScreen.showNavToolbox(); + }, + + // Checks whether we are allowed to collapse the chrome + _isPopupOpen: false, + _isChromeCollapsed: false, + _safeToCollapse: function(forceHide) + { + if (!gPrefService.getBoolPref("browser.fullscreen.autohide")) + return false; + + // a popup menu is open in chrome: don't collapse chrome + if (!forceHide && this._isPopupOpen) + return false; + + // a textbox in chrome is focused (location bar anyone?): don't collapse chrome + if (document.commandDispatcher.focusedElement && + document.commandDispatcher.focusedElement.ownerDocument == document && + document.commandDispatcher.focusedElement.localName == "input") { + if (forceHide) + // hidden textboxes that still have focus are bad bad bad + document.commandDispatcher.focusedElement.blur(); + else + return false; + } + return true; + }, + + _setPopupOpen: function(aEvent) + { + // Popups should only veto chrome collapsing if they were opened when the chrome was not collapsed. + // Otherwise, they would not affect chrome and the user would expect the chrome to go away. + // e.g. we wouldn't want the autoscroll icon firing this event, so when the user + // toggles chrome when moving mouse to the top, it doesn't go away again. + if (aEvent.type == "popupshown" && !FullScreen._isChromeCollapsed && + aEvent.target.localName != "tooltip" && aEvent.target.localName != "window") + FullScreen._isPopupOpen = true; + else if (aEvent.type == "popuphidden" && aEvent.target.localName != "tooltip" && + aEvent.target.localName != "window") + FullScreen._isPopupOpen = false; + }, + + // Autohide helpers for the context menu item + getAutohide: function(aItem) + { + aItem.setAttribute("checked", gPrefService.getBoolPref("browser.fullscreen.autohide")); + }, + setAutohide: function() + { + gPrefService.setBoolPref("browser.fullscreen.autohide", !gPrefService.getBoolPref("browser.fullscreen.autohide")); + }, + + // Animate the toolbars disappearing + _shouldAnimate: true, + + cancelWarning: function(event) { + if (!this.warningBox) + return; + this.warningBox.removeEventListener("transitionend", this); + if (this.warningFadeOutTimeout) { + clearTimeout(this.warningFadeOutTimeout); + this.warningFadeOutTimeout = null; + } + + // Ensure focus switches away from the (now hidden) warning box. If the user + // clicked buttons in the fullscreen key authorization UI, it would have been + // focused, and any key events would be directed at the (now hidden) chrome + // document instead of the target document. + gBrowser.selectedBrowser.focus(); + + this.warningBox.setAttribute("hidden", true); + this.warningBox.removeAttribute("fade-warning-out"); + this.warningBox = null; + }, + + warningBox: null, + warningFadeOutTimeout: null, + fullscreenDoc: null, + + // Shows a warning that the site has entered fullscreen for a short duration. + showWarning: function(targetDoc) { + let timeout = gPrefService.getIntPref("full-screen-api.warning.timeout"); + if (!document.mozFullScreen || timeout <= 0) + return; + + // Set the strings on the fullscreen warning UI. + this.fullscreenDoc = targetDoc; + let uri = this.fullscreenDoc.nodePrincipal.URI; + let host = null; + try { + host = uri.host; + } catch (e) { } + let hostLabel = document.getElementById("full-screen-domain-text"); + if (host) { + // Document's principal's URI has a host. Display a warning including the hostname. + let utils = {}; + Cu.import("resource://gre/modules/DownloadUtils.jsm", utils); + let displayHost = utils.DownloadUtils.getURIHost(uri.spec)[0]; + let bundle = Services.strings.createBundle("chrome://browser/locale/browser.properties"); + + hostLabel.textContent = bundle.formatStringFromName("fullscreen.entered", [displayHost], 1); + hostLabel.removeAttribute("hidden"); + } else { + hostLabel.setAttribute("hidden", "true"); + } + + // Note: the warning box can be non-null if the warning box from the previous request + // wasn't hidden before another request was made. + if (!this.warningBox) { + this.warningBox = document.getElementById("full-screen-warning-container"); + // Add a listener to clean up state after the warning is hidden. + this.warningBox.addEventListener("transitionend", this); + this.warningBox.removeAttribute("hidden"); + } else { + if (this.warningFadeOutTimeout) { + clearTimeout(this.warningFadeOutTimeout); + this.warningFadeOutTimeout = null; + } + this.warningBox.removeAttribute("fade-warning-out"); + } + + // Set a timeout to fade the warning out after a few moments. + this.warningFadeOutTimeout = setTimeout(() => { + if (this.warningBox) { + this.warningBox.setAttribute("fade-warning-out", "true"); + } + }, timeout); + }, + + showNavToolbox: function(trackMouse = true) { + this._fullScrToggler.hidden = true; + gNavToolbox.removeAttribute("fullscreenShouldAnimate"); + gNavToolbox.style.marginTop = ""; + + if (!this._isChromeCollapsed) { + return; + } + + // Track whether mouse is near the toolbox + this._isChromeCollapsed = false; + if (trackMouse) { + gBrowser.mPanelContainer.addEventListener("mousemove", + this._collapseCallback, false); + } + }, + + hideNavToolbox: function(forceHide = false) { + this._fullScrToggler.hidden = document.mozFullScreen; + if (this._isChromeCollapsed) { + if (forceHide) { + gNavToolbox.removeAttribute("fullscreenShouldAnimate"); + } + return; + } + if (!this._safeToCollapse(forceHide)) { + this._fullScrToggler.hidden = true; + return; + } + + // browser.fullscreen.animateUp + // 0 - never animate up + // 1 - animate only for first collapse after entering fullscreen (default for perf's sake) + // 2 - animate every time it collapses + let animateUp = gPrefService.getIntPref("browser.fullscreen.animateUp"); + if (animateUp == 0) { + this._shouldAnimate = false; + } else if (animateUp == 2) { + this._shouldAnimate = true; + } + if (this._shouldAnimate && !forceHide) { + gNavToolbox.setAttribute("fullscreenShouldAnimate", true); + this._shouldAnimate = false; + // Hide the fullscreen toggler until the transition ends. + let listener = () => { + gNavToolbox.removeEventListener("transitionend", listener, true); + if (this._isChromeCollapsed) + this._fullScrToggler.hidden = false; + }; + gNavToolbox.addEventListener("transitionend", listener, true); + this._fullScrToggler.hidden = true; + } + + gNavToolbox.style.marginTop = + -gNavToolbox.getBoundingClientRect().height + "px"; + this._isChromeCollapsed = true; + gBrowser.mPanelContainer.removeEventListener("mousemove", + this._collapseCallback, false); + }, + + showXULChrome: function(aTag, aShow) + { + var els = document.getElementsByTagNameNS(this._XULNS, aTag); + + for (let el of els) { + // XXX don't interfere with previously collapsed toolbars + if (el.getAttribute("fullscreentoolbar") == "true") { + if (!aShow) { + + var toolbarMode = el.getAttribute("mode"); + if (toolbarMode != "text") { + el.setAttribute("saved-mode", toolbarMode); + el.setAttribute("saved-iconsize", el.getAttribute("iconsize")); + el.setAttribute("mode", "icons"); + el.setAttribute("iconsize", "small"); + } + + // Give the main nav bar and the tab bar the fullscreen context menu, + // otherwise remove context menu to prevent breakage + el.setAttribute("saved-context", el.getAttribute("context")); + if (el.id == "nav-bar" || el.id == "TabsToolbar") + el.setAttribute("context", "autohide-context"); + else + el.removeAttribute("context"); + + // Set the inFullscreen attribute to allow specific styling + // in fullscreen mode + el.setAttribute("inFullscreen", true); + } + else { + var restoreAttr = function restoreAttr(attrName) { + var savedAttr = "saved-" + attrName; + if (el.hasAttribute(savedAttr)) { + el.setAttribute(attrName, el.getAttribute(savedAttr)); + el.removeAttribute(savedAttr); + } + } + + restoreAttr("mode"); + restoreAttr("iconsize"); + restoreAttr("context"); + + el.removeAttribute("inFullscreen"); + } + } else { + // use moz-collapsed so it doesn't persist hidden/collapsed, + // so that new windows don't have missing toolbars + if (aShow) + el.removeAttribute("moz-collapsed"); + else + el.setAttribute("moz-collapsed", "true"); + } + } + + if (aShow) { + gNavToolbox.removeAttribute("inFullscreen"); + document.documentElement.removeAttribute("inFullscreen"); + } else { + gNavToolbox.setAttribute("inFullscreen", true); + document.documentElement.setAttribute("inFullscreen", true); + } + + // In tabs-on-top mode, move window controls to the tab bar, + // and in tabs-on-bottom mode, move them back to the navigation toolbar. + // When there is a chance the tab bar may be collapsed, put window + // controls on nav bar. + var fullscreenctls = document.getElementById("window-controls"); + var navbar = document.getElementById("nav-bar"); + var ctlsOnTabbar = window.toolbar.visible && + (navbar.collapsed || (TabsOnTop.enabled && + !gPrefService.getBoolPref("browser.tabs.autoHide"))); + if (fullscreenctls.parentNode == navbar && ctlsOnTabbar) { + fullscreenctls.removeAttribute("flex"); + document.getElementById("TabsToolbar").appendChild(fullscreenctls); + } + else if (fullscreenctls.parentNode.id == "TabsToolbar" && !ctlsOnTabbar) { + fullscreenctls.setAttribute("flex", "1"); + navbar.appendChild(fullscreenctls); + } + fullscreenctls.hidden = aShow; + + ToolbarIconColor.inferFromText(); + } +}; +XPCOMUtils.defineLazyGetter(FullScreen, "useLionFullScreen", function() { + // We'll only use OS X Lion full screen if we're + // * on OS X + // * on Lion or higher (Darwin 11+) + // * have fullscreenbutton="true" +#ifdef XP_MACOSX + return parseFloat(Services.sysinfo.getProperty("version")) >= 11 && + document.documentElement.getAttribute("fullscreenbutton") == "true"; +#else + return false; +#endif +}); |