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: Added 32x32 icon and fixed my own review comments Created Dec. 2, 2013, 10:55 a.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View unified diff | Download patch
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 = widget.onBuild(toolbox.ownerDocument);
68 if (typeof widget.onClick == "function")
69 node.addEventListener("click", widget.onClick, false);
70 if (typeof widget.onCommand == "function")
71 node.addEventListener("command", widget.onCommand, false);
72
73 // Insert into the palette first
74 toolbox.palette.insertBefore(node, toolbox.palette.firstChild);
75
76 // Now find out where we should put it
77 let position = toolbox.getAttribute(widget.positionAttribute);
78 if (!/^\S*,\S*,\S*$/.test(position))
79 position = null;
80
81 if (position == null)
82 {
83 // No explicitly saved position but maybe we can find it in a currentset
84 // attribute somewhere.
85 let toolbars = toolbox.externalToolbars.slice();
86 for (let child of toolbox.children)
87 if (child.localName == "toolbar")
88 toolbars.push(child);
89 for (let toolbar of toolbars)
90 {
91 let currentSet = toolbar.getAttribute("currentset");
92 if (currentSet)
93 {
94 let items = currentSet.split(",");
95 let index = items.indexOf(widget.id);
96 if (index >= 0)
97 {
98 let before = (index + 1 < items.length ? items[index + 1] : "");
99 position = "visible," + toolbar.id + "," + before;
100 toolbox.setAttribute(widget.positionAttribute, position);
101 toolbox.ownerDocument.persist(toolbox.id, widget.positionAttribute);
102 break;
103 }
104 }
105 }
106 }
107
108 showWidget(toolbox, widget, position);
109 }
110
111 function showWidget(/**Element*/ toolbox, /**Widget*/ widget, /**String*/ positi on)
112 {
113 let visible = "visible", parent = null, before = null;
114 if (position)
115 {
116 [visible, parent, before] = position.split(",", 3);
117 parent = toolbox.ownerDocument.getElementById(parent);
118 if (before == "")
119 before = null;
120 else
121 before = toolbox.ownerDocument.getElementById(before);
122 if (before && before.parentNode != parent)
123 before = null;
124 }
125
126 if (visible == "visible" && !parent)
127 {
128 let insertionPoint = {
129 parent: widget.defaultArea
130 };
131 if (typeof widget.defaultBefore != "undefined")
132 insertionPoint.before = widget.defaultBefore;
133 if (typeof widget.defaultAfter != "undefined")
134 insertionPoint.after = widget.defaultAfter;
135
136 [parent, before] = UI.resolveInsertionPoint(toolbox.ownerDocument.defaultVie w, insertionPoint);
137 }
138
139 if (parent && parent.localName != "toolbar")
140 parent = null;
141
142 if (visible != "visible")
143 {
144 // Move to palette if the item is currently visible
145 let node = toolbox.ownerDocument.getElementById(widget.id);
146 if (node)
147 toolbox.palette.appendChild(node);
148 }
149 else if (parent)
150 {
151 // Add the item to the toolbar
152 let items = parent.currentSet.split(",");
153 let index = (before ? items.indexOf(before.id) : -1);
154 if (index < 0)
155 before = null;
156 parent.insertItem(widget.id, before, null, false);
157 }
158
159 saveState(toolbox, widget);
160 }
161
162 function removeWidget(/**Window*/ window, /**Widget*/ widget)
163 {
164 let element = window.document.getElementById(widget.id);
165 if (element)
166 element.parentNode.removeChild(element);
167
168 let toolbox = getToolbox(window, widget);
169 if (toolbox)
170 {
171 let paletteItem = getPaletteItem(toolbox, widget.id);
172 if (paletteItem)
173 paletteItem.parentNode.removeChild(paletteItem);
174 }
175 }
176
177 function onToolbarCustomization(/**Event*/ event)
178 {
179 let toolbox = event.currentTarget;
180 for (let [id, widget] of widgets)
181 saveState(toolbox, widget);
182 }
183
184 function saveState(/**Element*/ toolbox, /**Widget*/ widget)
185 {
186 let node = toolbox.ownerDocument.getElementById(widget.id);
187
188 let position = toolbox.getAttribute(widget.positionAttribute) || "hidden,,";
189 if (node)
190 {
191 if (typeof widget.onAdded == "function")
192 widget.onAdded(node)
193
194 let toolbar = getToolbar(node);
195 position = "visible," + toolbar.id + "," + (node.nextSibling ? node.nextSibl ing.id : "");
196 }
197 else
198 position = position.replace(/^visible,/, "hidden,")
199
200 toolbox.setAttribute(widget.positionAttribute, position);
201 toolbox.ownerDocument.persist(toolbox.id, widget.positionAttribute);
202 }
203
204 let CustomizableUI = exports.CustomizableUI =
205 {
206 createWidget: function(widget)
207 {
208 if (typeof widget.id == "undefined" ||
209 typeof widget.defaultArea == "undefined" ||
210 typeof widget.positionAttribute == "undefined")
211 {
212 throw new Error("Unexpected: required property missing from the widget dat a");
213 }
214 widgets.set(widget.id, widget);
215
216 // Show widget in any existing windows
217 for (let window of UI.applicationWindows)
218 {
219 let toolbox = getToolbox(window, widget);
220 if (toolbox)
221 {
222 toolbox.addEventListener("aftercustomization", onToolbarCustomization, f alse);
223 restoreWidget(toolbox, widget);
224 }
225 }
226 },
227
228 destroyWidget: function(id)
229 {
230 // Don't do anything here. This function is called on shutdown,
231 // removeFromWindow will take care of cleaning up already.
232 },
233
234 getPlacementOfWidget: function(id)
235 {
236 let window = UI.currentWindow;
237 if (!window)
238 return null;
239
240 let widget = window.document.getElementById(id);
241 if (!widget)
242 return null;
243
244 let toolbar = getToolbar(widget);
245 if (!toolbar)
246 return null;
247
248 return {area: toolbar.id};
249 },
250
251 addWidgetToArea: function(id)
252 {
253 // Note: the official API function also has area and position parameters.
254 // We ignore those here and simply restore the previous position instead.
255 let widget = widgets.get(id);
256 for (let window of UI.applicationWindows)
257 {
258 let toolbox = getToolbox(window, widget);
259 if (!toolbox)
260 continue;
261
262 let position = toolbox.getAttribute(widget.positionAttribute);
263 if (position)
264 position = position.replace(/^hidden,/, "visible,");
265 showWidget(toolbox, widget, position);
266 }
267 },
268
269 removeWidgetFromArea: function(id)
270 {
271 let widget = widgets.get(id);
272 for (let window of UI.applicationWindows)
273 {
274 let toolbox = getToolbox(window, widget);
275 if (!toolbox)
276 continue;
277
278 let position = toolbox.getAttribute(widget.positionAttribute);
279 if (position)
280 position = position.replace(/^visible,/, "hidden,");
281 else
282 position = "hidden,,";
283 showWidget(toolbox, widget, position);
284 }
285 }
286 };
287
288 let {WindowObserver} = require("windowObserver");
289 new WindowObserver({
290 applyToWindow: function(window)
291 {
292 let {isKnownWindow} = require("appSupport");
293 if (!isKnownWindow(window))
294 return;
295
296 for (let [id, widget] of widgets)
297 {
298 let toolbox = getToolbox(window, widget);
299 if (toolbox)
300 {
301 toolbox.addEventListener("aftercustomization", onToolbarCustomization, f alse);
302
303 // Restore widget asynchronously to allow the stylesheet to load
304 Utils.runAsync(restoreWidget.bind(null, toolbox, widget));
305 }
306 }
307 },
308
309 removeFromWindow: function(window)
310 {
311 let {isKnownWindow} = require("appSupport");
312 if (!isKnownWindow(window))
313 return;
314
315 for (let [id, widget] of widgets)
316 {
317 let toolbox = getToolbox(window, widget);
318 if (toolbox)
319 toolbox.removeEventListener("aftercustomization", onToolbarCustomization , false);
320
321 removeWidget(window, widget);
322 }
323 }
324 });
OLDNEW

Powered by Google App Engine
This is Rietveld