Bug 1437512 - Use a MutationObserver for disconnecting. draft
authorPaolo Amadini <paolo.mozmail@amadzone.org>
Tue, 13 Feb 2018 15:50:01 +0000
changeset 754454 8ce08f5bee74010f0568567f923fe63bd8f65fbf
parent 754453 e641153893d38345aec8691b974fbba1ac4e19bc
push id98875
push userpaolo.mozmail@amadzone.org
push dateTue, 13 Feb 2018 15:50:46 +0000
bugs1437512
milestone60.0a1
Bug 1437512 - Use a MutationObserver for disconnecting. MozReview-Commit-ID: 6ZDWYG1T6X2
browser/base/content/browser-pageActions.js
browser/components/customizableui/PanelMultiView.jsm
browser/components/customizableui/content/panelUI.js
--- a/browser/base/content/browser-pageActions.js
+++ b/browser/base/content/browser-pageActions.js
@@ -246,17 +246,17 @@ var BrowserPageActions = {
       iframeNode = document.createElement("iframe");
       iframeNode.setAttribute("type", "content");
       panelNode.appendChild(iframeNode);
     }
 
     let popupSet = document.getElementById("mainPopupSet");
     popupSet.appendChild(panelNode);
     panelNode.addEventListener("popuphidden", () => {
-      PanelMultiView.removePopup(panelNode);
+      panelNode.remove();
     }, { once: true });
 
     if (iframeNode) {
       panelNode.addEventListener("popupshowing", () => {
         action.onIframeShowing(iframeNode, panelNode);
       }, { once: true });
       panelNode.addEventListener("popuphiding", () => {
         action.onIframeHiding(iframeNode, panelNode);
--- a/browser/components/customizableui/PanelMultiView.jsm
+++ b/browser/components/customizableui/PanelMultiView.jsm
@@ -176,35 +176,16 @@ this.PanelMultiView = class extends this
     if (panelMultiViewNode) {
       this.forNode(panelMultiViewNode).hidePopup();
     } else {
       panelNode.hidePopup();
     }
   }
 
   /**
-   * Removes the specified <panel> from the document, ensuring that any
-   * <panelmultiview> node it contains is destroyed properly.
-   *
-   * If the panel does not contain a <panelmultiview>, it is removed directly.
-   * This allows consumers like page actions to accept different panel types.
-   */
-  static removePopup(panelNode) {
-    try {
-      let panelMultiViewNode = panelNode.querySelector("panelmultiview");
-      if (panelMultiViewNode) {
-        this.forNode(panelMultiViewNode).disconnect();
-      }
-    } finally {
-      // Make sure to remove the panel element even if disconnecting fails.
-      panelNode.remove();
-    }
-  }
-
-  /**
    * Ensures that when the specified window is closed all the <panelmultiview>
    * node it contains are destroyed properly.
    */
   static ensureUnloadHandlerRegistered(window) {
     if (gWindowsWithUnloadHandler.has(window)) {
       return;
     }
 
@@ -286,16 +267,24 @@ this.PanelMultiView = class extends this
     super(node);
     this._openPopupPromise = Promise.resolve(false);
     this._openPopupCancelCallback = () => {};
   }
 
   connect() {
     this.connected = true;
 
+    // This doesn't support moving the node to a different place.
+    this.observer = new this.window.MutationObserver(() => {
+      if (!this._panel.parentNode) {
+        this.disconnect();
+      }
+    });
+    this.observer.observe(this._panel.parentNode, { childList: true });
+
     PanelMultiView.ensureUnloadHandlerRegistered(this.window);
 
     let viewContainer = this._viewContainer =
       this.document.createElement("box");
     viewContainer.classList.add("panel-viewcontainer");
 
     let viewStack = this._viewStack = this.document.createElement("box");
     viewStack.classList.add("panel-viewstack");
@@ -350,16 +339,18 @@ this.PanelMultiView = class extends this
     });
   }
 
   disconnect() {
     // Guard against re-entrancy.
     if (!this.node || !this.connected)
       return;
 
+    this.observer.disconnect();
+
     this._cleanupTransitionPhase();
     if (this._ephemeral)
       this.hideAllViewsExcept(null);
     let mainView = this._mainView;
     if (mainView) {
       if (this._panelViewCache)
         this._panelViewCache.appendChild(mainView);
       mainView.removeAttribute("mainview");
@@ -369,17 +360,17 @@ this.PanelMultiView = class extends this
     this._panel.removeEventListener("mousemove", this);
     this._panel.removeEventListener("popupshowing", this);
     this._panel.removeEventListener("popuppositioned", this);
     this._panel.removeEventListener("popupshown", this);
     this._panel.removeEventListener("popuphidden", this);
     this.window.removeEventListener("keydown", this);
     this.node = this._openPopupPromise = this._openPopupCancelCallback =
       this._viewContainer = this._viewStack = this.__dwu =
-      this._panelViewCache = this._transitionDetails = null;
+      this._panelViewCache = this._transitionDetails = this.observer = null;
   }
 
   /**
    * Tries to open the panel associated with this PanelMultiView, and displays
    * the main view specified with the "mainViewId" attribute.
    *
    * The hidePopup method can be called while the operation is in progress to
    * prevent the panel from being displayed. View events may also cancel the
--- a/browser/components/customizableui/content/panelUI.js
+++ b/browser/components/customizableui/content/panelUI.js
@@ -438,17 +438,17 @@ const PanelUI = {
       let panelRemover = () => {
         viewNode.classList.remove("cui-widget-panelview");
         if (viewShown) {
           CustomizableUI.removePanelCloseListeners(tempPanel);
           tempPanel.removeEventListener("popuphidden", panelRemover);
         }
         aAnchor.open = false;
 
-        PanelMultiView.removePopup(tempPanel);
+        tempPanel.remove();
       };
 
       // Wait until all the tasks needed to show a view are done.
       PanelMultiView.forNode(multiView).connect();
       await multiView.currentShowPromise;
 
       if (!viewShown) {
         viewNode.removeEventListener("ViewShown", listener);