--- a/browser/components/extensions/ext-utils.js
+++ b/browser/components/extensions/ext-utils.js
@@ -118,17 +118,17 @@ class BasePopup {
}
destroy() {
this.extension.forgetOnClose(this);
this.destroyed = true;
this.browserLoadedDeferred.reject(new Error("Popup destroyed"));
return this.browserReady.then(() => {
- this.destroyBrowser(this.browser);
+ this.destroyBrowser(this.browser, true);
this.browser.remove();
this.viewNode.removeEventListener(this.DESTROY_EVENT, this);
this.viewNode.style.maxHeight = "";
if (this.panel) {
this.panel.style.removeProperty("--arrowpanel-background");
this.panel.style.removeProperty("--panel-arrow-image-vertical");
@@ -136,26 +136,29 @@ class BasePopup {
BasePopup.instances.get(this.window).delete(this.extension);
this.browser = null;
this.viewNode = null;
});
}
- destroyBrowser(browser) {
+ destroyBrowser(browser, finalize = false) {
let mm = browser.messageManager;
// If the browser has already been removed from the document, because the
- // popup was closed externally, there will be no message manager here.
+ // popup was closed externally, there will be no message manager here, so
+ // just replace our receiveMessage method with a stub.
if (mm) {
mm.removeMessageListener("DOMTitleChanged", this);
mm.removeMessageListener("Extension:BrowserBackgroundChanged", this);
mm.removeMessageListener("Extension:BrowserContentLoaded", this);
mm.removeMessageListener("Extension:BrowserResized", this);
mm.removeMessageListener("Extension:DOMWindowClose", this);
+ } else if (finalize) {
+ this.receiveMessage = () => {};
}
}
// Returns the name of the event fired on `viewNode` when the popup is being
// destroyed. This must be implemented by every subclass.
get DESTROY_EVENT() {
throw new Error("Not implemented");
}
@@ -223,45 +226,59 @@ class BasePopup {
this.browser = document.createElementNS(XUL_NS, "browser");
this.browser.setAttribute("type", "content");
this.browser.setAttribute("disableglobalhistory", "true");
this.browser.setAttribute("transparent", "true");
this.browser.setAttribute("class", "webextension-popup-browser");
this.browser.setAttribute("webextension-view-type", "popup");
this.browser.setAttribute("tooltip", "aHTMLTooltip");
+ if (this.extension.remote) {
+ this.browser.setAttribute("remote", "true");
+ }
+
// We only need flex sizing for the sake of the slide-in sub-views of the
// main menu panel, so that the browser occupies the full width of the view,
// and also takes up any extra height that's available to it.
this.browser.setAttribute("flex", "1");
// Note: When using noautohide panels, the popup manager will add width and
// height attributes to the panel, breaking our resize code, if the browser
// starts out smaller than 30px by 10px. This isn't an issue now, but it
// will be if and when we popup debugging.
+
+ let readyPromise;
+ if (this.extension.remote) {
+ readyPromise = promiseEvent(this.browser, "XULFrameLoaderCreated");
+ } else {
+ readyPromise = promiseEvent(this.browser, "load");
+ }
+
viewNode.appendChild(this.browser);
extensions.emit("extension-browser-inserted", this.browser);
let initBrowser = browser => {
let mm = browser.messageManager;
mm.addMessageListener("DOMTitleChanged", this);
mm.addMessageListener("Extension:BrowserBackgroundChanged", this);
mm.addMessageListener("Extension:BrowserContentLoaded", this);
mm.addMessageListener("Extension:BrowserResized", this);
mm.addMessageListener("Extension:DOMWindowClose", this, true);
};
if (!popupURL) {
- initBrowser(this.browser);
- return this.browser;
+ return readyPromise.then(() => {
+ initBrowser(this.browser);
+ return this.browser;
+ });
}
- return promiseEvent(this.browser, "load").then(() => {
+ return readyPromise.then(() => {
initBrowser(this.browser);
let mm = this.browser.messageManager;
mm.loadFrameScript(
"chrome://extensions/content/ext-browser-content.js", false);
mm.sendAsyncMessage("Extension:InitBrowser", {
@@ -362,18 +379,18 @@ class PanelPopup extends BasePopup {
destroy() {
super.destroy();
this.viewNode.remove();
}
closePopup() {
promisePopupShown(this.viewNode).then(() => {
- // Make sure we're not already destroyed.
- if (this.viewNode) {
+ // Make sure we're not already destroyed, or removed from the DOM.
+ if (this.viewNode && this.viewNode.hidePopup) {
this.viewNode.hidePopup();
}
});
}
}
class ViewPopup extends BasePopup {
constructor(extension, window, popupURL, browserStyle, fixedWidth) {
@@ -452,17 +469,17 @@ class ViewPopup extends BasePopup {
let screenBottom = win.screen.availTop + win.screen.availHeight;
this.extraHeight = {
bottom: Math.max(0, screenBottom - popupBottom),
top: Math.max(0, popupTop - win.screen.availTop),
};
// Create a new browser in the real popup.
let browser = this.browser;
- this.createBrowser(this.viewNode);
+ yield this.createBrowser(this.viewNode);
this.browser.swapDocShells(browser);
this.destroyBrowser(browser);
this.ignoreResizes = false;
if (this.dimensions) {
this.resizeBrowser(this.dimensions);
}