|
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/. */ |
|
4 |
|
5 "use strict"; |
|
6 |
|
7 const { classes: Cc, interfaces: Ci, utils: Cu } = Components; |
|
8 |
|
9 this.EXPORTED_SYMBOLS = [ "switchToFloatingScrollbars", "switchToNativeScrollbars" ]; |
|
10 |
|
11 Cu.import("resource://gre/modules/Services.jsm"); |
|
12 |
|
13 let URL = Services.io.newURI("chrome://browser/skin/devtools/floating-scrollbars.css", null, null); |
|
14 |
|
15 let trackedTabs = new WeakMap(); |
|
16 |
|
17 /** |
|
18 * Switch to floating scrollbars, à la mobile. |
|
19 * |
|
20 * @param aTab the targeted tab. |
|
21 * |
|
22 */ |
|
23 this.switchToFloatingScrollbars = function switchToFloatingScrollbars(aTab) { |
|
24 let mgr = trackedTabs.get(aTab); |
|
25 if (!mgr) { |
|
26 mgr = new ScrollbarManager(aTab); |
|
27 } |
|
28 mgr.switchToFloating(); |
|
29 } |
|
30 |
|
31 /** |
|
32 * Switch to original native scrollbars. |
|
33 * |
|
34 * @param aTab the targeted tab. |
|
35 * |
|
36 */ |
|
37 this.switchToNativeScrollbars = function switchToNativeScrollbars(aTab) { |
|
38 let mgr = trackedTabs.get(aTab); |
|
39 if (mgr) { |
|
40 mgr.reset(); |
|
41 } |
|
42 } |
|
43 |
|
44 function ScrollbarManager(aTab) { |
|
45 trackedTabs.set(aTab, this); |
|
46 |
|
47 this.attachedTab = aTab; |
|
48 this.attachedBrowser = aTab.linkedBrowser; |
|
49 |
|
50 this.reset = this.reset.bind(this); |
|
51 this.switchToFloating = this.switchToFloating.bind(this); |
|
52 |
|
53 this.attachedTab.addEventListener("TabClose", this.reset, true); |
|
54 this.attachedBrowser.addEventListener("DOMContentLoaded", this.switchToFloating, true); |
|
55 } |
|
56 |
|
57 ScrollbarManager.prototype = { |
|
58 get win() { |
|
59 return this.attachedBrowser.contentWindow; |
|
60 }, |
|
61 |
|
62 /* |
|
63 * Change the look of the scrollbars. |
|
64 */ |
|
65 switchToFloating: function() { |
|
66 let windows = this.getInnerWindows(this.win); |
|
67 windows.forEach(this.injectStyleSheet); |
|
68 this.forceStyle(); |
|
69 }, |
|
70 |
|
71 |
|
72 /* |
|
73 * Reset the look of the scrollbars. |
|
74 */ |
|
75 reset: function() { |
|
76 let windows = this.getInnerWindows(this.win); |
|
77 windows.forEach(this.removeStyleSheet); |
|
78 this.forceStyle(this.attachedBrowser); |
|
79 this.attachedBrowser.removeEventListener("DOMContentLoaded", this.switchToFloating, true); |
|
80 this.attachedTab.removeEventListener("TabClose", this.reset, true); |
|
81 trackedTabs.delete(this.attachedTab); |
|
82 }, |
|
83 |
|
84 /* |
|
85 * Toggle the display property of the window to force the style to be applied. |
|
86 */ |
|
87 forceStyle: function() { |
|
88 let parentWindow = this.attachedBrowser.ownerDocument.defaultView; |
|
89 let display = parentWindow.getComputedStyle(this.attachedBrowser).display; // Save display value |
|
90 this.attachedBrowser.style.display = "none"; |
|
91 parentWindow.getComputedStyle(this.attachedBrowser).display; // Flush |
|
92 this.attachedBrowser.style.display = display; // Restore |
|
93 }, |
|
94 |
|
95 /* |
|
96 * return all the window objects present in the hiearchy of a window. |
|
97 */ |
|
98 getInnerWindows: function(win) { |
|
99 let iframes = win.document.querySelectorAll("iframe"); |
|
100 let innerWindows = []; |
|
101 for (let iframe of iframes) { |
|
102 innerWindows = innerWindows.concat(this.getInnerWindows(iframe.contentWindow)); |
|
103 } |
|
104 return [win].concat(innerWindows); |
|
105 }, |
|
106 |
|
107 /* |
|
108 * Append the new scrollbar style. |
|
109 */ |
|
110 injectStyleSheet: function(win) { |
|
111 let winUtils = win.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils); |
|
112 try { |
|
113 winUtils.loadSheet(URL, win.AGENT_SHEET); |
|
114 }catch(e) {} |
|
115 }, |
|
116 |
|
117 /* |
|
118 * Remove the injected stylesheet. |
|
119 */ |
|
120 removeStyleSheet: function(win) { |
|
121 let winUtils = win.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils); |
|
122 try { |
|
123 winUtils.removeSheet(URL, win.AGENT_SHEET); |
|
124 }catch(e) {} |
|
125 }, |
|
126 } |