michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: "use strict"; michael@0: michael@0: const { classes: Cc, interfaces: Ci, utils: Cu } = Components; michael@0: michael@0: this.EXPORTED_SYMBOLS = [ "switchToFloatingScrollbars", "switchToNativeScrollbars" ]; michael@0: michael@0: Cu.import("resource://gre/modules/Services.jsm"); michael@0: michael@0: let URL = Services.io.newURI("chrome://browser/skin/devtools/floating-scrollbars.css", null, null); michael@0: michael@0: let trackedTabs = new WeakMap(); michael@0: michael@0: /** michael@0: * Switch to floating scrollbars, à la mobile. michael@0: * michael@0: * @param aTab the targeted tab. michael@0: * michael@0: */ michael@0: this.switchToFloatingScrollbars = function switchToFloatingScrollbars(aTab) { michael@0: let mgr = trackedTabs.get(aTab); michael@0: if (!mgr) { michael@0: mgr = new ScrollbarManager(aTab); michael@0: } michael@0: mgr.switchToFloating(); michael@0: } michael@0: michael@0: /** michael@0: * Switch to original native scrollbars. michael@0: * michael@0: * @param aTab the targeted tab. michael@0: * michael@0: */ michael@0: this.switchToNativeScrollbars = function switchToNativeScrollbars(aTab) { michael@0: let mgr = trackedTabs.get(aTab); michael@0: if (mgr) { michael@0: mgr.reset(); michael@0: } michael@0: } michael@0: michael@0: function ScrollbarManager(aTab) { michael@0: trackedTabs.set(aTab, this); michael@0: michael@0: this.attachedTab = aTab; michael@0: this.attachedBrowser = aTab.linkedBrowser; michael@0: michael@0: this.reset = this.reset.bind(this); michael@0: this.switchToFloating = this.switchToFloating.bind(this); michael@0: michael@0: this.attachedTab.addEventListener("TabClose", this.reset, true); michael@0: this.attachedBrowser.addEventListener("DOMContentLoaded", this.switchToFloating, true); michael@0: } michael@0: michael@0: ScrollbarManager.prototype = { michael@0: get win() { michael@0: return this.attachedBrowser.contentWindow; michael@0: }, michael@0: michael@0: /* michael@0: * Change the look of the scrollbars. michael@0: */ michael@0: switchToFloating: function() { michael@0: let windows = this.getInnerWindows(this.win); michael@0: windows.forEach(this.injectStyleSheet); michael@0: this.forceStyle(); michael@0: }, michael@0: michael@0: michael@0: /* michael@0: * Reset the look of the scrollbars. michael@0: */ michael@0: reset: function() { michael@0: let windows = this.getInnerWindows(this.win); michael@0: windows.forEach(this.removeStyleSheet); michael@0: this.forceStyle(this.attachedBrowser); michael@0: this.attachedBrowser.removeEventListener("DOMContentLoaded", this.switchToFloating, true); michael@0: this.attachedTab.removeEventListener("TabClose", this.reset, true); michael@0: trackedTabs.delete(this.attachedTab); michael@0: }, michael@0: michael@0: /* michael@0: * Toggle the display property of the window to force the style to be applied. michael@0: */ michael@0: forceStyle: function() { michael@0: let parentWindow = this.attachedBrowser.ownerDocument.defaultView; michael@0: let display = parentWindow.getComputedStyle(this.attachedBrowser).display; // Save display value michael@0: this.attachedBrowser.style.display = "none"; michael@0: parentWindow.getComputedStyle(this.attachedBrowser).display; // Flush michael@0: this.attachedBrowser.style.display = display; // Restore michael@0: }, michael@0: michael@0: /* michael@0: * return all the window objects present in the hiearchy of a window. michael@0: */ michael@0: getInnerWindows: function(win) { michael@0: let iframes = win.document.querySelectorAll("iframe"); michael@0: let innerWindows = []; michael@0: for (let iframe of iframes) { michael@0: innerWindows = innerWindows.concat(this.getInnerWindows(iframe.contentWindow)); michael@0: } michael@0: return [win].concat(innerWindows); michael@0: }, michael@0: michael@0: /* michael@0: * Append the new scrollbar style. michael@0: */ michael@0: injectStyleSheet: function(win) { michael@0: let winUtils = win.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils); michael@0: try { michael@0: winUtils.loadSheet(URL, win.AGENT_SHEET); michael@0: }catch(e) {} michael@0: }, michael@0: michael@0: /* michael@0: * Remove the injected stylesheet. michael@0: */ michael@0: removeStyleSheet: function(win) { michael@0: let winUtils = win.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils); michael@0: try { michael@0: winUtils.removeSheet(URL, win.AGENT_SHEET); michael@0: }catch(e) {} michael@0: }, michael@0: }