|
|
|
Lines 103-131
let gInBatchStack = 0;
|
Link Here
|
|---|
|
| 103 |
let gResetting = false; |
103 |
let gResetting = false; |
| 104 |
|
104 |
|
| 105 |
/** |
105 |
/** |
| 106 |
* gBuildAreas maps area IDs to actual area nodes within browser windows. |
106 |
* gBuildAreas maps area IDs to actual area nodes within browser windows. |
| 107 |
*/ |
107 |
*/ |
| 108 |
let gBuildAreas = new Map(); |
108 |
let gBuildAreas = new Map(); |
| 109 |
|
109 |
|
| 110 |
/** |
110 |
/** |
| 111 |
* gBuildWindows is a map of windows that have registered build areas, mapped |
111 |
* gBuildWindows is a set of windows that have registered build areas. |
| 112 |
* to a Set of known toolboxes in that window. |
|
|
| 113 |
*/ |
112 |
*/ |
| 114 |
let gBuildWindows = new Map(); |
113 |
let gBuildWindows = new Set(); |
| 115 |
|
114 |
|
| 116 |
let gNewElementCount = 0; |
115 |
let gNewElementCount = 0; |
| 117 |
let gGroupWrapperCache = new Map(); |
116 |
let gGroupWrapperCache = new Map(); |
| 118 |
let gSingleWrapperCache = new WeakMap(); |
117 |
let gSingleWrapperCache = new WeakMap(); |
| 119 |
let gListeners = new Set(); |
118 |
let gListeners = new Set(); |
| 120 |
|
119 |
|
| 121 |
let gModuleName = "[CustomizableUI]"; |
120 |
let gModuleName = "[CustomizableUI]"; |
| 122 |
#include logging.js |
121 |
#include logging.js |
| 123 |
|
122 |
|
|
|
123 |
let CustomizeHelper = { |
| 124 |
getToolboxForWindow: function(aWindow) { |
| 125 |
return aWindow.gNavToolbox; |
| 126 |
}, |
| 127 |
}; |
| 128 |
|
| 124 |
let CustomizableUIInternal = { |
129 |
let CustomizableUIInternal = { |
| 125 |
initialize: function() { |
130 |
initialize: function() { |
| 126 |
LOG("Initializing"); |
131 |
LOG("Initializing"); |
| 127 |
|
132 |
|
| 128 |
this.addListener(this); |
133 |
this.addListener(this); |
| 129 |
this._defineBuiltInWidgets(); |
134 |
this._defineBuiltInWidgets(); |
| 130 |
this.loadSavedState(); |
135 |
this.loadSavedState(); |
| 131 |
|
136 |
|
|
Lines 383-399
let CustomizableUIInternal = {
|
Link Here
|
|---|
|
| 383 |
|
388 |
|
| 384 |
this.insertWidgetBefore(node, currentNode, container, aArea); |
389 |
this.insertWidgetBefore(node, currentNode, container, aArea); |
| 385 |
this._addParentFlex(node); |
390 |
this._addParentFlex(node); |
| 386 |
if (gResetting) |
391 |
if (gResetting) |
| 387 |
this.notifyListeners("onWidgetReset", id); |
392 |
this.notifyListeners("onWidgetReset", id); |
| 388 |
} |
393 |
} |
| 389 |
|
394 |
|
| 390 |
if (currentNode) { |
395 |
if (currentNode) { |
| 391 |
let palette = aAreaNode.toolbox ? aAreaNode.toolbox.palette : null; |
396 |
let palette = CustomizeHelper.getToolboxForWindow(window).palette; |
| 392 |
let limit = currentNode.previousSibling; |
397 |
let limit = currentNode.previousSibling; |
| 393 |
let node = container.lastChild; |
398 |
let node = container.lastChild; |
| 394 |
while (node && node != limit) { |
399 |
while (node && node != limit) { |
| 395 |
let previousSibling = node.previousSibling; |
400 |
let previousSibling = node.previousSibling; |
| 396 |
// Nodes opt-in to removability. If they're removable, and we haven't |
401 |
// Nodes opt-in to removability. If they're removable, and we haven't |
| 397 |
// seen them in the placements array, then we toss them into the palette |
402 |
// seen them in the placements array, then we toss them into the palette |
| 398 |
// if one exists. If no palette exists, we just remove the node. If the |
403 |
// if one exists. If no palette exists, we just remove the node. If the |
| 399 |
// node is not removable, we leave it where it is. However, we can only |
404 |
// node is not removable, we leave it where it is. However, we can only |
|
Lines 520-536
let CustomizableUIInternal = {
|
Link Here
|
|---|
|
| 520 |
for (let btn of aPanel.querySelectorAll("toolbarbutton")) { |
525 |
for (let btn of aPanel.querySelectorAll("toolbarbutton")) { |
| 521 |
btn.setAttribute("tabindex", "0"); |
526 |
btn.setAttribute("tabindex", "0"); |
| 522 |
this.ensureButtonContextMenu(btn, true); |
527 |
this.ensureButtonContextMenu(btn, true); |
| 523 |
if (!btn.hasAttribute("type")) { |
528 |
if (!btn.hasAttribute("type")) { |
| 524 |
btn.setAttribute("type", "wrap"); |
529 |
btn.setAttribute("type", "wrap"); |
| 525 |
} |
530 |
} |
| 526 |
} |
531 |
} |
| 527 |
|
532 |
|
| 528 |
aPanel.toolbox = document.getElementById("navigator-toolbox"); |
|
|
| 529 |
aPanel.customizationTarget = aPanel; |
533 |
aPanel.customizationTarget = aPanel; |
| 530 |
|
534 |
|
| 531 |
this.addPanelCloseListeners(aPanel); |
535 |
this.addPanelCloseListeners(aPanel); |
| 532 |
|
536 |
|
| 533 |
let placements = gPlacements.get(CustomizableUI.AREA_PANEL); |
537 |
let placements = gPlacements.get(CustomizableUI.AREA_PANEL); |
| 534 |
this.buildArea(CustomizableUI.AREA_PANEL, placements, aPanel); |
538 |
this.buildArea(CustomizableUI.AREA_PANEL, placements, aPanel); |
| 535 |
this.registerBuildArea(CustomizableUI.AREA_PANEL, aPanel); |
539 |
this.registerBuildArea(CustomizableUI.AREA_PANEL, aPanel); |
| 536 |
}, |
540 |
}, |
|
Lines 613-629
let CustomizableUIInternal = {
|
Link Here
|
|---|
|
| 613 |
if (gPalette.has(aWidgetId) || this.isSpecialWidget(aWidgetId)) { |
617 |
if (gPalette.has(aWidgetId) || this.isSpecialWidget(aWidgetId)) { |
| 614 |
container.removeChild(widgetNode); |
618 |
container.removeChild(widgetNode); |
| 615 |
} else { |
619 |
} else { |
| 616 |
this.removeLocationAttributes(widgetNode); |
620 |
this.removeLocationAttributes(widgetNode); |
| 617 |
widgetNode.removeAttribute("tabindex"); |
621 |
widgetNode.removeAttribute("tabindex"); |
| 618 |
if (widgetNode.getAttribute("type") == "wrap") { |
622 |
if (widgetNode.getAttribute("type") == "wrap") { |
| 619 |
widgetNode.removeAttribute("type"); |
623 |
widgetNode.removeAttribute("type"); |
| 620 |
} |
624 |
} |
| 621 |
areaNode.toolbox.palette.appendChild(widgetNode); |
625 |
let palette = CustomizeHelper.getToolboxForWindow(window).palette; |
|
|
626 |
palette.appendChild(widgetNode); |
| 622 |
} |
627 |
} |
| 623 |
if (area.get("type") == CustomizableUI.TYPE_TOOLBAR) { |
628 |
if (area.get("type") == CustomizableUI.TYPE_TOOLBAR) { |
| 624 |
areaNode.setAttribute("currentset", areaNode.currentSet); |
629 |
areaNode.setAttribute("currentset", areaNode.currentSet); |
| 625 |
} |
630 |
} |
| 626 |
|
631 |
|
| 627 |
let windowCache = gSingleWrapperCache.get(window); |
632 |
let windowCache = gSingleWrapperCache.get(window); |
| 628 |
if (windowCache) { |
633 |
if (windowCache) { |
| 629 |
windowCache.delete(aWidgetId); |
634 |
windowCache.delete(aWidgetId); |
|
Lines 675-706
let CustomizableUIInternal = {
|
Link Here
|
|---|
|
| 675 |
}, |
680 |
}, |
| 676 |
|
681 |
|
| 677 |
registerBuildArea: function(aArea, aNode) { |
682 |
registerBuildArea: function(aArea, aNode) { |
| 678 |
// We ensure that the window is registered to have its customization data |
683 |
// We ensure that the window is registered to have its customization data |
| 679 |
// cleaned up when unloading. |
684 |
// cleaned up when unloading. |
| 680 |
let window = aNode.ownerDocument.defaultView; |
685 |
let window = aNode.ownerDocument.defaultView; |
| 681 |
this.registerBuildWindow(window); |
686 |
this.registerBuildWindow(window); |
| 682 |
|
687 |
|
| 683 |
// Also register this build area's toolbox. |
|
|
| 684 |
if (aNode.toolbox) { |
| 685 |
gBuildWindows.get(window).add(aNode.toolbox); |
| 686 |
} |
| 687 |
|
| 688 |
if (!gBuildAreas.has(aArea)) { |
688 |
if (!gBuildAreas.has(aArea)) { |
| 689 |
gBuildAreas.set(aArea, new Set()); |
689 |
gBuildAreas.set(aArea, new Set()); |
| 690 |
} |
690 |
} |
| 691 |
|
691 |
|
| 692 |
gBuildAreas.get(aArea).add(aNode); |
692 |
gBuildAreas.get(aArea).add(aNode); |
| 693 |
}, |
693 |
}, |
| 694 |
|
694 |
|
| 695 |
registerBuildWindow: function(aWindow) { |
695 |
registerBuildWindow: function(aWindow) { |
| 696 |
if (!gBuildWindows.has(aWindow)) { |
696 |
gBuildWindows.add(aWindow); |
| 697 |
gBuildWindows.set(aWindow, new Set()); |
|
|
| 698 |
} |
| 699 |
|
697 |
|
| 700 |
aWindow.addEventListener("unload", this); |
698 |
aWindow.addEventListener("unload", this); |
| 701 |
aWindow.addEventListener("command", this, true); |
699 |
aWindow.addEventListener("command", this, true); |
| 702 |
}, |
700 |
}, |
| 703 |
|
701 |
|
| 704 |
unregisterBuildWindow: function(aWindow) { |
702 |
unregisterBuildWindow: function(aWindow) { |
| 705 |
aWindow.removeEventListener("unload", this); |
703 |
aWindow.removeEventListener("unload", this); |
| 706 |
aWindow.removeEventListener("command", this, true); |
704 |
aWindow.removeEventListener("command", this, true); |
|
Lines 830-877
let CustomizableUIInternal = {
|
Link Here
|
|---|
|
| 830 |
let node = document.getElementById(aId); |
828 |
let node = document.getElementById(aId); |
| 831 |
if (node) { |
829 |
if (node) { |
| 832 |
let parent = node.parentNode; |
830 |
let parent = node.parentNode; |
| 833 |
while (parent && !(parent.customizationTarget || |
831 |
while (parent && !(parent.customizationTarget || |
| 834 |
parent.localName == "toolbarpaletteitem")) { |
832 |
parent.localName == "toolbarpaletteitem")) { |
| 835 |
parent = parent.parentNode; |
833 |
parent = parent.parentNode; |
| 836 |
} |
834 |
} |
| 837 |
|
835 |
|
| 838 |
if ((parent && parent.customizationTarget == node.parentNode && |
836 |
if ((parent && parent.customizationTarget == node.parentNode) || |
| 839 |
gBuildWindows.get(aWindow).has(parent.toolbox)) || |
|
|
| 840 |
(parent && parent.localName == "toolbarpaletteitem")) { |
837 |
(parent && parent.localName == "toolbarpaletteitem")) { |
| 841 |
// Normalize the removable attribute. For backwards compat, if |
838 |
// Normalize the removable attribute. For backwards compat, if |
| 842 |
// the widget is not defined in a toolbox palette then absence |
839 |
// the widget is not defined in a toolbox palette then absence |
| 843 |
// of the "removable" attribute means it is not removable. |
840 |
// of the "removable" attribute means it is not removable. |
| 844 |
if (!node.hasAttribute("removable")) { |
841 |
if (!node.hasAttribute("removable")) { |
| 845 |
// If we first see this in customization mode, it may be in the |
842 |
// If we first see this in customization mode, it may be in the |
| 846 |
// customization palette instead of the toolbox palette. |
843 |
// customization palette instead of the toolbox palette. |
| 847 |
node.setAttribute("removable", !parent.customizationTarget); |
844 |
node.setAttribute("removable", !parent.customizationTarget); |
| 848 |
} |
845 |
} |
| 849 |
|
846 |
|
| 850 |
return node; |
847 |
return node; |
| 851 |
} |
848 |
} |
| 852 |
} |
849 |
} |
| 853 |
|
850 |
|
| 854 |
let toolboxes = gBuildWindows.get(aWindow); |
851 |
let palette = CustomizeHelper.getToolboxForWindow(aWindow).palette; |
| 855 |
for (let toolbox of toolboxes) { |
852 |
// Attempt to locate a node with a matching ID within |
| 856 |
if (toolbox.palette) { |
853 |
// the palette. |
| 857 |
// Attempt to locate a node with a matching ID within |
854 |
let node = palette.querySelector(idToSelector(aId)); |
| 858 |
// the palette. |
855 |
if (node) { |
| 859 |
let node = toolbox.palette.querySelector(idToSelector(aId)); |
856 |
// Normalize the removable attribute. For backwards compat, this |
| 860 |
if (node) { |
857 |
// is optional if the widget is defined in the toolbox palette, |
| 861 |
// Normalize the removable attribute. For backwards compat, this |
858 |
// and defaults to *true*, unlike if it was defined elsewhere. |
| 862 |
// is optional if the widget is defined in the toolbox palette, |
859 |
if (!node.hasAttribute("removable")) { |
| 863 |
// and defaults to *true*, unlike if it was defined elsewhere. |
860 |
node.setAttribute("removable", true); |
| 864 |
if (!node.hasAttribute("removable")) { |
|
|
| 865 |
node.setAttribute("removable", true); |
| 866 |
} |
| 867 |
return node; |
| 868 |
} |
| 869 |
} |
861 |
} |
|
|
862 |
return node; |
| 870 |
} |
863 |
} |
| 871 |
return null; |
864 |
return null; |
| 872 |
}, |
865 |
}, |
| 873 |
|
866 |
|
| 874 |
buildWidget: function(aDocument, aWidget) { |
867 |
buildWidget: function(aDocument, aWidget) { |
| 875 |
if (typeof aWidget == "string") { |
868 |
if (typeof aWidget == "string") { |
| 876 |
aWidget = gPalette.get(aWidget); |
869 |
aWidget = gPalette.get(aWidget); |
| 877 |
} |
870 |
} |
|
Lines 1801-1817
let CustomizableUIInternal = {
|
Link Here
|
|---|
|
| 1801 |
if (gBuildWindows.size == 0) { |
1794 |
if (gBuildWindows.size == 0) { |
| 1802 |
// We don't have any build windows to look at, so just assume for now |
1795 |
// We don't have any build windows to look at, so just assume for now |
| 1803 |
// that its removable. |
1796 |
// that its removable. |
| 1804 |
return true; |
1797 |
return true; |
| 1805 |
} |
1798 |
} |
| 1806 |
|
1799 |
|
| 1807 |
if (!widgetNode) { |
1800 |
if (!widgetNode) { |
| 1808 |
// Pick any of the build windows to look at. |
1801 |
// Pick any of the build windows to look at. |
| 1809 |
let [window,] = [...gBuildWindows][0]; |
1802 |
let window = [...gBuildWindows][0]; |
| 1810 |
[, widgetNode] = this.getWidgetNode(widgetId, window); |
1803 |
[, widgetNode] = this.getWidgetNode(widgetId, window); |
| 1811 |
} |
1804 |
} |
| 1812 |
// If we don't have a node, we assume it's removable. This can happen because |
1805 |
// If we don't have a node, we assume it's removable. This can happen because |
| 1813 |
// getWidgetProvider returns PROVIDER_XUL by default, but this will also happen |
1806 |
// getWidgetProvider returns PROVIDER_XUL by default, but this will also happen |
| 1814 |
// for API-provided widgets which have been destroyed. |
1807 |
// for API-provided widgets which have been destroyed. |
| 1815 |
if (!widgetNode) { |
1808 |
if (!widgetNode) { |
| 1816 |
return true; |
1809 |
return true; |
| 1817 |
} |
1810 |
} |
|
Lines 2145-2161
function XULWidgetGroupWrapper(aWidgetId
|
Link Here
|
|---|
|
| 2145 |
if (wrapperMap.has(aWidgetId)) { |
2138 |
if (wrapperMap.has(aWidgetId)) { |
| 2146 |
return wrapperMap.get(aWidgetId); |
2139 |
return wrapperMap.get(aWidgetId); |
| 2147 |
} |
2140 |
} |
| 2148 |
|
2141 |
|
| 2149 |
let instance = aWindow.document.getElementById(aWidgetId); |
2142 |
let instance = aWindow.document.getElementById(aWidgetId); |
| 2150 |
if (!instance) { |
2143 |
if (!instance) { |
| 2151 |
// Toolbar palettes aren't part of the document, so elements in there |
2144 |
// Toolbar palettes aren't part of the document, so elements in there |
| 2152 |
// won't be found via document.getElementById(). |
2145 |
// won't be found via document.getElementById(). |
| 2153 |
instance = aWindow.gNavToolbox.palette.querySelector(idToSelector(aWidgetId)); |
2146 |
let palette = CustomizeHelper.getToolboxForWindow(aWindow).palette; |
|
|
2147 |
instance = palette.querySelector(idToSelector(aWidgetId)); |
| 2154 |
} |
2148 |
} |
| 2155 |
|
2149 |
|
| 2156 |
let wrapper = new XULWidgetSingleWrapper(aWidgetId, instance); |
2150 |
let wrapper = new XULWidgetSingleWrapper(aWidgetId, instance); |
| 2157 |
wrapperMap.set(aWidgetId, wrapper); |
2151 |
wrapperMap.set(aWidgetId, wrapper); |
| 2158 |
return wrapper; |
2152 |
return wrapper; |
| 2159 |
}; |
2153 |
}; |
| 2160 |
|
2154 |
|
| 2161 |
this.__defineGetter__("areaType", function() { |
2155 |
this.__defineGetter__("areaType", function() { |
|
Lines 2222-2239
OverflowableToolbar.prototype = {
|
Link Here
|
|---|
|
| 2222 |
|
2216 |
|
| 2223 |
init: function() { |
2217 |
init: function() { |
| 2224 |
this._target = this._toolbar.customizationTarget; |
2218 |
this._target = this._toolbar.customizationTarget; |
| 2225 |
let doc = this._toolbar.ownerDocument; |
2219 |
let doc = this._toolbar.ownerDocument; |
| 2226 |
this._list = doc.getElementById(this._toolbar.getAttribute("overflowtarget")); |
2220 |
this._list = doc.getElementById(this._toolbar.getAttribute("overflowtarget")); |
| 2227 |
|
2221 |
|
| 2228 |
let window = doc.defaultView; |
2222 |
let window = doc.defaultView; |
| 2229 |
window.addEventListener("resize", this); |
2223 |
window.addEventListener("resize", this); |
| 2230 |
window.gNavToolbox.addEventListener("customizationstarting", this); |
2224 |
let toolbox = CustomizeHelper.getToolboxForWindow(window); |
| 2231 |
window.gNavToolbox.addEventListener("aftercustomization", this); |
2225 |
toolbox.addEventListener("customizationstarting", this); |
|
|
2226 |
toolbox.addEventListener("aftercustomization", this); |
| 2232 |
|
2227 |
|
| 2233 |
let chevronId = this._toolbar.getAttribute("overflowbutton"); |
2228 |
let chevronId = this._toolbar.getAttribute("overflowbutton"); |
| 2234 |
this._chevron = doc.getElementById(chevronId); |
2229 |
this._chevron = doc.getElementById(chevronId); |
| 2235 |
this._chevron.addEventListener("command", this); |
2230 |
this._chevron.addEventListener("command", this); |
| 2236 |
|
2231 |
|
| 2237 |
this._panel = doc.getElementById("widget-overflow"); |
2232 |
this._panel = doc.getElementById("widget-overflow"); |
| 2238 |
this._panel.addEventListener("popuphiding", this); |
2233 |
this._panel.addEventListener("popuphiding", this); |
| 2239 |
CustomizableUIInternal.addPanelCloseListeners(this._panel); |
2234 |
CustomizableUIInternal.addPanelCloseListeners(this._panel); |
|
Lines 2254-2271
OverflowableToolbar.prototype = {
|
Link Here
|
|---|
|
| 2254 |
Services.obs.removeObserver(this, "browser-delayed-startup-finished"); |
2249 |
Services.obs.removeObserver(this, "browser-delayed-startup-finished"); |
| 2255 |
return; |
2250 |
return; |
| 2256 |
} |
2251 |
} |
| 2257 |
|
2252 |
|
| 2258 |
this._disable(); |
2253 |
this._disable(); |
| 2259 |
|
2254 |
|
| 2260 |
let window = this._toolbar.ownerDocument.defaultView; |
2255 |
let window = this._toolbar.ownerDocument.defaultView; |
| 2261 |
window.removeEventListener("resize", this); |
2256 |
window.removeEventListener("resize", this); |
| 2262 |
window.gNavToolbox.removeEventListener("customizationstarting", this); |
2257 |
let toolbox = CustomizeHelper.getToolboxForWindow(window); |
| 2263 |
window.gNavToolbox.removeEventListener("aftercustomization", this); |
2258 |
toolbox.removeEventListener("customizationstarting", this); |
|
|
2259 |
toolbox.removeEventListener("aftercustomization", this); |
| 2264 |
this._chevron.removeEventListener("command", this); |
2260 |
this._chevron.removeEventListener("command", this); |
| 2265 |
this._panel.removeEventListener("popuphiding", this); |
2261 |
this._panel.removeEventListener("popuphiding", this); |
| 2266 |
CustomizableUIInternal.removePanelCloseListeners(this._panel); |
2262 |
CustomizableUIInternal.removePanelCloseListeners(this._panel); |
| 2267 |
}, |
2263 |
}, |
| 2268 |
|
2264 |
|
| 2269 |
handleEvent: function(aEvent) { |
2265 |
handleEvent: function(aEvent) { |
| 2270 |
switch(aEvent.type) { |
2266 |
switch(aEvent.type) { |
| 2271 |
case "overflow": |
2267 |
case "overflow": |