summaryrefslogtreecommitdiffstats
path: root/browser/components/customizableui/content/panelUI.xml
diff options
context:
space:
mode:
Diffstat (limited to 'browser/components/customizableui/content/panelUI.xml')
-rw-r--r--browser/components/customizableui/content/panelUI.xml509
1 files changed, 0 insertions, 509 deletions
diff --git a/browser/components/customizableui/content/panelUI.xml b/browser/components/customizableui/content/panelUI.xml
deleted file mode 100644
index 6893bd8ff..000000000
--- a/browser/components/customizableui/content/panelUI.xml
+++ /dev/null
@@ -1,509 +0,0 @@
-<?xml version="1.0"?>
-<!-- This Source Code Form is subject to the terms of the Mozilla Public
- - 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/. -->
-
-<bindings id="browserPanelUIBindings"
- xmlns="http://www.mozilla.org/xbl"
- xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
- xmlns:xbl="http://www.mozilla.org/xbl">
-
- <binding id="panelmultiview">
- <resources>
- <stylesheet src="chrome://browser/content/customizableui/panelUI.css"/>
- </resources>
- <content>
- <xul:box anonid="viewContainer" class="panel-viewcontainer" xbl:inherits="panelopen,viewtype,transitioning">
- <xul:stack anonid="viewStack" xbl:inherits="viewtype,transitioning" viewtype="main" class="panel-viewstack">
- <xul:vbox anonid="mainViewContainer" class="panel-mainview" xbl:inherits="viewtype"/>
-
- <!-- 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
- to revert to the mainView mode, whereupon PanelUI-click-capture then
- allows click events to go through it. -->
- <xul:vbox anonid="clickCapturer" class="panel-clickcapturer"/>
-
- <!-- We manually set display: none (via a CSS attribute selector) on the
- subviews that are not being displayed. We're using this over a deck
- because a deck assumes the size of its largest child, regardless of
- 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="panelview"/>
- </xul:vbox>
- </xul:stack>
- </xul:box>
- </content>
- <implementation implements="nsIDOMEventListener">
- <field name="_clickCapturer" readonly="true">
- document.getAnonymousElementByAttribute(this, "anonid", "clickCapturer");
- </field>
- <field name="_viewContainer" readonly="true">
- document.getAnonymousElementByAttribute(this, "anonid", "viewContainer");
- </field>
- <field name="_mainViewContainer" readonly="true">
- document.getAnonymousElementByAttribute(this, "anonid", "mainViewContainer");
- </field>
- <field name="_subViews" readonly="true">
- document.getAnonymousElementByAttribute(this, "anonid", "subViews");
- </field>
- <field name="_viewStack" readonly="true">
- document.getAnonymousElementByAttribute(this, "anonid", "viewStack");
- </field>
- <field name="_panel" readonly="true">
- this.parentNode;
- </field>
-
- <field name="_currentSubView">null</field>
- <field name="_anchorElement">null</field>
- <field name="_mainViewHeight">0</field>
- <field name="_subViewObserver">null</field>
- <field name="__transitioning">false</field>
- <field name="_ignoreMutations">false</field>
-
- <property name="showingSubView" readonly="true"
- onget="return this._viewStack.getAttribute('viewtype') == 'subview'"/>
- <property name="_mainViewId" onget="return this.getAttribute('mainViewId');" onset="this.setAttribute('mainViewId', val); return val;"/>
- <property name="_mainView" readonly="true"
- onget="return this._mainViewId ? document.getElementById(this._mainViewId) : null;"/>
- <property name="showingSubViewAsMainView" readonly="true"
- onget="return this.getAttribute('mainViewIsSubView') == 'true'"/>
-
- <property name="ignoreMutations">
- <getter>
- return this._ignoreMutations;
- </getter>
- <setter><![CDATA[
- this._ignoreMutations = val;
- if (!val && this._panel.state == "open") {
- if (this.showingSubView) {
- this._syncContainerWithSubView();
- } else {
- this._syncContainerWithMainView();
- }
- }
- ]]></setter>
- </property>
-
- <property name="_transitioning">
- <getter>
- return this.__transitioning;
- </getter>
- <setter><![CDATA[
- this.__transitioning = val;
- if (val) {
- this.setAttribute("transitioning", "true");
- } else {
- this.removeAttribute("transitioning");
- }
- ]]></setter>
- </property>
- <constructor><![CDATA[
- this._clickCapturer.addEventListener("click", this);
- this._panel.addEventListener("popupshowing", this);
- this._panel.addEventListener("popupshown", 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._mainViewObserver =
- new MutationObserver(this._syncContainerWithMainView.bind(this));
-
- this._mainViewContainer.setAttribute("panelid",
- this._panel.id);
-
- if (this._mainView) {
- this.setMainView(this._mainView);
- }
- this.setAttribute("viewtype", "main");
- ]]></constructor>
-
- <destructor><![CDATA[
- if (this._mainView) {
- this._mainView.removeAttribute("mainview");
- }
- this._mainViewObserver.disconnect();
- this._subViewObserver.disconnect();
- this._panel.removeEventListener("popupshowing", this);
- this._panel.removeEventListener("popupshown", 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) {
- let viewNode = this._currentSubView;
- let evt = document.createEvent("CustomEvent");
- evt.initCustomEvent("ViewHiding", true, true, viewNode);
- viewNode.dispatchEvent(evt);
-
- viewNode.removeAttribute("current");
- this._currentSubView = null;
-
- this._subViewObserver.disconnect();
-
- this._setViewContainerHeight(this._mainViewHeight);
-
- this.setAttribute("viewtype", "main");
- }
-
- this._shiftMainView();
- ]]></body>
- </method>
-
- <method name="showSubView">
- <parameter name="aViewId"/>
- <parameter name="aAnchor"/>
- <body><![CDATA[
- Task.spawn(function*() {
- let viewNode = this.querySelector("#" + aViewId);
- viewNode.setAttribute("current", true);
- // Emit the ViewShowing event so that the widget definition has a chance
- // to lazily populate the subview with things.
- let detail = {
- blockers: new Set(),
- addBlocker(aPromise) {
- this.blockers.add(aPromise);
- },
- };
-
- let evt = new CustomEvent("ViewShowing", { bubbles: true, cancelable: true, detail });
- viewNode.dispatchEvent(evt);
-
- let cancel = evt.defaultPrevented;
- if (detail.blockers.size) {
- try {
- let results = yield Promise.all(detail.blockers);
- cancel = cancel || results.some(val => val === false);
- } catch (e) {
- Components.utils.reportError(e);
- cancel = true;
- }
- }
-
- if (cancel) {
- return;
- }
-
- this._currentSubView = viewNode;
-
- // Now we have to transition the panel. There are a few parts to this:
- //
- // 1) The main view content gets shifted so that the center of the anchor
- // node is at the left-most edge of the panel.
- // 2) The subview deck slides in so that it takes up almost all of the
- // panel.
- // 3) If the subview is taller then the main panel contents, then the panel
- // must grow to meet that new height. Otherwise, it must shrink.
- //
- // All three of these actions make use of CSS transformations, so they
- // should all occur simultaneously.
- this.setAttribute("viewtype", "subview");
- this._shiftMainView(aAnchor);
-
- this._mainViewHeight = this._viewStack.clientHeight;
-
- let newHeight = this._heightOfSubview(viewNode, this._subViews);
- this._setViewContainerHeight(newHeight);
-
- this._subViewObserver.observe(viewNode, {
- attributes: true,
- characterData: true,
- childList: true,
- subtree: true
- });
- }.bind(this));
- ]]></body>
- </method>
-
- <method name="_setViewContainerHeight">
- <parameter name="aHeight"/>
- <body><![CDATA[
- let container = this._viewContainer;
- this._transitioning = true;
-
- let onTransitionEnd = () => {
- container.removeEventListener("transitionend", onTransitionEnd);
- this._transitioning = false;
- };
-
- container.addEventListener("transitionend", onTransitionEnd);
- container.style.height = `${aHeight}px`;
- ]]></body>
- </method>
-
- <method name="_shiftMainView">
- <parameter name="aAnchor"/>
- <body><![CDATA[
- if (aAnchor) {
- // We need to find the edge of the anchor, relative to the main 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._mainViewContainer.getBoundingClientRect();
- let center = aAnchor.clientWidth / 2;
- let direction = aAnchor.ownerDocument.defaultView.getComputedStyle(aAnchor, null).direction;
- let edge;
- if (direction == "ltr") {
- edge = anchorRect.left - mainViewRect.left;
- } else {
- edge = mainViewRect.right - anchorRect.right;
- }
-
- // If the anchor is an element on the far end of the mainView we
- // don't want to shift the mainView too far, we would reveal empty
- // space otherwise.
- let cstyle = window.getComputedStyle(document.documentElement, null);
- let exitSubViewGutterWidth =
- cstyle.getPropertyValue("--panel-ui-exit-subview-gutter-width");
- let maxShift = mainViewRect.width - parseInt(exitSubViewGutterWidth);
- let target = Math.min(maxShift, edge + center);
-
- let neg = direction == "ltr" ? "-" : "";
- this._mainViewContainer.style.transform = `translateX(${neg}${target}px)`;
- aAnchor.setAttribute("panel-multiview-anchor", true);
- } else {
- this._mainViewContainer.style.transform = "";
- if (this.anchorElement)
- this.anchorElement.removeAttribute("panel-multiview-anchor");
- }
- this.anchorElement = aAnchor;
- ]]></body>
- </method>
-
- <method name="handleEvent">
- <parameter name="aEvent"/>
- <body><![CDATA[
- if (aEvent.type.startsWith("popup") && aEvent.target != this._panel) {
- // Shouldn't act on e.g. context menus being shown from within the panel.
- return;
- }
- switch (aEvent.type) {
- case "click":
- if (aEvent.originalTarget == this._clickCapturer) {
- this.showMainView();
- }
- break;
- case "overflow":
- if (aEvent.target.localName == "vbox") {
- // 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");
- // Bug 941196 - The panel can get taller when opening a subview. Disabling
- // autoPositioning means that the panel won't jump around if an opened
- // subview causes the panel to exceed the dimensions of the screen in the
- // direction that the panel originally opened in. This property resets
- // every time the popup closes, which is why we have to set it each time.
- this._panel.autoPosition = false;
- this._syncContainerWithMainView();
-
- this._mainViewObserver.observe(this._mainView, {
- attributes: true,
- characterData: true,
- childList: true,
- subtree: true
- });
-
- break;
- case "popupshown":
- this._setMaxHeight();
- break;
- case "popuphidden":
- this.removeAttribute("panelopen");
- this._mainView.style.removeProperty("height");
- this.showMainView();
- this._mainViewObserver.disconnect();
- break;
- }
- ]]></body>
- </method>
-
- <method name="_shouldSetPosition">
- <body><![CDATA[
- return this.getAttribute("nosubviews") == "true";
- ]]></body>
- </method>
-
- <method name="_shouldSetHeight">
- <body><![CDATA[
- return this.getAttribute("nosubviews") != "true";
- ]]></body>
- </method>
-
- <method name="_setMaxHeight">
- <body><![CDATA[
- if (!this._shouldSetHeight())
- return;
-
- // Ignore the mutation that'll fire when we set the height of
- // the main view.
- this.ignoreMutations = true;
- this._mainView.style.height =
- this.getBoundingClientRect().height + "px";
- this.ignoreMutations = false;
- ]]></body>
- </method>
- <method name="_adjustContainerHeight">
- <body><![CDATA[
- if (!this.ignoreMutations && !this.showingSubView && !this._transitioning) {
- let height;
- if (this.showingSubViewAsMainView) {
- height = this._heightOfSubview(this._mainView);
- } else {
- height = this._mainView.scrollHeight;
- }
- this._viewContainer.style.height = height + "px";
- }
- ]]></body>
- </method>
- <method name="_syncContainerWithSubView">
- <body><![CDATA[
- // Check that this panel is still alive:
- if (!this._panel || !this._panel.parentNode) {
- return;
- }
-
- if (!this.ignoreMutations && this.showingSubView) {
- let newHeight = this._heightOfSubview(this._currentSubView, this._subViews);
- this._viewContainer.style.height = newHeight + "px";
- }
- ]]></body>
- </method>
- <method name="_syncContainerWithMainView">
- <body><![CDATA[
- // Check that this panel is still alive:
- if (!this._panel || !this._panel.parentNode) {
- return;
- }
-
- if (this._shouldSetPosition()) {
- this._panel.adjustArrowPosition();
- }
-
- if (this._shouldSetHeight()) {
- this._adjustContainerHeight();
- }
- ]]></body>
- </method>
-
- <!-- Call this when the height of one of your views (the main view or a
- subview) changes and you want the heights of the multiview and panel
- to be the same as the view's height.
- If the caller can give a hint of the expected height change with the
- optional aExpectedChange parameter, it prevents flicker. -->
- <method name="setHeightToFit">
- <parameter name="aExpectedChange"/>
- <body><![CDATA[
- // Set the max-height to zero, wait until the height is actually
- // updated, and then remove it. If it's not removed, weird things can
- // happen, like widgets in the panel won't respond to clicks even
- // though they're visible.
- let count = 5;
- let height = getComputedStyle(this).height;
- if (aExpectedChange)
- this.style.maxHeight = (parseInt(height) + aExpectedChange) + "px";
- else
- this.style.maxHeight = "0";
- let interval = setInterval(() => {
- if (height != getComputedStyle(this).height || --count == 0) {
- clearInterval(interval);
- this.style.removeProperty("max-height");
- }
- }, 0);
- ]]></body>
- </method>
-
- <method name="_heightOfSubview">
- <parameter name="aSubview"/>
- <parameter name="aContainerToCheck"/>
- <body><![CDATA[
- function getFullHeight(element) {
- // XXXgijs: unfortunately, scrollHeight rounds values, and there's no alternative
- // that works with overflow: auto elements. Fortunately for us,
- // we have exactly 1 (potentially) scrolling element in here (the subview body),
- // and rounding 1 value is OK - rounding more than 1 and adding them means we get
- // off-by-1 errors. Now we might be off by a subpixel, but we care less about that.
- // So, use scrollHeight *only* if the element is vertically scrollable.
- let height;
- let elementCS;
- if (element.scrollTopMax) {
- height = element.scrollHeight;
- // Bounding client rects include borders, scrollHeight doesn't:
- elementCS = win.getComputedStyle(element);
- height += parseFloat(elementCS.borderTopWidth) +
- parseFloat(elementCS.borderBottomWidth);
- } else {
- height = element.getBoundingClientRect().height;
- if (height > 0) {
- elementCS = win.getComputedStyle(element);
- }
- }
- if (elementCS) {
- // Include margins - but not borders or paddings because they
- // were dealt with above.
- height += parseFloat(elementCS.marginTop) + parseFloat(elementCS.marginBottom);
- }
- return height;
- }
- let win = aSubview.ownerDocument.defaultView;
- let body = aSubview.querySelector(".panel-subview-body");
- let height = getFullHeight(body || aSubview);
- if (body) {
- let header = aSubview.querySelector(".panel-subview-header");
- let footer = aSubview.querySelector(".panel-subview-footer");
- height += (header ? getFullHeight(header) : 0) +
- (footer ? getFullHeight(footer) : 0);
- }
- if (aContainerToCheck) {
- let containerCS = win.getComputedStyle(aContainerToCheck);
- height += parseFloat(containerCS.paddingTop) + parseFloat(containerCS.paddingBottom);
- }
- return Math.ceil(height);
- ]]></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>