|
1 <?xml version="1.0"?> |
|
2 <!-- This Source Code Form is subject to the terms of the Mozilla Public |
|
3 - License, v. 2.0. If a copy of the MPL was not distributed with this |
|
4 - file, You can obtain one at http://mozilla.org/MPL/2.0/. --> |
|
5 |
|
6 <bindings id="browserToolbarBindings" |
|
7 xmlns="http://www.mozilla.org/xbl" |
|
8 xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" |
|
9 xmlns:xbl="http://www.mozilla.org/xbl"> |
|
10 |
|
11 <binding id="toolbar" role="xul:toolbar"> |
|
12 <resources> |
|
13 <stylesheet src="chrome://global/skin/toolbar.css"/> |
|
14 </resources> |
|
15 <implementation> |
|
16 <field name="overflowedDuringConstruction">null</field> |
|
17 |
|
18 <constructor><![CDATA[ |
|
19 let scope = {}; |
|
20 Cu.import("resource:///modules/CustomizableUI.jsm", scope); |
|
21 // Add an early overflow event listener that will mark if the |
|
22 // toolbar overflowed during construction. |
|
23 if (scope.CustomizableUI.isAreaOverflowable(this.id)) { |
|
24 this.addEventListener("overflow", this); |
|
25 this.addEventListener("underflow", this); |
|
26 } |
|
27 |
|
28 if (document.readyState == "complete") { |
|
29 this._init(); |
|
30 } else { |
|
31 // Need to wait until XUL overlays are loaded. See bug 554279. |
|
32 let self = this; |
|
33 document.addEventListener("readystatechange", function onReadyStateChange() { |
|
34 if (document.readyState != "complete") |
|
35 return; |
|
36 document.removeEventListener("readystatechange", onReadyStateChange, false); |
|
37 self._init(); |
|
38 }, false); |
|
39 } |
|
40 ]]></constructor> |
|
41 |
|
42 <method name="_init"> |
|
43 <body><![CDATA[ |
|
44 let scope = {}; |
|
45 Cu.import("resource:///modules/CustomizableUI.jsm", scope); |
|
46 let CustomizableUI = scope.CustomizableUI; |
|
47 |
|
48 // Bug 989289: Forcibly set the now unsupported "mode" and "iconsize" |
|
49 // attributes, just in case they accidentally get restored from |
|
50 // persistence from a user that's been upgrading and downgrading. |
|
51 if (CustomizableUI.isBuiltinToolbar(this.id)) { |
|
52 const kAttributes = new Map([["mode", "icons"], ["iconsize", "small"]]); |
|
53 for (let [attribute, value] of kAttributes) { |
|
54 if (this.getAttribute(attribute) != value) { |
|
55 this.setAttribute(attribute, value); |
|
56 document.persist(this.id, attribute); |
|
57 } |
|
58 if (this.toolbox) { |
|
59 if (this.toolbox.getAttribute(attribute) != value) { |
|
60 this.toolbox.setAttribute(attribute, value); |
|
61 document.persist(this.toolbox.id, attribute); |
|
62 } |
|
63 } |
|
64 } |
|
65 } |
|
66 |
|
67 // Searching for the toolbox palette in the toolbar binding because |
|
68 // toolbars are constructed first. |
|
69 let toolbox = this.toolbox; |
|
70 if (toolbox && !toolbox.palette) { |
|
71 for (let node of toolbox.children) { |
|
72 if (node.localName == "toolbarpalette") { |
|
73 // Hold on to the palette but remove it from the document. |
|
74 toolbox.palette = node; |
|
75 toolbox.removeChild(node); |
|
76 break; |
|
77 } |
|
78 } |
|
79 } |
|
80 |
|
81 // pass the current set of children for comparison with placements: |
|
82 let children = [node.id for (node of this.childNodes) |
|
83 if (node.getAttribute("skipintoolbarset") != "true" && node.id)]; |
|
84 CustomizableUI.registerToolbarNode(this, children); |
|
85 ]]></body> |
|
86 </method> |
|
87 |
|
88 <method name="handleEvent"> |
|
89 <parameter name="aEvent"/> |
|
90 <body><![CDATA[ |
|
91 if (aEvent.type == "overflow" && aEvent.detail > 0) { |
|
92 if (this.overflowable && this.overflowable.initialized) { |
|
93 this.overflowable.onOverflow(aEvent); |
|
94 } else { |
|
95 this.overflowedDuringConstruction = aEvent; |
|
96 } |
|
97 } else if (aEvent.type == "underflow" && aEvent.detail > 0) { |
|
98 this.overflowedDuringConstruction = null; |
|
99 } |
|
100 ]]></body> |
|
101 </method> |
|
102 |
|
103 <method name="insertItem"> |
|
104 <parameter name="aId"/> |
|
105 <parameter name="aBeforeElt"/> |
|
106 <parameter name="aWrapper"/> |
|
107 <body><![CDATA[ |
|
108 if (aWrapper) { |
|
109 Cu.reportError("Can't insert " + aId + ": using insertItem " + |
|
110 "no longer supports wrapper elements."); |
|
111 return null; |
|
112 } |
|
113 |
|
114 // Hack, the customizable UI code makes this be the last position |
|
115 let pos = null; |
|
116 if (aBeforeElt) { |
|
117 let beforeInfo = CustomizableUI.getPlacementOfWidget(aBeforeElt.id); |
|
118 if (beforeInfo.area != this.id) { |
|
119 Cu.reportError("Can't insert " + aId + " before " + |
|
120 aBeforeElt.id + " which isn't in this area (" + |
|
121 this.id + ")."); |
|
122 return null; |
|
123 } |
|
124 pos = beforeInfo.position; |
|
125 } |
|
126 |
|
127 CustomizableUI.addWidgetToArea(aId, this.id, pos); |
|
128 return this.ownerDocument.getElementById(aId); |
|
129 ]]></body> |
|
130 </method> |
|
131 |
|
132 <property name="toolbarName" |
|
133 onget="return this.getAttribute('toolbarname');" |
|
134 onset="this.setAttribute('toolbarname', val); return val;"/> |
|
135 |
|
136 <property name="customizationTarget" readonly="true"> |
|
137 <getter><![CDATA[ |
|
138 if (this._customizationTarget) |
|
139 return this._customizationTarget; |
|
140 |
|
141 let id = this.getAttribute("customizationtarget"); |
|
142 if (id) |
|
143 this._customizationTarget = document.getElementById(id); |
|
144 |
|
145 if (this._customizationTarget) |
|
146 this._customizationTarget.insertItem = this.insertItem.bind(this); |
|
147 else |
|
148 this._customizationTarget = this; |
|
149 |
|
150 return this._customizationTarget; |
|
151 ]]></getter> |
|
152 </property> |
|
153 |
|
154 <property name="toolbox" readonly="true"> |
|
155 <getter><![CDATA[ |
|
156 if (this._toolbox) |
|
157 return this._toolbox; |
|
158 |
|
159 let toolboxId = this.getAttribute("toolboxid"); |
|
160 if (toolboxId) { |
|
161 let toolbox = document.getElementById(toolboxId); |
|
162 if (toolbox) { |
|
163 if (toolbox.externalToolbars.indexOf(this) == -1) |
|
164 toolbox.externalToolbars.push(this); |
|
165 |
|
166 this._toolbox = toolbox; |
|
167 } |
|
168 } |
|
169 |
|
170 if (!this._toolbox && this.parentNode && |
|
171 this.parentNode.localName == "toolbox") { |
|
172 this._toolbox = this.parentNode; |
|
173 } |
|
174 |
|
175 return this._toolbox; |
|
176 ]]></getter> |
|
177 </property> |
|
178 |
|
179 <property name="currentSet"> |
|
180 <getter><![CDATA[ |
|
181 let currentWidgets = new Set(); |
|
182 for (let node of this.customizationTarget.children) { |
|
183 let realNode = node.localName == "toolbarpaletteitem" ? node.firstChild : node; |
|
184 if (realNode.getAttribute("skipintoolbarset") != "true") { |
|
185 currentWidgets.add(realNode.id); |
|
186 } |
|
187 } |
|
188 if (this.getAttribute("overflowing") == "true") { |
|
189 let overflowTarget = this.getAttribute("overflowtarget"); |
|
190 let overflowList = this.ownerDocument.getElementById(overflowTarget); |
|
191 for (let node of overflowList.children) { |
|
192 let realNode = node.localName == "toolbarpaletteitem" ? node.firstChild : node; |
|
193 if (realNode.getAttribute("skipintoolbarset") != "true") { |
|
194 currentWidgets.add(realNode.id); |
|
195 } |
|
196 } |
|
197 } |
|
198 let orderedPlacements = CustomizableUI.getWidgetIdsInArea(this.id); |
|
199 return orderedPlacements.filter((x) => currentWidgets.has(x)).join(','); |
|
200 ]]></getter> |
|
201 <setter><![CDATA[ |
|
202 // Get list of new and old ids: |
|
203 let newVal = (val || '').split(',').filter(x => x); |
|
204 let oldIds = CustomizableUI.getWidgetIdsInArea(this.id); |
|
205 |
|
206 // Get a list of items only in the new list |
|
207 let newIds = [id for (id of newVal) if (oldIds.indexOf(id) == -1)]; |
|
208 CustomizableUI.beginBatchUpdate(); |
|
209 try { |
|
210 for (let newId of newIds) { |
|
211 oldIds = CustomizableUI.getWidgetIdsInArea(this.id); |
|
212 let nextId = newId; |
|
213 let pos; |
|
214 do { |
|
215 // Get the next item |
|
216 nextId = newVal[newVal.indexOf(nextId) + 1]; |
|
217 // Figure out where it is in the old list |
|
218 pos = oldIds.indexOf(nextId); |
|
219 // If it's not in the old list, repeat: |
|
220 } while (pos == -1 && nextId); |
|
221 if (pos == -1) { |
|
222 pos = null; // We didn't find anything, insert at the end |
|
223 } |
|
224 CustomizableUI.addWidgetToArea(newId, this.id, pos); |
|
225 } |
|
226 |
|
227 let currentIds = this.currentSet.split(','); |
|
228 let removedIds = [id for (id of currentIds) if (newIds.indexOf(id) == -1 && newVal.indexOf(id) == -1)]; |
|
229 for (let removedId of removedIds) { |
|
230 CustomizableUI.removeWidgetFromArea(removedId); |
|
231 } |
|
232 } finally { |
|
233 CustomizableUI.endBatchUpdate(); |
|
234 } |
|
235 ]]></setter> |
|
236 </property> |
|
237 |
|
238 |
|
239 </implementation> |
|
240 </binding> |
|
241 |
|
242 <binding id="toolbar-menubar-stub"> |
|
243 <implementation> |
|
244 <property name="toolbox" readonly="true"> |
|
245 <getter><![CDATA[ |
|
246 if (this._toolbox) |
|
247 return this._toolbox; |
|
248 |
|
249 if (this.parentNode && this.parentNode.localName == "toolbox") { |
|
250 this._toolbox = this.parentNode; |
|
251 } |
|
252 |
|
253 return this._toolbox; |
|
254 ]]></getter> |
|
255 </property> |
|
256 <property name="currentSet" readonly="true"> |
|
257 <getter><![CDATA[ |
|
258 return this.getAttribute("defaultset"); |
|
259 ]]></getter> |
|
260 </property> |
|
261 <method name="insertItem"> |
|
262 <body><![CDATA[ |
|
263 return null; |
|
264 ]]></body> |
|
265 </method> |
|
266 </implementation> |
|
267 </binding> |
|
268 |
|
269 <!-- The toolbar-menubar-autohide and toolbar-drag bindings are almost |
|
270 verbatim copies of their toolkit counterparts - they just inherit from |
|
271 the customizableui's toolbar binding instead of toolkit's. We're currently |
|
272 OK with the maintainance burden of having two copies of a binding, since |
|
273 the long term goal is to move the customization framework into toolkit. --> |
|
274 |
|
275 <binding id="toolbar-menubar-autohide" |
|
276 extends="chrome://browser/content/customizableui/toolbar.xml#toolbar"> |
|
277 <implementation> |
|
278 <constructor> |
|
279 this._setInactive(); |
|
280 </constructor> |
|
281 <destructor> |
|
282 this._setActive(); |
|
283 </destructor> |
|
284 |
|
285 <field name="_inactiveTimeout">null</field> |
|
286 |
|
287 <field name="_contextMenuListener"><![CDATA[({ |
|
288 toolbar: this, |
|
289 contextMenu: null, |
|
290 |
|
291 get active () !!this.contextMenu, |
|
292 |
|
293 init: function (event) { |
|
294 let node = event.target; |
|
295 while (node != this.toolbar) { |
|
296 if (node.localName == "menupopup") |
|
297 return; |
|
298 node = node.parentNode; |
|
299 } |
|
300 |
|
301 let contextMenuId = this.toolbar.getAttribute("context"); |
|
302 if (!contextMenuId) |
|
303 return; |
|
304 |
|
305 this.contextMenu = document.getElementById(contextMenuId); |
|
306 if (!this.contextMenu) |
|
307 return; |
|
308 |
|
309 this.contextMenu.addEventListener("popupshown", this, false); |
|
310 this.contextMenu.addEventListener("popuphiding", this, false); |
|
311 this.toolbar.addEventListener("mousemove", this, false); |
|
312 }, |
|
313 handleEvent: function (event) { |
|
314 switch (event.type) { |
|
315 case "popupshown": |
|
316 this.toolbar.removeEventListener("mousemove", this, false); |
|
317 break; |
|
318 case "popuphiding": |
|
319 case "mousemove": |
|
320 this.toolbar._setInactiveAsync(); |
|
321 this.toolbar.removeEventListener("mousemove", this, false); |
|
322 this.contextMenu.removeEventListener("popuphiding", this, false); |
|
323 this.contextMenu.removeEventListener("popupshown", this, false); |
|
324 this.contextMenu = null; |
|
325 break; |
|
326 } |
|
327 } |
|
328 })]]></field> |
|
329 |
|
330 <method name="_setInactive"> |
|
331 <body><![CDATA[ |
|
332 this.setAttribute("inactive", "true"); |
|
333 ]]></body> |
|
334 </method> |
|
335 |
|
336 <method name="_setInactiveAsync"> |
|
337 <body><![CDATA[ |
|
338 this._inactiveTimeout = setTimeout(function (self) { |
|
339 if (self.getAttribute("autohide") == "true") { |
|
340 self._inactiveTimeout = null; |
|
341 self._setInactive(); |
|
342 } |
|
343 }, 0, this); |
|
344 ]]></body> |
|
345 </method> |
|
346 |
|
347 <method name="_setActive"> |
|
348 <body><![CDATA[ |
|
349 if (this._inactiveTimeout) { |
|
350 clearTimeout(this._inactiveTimeout); |
|
351 this._inactiveTimeout = null; |
|
352 } |
|
353 this.removeAttribute("inactive"); |
|
354 ]]></body> |
|
355 </method> |
|
356 </implementation> |
|
357 |
|
358 <handlers> |
|
359 <handler event="DOMMenuBarActive" action="this._setActive();"/> |
|
360 <handler event="popupshowing" action="this._setActive();"/> |
|
361 <handler event="mousedown" button="2" action="this._contextMenuListener.init(event);"/> |
|
362 <handler event="DOMMenuBarInactive"><![CDATA[ |
|
363 if (!this._contextMenuListener.active) |
|
364 this._setInactiveAsync(); |
|
365 ]]></handler> |
|
366 </handlers> |
|
367 </binding> |
|
368 |
|
369 <binding id="toolbar-drag" |
|
370 extends="chrome://browser/content/customizableui/toolbar.xml#toolbar"> |
|
371 <implementation> |
|
372 <field name="_dragBindingAlive">true</field> |
|
373 <constructor><![CDATA[ |
|
374 if (!this._draggableStarted) { |
|
375 this._draggableStarted = true; |
|
376 try { |
|
377 let tmp = {}; |
|
378 Components.utils.import("resource://gre/modules/WindowDraggingUtils.jsm", tmp); |
|
379 let draggableThis = new tmp.WindowDraggingElement(this); |
|
380 draggableThis.mouseDownCheck = function(e) { |
|
381 return this._dragBindingAlive; |
|
382 }; |
|
383 } catch (e) {} |
|
384 } |
|
385 ]]></constructor> |
|
386 </implementation> |
|
387 </binding> |
|
388 |
|
389 |
|
390 <!-- This is a peculiar binding. It is here to deal with overlayed/inserted add-on content, |
|
391 and immediately direct such content elsewhere. --> |
|
392 <binding id="addonbar-delegating"> |
|
393 <implementation> |
|
394 <constructor><![CDATA[ |
|
395 // Reading these immediately so nobody messes with them anymore: |
|
396 this._delegatingToolbar = this.getAttribute("toolbar-delegate"); |
|
397 this._wasCollapsed = this.getAttribute("collapsed") == "true"; |
|
398 // Leaving those in here to unbreak some code: |
|
399 if (document.readyState == "complete") { |
|
400 this._init(); |
|
401 } else { |
|
402 // Need to wait until XUL overlays are loaded. See bug 554279. |
|
403 let self = this; |
|
404 document.addEventListener("readystatechange", function onReadyStateChange() { |
|
405 if (document.readyState != "complete") |
|
406 return; |
|
407 document.removeEventListener("readystatechange", onReadyStateChange, false); |
|
408 self._init(); |
|
409 }, false); |
|
410 } |
|
411 ]]></constructor> |
|
412 |
|
413 <method name="_init"> |
|
414 <body><![CDATA[ |
|
415 // Searching for the toolbox palette in the toolbar binding because |
|
416 // toolbars are constructed first. |
|
417 let toolbox = this.toolbox; |
|
418 if (toolbox && !toolbox.palette) { |
|
419 for (let node of toolbox.children) { |
|
420 if (node.localName == "toolbarpalette") { |
|
421 // Hold on to the palette but remove it from the document. |
|
422 toolbox.palette = node; |
|
423 toolbox.removeChild(node); |
|
424 } |
|
425 } |
|
426 } |
|
427 |
|
428 // pass the current set of children for comparison with placements: |
|
429 let children = []; |
|
430 for (let node of this.childNodes) { |
|
431 if (node.getAttribute("skipintoolbarset") != "true" && node.id) { |
|
432 // Force everything to be removable so that buildArea can chuck stuff |
|
433 // out if the user has customized things / we've been here before: |
|
434 if (!this._whiteListed.has(node.id)) { |
|
435 node.setAttribute("removable", "true"); |
|
436 } |
|
437 children.push(node); |
|
438 } |
|
439 } |
|
440 CustomizableUI.registerToolbarNode(this, children); |
|
441 let existingMigratedItems = (this.getAttribute("migratedset") || "").split(','); |
|
442 for (let migratedItem of existingMigratedItems.filter((x) => !!x)) { |
|
443 this._currentSetMigrated.add(migratedItem); |
|
444 } |
|
445 this.evictNodes(); |
|
446 // We can't easily use |this| or strong bindings for the observer fn here |
|
447 // because that creates leaky circular references when the node goes away, |
|
448 // and XBL destructors are unreliable. |
|
449 let mutationObserver = new MutationObserver(function(mutations) { |
|
450 if (!mutations.length) { |
|
451 return; |
|
452 } |
|
453 let toolbar = mutations[0].target; |
|
454 // Can't use our own attribute because we might not have one if we're set to |
|
455 // collapsed |
|
456 let areCustomizing = toolbar.ownerDocument.documentElement.getAttribute("customizing"); |
|
457 if (!toolbar._isModifying && !areCustomizing) { |
|
458 toolbar.evictNodes(); |
|
459 } |
|
460 }); |
|
461 mutationObserver.observe(this, {childList: true}); |
|
462 ]]></body> |
|
463 </method> |
|
464 <method name="evictNodes"> |
|
465 <body><![CDATA[ |
|
466 this._isModifying = true; |
|
467 let i = this.childNodes.length; |
|
468 while (i--) { |
|
469 let node = this.childNodes[i]; |
|
470 if (this.childNodes[i].id) { |
|
471 this.evictNode(this.childNodes[i]); |
|
472 } else { |
|
473 node.remove(); |
|
474 } |
|
475 } |
|
476 this._isModifying = false; |
|
477 this._updateMigratedSet(); |
|
478 ]]></body> |
|
479 </method> |
|
480 <method name="evictNode"> |
|
481 <parameter name="aNode"/> |
|
482 <body> |
|
483 <![CDATA[ |
|
484 if (this._whiteListed.has(aNode.id) || CustomizableUI.isSpecialWidget(aNode.id)) { |
|
485 return; |
|
486 } |
|
487 const kItemMaxWidth = 100; |
|
488 let oldParent = aNode.parentNode; |
|
489 aNode.setAttribute("removable", "true"); |
|
490 this._currentSetMigrated.add(aNode.id); |
|
491 |
|
492 let movedOut = false; |
|
493 if (!this._wasCollapsed) { |
|
494 try { |
|
495 let nodeWidth = aNode.getBoundingClientRect().width; |
|
496 if (nodeWidth == 0 || nodeWidth > kItemMaxWidth) { |
|
497 throw new Error(aNode.id + " is too big (" + nodeWidth + |
|
498 "px wide), moving to the palette"); |
|
499 } |
|
500 CustomizableUI.addWidgetToArea(aNode.id, this._delegatingToolbar); |
|
501 movedOut = true; |
|
502 } catch (ex) { |
|
503 // This will throw if the node is too big, or can't be moved there for |
|
504 // some reason. Report this: |
|
505 Cu.reportError(ex); |
|
506 } |
|
507 } |
|
508 |
|
509 /* We won't have moved the widget if either the add-on bar was collapsed, |
|
510 * or if it was too wide to be inserted into the navbar. */ |
|
511 if (!movedOut) { |
|
512 try { |
|
513 CustomizableUI.removeWidgetFromArea(aNode.id); |
|
514 } catch (ex) { |
|
515 Cu.reportError(ex); |
|
516 aNode.remove(); |
|
517 } |
|
518 } |
|
519 |
|
520 // Surprise: addWidgetToArea(palette) will get you nothing if the palette |
|
521 // is not constructed yet. Fix: |
|
522 if (aNode.parentNode == oldParent) { |
|
523 let palette = this.toolbox.palette; |
|
524 if (palette && oldParent != palette) { |
|
525 palette.appendChild(aNode); |
|
526 } |
|
527 } |
|
528 ]]></body> |
|
529 </method> |
|
530 <method name="insertItem"> |
|
531 <parameter name="aId"/> |
|
532 <parameter name="aBeforeElt"/> |
|
533 <parameter name="aWrapper"/> |
|
534 <body><![CDATA[ |
|
535 if (aWrapper) { |
|
536 Cu.reportError("Can't insert " + aId + ": using insertItem " + |
|
537 "no longer supports wrapper elements."); |
|
538 return null; |
|
539 } |
|
540 |
|
541 let widget = CustomizableUI.getWidget(aId); |
|
542 widget = widget && widget.forWindow(window); |
|
543 let node = widget && widget.node; |
|
544 if (!node) { |
|
545 return null; |
|
546 } |
|
547 |
|
548 this._isModifying = true; |
|
549 // Temporarily add it here so it can have a width, then ditch it: |
|
550 this.appendChild(node); |
|
551 this.evictNode(node); |
|
552 this._isModifying = false; |
|
553 this._updateMigratedSet(); |
|
554 // We will now have moved stuff around; kick off some events |
|
555 // so add-ons know we've just moved their stuff: |
|
556 // XXXgijs: only in this window. It's hard to know for sure what's the right |
|
557 // thing to do here - typically insertItem is used on each window, so |
|
558 // this seems to make the most sense, even if some of the effects of |
|
559 // evictNode might affect multiple windows. |
|
560 CustomizableUI.dispatchToolboxEvent("customizationchange", {}, window); |
|
561 CustomizableUI.dispatchToolboxEvent("aftercustomization", {}, window); |
|
562 return node; |
|
563 ]]></body> |
|
564 </method> |
|
565 <method name="getMigratedItems"> |
|
566 <body><![CDATA[ |
|
567 return [... this._currentSetMigrated]; |
|
568 ]]></body> |
|
569 </method> |
|
570 <method name="_updateMigratedSet"> |
|
571 <body><![CDATA[ |
|
572 let newMigratedItems = this.getMigratedItems().join(','); |
|
573 if (this.getAttribute("migratedset") != newMigratedItems) { |
|
574 this.setAttribute("migratedset", newMigratedItems); |
|
575 this.ownerDocument.persist(this.id, "migratedset"); |
|
576 } |
|
577 ]]></body> |
|
578 </method> |
|
579 <property name="customizationTarget" readonly="true"> |
|
580 <getter><![CDATA[ |
|
581 return this; |
|
582 ]]></getter> |
|
583 </property> |
|
584 <property name="currentSet"> |
|
585 <getter><![CDATA[ |
|
586 return [node.id for (node of this.children)].join(','); |
|
587 ]]></getter> |
|
588 <setter><![CDATA[ |
|
589 let v = val.split(','); |
|
590 let newButtons = v.filter(x => x && (!this._whiteListed.has(x) && |
|
591 !CustomizableUI.isSpecialWidget(x) && |
|
592 !this._currentSetMigrated.has(x))); |
|
593 for (let newButton of newButtons) { |
|
594 this._currentSetMigrated.add(newButton); |
|
595 this.insertItem(newButton); |
|
596 } |
|
597 this._updateMigratedSet(); |
|
598 ]]></setter> |
|
599 </property> |
|
600 <property name="toolbox" readonly="true"> |
|
601 <getter><![CDATA[ |
|
602 if (!this._toolbox && this.parentNode && |
|
603 this.parentNode.localName == "toolbox") { |
|
604 this._toolbox = this.parentNode; |
|
605 } |
|
606 |
|
607 return this._toolbox; |
|
608 ]]></getter> |
|
609 </property> |
|
610 <field name="_whiteListed" readonly="true">new Set(["addonbar-closebutton", "status-bar"])</field> |
|
611 <field name="_isModifying">false</field> |
|
612 <field name="_currentSetMigrated">new Set()</field> |
|
613 </implementation> |
|
614 </binding> |
|
615 </bindings> |