Bug 1616143 - Allow setting of properties per tab on action buttons. r=mkmelin
--HG-- extra : rebase_source : 188814385f1072d4761fc6846e3e8d3bec47633c extra : histedit_source : 8992fd666c41be66bb175d4cb5811d299d0a7ebb
This commit is contained in:
Родитель
84ff495b42
Коммит
71f9fa4ccf
|
@ -43,6 +43,14 @@ XPCOMUtils.defineLazyGlobalGetters(this, ["InspectorUtils"]);
|
||||||
var DEFAULT_ICON = "chrome://messenger/content/extension.svg";
|
var DEFAULT_ICON = "chrome://messenger/content/extension.svg";
|
||||||
|
|
||||||
this.ToolbarButtonAPI = class extends ExtensionAPI {
|
this.ToolbarButtonAPI = class extends ExtensionAPI {
|
||||||
|
constructor(extension, global) {
|
||||||
|
super(extension);
|
||||||
|
this.global = global;
|
||||||
|
this.tabContext = new this.global.TabContext(target =>
|
||||||
|
this.getContextData(null)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when the extension is enabled.
|
* Called when the extension is enabled.
|
||||||
*
|
*
|
||||||
|
@ -235,8 +243,9 @@ this.ToolbarButtonAPI = class extends ExtensionAPI {
|
||||||
async triggerAction(window) {
|
async triggerAction(window) {
|
||||||
let { document } = window;
|
let { document } = window;
|
||||||
let button = document.getElementById(this.id);
|
let button = document.getElementById(this.id);
|
||||||
let popupURL = this.getProperty(this.globals, "popup");
|
let { popup: popupURL, enabled } = this.getContextData(
|
||||||
let enabled = this.getProperty(this.globals, "enabled");
|
this.getTargetFromWindow(window)
|
||||||
|
);
|
||||||
|
|
||||||
if (button && popupURL && enabled) {
|
if (button && popupURL && enabled) {
|
||||||
let popup =
|
let popup =
|
||||||
|
@ -262,6 +271,9 @@ this.ToolbarButtonAPI = class extends ExtensionAPI {
|
||||||
this.triggerAction(window);
|
this.triggerAction(window);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case "TabSelect":
|
||||||
|
this.updateWindow(window);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -428,7 +440,10 @@ this.ToolbarButtonAPI = class extends ExtensionAPI {
|
||||||
async updateWindow(window) {
|
async updateWindow(window) {
|
||||||
let button = window.document.getElementById(this.id);
|
let button = window.document.getElementById(this.id);
|
||||||
if (button) {
|
if (button) {
|
||||||
this.updateButton(button, this.globals);
|
this.updateButton(
|
||||||
|
button,
|
||||||
|
this.getContextData(this.getTargetFromWindow(window))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
await new Promise(window.requestAnimationFrame);
|
await new Promise(window.requestAnimationFrame);
|
||||||
}
|
}
|
||||||
|
@ -444,7 +459,7 @@ this.ToolbarButtonAPI = class extends ExtensionAPI {
|
||||||
*/
|
*/
|
||||||
async updateOnChange(target) {
|
async updateOnChange(target) {
|
||||||
if (target) {
|
if (target) {
|
||||||
let window = target.ownerGlobal;
|
let window = Cu.getGlobalForObject(target);
|
||||||
if (target === window || target.selected) {
|
if (target === window || target.selected) {
|
||||||
await this.updateWindow(window);
|
await this.updateWindow(window);
|
||||||
}
|
}
|
||||||
|
@ -460,38 +475,55 @@ this.ToolbarButtonAPI = class extends ExtensionAPI {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the target object and its associated values corresponding to
|
* Gets the active tab of the passed window if the window has tabs, or the
|
||||||
* the `details` parameter of the various get* and set* API methods.
|
* window itself.
|
||||||
|
*
|
||||||
|
* @param {ChromeWindow} window
|
||||||
|
* @returns {XULElement|ChromeWindow}
|
||||||
|
*/
|
||||||
|
getTargetFromWindow(window) {
|
||||||
|
let tabmail = window.document.getElementById("tabmail");
|
||||||
|
if (tabmail) {
|
||||||
|
return tabmail.currentTabInfo;
|
||||||
|
}
|
||||||
|
return window;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the target object corresponding to the `details` parameter of the various
|
||||||
|
* get* and set* API methods.
|
||||||
*
|
*
|
||||||
* @param {Object} details
|
* @param {Object} details
|
||||||
* An object with optional `tabId` or `windowId` properties.
|
* An object with optional `tabId` or `windowId` properties.
|
||||||
* @throws if both `tabId` and `windowId` are specified, or if they are invalid.
|
* @throws if `windowId` is specified, this is not valid in Thunderbird.
|
||||||
* @returns {Object}
|
* @returns {XULElement|ChromeWindow|null}
|
||||||
* An object with two properties: `target` and `values`.
|
* If a `tabId` was specified, the corresponding XULElement tab.
|
||||||
* - If a `tabId` was specified, `target` will be the corresponding
|
* If a `windowId` was specified, the corresponding ChromeWindow.
|
||||||
* XULElement tab. If a `windowId` was specified, `target` will be
|
* Otherwise, `null`.
|
||||||
* the corresponding ChromeWindow. Otherwise it will be `null`.
|
|
||||||
* - `values` will contain the icon, title, badge, etc. associated with
|
|
||||||
* the target.
|
|
||||||
*/
|
*/
|
||||||
getContextData({ tabId, windowId }) {
|
getTargetFromDetails({ tabId, windowId }) {
|
||||||
if (tabId != null && windowId != null) {
|
if (windowId != null) {
|
||||||
throw new ExtensionError(
|
throw new ExtensionError("windowId is not allowed, use tabId instead.");
|
||||||
"Only one of tabId and windowId can be specified."
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
let target, values;
|
if (tabId != null) {
|
||||||
// if (tabId != null) {
|
return this.global.tabTracker.getTab(tabId);
|
||||||
// target = tabTracker.getTab(tabId);
|
}
|
||||||
// values = this.tabContext.get(target);
|
return null;
|
||||||
// } else if (windowId != null) {
|
}
|
||||||
// target = windowTracker.getWindow(windowId);
|
|
||||||
// values = this.tabContext.get(target);
|
/**
|
||||||
// } else {
|
* Gets the data associated with a tab, window, or the global one.
|
||||||
target = null;
|
*
|
||||||
values = this.globals;
|
* @param {XULElement|ChromeWindow|null} target
|
||||||
// }
|
* A XULElement tab, a ChromeWindow, or null for the global data.
|
||||||
return { target, values };
|
* @returns {Object}
|
||||||
|
* The icon, title, badge, etc. associated with the target.
|
||||||
|
*/
|
||||||
|
getContextData(target) {
|
||||||
|
if (target) {
|
||||||
|
return this.tabContext.get(target);
|
||||||
|
}
|
||||||
|
return this.globals;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -506,7 +538,8 @@ this.ToolbarButtonAPI = class extends ExtensionAPI {
|
||||||
* Value for prop.
|
* Value for prop.
|
||||||
*/
|
*/
|
||||||
async setProperty(details, prop, value) {
|
async setProperty(details, prop, value) {
|
||||||
let { target, values } = this.getContextData(details);
|
let target = this.getTargetFromDetails(details);
|
||||||
|
let values = this.getContextData(target);
|
||||||
if (value === null) {
|
if (value === null) {
|
||||||
delete values[prop];
|
delete values[prop];
|
||||||
} else {
|
} else {
|
||||||
|
@ -528,7 +561,7 @@ this.ToolbarButtonAPI = class extends ExtensionAPI {
|
||||||
* Value of prop.
|
* Value of prop.
|
||||||
*/
|
*/
|
||||||
getProperty(details, prop) {
|
getProperty(details, prop) {
|
||||||
return this.getContextData(details).values[prop];
|
return this.getContextData(this.getTargetFromDetails(details))[prop];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -23,6 +23,7 @@ this.browserAction = class extends ToolbarButtonAPI {
|
||||||
close() {
|
close() {
|
||||||
super.close();
|
super.close();
|
||||||
browserActionMap.delete(this.extension);
|
browserActionMap.delete(this.extension);
|
||||||
|
windowTracker.removeListener("TabSelect", this);
|
||||||
}
|
}
|
||||||
|
|
||||||
static onUninstall(extensionId) {
|
static onUninstall(extensionId) {
|
||||||
|
@ -49,13 +50,14 @@ this.browserAction = class extends ToolbarButtonAPI {
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(extension) {
|
constructor(extension) {
|
||||||
super(extension);
|
super(extension, global);
|
||||||
this.manifest_name = "browser_action";
|
this.manifest_name = "browser_action";
|
||||||
this.manifestName = "browserAction";
|
this.manifestName = "browserAction";
|
||||||
this.windowURLs = ["chrome://messenger/content/messenger.xhtml"];
|
this.windowURLs = ["chrome://messenger/content/messenger.xhtml"];
|
||||||
this.toolboxId = "mail-toolbox";
|
this.toolboxId = "mail-toolbox";
|
||||||
this.toolbarId = "mail-bar3";
|
this.toolbarId = "mail-bar3";
|
||||||
this.global = global;
|
|
||||||
|
windowTracker.addListener("TabSelect", this);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ ChromeUtils.defineModuleGetter(
|
||||||
|
|
||||||
this.composeAction = class extends ToolbarButtonAPI {
|
this.composeAction = class extends ToolbarButtonAPI {
|
||||||
constructor(extension) {
|
constructor(extension) {
|
||||||
super(extension);
|
super(extension, global);
|
||||||
this.manifest_name = "compose_action";
|
this.manifest_name = "compose_action";
|
||||||
this.manifestName = "composeAction";
|
this.manifestName = "composeAction";
|
||||||
this.windowURLs = [
|
this.windowURLs = [
|
||||||
|
@ -25,8 +25,6 @@ this.composeAction = class extends ToolbarButtonAPI {
|
||||||
if (format) {
|
if (format) {
|
||||||
this.paint = this.paintFormatToolbar;
|
this.paint = this.paintFormatToolbar;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.global = global;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
paintFormatToolbar(window) {
|
paintFormatToolbar(window) {
|
||||||
|
|
|
@ -164,6 +164,50 @@ function getTabBrowser(nativeTabInfo) {
|
||||||
}
|
}
|
||||||
global.getTabBrowser = getTabBrowser;
|
global.getTabBrowser = getTabBrowser;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Manages tab-specific and window-specific context data, and dispatches
|
||||||
|
* tab select events across all windows.
|
||||||
|
*/
|
||||||
|
global.TabContext = class extends EventEmitter {
|
||||||
|
/**
|
||||||
|
* @param {Function} getDefaultPrototype
|
||||||
|
* Provides the prototype of the context value for a tab or window when there is none.
|
||||||
|
* Called with a XULElement or ChromeWindow argument.
|
||||||
|
* Should return an object or null.
|
||||||
|
*/
|
||||||
|
constructor(getDefaultPrototype) {
|
||||||
|
super();
|
||||||
|
this.getDefaultPrototype = getDefaultPrototype;
|
||||||
|
this.tabData = new WeakMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the context data associated with `keyObject`.
|
||||||
|
*
|
||||||
|
* @param {XULElement|ChromeWindow} keyObject
|
||||||
|
* Browser tab or browser chrome window.
|
||||||
|
* @returns {Object}
|
||||||
|
*/
|
||||||
|
get(keyObject) {
|
||||||
|
if (!this.tabData.has(keyObject)) {
|
||||||
|
let data = Object.create(this.getDefaultPrototype(keyObject));
|
||||||
|
this.tabData.set(keyObject, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.tabData.get(keyObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears the context data associated with `keyObject`.
|
||||||
|
*
|
||||||
|
* @param {XULElement|ChromeWindow} keyObject
|
||||||
|
* Browser tab or browser chrome window.
|
||||||
|
*/
|
||||||
|
clear(keyObject) {
|
||||||
|
this.tabData.delete(keyObject);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/* global searchInitialized */
|
/* global searchInitialized */
|
||||||
// This promise is used to wait for the search service to be initialized.
|
// This promise is used to wait for the search service to be initialized.
|
||||||
// None of the code in the WebExtension modules requests that initialization.
|
// None of the code in the WebExtension modules requests that initialization.
|
||||||
|
|
|
@ -25,10 +25,11 @@ this.messageDisplayAction = class extends ToolbarButtonAPI {
|
||||||
close() {
|
close() {
|
||||||
super.close();
|
super.close();
|
||||||
messageDisplayActionMap.delete(this.extension);
|
messageDisplayActionMap.delete(this.extension);
|
||||||
|
windowTracker.removeListener("TabSelect", this);
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(extension) {
|
constructor(extension) {
|
||||||
super(extension);
|
super(extension, global);
|
||||||
this.manifest_name = "message_display_action";
|
this.manifest_name = "message_display_action";
|
||||||
this.manifestName = "messageDisplayAction";
|
this.manifestName = "messageDisplayAction";
|
||||||
this.windowURLs = [
|
this.windowURLs = [
|
||||||
|
@ -37,6 +38,8 @@ this.messageDisplayAction = class extends ToolbarButtonAPI {
|
||||||
];
|
];
|
||||||
this.toolboxId = "header-view-toolbox";
|
this.toolboxId = "header-view-toolbox";
|
||||||
this.toolbarId = "header-view-toolbar";
|
this.toolbarId = "header-view-toolbar";
|
||||||
|
|
||||||
|
windowTracker.addListener("TabSelect", this);
|
||||||
}
|
}
|
||||||
|
|
||||||
makeButton(window) {
|
makeButton(window) {
|
||||||
|
|
|
@ -16,6 +16,7 @@ tags = webextensions
|
||||||
|
|
||||||
[browser_ext_addressBooksUI.js]
|
[browser_ext_addressBooksUI.js]
|
||||||
[browser_ext_browserAction.js]
|
[browser_ext_browserAction.js]
|
||||||
|
[browser_ext_browserAction_properties.js]
|
||||||
[browser_ext_commands_execute_browser_action.js]
|
[browser_ext_commands_execute_browser_action.js]
|
||||||
[browser_ext_commands_getAll.js]
|
[browser_ext_commands_getAll.js]
|
||||||
[browser_ext_commands_onCommand.js]
|
[browser_ext_commands_onCommand.js]
|
||||||
|
@ -24,6 +25,7 @@ tags = webextensions
|
||||||
[browser_ext_compose_details.js]
|
[browser_ext_compose_details.js]
|
||||||
[browser_ext_compose_onBeforeSend.js]
|
[browser_ext_compose_onBeforeSend.js]
|
||||||
[browser_ext_composeAction.js]
|
[browser_ext_composeAction.js]
|
||||||
|
[browser_ext_composeAction_properties.js]
|
||||||
[browser_ext_mailTabs.js]
|
[browser_ext_mailTabs.js]
|
||||||
[browser_ext_menus.js]
|
[browser_ext_menus.js]
|
||||||
support-files = data/content.html
|
support-files = data/content.html
|
||||||
|
@ -31,6 +33,7 @@ support-files = data/content.html
|
||||||
[browser_ext_menus_replace_menu_context.js]
|
[browser_ext_menus_replace_menu_context.js]
|
||||||
[browser_ext_messageDisplay.js]
|
[browser_ext_messageDisplay.js]
|
||||||
[browser_ext_messageDisplayAction.js]
|
[browser_ext_messageDisplayAction.js]
|
||||||
|
[browser_ext_messageDisplayAction_properties.js]
|
||||||
[browser_ext_quickFilter.js]
|
[browser_ext_quickFilter.js]
|
||||||
[browser_ext_windows.js]
|
[browser_ext_windows.js]
|
||||||
[browser_ext_windows_types.js]
|
[browser_ext_windows_types.js]
|
||||||
|
|
|
@ -0,0 +1,136 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, you can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
add_task(async () => {
|
||||||
|
let account = createAccount();
|
||||||
|
addIdentity(account);
|
||||||
|
let rootFolder = account.incomingServer.rootFolder;
|
||||||
|
|
||||||
|
window.gFolderTreeView.selectFolder(rootFolder);
|
||||||
|
await new Promise(resolve => executeSoon(resolve));
|
||||||
|
|
||||||
|
let extension = ExtensionTestUtils.loadExtension({
|
||||||
|
background: async () => {
|
||||||
|
async function checkProperty(property, expectedDefault, ...expected) {
|
||||||
|
browser.test.log(
|
||||||
|
`${property}: ${expectedDefault}, ${expected.join(", ")}`
|
||||||
|
);
|
||||||
|
|
||||||
|
browser.test.assertEq(
|
||||||
|
expectedDefault,
|
||||||
|
await browser.browserAction[property]({})
|
||||||
|
);
|
||||||
|
for (let i = 0; i < 3; i++) {
|
||||||
|
browser.test.assertEq(
|
||||||
|
expected[i],
|
||||||
|
await browser.browserAction[property]({ tabId: tabIDs[i] })
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
await new Promise(resolve => {
|
||||||
|
browser.test.onMessage.addListener(function listener() {
|
||||||
|
browser.test.onMessage.removeListener(listener);
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
|
browser.test.sendMessage("checkProperty", property, expected);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let tabs = await browser.mailTabs.query({});
|
||||||
|
let tabIDs = tabs.map(t => t.id);
|
||||||
|
|
||||||
|
await checkProperty("isEnabled", true, true, true, true);
|
||||||
|
await browser.browserAction.disable();
|
||||||
|
await checkProperty("isEnabled", false, false, false, false);
|
||||||
|
await browser.browserAction.enable(tabIDs[0]);
|
||||||
|
await checkProperty("isEnabled", false, true, false, false);
|
||||||
|
await browser.browserAction.enable();
|
||||||
|
await checkProperty("isEnabled", true, true, true, true);
|
||||||
|
await browser.browserAction.disable();
|
||||||
|
await checkProperty("isEnabled", false, true, false, false);
|
||||||
|
await browser.browserAction.disable(tabIDs[0]);
|
||||||
|
await checkProperty("isEnabled", false, false, false, false);
|
||||||
|
await browser.browserAction.enable();
|
||||||
|
await checkProperty("isEnabled", true, false, true, true);
|
||||||
|
|
||||||
|
await checkProperty(
|
||||||
|
"getTitle",
|
||||||
|
"default",
|
||||||
|
"default",
|
||||||
|
"default",
|
||||||
|
"default"
|
||||||
|
);
|
||||||
|
await browser.browserAction.setTitle({ tabId: tabIDs[2], title: "tab2" });
|
||||||
|
await checkProperty("getTitle", "default", "default", "default", "tab2");
|
||||||
|
await browser.browserAction.setTitle({ title: "new" });
|
||||||
|
await checkProperty("getTitle", "new", "new", "new", "tab2");
|
||||||
|
await browser.browserAction.setTitle({ tabId: tabIDs[1], title: "tab1" });
|
||||||
|
await checkProperty("getTitle", "new", "new", "tab1", "tab2");
|
||||||
|
await browser.browserAction.setTitle({ tabId: tabIDs[2], title: null });
|
||||||
|
await checkProperty("getTitle", "new", "new", "tab1", "new");
|
||||||
|
await browser.browserAction.setTitle({ title: null });
|
||||||
|
await checkProperty("getTitle", "default", "default", "tab1", "default");
|
||||||
|
await browser.browserAction.setTitle({ tabId: tabIDs[1], title: null });
|
||||||
|
await checkProperty(
|
||||||
|
"getTitle",
|
||||||
|
"default",
|
||||||
|
"default",
|
||||||
|
"default",
|
||||||
|
"default"
|
||||||
|
);
|
||||||
|
|
||||||
|
await browser.tabs.remove(tabIDs[0]);
|
||||||
|
await browser.tabs.remove(tabIDs[1]);
|
||||||
|
await browser.tabs.remove(tabIDs[2]);
|
||||||
|
browser.test.notifyPass("finished");
|
||||||
|
},
|
||||||
|
manifest: {
|
||||||
|
applications: {
|
||||||
|
gecko: {
|
||||||
|
id: "test1@mochi.test",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
browser_action: {
|
||||||
|
default_title: "default",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
await extension.startup();
|
||||||
|
|
||||||
|
let tabmail = document.getElementById("tabmail");
|
||||||
|
tabmail.openTab("folder", { folder: rootFolder, background: false });
|
||||||
|
tabmail.openTab("folder", { folder: rootFolder, background: false });
|
||||||
|
|
||||||
|
let mailTabs = tabmail.tabInfo;
|
||||||
|
is(mailTabs.length, 3);
|
||||||
|
|
||||||
|
let button = document.getElementById(
|
||||||
|
"test1_mochi_test-browserAction-toolbarbutton"
|
||||||
|
);
|
||||||
|
|
||||||
|
extension.onMessage("checkProperty", async (property, expected) => {
|
||||||
|
for (let i = 0; i < 3; i++) {
|
||||||
|
tabmail.switchToTab(mailTabs[i]);
|
||||||
|
await new Promise(resolve => requestAnimationFrame(resolve));
|
||||||
|
switch (property) {
|
||||||
|
case "isEnabled":
|
||||||
|
is(button.disabled, !expected[i], `button ${i} enabled state`);
|
||||||
|
break;
|
||||||
|
case "getTitle":
|
||||||
|
is(button.getAttribute("label"), expected[i], `button ${i} label`);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension.sendMessage();
|
||||||
|
});
|
||||||
|
|
||||||
|
await extension.awaitFinish("finished");
|
||||||
|
await extension.unload();
|
||||||
|
|
||||||
|
tabmail.closeTab(mailTabs[2]);
|
||||||
|
tabmail.closeTab(mailTabs[1]);
|
||||||
|
is(tabmail.tabInfo.length, 1);
|
||||||
|
});
|
|
@ -0,0 +1,130 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, you can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
add_task(async () => {
|
||||||
|
let account = createAccount();
|
||||||
|
addIdentity(account);
|
||||||
|
let rootFolder = account.incomingServer.rootFolder;
|
||||||
|
|
||||||
|
window.gFolderTreeView.selectFolder(rootFolder);
|
||||||
|
await new Promise(resolve => executeSoon(resolve));
|
||||||
|
|
||||||
|
let extension = ExtensionTestUtils.loadExtension({
|
||||||
|
background: async () => {
|
||||||
|
async function checkProperty(property, expectedDefault, ...expected) {
|
||||||
|
browser.test.log(
|
||||||
|
`${property}: ${expectedDefault}, ${expected.join(", ")}`
|
||||||
|
);
|
||||||
|
|
||||||
|
browser.test.assertEq(
|
||||||
|
expectedDefault,
|
||||||
|
await browser.composeAction[property]({})
|
||||||
|
);
|
||||||
|
for (let i = 0; i < 3; i++) {
|
||||||
|
browser.test.assertEq(
|
||||||
|
expected[i],
|
||||||
|
await browser.composeAction[property]({ tabId: tabIDs[i] })
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
await new Promise(resolve => {
|
||||||
|
browser.test.onMessage.addListener(function listener() {
|
||||||
|
browser.test.onMessage.removeListener(listener);
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
|
browser.test.sendMessage("checkProperty", property, expected);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
await browser.compose.beginNew();
|
||||||
|
await browser.compose.beginNew();
|
||||||
|
await browser.compose.beginNew();
|
||||||
|
let windows = await browser.windows.getAll({
|
||||||
|
populate: true,
|
||||||
|
windowTypes: ["messageCompose"],
|
||||||
|
});
|
||||||
|
let tabIDs = windows.map(w => w.tabs[0].id);
|
||||||
|
|
||||||
|
await checkProperty("isEnabled", true, true, true, true);
|
||||||
|
await browser.composeAction.disable();
|
||||||
|
await checkProperty("isEnabled", false, false, false, false);
|
||||||
|
await browser.composeAction.enable(tabIDs[0]);
|
||||||
|
await checkProperty("isEnabled", false, true, false, false);
|
||||||
|
await browser.composeAction.enable();
|
||||||
|
await checkProperty("isEnabled", true, true, true, true);
|
||||||
|
await browser.composeAction.disable();
|
||||||
|
await checkProperty("isEnabled", false, true, false, false);
|
||||||
|
await browser.composeAction.disable(tabIDs[0]);
|
||||||
|
await checkProperty("isEnabled", false, false, false, false);
|
||||||
|
await browser.composeAction.enable();
|
||||||
|
await checkProperty("isEnabled", true, false, true, true);
|
||||||
|
|
||||||
|
await checkProperty(
|
||||||
|
"getTitle",
|
||||||
|
"default",
|
||||||
|
"default",
|
||||||
|
"default",
|
||||||
|
"default"
|
||||||
|
);
|
||||||
|
await browser.composeAction.setTitle({ tabId: tabIDs[2], title: "tab2" });
|
||||||
|
await checkProperty("getTitle", "default", "default", "default", "tab2");
|
||||||
|
await browser.composeAction.setTitle({ title: "new" });
|
||||||
|
await checkProperty("getTitle", "new", "new", "new", "tab2");
|
||||||
|
await browser.composeAction.setTitle({ tabId: tabIDs[1], title: "tab1" });
|
||||||
|
await checkProperty("getTitle", "new", "new", "tab1", "tab2");
|
||||||
|
await browser.composeAction.setTitle({ tabId: tabIDs[2], title: null });
|
||||||
|
await checkProperty("getTitle", "new", "new", "tab1", "new");
|
||||||
|
await browser.composeAction.setTitle({ title: null });
|
||||||
|
await checkProperty("getTitle", "default", "default", "tab1", "default");
|
||||||
|
await browser.composeAction.setTitle({ tabId: tabIDs[1], title: null });
|
||||||
|
await checkProperty(
|
||||||
|
"getTitle",
|
||||||
|
"default",
|
||||||
|
"default",
|
||||||
|
"default",
|
||||||
|
"default"
|
||||||
|
);
|
||||||
|
|
||||||
|
await browser.tabs.remove(tabIDs[0]);
|
||||||
|
await browser.tabs.remove(tabIDs[1]);
|
||||||
|
await browser.tabs.remove(tabIDs[2]);
|
||||||
|
browser.test.notifyPass("finished");
|
||||||
|
},
|
||||||
|
manifest: {
|
||||||
|
applications: {
|
||||||
|
gecko: {
|
||||||
|
id: "test1@mochi.test",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
compose_action: {
|
||||||
|
default_title: "default",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
extension.onMessage("checkProperty", async (property, expected) => {
|
||||||
|
let composeWindows = [...Services.wm.getEnumerator("msgcompose")];
|
||||||
|
is(composeWindows.length, 3);
|
||||||
|
|
||||||
|
for (let i = 0; i < 3; i++) {
|
||||||
|
let button = composeWindows[i].document.getElementById(
|
||||||
|
"test1_mochi_test-composeAction-toolbarbutton"
|
||||||
|
);
|
||||||
|
switch (property) {
|
||||||
|
case "isEnabled":
|
||||||
|
is(button.disabled, !expected[i], `button ${i} enabled state`);
|
||||||
|
break;
|
||||||
|
case "getTitle":
|
||||||
|
is(button.getAttribute("label"), expected[i], `button ${i} label`);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension.sendMessage();
|
||||||
|
});
|
||||||
|
|
||||||
|
await extension.startup();
|
||||||
|
await extension.awaitFinish("finished");
|
||||||
|
await extension.unload();
|
||||||
|
});
|
|
@ -0,0 +1,174 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, you can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
add_task(async () => {
|
||||||
|
let account = createAccount();
|
||||||
|
addIdentity(account);
|
||||||
|
let rootFolder = account.incomingServer.rootFolder;
|
||||||
|
rootFolder.createSubfolder("test", null);
|
||||||
|
let folder = rootFolder.getChildNamed("test");
|
||||||
|
createMessages(folder, 1);
|
||||||
|
|
||||||
|
window.gFolderTreeView.selectFolder(folder);
|
||||||
|
window.gFolderDisplay.selectViewIndex(0);
|
||||||
|
|
||||||
|
window.MsgOpenSelectedMessages();
|
||||||
|
window.MsgOpenNewWindowForMessage();
|
||||||
|
await new Promise(resolve => executeSoon(resolve));
|
||||||
|
|
||||||
|
let extension = ExtensionTestUtils.loadExtension({
|
||||||
|
background: async () => {
|
||||||
|
async function checkProperty(property, expectedDefault, ...expected) {
|
||||||
|
browser.test.log(
|
||||||
|
`${property}: ${expectedDefault}, ${expected.join(", ")}`
|
||||||
|
);
|
||||||
|
|
||||||
|
browser.test.assertEq(
|
||||||
|
expectedDefault,
|
||||||
|
await browser.messageDisplayAction[property]({})
|
||||||
|
);
|
||||||
|
for (let i = 0; i < 3; i++) {
|
||||||
|
browser.test.assertEq(
|
||||||
|
expected[i],
|
||||||
|
await browser.messageDisplayAction[property]({ tabId: tabIDs[i] })
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
await new Promise(resolve => {
|
||||||
|
browser.test.onMessage.addListener(function listener() {
|
||||||
|
browser.test.onMessage.removeListener(listener);
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
|
browser.test.sendMessage("checkProperty", property, expected);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let tabs = await browser.tabs.query({});
|
||||||
|
browser.test.assertEq(3, tabs.length);
|
||||||
|
let tabIDs = tabs.map(t => t.id);
|
||||||
|
|
||||||
|
await checkProperty("isEnabled", true, true, true, true);
|
||||||
|
await browser.messageDisplayAction.disable();
|
||||||
|
await checkProperty("isEnabled", false, false, false, false);
|
||||||
|
await browser.messageDisplayAction.enable(tabIDs[0]);
|
||||||
|
await checkProperty("isEnabled", false, true, false, false);
|
||||||
|
await browser.messageDisplayAction.enable();
|
||||||
|
await checkProperty("isEnabled", true, true, true, true);
|
||||||
|
await browser.messageDisplayAction.disable();
|
||||||
|
await checkProperty("isEnabled", false, true, false, false);
|
||||||
|
await browser.messageDisplayAction.disable(tabIDs[0]);
|
||||||
|
await checkProperty("isEnabled", false, false, false, false);
|
||||||
|
await browser.messageDisplayAction.enable();
|
||||||
|
await checkProperty("isEnabled", true, false, true, true);
|
||||||
|
|
||||||
|
await checkProperty(
|
||||||
|
"getTitle",
|
||||||
|
"default",
|
||||||
|
"default",
|
||||||
|
"default",
|
||||||
|
"default"
|
||||||
|
);
|
||||||
|
await browser.messageDisplayAction.setTitle({
|
||||||
|
tabId: tabIDs[2],
|
||||||
|
title: "tab2",
|
||||||
|
});
|
||||||
|
await checkProperty("getTitle", "default", "default", "default", "tab2");
|
||||||
|
await browser.messageDisplayAction.setTitle({ title: "new" });
|
||||||
|
await checkProperty("getTitle", "new", "new", "new", "tab2");
|
||||||
|
await browser.messageDisplayAction.setTitle({
|
||||||
|
tabId: tabIDs[1],
|
||||||
|
title: "tab1",
|
||||||
|
});
|
||||||
|
await checkProperty("getTitle", "new", "new", "tab1", "tab2");
|
||||||
|
await browser.messageDisplayAction.setTitle({
|
||||||
|
tabId: tabIDs[2],
|
||||||
|
title: null,
|
||||||
|
});
|
||||||
|
await checkProperty("getTitle", "new", "new", "tab1", "new");
|
||||||
|
await browser.messageDisplayAction.setTitle({ title: null });
|
||||||
|
await checkProperty("getTitle", "default", "default", "tab1", "default");
|
||||||
|
await browser.messageDisplayAction.setTitle({
|
||||||
|
tabId: tabIDs[1],
|
||||||
|
title: null,
|
||||||
|
});
|
||||||
|
await checkProperty(
|
||||||
|
"getTitle",
|
||||||
|
"default",
|
||||||
|
"default",
|
||||||
|
"default",
|
||||||
|
"default"
|
||||||
|
);
|
||||||
|
|
||||||
|
await browser.tabs.remove(tabIDs[0]);
|
||||||
|
await browser.tabs.remove(tabIDs[1]);
|
||||||
|
await browser.tabs.remove(tabIDs[2]);
|
||||||
|
browser.test.notifyPass("finished");
|
||||||
|
},
|
||||||
|
manifest: {
|
||||||
|
applications: {
|
||||||
|
gecko: {
|
||||||
|
id: "test1@mochi.test",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
message_display_action: {
|
||||||
|
default_title: "default",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
await extension.startup();
|
||||||
|
|
||||||
|
let tabmail = document.getElementById("tabmail");
|
||||||
|
let mainWindowTabs = tabmail.tabInfo;
|
||||||
|
is(mainWindowTabs.length, 2);
|
||||||
|
|
||||||
|
let mainWindowButton = document.getElementById(
|
||||||
|
"test1_mochi_test-messageDisplayAction-toolbarbutton"
|
||||||
|
);
|
||||||
|
|
||||||
|
let messageWindow = Services.wm.getMostRecentWindow("mail:messageWindow");
|
||||||
|
let messageWindowButton = messageWindow.document.getElementById(
|
||||||
|
"test1_mochi_test-messageDisplayAction-toolbarbutton"
|
||||||
|
);
|
||||||
|
|
||||||
|
extension.onMessage("checkProperty", async (property, expected) => {
|
||||||
|
function checkButton(button, expectedIndex) {
|
||||||
|
switch (property) {
|
||||||
|
case "isEnabled":
|
||||||
|
is(
|
||||||
|
button.disabled,
|
||||||
|
!expected[expectedIndex],
|
||||||
|
`button ${expectedIndex} enabled state`
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
case "getTitle":
|
||||||
|
is(
|
||||||
|
button.getAttribute("label"),
|
||||||
|
expected[expectedIndex],
|
||||||
|
`button ${expectedIndex} label`
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 0; i < 2; i++) {
|
||||||
|
tabmail.switchToTab(mainWindowTabs[i]);
|
||||||
|
await new Promise(resolve => requestAnimationFrame(resolve));
|
||||||
|
checkButton(mainWindowButton, i);
|
||||||
|
}
|
||||||
|
checkButton(messageWindowButton, 2);
|
||||||
|
|
||||||
|
extension.sendMessage();
|
||||||
|
});
|
||||||
|
|
||||||
|
await extension.awaitFinish("finished");
|
||||||
|
await extension.unload();
|
||||||
|
|
||||||
|
messageWindow.close();
|
||||||
|
tabmail.closeTab(mainWindowTabs[1]);
|
||||||
|
is(tabmail.tabInfo.length, 1);
|
||||||
|
|
||||||
|
document.getElementById("folderTree").focus();
|
||||||
|
await new Promise(resolve => executeSoon(resolve));
|
||||||
|
});
|
Загрузка…
Ссылка в новой задаче