author | Andrew Swan <aswan@mozilla.com> |
Tue, 02 Jul 2019 17:18:51 -0700 | |
changeset 482268 | 4fb3655540652629dffdbe4c93f43f3d982f5fe2 |
parent 482267 | f03444317763648d5375cfec9a1a8078a8722d29 |
child 482269 | d3ff15541677cdddddbb95e5ab9ffa194be0a8ba |
push id | 36273 |
push user | csabou@mozilla.com |
push date | Thu, 11 Jul 2019 04:05:30 +0000 |
treeherder | mozilla-central@72e2bc6a932e [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | mstriemer |
bugs | 1563062 |
milestone | 70.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/toolkit/mozapps/extensions/content/abuse-report-frame.js +++ b/toolkit/mozapps/extensions/content/abuse-report-frame.js @@ -1,11 +1,11 @@ "use strict"; -/* globals MozXULElement, Services, useHtmlViews, getHtmlBrowser, htmlBrowserLoaded */ +/* globals MozXULElement, Services, getHtmlBrowser, htmlBrowserLoaded */ { const ABUSE_REPORT_ENABLED = Services.prefs.getBoolPref( "extensions.abuseReport.enabled", false ); const ABUSE_REPORT_FRAME_URL = "chrome://mozapps/content/extensions/abuse-report-frame.html"; @@ -261,17 +261,17 @@ set reportEntryPoint(value) { this.setAttribute("report-entry-point", value); } } // If the html about:addons and the abuse report are both enabled, register // the custom XUL WebComponent and append it to the XUL stack element // (if not registered the element will be just a dummy hidden box) - if (useHtmlViews && ABUSE_REPORT_ENABLED) { + if (ABUSE_REPORT_ENABLED) { customElements.define( "addon-abuse-report-xulframe", AddonAbuseReportsXULFrame ); } // Helper method exported into the about:addons global, used to open the // abuse report panel from outside of the about:addons page
--- a/toolkit/mozapps/extensions/content/extensions.css +++ b/toolkit/mozapps/extensions/content/extensions.css @@ -13,135 +13,25 @@ xhtml|link { -moz-binding: url("chrome://mozapps/content/extensions/extensions.xml#category"); } .sidebar-footer-button > .text-link { margin-top: 0; margin-bottom: 0; } -.addon[status="installed"] { - -moz-box-orient: vertical; - -moz-binding: url("chrome://mozapps/content/extensions/extensions.xml#addon-generic"); -} - -.addon[status="installing"] { - -moz-box-orient: vertical; - -moz-binding: url("chrome://mozapps/content/extensions/extensions.xml#addon-installing"); -} - -.addon[pending="uninstall"] { - -moz-binding: url("chrome://mozapps/content/extensions/extensions.xml#addon-uninstalled"); -} - -.creator { - -moz-binding: url("chrome://mozapps/content/extensions/extensions.xml#creator-link"); -} - -.meta-rating { - -moz-binding: url("chrome://mozapps/content/extensions/extensions.xml#rating"); -} - -.download-progress, .download-progress[mode="undetermined"] { - -moz-binding: url("chrome://mozapps/content/extensions/extensions.xml#download-progress"); -} - -.install-status { - -moz-binding: url("chrome://mozapps/content/extensions/extensions.xml#install-status"); -} - -.detail-row { - -moz-binding: url("chrome://mozapps/content/extensions/extensions.xml#detail-row"); -} .text-list { white-space: pre-line; } -row[unsupported="true"] { - display: none; -} - -#addonitem-popup > menuitem[disabled="true"] { - display: none; -} - -#addonitem-popup[addontype="theme"] > #menuitem_enableItem, -#addonitem-popup[addontype="theme"] > #menuitem_disableItem, -#addonitem-popup:not([addontype="theme"]) > #menuitem_enableTheme, -#addonitem-popup:not([addontype="theme"]) > #menuitem_disableTheme { - display: none; -} - -#show-disabled-unsigned-extensions .button-text { - margin-inline-start: 3px !important; - margin-inline-end: 2px !important; -} - #header-searching:not([active]) { visibility: hidden; } -#detail-view { - overflow: auto; -} - -.addon:not([notification="warning"]) .warning, -.addon:not([notification="error"]) .error, -.addon:not([notification="info"]) .info, -.addon:not([pending]) .pending, -.addon:not([upgrade="true"]) .update-postfix, -.addon[active="true"] .disabled-postfix, -.addon[pending="install"] .update-postfix, -.addon[pending="install"] .disabled-postfix, -.addon[legacy="false"] .legacy-warning, -#detail-view:not([notification="warning"]) .warning, -#detail-view:not([notification="error"]) .error, -#detail-view:not([notification="info"]) .info, -#detail-view:not([pending]) .pending, -#detail-view:not([upgrade="true"]) .update-postfix, -#detail-view[active="true"] .disabled-postfix, -#detail-view[legacy="false"] .legacy-warning, -#detail-view[loading] .detail-view-container, -#detail-view:not([loading]) .alert-container, -.detail-row:not([value]), -#legacy-list .addon .disabled-postfix { - display: none; -} - -.addon .privateBrowsing-notice { - display: none; -} -.addon[privateBrowsing="true"] .privateBrowsing-notice-container { - /* 40px is width and margin of .icon-container */ - margin-inline-start: 40px; -} -.addon[privateBrowsing="true"] .privateBrowsing-notice { - margin: 4px 0 0; - display: inline-block; -} -.addon[active="false"] .privateBrowsing-notice { - background-color: var(--purple-70-a40); -} - -#addons-page:not([warning]) #list-view > .global-warning-container { - display: none; -} -#addon-list .date-updated, -#legacy-list .date-updated { - display: none; -} - -.view-pane:not(#updates-view) .addon .relnotes-toggle, -.view-pane:not(#updates-view) .addon .include-update, -#updates-view:not([updatetype="available"]) .addon .include-update, -#updates-view[updatetype="available"] .addon .update-available-notice { - display: none; -} - #addons-page:not([warning]) .global-warning, #addons-page:not([warning="safemode"]) .global-warning-safemode, #addons-page:not([warning="checkcompatibility"]) .global-warning-checkcompatibility, #addons-page:not([warning="updatesecurity"]) .global-warning-updatesecurity { display: none; } /* Plugins aren't yet disabled by safemode (bug 342333), @@ -150,65 +40,28 @@ row[unsupported="true"] { #addons-page[warning="safemode"] .view-pane[type="plugin"] .global-warning-container, #addons-page[warning="safemode"] #detail-view[loading="true"] .global-warning { display: none; } #addons-page .view-pane:not([type="plugin"]) #plugindeprecation-notice { display: none; } -.list-view-notice { - margin-inline-start: 28px; - margin-bottom: 16px; -} - -.list-view-notice > .message-bar { - width: 664px; -} - .html-alert-container > .message-bar { margin-bottom: 8px; } .html-global-warning-button { margin-inline: 0; } -.addon .relnotes { - -moz-user-select: text; -} -#detail-name, #detail-desc, #detail-fulldesc { - -moz-user-select: text; - word-wrap: break-word; -} - -#detail-name-container { - /* Set a max-width on this so the labels inside of this will wrap instead of - growing the card horizontally with long names. */ - max-width: 580px; -} - -/* Make sure we're not animating hidden images. See bug 623739. */ -#view-port:not([selectedIndex="0"]) #discover-view .loading, -#discover-view:not([selectedIndex="0"]) .loading { - display: none; -} - /* Elements in unselected richlistitems cannot be focused */ richlistitem:not([selected]) * { -moz-user-focus: ignore; } #header-search { width: 22em; } -.discover-button[disabled="true"] { - display: none; -} - -.view-pane:not(#legacy-view) .addon-control.replacement { - display: none; -} - #pluginFlashBlockingCheckbox .checkbox-label-box { display: none; /*see bug 1508724*/ }
--- a/toolkit/mozapps/extensions/content/extensions.js +++ b/toolkit/mozapps/extensions/content/extensions.js @@ -2,17 +2,17 @@ * 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/. */ "use strict"; /* import-globals-from ../../../content/contentAreaUtils.js */ /* import-globals-from aboutaddonsCommon.js */ /* globals ProcessingInstruction */ -/* exported gBrowser, loadView */ +/* exported loadView */ const { DeferredTask } = ChromeUtils.import( "resource://gre/modules/DeferredTask.jsm" ); const { AddonManager } = ChromeUtils.import( "resource://gre/modules/AddonManager.jsm" ); const { AddonRepository } = ChromeUtils.import( @@ -21,41 +21,16 @@ const { AddonRepository } = ChromeUtils. ChromeUtils.defineModuleGetter( this, "AMTelemetry", "resource://gre/modules/AddonManager.jsm" ); ChromeUtils.defineModuleGetter( this, - "E10SUtils", - "resource://gre/modules/E10SUtils.jsm" -); -ChromeUtils.defineModuleGetter( - this, - "ExtensionParent", - "resource://gre/modules/ExtensionParent.jsm" -); -ChromeUtils.defineModuleGetter( - this, - "ExtensionPermissions", - "resource://gre/modules/ExtensionPermissions.jsm" -); -ChromeUtils.defineModuleGetter( - this, - "PluralForm", - "resource://gre/modules/PluralForm.jsm" -); -ChromeUtils.defineModuleGetter( - this, - "Preferences", - "resource://gre/modules/Preferences.jsm" -); -ChromeUtils.defineModuleGetter( - this, "ClientID", "resource://gre/modules/ClientID.jsm" ); ChromeUtils.defineModuleGetter( this, "PrivateBrowsingUtils", "resource://gre/modules/PrivateBrowsingUtils.jsm" ); @@ -64,68 +39,35 @@ XPCOMUtils.defineLazyPreferenceGetter( this, "XPINSTALL_ENABLED", "xpinstall.enabled", true ); XPCOMUtils.defineLazyPreferenceGetter( this, - "allowPrivateBrowsingByDefault", - "extensions.allowPrivateBrowsingByDefault", - true -); - -XPCOMUtils.defineLazyPreferenceGetter( - this, - "SUPPORT_URL", - "app.support.baseURL", - "", - null, - val => Services.urlFormatter.formatURL(val) -); -XPCOMUtils.defineLazyPreferenceGetter( - this, - "useHtmlViews", - "extensions.htmlaboutaddons.enabled" -); -XPCOMUtils.defineLazyPreferenceGetter( - this, "useHtmlDiscover", "extensions.htmlaboutaddons.discover.enabled" ); XPCOMUtils.defineLazyPreferenceGetter( this, "useNewAboutDebugging", "devtools.aboutdebugging.new-enabled" ); const PREF_DISCOVERURL = "extensions.webservice.discoverURL"; const PREF_DISCOVER_ENABLED = "extensions.getAddons.showPane"; const PREF_GETADDONS_CACHE_ENABLED = "extensions.getAddons.cache.enabled"; const PREF_GETADDONS_CACHE_ID_ENABLED = "extensions.%ID%.getAddons.cache.enabled"; const PREF_UI_TYPE_HIDDEN = "extensions.ui.%TYPE%.hidden"; const PREF_UI_LASTCATEGORY = "extensions.ui.lastCategory"; -const PREF_LEGACY_EXCEPTIONS = "extensions.legacy.exceptions"; -const PREF_LEGACY_ENABLED = "extensions.legacy.enabled"; - -const LOADING_MSG_DELAY = 100; - -const UPDATES_RECENT_TIMESPAN = 2 * 24 * 3600000; // 2 days (in milliseconds) var gViewDefault = "addons://discover/"; -XPCOMUtils.defineLazyGetter(this, "extensionStylesheets", () => { - const { ExtensionParent } = ChromeUtils.import( - "resource://gre/modules/ExtensionParent.jsm" - ); - return ExtensionParent.extensionStylesheets; -}); - var gStrings = {}; XPCOMUtils.defineLazyServiceGetter( gStrings, "bundleSvc", "@mozilla.org/intl/stringbundle;1", "nsIStringBundleService" ); @@ -147,31 +89,16 @@ XPCOMUtils.defineLazyGetter(gStrings, "d XPCOMUtils.defineLazyGetter(gStrings, "brandShortName", function() { return this.brand.GetStringFromName("brandShortName"); }); XPCOMUtils.defineLazyGetter(gStrings, "appVersion", function() { return Services.appinfo.version; }); -XPCOMUtils.defineLazyPreferenceGetter( - this, - "legacyWarningExceptions", - PREF_LEGACY_EXCEPTIONS, - "", - raw => raw.split(",") -); -XPCOMUtils.defineLazyPreferenceGetter( - this, - "legacyExtensionsEnabled", - PREF_LEGACY_ENABLED, - true, - () => gLegacyView.refreshVisibility() -); - document.addEventListener("load", initialize, true); window.addEventListener("unload", shutdown); var gPendingInitializations = 1; Object.defineProperty(this, "gIsInitializing", { get: () => gPendingInitializations > 0, }); @@ -183,24 +110,16 @@ function initialize(event) { } document.removeEventListener("load", initialize, true); let globalCommandSet = document.getElementById("globalCommandSet"); globalCommandSet.addEventListener("command", function(event) { gViewController.doCommand(event.target.id); }); - let viewCommandSet = document.getElementById("viewCommandSet"); - viewCommandSet.addEventListener("commandupdate", function(event) { - gViewController.updateCommands(); - }); - viewCommandSet.addEventListener("command", function(event) { - gViewController.doCommand(event.target.id); - }); - let addonPage = document.getElementById("addons-page"); addonPage.addEventListener("dragenter", function(event) { gDragDrop.onDragOver(event); }); addonPage.addEventListener("dragover", function(event) { gDragDrop.onDragOver(event); }); addonPage.addEventListener("drop", function(event) { @@ -348,31 +267,16 @@ function recordSetUpdatePolicyTelemetry( updatePolicy.push("enabled"); } recordActionTelemetry({ action: "setUpdatePolicy", value: updatePolicy.join(","), }); } -function recordSetAddonUpdateTelemetry(addon) { - let updates = addon.applyBackgroundUpdates; - let updatePolicy = ""; - if (updates == "1") { - updatePolicy = "default"; - } else if (updates == "2") { - updatePolicy = "enabled"; - } - recordActionTelemetry({ - action: "setAddonUpdate", - value: updatePolicy, - addon, - }); -} - function getCurrentViewName() { let view = gViewController.currentViewObj; let entries = Object.entries(gViewController.viewObjects); let viewIndex = entries.findIndex(([name, viewObj]) => { return viewObj == view; }); if (viewIndex != -1) { return entries[viewIndex][0]; @@ -387,43 +291,16 @@ function loadView(aViewId) { // should be the initial history entry gViewController.loadInitialView(aViewId); } else { gViewController.loadView(aViewId); } } -function isLegacyExtension(addon) { - let legacy = false; - if (addon.type == "extension" && !addon.isWebExtension) { - legacy = true; - } - if (addon.type == "theme") { - legacy = false; - } - - if ( - legacy && - (addon.hidden || addon.signedState == AddonManager.SIGNEDSTATE_PRIVILEGED) - ) { - legacy = false; - } - // Exceptions that can slip through above: the default theme plus - // test pilot addons until we get SIGNEDSTATE_PRIVILEGED deployed. - if (legacy && legacyWarningExceptions.includes(addon.id)) { - legacy = false; - } - return legacy; -} - -function isDisabledLegacy(addon) { - return !legacyExtensionsEnabled && isLegacyExtension(addon); -} - function isDiscoverEnabled() { if ( Services.prefs.getPrefType(PREF_DISCOVERURL) == Services.prefs.PREF_INVALID ) { return false; } try { @@ -629,66 +506,16 @@ var gEventManager = { } AddonManager.addManagerListener(this); AddonManager.addInstallListener(this); AddonManager.addAddonListener(this); this.refreshGlobalWarning(); this.refreshAutoUpdateDefault(); - - var contextMenu = document.getElementById("addonitem-popup"); - contextMenu.addEventListener("popupshowing", function() { - var addon = gViewController.currentViewObj.getSelectedAddon(); - contextMenu.setAttribute("addontype", addon.type); - - var menuSep = document.getElementById("addonitem-menuseparator"); - var countMenuItemsBeforeSep = 0; - for (let child of contextMenu.children) { - if (child == menuSep) { - break; - } - if ( - child.nodeName == "menuitem" && - gViewController.isCommandEnabled(child.command) - ) { - countMenuItemsBeforeSep++; - } - } - - // Hide the separator if there are no visible menu items before it - menuSep.hidden = countMenuItemsBeforeSep == 0; - }); - - let addonTooltip = document.getElementById("addonitem-tooltip"); - addonTooltip.addEventListener("popupshowing", function() { - let addonItem = addonTooltip.triggerNode; - // The way the test triggers the tooltip the richlistitem is the - // tooltipNode but in normal use it is the anonymous node. This allows - // any case - if (addonItem.localName != "richlistitem") { - addonItem = document.getBindingParent(addonItem); - } - - let tiptext = addonItem.getAttribute("name"); - - if (addonItem.mAddon) { - if (shouldShowVersionNumber(addonItem.mAddon)) { - tiptext += - " " + - (addonItem.hasAttribute("upgrade") - ? addonItem.mManualUpdate.version - : addonItem.mAddon.version); - } - } else if (shouldShowVersionNumber(addonItem.mInstall)) { - tiptext += " " + addonItem.mInstall.version; - } - - addonTooltip.label = tiptext; - }); }, shutdown() { AddonManager.removeManagerListener(this); AddonManager.removeInstallListener(this); AddonManager.removeAddonListener(this); }, @@ -830,31 +657,24 @@ var gViewController = { backButton: null, initialize() { this.viewPort = document.getElementById("view-port"); this.headeredViews = document.getElementById("headered-views"); this.headeredViewsDeck = document.getElementById("headered-views-content"); this.backButton = document.getElementById("go-back"); - this.viewObjects.legacy = gLegacyView; this.viewObjects.shortcuts = gShortcutsView; - if (useHtmlViews) { - this.viewObjects.list = htmlView("list"); - this.viewObjects.detail = htmlView("detail"); - this.viewObjects.updates = htmlView("updates"); - // gUpdatesView still handles when the Available Updates category is - // shown. Include it in viewObjects so it gets initialized and shutdown. - this.viewObjects._availableUpdatesSidebar = gUpdatesView; - } else { - this.viewObjects.list = gListView; - this.viewObjects.detail = gDetailView; - this.viewObjects.updates = gUpdatesView; - } + this.viewObjects.list = htmlView("list"); + this.viewObjects.detail = htmlView("detail"); + this.viewObjects.updates = htmlView("updates"); + // gUpdatesView still handles when the Available Updates category is + // shown. Include it in viewObjects so it gets initialized and shutdown. + this.viewObjects._availableUpdatesSidebar = gUpdatesView; if (useHtmlDiscover && isDiscoverEnabled()) { this.viewObjects.discover = htmlView("discover"); } else { this.viewObjects.discover = gDiscoverView; } for (let type in this.viewObjects) { @@ -1183,29 +1003,16 @@ var gViewController = { isEnabled() { return true; }, doCommand() { gViewController.loadView("addons://updates/available"); }, }, - cmd_showItemDetails: { - isEnabled(aAddon) { - return !!aAddon && gViewController.currentViewObj != gDetailView; - }, - doCommand(aAddon, aScrollToPreferences) { - gViewController.loadView( - "addons://detail/" + - encodeURIComponent(aAddon.id) + - (aScrollToPreferences ? "/preferences" : "") - ); - }, - }, - cmd_findAllUpdates: { inProgress: false, isEnabled() { return !this.inProgress; }, async doCommand() { this.inProgress = true; gViewController.updateCommand("cmd_findAllUpdates"); @@ -1306,192 +1113,16 @@ var gViewController = { recordActionTelemetry({ action: "checkForUpdates" }); if (pendingChecks == 0) { updateStatus(); } }, }, - cmd_findItemUpdates: { - isEnabled(aAddon) { - if (!aAddon) { - return false; - } - return hasPermission(aAddon, "upgrade"); - }, - doCommand(aAddon) { - var listener = { - onUpdateAvailable(aAddon, aInstall) { - gEventManager.delegateAddonEvent("onUpdateAvailable", [ - aAddon, - aInstall, - ]); - attachUpdateHandler(aInstall); - if (AddonManager.shouldAutoUpdate(aAddon)) { - aInstall.install(); - } - }, - onNoUpdateAvailable(aAddon) { - gEventManager.delegateAddonEvent("onNoUpdateAvailable", [aAddon]); - }, - }; - gEventManager.delegateAddonEvent("onCheckingUpdate", [aAddon]); - aAddon.findUpdates(listener, AddonManager.UPDATE_WHEN_USER_REQUESTED); - recordActionTelemetry({ action: "checkForUpdate", addon: aAddon }); - }, - }, - - cmd_showItemPreferences: { - isEnabled(aAddon) { - if (!aAddon || (!aAddon.isActive && aAddon.type !== "plugin")) { - return false; - } - if (gViewController.currentViewObj == gDetailView) { - return aAddon.optionsType && !hasInlineOptions(aAddon); - } - return aAddon.type == "plugin" || aAddon.optionsType; - }, - doCommand(aAddon) { - let inline = hasInlineOptions(aAddon); - let view = getCurrentViewName(); - - if (inline) { - gViewController.commands.cmd_showItemDetails.doCommand(aAddon, true); - } else if (aAddon.optionsType == AddonManager.OPTIONS_TYPE_TAB) { - openOptionsInTab(aAddon.optionsURL); - } - - let value = inline ? "inline" : "external"; - recordActionTelemetry({ - action: "preferences", - value, - view, - addon: aAddon, - }); - }, - }, - - cmd_enableItem: { - isEnabled(aAddon) { - if (!aAddon) { - return false; - } - let addonType = AddonManager.addonTypes[aAddon.type]; - return ( - !(addonType.flags & AddonManager.TYPE_SUPPORTS_ASK_TO_ACTIVATE) && - hasPermission(aAddon, "enable") - ); - }, - doCommand(aAddon) { - if (shouldShowPermissionsPrompt(aAddon)) { - showPermissionsPrompt(aAddon).then(() => { - // Record telemetry if the addon has been enabled. - recordActionTelemetry({ action: "enable", addon: aAddon }); - }); - } else { - aAddon.enable(); - recordActionTelemetry({ action: "enable", addon: aAddon }); - } - }, - getTooltip(aAddon) { - if (!aAddon) { - return ""; - } - return gStrings.ext.GetStringFromName("enableAddonTooltip"); - }, - }, - - cmd_disableItem: { - isEnabled(aAddon) { - if (!aAddon) { - return false; - } - let addonType = AddonManager.addonTypes[aAddon.type]; - return ( - !(addonType.flags & AddonManager.TYPE_SUPPORTS_ASK_TO_ACTIVATE) && - hasPermission(aAddon, "disable") - ); - }, - doCommand(aAddon) { - aAddon.disable(); - recordActionTelemetry({ action: "disable", addon: aAddon }); - }, - getTooltip(aAddon) { - if (!aAddon) { - return ""; - } - return gStrings.ext.GetStringFromName("disableAddonTooltip"); - }, - }, - - cmd_installItem: { - isEnabled(aAddon) { - if (!aAddon) { - return false; - } - return ( - aAddon.install && aAddon.install.state == AddonManager.STATE_AVAILABLE - ); - }, - doCommand(aAddon) { - function doInstall() { - gViewController.currentViewObj - .getListItemForID(aAddon.id) - ._installStatus.installRemote(); - } - - if (gViewController.currentViewObj == gDetailView) { - gViewController.popState(doInstall); - } else { - doInstall(); - } - }, - }, - - cmd_uninstallItem: { - isEnabled(aAddon) { - if (!aAddon) { - return false; - } - return hasPermission(aAddon, "uninstall"); - }, - async doCommand(aAddon) { - let view = getCurrentViewName(); - - // Make sure we're on the list view, which supports undo. - if (gViewController.currentViewObj != gListView) { - await new Promise(resolve => { - document.addEventListener("ViewChanged", resolve, { once: true }); - gViewController.loadView(`addons://list/${aAddon.type}`); - }); - } - recordActionTelemetry({ action: "uninstall", view, addon: aAddon }); - gViewController.currentViewObj.getListItemForID(aAddon.id).uninstall(); - }, - getTooltip(aAddon) { - if (!aAddon) { - return ""; - } - return gStrings.ext.GetStringFromName("uninstallAddonTooltip"); - }, - }, - - cmd_cancelUninstallItem: { - isEnabled(aAddon) { - if (!aAddon) { - return false; - } - return isPending(aAddon, "uninstall"); - }, - doCommand(aAddon) { - aAddon.cancelUninstall(); - }, - }, - cmd_installFromFile: { isEnabled() { return XPINSTALL_ENABLED; }, doCommand() { const nsIFilePicker = Ci.nsIFilePicker; var fp = Cc["@mozilla.org/filepicker;1"].createInstance(nsIFilePicker); fp.init( @@ -1549,109 +1180,16 @@ var gViewController = { let path = useNewAboutDebugging ? "/runtime/this-firefox" : "addons"; mainWindow.switchToTabHavingURI(`about:debugging#${path}`, true, { triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal(), }); } }, }, - cmd_cancelOperation: { - isEnabled(aAddon) { - if (!aAddon) { - return false; - } - return aAddon.pendingOperations != AddonManager.PENDING_NONE; - }, - doCommand(aAddon) { - if (isPending(aAddon, "uninstall")) { - aAddon.cancelUninstall(); - } - }, - }, - - cmd_contribute: { - isEnabled(aAddon) { - if (!aAddon) { - return false; - } - return "contributionURL" in aAddon && aAddon.contributionURL; - }, - doCommand(aAddon) { - openURL(aAddon.contributionURL); - recordActionTelemetry({ action: "contribute", addon: aAddon }); - }, - }, - - cmd_askToActivateItem: { - isEnabled(aAddon) { - if (!aAddon) { - return false; - } - let addonType = AddonManager.addonTypes[aAddon.type]; - return ( - addonType.flags & AddonManager.TYPE_SUPPORTS_ASK_TO_ACTIVATE && - hasPermission(aAddon, "ask_to_activate") - ); - }, - doCommand(aAddon) { - aAddon.userDisabled = AddonManager.STATE_ASK_TO_ACTIVATE; - }, - }, - - cmd_alwaysActivateItem: { - isEnabled(aAddon) { - if (!aAddon) { - return false; - } - let addonType = AddonManager.addonTypes[aAddon.type]; - return ( - addonType.flags & AddonManager.TYPE_SUPPORTS_ASK_TO_ACTIVATE && - hasPermission(aAddon, "enable") - ); - }, - doCommand(aAddon) { - aAddon.userDisabled = false; - }, - }, - - cmd_neverActivateItem: { - isEnabled(aAddon) { - if (!aAddon) { - return false; - } - let addonType = AddonManager.addonTypes[aAddon.type]; - return ( - addonType.flags & AddonManager.TYPE_SUPPORTS_ASK_TO_ACTIVATE && - hasPermission(aAddon, "disable") - ); - }, - doCommand(aAddon) { - aAddon.userDisabled = true; - }, - }, - - cmd_showUnsignedExtensions: { - isEnabled() { - return true; - }, - doCommand() { - gViewController.loadView("addons://list/extension?unsigned=true"); - }, - }, - - cmd_showAllExtensions: { - isEnabled() { - return true; - }, - doCommand() { - gViewController.loadView("addons://list/extension"); - }, - }, - cmd_showShortcuts: { isEnabled() { return true; }, doCommand() { gViewController.loadView("addons://shortcuts/shortcuts"); }, }, @@ -1709,281 +1247,21 @@ var gViewController = { return; } cmd.doCommand(aAddon); }, onEvent() {}, }; -async function isAddonAllowedInCurrentWindow(aAddon) { - if ( - allowPrivateBrowsingByDefault || - aAddon.type !== "extension" || - !PrivateBrowsingUtils.isContentWindowPrivate(window) - ) { - return true; - } - - const perms = await ExtensionPermissions.get(aAddon.id); - return perms.permissions.includes("internal:privateBrowsingAllowed"); -} - -function hasInlineOptions(aAddon) { - return ( - aAddon.optionsType == AddonManager.OPTIONS_TYPE_INLINE_BROWSER || - aAddon.type == "plugin" - ); -} - -function formatDate(aDate) { - const dtOptions = { year: "numeric", month: "long", day: "numeric" }; - return aDate.toLocaleDateString(undefined, dtOptions); -} - -function hasPermission(aAddon, aPerm) { - var perm = AddonManager["PERM_CAN_" + aPerm.toUpperCase()]; - return !!(aAddon.permissions & perm); -} - -function isPending(aAddon, aAction) { - var action = AddonManager["PENDING_" + aAction.toUpperCase()]; - return !!(aAddon.pendingOperations & action); -} - function isInState(aInstall, aState) { var state = AddonManager["STATE_" + aState.toUpperCase()]; return aInstall.state == state; } -function shouldShowVersionNumber(aAddon) { - if (!aAddon.version) { - return false; - } - - // The version number is hidden for lightweight themes. - if (aAddon.type == "theme") { - return !/@personas\.mozilla\.org$/.test(aAddon.id); - } - - return true; -} - -function createItem(aObj, aIsInstall) { - let item = document.createXULElement("richlistitem"); - - item.setAttribute("class", "addon addon-view card"); - item.setAttribute("name", aObj.name); - item.setAttribute("type", aObj.type); - - if (aIsInstall) { - item.mInstall = aObj; - - if (aObj.state != AddonManager.STATE_INSTALLED) { - item.setAttribute("status", "installing"); - return item; - } - aObj = aObj.addon; - } - - item.mAddon = aObj; - - item.setAttribute("status", "installed"); - - // set only attributes needed for sorting and XBL binding, - // the binding handles the rest - item.setAttribute("value", aObj.id); - - return item; -} - -function sortElements(aElements, aSortBy, aAscending) { - // aSortBy is an Array of attributes to sort by, in decending - // order of priority. - - const DATE_FIELDS = ["updateDate"]; - const NUMERIC_FIELDS = ["relevancescore"]; - - // We're going to group add-ons into the following buckets: - // - // enabledInstalled - // * Enabled - // * Incompatible but enabled because compatibility checking is off - // * Waiting to be installed - // * Waiting to be enabled - // - // pendingDisable - // * Waiting to be disabled - // - // pendingUninstall - // * Waiting to be removed - // - // disabledIncompatibleBlocked - // * Disabled - // * Incompatible - // * Blocklisted - - const UISTATE_ORDER = [ - "enabled", - "askToActivate", - "pendingDisable", - "pendingUninstall", - "disabled", - ]; - - function dateCompare(a, b) { - var aTime = a.getTime(); - var bTime = b.getTime(); - if (aTime < bTime) { - return -1; - } - if (aTime > bTime) { - return 1; - } - return 0; - } - - function numberCompare(a, b) { - return a - b; - } - - function stringCompare(a, b) { - return a.localeCompare(b); - } - - function uiStateCompare(a, b) { - // If we're in descending order, swap a and b, because - // we don't ever want to have descending uiStates - if (!aAscending) { - [a, b] = [b, a]; - } - - return UISTATE_ORDER.indexOf(a) - UISTATE_ORDER.indexOf(b); - } - - // Prioritize themes that have screenshots. - function hasPreview(aHasStr, bHasStr) { - let aHas = aHasStr == "true"; - let bHas = bHasStr == "true"; - if (aHas == bHas) { - return 0; - } - return aHas ? -1 : 1; - } - - function getValue(aObj, aKey) { - if (!aObj) { - return null; - } - - if (aObj.hasAttribute(aKey)) { - return aObj.getAttribute(aKey); - } - - var addon = aObj.mAddon || aObj.mInstall; - var addonType = aObj.mAddon && AddonManager.addonTypes[aObj.mAddon.type]; - - if (!addon) { - return null; - } - - if (aKey == "uiState") { - if (addon.pendingOperations == AddonManager.PENDING_DISABLE) { - return "pendingDisable"; - } - if (addon.pendingOperations == AddonManager.PENDING_UNINSTALL) { - return "pendingUninstall"; - } - if ( - !addon.isActive && - (addon.pendingOperations != AddonManager.PENDING_ENABLE && - addon.pendingOperations != AddonManager.PENDING_INSTALL) - ) { - return "disabled"; - } - if ( - addonType && - addonType.flags & AddonManager.TYPE_SUPPORTS_ASK_TO_ACTIVATE && - addon.userDisabled == AddonManager.STATE_ASK_TO_ACTIVATE - ) { - return "askToActivate"; - } - return "enabled"; - } - - return addon[aKey]; - } - - // aSortFuncs will hold the sorting functions that we'll - // use per element, in the correct order. - var aSortFuncs = []; - - for (let i = 0; i < aSortBy.length; i++) { - var sortBy = aSortBy[i]; - - aSortFuncs[i] = stringCompare; - - if (sortBy == "uiState") { - aSortFuncs[i] = uiStateCompare; - } else if (DATE_FIELDS.includes(sortBy)) { - aSortFuncs[i] = dateCompare; - } else if (NUMERIC_FIELDS.includes(sortBy)) { - aSortFuncs[i] = numberCompare; - } else if (sortBy == "hasPreview") { - aSortFuncs[i] = hasPreview; - } - } - - aElements.sort(function(a, b) { - if (!aAscending) { - [a, b] = [b, a]; - } - - for (let i = 0; i < aSortFuncs.length; i++) { - var sortBy = aSortBy[i]; - var aValue = getValue(a, sortBy); - var bValue = getValue(b, sortBy); - - if (!aValue && !bValue) { - return 0; - } - if (!aValue) { - return -1; - } - if (!bValue) { - return 1; - } - if (aValue != bValue) { - var result = aSortFuncs[i](aValue, bValue); - - if (result != 0) { - return result; - } - } - } - - // If we got here, then all values of a and b - // must have been equal. - return 0; - }); -} - -function sortList(aList, aSortBy, aAscending) { - var elements = Array.from(aList.childNodes); - sortElements(elements, [aSortBy], aAscending); - - while (aList.lastChild) { - aList.lastChild.remove(); - } - - for (let element of elements) { - aList.appendChild(element); - } -} - async function getAddonsAndInstalls(aType, aCallback) { let addons = null, installs = null; let types = aType != null ? [aType] : null; let aAddonsList = await AddonManager.getAddonsByTypes(types); addons = aAddonsList.filter(a => !a.hidden); if (installs != null) { @@ -1997,33 +1275,16 @@ async function getAddonsAndInstalls(aTyp ); }); if (addons != null) { aCallback(addons, installs); } } -function doPendingUninstalls(aListBox) { - // Uninstalling add-ons can mutate the list so find the add-ons first then - // uninstall them - var items = []; - var listitem = aListBox.firstChild; - while (listitem) { - if (listitem.getAttribute("pending") == "uninstall") { - items.push(listitem.mAddon); - } - listitem = listitem.nextSibling; - } - - for (let addon of items) { - addon.uninstall(); - } -} - var gCategories = { node: null, initialize() { this.node = document.getElementById("categories"); var types = AddonManager.addonTypes; for (var type in types) { @@ -2664,1513 +1925,52 @@ var gDiscoverView = { Ci.nsISupportsWeakReference, ]), getSelectedAddon() { return null; }, }; -var gLegacyView = { - node: null, - _listBox: null, +var gUpdatesView = { _categoryItem: null, isRoot: true, initialize() { - this.node = document.getElementById("legacy-view"); - this._listBox = document.getElementById("legacy-list"); - this._categoryItem = gCategories.get("addons://legacy/"); - - document.getElementById("legacy-learnmore").href = - SUPPORT_URL + "webextensions"; - - gEventManager.registerAddonListener(this, "ANY"); - - this.refreshVisibility(); - }, - - shutdown() { - gEventManager.unregisterAddonListener(this, "ANY"); - }, - - onUninstalled() { - this.refreshVisibility(); - }, - - async show(type, request) { - let addons = await AddonManager.getAddonsByTypes(["extension", "theme"]); - addons = addons.filter( - a => !a.hidden && (isDisabledLegacy(a) || isDisabledUnsigned(a)) - ); - - this._listBox.textContent = ""; - - let elements = addons.map(a => createItem(a)); - if (elements.length == 0) { - gViewController.loadView("addons://list/extension"); - return; - } - - sortElements(elements, ["uiState", "name"], true); - for (let element of elements) { - this._listBox.appendChild(element); - } - - gViewController.notifyViewChanged(); - }, - - hide() { - doPendingUninstalls(this._listBox); - }, - - getSelectedAddon() { - var item = this._listBox.selectedItem; - if (item) { - return item.mAddon; - } - return null; - }, - - async refreshVisibility() { - if (legacyExtensionsEnabled) { - this._categoryItem.disabled = true; - return; - } - - 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)) { - haveLegacy = true; - } - } - - if (haveLegacy || haveUnsigned) { - this._categoryItem.disabled = false; - let name = gStrings.ext.GetStringFromName( - `type.${haveUnsigned ? "unsupported" : "legacy"}.name` - ); - this._categoryItem.setAttribute("name", name); - this._categoryItem.tooltiptext = name; - } else { - this._categoryItem.disabled = true; - } - }, - - getListItemForID(aId) { - var listitem = this._listBox.firstChild; - while (listitem) { - if ( - listitem.getAttribute("status") == "installed" && - listitem.mAddon.id == aId - ) { - return listitem; - } - listitem = listitem.nextSibling; - } - return null; - }, -}; - -var gListView = { - node: null, - _listBox: null, - _emptyNotice: null, - _type: null, - isRoot: true, - - initialize() { - this.node = document.getElementById("list-view"); - this._listBox = document.getElementById("addon-list"); - this._emptyNotice = document.getElementById("addon-list-empty"); - - this._listBox.addEventListener("keydown", aEvent => { - if (aEvent.keyCode == aEvent.DOM_VK_RETURN) { - var item = this._listBox.selectedItem; - if (item) { - item.showInDetailView(); - } - } - }); - this._listBox.addEventListener("Uninstall", event => - recordActionTelemetry({ - action: "uninstall", - view: "list", - addon: event.target.mAddon, - }) - ); - this._listBox.addEventListener("Undo", event => - recordActionTelemetry({ action: "undo", addon: event.target.mAddon }) - ); - - document - .getElementById("signing-learn-more") - .setAttribute("href", SUPPORT_URL + "unsigned-addons"); - document - .getElementById("legacy-extensions-learnmore-link") - .addEventListener("click", evt => { - gViewController.loadView("addons://legacy/"); - }); - - try { - document - .getElementById("private-browsing-learnmore-link") - .setAttribute("href", SUPPORT_URL + "extensions-pb"); - } catch (e) { - document.getElementById("private-browsing-notice").hidden = true; - } - - let findSignedAddonsLink = document.getElementById( - "find-alternative-addons" - ); - try { - findSignedAddonsLink.setAttribute( - "href", - Services.urlFormatter.formatURLPref("extensions.getAddons.link.url") - ); - } catch (e) { - findSignedAddonsLink.classList.remove("text-link"); - } - - try { - document - .getElementById("signing-dev-manual-link") - .setAttribute( - "href", - Services.prefs.getCharPref("xpinstall.signatures.devInfoURL") - ); - } catch (e) { - document.getElementById("signing-dev-info").hidden = true; - } - - if (Preferences.get("plugin.load_flash_only", true)) { - document - .getElementById("plugindeprecation-learnmore-link") - .setAttribute("href", SUPPORT_URL + "npapi"); - } else { - document.getElementById("plugindeprecation-notice").hidden = true; - } - }, - - show(aType, aRequest) { - let showOnlyDisabledUnsigned = false; - if (aType.endsWith("?unsigned=true")) { - aType = aType.replace(/\?.*/, ""); - showOnlyDisabledUnsigned = true; - } - - if (!(aType in AddonManager.addonTypes)) { - throw Components.Exception( - "Attempting to show unknown type " + aType, - Cr.NS_ERROR_INVALID_ARG - ); - } - - this._type = aType; - this.node.setAttribute("type", aType); - this.showEmptyNotice(false); - - this._listBox.textContent = ""; - - if (aType == "plugin") { - navigator.plugins.refresh(false); - } - - getAddonsAndInstalls(aType, (aAddonsList, aInstallsList) => { - if (gViewController && aRequest != gViewController.currentViewRequest) { - return; - } - - let showLegacyInfo = false; - if (!legacyExtensionsEnabled && aType != "locale") { - let preLen = aAddonsList.length; - aAddonsList = aAddonsList.filter( - addon => !isLegacyExtension(addon) && !isDisabledUnsigned(addon) - ); - if (aAddonsList.length != preLen) { - showLegacyInfo = true; - } - } - - let privateNotice = document.getElementById("private-browsing-notice"); - privateNotice.hidden = - allowPrivateBrowsingByDefault || aType != "extension"; - - var elements = []; - - for (let addonItem of aAddonsList) { - elements.push(createItem(addonItem)); - } - - for (let installItem of aInstallsList) { - elements.push(createItem(installItem, true)); - } - - this.showEmptyNotice(elements.length == 0); - if (elements.length > 0) { - let sortBy; - if (aType == "theme") { - sortBy = ["uiState", "hasPreview", "name"]; - } else { - sortBy = ["uiState", "name"]; - } - sortElements(elements, sortBy, true); - for (let element of elements) { - this._listBox.appendChild(element); - } - } - - this.filterDisabledUnsigned(showOnlyDisabledUnsigned); - 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, - ]) + " "; - el.insertBefore(document.createTextNode(text), el.childNodes[0]); - legacyNotice.hidden = false; - } else { - legacyNotice.hidden = true; - } - - gEventManager.registerInstallListener(this); - gViewController.updateCommands(); - gViewController.notifyViewChanged(); - }); - }, - - hide() { - gEventManager.unregisterInstallListener(this); - doPendingUninstalls(this._listBox); - }, - - filterDisabledUnsigned(aFilter = true) { - let foundDisabledUnsigned = false; - - for (let item of this._listBox.childNodes) { - if (isDisabledUnsigned(item.mAddon)) { - foundDisabledUnsigned = true; - } else { - item.hidden = aFilter; - } - } - - document.getElementById("show-disabled-unsigned-extensions").hidden = - aFilter || !foundDisabledUnsigned; - - document.getElementById("show-all-extensions").hidden = !aFilter; - document.getElementById("disabled-unsigned-addons-info").hidden = !aFilter; - }, - - showEmptyNotice(aShow) { - this._emptyNotice.hidden = !aShow; - this._listBox.hidden = aShow; - }, - - onSortChanged(aSortBy, aAscending) { - sortList(this._listBox, aSortBy, aAscending); - }, - - onExternalInstall(aAddon, aExistingAddon) { - // The existing list item will take care of upgrade installs - if (aExistingAddon) { - return; - } - - if (aAddon.hidden) { - return; - } - - this.addItem(aAddon); - }, - - onDownloadStarted(aInstall) { - this.addItem(aInstall, true); - }, - - onInstallStarted(aInstall) { - this.addItem(aInstall, true); - }, - - onDownloadCancelled(aInstall) { - this.removeItem(aInstall, true); - }, - - onInstallCancelled(aInstall) { - this.removeItem(aInstall, true); - }, - - onInstallEnded(aInstall) { - // Remove any install entries for upgrades, their status will appear against - // the existing item - if (aInstall.existingAddon) { - this.removeItem(aInstall, true); - } - }, - - addItem(aObj, aIsInstall) { - if (aObj.type != this._type) { - return; - } - - if (aIsInstall && aObj.existingAddon) { - return; - } - - if (aObj.addon && aObj.addon.hidden) { - return; - } - - let prop = aIsInstall ? "mInstall" : "mAddon"; - for (let item of this._listBox.childNodes) { - if (item[prop] == aObj) { - return; - } - } - - let item = createItem(aObj, aIsInstall); - this._listBox.insertBefore(item, this._listBox.firstChild); - this.showEmptyNotice(false); - }, - - removeItem(aObj, aIsInstall) { - let prop = aIsInstall ? "mInstall" : "mAddon"; - - for (let item of this._listBox.childNodes) { - if (item[prop] == aObj) { - this._listBox.removeChild(item); - this.showEmptyNotice(this._listBox.itemCount == 0); - return; - } - } - }, - - getSelectedAddon() { - var item = this._listBox.selectedItem; - if (item) { - return item.mAddon; - } - return null; - }, - - getListItemForID(aId) { - var listitem = this._listBox.firstChild; - while (listitem) { - if ( - listitem.getAttribute("status") == "installed" && - listitem.mAddon.id == aId - ) { - return listitem; - } - listitem = listitem.nextSibling; - } - return null; - }, -}; - -var gDetailView = { - node: null, - _addon: null, - _loadingTimer: null, - _autoUpdate: null, - isRoot: false, - restartingAddon: false, - - initialize() { - this.node = document.getElementById("detail-view"); - this.node.addEventListener("click", this.recordClickTelemetry); - this.headingImage = this.node.querySelector(".card-heading-image"); - - this._autoUpdate = document.getElementById("detail-autoUpdate"); - this._autoUpdate.addEventListener( - "command", - () => { - this._addon.applyBackgroundUpdates = this._autoUpdate.value; - recordSetAddonUpdateTelemetry(this._addon); - }, - true - ); - - for (let el of document.getElementsByClassName("private-learnmore")) { - el.setAttribute("href", SUPPORT_URL + "extensions-pb"); - } - - this._privateBrowsing = document.getElementById("detail-privateBrowsing"); - this._privateBrowsing.addEventListener( - "command", - async () => { - let addon = this._addon; - let policy = WebExtensionPolicy.getByID(addon.id); - let extension = policy && policy.extension; - - let perms = { - permissions: ["internal:privateBrowsingAllowed"], - origins: [], - }; - if (this._privateBrowsing.value == "1") { - await ExtensionPermissions.add(addon.id, perms, extension); - recordActionTelemetry({ - action: "privateBrowsingAllowed", - value: "on", - addon, - }); - } else { - await ExtensionPermissions.remove(addon.id, perms, extension); - recordActionTelemetry({ - action: "privateBrowsingAllowed", - value: "off", - addon, - }); - } - - // Reload the extension if it is already enabled. This ensures any change - // on the private browsing permission is properly handled. - if (addon.isActive) { - try { - this.restartingAddon = true; - await addon.reload(); - } finally { - this.restartingAddon = false; - this.updateState(); - this._updateView(addon, false); - } - } - }, - true - ); - }, - - shutdown() { - AddonManager.removeManagerListener(this); - }, - - onUpdateModeChanged() { - this.onPropertyChanged(["applyBackgroundUpdates"]); - }, - - recordClickTelemetry(event) { - if (event.target.id == "detail-reviews") { - recordLinkTelemetry("rating"); - } else if (event.target.id == "detail-homepage") { - recordLinkTelemetry("homepage"); - } else if (event.originalTarget.getAttribute("anonid") == "creator-link") { - recordLinkTelemetry("author"); - } - }, - - async _updateView(aAddon, aIsRemote, aScrollToPreferences) { - // Skip updates to avoid flickering while restarting the addon. - if (this.restartingAddon) { - return; - } - - setSearchLabel(aAddon.type); - - // Set the preview image for themes, if available. - this.headingImage.src = ""; - if (aAddon.type == "theme") { - let previewURL = - aAddon.screenshots && - aAddon.screenshots[0] && - aAddon.screenshots[0].url; - if (previewURL) { - this.headingImage.src = previewURL; - } - } - - AddonManager.addManagerListener(this); - this.clearLoading(); - - this._addon = aAddon; - gEventManager.registerAddonListener(this, aAddon.id); - gEventManager.registerInstallListener(this); - - this.node.setAttribute("type", aAddon.type); - - let legacy = false; - if (!aAddon.install) { - legacy = isLegacyExtension(aAddon); - } - this.node.setAttribute("legacy", legacy); - document.getElementById("detail-legacy-warning").href = - SUPPORT_URL + "webextensions"; - - // Make sure to select the correct category - let category = - isDisabledLegacy(aAddon) || isDisabledUnsigned(aAddon) - ? "addons://legacy" - : `addons://list/${aAddon.type}`; - gCategories.select(category); - - document.getElementById("detail-name").textContent = aAddon.name; - var icon = AddonManager.getPreferredIconURL(aAddon, 32, window); - document.getElementById("detail-icon").src = icon ? icon : ""; - document - .getElementById("detail-creator") - .setCreator(aAddon.creator, aAddon.homepageURL); - - var version = document.getElementById("detail-version"); - if (shouldShowVersionNumber(aAddon)) { - version.hidden = false; - version.value = aAddon.version; - } else { - version.hidden = true; - } - - var desc = document.getElementById("detail-desc"); - desc.textContent = aAddon.description; - - var fullDesc = document.getElementById("detail-fulldesc"); - if (aAddon.getFullDescription) { - fullDesc.textContent = ""; - fullDesc.append(aAddon.getFullDescription(document)); - fullDesc.hidden = false; - } else if (aAddon.fullDescription) { - fullDesc.textContent = aAddon.fullDescription; - fullDesc.hidden = false; - } else { - fullDesc.hidden = true; - } - - var contributions = document.getElementById("detail-contributions"); - if ("contributionURL" in aAddon && aAddon.contributionURL) { - contributions.hidden = false; - } else { - contributions.hidden = true; - } - - var updateDateRow = document.getElementById("detail-dateUpdated"); - if (aAddon.updateDate) { - var date = formatDate(aAddon.updateDate); - updateDateRow.value = date; - } else { - updateDateRow.value = null; - } - - // TODO if the add-on was downloaded from releases.mozilla.org link to the - // AMO profile (bug 590344) - if (false) { - document.getElementById("detail-repository-row").hidden = false; - document.getElementById("detail-homepage-row").hidden = true; - var repository = document.getElementById("detail-repository"); - repository.value = aAddon.homepageURL; - repository.href = aAddon.homepageURL; - } else if (aAddon.homepageURL) { - document.getElementById("detail-repository-row").hidden = true; - document.getElementById("detail-homepage-row").hidden = false; - var homepage = document.getElementById("detail-homepage"); - homepage.value = aAddon.homepageURL; - homepage.href = aAddon.homepageURL; - } else { - document.getElementById("detail-repository-row").hidden = true; - document.getElementById("detail-homepage-row").hidden = true; - } - - var rating = document.getElementById("detail-rating"); - if (aAddon.averageRating) { - rating.averageRating = aAddon.averageRating; - rating.hidden = false; - } else { - rating.hidden = true; - } - - var reviews = document.getElementById("detail-reviews"); - if (aAddon.reviewURL) { - var text = gStrings.ext.GetStringFromName("numReviews"); - text = PluralForm.get(aAddon.reviewCount, text); - text = text.replace("#1", aAddon.reviewCount); - reviews.value = text; - reviews.hidden = false; - reviews.href = aAddon.reviewURL; - } else { - reviews.hidden = true; - } - - document.getElementById("detail-rating-row").hidden = - !aAddon.averageRating && !aAddon.reviewURL; - - var canUpdate = !aIsRemote && hasPermission(aAddon, "upgrade"); - document.getElementById("detail-updates-row").hidden = !canUpdate; - - if ("applyBackgroundUpdates" in aAddon) { - this._autoUpdate.hidden = false; - this._autoUpdate.value = aAddon.applyBackgroundUpdates; - let hideFindUpdates = AddonManager.shouldAutoUpdate(this._addon); - document.getElementById( - "detail-findUpdates-btn" - ).hidden = hideFindUpdates; - } else { - this._autoUpdate.hidden = true; - document.getElementById("detail-findUpdates-btn").hidden = false; - } - - // Only type = "extension" will ever get privateBrowsingAllowed, other types have - // no code that would be affected by the setting. The permission is read directly - // from ExtensionPermissions so we can get it whether or not the extension is - // currently active. - // Ensure that all private browsing rows are hidden by default, we'll then - // unhide what we want. - for (let el of document.getElementsByClassName("detail-privateBrowsing")) { - el.hidden = true; - } - if (!allowPrivateBrowsingByDefault && aAddon.type === "extension") { - if ( - aAddon.permissions & AddonManager.PERM_CAN_CHANGE_PRIVATEBROWSING_ACCESS - ) { - let privateBrowsingRow = document.getElementById( - "detail-privateBrowsing-row" - ); - let privateBrowsingFooterRow = document.getElementById( - "detail-privateBrowsing-row-footer" - ); - let perms = await ExtensionPermissions.get(aAddon.id); - this._privateBrowsing.hidden = false; - privateBrowsingRow.hidden = false; - privateBrowsingFooterRow.hidden = false; - this._privateBrowsing.value = perms.permissions.includes( - "internal:privateBrowsingAllowed" - ) - ? "1" - : "0"; - } else if (aAddon.incognito == "spanning") { - document.getElementById( - "detail-privateBrowsing-required" - ).hidden = false; - document.getElementById( - "detail-privateBrowsing-required-footer" - ).hidden = false; - } else if (aAddon.incognito == "not_allowed") { - document.getElementById( - "detail-privateBrowsing-disallowed" - ).hidden = false; - document.getElementById( - "detail-privateBrowsing-disallowed-footer" - ).hidden = false; - } - } - - // While updating the addon details view, also check if the preferences button should be disabled because - // we are in a private window and the addon is not allowed to access it. - let hidePreferences = - (!aIsRemote && - !gViewController.commands.cmd_showItemPreferences.isEnabled(aAddon)) || - !(await isAddonAllowedInCurrentWindow(aAddon)); - document.getElementById("detail-prefs-btn").hidden = hidePreferences; - - var gridRows = document.querySelectorAll("#detail-grid rows row"); - let first = true; - for (let gridRow of gridRows) { - if ( - first && - window.getComputedStyle(gridRow).getPropertyValue("display") != "none" - ) { - gridRow.setAttribute("first-row", true); - first = false; - } else { - gridRow.removeAttribute("first-row"); - } - } - - this.fillSettingsRows(aScrollToPreferences, () => { - this.updateState(); - gViewController.notifyViewChanged(); - }); - }, - - async show(aAddonId, aRequest) { - let index = aAddonId.indexOf("/preferences"); - let scrollToPreferences = false; - if (index >= 0) { - aAddonId = aAddonId.substring(0, index); - scrollToPreferences = true; - } - - this._loadingTimer = setTimeout(() => { - this.node.setAttribute("loading-extended", true); - }, LOADING_MSG_DELAY); - - let aAddon = await AddonManager.getAddonByID(aAddonId); - if (gViewController && aRequest != gViewController.currentViewRequest) { - return; - } - - if (aAddon) { - this._updateView(aAddon, false, scrollToPreferences); - return; - } - - // Look for an add-on pending install - let aInstalls = await AddonManager.getAllInstalls(); - for (let install of aInstalls) { - if ( - install.state == AddonManager.STATE_INSTALLED && - install.addon.id == aAddonId - ) { - this._updateView(install.addon, false); - return; - } - } - - // This might happen due to session restore restoring us back to an - // add-on that doesn't exist but otherwise shouldn't normally happen. - // Either way just revert to the default view. - gViewController.replaceView(gViewDefault); - }, - - hide() { - AddonManager.removeManagerListener(this); - this.clearLoading(); - if (this._addon) { - if (hasInlineOptions(this._addon)) { - Services.obs.notifyObservers( - document, - AddonManager.OPTIONS_NOTIFICATION_HIDDEN, - this._addon.id - ); - } - - gEventManager.unregisterAddonListener(this, this._addon.id); - gEventManager.unregisterInstallListener(this); - this._addon = null; - - // Flush the preferences to disk so they survive any crash - if (this.node.getElementsByTagName("setting").length) { - Services.prefs.savePrefFile(null); - } - } - }, - - updateState() { - // Skip updates to avoid flickering while restarting the addon. - if (this.restartingAddon) { - return; - } - - gViewController.updateCommands(); - - var pending = this._addon.pendingOperations; - if (pending & AddonManager.PENDING_UNINSTALL) { - this.node.removeAttribute("notification"); - - // We don't care about pending operations other than uninstall. - // They're transient, and cannot be undone. - this.node.setAttribute("pending", "uninstall"); - document.getElementById( - "detail-pending" - ).textContent = gStrings.ext.formatStringFromName( - "details.notification.restartless-uninstall", - [this._addon.name] - ); - } else { - this.node.removeAttribute("pending"); - - if (this._addon.blocklistState == Ci.nsIBlocklistService.STATE_BLOCKED) { - this.node.setAttribute("notification", "error"); - document.getElementById( - "detail-error" - ).textContent = gStrings.ext.formatStringFromName( - "details.notification.blocked", - [this._addon.name] - ); - var errorLink = document.getElementById("detail-error-link"); - errorLink.value = gStrings.ext.GetStringFromName( - "details.notification.blocked.link" - ); - this._addon.getBlocklistURL().then(url => { - errorLink.href = url; - errorLink.hidden = false; - }); - } else if (isDisabledUnsigned(this._addon)) { - this.node.setAttribute("notification", "error"); - document.getElementById( - "detail-error" - ).textContent = gStrings.ext.formatStringFromName( - "details.notification.unsignedAndDisabled", - [this._addon.name, gStrings.brandShortName] - ); - let errorLink = document.getElementById("detail-error-link"); - errorLink.value = gStrings.ext.GetStringFromName( - "details.notification.unsigned.link" - ); - errorLink.href = SUPPORT_URL + "unsigned-addons"; - errorLink.hidden = false; - } else if ( - !this._addon.isCompatible && - (AddonManager.checkCompatibility || - this._addon.blocklistState != - Ci.nsIBlocklistService.STATE_SOFTBLOCKED) - ) { - this.node.setAttribute("notification", "warning"); - document.getElementById( - "detail-warning" - ).textContent = gStrings.ext.formatStringFromName( - "details.notification.incompatible", - [this._addon.name, gStrings.brandShortName, gStrings.appVersion] - ); - document.getElementById("detail-warning-link").hidden = true; - } else if (!isCorrectlySigned(this._addon)) { - this.node.setAttribute("notification", "warning"); - document.getElementById( - "detail-warning" - ).textContent = gStrings.ext.formatStringFromName( - "details.notification.unsigned", - [this._addon.name, gStrings.brandShortName] - ); - var warningLink = document.getElementById("detail-warning-link"); - warningLink.value = gStrings.ext.GetStringFromName( - "details.notification.unsigned.link" - ); - warningLink.href = SUPPORT_URL + "unsigned-addons"; - warningLink.hidden = false; - } else if ( - this._addon.blocklistState == Ci.nsIBlocklistService.STATE_SOFTBLOCKED - ) { - this.node.setAttribute("notification", "warning"); - document.getElementById( - "detail-warning" - ).textContent = gStrings.ext.formatStringFromName( - "details.notification.softblocked", - [this._addon.name] - ); - let warningLink = document.getElementById("detail-warning-link"); - warningLink.value = gStrings.ext.GetStringFromName( - "details.notification.softblocked.link" - ); - this._addon.getBlocklistURL().then(url => { - warningLink.href = url; - warningLink.hidden = false; - }); - } else if ( - this._addon.blocklistState == Ci.nsIBlocklistService.STATE_OUTDATED - ) { - this.node.setAttribute("notification", "warning"); - document.getElementById( - "detail-warning" - ).textContent = gStrings.ext.formatStringFromName( - "details.notification.outdated", - [this._addon.name] - ); - let warningLink = document.getElementById("detail-warning-link"); - warningLink.value = gStrings.ext.GetStringFromName( - "details.notification.outdated.link" - ); - this._addon.getBlocklistURL().then(url => { - warningLink.href = url; - warningLink.hidden = false; - }); - } else if ( - this._addon.blocklistState == - Ci.nsIBlocklistService.STATE_VULNERABLE_UPDATE_AVAILABLE - ) { - this.node.setAttribute("notification", "error"); - document.getElementById( - "detail-error" - ).textContent = gStrings.ext.formatStringFromName( - "details.notification.vulnerableUpdatable", - [this._addon.name] - ); - let errorLink = document.getElementById("detail-error-link"); - errorLink.value = gStrings.ext.GetStringFromName( - "details.notification.vulnerableUpdatable.link" - ); - this._addon.getBlocklistURL().then(url => { - errorLink.href = url; - errorLink.hidden = false; - }); - } else if ( - this._addon.blocklistState == - Ci.nsIBlocklistService.STATE_VULNERABLE_NO_UPDATE - ) { - this.node.setAttribute("notification", "error"); - document.getElementById( - "detail-error" - ).textContent = gStrings.ext.formatStringFromName( - "details.notification.vulnerableNoUpdate", - [this._addon.name] - ); - let errorLink = document.getElementById("detail-error-link"); - errorLink.value = gStrings.ext.GetStringFromName( - "details.notification.vulnerableNoUpdate.link" - ); - this._addon.getBlocklistURL().then(url => { - errorLink.href = url; - errorLink.hidden = false; - }); - } else if ( - this._addon.isGMPlugin && - !this._addon.isInstalled && - this._addon.isActive - ) { - this.node.setAttribute("notification", "warning"); - let warning = document.getElementById("detail-warning"); - warning.textContent = gStrings.ext.formatStringFromName( - "details.notification.gmpPending", - [this._addon.name] - ); - } else { - this.node.removeAttribute("notification"); - } - } - - let menulist = document.getElementById("detail-state-menulist"); - let addonType = AddonManager.addonTypes[this._addon.type]; - if (addonType.flags & AddonManager.TYPE_SUPPORTS_ASK_TO_ACTIVATE) { - let askItem = document.getElementById("detail-ask-to-activate-menuitem"); - let alwaysItem = document.getElementById( - "detail-always-activate-menuitem" - ); - let neverItem = document.getElementById("detail-never-activate-menuitem"); - let hasActivatePermission = ["ask_to_activate", "enable", "disable"].some( - perm => hasPermission(this._addon, perm) - ); - - if (!this._addon.isActive) { - menulist.selectedItem = neverItem; - } else if ( - this._addon.userDisabled == AddonManager.STATE_ASK_TO_ACTIVATE - ) { - menulist.selectedItem = askItem; - } else { - menulist.selectedItem = alwaysItem; - } - - menulist.disabled = !hasActivatePermission; - menulist.hidden = false; - menulist.classList.add("no-auto-hide"); - } else { - menulist.hidden = true; - } - - this.node.setAttribute("active", this._addon.isActive); - }, - - clearLoading() { - if (this._loadingTimer) { - clearTimeout(this._loadingTimer); - this._loadingTimer = null; - } - - this.node.removeAttribute("loading-extended"); - }, - - emptySettingsRows() { - var lastRow = document.getElementById("detail-rating-row"); - var rows = lastRow.parentNode; - while (lastRow.nextSibling) { - rows.removeChild(rows.lastChild); - } - }, - - fillSettingsRows(aScrollToPreferences, aCallback) { - this.emptySettingsRows(); - if (!hasInlineOptions(this._addon)) { - if (aCallback) { - aCallback(); - } - return; - } - - // We can't use a promise for this, since some code (especially in tests) - // relies on us finishing before the ViewChanged event bubbles up to its - // listeners, and promises resolve asynchronously. - let whenViewLoaded = callback => { - if (gViewController.displayedView.hasAttribute("loading")) { - gDetailView.node.addEventListener( - "ViewChanged", - function() { - callback(); - }, - { once: true } - ); - } else { - callback(); - } - }; - - let finish = firstSetting => { - // Ensure the page has loaded and force the XBL bindings to be synchronously applied, - // then notify observers. - whenViewLoaded(() => { - if (firstSetting) { - firstSetting.clientTop; - } - Services.obs.notifyObservers( - document, - AddonManager.OPTIONS_NOTIFICATION_DISPLAYED, - this._addon.id - ); - if (aScrollToPreferences) { - gDetailView.scrollToPreferencesRows(); - } - }); - }; - - var rows = document.getElementById("detail-rows"); - - if (this._addon.optionsType == AddonManager.OPTIONS_TYPE_INLINE_BROWSER) { - whenViewLoaded(async () => { - const addon = this._addon; - await addon.startupPromise; - - // Do not create the inline addon options if about:addons is opened in a private window - // and the addon is not allowed to access it. - if (!(await isAddonAllowedInCurrentWindow(addon))) { - return; - } - - const browserContainer = await this.createOptionsBrowser(rows); - - if (browserContainer) { - // Make sure the browser is unloaded as soon as we change views, - // rather than waiting for the next detail view to load. - document.addEventListener( - "ViewChanged", - function() { - // Do not remove the addon options container if the view changed - // event is not related to a change to the current selected view - // or the current selected addon (e.g. it could be related to the - // disco pane view that has completed to load, See Bug 1435705 for - // a rationale). - if ( - gViewController.currentViewObj === gDetailView && - gDetailView._addon === addon - ) { - return; - } - browserContainer.remove(); - }, - { once: true } - ); - } - - finish(browserContainer); - }); - } - - if (aCallback) { - aCallback(); - } - }, - - scrollToPreferencesRows() { - // We find this row, rather than remembering it from above, - // in case it has been changed by the observers. - let firstRow = gDetailView.node.querySelector('setting[first-row="true"]'); - if (firstRow) { - let top = firstRow.getBoundingClientRect().y; - top -= parseInt( - window.getComputedStyle(firstRow).getPropertyValue("margin-top") - ); - - let detailView = gDetailView.node; - top -= detailView.getBoundingClientRect().y; - - detailView.scrollTo(0, top); - } - }, - - async createOptionsBrowser(parentNode) { - const containerId = "addon-options-prompts-stack"; - - let stack = document.getElementById(containerId); - - if (stack) { - // Remove the existent options container (if any). - stack.remove(); - } - - stack = document.createXULElement("stack"); - stack.setAttribute("id", containerId); - - let browser = document.createXULElement("browser"); - browser.setAttribute("type", "content"); - browser.setAttribute("disableglobalhistory", "true"); - browser.setAttribute("id", "addon-options"); - browser.setAttribute("class", "inline-options-browser"); - browser.setAttribute("transparent", "true"); - browser.setAttribute("forcemessagemanager", "true"); - browser.setAttribute("selectmenulist", "ContentSelectDropdown"); - browser.setAttribute("autocompletepopup", "PopupAutoComplete"); - - // The outer about:addons document listens for key presses to focus - // the search box when / is pressed. But if we're focused inside an - // options page, don't let those keypresses steal focus. - browser.addEventListener("keypress", event => { - event.stopPropagation(); - }); - - let { optionsURL, optionsBrowserStyle } = this._addon; - if (this._addon.isWebExtension) { - let policy = ExtensionParent.WebExtensionPolicy.getByID(this._addon.id); - browser.sameProcessAsFrameLoader = policy.extension.groupFrameLoader; - } - - let remoteSubframes = window.docShell.QueryInterface(Ci.nsILoadContext) - .useRemoteSubframes; - - let readyPromise; - if ( - E10SUtils.canLoadURIInRemoteType( - optionsURL, - remoteSubframes, - E10SUtils.EXTENSION_REMOTE_TYPE - ) - ) { - browser.setAttribute("remote", "true"); - browser.setAttribute("remoteType", E10SUtils.EXTENSION_REMOTE_TYPE); - readyPromise = promiseEvent("XULFrameLoaderCreated", browser); - - readyPromise.then(() => { - if (!browser.messageManager) { - // Early exit if the the extension page's XUL browser has been destroyed in the meantime - // (e.g. because the extension has been reloaded while the options page was still loading). - return; - } - const parentChromeWindow = window.docShell.parent.domWindow; - const parentContextMenuPopup = parentChromeWindow.document.getElementById( - "contentAreaContextMenu" - ); - - // Override openPopupAtScreen on the dummy menupopup element, so that we can forward - // "nsContextMenu.js openContextMenu"'s calls related to the extensions "options page" - // context menu events. - document.getElementById("contentAreaContextMenu").openPopupAtScreen = ( - ...args - ) => { - return parentContextMenuPopup.openPopupAtScreen(...args); - }; - }); - } else { - readyPromise = promiseEvent("load", browser, true); - } - - stack.appendChild(browser); - parentNode.appendChild(stack); - - // Force bindings to apply synchronously. - browser.clientTop; - - await readyPromise; - - if (!browser.messageManager) { - // If the browser.messageManager is undefined, the browser element has been - // removed from the document in the meantime (e.g. due to a rapid sequence - // of addon reload), ensure that the stack is also removed and return null. - stack.remove(); - return null; - } - - ExtensionParent.apiManager.emit("extension-browser-inserted", browser); - - return new Promise(resolve => { - let messageListener = { - receiveMessage({ name, data }) { - if (name === "Extension:BrowserResized") { - browser.style.height = `${data.height}px`; - } else if (name === "Extension:BrowserContentLoaded") { - resolve(stack); - } - }, - }; - - let mm = browser.messageManager; - - if (!mm) { - // If the browser.messageManager is undefined, the browser element has been - // removed from the document in the meantime (e.g. due to a rapid sequence - // of addon reload), ensure that the stack is also removed and return null. - stack.remove(); - resolve(null); - return; - } - - mm.loadFrameScript( - "chrome://extensions/content/ext-browser-content.js", - false, - true - ); - mm.loadFrameScript("chrome://browser/content/content.js", false, true); - mm.addMessageListener("Extension:BrowserContentLoaded", messageListener); - mm.addMessageListener("Extension:BrowserResized", messageListener); - - let browserOptions = { - fixedWidth: true, - isInline: true, - }; - - if (optionsBrowserStyle) { - browserOptions.stylesheets = extensionStylesheets; - } - - mm.sendAsyncMessage("Extension:InitBrowser", browserOptions); - - browser.loadURI(optionsURL, { - triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal(), - }); - }); - }, - - getSelectedAddon() { - return this._addon; - }, - - onEnabling() { - this.updateState(); - }, - - onEnabled() { - this.updateState(); - this.fillSettingsRows(); - }, - - onDisabling() { - this.updateState(); - if (hasInlineOptions(this._addon)) { - Services.obs.notifyObservers( - document, - AddonManager.OPTIONS_NOTIFICATION_HIDDEN, - this._addon.id - ); - } - }, - - onDisabled() { - this.updateState(); - this.emptySettingsRows(); - }, - - onUninstalling() { - this.updateState(); - }, - - onUninstalled() { - gViewController.popState(); - }, - - onOperationCancelled() { - this.updateState(); - }, - - onPropertyChanged(aProperties) { - if (aProperties.includes("applyBackgroundUpdates")) { - this._autoUpdate.value = this._addon.applyBackgroundUpdates; - let hideFindUpdates = AddonManager.shouldAutoUpdate(this._addon); - document.getElementById( - "detail-findUpdates-btn" - ).hidden = hideFindUpdates; - } - - if ( - aProperties.includes("appDisabled") || - aProperties.includes("signedState") || - aProperties.includes("userDisabled") - ) { - this.updateState(); - } - }, - - onExternalInstall(aAddon, aExistingAddon) { - // Only care about upgrades for the currently displayed add-on - if (!aExistingAddon || aExistingAddon.id != this._addon.id) { - return; - } - - this._updateView(aAddon, false); - }, - - onInstallCancelled(aInstall) { - if (aInstall.addon.id == this._addon.id) { - gViewController.popState(); - } - }, -}; - -var gUpdatesView = { - node: null, - _listBox: null, - _emptyNotice: null, - _updateSelected: null, - _categoryItem: null, - isRoot: true, - - initialize() { - this.node = document.getElementById("updates-view"); - this._listBox = document.getElementById("updates-list"); - this._emptyNotice = document.getElementById("updates-list-empty"); - this._categoryItem = gCategories.get("addons://updates/available"); - - this._updateSelected = document.getElementById("update-selected-btn"); - this._updateSelected.addEventListener("command", function() { - gUpdatesView.installSelected(); - }); - this.node.addEventListener("RelNotesShow", event => { - recordActionTelemetry({ - action: "releaseNotes", - addon: event.target.mAddon, - }); - }); - this.updateAvailableCount(true); AddonManager.addAddonListener(this); AddonManager.addInstallListener(this); }, shutdown() { AddonManager.removeAddonListener(this); AddonManager.removeInstallListener(this); }, show(aType, aRequest) { - document.getElementById("empty-availableUpdates-msg").hidden = - aType != "available"; - document.getElementById("empty-recentUpdates-msg").hidden = - aType != "recent"; - this.showEmptyNotice(false); - - this._listBox.textContent = ""; - - this.node.setAttribute("updatetype", aType); - if (aType == "recent") { - this._showRecentUpdates(aRequest); - } else { - this._showAvailableUpdates(false, aRequest); - } - }, - - hide() { - this._updateSelected.hidden = true; - this._categoryItem.hidden = this._categoryItem.badgeCount == 0; - doPendingUninstalls(this._listBox); - }, - - async _showRecentUpdates(aRequest) { - let aAddonsList = await AddonManager.getAllAddons(); - if (gViewController && aRequest != gViewController.currentViewRequest) { - return; - } - - var elements = []; - let threshold = Date.now() - UPDATES_RECENT_TIMESPAN; - for (let addon of aAddonsList) { - if ( - addon.hidden || - !addon.updateDate || - addon.updateDate.getTime() < threshold - ) { - continue; - } - - elements.push(createItem(addon)); - } - - this.showEmptyNotice(elements.length == 0); - if (elements.length > 0) { - sortElements(elements, ["updateDate"], false); - for (let element of elements) { - this._listBox.appendChild(element); - } - } - - gViewController.notifyViewChanged(); + throw new Error( + "should not get here (available updates view is in aboutaddons.js" + ); }, - async _showAvailableUpdates(aIsRefresh, aRequest) { - /* Disable the Update Selected button so it can't get clicked - before everything is initialized asynchronously. - It will get re-enabled by maybeDisableUpdateSelected(). */ - this._updateSelected.disabled = true; - - let aInstallsList = await AddonManager.getAllInstalls(); - if ( - !aIsRefresh && - gViewController && - aRequest && - aRequest != gViewController.currentViewRequest - ) { - return; - } - - if (aIsRefresh) { - this.showEmptyNotice(false); - this._updateSelected.hidden = true; - - while (this._listBox.childNodes.length > 0) { - this._listBox.firstChild.remove(); - } - } - - var elements = []; - - for (let install of aInstallsList) { - if (!this.isManualUpdate(install)) { - continue; - } - - let item = createItem(install.existingAddon); - item.setAttribute("upgrade", true); - item.addEventListener("IncludeUpdateChanged", () => { - this.maybeDisableUpdateSelected(); - }); - elements.push(item); - } - - this.showEmptyNotice(elements.length == 0); - if (elements.length > 0) { - this._updateSelected.hidden = false; - sortElements(elements, ["updateDate"], false); - for (let element of elements) { - this._listBox.appendChild(element); - } - } - - // ensure badge count is in sync - this._categoryItem.badgeCount = this._listBox.itemCount; - - gViewController.notifyViewChanged(); - }, - - showEmptyNotice(aShow) { - this._emptyNotice.hidden = !aShow; - this._listBox.hidden = aShow; - }, + hide() {}, isManualUpdate(aInstall, aOnlyAvailable) { var isManual = aInstall.existingAddon && !AddonManager.shouldAutoUpdate(aInstall.existingAddon); if (isManual && aOnlyAvailable) { return isInState(aInstall, "available"); } return isManual; }, maybeRefresh() { - if (gViewController.currentViewId == "addons://updates/available") { - this._showAvailableUpdates(true); - } this.updateAvailableCount(); }, async updateAvailableCount(aInitializing) { if (aInitializing) { gPendingInitializations++; } let aInstallsList = await AddonManager.getAllInstalls(); @@ -4181,59 +1981,16 @@ var gUpdatesView = { gViewController.currentViewId != "addons://updates/available" && count == 0; this._categoryItem.badgeCount = count; if (aInitializing) { notifyInitialized(); } }, - maybeDisableUpdateSelected() { - for (let item of this._listBox.childNodes) { - if (item.includeUpdate) { - this._updateSelected.disabled = false; - return; - } - } - this._updateSelected.disabled = true; - }, - - installSelected() { - for (let item of this._listBox.childNodes) { - if (item.includeUpdate) { - item.upgrade(); - } - } - - this._updateSelected.disabled = true; - }, - - getSelectedAddon() { - var item = this._listBox.selectedItem; - if (item) { - return item.mAddon; - } - return null; - }, - - getListItemForID(aId) { - var listitem = this._listBox.firstChild; - while (listitem) { - if (listitem.mAddon.id == aId) { - return listitem; - } - listitem = listitem.nextSibling; - } - return null; - }, - - onSortChanged(aSortBy, aAscending) { - sortList(this._listBox, aSortBy, aAscending); - }, - onNewInstall(aInstall) { if (!this.isManualUpdate(aInstall)) { return; } this.maybeRefresh(); }, onInstallStarted(aInstall) {
--- a/toolkit/mozapps/extensions/content/extensions.xml +++ b/toolkit/mozapps/extensions/content/extensions.xml @@ -13,202 +13,16 @@ <bindings id="addonBindings" xmlns="http://www.mozilla.org/xbl" xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" xmlns:xbl="http://www.mozilla.org/xbl" xmlns:html="http://www.w3.org/1999/xhtml"> - <!-- Rating - displays current/average rating, allows setting user rating --> - <binding id="rating"> - <content> - <xul:image class="star" - onmouseover="document.getBindingParent(this)._hover(1);" - onclick="document.getBindingParent(this).userRating = 1;"/> - <xul:image class="star" - onmouseover="document.getBindingParent(this)._hover(2);" - onclick="document.getBindingParent(this).userRating = 2;"/> - <xul:image class="star" - onmouseover="document.getBindingParent(this)._hover(3);" - onclick="document.getBindingParent(this).userRating = 3;"/> - <xul:image class="star" - onmouseover="document.getBindingParent(this)._hover(4);" - onclick="document.getBindingParent(this).userRating = 4;"/> - <xul:image class="star" - onmouseover="document.getBindingParent(this)._hover(5);" - onclick="document.getBindingParent(this).userRating = 5;"/> - </content> - - <implementation> - <constructor><![CDATA[ - this._updateStars(); - ]]></constructor> - - <property name="stars" readonly="true"> - <getter><![CDATA[ - return document.getAnonymousNodes(this); - ]]></getter> - </property> - - <property name="averageRating"> - <getter><![CDATA[ - if (this.hasAttribute("averagerating")) - return this.getAttribute("averagerating"); - return -1; - ]]></getter> - <setter><![CDATA[ - this.setAttribute("averagerating", val); - if (this.showRating == "average") - this._updateStars(); - ]]></setter> - </property> - - <property name="userRating"> - <getter><![CDATA[ - if (this.hasAttribute("userrating")) - return this.getAttribute("userrating"); - return -1; - ]]></getter> - <setter><![CDATA[ - if (this.showRating != "user") - return; - this.setAttribute("userrating", val); - if (this.showRating == "user") - this._updateStars(); - ]]></setter> - </property> - - <property name="showRating"> - <getter><![CDATA[ - if (this.hasAttribute("showrating")) - return this.getAttribute("showrating"); - return "average"; - ]]></getter> - <setter><![CDATA[ - if (val != "average" || val != "user") - throw Components.Exception("Invalid value", Cr.NS_ERROR_ILLEGAL_VALUE); - this.setAttribute("showrating", val); - this._updateStars(); - ]]></setter> - </property> - - <method name="_updateStars"> - <body><![CDATA[ - var stars = this.stars; - var rating = this[this.showRating + "Rating"]; - // average ratings can be non-whole numbers, round them so they - // match to their closest star - rating = Math.round(rating); - for (let i = 0; i < stars.length; i++) - stars[i].setAttribute("on", rating > i); - ]]></body> - </method> - - <method name="_hover"> - <parameter name="aScore"/> - <body><![CDATA[ - if (this.showRating != "user") - return; - var stars = this.stars; - for (let i = 0; i < stars.length; i++) - stars[i].setAttribute("on", i <= (aScore - 1)); - ]]></body> - </method> - - </implementation> - - <handlers> - <handler event="mouseout"> - this._updateStars(); - </handler> - </handlers> - </binding> - - <!-- Download progress - shows graphical progress of download and any - related status message. --> - <binding id="download-progress"> - <content> - <xul:stack flex="1"> - <xul:hbox flex="1"> - <xul:hbox class="start-cap"/> - <html:progress anonid="progress" class="progress" max="100"/> - <xul:hbox class="end-cap"/> - </xul:hbox> - <xul:hbox class="status-container"> - <xul:spacer flex="1"/> - <xul:label anonid="status" class="status"/> - <xul:spacer flex="1"/> - <xul:button anonid="cancel-btn" class="cancel" - tooltiptext="&progress.cancel.tooltip;" - oncommand="document.getBindingParent(this).cancel();"/> - </xul:hbox> - </xul:stack> - </content> - - <implementation> - <constructor><![CDATA[ - var progress = 0; - if (this.hasAttribute("progress")) - progress = parseInt(this.getAttribute("progress")); - this.progress = progress; - ]]></constructor> - - <field name="_progress"> - document.getAnonymousElementByAttribute(this, "anonid", "progress"); - </field> - <field name="_cancel"> - document.getAnonymousElementByAttribute(this, "anonid", "cancel-btn"); - </field> - <field name="_status"> - document.getAnonymousElementByAttribute(this, "anonid", "status"); - </field> - - <property name="progress"> - <setter><![CDATA[ - // This property is always updated after maxProgress. - if (this.getAttribute("mode") == "determined") { - this._progress.value = val; - } - if (val == this._progress.max) - this.setAttribute("complete", true); - else - this.removeAttribute("complete"); - ]]></setter> - </property> - - <property name="maxProgress"> - <setter><![CDATA[ - if (val == -1) { - this.setAttribute("mode", "undetermined"); - this._progress.removeAttribute("value"); - } else { - this.setAttribute("mode", "determined"); - this._progress.setAttribute("max", val); - } - ]]></setter> - </property> - - <property name="status"> - <getter><![CDATA[ - return this._status.value; - ]]></getter> - <setter><![CDATA[ - this._status.value = val; - ]]></setter> - </property> - - <method name="cancel"> - <body><![CDATA[ - this.mInstall.cancel(); - ]]></body> - </method> - </implementation> - </binding> - <!-- Category item - an item in the category list. --> <binding id="category" extends="chrome://global/content/bindings/richlistbox.xml#richlistitem"> <content align="center"> <xul:image anonid="icon" class="category-icon"/> <xul:label anonid="name" class="category-name" crop="end" flex="1" xbl:inherits="value=name"/> <xul:label anonid="badge" class="category-badge" xbl:inherits="value=count"/> </content> @@ -230,1496 +44,9 @@ this.setAttribute("count", val); var event = document.createEvent("Events"); event.initEvent("CategoryBadgeUpdated", true, true); this.dispatchEvent(event); ]]></setter> </property> </implementation> </binding> - - - <!-- Creator link - Name of a user/developer, providing a link if relevant. --> - <binding id="creator-link"> - <content> - <xul:label anonid="label" value="&addon.createdBy.label;"/> - <xul:label anonid="creator-link" class="creator-link" is="text-link"/> - <xul:label anonid="creator-name" class="creator-name"/> - </content> - - <implementation> - <constructor><![CDATA[ - if (this.hasAttribute("nameonly") && - this.getAttribute("nameonly") == "true") { - this._label.hidden = true; - } - ]]></constructor> - - <field name="_label"> - document.getAnonymousElementByAttribute(this, "anonid", "label"); - </field> - <field name="_creatorLink"> - document.getAnonymousElementByAttribute(this, "anonid", "creator-link"); - </field> - <field name="_creatorName"> - document.getAnonymousElementByAttribute(this, "anonid", "creator-name"); - </field> - - <method name="setCreator"> - <parameter name="aCreator"/> - <parameter name="aHomepageURL"/> - <body><![CDATA[ - if (!aCreator) { - this.collapsed = true; - return; - } - this.collapsed = false; - var url = aCreator.url || aHomepageURL; - var showLink = !!url; - if (showLink) { - this._creatorLink.value = aCreator.name; - this._creatorLink.href = url; - } else { - this._creatorName.value = aCreator.name; - } - this._creatorLink.hidden = !showLink; - this._creatorName.hidden = showLink; - ]]></body> - </method> - </implementation> - </binding> - - - <!-- Install status - Displays the status of an install/upgrade. --> - <binding id="install-status"> - <content> - <xul:label anonid="message"/> - <xul:box anonid="progress" class="download-progress"/> - <xul:button anonid="install-remote-btn" hidden="true" - class="addon-control install" label="&addon.install.label;" - tooltiptext="&addon.install.tooltip;" - oncommand="document.getBindingParent(this).installRemote();"/> - </content> - - <implementation> - <constructor><![CDATA[ - if (this.mInstall) - this.initWithInstall(this.mInstall); - else if (this.mControl.mAddon.install) - this.initWithInstall(this.mControl.mAddon.install); - else - this.refreshState(); - ]]></constructor> - - <destructor><![CDATA[ - if (this.mInstall) - this.mInstall.removeListener(this); - ]]></destructor> - - <field name="_message"> - document.getAnonymousElementByAttribute(this, "anonid", "message"); - </field> - <field name="_progress"> - document.getAnonymousElementByAttribute(this, "anonid", "progress"); - </field> - <field name="_installRemote"> - document.getAnonymousElementByAttribute(this, "anonid", - "install-remote-btn"); - </field> - <field name="_undo"> - document.getAnonymousElementByAttribute(this, "anonid", - "undo-btn"); - </field> - - <method name="initWithInstall"> - <parameter name="aInstall"/> - <body><![CDATA[ - if (this.mInstall) { - this.mInstall.removeListener(this); - this.mInstall = null; - } - this.mInstall = aInstall; - this._progress.mInstall = aInstall; - this.refreshState(); - this.mInstall.addListener(this); - ]]></body> - </method> - - <method name="refreshState"> - <body><![CDATA[ - var showInstallRemote = false; - - if (this.mInstall) { - switch (this.mInstall.state) { - case AddonManager.STATE_AVAILABLE: - if (this.mControl.getAttribute("remote") != "true") - break; - - this._progress.hidden = true; - showInstallRemote = true; - break; - case AddonManager.STATE_DOWNLOADING: - this.showMessage("installDownloading"); - break; - case AddonManager.STATE_CHECKING: - this.showMessage("installVerifying"); - break; - case AddonManager.STATE_DOWNLOADED: - this.showMessage("installDownloaded"); - break; - case AddonManager.STATE_DOWNLOAD_FAILED: - // XXXunf expose what error occured (bug 553487) - this.showMessage("installDownloadFailed", true); - break; - case AddonManager.STATE_INSTALLING: - this.showMessage("installInstalling"); - break; - case AddonManager.STATE_INSTALL_FAILED: - // XXXunf expose what error occured (bug 553487) - this.showMessage("installFailed", true); - break; - case AddonManager.STATE_CANCELLED: - this.showMessage("installCancelled", true); - break; - } - } - - this._installRemote.hidden = !showInstallRemote; - - if ("refreshInfo" in this.mControl) - this.mControl.refreshInfo(); - ]]></body> - </method> - - <method name="showMessage"> - <parameter name="aMsgId"/> - <parameter name="aHideProgress"/> - <body><![CDATA[ - this._message.setAttribute("hidden", !aHideProgress); - this._progress.setAttribute("hidden", !!aHideProgress); - - var msg = gStrings.ext.GetStringFromName(aMsgId); - if (aHideProgress) - this._message.value = msg; - else - this._progress.status = msg; - ]]></body> - </method> - - <method name="installRemote"> - <body><![CDATA[ - if (this.mControl.getAttribute("remote") != "true") - return; - - delete this.mControl.mAddon; - this.mControl.mInstall = this.mInstall; - this.mControl.setAttribute("status", "installing"); - let prompt = Services.prefs.getBoolPref("extensions.webextPermissionPrompts", false); - if (prompt) { - this.mInstall.promptHandler = info => new Promise((resolve, reject) => { - // Skip prompts for non-webextensions - if (!info.addon.userPermissions) { - resolve(); - return; - } - let subject = { - wrappedJSObject: { - target: window.docShell.chromeEventHandler, - info: { - addon: info.addon, - source: "AMO", - icon: info.addon.iconURL, - permissions: info.addon.userPermissions, - resolve, - reject, - }, - }, - }; - Services.obs.notifyObservers(subject, "webextension-permission-prompt"); - }); - } - this.mInstall.install(); - ]]></body> - </method> - - <method name="onDownloadStarted"> - <body><![CDATA[ - this.refreshState(); - ]]></body> - </method> - - <method name="onDownloadEnded"> - <body><![CDATA[ - this.refreshState(); - ]]></body> - </method> - - <method name="onDownloadFailed"> - <body><![CDATA[ - this.refreshState(); - ]]></body> - </method> - - <method name="onDownloadProgress"> - <body><![CDATA[ - this._progress.maxProgress = this.mInstall.maxProgress; - this._progress.progress = this.mInstall.progress; - ]]></body> - </method> - - <method name="onInstallStarted"> - <body><![CDATA[ - this._progress.progress = 0; - this.refreshState(); - ]]></body> - </method> - - <method name="onInstallEnded"> - <body><![CDATA[ - this.refreshState(); - if ("onInstallCompleted" in this.mControl) - this.mControl.onInstallCompleted(); - ]]></body> - </method> - - <method name="onInstallFailed"> - <body><![CDATA[ - this.refreshState(); - ]]></body> - </method> - </implementation> - </binding> - - - <!-- Addon - base - parent binding of any item representing an addon. --> - <binding id="addon-base" - extends="chrome://global/content/bindings/richlistbox.xml#richlistitem"> - <implementation> - <property name="isLegacy" readonly="true"> - <getter><![CDATA[ - if (this.mAddon.install) { - return false; - } - return isLegacyExtension(this.mAddon); - ]]></getter> - </property> - - <method name="hasPermission"> - <parameter name="aPerm"/> - <body><![CDATA[ - var perm = AddonManager["PERM_CAN_" + aPerm.toUpperCase()]; - return !!(this.mAddon.permissions & perm); - ]]></body> - </method> - - <method name="isPending"> - <parameter name="aAction"/> - <body><![CDATA[ - var action = AddonManager["PENDING_" + aAction.toUpperCase()]; - return !!(this.mAddon.pendingOperations & action); - ]]></body> - </method> - - <method name="typeHasFlag"> - <parameter name="aFlag"/> - <body><![CDATA[ - let flag = AddonManager["TYPE_" + aFlag]; - let type = AddonManager.addonTypes[this.mAddon.type]; - - return !!(type.flags & flag); - ]]></body> - </method> - - <method name="onUninstalled"> - <body><![CDATA[ - this.remove(); - ]]></body> - </method> - </implementation> - </binding> - - - <!-- Addon - generic - A normal addon item, or an update to one --> - <binding id="addon-generic" - extends="chrome://mozapps/content/extensions/extensions.xml#addon-base"> - <content tooltiptext="&addon.details.tooltip;"> - <xul:hbox anonid="warning-container" - class="warning"> - <xul:image class="warning-icon"/> - <xul:label anonid="warning" flex="1"/> - <xul:label anonid="warning-link" is="text-link"/> - <xul:button anonid="warning-btn" class="button-link" hidden="true"/> - <xul:spacer flex="5000"/> <!-- Necessary to allow the message to wrap --> - </xul:hbox> - <xul:hbox anonid="error-container" - class="error"> - <xul:image class="error-icon"/> - <xul:label anonid="error" flex="1"/> - <xul:label anonid="error-link" hidden="true" is="text-link"/> - <xul:spacer flex="5000"/> <!-- Necessary to allow the message to wrap --> - </xul:hbox> - <xul:hbox anonid="pending-container" - class="pending"> - <xul:image class="pending-icon"/> - <xul:label anonid="pending" flex="1"/> - <xul:button anonid="undo-btn" class="button-link" - label="&addon.undoAction.label;" - tooltipText="&addon.undoAction.tooltip;" - oncommand="document.getBindingParent(this).undo();"/> - <xul:spacer flex="5000"/> <!-- Necessary to allow the message to wrap --> - </xul:hbox> - - <xul:image class="card-heading-image" anonid="theme-screenshot" xbl:inherits="src=previewURL"/> - - <xul:hbox class="content-container"> - <xul:vbox class="icon-container"> - <xul:image anonid="icon" class="icon"/> - </xul:vbox> - <xul:vbox class="content-inner-container" flex="1"> - <xul:hbox class="basicinfo-container"> - <xul:hbox class="name-container"> - <xul:label anonid="name" class="name" crop="end" flex="1" - tooltip="addonitem-tooltip" xbl:inherits="xbl:text=name"/> - <xul:label anonid="legacy" class="legacy-warning" value="&addon.legacy.label;" is="text-link"/> - <xul:label class="disabled-postfix" value="&addon.disabled.postfix;"/> - <xul:label class="update-postfix" value="&addon.update.postfix;"/> - <xul:spacer flex="5000"/> <!-- Necessary to make the name crop --> - </xul:hbox> - <xul:label anonid="date-updated" class="date-updated" - unknown="&addon.unknownDate;"/> - </xul:hbox> - - <xul:hbox class="advancedinfo-container" flex="1"> - <xul:vbox class="description-outer-container" flex="1"> - <xul:hbox class="description-container"> - <xul:label anonid="description" class="description" crop="end" flex="1"/> - <xul:spacer flex="5000"/> <!-- Necessary to make the description crop --> - </xul:hbox> - <xul:hbox class="relnotes-toggle-container"> - <xul:button anonid="relnotes-toggle-btn" class="relnotes-toggle" - hidden="true" label="&cmd.showReleaseNotes.label;" - tooltiptext="&cmd.showReleaseNotes.tooltip;" - showlabel="&cmd.showReleaseNotes.label;" - showtooltip="&cmd.showReleaseNotes.tooltip;" - hidelabel="&cmd.hideReleaseNotes.label;" - hidetooltip="&cmd.hideReleaseNotes.tooltip;" - oncommand="document.getBindingParent(this).toggleReleaseNotes();"/> - </xul:hbox> - <xul:vbox anonid="relnotes-container" class="relnotes-container"> - <xul:label class="relnotes-header" value="&addon.releaseNotes.label;"/> - <xul:label anonid="relnotes-loading" value="&addon.loadingReleaseNotes.label;"/> - <xul:label anonid="relnotes-error" hidden="true" - value="&addon.errorLoadingReleaseNotes.label;"/> - <xul:vbox anonid="relnotes" class="relnotes"/> - </xul:vbox> - </xul:vbox> - </xul:hbox> - </xul:vbox> - <xul:vbox class="status-control-wrapper"> - <xul:hbox class="status-container"> - <xul:hbox anonid="checking-update" hidden="true"> - <xul:image class="spinner"/> - <xul:label value="&addon.checkingForUpdates.label;"/> - </xul:hbox> - <xul:vbox anonid="update-available" class="update-available" - hidden="true"> - <xul:checkbox anonid="include-update" class="include-update" - label="&addon.includeUpdate.label;" checked="true" - oncommand="document.getBindingParent(this).onIncludeUpdateChanged();"/> - <xul:hbox class="update-info-container"> - <xul:label class="update-available-notice" - value="&addon.updateAvailable.label;"/> - <xul:button anonid="update-btn" class="addon-control update" - label="&addon.updateNow.label;" - tooltiptext="&addon.updateNow.tooltip;" - oncommand="document.getBindingParent(this).upgrade();"/> - </xul:hbox> - </xul:vbox> - <xul:hbox anonid="install-status" class="install-status" - hidden="true"/> - </xul:hbox> - <xul:hbox anonid="control-container" class="control-container" flex="1"> - <xul:button anonid="preferences-btn" - class="addon-control preferences" -#ifdef XP_WIN - label="&cmd.showPreferencesWin.label;" - tooltiptext="&cmd.showPreferencesWin.tooltip;" -#else - label="&cmd.showPreferencesUnix.label;" - tooltiptext="&cmd.showPreferencesUnix.tooltip;" -#endif - oncommand="document.getBindingParent(this).showPreferences();"/> - <xul:button anonid="enable-btn" class="addon-control enable" - label="&cmd.enableAddon.label;" - oncommand="document.getBindingParent(this).userDisabled = false;"/> - <xul:button anonid="disable-btn" class="addon-control disable" - label="&cmd.disableAddon.label;" - oncommand="document.getBindingParent(this).userDisabled = true;"/> - <xul:button anonid="replacement-btn" class="addon-control replacement" - label="&cmd.findReplacement.label;" - oncommand="document.getBindingParent(this).findReplacement();"/> - <xul:button anonid="remove-btn" class="addon-control remove" - label="&cmd.uninstallAddon.label;" - oncommand="document.getBindingParent(this).uninstall();"/> - <xul:menulist anonid="state-menulist" - class="addon-control state" - flex="1" - tooltiptext="&cmd.stateMenu.tooltip;"> - <xul:menupopup> - <xul:menuitem anonid="ask-to-activate-menuitem" - class="addon-control" - label="&cmd.askToActivate.label;" - tooltiptext="&cmd.askToActivate.tooltip;" - oncommand="document.getBindingParent(this).userDisabled = AddonManager.STATE_ASK_TO_ACTIVATE;"/> - <xul:menuitem anonid="always-activate-menuitem" - class="addon-control" - label="&cmd.alwaysActivate.label;" - tooltiptext="&cmd.alwaysActivate.tooltip;" - oncommand="document.getBindingParent(this).userDisabled = false;"/> - <xul:menuitem anonid="never-activate-menuitem" - class="addon-control" - label="&cmd.neverActivate.label;" - tooltiptext="&cmd.neverActivate.tooltip;" - oncommand="document.getBindingParent(this).userDisabled = true;"/> - </xul:menupopup> - </xul:menulist> - </xul:hbox> - </xul:vbox> - </xul:hbox> - <xul:hbox class="description-container privateBrowsing-notice-container"> - <xul:label anonid="privateBrowsing" class="description privateBrowsing-notice" value="&addon.privateBrowsing.label;"/> - </xul:hbox> - </content> - - <implementation> - <constructor><![CDATA[ - window.customElements.upgrade(this._stateMenulist); - window.customElements.upgrade(this._enableBtn); - window.customElements.upgrade(this._disableBtn); - window.customElements.upgrade(this._askToActivateMenuitem); - window.customElements.upgrade(this._alwaysActivateMenuitem); - window.customElements.upgrade(this._neverActivateMenuitem); - - this._installStatus = document.getAnonymousElementByAttribute(this, "anonid", "install-status"); - this._installStatus.mControl = this; - - this.setAttribute("contextmenu", "addonitem-popup"); - - this._showStatus("none"); - - this._initWithAddon(this.mAddon); - - gEventManager.registerAddonListener(this, this.mAddon.id); - ]]></constructor> - - <destructor><![CDATA[ - gEventManager.unregisterAddonListener(this, this.mAddon.id); - ]]></destructor> - - <field name="_warningContainer"> - document.getAnonymousElementByAttribute(this, "anonid", - "warning-container"); - </field> - <field name="_warning"> - document.getAnonymousElementByAttribute(this, "anonid", - "warning"); - </field> - <field name="_warningLink"> - document.getAnonymousElementByAttribute(this, "anonid", - "warning-link"); - </field> - <field name="_warningBtn"> - document.getAnonymousElementByAttribute(this, "anonid", - "warning-btn"); - </field> - <field name="_errorContainer"> - document.getAnonymousElementByAttribute(this, "anonid", - "error-container"); - </field> - <field name="_error"> - document.getAnonymousElementByAttribute(this, "anonid", - "error"); - </field> - <field name="_errorLink"> - document.getAnonymousElementByAttribute(this, "anonid", - "error-link"); - </field> - <field name="_pendingContainer"> - document.getAnonymousElementByAttribute(this, "anonid", - "pending-container"); - </field> - <field name="_pending"> - document.getAnonymousElementByAttribute(this, "anonid", - "pending"); - </field> - <field name="_infoContainer"> - document.getAnonymousElementByAttribute(this, "anonid", - "info-container"); - </field> - <field name="_info"> - document.getAnonymousElementByAttribute(this, "anonid", - "info"); - </field> - <field name="_icon"> - document.getAnonymousElementByAttribute(this, "anonid", "icon"); - </field> - <field name="_dateUpdated"> - document.getAnonymousElementByAttribute(this, "anonid", - "date-updated"); - </field> - <field name="_description"> - document.getAnonymousElementByAttribute(this, "anonid", - "description"); - </field> - <field name="_stateMenulist"> - document.getAnonymousElementByAttribute(this, "anonid", - "state-menulist"); - </field> - <field name="_askToActivateMenuitem"> - document.getAnonymousElementByAttribute(this, "anonid", - "ask-to-activate-menuitem"); - </field> - <field name="_alwaysActivateMenuitem"> - document.getAnonymousElementByAttribute(this, "anonid", - "always-activate-menuitem"); - </field> - <field name="_neverActivateMenuitem"> - document.getAnonymousElementByAttribute(this, "anonid", - "never-activate-menuitem"); - </field> - <field name="_preferencesBtn"> - document.getAnonymousElementByAttribute(this, "anonid", - "preferences-btn"); - </field> - <field name="_enableBtn"> - document.getAnonymousElementByAttribute(this, "anonid", - "enable-btn"); - </field> - <field name="_disableBtn"> - document.getAnonymousElementByAttribute(this, "anonid", - "disable-btn"); - </field> - <field name="_removeBtn"> - document.getAnonymousElementByAttribute(this, "anonid", - "remove-btn"); - </field> - <field name="_updateBtn"> - document.getAnonymousElementByAttribute(this, "anonid", - "update-btn"); - </field> - <field name="_controlContainer"> - document.getAnonymousElementByAttribute(this, "anonid", - "control-container"); - </field> - <field name="_installStatus"> - document.getAnonymousElementByAttribute(this, "anonid", - "install-status"); - </field> - <field name="_checkingUpdate"> - document.getAnonymousElementByAttribute(this, "anonid", - "checking-update"); - </field> - <field name="_updateAvailable"> - document.getAnonymousElementByAttribute(this, "anonid", - "update-available"); - </field> - <field name="_includeUpdate"> - document.getAnonymousElementByAttribute(this, "anonid", - "include-update"); - </field> - <field name="_relNotesLoaded">false</field> - <field name="_relNotesToggle"> - document.getAnonymousElementByAttribute(this, "anonid", - "relnotes-toggle-btn"); - </field> - <field name="_relNotesLoading"> - document.getAnonymousElementByAttribute(this, "anonid", - "relnotes-loading"); - </field> - <field name="_relNotesError"> - document.getAnonymousElementByAttribute(this, "anonid", - "relnotes-error"); - </field> - <field name="_relNotesContainer"> - document.getAnonymousElementByAttribute(this, "anonid", - "relnotes-container"); - </field> - <field name="_relNotes"> - document.getAnonymousElementByAttribute(this, "anonid", - "relnotes"); - </field> - - <property name="userDisabled"> - <getter><![CDATA[ - return this.mAddon.userDisabled; - ]]></getter> - <setter><![CDATA[ - if (val === true) { - gViewController.commands.cmd_disableItem.doCommand(this.mAddon); - } else if (val === false) { - gViewController.commands.cmd_enableItem.doCommand(this.mAddon); - } else { - this.mAddon.userDisabled = val; - } - ]]></setter> - </property> - - <property name="includeUpdate"> - <getter><![CDATA[ - return this._includeUpdate.checked && !!this.mManualUpdate; - ]]></getter> - <setter><![CDATA[ - // XXXunf Eventually, we'll want to persist this for individual - // updates - see bug 594619. - this._includeUpdate.checked = !!val; - ]]></setter> - </property> - - <method name="_initWithAddon"> - <parameter name="aAddon"/> - <body><![CDATA[ - this.mAddon = aAddon; - - this._installStatus.mAddon = this.mAddon; - this._updateDates(); - this._updateState(); - - this.setAttribute("name", aAddon.name); - - var iconURL = AddonManager.getPreferredIconURL(aAddon, 24, window); - if (iconURL) - this._icon.src = iconURL; - else - this._icon.src = ""; - - if (this.mAddon.description) - this._description.value = this.mAddon.description; - else - this._description.hidden = true; - - // Set a previewURL for themes if one exists. - let previewURL = this.mAddon.type == "theme" && - this.mAddon.screenshots && - this.mAddon.screenshots[0] && - this.mAddon.screenshots[0].url; - this.setAttribute("previewURL", previewURL ? previewURL : ""); - this.setAttribute("hasPreview", previewURL ? "true" : "fase"); - - let legacyWarning = legacyExtensionsEnabled && !this.mAddon.install && - isLegacyExtension(this.mAddon); - this.setAttribute("legacy", legacyWarning); - document.getAnonymousElementByAttribute(this, "anonid", "legacy").href = SUPPORT_URL + "webextensions"; - - if (!allowPrivateBrowsingByDefault && this.mAddon.type === "extension") { - ExtensionPermissions.get(this.mAddon.id).then((perms) => { - let allowed = perms.permissions.includes("internal:privateBrowsingAllowed"); - this.setAttribute("privateBrowsing", allowed); - if (!allowed && PrivateBrowsingUtils.isContentWindowPrivate(window)) { - // Hide the preferences button if the current window is - // private and the addon is not allowed to access it. - this._preferencesBtn.hidden = true; - } - }); - } - - if (!("applyBackgroundUpdates" in this.mAddon) || - (this.mAddon.applyBackgroundUpdates == AddonManager.AUTOUPDATE_DISABLE || - (this.mAddon.applyBackgroundUpdates == AddonManager.AUTOUPDATE_DEFAULT && - !AddonManager.autoUpdateDefault))) { - AddonManager.getAllInstalls().then(aInstallsList => { - // This can return after the binding has been destroyed, - // so try to detect that and return early - if (!("onNewInstall" in this)) - return; - for (let install of aInstallsList) { - if (install.existingAddon && - install.existingAddon.id == this.mAddon.id && - install.state == AddonManager.STATE_AVAILABLE) { - this.onNewInstall(install); - this.onIncludeUpdateChanged(); - } - } - }); - } - ]]></body> - </method> - - <method name="_showStatus"> - <parameter name="aType"/> - <body><![CDATA[ - this._controlContainer.hidden = aType != "none" && - !(aType == "update-available" && !this.hasAttribute("upgrade")); - - this._installStatus.hidden = aType != "progress"; - if (aType == "progress") - this._installStatus.refreshState(); - this._checkingUpdate.hidden = aType != "checking-update"; - this._updateAvailable.hidden = aType != "update-available"; - this._relNotesToggle.hidden = !(this.mManualUpdate ? - this.mManualUpdate.releaseNotesURI : - this.mAddon.releaseNotesURI); - ]]></body> - </method> - - <method name="_updateDates"> - <body><![CDATA[ - function formatDate(aDate) { - const dtOptions = { year: "numeric", month: "long", day: "numeric" }; - return aDate.toLocaleDateString(undefined, dtOptions); - } - - if (this.mAddon.updateDate) - this._dateUpdated.value = formatDate(this.mAddon.updateDate); - else - this._dateUpdated.value = this._dateUpdated.getAttribute("unknown"); - ]]></body> - </method> - - <method name="_updateState"> - <body><![CDATA[ - if (this.parentNode.selectedItem == this) - gViewController.updateCommands(); - - var pending = this.mAddon.pendingOperations; - if (pending & AddonManager.PENDING_UNINSTALL) { - this.removeAttribute("notification"); - - // We don't care about pending operations other than uninstall. - // They're transient, and cannot be undone. - this.setAttribute("pending", "uninstall"); - this._pending.textContent = gStrings.ext.formatStringFromName( - "notification.restartless-uninstall", - [this.mAddon.name]); - } else { - this.removeAttribute("pending"); - - var isUpgrade = this.hasAttribute("upgrade"); - var install = this._installStatus.mInstall; - - if (install && install.state == AddonManager.STATE_DOWNLOAD_FAILED) { - this.setAttribute("notification", "warning"); - this._warning.textContent = gStrings.ext.formatStringFromName( - "notification.downloadError", - [this.mAddon.name] - ); - this._warningBtn.label = gStrings.ext.GetStringFromName("notification.downloadError.retry"); - this._warningBtn.tooltipText = gStrings.ext.GetStringFromName("notification.downloadError.retry.tooltip"); - this._warningBtn.setAttribute("oncommand", "document.getBindingParent(this).retryInstall();"); - this._warningBtn.hidden = false; - this._warningLink.hidden = true; - } else if (install && install.state == AddonManager.STATE_INSTALL_FAILED) { - this.setAttribute("notification", "warning"); - this._warning.textContent = gStrings.ext.formatStringFromName( - "notification.installError", - [this.mAddon.name] - ); - this._warningBtn.label = gStrings.ext.GetStringFromName("notification.installError.retry"); - this._warningBtn.tooltipText = gStrings.ext.GetStringFromName("notification.downloadError.retry.tooltip"); - this._warningBtn.setAttribute("oncommand", "document.getBindingParent(this).retryInstall();"); - this._warningBtn.hidden = false; - this._warningLink.hidden = true; - } else if (!isUpgrade && this.mAddon.blocklistState == Ci.nsIBlocklistService.STATE_BLOCKED) { - this.setAttribute("notification", "error"); - this._error.textContent = gStrings.ext.formatStringFromName( - "notification.blocked", - [this.mAddon.name] - ); - this._errorLink.value = gStrings.ext.GetStringFromName("notification.blocked.link"); - this.mAddon.getBlocklistURL().then(url => { - this._errorLink.href = url; - this._errorLink.hidden = false; - }); - } else if (!isUpgrade && isDisabledUnsigned(this.mAddon)) { - this.setAttribute("notification", "error"); - this._error.textContent = gStrings.ext.formatStringFromName( - "notification.unsignedAndDisabled", [this.mAddon.name, gStrings.brandShortName] - ); - this._errorLink.value = gStrings.ext.GetStringFromName("notification.unsigned.link"); - this._errorLink.href = SUPPORT_URL + "unsigned-addons"; - this._errorLink.hidden = false; - } else if ((!isUpgrade && !this.mAddon.isCompatible) && (AddonManager.checkCompatibility - || (this.mAddon.blocklistState != Ci.nsIBlocklistService.STATE_SOFTBLOCKED))) { - this.setAttribute("notification", "warning"); - this._warning.textContent = gStrings.ext.formatStringFromName( - "notification.incompatible", - [this.mAddon.name, gStrings.brandShortName, gStrings.appVersion] - ); - this._warningLink.hidden = true; - this._warningBtn.hidden = true; - } else if (!isUpgrade && !isCorrectlySigned(this.mAddon)) { - this.setAttribute("notification", "warning"); - this._warning.textContent = gStrings.ext.formatStringFromName( - "notification.unsigned", [this.mAddon.name, gStrings.brandShortName] - ); - this._warningLink.value = gStrings.ext.GetStringFromName("notification.unsigned.link"); - this._warningLink.href = SUPPORT_URL + "unsigned-addons"; - this._warningLink.hidden = false; - } else if (!isUpgrade && this.mAddon.blocklistState == Ci.nsIBlocklistService.STATE_SOFTBLOCKED) { - this.setAttribute("notification", "warning"); - this._warning.textContent = gStrings.ext.formatStringFromName( - "notification.softblocked", - [this.mAddon.name] - ); - this._warningLink.value = gStrings.ext.GetStringFromName("notification.softblocked.link"); - this.mAddon.getBlocklistURL().then(url => { - this._warningLink.href = url; - this._warningLink.hidden = false; - }); - this._warningBtn.hidden = true; - } else if (!isUpgrade && this.mAddon.blocklistState == Ci.nsIBlocklistService.STATE_OUTDATED) { - this.setAttribute("notification", "warning"); - this._warning.textContent = gStrings.ext.formatStringFromName( - "notification.outdated", - [this.mAddon.name] - ); - this._warningLink.value = gStrings.ext.GetStringFromName("notification.outdated.link"); - this.mAddon.getBlocklistURL().then(url => { - this._warningLink.href = url; - this._warningLink.hidden = false; - }); - this._warningBtn.hidden = true; - } else if (!isUpgrade && this.mAddon.blocklistState == Ci.nsIBlocklistService.STATE_VULNERABLE_UPDATE_AVAILABLE) { - this.setAttribute("notification", "error"); - this._error.textContent = gStrings.ext.formatStringFromName( - "notification.vulnerableUpdatable", - [this.mAddon.name] - ); - this._errorLink.value = gStrings.ext.GetStringFromName("notification.vulnerableUpdatable.link"); - this.mAddon.getBlocklistURL().then(url => { - this._errorLink.href = url; - this._errorLink.hidden = false; - }); - } else if (!isUpgrade && this.mAddon.blocklistState == Ci.nsIBlocklistService.STATE_VULNERABLE_NO_UPDATE) { - this.setAttribute("notification", "error"); - this._error.textContent = gStrings.ext.formatStringFromName( - "notification.vulnerableNoUpdate", - [this.mAddon.name] - ); - this._errorLink.value = gStrings.ext.GetStringFromName("notification.vulnerableNoUpdate.link"); - this.mAddon.getBlocklistURL().then(url => { - this._errorLink.href = url; - this._errorLink.hidden = false; - }); - } else if (this.mAddon.isGMPlugin && !this.mAddon.isInstalled && - this.mAddon.isActive) { - this.setAttribute("notification", "warning"); - this._warning.textContent = - gStrings.ext.formatStringFromName("notification.gmpPending", - [this.mAddon.name]); - } else { - this.removeAttribute("notification"); - } - } - - this._preferencesBtn.hidden = !this.mAddon.optionsType && this.mAddon.type != "plugin"; - - if (this.typeHasFlag("SUPPORTS_ASK_TO_ACTIVATE")) { - this._enableBtn.disabled = true; - this._disableBtn.disabled = true; - this._askToActivateMenuitem.disabled = !this.hasPermission("ask_to_activate"); - let alwaysActivateProp = this.mAddon.isFlashPlugin ? "hidden" : "disabled"; - this._alwaysActivateMenuitem[alwaysActivateProp] = !this.hasPermission("enable"); - this._neverActivateMenuitem.disabled = !this.hasPermission("disable"); - if (!this.mAddon.isActive) { - this._stateMenulist.selectedItem = this._neverActivateMenuitem; - } else if (this.mAddon.userDisabled == AddonManager.STATE_ASK_TO_ACTIVATE) { - this._stateMenulist.selectedItem = this._askToActivateMenuitem; - } else { - this._stateMenulist.selectedItem = this._alwaysActivateMenuitem; - } - let hasActivatePermission = - ["ask_to_activate", "enable", "disable"].some(perm => this.hasPermission(perm)); - this._stateMenulist.disabled = !hasActivatePermission; - this._stateMenulist.hidden = false; - this._askToActivateMenuitem.classList.add("no-auto-hide"); - this._alwaysActivateMenuitem.classList.add("no-auto-hide"); - this._neverActivateMenuitem.classList.add("no-auto-hide"); - this._stateMenulist.classList.add("no-auto-hide"); - } else { - this._stateMenulist.hidden = true; - - let enableTooltip = gViewController.commands.cmd_enableItem - .getTooltip(this.mAddon); - this._enableBtn.setAttribute("tooltiptext", enableTooltip); - if (this.hasPermission("enable")) { - this._enableBtn.hidden = false; - } else { - this._enableBtn.hidden = true; - } - - let disableTooltip = gViewController.commands.cmd_disableItem - .getTooltip(this.mAddon); - this._disableBtn.setAttribute("tooltiptext", disableTooltip); - if (this.hasPermission("disable")) { - this._disableBtn.hidden = false; - } else { - this._disableBtn.hidden = true; - } - } - - let uninstallTooltip = gViewController.commands.cmd_uninstallItem - .getTooltip(this.mAddon); - this._removeBtn.setAttribute("tooltiptext", uninstallTooltip); - if (this.hasPermission("uninstall")) { - this._removeBtn.hidden = false; - } else { - this._removeBtn.hidden = true; - } - - this.setAttribute("active", this.mAddon.isActive); - - var showProgress = (this.mAddon.install && - this.mAddon.install.state != AddonManager.STATE_INSTALLED); - this._showStatus(showProgress ? "progress" : "none"); - ]]></body> - </method> - - <method name="_fetchReleaseNotes"> - <parameter name="aURI"/> - <body><![CDATA[ - let sendToggleEvent = () => { - var event = document.createEvent("Events"); - event.initEvent("RelNotesToggle", true, true); - this.dispatchEvent(event); - }; - - if (!aURI || this._relNotesLoaded) { - sendToggleEvent(); - return; - } - - this._relNotesLoaded = true; - this._relNotesLoading.hidden = false; - this._relNotesError.hidden = true; - - loadReleaseNotes(aURI).then(fragment => { - this._relNotesLoading.hidden = true; - this._relNotes.appendChild(fragment); - if (this.hasAttribute("show-relnotes")) { - var container = this._relNotesContainer; - container.style.height = container.scrollHeight + "px"; - } - sendToggleEvent(); - }, () => { - this._relNotesLoading.hidden = true; - this._relNotesError.hidden = false; - this._relNotesLoaded = false; // allow loading to be re-tried - sendToggleEvent(); - }); - ]]></body> - </method> - - <method name="toggleReleaseNotes"> - <body><![CDATA[ - if (this.hasAttribute("show-relnotes")) { - this._relNotesContainer.style.height = "0px"; - this.removeAttribute("show-relnotes"); - this._relNotesToggle.setAttribute( - "label", - this._relNotesToggle.getAttribute("showlabel") - ); - this._relNotesToggle.setAttribute( - "tooltiptext", - this._relNotesToggle.getAttribute("showtooltip") - ); - let event = document.createEvent("Events"); - event.initEvent("RelNotesToggle", true, true); - this.dispatchEvent(event); - } else { - this._relNotesContainer.style.height = this._relNotesContainer.scrollHeight + - "px"; - this.setAttribute("show-relnotes", true); - this._relNotesToggle.setAttribute( - "label", - this._relNotesToggle.getAttribute("hidelabel") - ); - this._relNotesToggle.setAttribute( - "tooltiptext", - this._relNotesToggle.getAttribute("hidetooltip") - ); - var uri = this.mManualUpdate ? - this.mManualUpdate.releaseNotesURI : - this.mAddon.releaseNotesURI; - this._fetchReleaseNotes(uri); - - // Dispatch an event so extensions.js can record telemetry. - let event = document.createEvent("Events"); - event.initEvent("RelNotesShow", true, true); - this.dispatchEvent(event); - } - ]]></body> - </method> - - <method name="undo"> - <body><![CDATA[ - gViewController.commands.cmd_cancelOperation.doCommand(this.mAddon); - ]]></body> - </method> - - <method name="uninstall"> - <body><![CDATA[ - // If the type doesn't support undoing of restartless uninstalls, - // then we fake it by just disabling it it, and doing the real - // uninstall later. - if (this.typeHasFlag("SUPPORTS_UNDO_RESTARTLESS_UNINSTALL")) { - this.mAddon.uninstall(true); - } else { - this.setAttribute("wasDisabled", this.mAddon.userDisabled); - - // We must set userDisabled to true first, this will call - // _updateState which will clear any pending attribute set. - this.mAddon.disable().then(() => { - // This won't update any other add-on manager views (bug 582002) - this.setAttribute("pending", "uninstall"); - }); - } - - // Dispatch an event so extensions.js can track telemetry. - var event = document.createEvent("Events"); - event.initEvent("Uninstall", true, true); - this.dispatchEvent(event); - ]]></body> - </method> - - <method name="showPreferences"> - <body><![CDATA[ - gViewController.doCommand("cmd_showItemPreferences", this.mAddon); - ]]></body> - </method> - - <method name="upgrade"> - <body><![CDATA[ - var install = this.mManualUpdate; - delete this.mManualUpdate; - install.install(); - ]]></body> - </method> - - <method name="retryInstall"> - <body><![CDATA[ - var install = this._installStatus.mInstall; - if (!install) - return; - if (install.state != AddonManager.STATE_DOWNLOAD_FAILED && - install.state != AddonManager.STATE_INSTALL_FAILED) - return; - install.install(); - ]]></body> - </method> - - <method name="showInDetailView"> - <body><![CDATA[ - gViewController.loadView("addons://detail/" + - encodeURIComponent(this.mAddon.id)); - ]]></body> - </method> - - <method name="findReplacement"> - <body><![CDATA[ - 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); - ]]></body> - </method> - - <method name="onEnabling"> - <body><![CDATA[ - this._updateState(); - ]]></body> - </method> - - <method name="onEnabled"> - <body><![CDATA[ - this._updateState(); - ]]></body> - </method> - - <method name="onDisabling"> - <body><![CDATA[ - this._updateState(); - ]]></body> - </method> - - <method name="onDisabled"> - <body><![CDATA[ - this._updateState(); - ]]></body> - </method> - - <method name="onUninstalling"> - <body><![CDATA[ - this._updateState(); - ]]></body> - </method> - - <method name="onOperationCancelled"> - <body><![CDATA[ - this._updateState(); - ]]></body> - </method> - - <method name="onPropertyChanged"> - <parameter name="aProperties"/> - <body><![CDATA[ - if (aProperties.includes("appDisabled") || - aProperties.includes("signedState") || - aProperties.includes("userDisabled")) - this._updateState(); - ]]></body> - </method> - - <method name="onUpdateAvailable"> - <body><![CDATA[ - this._showStatus("update-available"); - ]]></body> - </method> - - <method name="onNoUpdateAvailable"> - <body><![CDATA[ - this._showStatus("none"); - ]]></body> - </method> - - <method name="onCheckingUpdate"> - <body><![CDATA[ - this._showStatus("checking-update"); - ]]></body> - </method> - - <method name="onCompatibilityUpdateAvailable"> - <body><![CDATA[ - this._updateState(); - ]]></body> - </method> - - <method name="onExternalInstall"> - <parameter name="aAddon"/> - <parameter name="aExistingAddon"/> - <body><![CDATA[ - if (aExistingAddon.id != this.mAddon.id) - return; - - this._initWithAddon(aAddon); - ]]></body> - </method> - - <method name="onNewInstall"> - <parameter name="aInstall"/> - <body><![CDATA[ - if (this.mAddon.applyBackgroundUpdates == AddonManager.AUTOUPDATE_ENABLE) - return; - if (this.mAddon.applyBackgroundUpdates == AddonManager.AUTOUPDATE_DEFAULT && - AddonManager.autoUpdateDefault) - return; - - this.mManualUpdate = aInstall; - this._showStatus("update-available"); - ]]></body> - </method> - - <method name="onDownloadStarted"> - <parameter name="aInstall"/> - <body><![CDATA[ - this._updateState(); - this._showStatus("progress"); - this._installStatus.initWithInstall(aInstall); - ]]></body> - </method> - - <method name="onInstallStarted"> - <parameter name="aInstall"/> - <body><![CDATA[ - this._updateState(); - this._showStatus("progress"); - this._installStatus.initWithInstall(aInstall); - ]]></body> - </method> - - <method name="onInstallEnded"> - <parameter name="aInstall"/> - <parameter name="aAddon"/> - <body><![CDATA[ - this._initWithAddon(aAddon); - ]]></body> - </method> - - <method name="onDownloadFailed"> - <body><![CDATA[ - this._updateState(); - ]]></body> - </method> - - <method name="onInstallFailed"> - <body><![CDATA[ - this._updateState(); - ]]></body> - </method> - - <method name="onInstallCancelled"> - <body><![CDATA[ - this._updateState(); - ]]></body> - </method> - </implementation> - - <handlers> - <handler event="click" button="0"><![CDATA[ - if (!["button", "checkbox", "menulist", "menuitem"].includes(event.originalTarget.localName) && - !event.originalTarget.classList.contains("text-link") && - // Treat the relnotes container as embedded text instead of a click target. - !event.originalTarget.closest(".relnotes-container")) { - this.showInDetailView(); - } else if (event.originalTarget.localName == "a" && - event.originalTarget.closest(".relnotes-container") && - event.originalTarget.href) { - event.preventDefault(); - event.stopPropagation(); - openURL(event.originalTarget.href); - } - ]]></handler> - </handlers> - </binding> - - - <!-- Addon - uninstalled - An uninstalled addon that can be re-installed. --> - <binding id="addon-uninstalled" - extends="chrome://mozapps/content/extensions/extensions.xml#addon-base"> - <content> - <xul:hbox class="pending"> - <xul:image class="pending-icon"/> - <xul:label anonid="notice" flex="1"/> - <xul:button anonid="undo-btn" class="button-link" - label="&addon.undoRemove.label;" - tooltiptext="&addon.undoRemove.tooltip;" - oncommand="document.getBindingParent(this).cancelUninstall();"/> - <xul:spacer flex="5000"/> <!-- Necessary to allow the message to wrap --> - </xul:hbox> - </content> - - <implementation> - <constructor><![CDATA[ - this._notice.textContent = gStrings.ext.formatStringFromName("uninstallNotice", - [this.mAddon.name]); - - gEventManager.registerAddonListener(this, this.mAddon.id); - ]]></constructor> - - <destructor><![CDATA[ - gEventManager.unregisterAddonListener(this, this.mAddon.id); - ]]></destructor> - - <field name="_notice" readonly="true"> - document.getAnonymousElementByAttribute(this, "anonid", "notice"); - </field> - - <method name="cancelUninstall"> - <body><![CDATA[ - // This assumes that disabling does not require a restart when - // uninstalling doesn't. Things will still work if not, the add-on - // will just still be active until finally getting uninstalled. - - if (this.isPending("uninstall")) - this.mAddon.cancelUninstall(); - else if (this.getAttribute("wasDisabled") != "true") - this.mAddon.enable(); - - // Dispatch an event so extensions.js can record telemetry. - var event = document.createEvent("Events"); - event.initEvent("Undo", true, true); - this.dispatchEvent(event); - - this.removeAttribute("pending"); - ]]></body> - </method> - - <method name="onExternalInstall"> - <parameter name="aAddon"/> - <parameter name="aExistingAddon"/> - <body><![CDATA[ - if (aExistingAddon.id != this.mAddon.id) - return; - - // Make sure any newly installed add-on has the correct disabled state - if (this.hasAttribute("wasDisabled")) { - if (this.getAttribute("wasDisabled") == "true") - aAddon.disable(); - else - aAddon.enable(); - } - - this.mAddon = aAddon; - - this.removeAttribute("pending"); - ]]></body> - </method> - - <method name="onInstallStarted"> - <parameter name="aInstall"/> - <body><![CDATA[ - // Make sure any newly installed add-on has the correct disabled state - if (this.hasAttribute("wasDisabled")) { - if (this.getAttribute("wasDisabled") == "true") - aInstall.addon.disable(); - else - aInstall.addon.enable(); - } - ]]></body> - </method> - - <method name="onInstallEnded"> - <parameter name="aInstall"/> - <parameter name="aAddon"/> - <body><![CDATA[ - this.mAddon = aAddon; - - this.removeAttribute("pending"); - ]]></body> - </method> - </implementation> - </binding> - - - <!-- Addon - installing - an addon item that is currently being installed --> - <binding id="addon-installing" - extends="chrome://mozapps/content/extensions/extensions.xml#addon-base"> - <content> - <xul:hbox anonid="warning-container" class="warning"> - <xul:image class="warning-icon"/> - <xul:label anonid="warning" flex="1"/> - <xul:button anonid="warning-link" class="button-link" - oncommand="document.getBindingParent(this).retryInstall();"/> - <xul:spacer flex="5000"/> <!-- Necessary to allow the message to wrap --> - </xul:hbox> - <xul:hbox class="content-container"> - <xul:vbox class="icon-outer-container"> - <xul:vbox class="icon-container"> - <xul:image anonid="icon" class="icon"/> - </xul:vbox> - </xul:vbox> - <xul:vbox class="fade name-outer-container" flex="1"> - <xul:hbox class="name-container"> - <xul:label anonid="name" class="name" crop="end" tooltip="addonitem-tooltip"/> - </xul:hbox> - </xul:vbox> - <xul:vbox class="install-status-container"> - <xul:hbox anonid="install-status" class="install-status"/> - </xul:vbox> - </xul:hbox> - </content> - - <implementation> - <constructor><![CDATA[ - this._installStatus.mControl = this; - this._installStatus.mInstall = this.mInstall; - this.refreshInfo(); - ]]></constructor> - - <field name="_icon"> - document.getAnonymousElementByAttribute(this, "anonid", "icon"); - </field> - <field name="_name"> - document.getAnonymousElementByAttribute(this, "anonid", "name"); - </field> - <field name="_warning"> - document.getAnonymousElementByAttribute(this, "anonid", "warning"); - </field> - <field name="_warningLink"> - document.getAnonymousElementByAttribute(this, "anonid", "warning-link"); - </field> - <field name="_installStatus"> - document.getAnonymousElementByAttribute(this, "anonid", - "install-status"); - </field> - - <method name="onInstallCompleted"> - <body><![CDATA[ - this.mAddon = this.mInstall.addon; - this.setAttribute("name", this.mAddon.name); - this.setAttribute("value", this.mAddon.id); - this.setAttribute("status", "installed"); - ]]></body> - </method> - - <method name="refreshInfo"> - <body><![CDATA[ - this.mAddon = this.mAddon || this.mInstall.addon; - if (this.mAddon) { - this._icon.src = this.mAddon.iconURL || - (this.mInstall ? this.mInstall.iconURL : ""); - this._name.value = this.mAddon.name; - } else { - this._icon.src = this.mInstall.iconURL; - // AddonInstall.name isn't always available - fallback to filename - if (this.mInstall.name) { - this._name.value = this.mInstall.name; - } else if (this.mInstall.sourceURI) { - var url = Cc["@mozilla.org/network/standard-url-mutator;1"] - .createInstance(Ci.nsIStandardURLMutator) - .init(Ci.nsIStandardURL.URLTYPE_STANDARD, - 80, this.mInstall.sourceURI.spec, - null, null) - .finalize() - .QueryInterface(Ci.nsIURL); - this._name.value = url.fileName; - } - } - - if (this.mInstall.state == AddonManager.STATE_DOWNLOAD_FAILED) { - this.setAttribute("notification", "warning"); - this._warning.textContent = gStrings.ext.formatStringFromName( - "notification.downloadError", - [this._name.value] - ); - this._warningLink.label = gStrings.ext.GetStringFromName("notification.downloadError.retry"); - this._warningLink.tooltipText = gStrings.ext.GetStringFromName("notification.downloadError.retry.tooltip"); - } else if (this.mInstall.state == AddonManager.STATE_INSTALL_FAILED) { - this.setAttribute("notification", "warning"); - this._warning.textContent = gStrings.ext.formatStringFromName( - "notification.installError", - [this._name.value] - ); - this._warningLink.label = gStrings.ext.GetStringFromName("notification.installError.retry"); - this._warningLink.tooltipText = gStrings.ext.GetStringFromName("notification.downloadError.retry.tooltip"); - } else { - this.removeAttribute("notification"); - } - ]]></body> - </method> - - <method name="retryInstall"> - <body><![CDATA[ - this.mInstall.install(); - ]]></body> - </method> - </implementation> - </binding> - - <binding id="detail-row"> - <content> - <xul:label class="detail-row-label" xbl:inherits="value=label"/> - <xul:label class="detail-row-value" xbl:inherits="value"/> - </content> - - <implementation> - <property name="value"> - <getter><![CDATA[ - return this.getAttribute("value"); - ]]></getter> - <setter><![CDATA[ - if (!val) - this.removeAttribute("value"); - else - this.setAttribute("value", val); - ]]></setter> - </property> - </implementation> - </binding> - </bindings>
--- a/toolkit/mozapps/extensions/content/extensions.xul +++ b/toolkit/mozapps/extensions/content/extensions.xul @@ -31,42 +31,16 @@ </linkset> <script src="chrome://global/content/contentAreaUtils.js"/> <script src="chrome://mozapps/content/extensions/aboutaddonsCommon.js"/> <script src="chrome://mozapps/content/extensions/extensions.js"/> <script src="chrome://mozapps/content/extensions/abuse-report-frame.js"/> <popupset> - <!-- menu for an addon item --> - <menupopup id="addonitem-popup"> - <menuitem id="menuitem_showDetails" command="cmd_showItemDetails" - default="true" data-l10n-id="cmd-show-details"/> - <menuitem id="menuitem_enableItem" command="cmd_enableItem" - label="&cmd.enableAddon.label;" - accesskey="&cmd.enableAddon.accesskey;"/> - <menuitem id="menuitem_disableItem" command="cmd_disableItem" - label="&cmd.disableAddon.label;" - accesskey="&cmd.disableAddon.accesskey;"/> - <menuitem id="menuitem_enableTheme" command="cmd_enableItem" - data-l10n-id="cmd-enable-theme"/> - <menuitem id="menuitem_disableTheme" command="cmd_disableItem" - data-l10n-id="cmd-disable-theme"/> - <menuitem id="menuitem_installItem" command="cmd_installItem" - data-l10n-id="cmd-install-addon"/> - <menuitem id="menuitem_uninstallItem" command="cmd_uninstallItem" - label="&cmd.uninstallAddon.label;" - accesskey="&cmd.uninstallAddon.accesskey;"/> - <menuseparator id="addonitem-menuseparator" /> - <menuitem id="menuitem_preferences" command="cmd_showItemPreferences" - data-l10n-id="cmd-preferences"/> - <menuitem id="menuitem_findUpdates" command="cmd_findItemUpdates" - data-l10n-id="cmd-find-updates"/> - </menupopup> - <menulist popuponly="true" id="ContentSelectDropdown" hidden="true"> <menupopup rolluponmousewheel="true" activateontab="true" position="after_start" level="parent" #ifdef XP_WIN consumeoutsideclicks="false" ignorekeys="shortcuts" #endif /> @@ -75,85 +49,59 @@ <panel is="autocomplete-richlistbox-popup" type="autocomplete-richlistbox" id="PopupAutoComplete" noautofocus="true" hidden="true" norolluponanchor="true" nomaxresults="true" /> - <tooltip id="addonitem-tooltip"/> - <menupopup id="contentAreaContextMenu" onpopupshowing="Cu.reportError('This dummy menupopup is not supposed to be shown'); return false"> <!-- a dummy element used to forward the context menu related to the extension's options page XUL browsers to the context menu defined in the parent chrome window --> </menupopup> </popupset> <!-- global commands - these act on all addons, or affect the addons manager in some other way --> <commandset id="globalCommandSet"> <!-- XXXsw remove useless oncommand attribute once bug 371900 is fixed --> <command id="cmd_focusSearch" oncommand=";"/> <command id="cmd_findAllUpdates"/> - <command id="cmd_restartApp"/> <command id="cmd_goToDiscoverPane"/> <command id="cmd_goToRecentUpdates"/> <command id="cmd_goToAvailableUpdates"/> <command id="cmd_installFromFile"/> <command id="cmd_debugAddons"/> <command id="cmd_back"/> <command id="cmd_forward"/> <command id="cmd_enableCheckCompatibility"/> <command id="cmd_enableUpdateSecurity"/> <command id="cmd_toggleAutoUpdateDefault"/> <command id="cmd_resetAddonAutoUpdate"/> - <command id="cmd_showUnsignedExtensions"/> - <command id="cmd_showAllExtensions"/> <command id="cmd_showShortcuts"/> </commandset> - <!-- view commands - these act on the selected addon --> - <commandset id="viewCommandSet" - events="richlistbox-select" commandupdater="true"> - <command id="cmd_showItemDetails"/> - <command id="cmd_findItemUpdates"/> - <command id="cmd_showItemPreferences"/> - <command id="cmd_enableItem"/> - <command id="cmd_disableItem"/> - <command id="cmd_installItem"/> - <command id="cmd_uninstallItem"/> - <command id="cmd_cancelUninstallItem"/> - <command id="cmd_cancelOperation"/> - <command id="cmd_contribute"/> - <command id="cmd_askToActivateItem"/> - <command id="cmd_alwaysActivateItem"/> - <command id="cmd_neverActivateItem"/> - </commandset> - <keyset> <key id="focusSearch" data-l10n-id="search-header-shortcut" modifiers="accel" command="cmd_focusSearch"/> </keyset> <stack id="main-page-stack" flex="1"> <hbox id="main-page-content" flex="1"> <vbox id="category-box"> <!-- category list --> <richlistbox id="categories" flex="1"> <richlistitem id="category-discover" value="addons://discover/" class="category" data-l10n-id="extensions-view-discopane" data-l10n-attrs="name" priority="1000"/> - <richlistitem id="category-legacy" value="addons://legacy/" - class="category" priority="20000" - hidden="true"/> <richlistitem id="category-availableUpdates" value="addons://updates/available" class="category" data-l10n-id="extensions-view-available-updates" data-l10n-attrs="name" hidden="true"/> <richlistitem id="category-recentUpdates" value="addons://updates/recent" class="category" data-l10n-id="extensions-view-recent-updates" @@ -216,24 +164,17 @@ <browser id="discover-browser" type="content" flex="1" disablehistory="true"/> </deck> <!-- container for views with the search/tools header --> <vbox id="headered-views" flex="1"> <!-- main header --> <hbox id="header"> - <hbox id="header-inner" align="center"> - <button id="show-all-extensions" hidden="true" - data-l10n-id="show-all-extensions-button" - command="cmd_showAllExtensions"/> - <spacer flex="1"/> - <button id="show-disabled-unsigned-extensions" hidden="true" - class="warning" data-l10n-id="show-unsigned-extensions-button" - command="cmd_showUnsignedExtensions"/> + <hbox id="header-inner" align="center" pack="end"> <label id="search-label" control="header-search"/> <textbox id="header-search" is="search-textbox" searchbutton="true" data-l10n-id="search-header" data-l10n-attrs="searchbuttonlabel" maxlength="100"/> </hbox> </hbox> <hbox id="heading"> @@ -253,19 +194,16 @@ data-l10n-id="extensions-updates-manual-updates-found" command="cmd_goToAvailableUpdates"/> <label id="updates-progress" hidden="true" data-l10n-id="extensions-updates-updating"/> <label id="updates-installed" hidden="true" data-l10n-id="extensions-updates-installed"/> <label id="updates-downloaded" hidden="true" data-l10n-id="extensions-updates-downloaded"/> - <button id="updates-restart-btn" class="button-link" hidden="true" - data-l10n-id="extensions-updates-restart" - command="cmd_restartApp"/> </hbox> <button id="header-utils-btn" type="menu" data-l10n-id="tools-menu"> <menupopup id="utils-menu"> <menuitem id="utils-updateNow" data-l10n-id="extensions-updates-check-for-updates" command="cmd_findAllUpdates"/> <menuitem id="utils-viewUpdates" @@ -294,389 +232,19 @@ data-l10n-id="manage-extensions-shortcuts" command="cmd_showShortcuts"/> </menupopup> </button> </hbox> </hbox> <deck id="headered-views-content" flex="1" selectedIndex="0"> - <!-- list view --> - <vbox id="list-view" flex="1" class="view-pane" align="stretch"> - <!-- info UI for add-ons that have been disabled for being unsigned --> - <vbox id="disabled-unsigned-addons-info" class="alert-container" hidden="true"> - <label id="disabled-unsigned-addons-heading" data-l10n-id="disabled-unsigned-heading"/> - <description data-l10n-id="disabled-unsigned-description"> - <label class="plain" id="find-alternative-addons" data-l10n-name="find-addons" is="text-link"/> - </description> - <hbox pack="start"><label id="signing-learn-more" data-l10n-id="disabled-unsigned-learn-more" is="text-link"></label></hbox> - <description id="signing-dev-info" data-l10n-id="disabled-unsigned-devinfo"> - <label class="plain" id="signing-dev-manual-link" data-l10n-name="learn-more" is="text-link"/> - </description> - </vbox> - <vbox id="legacy-extensions-notice" class="alert-container" hidden="true"> - <vbox class="alert"> - <description id="legacy-extensions-description"> - <label class="plain" id="legacy-extensions-learnmore-link" data-l10n-id="legacy-warning-show-legacy" is="text-link"/> - </description> - </vbox> - </vbox> - <vbox id="private-browsing-notice" class="alert-container" hidden="true" align="start"> - <hbox class="message-bar" align="start"> - <image class="message-bar-icon"/> - <vbox class="message-container"> - <description class="message-bar-description" data-l10n-id="private-browsing-description2"> - <label class="plain" id="private-browsing-learnmore-link" data-l10n-name="private-browsing-learn-more" is="text-link"/> - </description> - </vbox> - </hbox> - </vbox> - <vbox id="plugindeprecation-notice" class="list-view-notice" align="start"> - <hbox class="message-bar"> - <image class="message-bar-icon"/> - <description class="message-bar-description" data-l10n-id="plugin-deprecation-description"> - <label class="plain" id="plugindeprecation-learnmore-link" data-l10n-name="learn-more" is="text-link"></label> - </description> - </hbox> - </vbox> - <hbox class="view-header global-warning-container"> - <!-- global warnings --> - <hbox class="global-warning" flex="1"> - <hbox class="global-warning-safemode" flex="1" align="center" - data-l10n-id="extensions-warning-safe-mode-container"> - <image class="warning-icon"/> - <label class="global-warning-text" flex="1" crop="end" - data-l10n-id="extensions-warning-safe-mode-label"/> - </hbox> - <hbox class="global-warning-checkcompatibility" flex="1" align="center" - data-l10n-id="extensions-warning-check-compatibility-container"> - <image class="warning-icon"/> - <label class="global-warning-text" flex="1" crop="end" - data-l10n-id="extensions-warning-check-compatibility-label"/> - </hbox> - <button class="button-link global-warning-checkcompatibility" - data-l10n-id="extensions-warning-check-compatibility-enable" - command="cmd_enableCheckCompatibility"/> - <hbox class="global-warning-updatesecurity" flex="1" align="center" - data-l10n-id="extensions-warning-update-security-container"> - <image class="warning-icon"/> - <label class="global-warning-text" flex="1" crop="end" - data-l10n-id="extensions-warning-update-security-label"/> - </hbox> - <button class="button-link global-warning-updatesecurity" - data-l10n-id="extensions-warning-update-security-enable" - command="cmd_enableUpdateSecurity"/> - <spacer flex="5000"/> <!-- Necessary to allow the message to wrap --> - </hbox> - </hbox> - <vbox id="addon-list-empty" class="alert-container" - flex="1" hidden="true"> - <spacer class="alert-spacer-before"/> - <vbox class="alert"> - <label data-l10n-id="list-empty-installed"/> - <button class="discover-button" - id="discover-button-install" - data-l10n-id="list-empty-button" - command="cmd_goToDiscoverPane"/> - </vbox> - <spacer class="alert-spacer-after"/> - </vbox> - <richlistbox id="addon-list" class="list" flex="1"/> - </vbox> - <!-- extension shortcuts view --> <browser id="shortcuts-view" type="content" flex="1" disablehistory="true"/> - <!-- legacy extensions view --> - <vbox id="legacy-view" flex="1" class="view-pane" align="stretch"> - <vbox id="legacy-extensions-info"> - <label id="legacy-extensions-heading" data-l10n-id="legacy-extensions"/> - <description data-l10n-id="legacy-extensions-description"> - <label class="plain" id="legacy-learnmore" data-l10n-name="legacy-learn-more" is="text-link"></label> - </description> - </vbox> - <richlistbox id="legacy-list" class="list" flex="1"/> - </vbox> - - <!-- updates view --> - <vbox id="updates-view" flex="1" class="view-pane"> - <hbox class="view-header global-warning-container" align="center"> - <!-- global warnings --> - <hbox class="global-warning" flex="1"> - <hbox class="global-warning-safemode" flex="1" align="center" - data-l10n-id="extensions-warning-safe-mode-container"> - <image class="warning-icon"/> - <label class="global-warning-text" flex="1" crop="end" - data-l10n-id="extensions-warning-safe-mode-label"/> - </hbox> - <hbox class="global-warning-checkcompatibility" flex="1" align="center" - data-l10n-id="extensions-warning-check-compatibility-label"> - <image class="warning-icon"/> - <label class="global-warning-text" flex="1" crop="end" - data-l10n-id="extensions-warning-check-compatibility-label"/> - </hbox> - <button class="button-link global-warning-checkcompatibility" - data-l10n-id="extensions-warning-check-compatibility-enable" - command="cmd_enableCheckCompatibility"/> - <hbox class="global-warning-updatesecurity" flex="1" align="center" - data-l10n-id="extensions-warning-update-security-label"> - <image class="warning-icon"/> - <label class="global-warning-text" flex="1" crop="end" - data-l10n-id="extensions-warning-update-security-label"/> - </hbox> - <button class="button-link global-warning-updatesecurity" - data-l10n-id="extensions-warning-update-security-enable" - command="cmd_enableUpdateSecurity"/> - <spacer flex="5000"/> <!-- Necessary to allow the message to wrap --> - </hbox> - </hbox> - <vbox id="updates-list-empty" class="alert-container" - flex="1" hidden="true"> - <spacer class="alert-spacer-before"/> - <vbox class="alert"> - <label id="empty-availableUpdates-msg" data-l10n-id="list-empty-available-updates"/> - <label id="empty-recentUpdates-msg" data-l10n-id="list-empty-recent-updates"/> - <button data-l10n-id="list-empty-find-updates" - command="cmd_findAllUpdates"/> - </vbox> - <spacer class="alert-spacer-after"/> - </vbox> - <hbox id="update-actions" pack="center"> - <button id="update-selected-btn" hidden="true" - data-l10n-id="extensions-updates-update-selected"/> - </hbox> - <richlistbox id="updates-list" class="list" flex="1"/> - </vbox> - - <!-- detail view --> - <scrollbox id="detail-view" class="view-pane addon-view" orient="vertical" tabindex="0" - role="document"> - <!-- global warnings --> - <hbox class="global-warning-container global-warning"> - <hbox class="global-warning-safemode" flex="1" align="center" - data-l10n-id="extensions-warning-safe-mode-container"> - <image class="warning-icon"/> - <label class="global-warning-text" flex="1" crop="end" - data-l10n-id="extensions-warning-safe-mode-label"/> - </hbox> - <hbox class="global-warning-checkcompatibility" flex="1" align="center" - data-l10n-id="extensions-warning-check-compatibility-container"> - <image class="warning-icon"/> - <label class="global-warning-text" flex="1" crop="end" - data-l10n-id="extensions-warning-check-compatibility-label"/> - </hbox> - <button class="button-link global-warning-checkcompatibility" - data-l10n-id="extensions-warning-check-compatibility-enable" - command="cmd_enableCheckCompatibility"/> - <hbox class="global-warning-updatesecurity" flex="1" align="center" - data-l10n-id="extensions-warning-update-security-container"> - <image class="warning-icon"/> - <label class="global-warning-text" flex="1" crop="end" - data-l10n-id="extensions-warning-update-security-label"/> - </hbox> - <button class="button-link global-warning-updatesecurity" - data-l10n-id="extensions-warning-update-security-label" - command="cmd_enableUpdateSecurity"/> - <spacer flex="5000"/> <!-- Necessary to allow the message to wrap --> - </hbox> - <hbox class="detail-view-wrapper"> - <!-- "loading" splash screen --> - <vbox class="alert-container"> - <spacer class="alert-spacer-before"/> - <hbox class="alert loading"> - <image/> - <label data-l10n-id="loading-label"/> - </hbox> - <spacer class="alert-spacer-after"/> - </vbox> - <!-- actual detail view --> - <vbox class="detail-view-container" contextmenu="addonitem-popup"> - <vbox id="detail-notifications"> - <hbox id="warning-container" align="center" class="warning"> - <image class="warning-icon"/> - <label id="detail-warning" flex="1"/> - <label id="detail-warning-link" is="text-link"/> - <spacer flex="5000"/> <!-- Necessary to allow the message to wrap --> - </hbox> - <hbox id="error-container" align="center" class="error"> - <image class="error-icon"/> - <label id="detail-error" flex="1"/> - <label id="detail-error-link" is="text-link"/> - <spacer flex="5000"/> <!-- Necessary to allow the message to wrap --> - </hbox> - <hbox id="pending-container" align="center" class="pending"> - <image class="pending-icon"/> - <label id="detail-pending" flex="1"/> - <button id="detail-restart-btn" class="button-link" - data-l10n-id="addon-restart-now" - command="cmd_restartApp"/> - <button id="detail-undo-btn" class="button-link" - label="&addon.undoAction.label;" - tooltipText="&addon.undoAction.tooltip;" - command="cmd_cancelOperation"/> - <spacer flex="5000"/> <!-- Necessary to allow the message to wrap --> - </hbox> - </vbox> - <hbox class="card addon-detail" align="start"> - <vbox flex="1"> - <image class="card-heading-image theme-screenshot"/> - <hbox align="start"> - <vbox id="detail-icon-container" align="end"> - <image id="detail-icon" class="icon"/> - </vbox> - <vbox id="detail-summary"> - <hbox id="detail-name-container" class="name-container" - align="start"> - <label id="detail-name" flex="1"/> - <label id="detail-legacy-warning" class="legacy-warning" value="&addon.legacy.label;" is="text-link"/> - <label class="disabled-postfix" value="&addon.disabled.postfix;"/> - <label class="update-postfix" value="&addon.update.postfix;"/> - <spacer flex="5000"/> <!-- Necessary to allow the name to wrap --> - </hbox> - <label id="detail-creator" class="creator"/> - </vbox> - </hbox> - <vbox id="detail-desc-container" align="start" flex="1"> - <description id="detail-desc"/> - <description id="detail-fulldesc"/> - </vbox> - <vbox id="detail-contributions"> - <description id="detail-contrib-description" data-l10n-id="detail-contributions-description"/> - <hbox align="center"> - <spacer flex="1"/> - <button id="detail-contrib-btn" - data-l10n-id="cmd-contribute" - command="cmd_contribute"/> - </hbox> - </vbox> - <grid id="detail-grid"> - <columns> - <column flex="1"/> - <column flex="2"/> - </columns> - <rows id="detail-rows"> - <row class="detail-row-complex detail-privateBrowsing" id="detail-privateBrowsing-row"> - <label class="detail-row-label" data-l10n-id="detail-private-browsing-label"/> - <hbox align="center"> - <radiogroup id="detail-privateBrowsing" orient="horizontal"> - <radio data-l10n-id="detail-private-browsing-on" - value="1"/> - <radio data-l10n-id="detail-private-browsing-off" - value="0"/> - </radiogroup> - </hbox> - </row> - <hbox class="detail-row-footer detail-privateBrowsing" id="detail-privateBrowsing-row-footer"> - <description class="indent preferences-description" data-l10n-id="detail-private-browsing-description2"> - <label class="learnMore private-learnmore" data-l10n-name="detail-private-browsing-learn-more" is="text-link"/> - </description> - </hbox> - <row class="detail-row-complex detail-privateBrowsing" id="detail-privateBrowsing-required"> - <label class="detail-row-label" data-l10n-id="detail-private-required-label"/> - </row> - <hbox class="detail-row-footer detail-privateBrowsing" id="detail-privateBrowsing-required-footer"> - <description class="indent preferences-description" data-l10n-id="detail-private-required-description"> - <label class="learnMore private-learnmore" data-l10n-name="detail-private-browsing-learn-more" is="text-link"/> - </description> - </hbox> - <row class="detail-row-complex detail-privateBrowsing" id="detail-privateBrowsing-disallowed"> - <label class="detail-row-label" data-l10n-id="detail-private-disallowed-label"/> - </row> - <hbox class="detail-row-footer detail-privateBrowsing" id="detail-privateBrowsing-disallowed-footer"> - <description class="indent preferences-description" data-l10n-id="detail-private-disallowed-description"> - <label class="learnMore private-learnmore" data-l10n-name="detail-private-browsing-learn-more" is="text-link"/> - </description> - </hbox> - <row class="detail-row-complex" id="detail-updates-row"> - <label class="detail-row-label" data-l10n-id="detail-update-type"/> - <hbox align="center"> - <radiogroup id="detail-autoUpdate" orient="horizontal"> - <!-- The values here need to match the values of - AddonManager.AUTOUPDATE_* --> - <radio data-l10n-id="detail-update-default" - value="1"/> - <radio data-l10n-id="detail-update-automatic" - value="2"/> - <radio data-l10n-id="detail-update-manual" - value="0"/> - </radiogroup> - <button id="detail-findUpdates-btn" class="button-link" - data-l10n-id="detail-check-for-updates" - command="cmd_findItemUpdates"/> - </hbox> - </row> - <row class="detail-row" id="detail-version" data-l10n-id="detail-version"/> - <row class="detail-row" id="detail-dateUpdated" data-l10n-id="detail-last-updated"/> - <row class="detail-row-complex" id="detail-homepage-row" data-l10n-id="detail-home"> - <label class="detail-row-label" data-l10n-id="detail-home-value"/> - <label id="detail-homepage" class="detail-row-value" crop="end" is="text-link"/> - </row> - <row class="detail-row-complex" id="detail-repository-row" data-l10n-id="detail-repository"> - <label class="detail-row-label" data-l10n-id="detail-repository-value"/> - <label id="detail-repository" class="detail-row-value" is="text-link"/> - </row> - <row class="detail-row-complex" id="detail-rating-row"> - <label class="detail-row-label" data-l10n-id="detail-rating"/> - <hbox> - <label id="detail-rating" class="meta-value meta-rating" - showrating="average"/> - <label id="detail-reviews" is="text-link"/> - </hbox> - </row> - </rows> - </grid> - <hbox id="detail-controls"> - <button id="detail-prefs-btn" class="addon-control preferences" - data-l10n-id="detail-show-preferences" - command="cmd_showItemPreferences"/> - <spacer flex="1"/> - <button id="detail-enable-btn" class="addon-control enable" - label="&cmd.enableAddon.label;" - accesskey="&cmd.enableAddon.accesskey;" - command="cmd_enableItem"/> - <button id="detail-disable-btn" class="addon-control disable" - label="&cmd.disableAddon.label;" - accesskey="&cmd.disableAddon.accesskey;" - command="cmd_disableItem"/> - <button id="detail-uninstall-btn" class="addon-control remove" - label="&cmd.uninstallAddon.label;" - accesskey="&cmd.uninstallAddon.accesskey;" - command="cmd_uninstallItem"/> - <button id="detail-install-btn" class="addon-control install" - data-l10n-id="cmd-install-addon" - command="cmd_installItem"/> - <menulist id="detail-state-menulist" - crop="none" sizetopopup="always" - tooltiptext="&cmd.stateMenu.tooltip;"> - <menupopup> - <menuitem id="detail-ask-to-activate-menuitem" - class="addon-control" - label="&cmd.askToActivate.label;" - tooltiptext="&cmd.askToActivate.tooltip;" - command="cmd_askToActivateItem"/> - <menuitem id="detail-always-activate-menuitem" - class="addon-control" - label="&cmd.alwaysActivate.label;" - tooltiptext="&cmd.alwaysActivate.tooltip;" - command="cmd_alwaysActivateItem"/> - <menuitem id="detail-never-activate-menuitem" - class="addon-control" - label="&cmd.neverActivate.label;" - tooltiptext="&cmd.neverActivate.tooltip;" - command="cmd_neverActivateItem"/> - </menupopup> - </menulist> - </hbox> - </vbox> - </hbox> - </vbox> - <spacer flex="1"/> - </hbox> - </scrollbox> - <vbox id="html-view" flex="1"> <vbox class="alert-container html-alert-container" align="start"> <hbox class="global-warning-safemode message-bar" data-l10n-id="extensions-warning-safe-mode-container" align="start"> <image class="message-bar-icon"/> <vbox class="message-container"> <description class="message-bar-description"
--- a/toolkit/mozapps/extensions/jar.mn +++ b/toolkit/mozapps/extensions/jar.mn @@ -6,17 +6,17 @@ toolkit.jar: % content mozapps %content/mozapps/ content/mozapps/extensions/shortcuts.html (content/shortcuts.html) content/mozapps/extensions/shortcuts.css (content/shortcuts.css) content/mozapps/extensions/shortcuts.js (content/shortcuts.js) #ifndef MOZ_FENNEC * content/mozapps/extensions/extensions.xul (content/extensions.xul) content/mozapps/extensions/extensions.css (content/extensions.css) content/mozapps/extensions/extensions.js (content/extensions.js) -* content/mozapps/extensions/extensions.xml (content/extensions.xml) + content/mozapps/extensions/extensions.xml (content/extensions.xml) content/mozapps/extensions/blocklist.xul (content/blocklist.xul) content/mozapps/extensions/blocklist.js (content/blocklist.js) content/mozapps/extensions/pluginPrefs.xul (content/pluginPrefs.xul) content/mozapps/extensions/pluginPrefs.js (content/pluginPrefs.js) content/mozapps/extensions/OpenH264-license.txt (content/OpenH264-license.txt) content/mozapps/extensions/aboutaddons.html (content/aboutaddons.html) content/mozapps/extensions/aboutaddons.js (content/aboutaddons.js) content/mozapps/extensions/aboutaddonsCommon.js (content/aboutaddonsCommon.js)
--- a/toolkit/themes/shared/in-content/common.inc.css +++ b/toolkit/themes/shared/in-content/common.inc.css @@ -75,17 +75,16 @@ --grey-90-a60: rgba(12, 12, 13, 0.6); --green-50: #30e60b; --green-60: #12bc00; --green-70: #058b00; --green-80: #006504; --green-90: #003706; --orange-50: #ff9400; --purple-70: #6200a4; - --purple-70-a40: rgba(98, 0, 164, 0.4); --red-50: #ff0039; --red-50-a30: rgba(255, 0, 57, 0.3); --red-60: #d70022; --red-70: #a4000f; --red-80: #5a0002; --red-90: #3e0200; --yellow-50: #ffe900; --yellow-60: #d7b600;