зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1246034 - Part 1: [webext] Add a helper function to trigger a browserAction. r=jaws
MozReview-Commit-ID: JUW6oUpWiN4 --HG-- extra : rebase_source : 91473d3b5278df43694709fe732b176696f25151
This commit is contained in:
Родитель
45911f854e
Коммит
1d020acead
|
@ -10,8 +10,9 @@ XPCOMUtils.defineLazyGetter(this, "colorUtils", () => {
|
|||
});
|
||||
|
||||
Cu.import("resource://devtools/shared/event-emitter.js");
|
||||
|
||||
Cu.import("resource://gre/modules/ExtensionUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Task.jsm");
|
||||
|
||||
var {
|
||||
EventManager,
|
||||
IconDetails,
|
||||
|
@ -22,6 +23,8 @@ const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
|
|||
// WeakMap[Extension -> BrowserAction]
|
||||
var browserActionMap = new WeakMap();
|
||||
|
||||
global.browserActionOf = browserActionOf;
|
||||
|
||||
// Responsible for the browser_action section of the manifest as well
|
||||
// as the associated popup.
|
||||
function BrowserAction(options, extension) {
|
||||
|
@ -97,10 +100,9 @@ BrowserAction.prototype = {
|
|||
let popupURL = this.getProperty(tab, "popup");
|
||||
this.tabManager.addActiveTabPermission(tab);
|
||||
|
||||
// If the widget has a popup URL defined, we open a popup, but do not
|
||||
// dispatch a click event to the extension.
|
||||
// If it has no popup URL defined, we dispatch a click event, but do not
|
||||
// open a popup.
|
||||
// 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 {
|
||||
new ViewPopup(this.extension, event.target, popupURL, this.browserStyle);
|
||||
|
@ -123,6 +125,42 @@ BrowserAction.prototype = {
|
|||
this.widget = widget;
|
||||
},
|
||||
|
||||
/**
|
||||
* Triggers this browser action for the given window, with the same effects as
|
||||
* if it were clicked by a user.
|
||||
*
|
||||
* This has no effect if the browser action is disabled for, or not
|
||||
* present in, the given window.
|
||||
*/
|
||||
triggerAction: Task.async(function* (window) {
|
||||
let popup = ViewPopup.for(this.extension, window);
|
||||
if (popup) {
|
||||
popup.closePopup();
|
||||
return;
|
||||
}
|
||||
|
||||
let widget = this.widget.forWindow(window);
|
||||
let tab = window.gBrowser.selectedTab;
|
||||
|
||||
if (!widget || !this.getProperty(tab, "enabled")) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 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 (this.getProperty(tab, "popup")) {
|
||||
if (this.widget.areaType == CustomizableUI.TYPE_MENU_PANEL) {
|
||||
yield window.PanelUI.show();
|
||||
}
|
||||
|
||||
let event = new window.CustomEvent("command", {bubbles: true, cancelable: true});
|
||||
widget.node.dispatchEvent(event);
|
||||
} else {
|
||||
this.emit("click");
|
||||
}
|
||||
}),
|
||||
|
||||
// Update the toolbar button |node| with the tab context data
|
||||
// in |tabData|.
|
||||
updateButton(node, tabData) {
|
||||
|
|
|
@ -26,6 +26,7 @@ const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
|
|||
const RESIZE_TIMEOUT = 100;
|
||||
|
||||
var {
|
||||
DefaultWeakMap,
|
||||
EventManager,
|
||||
} = ExtensionUtils;
|
||||
|
||||
|
@ -111,6 +112,12 @@ class BasePopup {
|
|||
|
||||
this.browser = null;
|
||||
this.browserReady = this.createBrowser(viewNode, popupURI);
|
||||
|
||||
BasePopup.instances.get(this.window).set(extension, this);
|
||||
}
|
||||
|
||||
static for(extension, window) {
|
||||
return BasePopup.instances.get(window).get(extension);
|
||||
}
|
||||
|
||||
destroy() {
|
||||
|
@ -127,6 +134,8 @@ class BasePopup {
|
|||
this.panel.style.setProperty("--panel-arrowcontent-background", "");
|
||||
this.panel.style.setProperty("--panel-arrow-image-vertical", "");
|
||||
|
||||
BasePopup.instances.get(this.window).delete(this.extension);
|
||||
|
||||
this.browser = null;
|
||||
this.viewNode = null;
|
||||
});
|
||||
|
@ -379,6 +388,13 @@ class BasePopup {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A map of active popups for a given browser window.
|
||||
*
|
||||
* WeakMap[window -> WeakMap[Extension -> BasePopup]]
|
||||
*/
|
||||
BasePopup.instances = new DefaultWeakMap(() => new WeakMap());
|
||||
|
||||
global.PanelPopup = class PanelPopup extends BasePopup {
|
||||
constructor(extension, imageNode, popupURL, browserStyle) {
|
||||
let document = imageNode.ownerDocument;
|
||||
|
|
|
@ -2,6 +2,13 @@
|
|||
/* vim: set sts=2 sw=2 et tw=80: */
|
||||
"use strict";
|
||||
|
||||
function getBrowserAction(extension) {
|
||||
let {GlobalManager, browserActionFor} = Cu.import("resource://gre/modules/Extension.jsm", {});
|
||||
|
||||
let ext = GlobalManager.extensionMap.get(extension.id);
|
||||
return browserActionFor(ext);
|
||||
}
|
||||
|
||||
function* testInArea(area) {
|
||||
let scriptPage = url => `<html><head><meta charset="utf-8"><script src="${url}"></script></head><body>${url}</body></html>`;
|
||||
|
||||
|
@ -25,7 +32,7 @@ function* testInArea(area) {
|
|||
browser.runtime.sendMessage("from-popup-a");
|
||||
};
|
||||
browser.runtime.onMessage.addListener(msg => {
|
||||
if (msg == "close-popup") {
|
||||
if (msg == "close-popup-using-window.close") {
|
||||
window.close();
|
||||
}
|
||||
});
|
||||
|
@ -42,42 +49,67 @@ function* testInArea(area) {
|
|||
let sendClick;
|
||||
let tests = [
|
||||
() => {
|
||||
browser.test.log(`Click browser action, expect popup "a".`);
|
||||
sendClick({expectEvent: false, expectPopup: "a"});
|
||||
},
|
||||
() => {
|
||||
browser.test.log(`Click browser action again, expect popup "a".`);
|
||||
sendClick({expectEvent: false, expectPopup: "a"});
|
||||
},
|
||||
() => {
|
||||
browser.test.log(`Call triggerAction, expect popup "a" again. Leave popup open.`);
|
||||
sendClick({expectEvent: false, expectPopup: "a", leaveOpen: true}, "trigger-action");
|
||||
},
|
||||
() => {
|
||||
browser.test.log(`Call triggerAction again. Expect remaining popup closed.`);
|
||||
sendClick({expectEvent: false, expectPopup: null}, "trigger-action");
|
||||
browser.test.sendMessage("next-test", {waitUntilClosed: true});
|
||||
},
|
||||
() => {
|
||||
browser.test.log(`Call triggerAction again. Expect popup "a" again.`);
|
||||
sendClick({expectEvent: false, expectPopup: "a"}, "trigger-action");
|
||||
},
|
||||
() => {
|
||||
browser.test.log(`Change popup URL. Click browser action. Expect popup "b".`);
|
||||
browser.browserAction.setPopup({popup: "popup-b.html"});
|
||||
sendClick({expectEvent: false, expectPopup: "b"});
|
||||
},
|
||||
() => {
|
||||
browser.test.log(`Click browser action again. Expect popup "b" again.`);
|
||||
sendClick({expectEvent: false, expectPopup: "b"});
|
||||
},
|
||||
() => {
|
||||
browser.test.log(`Clear popup URL. Click browser action. Expect click event.`);
|
||||
browser.browserAction.setPopup({popup: ""});
|
||||
sendClick({expectEvent: true, expectPopup: null});
|
||||
},
|
||||
() => {
|
||||
browser.test.log(`Click browser action again. Expect another click event.`);
|
||||
sendClick({expectEvent: true, expectPopup: null});
|
||||
},
|
||||
() => {
|
||||
browser.browserAction.setPopup({popup: "/popup-a.html"});
|
||||
sendClick({expectEvent: false, expectPopup: "a", runNextTest: true});
|
||||
browser.test.log(`Call triggerAction. Expect click event.`);
|
||||
sendClick({expectEvent: true, expectPopup: null}, "trigger-action");
|
||||
},
|
||||
() => {
|
||||
browser.test.sendMessage("next-test", {expectClosed: true});
|
||||
browser.test.log(`Change popup URL. Click browser action. Expect popup "a", and leave open.`);
|
||||
browser.browserAction.setPopup({popup: "/popup-a.html"});
|
||||
sendClick({expectEvent: false, expectPopup: "a", leaveOpen: true});
|
||||
},
|
||||
() => {
|
||||
browser.test.log(`Call window.close(). Expect popup closed.`);
|
||||
browser.test.sendMessage("next-test", {closePopupUsingWindow: true});
|
||||
},
|
||||
];
|
||||
|
||||
let expect = {};
|
||||
sendClick = ({expectEvent, expectPopup, runNextTest}) => {
|
||||
expect = {event: expectEvent, popup: expectPopup, runNextTest};
|
||||
browser.test.sendMessage("send-click");
|
||||
sendClick = ({expectEvent, expectPopup, runNextTest, waitUntilClosed, leaveOpen}, message = "send-click") => {
|
||||
expect = {event: expectEvent, popup: expectPopup, runNextTest, waitUntilClosed, leaveOpen};
|
||||
browser.test.sendMessage(message);
|
||||
};
|
||||
|
||||
browser.runtime.onMessage.addListener(msg => {
|
||||
if (msg == "close-popup") {
|
||||
if (msg == "close-popup-using-window.close") {
|
||||
return;
|
||||
} else if (expect.popup) {
|
||||
browser.test.assertEq(msg, `from-popup-${expect.popup}`,
|
||||
|
@ -87,12 +119,7 @@ function* testInArea(area) {
|
|||
}
|
||||
|
||||
expect.popup = null;
|
||||
if (expect.runNextTest) {
|
||||
expect.runNextTest = false;
|
||||
tests.shift()();
|
||||
} else {
|
||||
browser.test.sendMessage("next-test");
|
||||
}
|
||||
browser.test.sendMessage("next-test", expect);
|
||||
});
|
||||
|
||||
browser.browserAction.onClicked.addListener(() => {
|
||||
|
@ -103,12 +130,12 @@ function* testInArea(area) {
|
|||
}
|
||||
|
||||
expect.event = false;
|
||||
browser.test.sendMessage("next-test");
|
||||
browser.test.sendMessage("next-test", expect);
|
||||
});
|
||||
|
||||
browser.test.onMessage.addListener((msg) => {
|
||||
if (msg == "close-popup") {
|
||||
browser.runtime.sendMessage("close-popup");
|
||||
if (msg == "close-popup-using-window.close") {
|
||||
browser.runtime.sendMessage("close-popup-using-window.close");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -133,22 +160,31 @@ function* testInArea(area) {
|
|||
clickBrowserAction(extension);
|
||||
});
|
||||
|
||||
extension.onMessage("trigger-action", () => {
|
||||
getBrowserAction(extension).triggerAction(window);
|
||||
});
|
||||
|
||||
let widget;
|
||||
extension.onMessage("next-test", Task.async(function* (expecting = {}) {
|
||||
if (!widget) {
|
||||
widget = getBrowserActionWidget(extension);
|
||||
CustomizableUI.addWidgetToArea(widget.id, area);
|
||||
}
|
||||
if (expecting.expectClosed) {
|
||||
if (expecting.waitUntilClosed) {
|
||||
let panel = getBrowserActionPopup(extension);
|
||||
if (panel && panel.state != "closed") {
|
||||
yield promisePopupHidden(panel);
|
||||
}
|
||||
} else if (expecting.closePopupUsingWindow) {
|
||||
let panel = getBrowserActionPopup(extension);
|
||||
ok(panel, "Expect panel to exist");
|
||||
yield promisePopupShown(panel);
|
||||
|
||||
extension.sendMessage("close-popup");
|
||||
extension.sendMessage("close-popup-using-window.close");
|
||||
|
||||
yield promisePopupHidden(panel);
|
||||
ok(true, "Panel is closed");
|
||||
} else {
|
||||
} else if (!expecting.leaveOpen) {
|
||||
yield closeBrowserAction(extension);
|
||||
}
|
||||
|
||||
|
|
|
@ -128,29 +128,24 @@ function extend(obj, ...args) {
|
|||
return obj;
|
||||
}
|
||||
|
||||
// Similar to a WeakMap, but returns a particular default value for
|
||||
// |get| if a key is not present.
|
||||
function DefaultWeakMap(defaultValue) {
|
||||
this.defaultValue = defaultValue;
|
||||
this.weakmap = new WeakMap();
|
||||
}
|
||||
/**
|
||||
* Similar to a WeakMap, but creates a new key with the given
|
||||
* constructor if one is not present.
|
||||
*/
|
||||
class DefaultWeakMap extends WeakMap {
|
||||
constructor(defaultConstructor, init) {
|
||||
super(init);
|
||||
this.defaultConstructor = defaultConstructor;
|
||||
}
|
||||
|
||||
DefaultWeakMap.prototype = {
|
||||
get(key) {
|
||||
if (this.weakmap.has(key)) {
|
||||
return this.weakmap.get(key);
|
||||
if (!this.has(key)) {
|
||||
this.set(key, this.defaultConstructor());
|
||||
}
|
||||
return this.defaultValue;
|
||||
},
|
||||
|
||||
set(key, value) {
|
||||
if (key) {
|
||||
this.weakmap.set(key, value);
|
||||
} else {
|
||||
this.defaultValue = value;
|
||||
}
|
||||
},
|
||||
};
|
||||
return super.get(key);
|
||||
}
|
||||
}
|
||||
|
||||
class SpreadArgs extends Array {
|
||||
constructor(args) {
|
||||
|
|
Загрузка…
Ссылка в новой задаче