Bug 1370580 - Part 1 - Ensure that the overflow rules are set the exact same way for the temporary panel as for the appMenu panel. r?Gijs draft
authorMike de Boer <mdeboer@mozilla.com>
Fri, 16 Jun 2017 15:41:57 +0200
changeset 595606 bccc6b264b2f321f9240525e263b58f98784891f
parent 595489 fe809f57bf2287bb937c3422ed03a63740b3448b
child 633744 76a9c9bf4617405adea478cba3273707489ea55d
push id64381
push usermdeboer@mozilla.com
push dateFri, 16 Jun 2017 13:45:41 +0000
reviewersGijs
bugs1370580
milestone56.0a1
Bug 1370580 - Part 1 - Ensure that the overflow rules are set the exact same way for the temporary panel as for the appMenu panel. r?Gijs These rules are set explicitly to allow the two views to be displayed next to each other briefly when the slide-in transition starts. This patch also applies the last remaining photon styles to the temporary panel, which is used by the new Library widget as well. MozReview-Commit-ID: 45aYzVHwRYv
browser/components/customizableui/PanelMultiView.jsm
browser/components/customizableui/content/panelUI.js
browser/components/customizableui/test/browser_947914_button_history.js
browser/components/extensions/ext-browserAction.js
browser/components/extensions/test/browser/browser_ext_popup_corners.js
browser/themes/shared/customizableui/panelUI.inc.css
--- a/browser/components/customizableui/PanelMultiView.jsm
+++ b/browser/components/customizableui/PanelMultiView.jsm
@@ -162,19 +162,16 @@ this.PanelMultiView = class {
   }
   set _mainViewId(val) {
     this.node.setAttribute("mainViewId", val);
     return val;
   }
   get _mainView() {
     return this._mainViewId ? this.document.getElementById(this._mainViewId) : null;
   }
-  get showingSubViewAsMainView() {
-    return this.node.getAttribute("mainViewIsSubView") == "true";
-  }
 
   get _transitioning() {
     return this.__transitioning;
   }
   set _transitioning(val) {
     this.__transitioning = val;
     if (val) {
       this.node.setAttribute("transitioning", "true");
@@ -455,50 +452,52 @@ this.PanelMultiView = class {
       let detail = {
         blockers: new Set(),
         addBlocker(aPromise) {
           this.blockers.add(aPromise);
         },
       };
 
       // Make sure that new panels always have a title set.
+      let cancel = false;
       if (this.panelViews && aAnchor) {
         if (aAnchor && !viewNode.hasAttribute("title"))
           viewNode.setAttribute("title", aAnchor.getAttribute("label"));
         viewNode.classList.add("PanelUI-subView");
         let custWidget = CustomizableWidgets.find(widget => widget.viewId == viewNode.id);
         if (custWidget) {
           if (custWidget.onInit)
             custWidget.onInit(aAnchor);
-          custWidget.onViewShowing({ target: aAnchor, detail });
+          custWidget.onViewShowing({ target: viewNode, preventDefault: () => cancel = true, detail });
         }
       }
-      viewNode.setAttribute("current", true);
       if (this.panelViews && this._mainViewWidth)
         viewNode.style.maxWidth = viewNode.style.minWidth = this._mainViewWidth + "px";
 
       let evt = new window.CustomEvent("ViewShowing", { bubbles: true, cancelable: true, detail });
       viewNode.dispatchEvent(evt);
 
-      let cancel = evt.defaultPrevented;
+      if (!cancel)
+        cancel = evt.defaultPrevented;
       if (detail.blockers.size) {
         try {
           let results = await Promise.all(detail.blockers);
           cancel = cancel || results.some(val => val === false);
         } catch (e) {
           Cu.reportError(e);
           cancel = true;
         }
       }
 
       if (cancel) {
         return;
       }
 
       this._currentSubView = viewNode;
+      viewNode.setAttribute("current", true);
       if (this.panelViews) {
         this.node.setAttribute("viewtype", "subview");
         if (!playTransition)
           this.descriptionHeightWorkaround(viewNode);
       }
 
       // Now we have to transition the panel. There are a few parts to this:
       //
@@ -620,29 +619,31 @@ this.PanelMultiView = class {
 
                 if (!reverse)
                   viewNode.style.removeProperty("margin-inline-start");
                 if (aAnchor)
                   aAnchor.removeAttribute("open");
 
                 this._viewContainer.removeAttribute("transition-reverse");
 
-                evt = new window.CustomEvent("ViewShown", { bubbles: true, cancelable: false });
-                viewNode.dispatchEvent(evt);
+                viewNode.dispatchEvent(new window.CustomEvent("ViewShown",
+                  { bubbles: true, cancelable: false }));
               }, { once: true });
             });
           }, { once: true });
         });
       } else if (!this.panelViews) {
         this._transitionHeight(() => {
           viewNode.setAttribute("current", true);
           this.node.setAttribute("viewtype", "subview");
           // Now that the subview is visible, we can check the height of the
           // description elements it contains.
           this.descriptionHeightWorkaround(viewNode);
+          viewNode.dispatchEvent(new window.CustomEvent("ViewShown",
+            { bubbles: true, cancelable: false }));
         });
         this._shiftMainView(aAnchor);
       }
     })().catch(e => Cu.reportError(e));
   }
 
   /**
    * Calculate the correct bounds of a panelview node offscreen to minimize the
--- a/browser/components/customizableui/content/panelUI.js
+++ b/browser/components/customizableui/content/panelUI.js
@@ -510,22 +510,24 @@ const PanelUI = {
       tempPanel.classList.toggle("cui-widget-panelWithFooter",
                                  viewNode.querySelector(".panel-subview-footer"));
 
       let multiView = document.createElement(gPhotonStructure ? "photonpanelmultiview" : "panelmultiview");
       multiView.setAttribute("id", "customizationui-widget-multiview");
       multiView.setAttribute("nosubviews", "true");
       multiView.setAttribute("viewCacheId", "appMenu-viewCache");
       if (gPhotonStructure) {
+        tempPanel.setAttribute("photon", true);
         multiView.setAttribute("mainViewId", viewNode.id);
         multiView.appendChild(viewNode);
       }
       tempPanel.appendChild(multiView);
-      multiView.setAttribute("mainViewIsSubView", "true");
-      multiView.setMainView(viewNode);
+      if (!gPhotonStructure) {
+        multiView.setMainView(viewNode);
+      }
       viewNode.classList.add("cui-widget-panelview");
 
       let viewShown = false;
       let panelRemover = () => {
         viewNode.classList.remove("cui-widget-panelview");
         if (viewShown) {
           CustomizableUI.removePanelCloseListeners(tempPanel);
           tempPanel.removeEventListener("popuphidden", panelRemover);
--- a/browser/components/customizableui/test/browser_947914_button_history.js
+++ b/browser/components/customizableui/test/browser_947914_button_history.js
@@ -9,17 +9,19 @@ add_task(async function() {
   info("Check history button existence and functionality");
 
   await PanelUI.show();
   info("Menu panel was opened");
 
   let historyButton = document.getElementById("history-panelmenu");
   ok(historyButton, "History button appears in Panel Menu");
 
+  let historyPanel = document.getElementById("PanelUI-history");
+  let promise = BrowserTestUtils.waitForEvent(historyPanel, "ViewShown");
   historyButton.click();
-  let historyPanel = document.getElementById("PanelUI-history");
+  await promise;
   ok(historyPanel.getAttribute("current"), "History Panel is in view");
 
   let panelHiddenPromise = promisePanelHidden(window);
   PanelUI.hide();
   await panelHiddenPromise
   info("Menu panel was closed");
 });
--- a/browser/components/extensions/ext-browserAction.js
+++ b/browser/components/extensions/ext-browserAction.js
@@ -125,16 +125,17 @@ this.browserAction = class extends Exten
       label: this.defaults.title || this.extension.name,
       tooltiptext: this.defaults.title || "",
       defaultArea: this.defaults.area,
 
       onBeforeCreated: document => {
         let view = document.createElementNS(XUL_NS, "panelview");
         view.id = this.viewId;
         view.setAttribute("flex", "1");
+        view.setAttribute("extension", true);
 
         document.getElementById("PanelUI-multiView").appendChild(view);
         document.addEventListener("popupshowing", this);
       },
 
       onDestroyed: document => {
         document.removeEventListener("popupshowing", this);
 
@@ -166,16 +167,20 @@ this.browserAction = class extends Exten
         let popupURL = this.getProperty(tab, "popup");
         this.tabManager.addActiveTabPermission(tab);
 
         // Popups are shown only if a popup URL is defined; otherwise
         // a "click" event is dispatched. This is done for compatibility with the
         // Google Chrome onClicked extension API.
         if (popupURL) {
           try {
+            // FIXME: The line below needs to change eventually, but for now:
+            // ensure the view is _always_ visible _before_ `popup.attach()` is
+            // called. PanelMultiView.jsm dictates different behavior.
+            event.target.setAttribute("current", true);
             let popup = this.getPopup(document.defaultView, popupURL);
             event.detail.addBlocker(popup.attach(event.target));
           } catch (e) {
             Cu.reportError(e);
             event.preventDefault();
           }
         } else {
           // This isn't not a hack, but it seems to provide the correct behavior
--- a/browser/components/extensions/test/browser/browser_ext_popup_corners.js
+++ b/browser/components/extensions/test/browser/browser_ext_popup_corners.js
@@ -1,13 +1,15 @@
 /* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
 /* vim: set sts=2 sw=2 et tw=80: */
 "use strict";
 
 add_task(async function testPopupBorderRadius() {
+  await SpecialPowers.pushPrefEnv({set: [["browser.photon.structure.enabled", false]]});
+
   let extension = ExtensionTestUtils.loadExtension({
     background() {
       browser.tabs.query({active: true, currentWindow: true}, tabs => {
         browser.pageAction.show(tabs[0].id);
       });
     },
 
     manifest: {
--- a/browser/themes/shared/customizableui/panelUI.inc.css
+++ b/browser/themes/shared/customizableui/panelUI.inc.css
@@ -256,17 +256,18 @@ photonpanelmultiview .panel-subview-head
 }
 
 #appMenu-popup > arrowscrollbox > scrollbox,
 #PanelUI-popup > arrowscrollbox > scrollbox {
   overflow: visible;
 }
 
 #appMenu-popup > .panel-arrowcontainer > .panel-arrowcontent,
-#PanelUI-popup > .panel-arrowcontainer > .panel-arrowcontent {
+#PanelUI-popup > .panel-arrowcontainer > .panel-arrowcontent,
+panel[photon] > .panel-arrowcontainer > .panel-arrowcontent {
   overflow: hidden;
 }
 
 #PanelUI-popup > .panel-arrowcontainer > .panel-arrowcontent,
 .cui-widget-panel > .panel-arrowcontainer > .panel-arrowcontent > .popup-internal-box {
   padding: 0;
 }
 
@@ -333,27 +334,29 @@ panelview:not([mainview]) .toolbarbutton
 }
 
 .cui-widget-panel > .panel-arrowcontainer > .panel-arrowcontent {
   padding: 4px 0;
 }
 
 /* START photonpanelview adjustments */
 
-#appMenu-popup > .panel-arrowcontainer > .panel-arrowcontent {
+#appMenu-popup > .panel-arrowcontainer > .panel-arrowcontent,
+panel[photon] > .panel-arrowcontainer > .panel-arrowcontent {
   padding: 0;
   border-radius: 0;
 }
 
 photonpanelmultiview panelview {
   background: var(--arrowpanel-background);
   padding: 6px 0;
 }
 
-#appMenu-popup panelview {
+#appMenu-popup panelview,
+#customizationui-widget-multiview panelview:not([extension]) {
   min-width: @menuPanelWidth@;
 }
 
 photonpanelmultiview panelview[title] {
   padding-top: 0;
 }
 
 /* END photonpanelview adjustments */
@@ -2071,9 +2074,19 @@ photonpanelmultiview .PanelUI-subView .p
   display: none;
 }
 
 photonpanelmultiview .PanelUI-subView toolbarseparator {
   margin-inline-start: 0;
   margin-inline-end: 0;
 }
 
+photonpanelmultiview#customizationui-widget-multiview > .panel-viewcontainer {
+  overflow: hidden;
+}
+
+/* This is explicitly overriding the overflow properties set above. */
+photonpanelmultiview .cui-widget-panelview {
+  overflow-x: visible;
+  overflow-y: visible;
+}
+
 /* END photon adjustments */