зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1317101 - Part 7c: Run extension popups in a remote browser. r=aswan
MozReview-Commit-ID: CATeESBwj1J --HG-- extra : rebase_source : c83dbcabbafbe2884746d282de78d23f5e0edff6 extra : source : b7892d3fb0ca5268a252377ecbb44dfb1d289500
This commit is contained in:
Родитель
7d4520e4ec
Коммит
73f6cab403
|
@ -123,11 +123,13 @@ class BasePopup {
|
||||||
this.destroyed = true;
|
this.destroyed = true;
|
||||||
this.browserLoadedDeferred.reject(new Error("Popup destroyed"));
|
this.browserLoadedDeferred.reject(new Error("Popup destroyed"));
|
||||||
return this.browserReady.then(() => {
|
return this.browserReady.then(() => {
|
||||||
this.destroyBrowser(this.browser);
|
this.destroyBrowser(this.browser, true);
|
||||||
this.browser.remove();
|
this.browser.remove();
|
||||||
|
|
||||||
this.viewNode.removeEventListener(this.DESTROY_EVENT, this);
|
if (this.viewNode) {
|
||||||
this.viewNode.style.maxHeight = "";
|
this.viewNode.removeEventListener(this.DESTROY_EVENT, this);
|
||||||
|
this.viewNode.style.maxHeight = "";
|
||||||
|
}
|
||||||
|
|
||||||
if (this.panel) {
|
if (this.panel) {
|
||||||
this.panel.style.removeProperty("--arrowpanel-background");
|
this.panel.style.removeProperty("--arrowpanel-background");
|
||||||
|
@ -141,16 +143,19 @@ class BasePopup {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
destroyBrowser(browser) {
|
destroyBrowser(browser, finalize = false) {
|
||||||
let mm = browser.messageManager;
|
let mm = browser.messageManager;
|
||||||
// If the browser has already been removed from the document, because the
|
// 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) {
|
if (mm) {
|
||||||
mm.removeMessageListener("DOMTitleChanged", this);
|
mm.removeMessageListener("DOMTitleChanged", this);
|
||||||
mm.removeMessageListener("Extension:BrowserBackgroundChanged", this);
|
mm.removeMessageListener("Extension:BrowserBackgroundChanged", this);
|
||||||
mm.removeMessageListener("Extension:BrowserContentLoaded", this);
|
mm.removeMessageListener("Extension:BrowserContentLoaded", this);
|
||||||
mm.removeMessageListener("Extension:BrowserResized", this);
|
mm.removeMessageListener("Extension:BrowserResized", this);
|
||||||
mm.removeMessageListener("Extension:DOMWindowClose", this);
|
mm.removeMessageListener("Extension:DOMWindowClose", this);
|
||||||
|
} else if (finalize) {
|
||||||
|
this.receiveMessage = () => {};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -213,53 +218,73 @@ class BasePopup {
|
||||||
handleEvent(event) {
|
handleEvent(event) {
|
||||||
switch (event.type) {
|
switch (event.type) {
|
||||||
case this.DESTROY_EVENT:
|
case this.DESTROY_EVENT:
|
||||||
this.destroy();
|
if (!this.destroyed) {
|
||||||
|
this.destroy();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
createBrowser(viewNode, popupURL = null) {
|
createBrowser(viewNode, popupURL = null) {
|
||||||
let document = viewNode.ownerDocument;
|
let document = viewNode.ownerDocument;
|
||||||
this.browser = document.createElementNS(XUL_NS, "browser");
|
let browser = document.createElementNS(XUL_NS, "browser");
|
||||||
this.browser.setAttribute("type", "content");
|
browser.setAttribute("type", "content");
|
||||||
this.browser.setAttribute("disableglobalhistory", "true");
|
browser.setAttribute("disableglobalhistory", "true");
|
||||||
this.browser.setAttribute("transparent", "true");
|
browser.setAttribute("transparent", "true");
|
||||||
this.browser.setAttribute("class", "webextension-popup-browser");
|
browser.setAttribute("class", "webextension-popup-browser");
|
||||||
this.browser.setAttribute("webextension-view-type", "popup");
|
browser.setAttribute("webextension-view-type", "popup");
|
||||||
this.browser.setAttribute("tooltip", "aHTMLTooltip");
|
browser.setAttribute("tooltip", "aHTMLTooltip");
|
||||||
|
|
||||||
|
if (this.extension.remote) {
|
||||||
|
browser.setAttribute("remote", "true");
|
||||||
|
}
|
||||||
|
|
||||||
// We only need flex sizing for the sake of the slide-in sub-views of the
|
// 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,
|
// 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.
|
// and also takes up any extra height that's available to it.
|
||||||
this.browser.setAttribute("flex", "1");
|
browser.setAttribute("flex", "1");
|
||||||
|
|
||||||
// Note: When using noautohide panels, the popup manager will add width and
|
// Note: When using noautohide panels, the popup manager will add width and
|
||||||
// height attributes to the panel, breaking our resize code, if the browser
|
// 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
|
// starts out smaller than 30px by 10px. This isn't an issue now, but it
|
||||||
// will be if and when we popup debugging.
|
// will be if and when we popup debugging.
|
||||||
|
|
||||||
viewNode.appendChild(this.browser);
|
this.browser = browser;
|
||||||
|
|
||||||
extensions.emit("extension-browser-inserted", this.browser);
|
let readyPromise;
|
||||||
|
if (this.extension.remote) {
|
||||||
|
readyPromise = promiseEvent(browser, "XULFrameLoaderCreated");
|
||||||
|
} else {
|
||||||
|
readyPromise = promiseEvent(browser, "load");
|
||||||
|
}
|
||||||
|
|
||||||
let initBrowser = browser => {
|
viewNode.appendChild(browser);
|
||||||
|
|
||||||
|
extensions.emit("extension-browser-inserted", browser);
|
||||||
|
|
||||||
|
let setupBrowser = browser => {
|
||||||
let mm = browser.messageManager;
|
let mm = browser.messageManager;
|
||||||
mm.addMessageListener("DOMTitleChanged", this);
|
mm.addMessageListener("DOMTitleChanged", this);
|
||||||
mm.addMessageListener("Extension:BrowserBackgroundChanged", this);
|
mm.addMessageListener("Extension:BrowserBackgroundChanged", this);
|
||||||
mm.addMessageListener("Extension:BrowserContentLoaded", this);
|
mm.addMessageListener("Extension:BrowserContentLoaded", this);
|
||||||
mm.addMessageListener("Extension:BrowserResized", this);
|
mm.addMessageListener("Extension:BrowserResized", this);
|
||||||
mm.addMessageListener("Extension:DOMWindowClose", this, true);
|
mm.addMessageListener("Extension:DOMWindowClose", this, true);
|
||||||
|
return browser;
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!popupURL) {
|
if (!popupURL) {
|
||||||
initBrowser(this.browser);
|
// For remote browsers, we can't do any setup until the frame loader is
|
||||||
return this.browser;
|
// created. Non-remote browsers get a message manager immediately, so
|
||||||
|
// there's no need to wait for the load event.
|
||||||
|
if (this.extension.remote) {
|
||||||
|
return readyPromise.then(() => setupBrowser(browser));
|
||||||
|
}
|
||||||
|
return setupBrowser(browser);
|
||||||
}
|
}
|
||||||
|
|
||||||
return promiseEvent(this.browser, "load").then(() => {
|
return readyPromise.then(() => {
|
||||||
initBrowser(this.browser);
|
setupBrowser(browser);
|
||||||
|
let mm = browser.messageManager;
|
||||||
let mm = this.browser.messageManager;
|
|
||||||
|
|
||||||
mm.loadFrameScript(
|
mm.loadFrameScript(
|
||||||
"chrome://extensions/content/ext-browser-content.js", false);
|
"chrome://extensions/content/ext-browser-content.js", false);
|
||||||
|
@ -272,7 +297,7 @@ class BasePopup {
|
||||||
stylesheets: this.STYLESHEETS,
|
stylesheets: this.STYLESHEETS,
|
||||||
});
|
});
|
||||||
|
|
||||||
this.browser.loadURI(popupURL);
|
browser.loadURI(popupURL);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -363,12 +388,13 @@ class PanelPopup extends BasePopup {
|
||||||
destroy() {
|
destroy() {
|
||||||
super.destroy();
|
super.destroy();
|
||||||
this.viewNode.remove();
|
this.viewNode.remove();
|
||||||
|
this.viewNode = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
closePopup() {
|
closePopup() {
|
||||||
promisePopupShown(this.viewNode).then(() => {
|
promisePopupShown(this.viewNode).then(() => {
|
||||||
// Make sure we're not already destroyed.
|
// Make sure we're not already destroyed, or removed from the DOM.
|
||||||
if (this.viewNode) {
|
if (this.viewNode && this.viewNode.hidePopup) {
|
||||||
this.viewNode.hidePopup();
|
this.viewNode.hidePopup();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -391,6 +417,7 @@ class ViewPopup extends BasePopup {
|
||||||
this.ignoreResizes = true;
|
this.ignoreResizes = true;
|
||||||
|
|
||||||
this.attached = false;
|
this.attached = false;
|
||||||
|
this.shown = false;
|
||||||
this.tempPanel = panel;
|
this.tempPanel = panel;
|
||||||
|
|
||||||
this.browser.classList.add("webextension-preload-browser");
|
this.browser.classList.add("webextension-preload-browser");
|
||||||
|
@ -432,11 +459,13 @@ class ViewPopup extends BasePopup {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.destroyed) {
|
if (this.destroyed) {
|
||||||
|
CustomizableUI.hidePanelForNode(viewNode);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.attached = true;
|
this.attached = true;
|
||||||
|
|
||||||
|
|
||||||
// Store the initial height of the view, so that we never resize menu panel
|
// Store the initial height of the view, so that we never resize menu panel
|
||||||
// sub-views smaller than the initial height of the menu.
|
// sub-views smaller than the initial height of the menu.
|
||||||
this.viewHeight = this.viewNode.boxObject.height;
|
this.viewHeight = this.viewNode.boxObject.height;
|
||||||
|
@ -457,7 +486,7 @@ class ViewPopup extends BasePopup {
|
||||||
|
|
||||||
// Create a new browser in the real popup.
|
// Create a new browser in the real popup.
|
||||||
let browser = this.browser;
|
let browser = this.browser;
|
||||||
this.createBrowser(this.viewNode);
|
yield this.createBrowser(this.viewNode);
|
||||||
|
|
||||||
this.browser.swapDocShells(browser);
|
this.browser.swapDocShells(browser);
|
||||||
this.destroyBrowser(browser);
|
this.destroyBrowser(browser);
|
||||||
|
@ -470,6 +499,14 @@ class ViewPopup extends BasePopup {
|
||||||
this.tempPanel.remove();
|
this.tempPanel.remove();
|
||||||
this.tempPanel = null;
|
this.tempPanel = null;
|
||||||
|
|
||||||
|
this.shown = true;
|
||||||
|
|
||||||
|
if (this.destroyed) {
|
||||||
|
this.closePopup();
|
||||||
|
this.destroy();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
let event = new this.window.CustomEvent("WebExtPopupLoaded", {
|
let event = new this.window.CustomEvent("WebExtPopupLoaded", {
|
||||||
bubbles: true,
|
bubbles: true,
|
||||||
detail: {extension: this.extension},
|
detail: {extension: this.extension},
|
||||||
|
@ -494,8 +531,10 @@ class ViewPopup extends BasePopup {
|
||||||
}
|
}
|
||||||
|
|
||||||
closePopup() {
|
closePopup() {
|
||||||
if (this.attached) {
|
if (this.shown) {
|
||||||
CustomizableUI.hidePanelForNode(this.viewNode);
|
CustomizableUI.hidePanelForNode(this.viewNode);
|
||||||
|
} else if (this.attached) {
|
||||||
|
this.destroyed = true;
|
||||||
} else {
|
} else {
|
||||||
this.destroy();
|
this.destroy();
|
||||||
}
|
}
|
||||||
|
|
|
@ -82,7 +82,7 @@ function* testInArea(area) {
|
||||||
() => {
|
() => {
|
||||||
browser.test.log(`Set popup to "c" and click browser action. Expect popup "c".`);
|
browser.test.log(`Set popup to "c" and click browser action. Expect popup "c".`);
|
||||||
browser.browserAction.setPopup({popup: "popup-c.html"});
|
browser.browserAction.setPopup({popup: "popup-c.html"});
|
||||||
sendClick({expectEvent: false, expectPopup: "c", closePopup: false});
|
sendClick({expectEvent: false, expectPopup: "c", waitUntilClosed: true});
|
||||||
},
|
},
|
||||||
() => {
|
() => {
|
||||||
browser.test.log(`Set popup to "b" and click browser action. Expect popup "b".`);
|
browser.test.log(`Set popup to "b" and click browser action. Expect popup "b".`);
|
||||||
|
@ -120,7 +120,7 @@ function* testInArea(area) {
|
||||||
let expect = {};
|
let expect = {};
|
||||||
sendClick = ({expectEvent, expectPopup, runNextTest, waitUntilClosed, closePopup}, message = "send-click") => {
|
sendClick = ({expectEvent, expectPopup, runNextTest, waitUntilClosed, closePopup}, message = "send-click") => {
|
||||||
if (closePopup == undefined) {
|
if (closePopup == undefined) {
|
||||||
closePopup = true;
|
closePopup = !expectEvent;
|
||||||
}
|
}
|
||||||
|
|
||||||
expect = {event: expectEvent, popup: expectPopup, runNextTest, waitUntilClosed, closePopup};
|
expect = {event: expectEvent, popup: expectPopup, runNextTest, waitUntilClosed, closePopup};
|
||||||
|
@ -190,8 +190,11 @@ function* testInArea(area) {
|
||||||
CustomizableUI.addWidgetToArea(widget.id, area);
|
CustomizableUI.addWidgetToArea(widget.id, area);
|
||||||
}
|
}
|
||||||
if (expecting.waitUntilClosed) {
|
if (expecting.waitUntilClosed) {
|
||||||
|
yield new Promise(resolve => setTimeout(resolve, 0));
|
||||||
|
|
||||||
let panel = getBrowserActionPopup(extension);
|
let panel = getBrowserActionPopup(extension);
|
||||||
if (panel && panel.state != "closed") {
|
if (panel && panel.state != "closed") {
|
||||||
|
info("Popup is open. Waiting for close");
|
||||||
yield promisePopupHidden(panel);
|
yield promisePopupHidden(panel);
|
||||||
}
|
}
|
||||||
} else if (expecting.closePopupUsingWindow) {
|
} else if (expecting.closePopupUsingWindow) {
|
||||||
|
@ -204,9 +207,16 @@ function* testInArea(area) {
|
||||||
yield promisePopupHidden(panel);
|
yield promisePopupHidden(panel);
|
||||||
ok(true, "Panel is closed");
|
ok(true, "Panel is closed");
|
||||||
} else if (expecting.closePopup) {
|
} else if (expecting.closePopup) {
|
||||||
|
if (!getBrowserActionPopup(extension)) {
|
||||||
|
info("Waiting for panel");
|
||||||
|
yield awaitExtensionPanel(extension);
|
||||||
|
}
|
||||||
|
|
||||||
|
info("Closing for panel");
|
||||||
yield closeBrowserAction(extension);
|
yield closeBrowserAction(extension);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
info("Starting next test");
|
||||||
extension.sendMessage("next-test");
|
extension.sendMessage("next-test");
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|
|
@ -82,6 +82,10 @@ function* testExecuteBrowserActionWithOptions(options = {}) {
|
||||||
|
|
||||||
if (options.withPopup) {
|
if (options.withPopup) {
|
||||||
yield extension.awaitFinish("execute-browser-action-popup-opened");
|
yield extension.awaitFinish("execute-browser-action-popup-opened");
|
||||||
|
|
||||||
|
if (!getBrowserActionPopup(extension)) {
|
||||||
|
yield awaitExtensionPanel(extension);
|
||||||
|
}
|
||||||
yield closeBrowserAction(extension);
|
yield closeBrowserAction(extension);
|
||||||
} else {
|
} else {
|
||||||
yield extension.awaitFinish("execute-browser-action-on-clicked-fired");
|
yield extension.awaitFinish("execute-browser-action-on-clicked-fired");
|
||||||
|
|
Загрузка…
Ссылка в новой задаче