Bug 1354079 - add sticky / permanent part to overflow panel, r?mikedeboer
MozReview-Commit-ID: 7wv43JWLx8Q
--- a/browser/components/customizableui/CustomizableUI.jsm
+++ b/browser/components/customizableui/CustomizableUI.jsm
@@ -229,16 +229,23 @@ var CustomizableUIInternal = {
this.registerArea(CustomizableUI.AREA_PANEL, {
anchor: "PanelUI-menu-button",
type: CustomizableUI.TYPE_MENU_PANEL,
defaultPlacements: panelPlacements
}, true);
PanelWideWidgetTracker.init();
+ if (Services.prefs.getBoolPref("browser.photon.structure.enabled")) {
+ this.registerArea(CustomizableUI.AREA_FIXED_OVERFLOW_PANEL, {
+ type: CustomizableUI.TYPE_MENU_PANEL,
+ defaultPlacements: [],
+ }, true);
+ }
+
let navbarPlacements = [
"urlbar-container",
"search-container",
"bookmarks-menu-button",
"downloads-button",
"home-button",
];
@@ -892,45 +899,44 @@ var CustomizableUIInternal = {
if (node) {
return [ CustomizableUI.PROVIDER_XUL, node ];
}
log.debug("No node for " + aWidgetId + " found.");
return [null, null];
},
- registerMenuPanel(aPanelContents) {
- if (gBuildAreas.has(CustomizableUI.AREA_PANEL) &&
- gBuildAreas.get(CustomizableUI.AREA_PANEL).has(aPanelContents)) {
+ registerMenuPanel(aPanelContents, aArea) {
+ if (gBuildAreas.has(aArea) && gBuildAreas.get(aArea).has(aPanelContents)) {
return;
}
let document = aPanelContents.ownerDocument;
aPanelContents.toolbox = document.getElementById("navigator-toolbox");
aPanelContents.customizationTarget = aPanelContents;
this.addPanelCloseListeners(this._getPanelForNode(aPanelContents));
- let placements = gPlacements.get(CustomizableUI.AREA_PANEL);
- this.buildArea(CustomizableUI.AREA_PANEL, placements, aPanelContents);
- this.notifyListeners("onAreaNodeRegistered", CustomizableUI.AREA_PANEL, aPanelContents);
+ let placements = gPlacements.get(aArea);
+ this.buildArea(aArea, placements, aPanelContents);
+ this.notifyListeners("onAreaNodeRegistered", aArea, aPanelContents);
for (let child of aPanelContents.children) {
if (child.localName != "toolbarbutton") {
if (child.localName == "toolbaritem") {
this.ensureButtonContextMenu(child, aPanelContents);
}
continue;
}
this.ensureButtonContextMenu(child, aPanelContents);
child.setAttribute("wrap", "true");
}
- this.registerBuildArea(CustomizableUI.AREA_PANEL, aPanelContents);
+ this.registerBuildArea(aArea, aPanelContents);
},
onWidgetAdded(aWidgetId, aArea, aPosition) {
this.insertNode(aWidgetId, aArea, aPosition, true);
if (!gResetting) {
this._clearPreviousUIState();
}
@@ -1484,18 +1490,19 @@ var CustomizableUIInternal = {
// XXXunf Need to think this through more, and formalize.
Services.obs.notifyObservers(aNode,
"customizedui-widget-command",
aWidget.id);
}
} else if (aWidget.type == "view") {
let ownerWindow = aNode.ownerGlobal;
let area = this.getPlacementOfWidget(aNode.id).area;
+ let areaType = CustomizableUI.getAreaType(area);
let anchor = aNode;
- if (area != CustomizableUI.AREA_PANEL) {
+ if (areaType != CustomizableUI.TYPE_MENU_PANEL) {
let wrapper = this.wrapWidget(aWidget.id).forWindow(ownerWindow);
if (wrapper && !wrapper.overflowed && wrapper.anchor) {
this.hidePanelForNode(aNode);
anchor = wrapper.anchor;
}
}
ownerWindow.PanelUI.showSubView(aWidget.viewId, anchor, area);
@@ -2146,17 +2153,18 @@ var CustomizableUIInternal = {
}
this.notifyListeners("onWidgetCreated", widget.id);
if (widget.defaultArea) {
let addToDefaultPlacements = false;
let area = gAreas.get(widget.defaultArea);
if (!CustomizableUI.isBuiltinToolbar(widget.defaultArea) &&
- widget.defaultArea != CustomizableUI.AREA_PANEL) {
+ widget.defaultArea != CustomizableUI.AREA_PANEL &&
+ widget.defaultArea != CustomizableUI.AREA_FIXED_OVERFLOW_PANEL) {
addToDefaultPlacements = true;
}
if (addToDefaultPlacements) {
if (area.has("defaultPlacements")) {
area.get("defaultPlacements").push(widget.id);
} else {
area.set("defaultPlacements", [widget.id]);
@@ -2820,16 +2828,21 @@ this.CustomizableUI = {
AREA_BOOKMARKS: "PersonalToolbar",
/**
* Constant reference to the ID of the addon-bar toolbar shim.
* Do not use, this will be removed as soon as reasonably possible.
* @deprecated
*/
AREA_ADDONBAR: "addon-bar",
/**
+ * Constant reference to the ID of the non-dymanic (fixed) list in the overflow panel.
+ */
+ AREA_FIXED_OVERFLOW_PANEL: "widget-overflow-fixed-list",
+
+ /**
* Constant indicating the area is a menu panel.
*/
TYPE_MENU_PANEL: "menu-panel",
/**
* Constant indicating the area is a toolbar.
*/
TYPE_TOOLBAR: "toolbar",
@@ -3040,20 +3053,21 @@ this.CustomizableUI = {
* with it, until the area has been registered.
*/
registerToolbarNode(aToolbar, aExistingChildren) {
CustomizableUIInternal.registerToolbarNode(aToolbar, aExistingChildren);
},
/**
* Register the menu panel node. This method should not be called by anyone
* apart from the built-in PanelUI.
- * @param aPanel the panel DOM node being registered.
+ * @param aPanelContents the panel contents DOM node being registered.
+ * @param aArea the area for which to register this node.
*/
- registerMenuPanel(aPanel) {
- CustomizableUIInternal.registerMenuPanel(aPanel);
+ registerMenuPanel(aPanelContents, aArea) {
+ CustomizableUIInternal.registerMenuPanel(aPanelContents, aArea);
},
/**
* Unregister a customizable area. The inverse of registerArea.
*
* Unregistering an area will remove all the (removable) widgets in the
* area, which will return to the panel, and destroy all other traces
* of the area within CustomizableUI. Note that this means the *contents*
* of the area's DOM nodes will be moved to the panel or removed, but
@@ -4145,18 +4159,21 @@ OverflowableToolbar.prototype = {
}
},
_onPanelHiding(aEvent) {
this._chevron.open = false;
this._panel.removeEventListener("dragover", this);
this._panel.removeEventListener("dragend", this);
let doc = aEvent.target.ownerDocument;
- let contextMenu = doc.getElementById(this._panel.getAttribute("context"));
- gELS.removeSystemEventListener(contextMenu, "command", this, true);
+ let contextMenuId = this._panel.getAttribute("context");
+ if (contextMenuId) {
+ let contextMenu = doc.getElementById(contextMenuId);
+ gELS.removeSystemEventListener(contextMenu, "command", this, true);
+ }
},
onOverflow(aEvent) {
// The rangeParent check is here because of bug 1111986 and ensuring that
// overflow events from the bookmarks toolbar items or similar things that
// manage their own overflow don't trigger an overflow on the entire toolbar
if (!this._enabled ||
(aEvent && aEvent.target != this._toolbar.customizationTarget) ||
--- a/browser/components/customizableui/CustomizableWidgets.jsm
+++ b/browser/components/customizableui/CustomizableWidgets.jsm
@@ -1001,56 +1001,59 @@ const CustomizableWidgets = [
} catch (e) {
Cu.reportError("Failed to set the intl.charset.detector preference.");
}
// Prepare a browser page reload with a changed charset.
window.BrowserCharsetReload();
}
},
onCreated(aNode) {
- const kPanelId = "PanelUI-popup";
let document = aNode.ownerDocument;
let updateButton = () => {
if (this.maybeDisableMenu(document))
aNode.setAttribute("disabled", "true");
else
aNode.removeAttribute("disabled");
};
- if (this.currentArea == CustomizableUI.AREA_PANEL) {
- let panel = document.getElementById(kPanelId);
- panel.addEventListener("popupshowing", updateButton);
+ let getPanel = () => {
+ let {PanelUI} = document.ownerGlobal;
+ if (PanelUI.overflowContents) {
+ return document.getElementById("widget-overflow");
+ }
+ return PanelUI.panel;
+ }
+
+ if (CustomizableUI.getAreaType(this.currentArea) == CustomizableUI.TYPE_MENU_PANEL) {
+ getPanel().addEventListener("popupshowing", updateButton);
}
let listener = {
onWidgetAdded: (aWidgetId, aArea) => {
if (aWidgetId != this.id)
return;
- if (aArea == CustomizableUI.AREA_PANEL) {
- let panel = document.getElementById(kPanelId);
- panel.addEventListener("popupshowing", updateButton);
+ if (CustomizableUI.getAreaType(aArea) == CustomizableUI.TYPE_MENU_PANEL) {
+ getPanel().addEventListener("popupshowing", updateButton);
}
},
onWidgetRemoved: (aWidgetId, aPrevArea) => {
if (aWidgetId != this.id)
return;
aNode.removeAttribute("disabled");
- if (aPrevArea == CustomizableUI.AREA_PANEL) {
- let panel = document.getElementById(kPanelId);
- panel.removeEventListener("popupshowing", updateButton);
+ if (CustomizableUI.getAreaType(aPrevArea) == CustomizableUI.TYPE_MENU_PANEL) {
+ getPanel().removeEventListener("popupshowing", updateButton);
}
},
onWidgetInstanceRemoved: (aWidgetId, aDoc) => {
if (aWidgetId != this.id || aDoc != document)
return;
CustomizableUI.removeListener(listener);
- let panel = aDoc.getElementById(kPanelId);
- panel.removeEventListener("popupshowing", updateButton);
+ getPanel().removeEventListener("popupshowing", updateButton);
}
};
CustomizableUI.addListener(listener);
if (!this.charsetInfo) {
this.charsetInfo = CharsetMenu.getData();
}
}
}, {
--- a/browser/components/customizableui/DragPositionManager.jsm
+++ b/browser/components/customizableui/DragPositionManager.jsm
@@ -374,39 +374,39 @@ AreaPositionManager.prototype = {
rv = rv[aDirection + "Sibling"];
} while (rv && rv.getAttribute("hidden") == "true")
return rv;
}
}
var DragPositionManager = {
start(aWindow) {
- let areas = CustomizableUI.areas.filter((area) => CustomizableUI.getAreaType(area) != "toolbar");
+ let areas = [CustomizableUI.AREA_PANEL];
areas = areas.map((area) => CustomizableUI.getCustomizeTargetForArea(area, aWindow));
areas.push(aWindow.document.getElementById(kPaletteId));
for (let areaNode of areas) {
let positionManager = gManagers.get(areaNode);
if (positionManager) {
positionManager.update(areaNode);
} else {
gManagers.set(areaNode, new AreaPositionManager(areaNode));
}
}
},
add(aWindow, aArea, aContainer) {
- if (CustomizableUI.getAreaType(aArea) != "toolbar") {
+ if (aArea != CustomizableUI.AREA_PANEL) {
return;
}
gManagers.set(aContainer, new AreaPositionManager(aContainer));
},
remove(aWindow, aArea, aContainer) {
- if (CustomizableUI.getAreaType(aArea) != "toolbar") {
+ if (aArea != CustomizableUI.AREA_PANEL) {
return;
}
gManagers.delete(aContainer);
},
stop() {
gManagers = new WeakMap();
--- a/browser/components/customizableui/content/panelUI.inc.xul
+++ b/browser/components/customizableui/content/panelUI.inc.xul
@@ -378,16 +378,18 @@
type="arrow"
noautofocus="true"
position="bottomcenter topright"
hidden="true">
<panelmultiview mainViewId="widget-overflow-mainView">
<panelview id="widget-overflow-mainView"
context="toolbar-context-menu">
<vbox id="widget-overflow-scroller">
+ <vbox id="widget-overflow-fixed-list" class="widget-overflow-list" hidden="true"/>
+ <toolbarseparator id="widget-overflow-fixed-separator" hidden="true"/>
<vbox id="widget-overflow-list" class="widget-overflow-list"
overflowfortoolbar="nav-bar"/>
</vbox>
</panelview>
</panelmultiview>
</panel>
<panel id="customization-tipPanel"
--- a/browser/components/customizableui/content/panelUI.js
+++ b/browser/components/customizableui/content/panelUI.js
@@ -32,23 +32,28 @@ const PanelUI = {
contents: "PanelUI-contents",
mainView: gPhotonStructure ? "appMenu-mainView" : "PanelUI-mainView",
multiView: gPhotonStructure ? "appMenu-multiView" : "PanelUI-multiView",
helpView: "PanelUI-helpView",
menuButton: "PanelUI-menu-button",
panel: gPhotonStructure ? "appMenu-popup" : "PanelUI-popup",
notificationPanel: "PanelUI-notification-popup",
scroller: "PanelUI-contents-scroller",
- footer: "PanelUI-footer"
+ footer: "PanelUI-footer",
+
+ overflowFixedList: gPhotonStructure ? "widget-overflow-fixed-list" : "",
};
},
_initialized: false,
init() {
for (let [k, v] of Object.entries(this.kElements)) {
+ if (!v) {
+ continue;
+ }
// Need to do fresh let-bindings per iteration
let getKey = k;
let id = v;
this.__defineGetter__(getKey, function() {
delete this[getKey];
return this[getKey] = document.getElementById(id);
});
}
@@ -65,16 +70,22 @@ const PanelUI = {
window.addEventListener("fullscreen", this);
window.matchMedia("(-moz-overlay-scrollbars)").addListener(this._overlayScrollListenerBoundFn);
CustomizableUI.addListener(this);
for (let event of this.kEvents) {
this.notificationPanel.addEventListener(event, this);
}
+ if (gPhotonStructure) {
+ this.overflowFixedList.hidden = false;
+ this.overflowFixedList.nextSibling.hidden = false;
+ CustomizableUI.registerMenuPanel(this.overflowFixedList, CustomizableUI.AREA_FIXED_OVERFLOW_PANEL);
+ }
+
this._initialized = true;
},
_eventListenersAdded: false,
_ensureEventListenersAdded() {
if (this._eventListenersAdded)
return;
this._addEventListeners();
@@ -380,21 +391,21 @@ const PanelUI = {
let paddingLeft = cstyle.paddingLeft;
let paddingRight = cstyle.paddingRight;
let calcStr = [widthStr, this._scrollWidth,
paddingLeft, paddingRight].join(" + ");
this.scroller.style.width = "calc(" + calcStr + ")";
}
if (aCustomizing) {
- CustomizableUI.registerMenuPanel(this.contents);
+ CustomizableUI.registerMenuPanel(this.contents, CustomizableUI.AREA_PANEL);
} else {
this.beginBatchUpdate();
try {
- CustomizableUI.registerMenuPanel(this.contents);
+ CustomizableUI.registerMenuPanel(this.contents, CustomizableUI.AREA_PANEL);
} finally {
this.endBatchUpdate();
}
}
this._updateQuitTooltip();
this.panel.hidden = false;
this._isReady = true;
}.bind(this)).then(null, Cu.reportError);
--- a/browser/themes/shared/customizableui/panelUI.inc.css
+++ b/browser/themes/shared/customizableui/panelUI.inc.css
@@ -1198,16 +1198,24 @@ menuitem.panel-subview-footer@menuStateA
padding-bottom: 4px;
}
/* Disabled (empty) item is always alone and never has an icon, so fix its left padding */
#BMB_bookmarksPopup menupopup[emptyplacesresult] .bookmark-item.subviewbutton {
padding-left: 6px;
}
+/* Yeah, the ids are ugly, but this should be reasonably performant, and
+ * using a tagname as the last item would be less so.
+ */
+#widget-overflow-fixed-list:empty + #widget-overflow-fixed-separator {
+ display: none;
+}
+
+#widget-overflow-scroller > toolbarseparator,
.PanelUI-subView menuseparator,
.PanelUI-subView toolbarseparator,
.cui-widget-panelview menuseparator {
-moz-appearance: none;
min-height: 0;
border-top: 1px solid var(--panel-separator-color);
border-bottom: none;
margin: 6px 0;
@@ -1423,17 +1431,17 @@ toolbarpaletteitem[haswideitem][place="p
}
#widget-overflow-scroller {
max-height: 30em;
margin-top: 10px;
margin-bottom: 10px;
}
-#widget-overflow-list {
+.widget-overflow-list {
width: @menuPanelWidth@;
padding-left: 10px;
padding-right: 10px;
}
toolbaritem[overflowedItem=true],
.widget-overflow-list .toolbarbutton-1 {
width: 100%;
@@ -1450,17 +1458,17 @@ toolbaritem[overflowedItem=true],
}
.widget-overflow-list .toolbarbutton-1:not(.toolbarbutton-combined) > .toolbarbutton-text,
.widget-overflow-list .toolbarbutton-1 > .toolbarbutton-menubutton-button > .toolbarbutton-text {
text-align: start;
padding-inline-start: .5em;
}
-#widget-overflow-list > .toolbaritem-combined-buttons {
+.widget-overflow-list > .toolbaritem-combined-buttons {
min-height: 28px;
}
.widget-overflow-list .toolbarbutton-1 > .toolbarbutton-menubutton-button::after {
content: "";
display: -moz-box;
width: 1px;
height: 18px;