Bug 1572946 - Explicitly persist browser/composeAction toolbar position, and clear on uninstall. r=mkmelin a=jorgk
authorGeoff Lankow <geoff@darktrojan.net>
Tue, 13 Aug 2019 11:11:14 +1200
changeset 35290 a221fedbe06298daff382f00ab1e5890c3f6b1b3
parent 35289 4d87c1eeaf459c63c013e206c36252dc75a7bac0
child 35291 4081e478928cf08b3eecda59423387a6eefd86eb
push id2477
push usermozilla@jorgk.com
push dateTue, 13 Aug 2019 21:14:23 +0000
treeherdercomm-beta@436d8b620b6a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmkmelin, jorgk
bugs1572946
Bug 1572946 - Explicitly persist browser/composeAction toolbar position, and clear on uninstall. r=mkmelin a=jorgk
mail/components/extensions/ExtensionToolbarButtons.jsm
mail/components/extensions/ext-mail.json
mail/components/extensions/parent/ext-browserAction.js
mail/components/extensions/parent/ext-composeAction.js
mail/components/extensions/test/browser/browser_ext_browserAction.js
mail/components/extensions/test/browser/browser_ext_composeAction.js
--- a/mail/components/extensions/ExtensionToolbarButtons.jsm
+++ b/mail/components/extensions/ExtensionToolbarButtons.jsm
@@ -54,16 +54,33 @@ this.ToolbarButtonAPI = class extends Ex
       enabled: true,
       title: options.default_title || extension.name,
       badgeText: "",
       badgeBackgroundColor: null,
       popup: options.default_popup || "",
     };
     this.globals = Object.create(this.defaults);
 
+    // In tests, startupReason is undefined, because the test suite is naughty.
+    // Assume ADDON_INSTALL.
+    if (!this.extension.startupReason || this.extension.startupReason == "ADDON_INSTALL") {
+      for (let windowURL of this.windowURLs) {
+        let currentSet = Services.xulStore.getValue(windowURL, this.toolbarId, "currentset");
+        if (!currentSet) {
+          continue;
+        }
+        currentSet = currentSet.split(",");
+        if (currentSet.includes(this.id)) {
+          continue;
+        }
+        currentSet.push(this.id);
+        Services.xulStore.setValue(windowURL, this.toolbarId, "currentset", currentSet.join(","));
+      }
+    }
+
     this.browserStyle = options.browser_style;
 
     this.defaults.icon = await StartupCache.get(
       extension, [this.manifestName, "default_icon"],
       () => IconDetails.normalize({
         path: options.default_icon,
         iconType: this.manifestName,
         themeIcons: options.theme_icons,
@@ -133,28 +150,25 @@ this.ToolbarButtonAPI = class extends Ex
       return;
     }
     let button = this.makeButton(window);
     if (toolbox.palette) {
       toolbox.palette.appendChild(button);
     } else {
       toolbar.appendChild(button);
     }
-    let currentSet = toolbar.hasAttribute("currentset") ?
-                     toolbar.getAttribute("currentset") :
-                     toolbar.getAttribute("defaultset");
-    currentSet = currentSet.split(",");
-    if (currentSet.includes(this.id)) {
-      toolbar.currentSet = currentSet.join(",");
+    if (Services.xulStore.hasValue(window.location.href, this.toolbarId, "currentset")) {
+      toolbar.currentSet = Services.xulStore.getValue(window.location.href, this.toolbarId, "currentset");
+      toolbar.setAttribute("currentset", toolbar.currentSet);
     } else {
-      currentSet.push(this.id);
-      toolbar.currentSet = currentSet.join(",");
-
-      let persistAttribute = toolbar.getAttribute("persist");
-      if (persistAttribute && persistAttribute.split(/\s+/).includes("currentset")) {
+      let currentSet = toolbar.getAttribute("defaultset").split(",");
+      if (!currentSet.includes(this.id)) {
+        currentSet.push(this.id);
+        toolbar.currentSet = currentSet.join(",");
+        toolbar.setAttribute("currentset", toolbar.currentSet);
         Services.xulStore.persist(toolbar, "currentset");
       }
     }
   }
 
   /**
    * Removes the toolbar button from this window.
    *
--- a/mail/components/extensions/ext-mail.json
+++ b/mail/components/extensions/ext-mail.json
@@ -15,16 +15,17 @@
       ["addressBooks"], ["contacts"], ["mailingLists"]
     ]
   },
   "browserAction": {
     "url": "chrome://messenger/content/parent/ext-browserAction.js",
     "schema": "chrome://messenger/content/schemas/browserAction.json",
     "scopes": ["addon_parent"],
     "manifest": ["browser_action"],
+    "events": ["uninstall"],
     "paths": [
       ["browserAction"]
     ]
   },
   "chrome_settings_overrides": {
     "url": "chrome://messenger/content/parent/ext-chrome-settings-overrides.js",
     "scopes": [],
     "events": ["update", "uninstall"],
@@ -58,16 +59,17 @@
       ["compose"]
     ]
   },
   "composeAction": {
     "url": "chrome://messenger/content/parent/ext-composeAction.js",
     "schema": "chrome://messenger/content/schemas/composeAction.json",
     "scopes": ["addon_parent"],
     "manifest": ["compose_action"],
+    "events": ["uninstall"],
     "paths": [
       ["composeAction"]
     ]
   },
   "folders": {
     "url": "chrome://messenger/content/parent/ext-folders.js",
     "schema": "chrome://messenger/content/schemas/folders.json",
     "scopes": ["addon_parent"],
--- a/mail/components/extensions/parent/ext-browserAction.js
+++ b/mail/components/extensions/parent/ext-browserAction.js
@@ -16,16 +16,30 @@ this.browserAction = class extends Toolb
     browserActionMap.set(this.extension, this);
   }
 
   close() {
     super.close();
     browserActionMap.delete(this.extension);
   }
 
+  static onUninstall(extensionId) {
+    let widgetId = makeWidgetId(extensionId);
+    let id = `${widgetId}-browserAction-toolbarbutton`;
+
+    let windowURL = "chrome://messenger/content/messenger.xul";
+    let currentSet = Services.xulStore.getValue(windowURL, "mail-bar3", "currentset");
+    currentSet = currentSet.split(",");
+    let index = currentSet.indexOf(id);
+    if (index >= 0) {
+      currentSet.splice(index, 1);
+      Services.xulStore.setValue(windowURL, "mail-bar3", "currentset", currentSet.join(","));
+    }
+  }
+
   constructor(extension) {
     super(extension);
     this.manifest_name = "browser_action";
     this.manifestName = "browserAction";
     this.windowURLs = ["chrome://messenger/content/messenger.xul"];
     this.toolboxId = "mail-toolbox";
     this.toolbarId = "mail-bar3";
   }
--- a/mail/components/extensions/parent/ext-composeAction.js
+++ b/mail/components/extensions/parent/ext-composeAction.js
@@ -29,9 +29,23 @@ this.composeAction = class extends Toolb
     let toolbar = document.getElementById(this.toolbarId);
     let button = this.makeButton(window);
     let before = toolbar.lastElementChild;
     while (before.localName == "spacer") {
       before = before.previousElementSibling;
     }
     toolbar.insertBefore(button, before.nextElementSibling);
   }
+
+  static onUninstall(extensionId) {
+    let widgetId = makeWidgetId(extensionId);
+    let id = `${widgetId}-composeAction-toolbarbutton`;
+
+    let windowURL = "chrome://messenger/content/messengercompose/messengercompose.xul";
+    let currentSet = Services.xulStore.getValue(windowURL, "composeToolbar2", "currentset");
+    currentSet = currentSet.split(",");
+    let index = currentSet.indexOf(id);
+    if (index >= 0) {
+      currentSet.splice(index, 1);
+      Services.xulStore.setValue(windowURL, "composeToolbar2", "currentset", currentSet.join(","));
+    }
+  }
 };
--- a/mail/components/extensions/test/browser/browser_ext_browserAction.js
+++ b/mail/components/extensions/test/browser/browser_ext_browserAction.js
@@ -1,90 +1,103 @@
 /* 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 () => {
   async function test_it(extension) {
     await extension.startup();
+    await new Promise(resolve => setTimeout(resolve));
 
     let buttonId = "test1_mochi_test-browserAction-toolbarbutton";
     let toolbar = document.getElementById("mail-bar3");
-    ok(!toolbar.getAttribute("currentset"), "No toolbar current set");
 
     let button = document.getElementById(buttonId);
     ok(button, "Button created");
     is(toolbar.id, button.parentNode.id, "Button added to toolbar");
     ok(toolbar.currentSet.split(",").includes(buttonId), "Button added to toolbar current set");
+    ok(toolbar.getAttribute("currentset").split(",").includes(buttonId),
+       "Button added to toolbar current set attribute");
+    ok(Services.xulStore.getValue(location.href, "mail-bar3", "currentset")
+                        .split(",")
+                        .includes(buttonId),
+       "Button added to toolbar current set persistence");
 
     let icon = button.querySelector(".toolbarbutton-icon");
     is(getComputedStyle(icon).listStyleImage,
        `url("chrome://messenger/content/extension.svg")`, "Default icon");
     let label = button.querySelector(".toolbarbutton-text");
     is(label.value, "This is a test", "Correct label");
 
     EventUtils.synthesizeMouseAtCenter(button, { clickCount: 1 });
-    await extension.awaitFinish("browserAction");
+    await extension.awaitMessage("browserAction");
     await promiseAnimationFrame();
 
     is(document.getElementById(buttonId), button);
     label = button.querySelector(".toolbarbutton-text");
     is(label.value, "New title", "Correct label");
 
     await extension.unload();
     await promiseAnimationFrame();
 
     ok(!document.getElementById(buttonId), "Button destroyed");
+    ok(!Services.xulStore.getValue(location.href, "mail-bar3", "currentset")
+                         .split(",")
+                         .includes(buttonId),
+       "Button removed from toolbar current set persistence");
   }
 
   async function background_nopopup() {
     browser.browserAction.onClicked.addListener(async () => {
       await browser.browserAction.setTitle({ title: "New title" });
-      await new Promise(setTimeout);
-      browser.test.notifyPass("browserAction");
+      browser.test.sendMessage("browserAction");
     });
   }
 
   async function background_popup() {
     browser.runtime.onMessage.addListener(async (msg) => {
       browser.test.assertEq("popup.html", msg);
       await browser.browserAction.setTitle({ title: "New title" });
-      await new Promise(setTimeout);
-      browser.test.notifyPass("browserAction");
+      browser.test.sendMessage("browserAction");
     });
   }
 
   let extensionDetails = {
     background: background_nopopup,
     files: {
       "popup.html": `<html>
           <head>
             <meta charset="utf-8">
             <script src="popup.js"></script>
           </head>
           <body>popup.js</body>
         </html>`,
       "popup.js": function() {
         window.onload = async () => {
+          // eslint-disable-next-line mozilla/no-arbitrary-setTimeout
+          await new Promise(resolve => setTimeout(resolve, 1000));
           await browser.runtime.sendMessage("popup.html");
           window.close();
         };
       },
     },
     manifest: {
       applications: {
         gecko: {
           id: "test1@mochi.test",
         },
       },
       browser_action: {
         default_title: "This is a test",
       },
     },
+    useAddonManager: "temporary",
   };
   let extension = ExtensionTestUtils.loadExtension(extensionDetails);
   await test_it(extension);
 
   extensionDetails.background = background_popup;
   extensionDetails.manifest.browser_action.default_popup = "popup.html";
   extension = ExtensionTestUtils.loadExtension(extensionDetails);
   await test_it(extension);
+
+  Services.xulStore.removeDocument("chrome://messenger/content/messenger.xul");
 });
--- a/mail/components/extensions/test/browser/browser_ext_composeAction.js
+++ b/mail/components/extensions/test/browser/browser_ext_composeAction.js
@@ -33,44 +33,59 @@ async function test_it(extensionDetails,
   let buttonId = "test1_mochi_test-composeAction-toolbarbutton";
 
   await extension.startup();
   await extension.awaitMessage();
 
   let composeWindow = await openComposeWindow();
   let composeDocument = composeWindow.document;
   await promiseAnimationFrame(composeWindow);
+  await new Promise(resolve => composeWindow.setTimeout(resolve));
 
   try {
     let toolbar = composeDocument.getElementById(toolbarId);
-    ok(!toolbar.getAttribute("currentset"), "No toolbar current set");
 
     let button = composeDocument.getElementById(buttonId);
     ok(button, "Button created");
     is(toolbar.id, button.parentNode.id, "Button added to toolbar");
     ok(toolbar.currentSet.split(",").includes(buttonId), "Button added to toolbar current set");
+    if (toolbarId != "FormatToolbar") {
+      ok(toolbar.getAttribute("currentset").split(",").includes(buttonId),
+         "Button added to toolbar current set attribute");
+      ok(Services.xulStore.getValue(composeWindow.location.href, toolbarId, "currentset")
+                          .split(",")
+                          .includes(buttonId),
+         "Button added to toolbar current set persistence");
+    }
 
     let icon = button.querySelector(".toolbarbutton-icon");
     is(getComputedStyle(icon).listStyleImage,
        `url("chrome://messenger/content/extension.svg")`, "Default icon");
     let label = button.querySelector(".toolbarbutton-text");
     is(label.value, "This is a test", "Correct label");
 
     EventUtils.synthesizeMouseAtCenter(button, { clickCount: 1 }, composeWindow);
-    await extension.awaitFinish("composeAction");
+    await extension.awaitMessage("composeAction");
     await promiseAnimationFrame(composeWindow);
 
     is(composeDocument.getElementById(buttonId), button);
 
     label = button.querySelector(".toolbarbutton-text");
     is(label.value, "New title", "Correct label");
   } finally {
     await extension.unload();
     await promiseAnimationFrame(composeWindow);
+
     ok(!composeDocument.getElementById(buttonId), "Button destroyed");
+    if (toolbarId != "FormatToolbar") {
+      ok(!Services.xulStore.getValue(composeWindow.location.href, toolbarId, "currentset")
+                           .split(",")
+                           .includes(buttonId),
+        "Button removed from toolbar current set persistence");
+    }
     composeWindow.close();
   }
 }
 
 add_task(async function setup() {
   gAccount = createAccount();
   addIdentity(gAccount);
   let rootFolder = gAccount.incomingServer.rootFolder;
@@ -80,68 +95,75 @@ add_task(async function setup() {
 });
 
 add_task(async function the_test() {
   async function background_nopopup() {
     browser.test.log("nopopup background script ran");
     browser.composeAction.onClicked.addListener(async () => {
       await browser.composeAction.setTitle({ title: "New title" });
       await new Promise(setTimeout);
-      browser.test.notifyPass("composeAction");
+      browser.test.sendMessage("composeAction");
     });
+
     browser.test.sendMessage();
   }
 
   async function background_popup() {
     browser.test.log("popup background script ran");
     browser.runtime.onMessage.addListener(async (msg) => {
       browser.test.assertEq("popup.html", msg);
       await browser.composeAction.setTitle({ title: "New title" });
       await new Promise(setTimeout);
-      browser.test.notifyPass("composeAction");
+      browser.test.sendMessage("composeAction");
     });
+
     browser.test.sendMessage();
   }
 
   let extensionDetails = {
     background: background_nopopup,
     files: {
       "popup.html": `<html>
           <head>
             <meta charset="utf-8">
             <script src="popup.js"></script>
           </head>
           <body>popup.js</body>
         </html>`,
       "popup.js": function() {
         window.onload = async () => {
+          // eslint-disable-next-line mozilla/no-arbitrary-setTimeout
+          await new Promise(resolve => setTimeout(resolve, 1000));
           await browser.runtime.sendMessage("popup.html");
           window.close();
         };
       },
     },
     manifest: {
       applications: {
         gecko: {
           id: "test1@mochi.test",
         },
       },
       compose_action: {
         default_title: "This is a test",
       },
     },
+    useAddonManager: "temporary",
   };
 
   await test_it(extensionDetails, "composeToolbar2");
 
   extensionDetails.background = background_popup;
   extensionDetails.manifest.compose_action.default_popup = "popup.html";
   await test_it(extensionDetails, "composeToolbar2");
 
   extensionDetails.background = background_nopopup;
   extensionDetails.manifest.compose_action.default_area = "formattoolbar";
   delete extensionDetails.manifest.compose_action.default_popup;
   await test_it(extensionDetails, "FormatToolbar");
 
   extensionDetails.background = background_popup;
   extensionDetails.manifest.compose_action.default_popup = "popup.html";
   await test_it(extensionDetails, "FormatToolbar");
+
+  Services.xulStore.removeDocument("chrome://messenger/content/messengercompose/messengercompose.xul");
 });