Bug 1384608 Show complete themes with legacy extensions draft
authorAndrew Swan <aswan@mozilla.com>
Wed, 13 Sep 2017 13:23:39 -0700
changeset 665206 e0940ae237c3da0629b6208815fb11eb609526d5
parent 663134 a73cc4e08bf5a005722c95b43f84ab0c8ff2bc7c
child 731688 7239785c1fedda69536a210173a444d805aff73d
push id79966
push useraswan@mozilla.com
push dateFri, 15 Sep 2017 02:58:57 +0000
bugs1384608
milestone57.0a1
Bug 1384608 Show complete themes with legacy extensions MozReview-Commit-ID: 6jiQZ8SQpzI
toolkit/locales/en-US/chrome/mozapps/extensions/extensions.dtd
toolkit/locales/en-US/chrome/mozapps/extensions/extensions.properties
toolkit/mozapps/extensions/content/extensions.js
toolkit/mozapps/extensions/content/extensions.xml
toolkit/mozapps/extensions/content/extensions.xul
toolkit/mozapps/extensions/test/browser/browser.ini
toolkit/mozapps/extensions/test/browser/browser_legacy.js
toolkit/mozapps/extensions/test/browser/browser_legacy_themes.js
--- a/toolkit/locales/en-US/chrome/mozapps/extensions/extensions.dtd
+++ b/toolkit/locales/en-US/chrome/mozapps/extensions/extensions.dtd
@@ -253,13 +253,12 @@
      being a link to an external site. -->
 <!ENTITY disabledUnsigned.devInfo.start "Developers interested in getting their add-ons verified can continue by reading our ">
 <!ENTITY disabledUnsigned.devInfo.linkToManual "manual">
 <!ENTITY disabledUnsigned.devInfo.end ".">
 
 <!ENTITY pluginDeprecation.description "Missing something? Some plugins are no longer supported by &brandShortName;.">
 <!ENTITY pluginDeprecation.learnMore "Learn More.">
 
-<!ENTITY legacyWarning.description "Missing something? Some extensions are no longer supported by &brandShortName;.">
 <!ENTITY legacyWarning.showLegacy "Show legacy extensions">
 <!ENTITY legacyExtensions.title "Legacy Extensions">
 <!ENTITY legacyExtensions.description "These extensions do not meet current &brandShortName; standards so they have been deactivated.">
 <!ENTITY legacyExtensions.learnMore "Learn about the changes to add-ons">
--- a/toolkit/locales/en-US/chrome/mozapps/extensions/extensions.properties
+++ b/toolkit/locales/en-US/chrome/mozapps/extensions/extensions.properties
@@ -185,8 +185,13 @@ type.extension.name=Extensions
 type.themes.name=Themes
 type.locale.name=Languages
 type.plugin.name=Plugins
 type.dictionary.name=Dictionaries
 type.service.name=Services
 type.experiment.name=Experiments
 type.legacy.name=Legacy Extensions
 type.unsupported.name=Unsupported
+
+#LOCALIZATION NOTE(legacyWarning.description) %S is the brandShortName
+legacyWarning.description=Missing something? Some extensions are no longer supported by %S.
+#LOCALIZATION NOTE(legacyThemeWarning.description) %S is the brandShortName
+legacyThemeWarning.description=Missing something? Some themes are no longer supported by %S.
--- a/toolkit/mozapps/extensions/content/extensions.js
+++ b/toolkit/mozapps/extensions/content/extensions.js
@@ -2788,17 +2788,17 @@ var gLegacyView = {
     gEventManager.unregisterAddonListener(this, "ANY");
   },
 
   onUninstalled() {
     this.refreshVisibility();
   },
 
   async show(type, request) {
-    let addons = await AddonManager.getAddonsByTypes(["extension"]);
+    let addons = await AddonManager.getAddonsByTypes(["extension", "theme"]);
     addons = addons.filter(a => !a.hidden &&
                               (isDisabledLegacy(a) || isDisabledUnsigned(a)));
 
     while (this._listBox.itemCount > 0)
       this._listBox.removeItemAt(0);
 
     let elements = addons.map(a => createItem(a));
     if (elements.length == 0) {
@@ -2826,17 +2826,17 @@ var gLegacyView = {
   },
 
   async refreshVisibility() {
     if (legacyExtensionsEnabled) {
       this._categoryItem.disabled = true;
       return;
     }
 
-    let extensions = await AddonManager.getAddonsByTypes(["extension"]);
+    let extensions = await AddonManager.getAddonsByTypes(["extension", "theme"]);
 
     let haveUnsigned = false;
     let haveLegacy = false;
     for (let extension of extensions) {
       if (isDisabledUnsigned(extension)) {
         haveUnsigned = true;
       }
       if (isLegacyExtension(extension)) {
@@ -2965,17 +2965,31 @@ var gListView = {
       this.showEmptyNotice(elements.length == 0);
       if (elements.length > 0) {
         sortElements(elements, ["uiState", "name"], true);
         for (let element of elements)
           this._listBox.appendChild(element);
       }
 
       this.filterDisabledUnsigned(showOnlyDisabledUnsigned);
-      document.getElementById("legacy-extensions-notice").hidden = !showLegacyInfo;
+      let legacyNotice = document.getElementById("legacy-extensions-notice");
+      if (showLegacyInfo) {
+        let el = document.getElementById("legacy-extensions-description");
+        if (el.childNodes[0].nodeName == "#text") {
+          el.removeChild(el.childNodes[0]);
+        }
+
+        let descriptionId = (aType == "theme") ?
+                            "legacyThemeWarning.description" : "legacyWarning.description";
+        let text = gStrings.ext.formatStringFromName(descriptionId, [gStrings.brandShortName], 1) + " ";
+        el.insertBefore(document.createTextNode(text), el.childNodes[0]);
+        legacyNotice.hidden = false;
+      } else {
+        legacyNotice.hidden = true;
+      }
 
       gEventManager.registerInstallListener(this);
       gViewController.updateCommands();
       gViewController.notifyViewChanged();
     });
   },
 
   hide() {
--- a/toolkit/mozapps/extensions/content/extensions.xml
+++ b/toolkit/mozapps/extensions/content/extensions.xml
@@ -1298,16 +1298,17 @@
               this.setAttribute("notification", "warning");
               this._warning.textContent = gStrings.ext.formatStringFromName(
                 "notification.incompatible",
                 [this.mAddon.name, gStrings.brandShortName, gStrings.appVersion], 3
               );
               this._warningLink.hidden = true;
               this._warningBtn.hidden = true;
             } else if (!isUpgrade && this.mAddon.appDisabled &&
+                       this.mAddon.type == "extension" &&
                        !this.mAddon.multiprocessCompatible &&
                        !Services.prefs.getBoolPref("extensions.allow-non-mpc-extensions", true)) {
               this.setAttribute("notification", "error");
               this._error.textContent = gStrings.ext.formatStringFromName(
                 "notification.nonMpcDisabled", [this.mAddon.name], 1
               );
               this._errorLink.value = gStrings.ext.GetStringFromName("notification.nonMpcDisabled.link");
               this._errorLink.href = "https://wiki.mozilla.org/Add-ons/ShimsNightly";
@@ -1642,17 +1643,20 @@
         <body><![CDATA[
           gViewController.loadView("addons://detail/" +
                                    encodeURIComponent(this.mAddon.id));
         ]]></body>
       </method>
 
       <method name="findReplacement">
         <body><![CDATA[
-          openURL(`https://addons.mozilla.org/find-replacement/?guid=${this.mAddon.id}`);
+          let url = (this.mAddon.type == "theme") ?
+            SUPPORT_URL + "complete-themes" :
+            `https://addons.mozilla.org/find-replacement/?guid=${this.mAddon.id}`;
+            openURL(url);
         ]]></body>
       </method>
 
       <method name="onIncludeUpdateChanged">
         <body><![CDATA[
           var event = document.createEvent("Events");
           event.initEvent("IncludeUpdateChanged", true, true);
           this.dispatchEvent(event);
--- a/toolkit/mozapps/extensions/content/extensions.xul
+++ b/toolkit/mozapps/extensions/content/extensions.xul
@@ -363,17 +363,17 @@
                 </description>
                 <hbox pack="start"><label class="text-link" id="signing-learn-more">&disabledUnsigned.learnMore;</label></hbox>
                 <description id="signing-dev-info">
                   &disabledUnsigned.devInfo.start;<label class="text-link plain" id="signing-dev-manual-link">&disabledUnsigned.devInfo.linkToManual;</label>&disabledUnsigned.devInfo.end;
                 </description>
               </vbox>
               <vbox id="legacy-extensions-notice" class="alert-container" hidden="true">
                 <vbox class="alert">
-                  <description>&legacyWarning.description;
+                  <description id="legacy-extensions-description">
                     <label class="text-link plain" id="legacy-extensions-learnmore-link">&legacyWarning.showLegacy;</label>
                   </description>
                 </vbox>
               </vbox>
               <vbox id="plugindeprecation-notice" class="alert-container">
                 <vbox class="alert">
                   <description>&pluginDeprecation.description; &#160;
                     <label class="text-link plain" id="plugindeprecation-learnmore-link">&pluginDeprecation.learnMore;</label>
--- a/toolkit/mozapps/extensions/test/browser/browser.ini
+++ b/toolkit/mozapps/extensions/test/browser/browser.ini
@@ -48,16 +48,17 @@ support-files =
 skip-if = buildapp == 'mulet'
 [browser_file_xpi_no_process_switch.js]
 [browser_getmorethemes.js]
 [browser_gmpProvider.js]
 [browser_install.js]
 [browser_installssl.js]
 [browser_legacy.js]
 [browser_legacy_pre57.js]
+[browser_legacy_themes.js]
 [browser_newaddon.js]
 [browser_non_mpc.js]
 [browser_searching.js]
 [browser_system_addons_are_e10s.js]
 [browser_task_next_test.js]
 [browser_update.js]
 [browser_updatessl.js]
 [browser_webapi.js]
--- a/toolkit/mozapps/extensions/test/browser/browser_legacy.js
+++ b/toolkit/mozapps/extensions/test/browser/browser_legacy.js
@@ -127,17 +127,17 @@ add_task(async function() {
 
   let catItem = mgrWin.gLegacyView._categoryItem;
   is(catItem.disabled, false, "Legacy category is visible");
   is(catItem.getAttribute("name"), get_string("type.legacy.name"),
      "Category label with no unsigned extensions is correct");
 
   // Follow the link to the legacy extensions page
   let legacyLink = mgrWin.document.getElementById("legacy-extensions-learnmore-link");
-  is_element_visible(legacyLink, "Link to leagcy extension is visible");
+  is_element_visible(legacyLink, "Link to legacy extension is visible");
 
   let loadPromise = new Promise(resolve => wait_for_view_load(mgrWin, resolve, true));
   legacyLink.click();
   await loadPromise;
 
   is(mgrWin.gViewController.currentViewId, "addons://legacy/",
      "Legacy extensions link leads to the correct view");
 
new file mode 100644
--- /dev/null
+++ b/toolkit/mozapps/extensions/test/browser/browser_legacy_themes.js
@@ -0,0 +1,79 @@
+
+add_task(async function() {
+  // The mochitest framework installs a bunch of legacy extensions.
+  // Fortunately, the extensions.legacy.exceptions preference exists to
+  // avoid treating some extensions as legacy for the purposes of the UI.
+  const IGNORE = [
+    "special-powers@mozilla.org",
+    "mochikit@mozilla.org",
+    "workerbootstrap-test@mozilla.org",
+    "worker-test@mozilla.org",
+  ];
+
+  let exceptions = Services.prefs.getCharPref("extensions.legacy.exceptions");
+  exceptions = [ exceptions, ...IGNORE ].join(",");
+
+  await SpecialPowers.pushPrefEnv({
+    set: [
+      ["extensions.legacy.enabled", false],
+      ["extensions.legacy.exceptions", exceptions],
+    ],
+  });
+
+  const ID = "theme@tests.mozilla.org";
+
+  let provider = new MockProvider();
+  provider.createAddons([{
+    id: ID,
+    name: "Complete Theme",
+    type: "theme",
+    appDisabled: true,
+  }]);
+
+  // Open about:addons and go to the themes list
+  let mgrWin = await open_manager(null);
+  let catUtils = new CategoryUtilities(mgrWin);
+  await catUtils.openType("theme");
+
+  // Our complete theme should not be displayed
+  let list = mgrWin.document.getElementById("addon-list");
+  let item = list.children.find(item => item.mAddon.id == ID);
+  is(item, undefined, `Theme ${ID} should not be in the list of active themes`);
+
+  // The warning banner and the legacy category should both be visible
+  let banner = mgrWin.document.getElementById("legacy-extensions-notice");
+  is_element_visible(banner, "Warning about legacy themes should be visible");
+  is(mgrWin.gLegacyView._categoryItem.disabled, false, "Legacy category should be visible ");
+
+  // Follow the link to the legacy extensions page
+  let legacyLink = mgrWin.document.getElementById("legacy-extensions-learnmore-link");
+  is_element_visible(legacyLink, "Link to legacy extensions is visible");
+
+  let loadPromise = new Promise(resolve => wait_for_view_load(mgrWin, resolve, true));
+  legacyLink.click();
+  await loadPromise;
+
+  is(mgrWin.gViewController.currentViewId, "addons://legacy/",
+     "Legacy extensions link leads to the correct view");
+
+  list = mgrWin.document.getElementById("legacy-list");
+  is(list.children.length, 1, "Should have 1 item in the legacy list");
+  item = list.children[0];
+  is(item.mAddon.id, ID, "Complete theme should be in the list");
+
+  // Click the find a replacement button
+  let button = document.getAnonymousElementByAttribute(item, "anonid", "replacement-btn");
+  is_element_visible(button, "Find a replacement butotn is visible");
+
+  // In automation, app.support.baseURL points to a page on localhost.
+  // The actual page is 404 in the test but that doesn't matter here,
+  // just the fact that we load the right URL.
+  let url = Services.prefs.getStringPref("app.support.baseURL") + "complete-themes";
+  let tabPromise = BrowserTestUtils.waitForNewTab(gBrowser, url);
+  button.click();
+  let tab = await tabPromise;
+  ok(true, "Find a replacement button opened SUMO page");
+  await BrowserTestUtils.removeTab(tab);
+
+  await close_manager(mgrWin);
+});