summaryrefslogtreecommitdiffstats
path: root/comm/mail/base/content/aboutAddonsExtra.js
diff options
context:
space:
mode:
Diffstat (limited to 'comm/mail/base/content/aboutAddonsExtra.js')
-rw-r--r--comm/mail/base/content/aboutAddonsExtra.js211
1 files changed, 211 insertions, 0 deletions
diff --git a/comm/mail/base/content/aboutAddonsExtra.js b/comm/mail/base/content/aboutAddonsExtra.js
new file mode 100644
index 0000000000..1499d3927b
--- /dev/null
+++ b/comm/mail/base/content/aboutAddonsExtra.js
@@ -0,0 +1,211 @@
+/* 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/. */
+
+/* import-globals-from ../../../../toolkit/mozapps/extensions/content/aboutaddons.js */
+
+const THUNDERBIRD_THEME_PREVIEWS = new Map([
+ [
+ "thunderbird-compact-light@mozilla.org",
+ "resource://builtin-themes/light/preview.svg",
+ ],
+ [
+ "thunderbird-compact-dark@mozilla.org",
+ "resource://builtin-themes/dark/preview.svg",
+ ],
+]);
+
+var { UIFontSize } = ChromeUtils.import("resource:///modules/UIFontSize.jsm");
+ChromeUtils.defineESModuleGetters(this, {
+ ExtensionData: "resource://gre/modules/Extension.sys.mjs",
+});
+
+XPCOMUtils.defineLazyPreferenceGetter(
+ this,
+ "alternativeAddonSearchUrl",
+ "extensions.alternativeAddonSearch.url"
+);
+
+(async function () {
+ window.MozXULElement.insertFTLIfNeeded("messenger/aboutAddonsExtra.ftl");
+ // Needed for webext-perms-description-experiment.
+ window.MozXULElement.insertFTLIfNeeded("messenger/extensionPermissions.ftl");
+ UIFontSize.registerWindow(window);
+
+ // Consume clicks on a-tags and let openTrustedLinkIn() decide how to open them.
+ window.addEventListener("click", event => {
+ if (event.target.matches("a[href]") && event.target.href) {
+ let uri = Services.io.newURI(event.target.href);
+ if (uri.scheme == "http" || uri.scheme == "https") {
+ event.preventDefault();
+ event.stopPropagation();
+ windowRoot.ownerGlobal.openTrustedLinkIn(event.target.href, "tab");
+ }
+ }
+ });
+
+ // Fix the "Search on addons.mozilla.org" placeholder text in the searchbox.
+ let textbox = document.querySelector("search-addons > search-textbox");
+ document.l10n.setAttributes(textbox, "atn-addons-heading-search-input");
+
+ // Add our stylesheet.
+ let contentStylesheet = document.createElement("link");
+ contentStylesheet.rel = "stylesheet";
+ contentStylesheet.href = "chrome://messenger/skin/aboutAddonsExtra.css";
+ document.head.appendChild(contentStylesheet);
+
+ // Override logic for detecting unsigned add-ons.
+ window.isCorrectlySigned = function () {
+ return true;
+ };
+
+ // Load our theme screenshots.
+ let _getScreenshotUrlForAddon = getScreenshotUrlForAddon;
+ getScreenshotUrlForAddon = function (addon) {
+ if (THUNDERBIRD_THEME_PREVIEWS.has(addon.id)) {
+ return THUNDERBIRD_THEME_PREVIEWS.get(addon.id);
+ }
+ return _getScreenshotUrlForAddon(addon);
+ };
+
+ // Add logic to detect add-ons using the unsupported legacy API.
+ let getMozillaAddonMessageInfo = window.getAddonMessageInfo;
+ window.getAddonMessageInfo = async function (addon) {
+ const { name } = addon;
+ const { STATE_SOFTBLOCKED } = Ci.nsIBlocklistService;
+
+ let data = new ExtensionData(addon.getResourceURI());
+ await data.loadManifest();
+ if (
+ addon.type == "extension" &&
+ (data.manifest.legacy ||
+ (!addon.isCompatible &&
+ (AddonManager.checkCompatibility ||
+ addon.blocklistState !== STATE_SOFTBLOCKED)))
+ ) {
+ return {
+ linkText: await document.l10n.formatValue(
+ "add-on-search-alternative-button-label"
+ ),
+ linkUrl: `${alternativeAddonSearchUrl}?id=${encodeURIComponent(
+ addon.id
+ )}&q=${encodeURIComponent(name)}`,
+ messageId: "details-notification-incompatible",
+ messageArgs: { name, version: Services.appinfo.version },
+ type: "warning",
+ };
+ }
+ return getMozillaAddonMessageInfo(addon);
+ };
+ document.querySelectorAll("addon-card").forEach(card => card.updateMessage());
+
+ // Override parts of the addon-card customElement to be able
+ // to add a dedicated button for extension preferences.
+ await customElements.whenDefined("addon-card");
+ AddonCard.prototype.addOptionsButton = async function () {
+ let { addon, optionsButton } = this;
+ if (addon.type != "extension") {
+ return;
+ }
+
+ let addonOptionsButton = this.querySelector(".extension-options-button");
+ if (!addonOptionsButton) {
+ addonOptionsButton = document.createElement("button");
+ addonOptionsButton.classList.add("extension-options-button");
+ addonOptionsButton.setAttribute("action", "preferences");
+ document.l10n.setAttributes(addonOptionsButton, "add-on-options-button");
+ addonOptionsButton.disabled = true;
+ optionsButton.parentNode.insertBefore(addonOptionsButton, optionsButton);
+ }
+
+ // Upon fresh install the manifest has not been parsed and optionsType
+ // is not known, manually trigger parsing.
+ if (addon.isActive && !addon.optionsType) {
+ let data = new ExtensionData(addon.getResourceURI());
+ await data.loadManifest();
+ }
+
+ addonOptionsButton.disabled = !(addon.isActive && addon.optionsType);
+ };
+ AddonCard.prototype._update = AddonCard.prototype.update;
+ AddonCard.prototype.update = function () {
+ this._update();
+ this.addOptionsButton();
+ };
+
+ // Override parts of the addon-permission-list customElement to be able
+ // to show the usage of Experiments in the permission list.
+ await customElements.whenDefined("addon-permissions-list");
+ AddonPermissionsList.prototype.renderExperimentOnly = function () {
+ this.textContent = "";
+ let frag = importTemplate("addon-permissions-list");
+ let section = frag.querySelector(".addon-permissions-required");
+ section.hidden = false;
+ let list = section.querySelector(".addon-permissions-list");
+
+ let item = document.createElement("li");
+ document.l10n.setAttributes(item, "webext-perms-description-experiment");
+ item.classList.add("permission-info", "permission-checked");
+ list.appendChild(item);
+
+ this.appendChild(frag);
+ };
+ // We change this function from sync to async, which does not matter.
+ // It calls this.render() which is async without awaiting it anyway.
+ AddonPermissionsList.prototype.setAddon = async function (addon) {
+ this.addon = addon;
+ let data = new ExtensionData(addon.getResourceURI());
+ await data.loadManifest();
+ if (data.manifest.experiment_apis) {
+ this.renderExperimentOnly();
+ } else {
+ this.render();
+ }
+ };
+
+ await customElements.whenDefined("recommended-addon-card");
+ RecommendedAddonCard.prototype._setCardContent =
+ RecommendedAddonCard.prototype.setCardContent;
+ RecommendedAddonCard.prototype.setCardContent = function (card, addon) {
+ this._setCardContent(card, addon);
+ card.addEventListener("click", event => {
+ if (event.target.matches("a[href]") || event.target.matches("button")) {
+ return;
+ }
+ windowRoot.ownerGlobal.openTrustedLinkIn(
+ card.querySelector(".disco-addon-author a").href,
+ "tab"
+ );
+ });
+ };
+
+ await customElements.whenDefined("search-addons");
+ SearchAddons.prototype.searchAddons = function (query) {
+ if (query.length === 0) {
+ return;
+ }
+
+ let url = new URL(
+ formatUTMParams(
+ "addons-manager-search",
+ AddonRepository.getSearchURL(query)
+ )
+ );
+
+ // Limit search to themes, if the themes section is currently active.
+ if (
+ document.getElementById("page-header").getAttribute("type") == "theme"
+ ) {
+ url.searchParams.set("cat", "themes");
+ }
+
+ let browser = getBrowserElement();
+ let chromewin = browser.ownerGlobal;
+ chromewin.openLinkIn(url.href, "tab", {
+ fromChrome: true,
+ triggeringPrincipal: Services.scriptSecurityManager.createNullPrincipal(
+ {}
+ ),
+ });
+ };
+})();