зеркало из https://github.com/mozilla/gecko-dev.git
Bug 865926 - Allow the nav-bar to overflow toolbaritems into an overflow panel. r=mconley.
This commit is contained in:
Родитель
92b1661f1f
Коммит
b84e035950
|
@ -108,6 +108,15 @@ toolbar[printpreview="true"] {
|
|||
-moz-box-ordinal-group: 50;
|
||||
}
|
||||
|
||||
toolbar[overflowable] > .customization-target {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
toolbar[customizing][overflowable] > .overflow-button,
|
||||
toolbar[overflowable]:not([overflowing]) > .overflow-button {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#TabsToolbar {
|
||||
-moz-box-ordinal-group: 100;
|
||||
}
|
||||
|
|
|
@ -502,15 +502,17 @@
|
|||
aria-label="&navbarCmd.label;"
|
||||
fullscreentoolbar="true" mode="icons" customizable="true"
|
||||
iconsize="large"
|
||||
defaultset="unified-back-forward-button,urlbar-container,reload-button,stop-button,search-container,webrtc-status-button,bookmarks-menu-button,downloads-button,home-button,window-controls"
|
||||
defaultset="unified-back-forward-button,urlbar-container,reload-button,stop-button,search-container,webrtc-status-button,bookmarks-menu-button,downloads-button,home-button"
|
||||
customizationtarget="nav-bar-customizationtarget"
|
||||
overflowbutton="nav-bar-overflow-button"
|
||||
context="toolbar-context-menu">
|
||||
|
||||
<hbox id="nav-bar-customizationtarget" class="customization-target" flex="0">
|
||||
<hbox id="nav-bar-customizationtarget" class="customization-target" flex="1">
|
||||
<toolbaritem id="unified-back-forward-button" class="chromeclass-toolbar-additional"
|
||||
context="backForwardMenu" removable="false"
|
||||
forwarddisabled="true"
|
||||
title="&backForwardItem.title;">
|
||||
title="&backForwardItem.title;"
|
||||
nooverflow="true">
|
||||
<toolbarbutton id="back-button" class="toolbarbutton-1"
|
||||
label="&backCmd.label;"
|
||||
command="Browser:BackOrBackDuplicate"
|
||||
|
@ -531,7 +533,7 @@
|
|||
</toolbaritem>
|
||||
|
||||
<toolbaritem id="urlbar-container" align="center" flex="400" persist="width" combined="true"
|
||||
title="&locationItem.title;" class="chromeclass-location" removable="false">
|
||||
title="&locationItem.title;" class="chromeclass-location" removable="false" nooverflow="true">
|
||||
<textbox id="urlbar" flex="1"
|
||||
placeholder="&urlbar.placeholder2;"
|
||||
type="autocomplete"
|
||||
|
@ -623,12 +625,14 @@
|
|||
label="&reloadCmd.label;" removable="true"
|
||||
command="Browser:ReloadOrDuplicate"
|
||||
onclick="checkForMiddleClick(this, event);"
|
||||
tooltiptext="&reloadButton.tooltip;"/>
|
||||
tooltiptext="&reloadButton.tooltip;"
|
||||
nooverflow="true"/>
|
||||
|
||||
<toolbarbutton id="stop-button" class="toolbarbutton-1 chromeclass-toolbar-additional"
|
||||
label="&stopCmd.label;" removable="true"
|
||||
command="Browser:Stop"
|
||||
tooltiptext="&stopButton.tooltip;"/>
|
||||
tooltiptext="&stopButton.tooltip;"
|
||||
nooverflow="true"/>
|
||||
|
||||
<toolbarbutton id="webrtc-status-button"
|
||||
class="toolbarbutton-1 chromeclass-toolbar-additional"
|
||||
|
@ -636,7 +640,8 @@
|
|||
hidden="true"
|
||||
orient="horizontal"
|
||||
label="&webrtcIndicatorButton.label;"
|
||||
tooltiptext="&webrtcIndicatorButton.tooltip;">
|
||||
tooltiptext="&webrtcIndicatorButton.tooltip;"
|
||||
nooverflow="true">
|
||||
<menupopup onpopupshowing="WebrtcIndicator.fillPopup(this);"
|
||||
onpopuphiding="WebrtcIndicator.clearPopup(this);"
|
||||
oncommand="WebrtcIndicator.menuCommand(event.target);"/>
|
||||
|
@ -645,6 +650,7 @@
|
|||
<toolbarbutton id="social-share-button"
|
||||
class="toolbarbutton-1 chromeclass-toolbar-additional"
|
||||
hidden="true"
|
||||
nooverflow="true"
|
||||
label="&sharePageCmd.label;"
|
||||
tooltiptext="&sharePageCmd.label;"
|
||||
command="Social:SharePage"/>
|
||||
|
@ -654,6 +660,7 @@
|
|||
removable="false"
|
||||
title="&socialToolbar.title;"
|
||||
hidden="true"
|
||||
nooverflow="true"
|
||||
skipintoolbarset="true"
|
||||
observes="socialActiveBroadcaster">
|
||||
<toolbarbutton id="social-provider-button"
|
||||
|
@ -703,6 +710,11 @@
|
|||
</toolbaritem>
|
||||
</hbox>
|
||||
|
||||
<toolbarbutton id="nav-bar-overflow-button"
|
||||
class="toolbarbutton-1 chromeclass-toolbar-additional chevron overflow-button"
|
||||
skipintoolbarset="true"
|
||||
tooltiptext="&navbarOverflow.label;"/>
|
||||
|
||||
<toolbaritem id="PanelUI-button"
|
||||
class="chromeclass-toolbar-additional"
|
||||
removable="false"
|
||||
|
@ -859,7 +871,7 @@
|
|||
|
||||
<toolbaritem id="search-container" title="&searchItem.title;"
|
||||
align="center" class="chromeclass-toolbar-additional"
|
||||
flex="100" persist="width" removable="true">
|
||||
flex="100" persist="width" removable="true" noautoclose="true">
|
||||
<searchbar id="searchbar" flex="1"/>
|
||||
</toolbaritem>
|
||||
|
||||
|
|
|
@ -81,3 +81,12 @@
|
|||
</panelsubview>
|
||||
</panelmultiview>
|
||||
</panel>
|
||||
|
||||
<panel id="widget-overflow"
|
||||
role="group"
|
||||
type="arrow"
|
||||
level="top"
|
||||
consumeoutsideclicks="true">
|
||||
<vbox id="widget-overflow-list">
|
||||
</vbox>
|
||||
</panel>
|
||||
|
|
|
@ -13,6 +13,8 @@ Cu.import("resource://gre/modules/NetUtil.jsm");
|
|||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "CustomizableWidgets",
|
||||
"resource:///modules/CustomizableWidgets.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "DeferredTask",
|
||||
"resource://gre/modules/DeferredTask.jsm");
|
||||
|
||||
const kNSXUL = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
|
||||
|
||||
|
@ -157,7 +159,8 @@ let CustomizableUIInternal = {
|
|||
});
|
||||
this.registerArea(CustomizableUI.AREA_NAVBAR, {
|
||||
legacy: true,
|
||||
type: CustomizableUI.TYPE_TOOLBAR
|
||||
type: CustomizableUI.TYPE_TOOLBAR,
|
||||
overflowable: true
|
||||
});
|
||||
this.registerArea(CustomizableUI.AREA_MENUBAR, {
|
||||
legacy: true,
|
||||
|
@ -246,6 +249,10 @@ let CustomizableUIInternal = {
|
|||
this.restoreStateForArea(area, legacyState);
|
||||
}
|
||||
|
||||
if (areaProperties.has("overflowable")) {
|
||||
aToolbar.overflowable = new OverflowableToolbar(aToolbar);
|
||||
}
|
||||
|
||||
this.registerBuildArea(area, aToolbar);
|
||||
|
||||
let placements = gPlacements.get(area);
|
||||
|
@ -538,10 +545,15 @@ let CustomizableUIInternal = {
|
|||
gBuildWindows.delete(aWindow);
|
||||
let document = aWindow.document;
|
||||
|
||||
for (let [, area] of gBuildAreas) {
|
||||
for (let node of area) {
|
||||
for (let [areaId, areaNodes] of gBuildAreas) {
|
||||
let areaProperties = gAreas.get(areaId);
|
||||
for (let node of areaNodes) {
|
||||
if (node.ownerDocument == document) {
|
||||
area.delete(node);
|
||||
if (areaProperties.has("overflowable")) {
|
||||
node.overflowable.uninit();
|
||||
node.overflowable = null;
|
||||
}
|
||||
areaNodes.delete(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1746,6 +1758,182 @@ function XULWidgetSingleWrapper(aWidgetId, aNode) {
|
|||
Object.freeze(this);
|
||||
}
|
||||
|
||||
const LAZY_RESIZE_INTERVAL_MS = 20;
|
||||
|
||||
function OverflowableToolbar(aToolbarNode) {
|
||||
this._toolbar = aToolbarNode;
|
||||
this._target = aToolbarNode.customizationTarget;
|
||||
let chevronId = this._toolbar.getAttribute("overflowbutton");
|
||||
let doc = this._toolbar.ownerDocument;
|
||||
this._chevron = doc.getElementById(chevronId);
|
||||
this._panel = doc.getElementById("widget-overflow");
|
||||
this._list = doc.getElementById("widget-overflow-list");
|
||||
this._collapsed = [];
|
||||
this._enabled = true;
|
||||
|
||||
this._toolbar.setAttribute("overflowable", "true");
|
||||
this._toolbar.customizationTarget.addEventListener("overflow", this);
|
||||
let window = doc.defaultView;
|
||||
window.addEventListener("resize", this);
|
||||
window.gNavToolbox.addEventListener("customizationstarting", this);
|
||||
window.gNavToolbox.addEventListener("aftercustomization", this);
|
||||
this._chevron.addEventListener("command", this);
|
||||
this._panel.addEventListener("popuphiding", this);
|
||||
|
||||
// The toolbar could initialize in an overflowed state, in which case
|
||||
// the 'overflow' event may have been fired before the handler was registered.
|
||||
this._onOverflow();
|
||||
}
|
||||
|
||||
OverflowableToolbar.prototype = {
|
||||
|
||||
uninit: function() {
|
||||
this._disable();
|
||||
|
||||
this._toolbar.removeAttribute("overflowable");
|
||||
this._toolbar.customizationTarget.removeEventListener("overflow", this);
|
||||
let window = this._toolbar.ownerDocument.defaultView;
|
||||
window.removeEventListener("resize", this);
|
||||
window.gNavToolbox.removeEventListener("customizationstarting", this);
|
||||
window.gNavToolbox.removeEventListener("aftercustomization", this);
|
||||
this._chevron.removeEventListener("command", this);
|
||||
this._panel.removeEventListener("popuphiding", this);
|
||||
},
|
||||
|
||||
handleEvent: function(aEvent) {
|
||||
switch(aEvent.type) {
|
||||
case "overflow":
|
||||
this._onOverflow();
|
||||
break;
|
||||
case "resize":
|
||||
this._onResize(aEvent);
|
||||
break;
|
||||
case "command":
|
||||
this._onClickChevron(aEvent);
|
||||
break;
|
||||
case "popuphiding":
|
||||
this._onPanelHiding(aEvent);
|
||||
break;
|
||||
case "mouseup":
|
||||
case "keypress":
|
||||
this._maybeAutoHidePanel(aEvent);
|
||||
break;
|
||||
case "customizationstarting":
|
||||
this._disable();
|
||||
break;
|
||||
case "aftercustomization":
|
||||
this._enable();
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
_onClickChevron: function(aEvent) {
|
||||
if (this._chevron.open)
|
||||
this._panel.hidePopup();
|
||||
else {
|
||||
let doc = aEvent.target.ownerDocument;
|
||||
let anchor = doc.getAnonymousElementByAttribute(this._chevron, "class", "toolbarbutton-icon");
|
||||
this._panel.openPopup(anchor || this._chevron, "bottomcenter topright");
|
||||
}
|
||||
this._chevron.open = !this._chevron.open;
|
||||
},
|
||||
|
||||
_onPanelHiding: function(aEvent) {
|
||||
this._chevron.open = false;
|
||||
},
|
||||
|
||||
_onOverflow: function() {
|
||||
if (!this._enabled)
|
||||
return;
|
||||
|
||||
let child = this._target.lastChild;
|
||||
|
||||
while(child && this._target.clientWidth < this._target.scrollWidth) {
|
||||
let prevChild = child.previousSibling;
|
||||
|
||||
if (!child.hasAttribute("nooverflow")) {
|
||||
this._collapsed.push({child: child, minSize: this._target.clientWidth});
|
||||
child.classList.add("overflowedItem");
|
||||
|
||||
child.addEventListener("mouseup", this);
|
||||
child.addEventListener("keypress", this);
|
||||
|
||||
this._list.insertBefore(child, this._list.firstChild);
|
||||
this._toolbar.setAttribute("overflowing", "true");
|
||||
}
|
||||
child = prevChild;
|
||||
};
|
||||
},
|
||||
|
||||
_maybeAutoHidePanel: function(aEvent) {
|
||||
LOG("_maybeAutoHidePanel: " + aEvent.type);
|
||||
|
||||
if (aEvent.currentTarget.hasAttribute("noautoclose"))
|
||||
return;
|
||||
|
||||
if (aEvent.type == "keypress" &&
|
||||
!(aEvent.keyCode == aEvent.DOM_VK_ENTER ||
|
||||
aEvent.keyCode == aEvent.DOM_VK_RETURN)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (aEvent.type == "mouseup" && aEvent.button != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._panel.hidePopup();
|
||||
},
|
||||
|
||||
_onResize: function(aEvent) {
|
||||
if (!this._lazyResizeHandler) {
|
||||
this._lazyResizeHandler = new DeferredTask(this._onLazyResize.bind(this),
|
||||
LAZY_RESIZE_INTERVAL_MS);
|
||||
}
|
||||
this._lazyResizeHandler.start();
|
||||
},
|
||||
|
||||
_moveItemsBackToTheirOrigin: function(shouldMoveAllItems) {
|
||||
for (let i = this._collapsed.length - 1; i >= 0; i--) {
|
||||
let {child, minSize} = this._collapsed[i];
|
||||
|
||||
if (!shouldMoveAllItems &&
|
||||
this._target.clientWidth <= minSize) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._collapsed.pop();
|
||||
this._target.appendChild(child);
|
||||
child.classList.remove("overflowedItem");
|
||||
child.removeEventListener("mouseup", this);
|
||||
child.removeEventListener("keypress", this);
|
||||
}
|
||||
|
||||
if (!this._collapsed.length) {
|
||||
this._toolbar.removeAttribute("overflowing");
|
||||
}
|
||||
},
|
||||
|
||||
_onLazyResize: function() {
|
||||
if (!this._enabled)
|
||||
return;
|
||||
|
||||
this._moveItemsBackToTheirOrigin();
|
||||
},
|
||||
|
||||
_disable: function() {
|
||||
this._enabled = false;
|
||||
this._moveItemsBackToTheirOrigin(true);
|
||||
if (this._lazyResizeHandler) {
|
||||
this._lazyResizeHandler.cancel();
|
||||
}
|
||||
},
|
||||
|
||||
_enable: function() {
|
||||
this._enabled = true;
|
||||
this._onOverflow();
|
||||
}
|
||||
};
|
||||
|
||||
// When IDs contain special characters, we need to escape them for use with querySelector:
|
||||
function idToSelector(aId) {
|
||||
return "#" + aId.replace(/[ !"'#$%&\(\)*+\-,.\/:;<=>?@\[\\\]^`{|}~]/g, '\\$&');
|
||||
|
|
|
@ -153,6 +153,10 @@ CustomizeMode.prototype = {
|
|||
|
||||
this.resetButton.hidden = CustomizableUI.inDefaultState;
|
||||
|
||||
let customizableToolbars = document.querySelectorAll("toolbar[customizable=true]:not([autohide=true])");
|
||||
for (let toolbar of customizableToolbars)
|
||||
toolbar.setAttribute("customizing", true);
|
||||
|
||||
document.documentElement.setAttribute("customizing", true);
|
||||
this._customizing = true;
|
||||
},
|
||||
|
@ -255,6 +259,10 @@ CustomizeMode.prototype = {
|
|||
});
|
||||
documentElement.removeAttribute("customizing");
|
||||
|
||||
let customizableToolbars = document.querySelectorAll("toolbar[customizable=true]:not([autohide=true])");
|
||||
for (let toolbar of customizableToolbars)
|
||||
toolbar.removeAttribute("customizing");
|
||||
|
||||
let customizer = document.getElementById("customization-container");
|
||||
customizer.hidden = true;
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
<!ENTITY mainWindow.titlePrivateBrowsingSuffix "(Private Browsing)">
|
||||
|
||||
<!ENTITY appmenu.title "Customize and Control &brandFullName;">
|
||||
<!ENTITY navbarOverflow.label "More tools…">
|
||||
|
||||
<!-- Tab context menu -->
|
||||
<!ENTITY reloadTab.label "Reload Tab">
|
||||
|
|
|
@ -68,6 +68,22 @@
|
|||
z-index: 1;
|
||||
}
|
||||
|
||||
#nav-bar-overflow-button {
|
||||
-moz-image-region: rect(-5px, 12px, 11px, -4px);
|
||||
}
|
||||
|
||||
#widget-overflow-list > .overflowedItem {
|
||||
width: 100%;
|
||||
min-height: 36px;
|
||||
background-repeat: no-repeat;
|
||||
background-position: 0 center;
|
||||
}
|
||||
|
||||
#widget-overflow-list > .overflowedItem > .toolbarbutton-text {
|
||||
-moz-padding-start: 10px;
|
||||
text-align: start;
|
||||
}
|
||||
|
||||
#personal-bookmarks {
|
||||
min-height: 29px;
|
||||
}
|
||||
|
|
|
@ -112,6 +112,22 @@ toolbox[tabsontop=true] > toolbar:not(#TabsToolbar):not(#nav-bar):not(:-moz-lwth
|
|||
background-color: -moz-mac-chrome-inactive;
|
||||
}
|
||||
|
||||
#nav-bar-overflow-button {
|
||||
-moz-image-region: rect(-5px, 12px, 11px, -4px);
|
||||
}
|
||||
|
||||
#widget-overflow-list > .overflowedItem {
|
||||
width: 100%;
|
||||
min-height: 36px;
|
||||
background-repeat: no-repeat;
|
||||
background-position: 0 center;
|
||||
}
|
||||
|
||||
#widget-overflow-list > .overflowedItem > .toolbarbutton-text {
|
||||
-moz-padding-start: 10px;
|
||||
text-align: start;
|
||||
}
|
||||
|
||||
/* ----- BOOKMARK TOOLBAR ----- */
|
||||
|
||||
#personal-bookmarks {
|
||||
|
|
|
@ -180,10 +180,12 @@ panelsubview toolbarbutton > .toolbarbutton-text,
|
|||
panelmainview toolbarbutton,
|
||||
panelsubview toolbarbutton,
|
||||
#customizationui-widget-panel toolbarbutton,
|
||||
#widget-overflow-list > toolbarbutton,
|
||||
.customizationmode-button {
|
||||
-moz-appearance: none;
|
||||
padding: 2px 6px;
|
||||
background: hsla(210,32%,93%,0) padding-box;
|
||||
background-color: hsla(210,32%,93%,0);
|
||||
background-clip: padding-box;
|
||||
border-radius: 2px;
|
||||
border: 1px solid;
|
||||
border-color: hsla(210,54%,20%,0) hsla(210,54%,20%,0) hsla(210,54%,20%,0);
|
||||
|
@ -197,6 +199,7 @@ panelsubview toolbarbutton,
|
|||
panelmainview toolbarbutton:not([disabled]):not([checked]):not([open]):not(:active):hover,
|
||||
panelsubview toolbarbutton:not([disabled]):not([checked]):not([open]):not(:active):hover,
|
||||
#customizationui-widget-panel toolbarbutton:not([disabled]):not([checked]):not([open]):not(:active):hover,
|
||||
#widget-overflow-list > toolbarbutton:not([disabled]):not([checked]):not([open]):not(:active):hover,
|
||||
#PanelUI-mainView .PanelUI-pageControls toolbarbutton,
|
||||
.customizationmode-button,
|
||||
#PanelUI-mainView #PanelUI-customize-btn {
|
||||
|
@ -210,7 +213,8 @@ panelsubview toolbarbutton:not([disabled]):not([checked]):not([open]):not(:activ
|
|||
panelmainview toolbarbutton:not([disabled]):-moz-any([open],[checked],:hover:active),
|
||||
panelsubview toolbarbutton:not([disabled]):-moz-any([open],[checked],:hover:active),
|
||||
.customizationmode-button:hover:active,
|
||||
#customizationui-widget-panel toolbarbutton:not([disabled]):-moz-any([open],[checked],:hover:active) {
|
||||
#customizationui-widget-panel toolbarbutton:not([disabled]):-moz-any([open],[checked],:hover:active),
|
||||
#widget-overflow-list > toolbarbutton:not([disabled]):-moz-any([open],[checked],:hover:active) {
|
||||
background-image: -moz-linear-gradient(hsla(0,0%,100%,.6), hsla(0,0%,100%,.1));
|
||||
background-color: hsla(210,54%,20%,.15);
|
||||
border-color: hsla(210,54%,20%,.3) hsla(210,54%,20%,.35) hsla(210,54%,20%,.4);
|
||||
|
|
|
@ -106,6 +106,22 @@
|
|||
z-index: 1;
|
||||
}
|
||||
|
||||
#nav-bar-overflow-button {
|
||||
-moz-image-region: rect(-5px, 12px, 11px, -4px);
|
||||
}
|
||||
|
||||
#widget-overflow-list > .overflowedItem {
|
||||
width: 100%;
|
||||
min-height: 36px;
|
||||
background-repeat: no-repeat;
|
||||
background-position: 0 center;
|
||||
}
|
||||
|
||||
#widget-overflow-list > .overflowedItem > .toolbarbutton-text {
|
||||
-moz-padding-start: 10px;
|
||||
text-align: start;
|
||||
}
|
||||
|
||||
#personal-bookmarks {
|
||||
min-height: 24px;
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче