Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
1 /* -*- Mode: Javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ft=javascript ts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 const {Cu} = require("chrome");
9 Cu.import("resource://gre/modules/Services.jsm");
11 var {Promise: promise} = require("resource://gre/modules/Promise.jsm");
12 var EventEmitter = require("devtools/toolkit/event-emitter");
13 var Telemetry = require("devtools/shared/telemetry");
15 const XULNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
17 /**
18 * ToolSidebar provides methods to register tabs in the sidebar.
19 * It's assumed that the sidebar contains a xul:tabbox.
20 *
21 * @param {Node} tabbox
22 * <tabbox> node;
23 * @param {ToolPanel} panel
24 * Related ToolPanel instance;
25 * @param {String} uid
26 * Unique ID
27 * @param {Boolean} showTabstripe
28 * Show the tabs.
29 */
30 function ToolSidebar(tabbox, panel, uid, showTabstripe=true)
31 {
32 EventEmitter.decorate(this);
34 this._tabbox = tabbox;
35 this._uid = uid;
36 this._panelDoc = this._tabbox.ownerDocument;
37 this._toolPanel = panel;
39 try {
40 this._width = Services.prefs.getIntPref("devtools.toolsidebar-width." + this._uid);
41 } catch(e) {}
43 this._telemetry = new Telemetry();
45 this._tabbox.tabpanels.addEventListener("select", this, true);
47 this._tabs = new Map();
49 if (!showTabstripe) {
50 this._tabbox.setAttribute("hidetabs", "true");
51 }
52 }
54 exports.ToolSidebar = ToolSidebar;
56 ToolSidebar.prototype = {
57 /**
58 * Register a tab. A tab is a document.
59 * The document must have a title, which will be used as the name of the tab.
60 *
61 * @param {string} tab uniq id
62 * @param {string} url
63 */
64 addTab: function ToolSidebar_addTab(id, url, selected=false) {
65 let iframe = this._panelDoc.createElementNS(XULNS, "iframe");
66 iframe.className = "iframe-" + id;
67 iframe.setAttribute("flex", "1");
68 iframe.setAttribute("src", url);
69 iframe.tooltip = "aHTMLTooltip";
71 let tab = this._tabbox.tabs.appendItem();
72 tab.setAttribute("label", ""); // Avoid showing "undefined" while the tab is loading
74 let onIFrameLoaded = function() {
75 tab.setAttribute("label", iframe.contentDocument.title);
76 iframe.removeEventListener("load", onIFrameLoaded, true);
77 if ("setPanel" in iframe.contentWindow) {
78 iframe.contentWindow.setPanel(this._toolPanel, iframe);
79 }
80 this.emit(id + "-ready");
81 }.bind(this);
83 iframe.addEventListener("load", onIFrameLoaded, true);
85 let tabpanel = this._panelDoc.createElementNS(XULNS, "tabpanel");
86 tabpanel.setAttribute("id", "sidebar-panel-" + id);
87 tabpanel.appendChild(iframe);
88 this._tabbox.tabpanels.appendChild(tabpanel);
90 this._tooltip = this._panelDoc.createElementNS(XULNS, "tooltip");
91 this._tooltip.id = "aHTMLTooltip";
92 tabpanel.appendChild(this._tooltip);
93 this._tooltip.page = true;
95 tab.linkedPanel = "sidebar-panel-" + id;
97 // We store the index of this tab.
98 this._tabs.set(id, tab);
100 if (selected) {
101 // For some reason I don't understand, if we call this.select in this
102 // event loop (after inserting the tab), the tab will never get the
103 // the "selected" attribute set to true.
104 this._panelDoc.defaultView.setTimeout(function() {
105 this.select(id);
106 }.bind(this), 10);
107 }
109 this.emit("new-tab-registered", id);
110 },
112 /**
113 * Select a specific tab.
114 */
115 select: function ToolSidebar_select(id) {
116 let tab = this._tabs.get(id);
117 if (tab) {
118 this._tabbox.selectedTab = tab;
119 }
120 },
122 /**
123 * Return the id of the selected tab.
124 */
125 getCurrentTabID: function ToolSidebar_getCurrentTabID() {
126 let currentID = null;
127 for (let [id, tab] of this._tabs) {
128 if (this._tabbox.tabs.selectedItem == tab) {
129 currentID = id;
130 break;
131 }
132 }
133 return currentID;
134 },
136 /**
137 * Returns the requested tab based on the id.
138 *
139 * @param String id
140 * unique id of the requested tab.
141 */
142 getTab: function ToolSidebar_getTab(id) {
143 return this._tabbox.tabpanels.querySelector("#sidebar-panel-" + id);
144 },
146 /**
147 * Event handler.
148 */
149 handleEvent: function ToolSidebar_eventHandler(event) {
150 if (event.type == "select") {
151 if (this._currentTool == this.getCurrentTabID()) {
152 // Tool hasn't changed.
153 return;
154 }
156 let previousTool = this._currentTool;
157 this._currentTool = this.getCurrentTabID();
158 if (previousTool) {
159 this._telemetry.toolClosed(previousTool);
160 this.emit(previousTool + "-unselected");
161 }
163 this._telemetry.toolOpened(this._currentTool);
164 this.emit(this._currentTool + "-selected");
165 this.emit("select", this._currentTool);
166 }
167 },
169 /**
170 * Toggle sidebar's visibility state.
171 */
172 toggle: function ToolSidebar_toggle() {
173 if (this._tabbox.hasAttribute("hidden")) {
174 this.show();
175 } else {
176 this.hide();
177 }
178 },
180 /**
181 * Show the sidebar.
182 */
183 show: function ToolSidebar_show() {
184 if (this._width) {
185 this._tabbox.width = this._width;
186 }
187 this._tabbox.removeAttribute("hidden");
188 },
190 /**
191 * Show the sidebar.
192 */
193 hide: function ToolSidebar_hide() {
194 Services.prefs.setIntPref("devtools.toolsidebar-width." + this._uid, this._tabbox.width);
195 this._tabbox.setAttribute("hidden", "true");
196 },
198 /**
199 * Return the window containing the tab content.
200 */
201 getWindowForTab: function ToolSidebar_getWindowForTab(id) {
202 if (!this._tabs.has(id)) {
203 return null;
204 }
206 let panel = this._panelDoc.getElementById(this._tabs.get(id).linkedPanel);
207 return panel.firstChild.contentWindow;
208 },
210 /**
211 * Clean-up.
212 */
213 destroy: function ToolSidebar_destroy() {
214 if (this._destroyed) {
215 return promise.resolve(null);
216 }
217 this._destroyed = true;
219 Services.prefs.setIntPref("devtools.toolsidebar-width." + this._uid, this._tabbox.width);
221 this._tabbox.tabpanels.removeEventListener("select", this, true);
223 while (this._tabbox.tabpanels.hasChildNodes()) {
224 this._tabbox.tabpanels.removeChild(this._tabbox.tabpanels.firstChild);
225 }
227 while (this._tabbox.tabs.hasChildNodes()) {
228 this._tabbox.tabs.removeChild(this._tabbox.tabs.firstChild);
229 }
231 if (this._currentTool) {
232 this._telemetry.toolClosed(this._currentTool);
233 }
235 this._tabs = null;
236 this._tabbox = null;
237 this._panelDoc = null;
238 this._toolPanel = null;
240 return promise.resolve(null);
241 },
242 }