Bug 873867 - Adjust panelmultiview binding to allow easy swapping of mainviews. r=Unfocused.

This commit is contained in:
Mike Conley 2013-05-31 11:07:36 -04:00
parent 09fb037999
commit e9ca89261d
7 changed files with 147 additions and 59 deletions

View File

@ -27,6 +27,23 @@ toolbar[customizable="true"]:not([nowindowdrag="true"]) {
-moz-binding: url("chrome://browser/content/customizableui/toolbar.xml#toolbar-menubar-autohide");
}
panelmultiview {
-moz-binding: url("chrome://browser/content/customizableui/panelUI.xml#panelmultiview");
}
panelview {
-moz-binding: url("chrome://browser/content/customizableui/panelUI.xml#panelview");
-moz-box-orient: vertical;
}
.panel-mainview {
transition: transform 150ms;
}
panelview:not([mainview]):not([current]) {
display: none;
}
tabbrowser {
-moz-binding: url("chrome://browser/content/tabbrowser.xml#tabbrowser");
}

View File

@ -6,6 +6,7 @@
pointer-events: none;
}
.panel-mainview,
.panel-viewcontainer,
.panel-viewstack {
overflow: hidden;

View File

@ -7,8 +7,8 @@
type="arrow"
level="top"
consumeoutsideclicks="true">
<panelmultiview id="PanelUI-multiView">
<panelmainview id="PanelUI-mainView">
<panelmultiview id="PanelUI-multiView" mainViewId="PanelUI-mainView">
<panelview id="PanelUI-mainView" flex="1">
<vbox class="PanelUI-pageControls" pack="center">
<hbox class="PanelUI-editControls">
<toolbarbutton id="PanelUI-cut-btn" flex="1"
@ -58,9 +58,9 @@
<toolbarbutton id="PanelUI-customize-btn" label="&appMenuCustomize.label;"
command="cmd_CustomizeToolbars"/>
</footer>
</panelmainview>
</panelview>
<panelsubview id="PanelUI-history" flex="1">
<panelview id="PanelUI-history" flex="1">
<label value="&appMenuHistory.label;"/>
<toolbarbutton id="appMenuClearRecentHistory"
label="&appMenuHistory.clearRecent.label;"
@ -73,12 +73,12 @@
id="PanelUI-historyMore"
class="text-link"
onclick="PlacesCommandHook.showPlacesOrganizer('History'); PanelUI.hide();"/>
</panelsubview>
</panelview>
<panelsubview id="PanelUI-help" flex="1">
<panelview id="PanelUI-help" flex="1">
<label value="&helpMenu.label;"/>
<vbox id="PanelUI-helpItems"/>
</panelsubview>
</panelview>
</panelmultiview>
</panel>

View File

@ -70,8 +70,8 @@ const PanelUI = {
* @param aMainView
* The mainView node to put back into place.
*/
replaceMainView: function(aMainView) {
this.multiView.insertBefore(aMainView, this.multiView.firstChild);
setMainView: function(aMainView) {
this.multiView.setMainView(aMainView);
},
/**
@ -180,17 +180,27 @@ const PanelUI = {
viewNode.dispatchEvent(evt);
let tempPanel = document.createElement("panel");
tempPanel.appendChild(viewNode);
tempPanel.setAttribute("type", "arrow");
tempPanel.setAttribute("id", "customizationui-widget-panel");
document.getElementById(CustomizableUI.AREA_NAVBAR).appendChild(tempPanel);
let multiView = document.createElement("panelmultiview");
tempPanel.appendChild(multiView);
multiView.setMainView(viewNode);
tempPanel.addEventListener("command", PanelUI._onWidgetPanelCommand);
tempPanel.addEventListener("popuphidden", function panelRemover() {
tempPanel.removeEventListener("popuphidden", panelRemover);
tempPanel.removeEventListener("command", PanelUI._onWidgetPanelCommand);
this.multiView.appendChild(viewNode);
tempPanel.parentElement.removeChild(tempPanel);
}.bind(this));
tempPanel.openPopup(aAnchor, "bottomcenter topright");
let iconAnchor =
document.getAnonymousElementByAttribute(aAnchor, "class",
"toolbarbutton-icon");
tempPanel.openPopup(iconAnchor || aAnchor, "bottomcenter topright");
}
},
@ -208,9 +218,14 @@ const PanelUI = {
.getFormattedString("zoomReset.label", [Math.floor(ZoomManager.zoom * 100)]));
},
// Button onclick handler which hides the whole PanelUI
_onHelpViewClick: function(aEvent) {
if (aEvent.button == 0 && !aEvent.target.hasAttribute("disabled")) {
_onWidgetPanelCommand: function(aEvent) {
if (!aEvent.originalTarget.hasAttribute("noautoclose")) {
aEvent.currentTarget.hidePopup();
}
},
_onHelpViewCommand: function(aEvent) {
if (!aEvent.originalTarget.hasAttribute("noautoclose")) {
PanelUI.hide();
}
},
@ -246,10 +261,10 @@ const PanelUI = {
}
items.appendChild(fragment);
this.addEventListener("click", PanelUI._onHelpViewClick, false);
this.addEventListener("command", PanelUI._onHelpViewCommand);
},
_onHelpViewHide: function(aEvent) {
this.removeEventListener("click", PanelUI._onHelpViewClick);
this.removeEventListener("command", PanelUI._onHelpViewCommand);
}
};

View File

@ -45,7 +45,7 @@
<content>
<xul:box anonid="viewContainer" class="panel-viewcontainer" xbl:inherits="panelopen">
<xul:stack anonid="viewStack" view="main" class="panel-viewstack">
<children includes="panelmainview"/>
<xul:vbox anonid="mainViewContainer" class="panel-mainview"/>
<!-- Used to capture click events over the PanelUI-mainView if we're in
subview mode. That way, any click on the PanelUI-mainView causes us
@ -59,7 +59,7 @@
whether or not it is shown. That's not good for our case, since we
want to allow each subview to be uniquely sized. -->
<xul:vbox anonid="subViews" class="panel-subviews" xbl:inherits="panelopen">
<children includes="panelsubview"/>
<children includes="panelview"/>
</xul:vbox>
</xul:stack>
</xul:box>
@ -71,8 +71,8 @@
<field name="_viewContainer" readonly="true">
document.getAnonymousElementByAttribute(this, "anonid", "viewContainer");
</field>
<field name="_mainView" readonly="true">
this.querySelector("panelmainview");
<field name="_mainViewContainer" readonly="true">
document.getAnonymousElementByAttribute(this, "anonid", "mainViewContainer");
</field>
<field name="_subViews" readonly="true">
document.getAnonymousElementByAttribute(this, "anonid", "subViews");
@ -88,28 +88,63 @@
<field name="_anchorElement">null</field>
<field name="_mainViewHeight">0</field>
<field name="_subViewObserver">null</field>
<field name="_transitioning">false</field>
<property name="showingSubView" readonly="true"
onget="return this._viewStack.getAttribute('view') == 'subview'"/>
<property name="_mainViewId" onget="return this.getAttribute('mainViewId');" onset="this.setAttribute('mainViewId', val); return val;"/>
<property name="_mainView" readonly="true"
onget="return document.getElementById(this._mainViewId);"/>
<constructor><![CDATA[
this._clickCapturer.addEventListener("click", this);
this._panel.addEventListener("popupshowing", this);
this._panel.addEventListener("popuphidden", this);
this._subViews.addEventListener("overflow", this);
this._mainViewContainer.addEventListener("overflow", this);
// Get a MutationObserver ready to react to subview size changes. We
// only attach this MutationObserver when a subview is being displayed.
this._subViewObserver =
new MutationObserver(this._syncContainerWithSubView.bind(this));
this._subViews.addEventListener("overflow", this);
this._mainViewObserver =
new MutationObserver(this._syncContainerWithMainView.bind(this));
this._mainViewContainer.setAttribute("panelid",
this._panel.id);
if (this._mainView) {
this.setMainView(this._mainView);
}
]]></constructor>
<destructor><![CDATA[
if (this._mainView) {
this._mainView.removeAttribute("mainview");
}
this._mainViewObserver.disconnect();
this._subViewObserver.disconnect();
this._panel.removeEventListener("popupshowing", this);
this._panel.removeEventListener("popuphidden", this);
this._subViews.removeEventListener("overflow", this);
this._mainViewContainer.removeEventListener("overflow", this);
this._clickCapturer.removeEventListener("click", this);
]]></destructor>
<method name="setMainView">
<parameter name="aNewMainView"/>
<body><![CDATA[
if (this._mainView) {
this._mainViewObserver.disconnect();
this._subViews.appendChild(this._mainView);
this._mainView.removeAttribute("mainview");
}
this._mainViewId = aNewMainView.id;
aNewMainView.setAttribute("mainview", "true");
this._mainViewContainer.appendChild(aNewMainView);
]]></body>
</method>
<method name="showMainView">
<body><![CDATA[
if (this.showingSubView) {
@ -121,12 +156,26 @@
viewNode.removeAttribute("current");
this._currentSubView = null;
this._viewContainer.style.height = this._mainViewHeight + "px";
this._subViewObserver.disconnect();
this._transitioning = true;
this._viewContainer.addEventListener("transitionend", function trans() {
this._viewContainer.removeEventListener("transitionend", trans);
this._transitioning = false;
}.bind(this));
this._viewContainer.style.height = this._mainViewHeight + "px";
this._viewStack.setAttribute("view", "main");
}
this._mainViewObserver.observe(this._mainView, {
attributes: true,
characterData: true,
childList: true,
subtree: true
});
this._shiftMainView();
]]></body>
</method>
@ -161,7 +210,14 @@
this._shiftMainView(aAnchor);
this._mainViewHeight = this._viewStack.clientHeight;
this._transitioning = true;
this._viewContainer.addEventListener("transitionend", function trans() {
this._viewContainer.removeEventListener("transitionend", trans);
this._transitioning = false;
}.bind(this));
this._viewContainer.style.height = this._subViews.scrollHeight + "px";
this._subViewObserver.observe(viewNode, {
attributes: true,
characterData: true,
@ -179,14 +235,14 @@
// panel. Then we need to add half the width of the anchor. This is the
// target that we need to transition to.
let anchorRect = aAnchor.getBoundingClientRect();
let mainViewRect = this._mainView.getBoundingClientRect();
let mainViewRect = this._mainViewContainer.getBoundingClientRect();
let leftEdge = anchorRect.left - mainViewRect.left;
let center = aAnchor.clientWidth / 2;
let target = leftEdge + center;
this._mainView.style.transform = "translateX(-" + target + "px)";
this._mainViewContainer.style.transform = "translateX(-" + target + "px)";
aAnchor.classList.add("panel-multiview-anchor");
} else {
this._mainView.style.transform = "";
this._mainViewContainer.style.transform = "";
if (this.anchorElement)
this.anchorElement.classList.remove("panel-multiview-anchor");
}
@ -204,8 +260,12 @@
}
break;
case "overflow":
// Resize the subview on the next tick.
setTimeout(this._syncContainerWithSubView.bind(this), 0);
// Resize the right view on the next tick.
if (this.showingSubView) {
setTimeout(this._syncContainerWithSubView.bind(this), 0);
} else if (!this.transitioning) {
setTimeout(this._syncContainerWithMainView.bind(this), 0);
}
break;
case "popupshowing":
this.setAttribute("panelopen", "true");
@ -221,16 +281,35 @@
<method name="_syncContainerWithSubView">
<body><![CDATA[
this._viewContainer.style.height = this._subViews.scrollHeight + "px";
if (this.showingSubView) {
this._viewContainer.style.height =
this._subViews.scrollHeight + "px";
}
]]></body>
</method>
<method name="_syncContainerWithMainView">
<body><![CDATA[
this._viewContainer.style.height = this._mainView.scrollHeight + "px";
if (!this.showingSubView && !this._transitioning) {
this._viewContainer.style.height =
this._mainViewContainer.scrollHeight + "px";
}
]]></body>
</method>
</implementation>
</binding>
<binding id="panelview">
<implementation>
<property name="panelMultiView" readonly="true">
<getter><![CDATA[
if (this.parentNode.localName != "panelmultiview") {
return document.getBindingParent(this.parentNode);
}
return this.parentNode;
]]></getter>
</property>
</implementation>
</binding>
</bindings>

View File

@ -198,7 +198,7 @@ CustomizeMode.prototype = {
// Let everybody in this window know that we're starting to
// exit customization mode.
this.dispatchToolboxEvent("customizationending");
window.PanelUI.replaceMainView(window.PanelUI.mainView);
window.PanelUI.setMainView(window.PanelUI.mainView);
let browser = document.getElementById("browser");
browser.parentNode.selectedPanel = browser;

View File

@ -2,24 +2,6 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
panelmultiview {
-moz-binding: url("chrome://browser/content/customizableui/panelUI.xml#panelmultiview");
}
panelmainview,
panelsubview {
display: -moz-box;
-moz-box-orient: vertical;
}
panelmainview {
transition: transform 150ms;
}
panelmultiview > panelsubview:not([current]) {
display: none;
}
.panel-subviews {
background-image: linear-gradient(to bottom, white 1px, rgba(255, 255, 255, 0) 15px);
background-color: -moz-dialog;
@ -79,13 +61,13 @@ panelmultiview > panelsubview:not([current]) {
.PanelUI-zoomControls,
#PanelUI-contents,
.PanelUI-footer,
#customizationui-widget-panel {
.panel-mainview:not([panelid="PanelUI-popup"]) {
max-width: @menuPanelWidth@;
padding: .5em 1em;
}
#PanelUI-contents[type="list"] toolbarbutton > .toolbarbutton-text,
panelsubview toolbarbutton > .toolbarbutton-text,
panelview:not([mainview]) .toolbarbutton-text,
#customizationui-widget-panel toolbarbutton > .toolbarbutton-text {
text-align: start;
-moz-padding-start: 8px;
@ -177,9 +159,7 @@ panelsubview toolbarbutton > .toolbarbutton-text,
display: none;
}
panelmainview toolbarbutton,
panelsubview toolbarbutton,
#customizationui-widget-panel toolbarbutton,
panelview toolbarbutton,
#widget-overflow-list > toolbarbutton,
.customizationmode-button {
-moz-appearance: none;
@ -196,9 +176,7 @@ panelsubview toolbarbutton,
transition-duration: 150ms;
}
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,
panelview 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,
@ -210,10 +188,8 @@ panelsubview toolbarbutton:not([disabled]):not([checked]):not([open]):not(:activ
0 0 2px hsla(210,54%,20%,.1);
}
panelmainview toolbarbutton:not([disabled]):-moz-any([open],[checked],:hover:active),
panelsubview toolbarbutton:not([disabled]):-moz-any([open],[checked],:hover:active),
panelview 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),
#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);