Bug 864425 - Make toolbar-menubar, TabsToolbar and PersonalToolbar customization targets. r=Unfocused.

This commit is contained in:
Mike Conley 2013-04-30 11:00:41 -04:00
parent 92ac10a373
commit 7f35c7eb86
7 changed files with 185 additions and 31 deletions

View File

@ -9,10 +9,14 @@ searchbar {
-moz-binding: url("chrome://browser/content/search/search.xml#searchbar"); -moz-binding: url("chrome://browser/content/search/search.xml#searchbar");
} }
#nav-bar { toolbar[customizable="true"] {
-moz-binding: url("chrome://browser/content/customizableui/toolbar.xml#toolbar"); -moz-binding: url("chrome://browser/content/customizableui/toolbar.xml#toolbar");
} }
#toolbar-menubar[autohide="true"] {
-moz-binding: url("chrome://browser/content/customizableui/toolbar.xml#toolbar-menubar-autohide");
}
tabbrowser { tabbrowser {
-moz-binding: url("chrome://browser/content/tabbrowser.xml#tabbrowser"); -moz-binding: url("chrome://browser/content/tabbrowser.xml#tabbrowser");
} }

View File

@ -1186,7 +1186,6 @@
mode="icons" iconsize="small" defaulticonsize="small" mode="icons" iconsize="small" defaulticonsize="small"
lockiconsize="true" lockiconsize="true"
defaultset="addonbar-closebutton,spring,status-bar" defaultset="addonbar-closebutton,spring,status-bar"
customizable="true"
key="key_toggleAddonBar"> key="key_toggleAddonBar">
<toolbarbutton id="addonbar-closebutton" <toolbarbutton id="addonbar-closebutton"
tooltiptext="&addonBarCloseButton.tooltip;" tooltiptext="&addonBarCloseButton.tooltip;"

View File

@ -10,7 +10,6 @@ browser.jar:
content/browser/customizableui/panelUIOverlay.js content/browser/customizableui/panelUIOverlay.js
content/browser/customizableui/toolbar.xml content/browser/customizableui/toolbar.xml
# These overlays should be kept in sync with what pages are in # These overlays should be kept in sync with what pages are in
# XULBrowserWindow.inContentWhitelist in browser.js # XULBrowserWindow.inContentWhitelist in browser.js
% overlay about:addons chrome://browser/content/customizableui/panelUIOverlay.xul % overlay about:addons chrome://browser/content/customizableui/panelUIOverlay.xul

View File

@ -112,4 +112,122 @@
</implementation> </implementation>
</binding> </binding>
<!-- The toolbar-menubar-autohide and toolbar-drag bindings are almost
verbatim copies of their toolkit counterparts - they just inherit from
the customizableui's toolbar binding instead of toolkit's. We're currently
OK with the maintainance burden of having two copies of a binding, since
the long term goal is to move the customization framework into toolkit. -->
<binding id="toolbar-menubar-autohide"
extends="chrome://browser/content/customizableui/toolbar.xml#toolbar">
<implementation>
<constructor>
this._setInactive();
</constructor>
<field name="_inactiveTimeout">null</field>
<field name="_contextMenuListener"><![CDATA[({
toolbar: this,
contextMenu: null,
get active () !!this.contextMenu,
init: function (event) {
let node = event.target;
while (node != this.toolbar) {
if (node.localName == "menupopup")
return;
node = node.parentNode;
}
let contextMenuId = this.toolbar.getAttribute("context");
if (!contextMenuId)
return;
this.contextMenu = document.getElementById(contextMenuId);
if (!this.contextMenu)
return;
this.contextMenu.addEventListener("popupshown", this, false);
this.contextMenu.addEventListener("popuphiding", this, false);
this.toolbar.addEventListener("mousemove", this, false);
},
handleEvent: function (event) {
switch (event.type) {
case "popupshown":
this.toolbar.removeEventListener("mousemove", this, false);
break;
case "popuphiding":
case "mousemove":
this.toolbar._setInactiveAsync();
this.toolbar.removeEventListener("mousemove", this, false);
this.contextMenu.removeEventListener("popuphiding", this, false);
this.contextMenu.removeEventListener("popupshown", this, false);
this.contextMenu = null;
break;
}
}
})]]></field>
<method name="_setInactive">
<body><![CDATA[
this.setAttribute("inactive", "true");
]]></body>
</method>
<method name="_setInactiveAsync">
<body><![CDATA[
this._inactiveTimeout = setTimeout(function (self) {
if (self.getAttribute("autohide") == "true") {
self._inactiveTimeout = null;
self._setInactive();
}
}, 0, this);
]]></body>
</method>
<method name="_setActive">
<body><![CDATA[
if (this._inactiveTimeout) {
clearTimeout(this._inactiveTimeout);
this._inactiveTimeout = null;
}
this.removeAttribute("inactive");
]]></body>
</method>
</implementation>
<handlers>
<handler event="DOMMenuBarActive" action="this._setActive();"/>
<handler event="popupshowing" action="this._setActive();"/>
<handler event="mousedown" button="2" action="this._contextMenuListener.init(event);"/>
<handler event="DOMMenuBarInactive"><![CDATA[
if (!this._contextMenuListener.active)
this._setInactiveAsync();
]]></handler>
</handlers>
</binding>
<binding id="toolbar-drag"
extends="chrome://browser/content/customizableui/toolbar.xml#toolbar">
<implementation>
<field name="_dragBindingAlive">true</field>
<constructor><![CDATA[
if (!this._draggableStarted) {
this._draggableStarted = true;
try {
let tmp = {};
Components.utils.import("resource://gre/modules/WindowDraggingUtils.jsm", tmp);
let draggableThis = new tmp.WindowDraggingElement(this);
draggableThis.mouseDownCheck = function(e) {
// Don't move while customizing.
return this._dragBindingAlive &&
this.getAttribute("customizing") != "true";
};
} catch (e) {}
}
]]></constructor>
</implementation>
</binding>
</bindings> </bindings>

View File

@ -223,6 +223,15 @@ let gFuturePlacements = new Map();
* placements to use. * placements to use.
*/ */
let gDefaultPlacements = new Map([ let gDefaultPlacements = new Map([
["toolbar-menubar", [
"menubar-items",
]],
["TabsToolbar", [
"tabbrowser-tabs",
"new-tab-button",
"alltabs-button",
"tabs-closebutton"
]],
["nav-bar", [ ["nav-bar", [
"unified-back-forward-button", "unified-back-forward-button",
"urlbar-container", "urlbar-container",
@ -236,6 +245,9 @@ let gDefaultPlacements = new Map([
"social-toolbar-button", "social-toolbar-button",
"share-page" "share-page"
]], ]],
["PersonalToolbar", [
"personal-bookmarks",
]],
["PanelUI-contents", [ ["PanelUI-contents", [
"new-window-button", "new-window-button",
"print-button", "print-button",
@ -294,6 +306,9 @@ let CustomizableUIInternal = {
this.registerArea(CustomizableUI.AREA_PANEL); this.registerArea(CustomizableUI.AREA_PANEL);
this.registerArea(CustomizableUI.AREA_NAVBAR, ["legacy"]); this.registerArea(CustomizableUI.AREA_NAVBAR, ["legacy"]);
this.registerArea(CustomizableUI.AREA_MENUBAR, ["legacy"]);
this.registerArea(CustomizableUI.AREA_TABSTRIP, ["legacy"]);
this.registerArea(CustomizableUI.AREA_BOOKMARKS, ["legacy"]);
}, },
_defineBuiltInWidgets: function() { _defineBuiltInWidgets: function() {
@ -347,7 +362,7 @@ let CustomizableUIInternal = {
let area = aToolbar.id; let area = aToolbar.id;
if (!gAreas.has(area)) { if (!gAreas.has(area)) {
throw new Error("Unknown customization area"); throw new Error("Unknown customization area: " + area);
} }
if (this.isBuildAreaRegistered(area, aToolbar)) { if (this.isBuildAreaRegistered(area, aToolbar)) {
@ -361,12 +376,6 @@ let CustomizableUIInternal = {
if (legacyState) { if (legacyState) {
legacyState = legacyState.split(","); legacyState = legacyState.split(",");
} }
//XXXunf should the legacy attribute be purged?
// kinda messes up switching to older builds
//XXXmconley No, I don't think so - I think we want to make it easy to
// switch back and forth between builds until this thing hits
// release.
//aToolbar.removeAttribute("currentset");
// Manually restore the state here, so the legacy state can be converted. // Manually restore the state here, so the legacy state can be converted.
this.restoreStateForArea(area, legacyState); this.restoreStateForArea(area, legacyState);
@ -378,8 +387,8 @@ let CustomizableUIInternal = {
this.buildArea(area, placements, aToolbar); this.buildArea(area, placements, aToolbar);
aToolbar.setAttribute("currentset", placements.join(",")); aToolbar.setAttribute("currentset", placements.join(","));
// We register this window to have its customization data cleaned up when // We ensure that the window is registered to have its customization data
// unloading. // cleaned up when unloading.
this.registerBuildWindow(document.defaultView); this.registerBuildWindow(document.defaultView);
}, },
@ -395,6 +404,7 @@ let CustomizableUIInternal = {
let currentNode = container.firstChild; let currentNode = container.firstChild;
for (let id of aPlacements) { for (let id of aPlacements) {
if (currentNode && currentNode.id == id) { if (currentNode && currentNode.id == id) {
this._addParentFlex(currentNode);
currentNode = currentNode.nextSibling; currentNode = currentNode.nextSibling;
continue; continue;
} }
@ -483,6 +493,7 @@ let CustomizableUIInternal = {
this.buildWidget(aDocument, null, widget) ]; this.buildWidget(aDocument, null, widget) ];
} }
LOG("Searching for " + aWidgetId + " in toolbox.");
let node = this.findWidgetInToolbox(aWidgetId, aToolbox, aDocument); let node = this.findWidgetInToolbox(aWidgetId, aToolbox, aDocument);
if (node) { if (node) {
return [ CustomizableUI.PROVIDER_XUL, node ]; return [ CustomizableUI.PROVIDER_XUL, node ];
@ -815,7 +826,7 @@ let CustomizableUIInternal = {
LOG("Iterating the actual nodes of the window palette"); LOG("Iterating the actual nodes of the window palette");
for (let node of aWindowPalette.children) { for (let node of aWindowPalette.children) {
LOG("In palette children: " + node.id); LOG("In palette children: " + node.id);
if (!this.getPlacementOfWidget(node.id)) { if (node.id && !this.getPlacementOfWidget(node.id)) {
widgets.add(node.id); widgets.add(node.id);
} }
} }
@ -838,7 +849,7 @@ let CustomizableUIInternal = {
addWidgetToArea: function(aWidgetId, aArea, aPosition) { addWidgetToArea: function(aWidgetId, aArea, aPosition) {
if (!gAreas.has(aArea)) { if (!gAreas.has(aArea)) {
throw new Error("Unknown customization area"); throw new Error("Unknown customization area: " + aArea);
} }
// If this is a lazy area that hasn't been restored yet, we can't yet modify // If this is a lazy area that hasn't been restored yet, we can't yet modify
@ -1465,6 +1476,9 @@ Object.freeze(CustomizableUIInternal);
this.CustomizableUI = { this.CustomizableUI = {
get AREA_PANEL() "PanelUI-contents", get AREA_PANEL() "PanelUI-contents",
get AREA_NAVBAR() "nav-bar", get AREA_NAVBAR() "nav-bar",
get AREA_MENUBAR() "toolbar-menubar",
get AREA_TABSTRIP() "TabsToolbar",
get AREA_BOOKMARKS() "PersonalToolbar",
get PROVIDER_XUL() "xul", get PROVIDER_XUL() "xul",
get PROVIDER_API() "api", get PROVIDER_API() "api",
@ -1525,7 +1539,7 @@ this.CustomizableUI = {
}, },
getWidgetsInArea: function(aArea) { getWidgetsInArea: function(aArea) {
if (!gAreas.has(aArea)) { if (!gAreas.has(aArea)) {
throw new Error("Unknown customization area"); throw new Error("Unknown customization area: " + aArea);
} }
if (!gPlacements.has(aArea)) { if (!gPlacements.has(aArea)) {
throw new Error("Area not yet restored"); throw new Error("Area not yet restored");

View File

@ -12,6 +12,9 @@ const kPrefCustomizationDebug = "browser.uiCustomization.debug";
const kPaletteId = "customization-palette"; const kPaletteId = "customization-palette";
const kAboutURI = "about:customizing"; const kAboutURI = "about:customizing";
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource:///modules/CustomizableUI.jsm");
let gDebug = false; let gDebug = false;
try { try {
gDebug = Services.prefs.getBoolPref(kPrefCustomizationDebug); gDebug = Services.prefs.getBoolPref(kPrefCustomizationDebug);
@ -19,15 +22,12 @@ try {
function LOG(str) { function LOG(str) {
if (gDebug) { if (gDebug) {
Services.console.logStringMessage(str); Services.console.logStringMessage("[CustomizeMode] " + str);
} }
} }
function ERROR(aMsg) Cu.reportError("[CustomizeMode] " + aMsg); function ERROR(aMsg) Cu.reportError("[CustomizeMode] " + aMsg);
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource:///modules/CustomizableUI.jsm");
function CustomizeMode(aWindow) { function CustomizeMode(aWindow) {
this.window = aWindow; this.window = aWindow;
this.document = aWindow.document; this.document = aWindow.document;
@ -68,6 +68,10 @@ CustomizeMode.prototype = {
}, },
enter: function() { enter: function() {
if (this._customizing) {
return;
}
let window = this.window; let window = this.window;
let document = this.document; let document = this.document;
@ -124,8 +128,10 @@ CustomizeMode.prototype = {
target.addEventListener("dragexit", self); target.addEventListener("dragexit", self);
target.addEventListener("drop", self); target.addEventListener("drop", self);
for (let child of target.children) { for (let child of target.children) {
if (self.isCustomizableItem(child)) {
self.wrapToolbarItem(child, getPlaceForItem(child)); self.wrapToolbarItem(child, getPlaceForItem(child));
} }
}
self.areas.push(target); self.areas.push(target);
} }
@ -142,6 +148,10 @@ CustomizeMode.prototype = {
}, },
exit: function() { exit: function() {
if (!this._customizing) {
return;
}
CustomizableUI.removeListener(this); CustomizableUI.removeListener(this);
let deck = this.document.getElementById("tab-view-deck"); let deck = this.document.getElementById("tab-view-deck");
@ -172,8 +182,10 @@ CustomizeMode.prototype = {
for (let target of this.areas) { for (let target of this.areas) {
for (let toolbarItem of target.children) { for (let toolbarItem of target.children) {
if (this.isWrappedToolbarItem(toolbarItem)) {
this.unwrapToolbarItem(toolbarItem); this.unwrapToolbarItem(toolbarItem);
} }
}
target.removeEventListener("dragstart", this); target.removeEventListener("dragstart", this);
target.removeEventListener("dragover", this); target.removeEventListener("dragover", this);
target.removeEventListener("dragexit", this); target.removeEventListener("dragexit", this);
@ -280,6 +292,18 @@ CustomizeMode.prototype = {
this.window.gNavToolbox.palette = this._stowedPalette; this.window.gNavToolbox.palette = this._stowedPalette;
}, },
isCustomizableItem: function(aNode) {
return aNode.localName == "toolbarbutton" ||
aNode.localName == "toolbaritem" ||
aNode.localName == "toolbarseparator" ||
aNode.localName == "toolbarspring" ||
aNode.localName == "toolbarspacer";
},
isWrappedToolbarItem: function(aNode) {
return aNode.localName == "toolbarpaletteitem";
},
wrapToolbarItem: function(aNode, aPlace) { wrapToolbarItem: function(aNode, aPlace) {
let wrapper = this.createWrapper(aNode, aPlace); let wrapper = this.createWrapper(aNode, aPlace);
// It's possible that this toolbar node is "mid-flight" and doesn't have // It's possible that this toolbar node is "mid-flight" and doesn't have
@ -370,17 +394,13 @@ CustomizeMode.prototype = {
return toolbarItem; return toolbarItem;
}, },
//XXXjaws This doesn't handle custom toolbars.
//XXXmconley While CustomizableUI.jsm uses prefs to preserve state, we might
// also want to (try) persisting with currentset as well to make it
// less painful to switch to older builds.
persistCurrentSets: function() { persistCurrentSets: function() {
let document = this.document; let document = this.document;
let toolbars = document.querySelectorAll("toolbar"); let toolbars = document.querySelectorAll("toolbar[customizable='true']");
for (let toolbar of toolbars) { for (let toolbar of toolbars) {
// Calculate currentset and store it in the attribute. let set = toolbar.currentSet;
toolbar.setAttribute("currentset", toolbar.currentSet); toolbar.setAttribute("currentset", set);
LOG("Setting currentset of " + toolbar.id + " as " + set);
// Persist the currentset attribute directly on hardcoded toolbars. // Persist the currentset attribute directly on hardcoded toolbars.
document.persist(toolbar.id, "currentset"); document.persist(toolbar.id, "currentset");
} }

View File

@ -257,7 +257,7 @@
#nav-bar[tabsontop=false], #nav-bar[tabsontop=false],
#nav-bar + #customToolbars + #PersonalToolbar[collapsed="true"] + #TabsToolbar[tabsontop="false"]:last-child, #nav-bar + #customToolbars + #PersonalToolbar[collapsed="true"] + #TabsToolbar[tabsontop="false"]:last-child,
#navigator-toolbox > toolbar:not(#toolbar-menubar):-moz-lwtheme { #navigator-toolbox > toolbar:not(#toolbar-menubar):-moz-lwtheme {
-moz-binding: url("chrome://global/content/bindings/toolbar.xml#toolbar-drag"); -moz-binding: url("chrome://browser/content/customizableui/toolbar.xml#toolbar-drag");
} }
#appcontent:not(:-moz-lwtheme) { #appcontent:not(:-moz-lwtheme) {