Bug 1427431 - Add methods to check if browser/page/sidebar actions are enabled/shown/open
MozReview-Commit-ID: DPbg8SwKVQL
--- a/browser/components/extensions/ext-browserAction.js
+++ b/browser/components/extensions/ext-browserAction.js
@@ -604,16 +604,21 @@ this.browserAction = class extends Exten
browserAction.setProperty(tab, "enabled", true);
},
disable: function(tabId) {
let tab = getTab(tabId);
browserAction.setProperty(tab, "enabled", false);
},
+ isEnabled: function(details) {
+ let tab = getTab(details.tabId);
+ return browserAction.getProperty(tab, "enabled");
+ },
+
setTitle: function(details) {
let tab = getTab(details.tabId);
browserAction.setProperty(tab, "title", details.title);
},
getTitle: function(details) {
let tab = getTab(details.tabId);
--- a/browser/components/extensions/ext-pageAction.js
+++ b/browser/components/extensions/ext-pageAction.js
@@ -36,17 +36,17 @@ this.pageAction = class extends Extensio
let options = extension.manifest.page_action;
let widgetId = makeWidgetId(extension.id);
this.id = widgetId + "-page-action";
this.tabManager = extension.tabManager;
// If <all_urls> is present, the default is to show the page action.
- let show = options.show_matches && options.show_matches.includes("<all_urls>");
+ let show = !!options.show_matches && options.show_matches.includes("<all_urls>");
let showMatches = new MatchPatternSet(options.show_matches || []);
let hideMatches = new MatchPatternSet(options.hide_matches || []);
this.defaults = {
show,
showMatches,
hideMatches,
title: options.default_title || extension.name,
@@ -267,16 +267,21 @@ this.pageAction = class extends Extensio
pageAction.setProperty(tab, "show", true);
},
hide(tabId) {
let tab = tabTracker.getTab(tabId);
pageAction.setProperty(tab, "show", false);
},
+ isShown(details) {
+ let tab = tabTracker.getTab(details.tabId);
+ return pageAction.getProperty(tab, "show");
+ },
+
setTitle(details) {
let tab = tabTracker.getTab(details.tabId);
// Clear the tab-specific title when given a null string.
pageAction.setProperty(tab, "title", details.title || null);
},
getTitle(details) {
--- a/browser/components/extensions/ext-sidebarAction.js
+++ b/browser/components/extensions/ext-sidebarAction.js
@@ -1,14 +1,15 @@
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set sts=2 sw=2 et tw=80: */
"use strict";
// The ext-* files are imported into the same scopes.
/* import-globals-from ext-browser.js */
+/* globals WINDOW_ID_CURRENT */
Cu.import("resource://gre/modules/ExtensionParent.jsm");
var {
ExtensionError,
} = ExtensionUtils;
var {
@@ -343,20 +344,30 @@ this.sidebarAction = class extends Exten
}
/**
* Closes this sidebar action for the given window if this sidebar action is open.
*
* @param {ChromeWindow} window
*/
close(window) {
+ if (this.isOpen(window)) {
+ window.SidebarUI.hide();
+ }
+ }
+
+ /**
+ * Checks whether this sidebar action is open in the given window.
+ *
+ * @param {ChromeWindow} window
+ * @returns {boolean}
+ */
+ isOpen(window) {
let {SidebarUI} = window;
- if (SidebarUI.isOpen && this.id == SidebarUI.currentID) {
- SidebarUI.hide();
- }
+ return SidebarUI.isOpen && this.id == SidebarUI.currentID;
}
getAPI(context) {
let {extension} = context;
const sidebarAction = this;
function getTab(tabId) {
if (tabId !== null) {
@@ -422,14 +433,23 @@ this.sidebarAction = class extends Exten
let window = windowTracker.topWindow;
sidebarAction.open(window);
},
close() {
let window = windowTracker.topWindow;
sidebarAction.close(window);
},
+
+ isOpen(details) {
+ let {windowId} = details;
+ if (windowId == null) {
+ windowId = WINDOW_ID_CURRENT;
+ }
+ let window = windowTracker.getWindow(windowId, context);
+ return sidebarAction.isOpen(window);
+ },
},
};
}
};
global.sidebarActionFor = this.sidebarAction.for;
--- a/browser/components/extensions/schemas/browser_action.json
+++ b/browser/components/extensions/schemas/browser_action.json
@@ -413,16 +413,35 @@
"type": "function",
"name": "callback",
"optional": true,
"parameters": []
}
]
},
{
+ "name": "isEnabled",
+ "type": "function",
+ "description": "Checks whether the browser action is enabled.",
+ "async": true,
+ "parameters": [
+ {
+ "name": "details",
+ "type": "object",
+ "properties": {
+ "tabId": {
+ "type": "integer",
+ "optional": true,
+ "description": "Specify the tab to get the enabledness from. If no tab is specified, the non-tab-specific enabledness is returned."
+ }
+ }
+ }
+ ]
+ },
+ {
"name": "openPopup",
"type": "function",
"requireUserInput": true,
"description": "Opens the extension popup window in the active window.",
"async": true,
"parameters": []
}
],
--- a/browser/components/extensions/schemas/page_action.json
+++ b/browser/components/extensions/schemas/page_action.json
@@ -92,16 +92,34 @@
"type": "function",
"name": "callback",
"optional": true,
"parameters": []
}
]
},
{
+ "name": "isShown",
+ "type": "function",
+ "description": "Checks whether the page action is shown.",
+ "async": true,
+ "parameters": [
+ {
+ "name": "details",
+ "type": "object",
+ "properties": {
+ "tabId": {
+ "type": "integer",
+ "description": "Specify the tab to get the shownness from."
+ }
+ }
+ }
+ ]
+ },
+ {
"name": "setTitle",
"type": "function",
"description": "Sets the title of the page action. This is displayed in a tooltip over the page action.",
"parameters": [
{
"name": "details",
"type": "object",
"properties": {
--- a/browser/components/extensions/schemas/sidebar_action.json
+++ b/browser/components/extensions/schemas/sidebar_action.json
@@ -192,12 +192,32 @@
},
{
"name": "close",
"type": "function",
"requireUserInput": true,
"description": "Closes the extension sidebar in the active window if the sidebar belongs to the extension.",
"async": true,
"parameters": []
+ },
+ {
+ "name": "isOpen",
+ "type": "function",
+ "description": "Checks whether the sidebar action is open.",
+ "async": true,
+ "parameters": [
+ {
+ "name": "details",
+ "type": "object",
+ "properties": {
+ "windowId": {
+ "type": "integer",
+ "minimum": -2,
+ "optional": true,
+ "description": "Specify the window to get the openness from."
+ }
+ }
+ }
+ ]
}
]
}
]
--- a/browser/components/extensions/test/browser/browser_ext_browserAction_context.js
+++ b/browser/components/extensions/test/browser/browser_ext_browserAction_context.js
@@ -16,16 +16,20 @@ async function runTests(options) {
let badge = await browser.browserAction.getBadgeText({tabId});
browser.test.assertEq(expecting.badge, badge,
"expected value from getBadge");
let badgeBackgroundColor = await browser.browserAction.getBadgeBackgroundColor({tabId});
browser.test.assertEq(String(expecting.badgeBackgroundColor),
String(badgeBackgroundColor),
"expected value from getBadgeBackgroundColor");
+
+ let enabled = await browser.browserAction.isEnabled({tabId});
+ browser.test.assertEq(!expecting.disabled, enabled,
+ "expected value from isEnabled");
}
let expectDefaults = expecting => {
return checkDetails(expecting);
};
let tabs = [];
let tests = getTests(tabs, expectDefaults);
@@ -280,17 +284,17 @@ add_task(async function testTabSwitchCon
await expectDefaults(details[4]);
expect(details[4]);
},
async expect => {
browser.test.log("Switch back to tab 2. Expect former value, unaffected by changes to defaults in previous step.");
await browser.tabs.update(tabs[1], {active: true});
- await expectDefaults(details[3]);
+ await expectDefaults(details[4]);
expect(details[2]);
},
expect => {
browser.test.log("Navigate to a new page. Expect defaults.");
browser.tabs.onUpdated.addListener(function listener(tabId, changed) {
if (tabId == tabs[1] && changed.url) {
browser.tabs.onUpdated.removeListener(listener);
--- a/browser/components/extensions/test/browser/browser_ext_sidebarAction.js
+++ b/browser/components/extensions/test/browser/browser_ext_sidebarAction.js
@@ -27,28 +27,38 @@ let extData = {
"sidebar.js": function() {
window.onload = () => {
browser.test.sendMessage("sidebar");
};
},
},
background: function() {
- browser.test.onMessage.addListener(msg => {
+ browser.test.onMessage.addListener(async ({msg, data}) => {
if (msg === "set-panel") {
- browser.sidebarAction.setPanel({panel: ""}).then(() => {
+ await browser.sidebarAction.setPanel({panel: ""}).then(() => {
browser.test.notifyFail("empty panel settable");
}).catch(() => {
browser.test.notifyPass("unable to set empty panel");
});
+ } else if (msg === "isOpen") {
+ let {arg = {}, result} = data;
+ let isOpen = await browser.sidebarAction.isOpen(arg);
+ browser.test.assertEq(result, isOpen, "expected value from isOpen");
}
+ browser.test.sendMessage("done");
});
},
};
+async function sendMessage(ext, msg, data = undefined) {
+ ext.sendMessage({msg, data});
+ await ext.awaitMessage("done");
+}
+
add_task(async function sidebar_initial_install() {
ok(document.getElementById("sidebar-box").hidden, "sidebar box is not visible");
let extension = ExtensionTestUtils.loadExtension(extData);
await extension.startup();
// Test sidebar is opened on install
await extension.awaitMessage("sidebar");
ok(!document.getElementById("sidebar-box").hidden, "sidebar box is visible");
@@ -80,12 +90,68 @@ add_task(async function sidebar_two_side
});
add_task(async function sidebar_empty_panel() {
let extension = ExtensionTestUtils.loadExtension(extData);
await extension.startup();
// Test sidebar is opened on install
await extension.awaitMessage("sidebar");
ok(!document.getElementById("sidebar-box").hidden, "sidebar box is visible in first window");
- extension.sendMessage("set-panel");
+ await sendMessage(extension, "set-panel");
await extension.awaitFinish();
await extension.unload();
});
+
+add_task(async function sidebar_isOpen() {
+ info("Load extension1");
+ let extension1 = ExtensionTestUtils.loadExtension(extData);
+ await extension1.startup();
+
+ info("Test extension1's sidebar is opened on install");
+ await extension1.awaitMessage("sidebar");
+ await sendMessage(extension1, "isOpen", {result: true});
+ let sidebar1ID = SidebarUI.currentID;
+
+ info("Load extension2");
+ let extension2 = ExtensionTestUtils.loadExtension(extData);
+ await extension2.startup();
+
+ info("Test extension2's sidebar is opened on install");
+ await extension2.awaitMessage("sidebar");
+ await sendMessage(extension1, "isOpen", {result: false});
+ await sendMessage(extension2, "isOpen", {result: true});
+
+ info("Switch back to extension1's sidebar");
+ SidebarUI.show(sidebar1ID);
+ await extension1.awaitMessage("sidebar");
+ await sendMessage(extension1, "isOpen", {result: true});
+ await sendMessage(extension2, "isOpen", {result: false});
+
+ info("Test passing a windowId parameter");
+ let windowId = window.getInterface(Ci.nsIDOMWindowUtils).outerWindowID;
+ let WINDOW_ID_CURRENT = -2;
+ await sendMessage(extension1, "isOpen", {arg: {windowId}, result: true});
+ await sendMessage(extension2, "isOpen", {arg: {windowId}, result: false});
+ await sendMessage(extension1, "isOpen", {arg: {windowId: WINDOW_ID_CURRENT}, result: true});
+ await sendMessage(extension2, "isOpen", {arg: {windowId: WINDOW_ID_CURRENT}, result: false});
+
+ info("Open a new window");
+ let newWin = open();
+
+ info("The new window has no sidebar");
+ await sendMessage(extension1, "isOpen", {result: false});
+ await sendMessage(extension2, "isOpen", {result: false});
+
+ info("But the original window still does");
+ await sendMessage(extension1, "isOpen", {arg: {windowId}, result: true});
+ await sendMessage(extension2, "isOpen", {arg: {windowId}, result: false});
+
+ info("Close the new window");
+ newWin.close();
+
+ info("Close the sidebar in the original window");
+ SidebarUI.hide();
+ await sendMessage(extension1, "isOpen", {result: false});
+ await sendMessage(extension2, "isOpen", {result: false});
+
+ await extension1.unload();
+ await extension2.unload();
+});
--- a/browser/components/extensions/test/browser/head_pageAction.js
+++ b/browser/components/extensions/test/browser/head_pageAction.js
@@ -29,44 +29,47 @@ async function runTests(options) {
let [tab] = await browser.tabs.query({active: true, currentWindow: true});
let tabId = tab.id;
browser.test.log(`Get details: tab={id: ${tabId}, url: ${JSON.stringify(tab.url)}}`);
return {
title: await browser.pageAction.getTitle({tabId}),
popup: await browser.pageAction.getPopup({tabId}),
+ isShown: await browser.pageAction.isShown({tabId}),
};
}
// Runs the next test in the `tests` array, checks the results,
// and passes control back to the outer test scope.
function nextTest() {
let test = tests.shift();
test(async expecting => {
function finish() {
// Check that the actual icon has the expected values, then
// run the next test.
browser.test.sendMessage("nextTest", expecting, tests.length);
}
+ // Check that the API returns the expected values, and then
+ // run the next test.
+ let details = await getDetails();
if (expecting) {
- // Check that the API returns the expected values, and then
- // run the next test.
- let details = await getDetails();
-
browser.test.assertEq(expecting.title, details.title,
"expected value from getTitle");
browser.test.assertEq(expecting.popup, details.popup,
"expected value from getPopup");
}
+ browser.test.assertEq(!!expecting, details.isShown,
+ "expected value from isShown");
+
finish();
});
}
async function runTests() {
tabs = [];
tests = getTests(tabs);