Bug 865926 - Allow the nav-bar to overflow toolbaritems into an overflow panel. r=mconley.

This commit is contained in:
Jared Wein 2013-05-23 09:40:55 -04:00
Родитель 92b1661f1f
Коммит b84e035950
10 изменённых файлов: 293 добавлений и 14 удалений

Просмотреть файл

@ -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;
}