Bug 1427431 - Add methods to check if browser/page/sidebar actions are enabled/shown/open draft
authorOriol Brufau <oriol-bugzilla@hotmail.com>
Thu, 11 Jan 2018 18:19:02 +0100
changeset 721159 090766c4c200f0c8c3a106b18c27ee1ec8263a88
parent 716619 b84fe2ad1ca27fc30c2e3f609b8f766185652560
child 746250 9f6b3826865d9897742d71b2cc1b49097cd1dade
push id95748
push userbmo:oriol-bugzilla@hotmail.com
push dateTue, 16 Jan 2018 20:29:37 +0000
bugs1427431
milestone59.0a1
Bug 1427431 - Add methods to check if browser/page/sidebar actions are enabled/shown/open MozReview-Commit-ID: DPbg8SwKVQL
browser/components/extensions/ext-browserAction.js
browser/components/extensions/ext-pageAction.js
browser/components/extensions/ext-sidebarAction.js
browser/components/extensions/schemas/browser_action.json
browser/components/extensions/schemas/page_action.json
browser/components/extensions/schemas/sidebar_action.json
browser/components/extensions/test/browser/browser_ext_browserAction_context.js
browser/components/extensions/test/browser/browser_ext_sidebarAction.js
browser/components/extensions/test/browser/head_pageAction.js
--- 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);