Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code

Side by Side Diff: lib/customizableUI.js

Issue 5741004535627776: Fix toolbar icon customization in Australis (Closed)
Patch Set: Got rid of repeated require() calls Created Nov. 22, 2013, 5:15 p.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View unified diff | Download patch
« no previous file with comments | « lib/appSupport.js ('k') | lib/ui.js » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 /*
2 * This file is part of Adblock Plus <http://adblockplus.org/>,
3 * Copyright (C) 2006-2013 Eyeo GmbH
4 *
5 * Adblock Plus is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 3 as
7 * published by the Free Software Foundation.
8 *
9 * Adblock Plus is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 /**
19 * @fileOverview This emulates a subset of the CustomizableUI API from Firefox 2 8.
20 */
21
22 let {XPCOMUtils} = Cu.import("resource://gre/modules/XPCOMUtils.jsm", null);
23
24 let {Utils} = require("utils");
25
26 // UI module has to be referenced lazily to avoid circular references
27 XPCOMUtils.defineLazyGetter(this, "UI", function() require("ui").UI);
28
29 let widgets = Map();
30
31 function getToolbox(/**Window*/ window, /**Widget*/ widget) /**Element*/
32 {
33 if (!("defaultArea" in widget) || !widget.defaultArea)
34 return null;
35
36 let toolbar = UI.findElement(window, widget.defaultArea);
37 if (!toolbar)
38 return null;
39
40 let toolbox = toolbar.toolbox;
41 if (toolbox && ("palette" in toolbox) && toolbox.palette)
42 return toolbox;
43 else
44 return null;
45 }
46
47 function getToolbar(/**Element*/ element) /**Element*/
48 {
49 for (let parent = element.parentNode; parent; parent = parent.parentNode)
50 if (parent.localName == "toolbar")
51 return parent;
52 return null;
53 }
54
55 function getPaletteItem(/**Element*/ toolbox, /**String*/ id) /**Element*/
56 {
57 for (let child of toolbox.palette.children)
58 if (child.id == id)
59 return child;
60
61 return null;
62 }
63
64 function restoreWidget(/**Element*/ toolbox, /**Widget*/ widget)
65 {
66 // Create node
67 let node = toolbox.ownerDocument.createElement("toolbarbutton");
68 node.setAttribute("id", widget.id);
69 if (typeof widget.onClick == "function")
70 node.addEventListener("click", widget.onClick, false);
71 if (typeof widget.onCommand == "function")
72 node.addEventListener("command", widget.onCommand, false);
73 if (typeof widget.onCreated == "function")
74 widget.onCreated(node);
75
76 // Insert into the palette first
77 toolbox.palette.insertBefore(node, toolbox.palette.firstChild);
78
79 // Now find out where we should put it
80 let position = toolbox.getAttribute(widget.positionAttribute);
81 if (!/^\S*,\S*,\S*$/.test(position))
82 position = null;
83
84 if (position == null)
85 {
86 // No explicitly saved position but maybe we can find it in a currentset
87 // attribute somewhere.
88 let toolbars = toolbox.externalToolbars.slice();
89 for (let child of toolbox.children)
90 if (child.localName == "toolbar")
91 toolbars.push(child);
92 for (let toolbar of toolbars)
93 {
94 let currentSet = toolbar.getAttribute("currentset");
95 if (currentSet)
96 {
97 let items = currentSet.split(",");
98 let index = items.indexOf(widget.id);
99 if (index >= 0)
100 {
101 let before = (index + 1 < items.length ? items[index + 1] : "");
102 position = "visible," + toolbar.id + "," + before;
103 toolbox.setAttribute(widget.positionAttribute, position);
104 toolbox.ownerDocument.persist(toolbox.id, widget.positionAttribute);
105 break;
106 }
107 }
108 }
109 }
110
111 showWidget(toolbox, widget, position);
112 }
113
114 function showWidget(/**Element*/ toolbox, /**Widget*/ widget, /**String*/ positi on)
115 {
116 let visible = "visible", parent = null, before = null;
117 if (position)
118 {
119 [visible, parent, before] = position.split(",", 3);
120 parent = toolbox.ownerDocument.getElementById(parent);
121 if (before == "")
122 before = null;
123 else
124 before = toolbox.ownerDocument.getElementById(before);
125 if (before && before.parentNode != parent)
126 before = null;
127 }
128
129 if (visible == "visible" && !parent)
130 {
131 let insertionPoint = {
132 parent: widget.defaultArea
133 };
134 if (typeof widget.defaultBefore != "undefined")
135 insertionPoint.before = widget.defaultBefore;
136 if (typeof widget.defaultAfter != "undefined")
137 insertionPoint.after = widget.defaultAfter;
138
139 [parent, before] = UI.resolveInsertionPoint(toolbox.ownerDocument.defaultVie w, insertionPoint);
140 }
141
142 if (parent && parent.localName != "toolbar")
143 parent = null;
144
145 if (visible != "visible")
146 {
147 // Move to palette if the item is currently visible
148 let node = toolbox.ownerDocument.getElementById(widget.id);
149 if (node)
150 toolbox.palette.appendChild(node);
151 }
152 else if (parent)
153 {
154 // Add the item to the toolbar
155 let items = parent.currentSet.split(",");
156 let index = (before ? items.indexOf(before.id) : -1);
157 if (index < 0)
158 before = null;
159 parent.insertItem(widget.id, before, null, false);
160 }
161
162 saveState(toolbox, widget);
163 }
164
165 function removeWidget(/**Window*/ window, /**Widget*/ widget)
166 {
167 let element = window.document.getElementById(widget.id);
168 if (element)
169 element.parentNode.removeChild(element);
170
171 let toolbox = getToolbox(window, widget);
172 if (toolbox)
173 {
174 let paletteItem = getPaletteItem(toolbox, widget.id);
175 if (paletteItem)
176 paletteItem.parentNode.removeChild(paletteItem);
177 }
178 }
179
180 function onToolbarCustomization(/**Event*/ event)
181 {
182 let toolbox = event.currentTarget;
183 for (let [id, widget] of widgets)
184 saveState(toolbox, widget);
185 }
186
187 function saveState(/**Element*/ toolbox, /**Widget*/ widget)
188 {
189 let node = toolbox.ownerDocument.getElementById(widget.id);
190
191 let position = toolbox.getAttribute(widget.positionAttribute) || "hidden,,";
192 if (node)
193 {
194 if (typeof widget.onCreated == "function")
195 widget.onCreated(node);
196
197 let toolbar = getToolbar(node);
198 position = "visible," + toolbar.id + "," + (node.nextSibling ? node.nextSibl ing.id : "");
199 }
200 else
201 position = position.replace(/^visible,/, "hidden,")
202
203 toolbox.setAttribute(widget.positionAttribute, position);
204 toolbox.ownerDocument.persist(toolbox.id, widget.positionAttribute);
205 }
206
207 let CustomizableUI = exports.CustomizableUI =
208 {
209 createWidget: function(widget)
210 {
211 if (typeof widget.id == "undefined" ||
212 typeof widget.defaultArea == "undefined" ||
213 typeof widget.positionAttribute == "undefined")
214 {
215 throw new Error("Unexpected: required property missing from the widget dat a");
216 }
217 widgets.set(widget.id, widget);
218
219 // Show widget in any existing windows
220 for (let window of UI.applicationWindows)
221 {
222 let toolbox = getToolbox(window, widget);
223 if (toolbox)
224 {
225 toolbox.addEventListener("aftercustomization", onToolbarCustomization, f alse);
226 restoreWidget(toolbox, widget);
227 }
228 }
229 },
230
231 destroyWidget: function(id)
232 {
233 // Don't do anything here. This function is called on shutdown,
234 // removeFromWindow will take care of cleaning up already.
235 },
236
237 getPlacementOfWidget: function(id)
238 {
239 let window = UI.currentWindow;
240 if (!window)
241 return null;
242
243 let widget = window.document.getElementById(id);
244 if (!widget)
245 return null;
246
247 let toolbar = getToolbar(widget);
248 if (!toolbar)
249 return null;
250
251 let items = toolbar.currentSet.split(",");
252 let index = items.indexOf(id);
253 if (index < 0)
254 return null;
255 else
256 return {area: toolbar.id, placement: index};
257 },
258
259 addWidgetToArea: function(id, area, position)
260 {
261 let widget = widgets.get(id);
262 for (let window of UI.applicationWindows)
263 {
264 let toolbox = getToolbox(window, widget);
265 if (!toolbox)
266 continue;
267
268 let position = toolbox.getAttribute(widget.positionAttribute);
269 if (position)
270 position = position.replace(/^hidden,/, "visible,");
271 showWidget(toolbox, widget, position);
272 }
273 },
274
275 removeWidgetFromArea: function(id)
276 {
277 let widget = widgets.get(id);
278 for (let window of UI.applicationWindows)
279 {
280 let toolbox = getToolbox(window, widget);
281 if (!toolbox)
282 continue;
283
284 let position = toolbox.getAttribute(widget.positionAttribute);
285 if (position)
286 position = position.replace(/^visible,/, "hidden,");
287 else
288 position = "hidden,,";
289 showWidget(toolbox, widget, position);
290 }
291 }
292 };
293
294 let {WindowObserver} = require("windowObserver");
295 new WindowObserver({
296 applyToWindow: function(window)
297 {
298 let {isKnownWindow} = require("appSupport");
299 if (!isKnownWindow(window))
300 return;
301
302 for (let [id, widget] of widgets)
303 {
304 let toolbox = getToolbox(window, widget);
305 if (toolbox)
306 {
307 toolbox.addEventListener("aftercustomization", onToolbarCustomization, f alse);
308
309 // Restore widget asynchronously to allow the stylesheet to load
310 Utils.runAsync(restoreWidget.bind(null, toolbox, widget));
311 }
312 }
313 },
314
315 removeFromWindow: function(window)
316 {
317 let {isKnownWindow} = require("appSupport");
318 if (!isKnownWindow(window))
319 return;
320
321 for (let [id, widget] of widgets)
322 {
323 let toolbox = getToolbox(window, widget);
324 if (toolbox)
325 toolbox.removeEventListener("aftercustomization", onToolbarCustomization , false);
326
327 removeWidget(window, widget);
328 }
329 }
330 });
OLDNEW
« no previous file with comments | « lib/appSupport.js ('k') | lib/ui.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld