diff options
Diffstat (limited to 'toolkit/mozapps/webextensions/content')
-rw-r--r-- | toolkit/mozapps/webextensions/content/about.js | 103 | ||||
-rw-r--r-- | toolkit/mozapps/webextensions/content/eula.js | 25 | ||||
-rw-r--r-- | toolkit/mozapps/webextensions/content/extensions.css | 270 | ||||
-rw-r--r-- | toolkit/mozapps/webextensions/content/extensions.js | 3827 | ||||
-rw-r--r-- | toolkit/mozapps/webextensions/content/extensions.xml | 2008 | ||||
-rw-r--r-- | toolkit/mozapps/webextensions/content/extensions.xul | 715 | ||||
-rw-r--r-- | toolkit/mozapps/webextensions/content/newaddon.xul | 67 | ||||
-rw-r--r-- | toolkit/mozapps/webextensions/content/setting.xml | 486 | ||||
-rw-r--r-- | toolkit/mozapps/webextensions/content/update.js | 663 | ||||
-rw-r--r-- | toolkit/mozapps/webextensions/content/update.xul | 194 |
10 files changed, 0 insertions, 8358 deletions
diff --git a/toolkit/mozapps/webextensions/content/about.js b/toolkit/mozapps/webextensions/content/about.js deleted file mode 100644 index 4f8fb353e..000000000 --- a/toolkit/mozapps/webextensions/content/about.js +++ /dev/null @@ -1,103 +0,0 @@ -// -*- indent-tabs-mode: nil; js-indent-level: 2 -*- - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -"use strict"; - -/* import-globals-from ../../../content/contentAreaUtils.js */ - -var Cu = Components.utils; -Cu.import("resource://gre/modules/AddonManager.jsm"); - -function init() { - var addon = window.arguments[0]; - var extensionsStrings = document.getElementById("extensionsStrings"); - - document.documentElement.setAttribute("addontype", addon.type); - - var iconURL = AddonManager.getPreferredIconURL(addon, 48, window); - if (iconURL) { - var extensionIcon = document.getElementById("extensionIcon"); - extensionIcon.src = iconURL; - } - - document.title = extensionsStrings.getFormattedString("aboutWindowTitle", [addon.name]); - var extensionName = document.getElementById("extensionName"); - extensionName.textContent = addon.name; - - var extensionVersion = document.getElementById("extensionVersion"); - if (addon.version) - extensionVersion.setAttribute("value", extensionsStrings.getFormattedString("aboutWindowVersionString", [addon.version])); - else - extensionVersion.hidden = true; - - var extensionDescription = document.getElementById("extensionDescription"); - if (addon.description) - extensionDescription.textContent = addon.description; - else - extensionDescription.hidden = true; - - var numDetails = 0; - - var extensionCreator = document.getElementById("extensionCreator"); - if (addon.creator) { - extensionCreator.setAttribute("value", addon.creator); - numDetails++; - } else { - extensionCreator.hidden = true; - var extensionCreatorLabel = document.getElementById("extensionCreatorLabel"); - extensionCreatorLabel.hidden = true; - } - - var extensionHomepage = document.getElementById("extensionHomepage"); - var homepageURL = addon.homepageURL; - if (homepageURL) { - extensionHomepage.setAttribute("homepageURL", homepageURL); - extensionHomepage.setAttribute("tooltiptext", homepageURL); - numDetails++; - } else { - extensionHomepage.hidden = true; - } - - numDetails += appendToList("extensionDevelopers", "developersBox", addon.developers); - numDetails += appendToList("extensionTranslators", "translatorsBox", addon.translators); - numDetails += appendToList("extensionContributors", "contributorsBox", addon.contributors); - - if (numDetails == 0) { - var groove = document.getElementById("groove"); - groove.hidden = true; - var extensionDetailsBox = document.getElementById("extensionDetailsBox"); - extensionDetailsBox.hidden = true; - } - - var acceptButton = document.documentElement.getButton("accept"); - acceptButton.label = extensionsStrings.getString("aboutWindowCloseButton"); - - setTimeout(sizeToContent, 0); -} - -function appendToList(aHeaderId, aNodeId, aItems) { - var header = document.getElementById(aHeaderId); - var node = document.getElementById(aNodeId); - - if (!aItems || aItems.length == 0) { - header.hidden = true; - return 0; - } - - for (let currentItem of aItems) { - var label = document.createElement("label"); - label.textContent = currentItem; - label.setAttribute("class", "contributor"); - node.appendChild(label); - } - - return aItems.length; -} - -function loadHomepage(aEvent) { - window.close(); - openURL(aEvent.target.getAttribute("homepageURL")); -} diff --git a/toolkit/mozapps/webextensions/content/eula.js b/toolkit/mozapps/webextensions/content/eula.js deleted file mode 100644 index 537ee7284..000000000 --- a/toolkit/mozapps/webextensions/content/eula.js +++ /dev/null @@ -1,25 +0,0 @@ -// -*- indent-tabs-mode: nil; js-indent-level: 2 -*- - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -"use strict"; - -var Cu = Components.utils; -Cu.import("resource://gre/modules/AddonManager.jsm"); - -function Startup() { - var bundle = document.getElementById("extensionsStrings"); - var addon = window.arguments[0].addon; - - document.documentElement.setAttribute("addontype", addon.type); - - var iconURL = AddonManager.getPreferredIconURL(addon, 48, window); - if (iconURL) - document.getElementById("icon").src = iconURL; - - var label = document.createTextNode(bundle.getFormattedString("eulaHeader", [addon.name])); - document.getElementById("heading").appendChild(label); - document.getElementById("eula").value = addon.eula; -} diff --git a/toolkit/mozapps/webextensions/content/extensions.css b/toolkit/mozapps/webextensions/content/extensions.css deleted file mode 100644 index cb5313365..000000000 --- a/toolkit/mozapps/webextensions/content/extensions.css +++ /dev/null @@ -1,270 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -@namespace xhtml "http://www.w3.org/1999/xhtml"; - -/* HTML link elements do weird things to the layout if they are not hidden */ -xhtml|link { - display: none; -} - -#categories { - -moz-binding: url("chrome://mozapps/content/extensions/extensions.xml#categories-list"); -} - -.category { - -moz-binding: url("chrome://mozapps/content/extensions/extensions.xml#category"); -} - -.sort-controls { - -moz-binding: url("chrome://mozapps/content/extensions/extensions.xml#sorters"); -} - -.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; - -moz-user-select: element; -} - -setting, row[unsupported="true"] { - display: none; -} - -setting[type="bool"] { - display: -moz-grid-line; - -moz-binding: url("chrome://mozapps/content/extensions/setting.xml#setting-bool"); -} - -setting[type="bool"][localized="true"] { - display: -moz-grid-line; - -moz-binding: url("chrome://mozapps/content/extensions/setting.xml#setting-localized-bool"); -} - -setting[type="bool"]:not([learnmore]) .preferences-learnmore, -setting[type="boolint"]:not([learnmore]) .preferences-learnmore { - visibility: collapse; -} - -setting[type="boolint"] { - display: -moz-grid-line; - -moz-binding: url("chrome://mozapps/content/extensions/setting.xml#setting-boolint"); -} - -setting[type="integer"] { - display: -moz-grid-line; - -moz-binding: url("chrome://mozapps/content/extensions/setting.xml#setting-integer"); -} - -setting[type="integer"]:not([size]) textbox { - -moz-box-flex: 1; -} - -setting[type="control"] { - display: -moz-grid-line; - -moz-binding: url("chrome://mozapps/content/extensions/setting.xml#setting-control"); -} - -setting[type="string"] { - display: -moz-grid-line; - -moz-binding: url("chrome://mozapps/content/extensions/setting.xml#setting-string"); -} - -setting[type="color"] { - display: -moz-grid-line; - -moz-binding: url("chrome://mozapps/content/extensions/setting.xml#setting-color"); -} - -setting[type="file"], -setting[type="directory"] { - display: -moz-grid-line; - -moz-binding: url("chrome://mozapps/content/extensions/setting.xml#setting-path"); -} - -setting[type="radio"], -setting[type="menulist"] { - display: -moz-grid-line; - -moz-binding: url("chrome://mozapps/content/extensions/setting.xml#setting-multi"); -} - -#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; -} - -#search-list[local="false"] > .addon[remote="false"], -#search-list[remote="false"] > .addon[remote="true"] { - visibility: collapse; -} - -#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, -#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[loading] .detail-view-container, -#detail-view:not([loading]) .alert-container, -.detail-row:not([value]), -#search-list[remote="false"] #search-allresults-link { - display: none; -} - -#addons-page:not([warning]) #list-view > .global-warning-container { - display: none; -} -#addon-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), - so don't show that warning when viewing plugins. */ -#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; -} - -#addons-page .view-pane:not([type="experiment"]) .experiment-info-container { - display: none; -} - -.addon .relnotes { - -moz-user-select: text; -} -#detail-name, #detail-desc, #detail-fulldesc { - -moz-user-select: text; -} - -/* 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; -} - -#header-utils-btn { - -moz-user-focus: normal; -} - -.discover-button[disabled="true"] { - display: none; -} - -#experiments-learn-more[disabled="true"] { - display: none; -} - -#experiments-change-telemetry[disabled="true"] { - display: none; -} - -.view-pane[type="experiment"] .error, -.view-pane[type="experiment"] .warning, -.view-pane[type="experiment"] .addon:not([pending="uninstall"]) .pending, -.view-pane[type="experiment"] .disabled-postfix, -.view-pane[type="experiment"] .update-postfix, -.view-pane[type="experiment"] .addon-control.enable, -.view-pane[type="experiment"] .addon-control.disable, -#detail-view[type="experiment"] .alert-container, -#detail-view[type="experiment"] #detail-version, -#detail-view[type="experiment"] #detail-creator, -#detail-view[type="experiment"] #detail-enable-btn, -#detail-view[type="experiment"] #detail-disable-btn { - display: none; -} - -.view-pane:not([type="experiment"]) .experiment-container, -.view-pane:not([type="experiment"]) #detail-experiment-container { - display: none; -} - -.addon[type="experiment"][status="installing"] .experiment-time, -.addon[type="experiment"][status="installing"] .experiment-state { - display: none; -} diff --git a/toolkit/mozapps/webextensions/content/extensions.js b/toolkit/mozapps/webextensions/content/extensions.js deleted file mode 100644 index 3159eb1e1..000000000 --- a/toolkit/mozapps/webextensions/content/extensions.js +++ /dev/null @@ -1,3827 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -"use strict"; - -/* import-globals-from ../../../content/contentAreaUtils.js */ -/* globals XMLStylesheetProcessingInstruction*/ - -var Cc = Components.classes; -var Ci = Components.interfaces; -var Cu = Components.utils; -var Cr = Components.results; - -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); -Cu.import("resource://gre/modules/Services.jsm"); -Cu.import("resource://gre/modules/DownloadUtils.jsm"); -Cu.import("resource://gre/modules/AddonManager.jsm"); -Cu.import("resource://gre/modules/addons/AddonRepository.jsm"); - -const CONSTANTS = {}; -Cu.import("resource://gre/modules/addons/AddonConstants.jsm", CONSTANTS); -const SIGNING_REQUIRED = CONSTANTS.REQUIRE_SIGNING ? - true : - Services.prefs.getBoolPref("xpinstall.signatures.required"); - -XPCOMUtils.defineLazyModuleGetter(this, "PluralForm", - "resource://gre/modules/PluralForm.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "Preferences", - "resource://gre/modules/Preferences.jsm"); - -const PREF_DISCOVERURL = "extensions.webservice.discoverURL"; -const PREF_DISCOVER_ENABLED = "extensions.getAddons.showPane"; -const PREF_XPI_ENABLED = "xpinstall.enabled"; -const PREF_MAXRESULTS = "extensions.getAddons.maxResults"; -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 LOADING_MSG_DELAY = 100; - -const SEARCH_SCORE_MULTIPLIER_NAME = 2; -const SEARCH_SCORE_MULTIPLIER_DESCRIPTION = 2; - -// Use integers so search scores are sortable by nsIXULSortService -const SEARCH_SCORE_MATCH_WHOLEWORD = 10; -const SEARCH_SCORE_MATCH_WORDBOUNDRY = 6; -const SEARCH_SCORE_MATCH_SUBSTRING = 3; - -const UPDATES_RECENT_TIMESPAN = 2 * 24 * 3600000; // 2 days (in milliseconds) -const UPDATES_RELEASENOTES_TRANSFORMFILE = "chrome://mozapps/content/extensions/updateinfo.xsl"; - -const XMLURI_PARSE_ERROR = "http://www.mozilla.org/newlayout/xml/parsererror.xml" - -var gViewDefault = "addons://discover/"; - -var gStrings = {}; -XPCOMUtils.defineLazyServiceGetter(gStrings, "bundleSvc", - "@mozilla.org/intl/stringbundle;1", - "nsIStringBundleService"); - -XPCOMUtils.defineLazyGetter(gStrings, "brand", function() { - return this.bundleSvc.createBundle("chrome://branding/locale/brand.properties"); -}); -XPCOMUtils.defineLazyGetter(gStrings, "ext", function() { - return this.bundleSvc.createBundle("chrome://mozapps/locale/extensions/extensions.properties"); -}); -XPCOMUtils.defineLazyGetter(gStrings, "dl", function() { - return this.bundleSvc.createBundle("chrome://mozapps/locale/downloads/downloads.properties"); -}); - -XPCOMUtils.defineLazyGetter(gStrings, "brandShortName", function() { - return this.brand.GetStringFromName("brandShortName"); -}); -XPCOMUtils.defineLazyGetter(gStrings, "appVersion", function() { - return Services.appinfo.version; -}); - -document.addEventListener("load", initialize, true); -window.addEventListener("unload", shutdown, false); - -class MessageDispatcher { - constructor(target) { - this.listeners = new Map(); - this.target = target; - } - - addMessageListener(name, handler) { - if (!this.listeners.has(name)) { - this.listeners.set(name, new Set()); - } - - this.listeners.get(name).add(handler); - } - - removeMessageListener(name, handler) { - if (this.listeners.has(name)) { - this.listeners.get(name).delete(handler); - } - } - - sendAsyncMessage(name, data) { - for (let handler of this.listeners.get(name) || new Set()) { - Promise.resolve().then(() => { - handler.receiveMessage({ - name, - data, - target: this.target, - }); - }); - } - } -} - -/** - * A mock FrameMessageManager global to allow frame scripts to run in - * non-top-level, non-remote <browser>s as if they were top-level or - * remote. - * - * @param {Element} browser - * A XUL <browser> element. - */ -class FakeFrameMessageManager { - constructor(browser) { - let dispatcher = new MessageDispatcher(browser); - let frameDispatcher = new MessageDispatcher(null); - - this.sendAsyncMessage = frameDispatcher.sendAsyncMessage.bind(frameDispatcher); - this.addMessageListener = dispatcher.addMessageListener.bind(dispatcher); - this.removeMessageListener = dispatcher.removeMessageListener.bind(dispatcher); - - this.frame = { - get content() { - return browser.contentWindow; - }, - - get docShell() { - return browser.docShell; - }, - - addEventListener: browser.addEventListener.bind(browser), - removeEventListener: browser.removeEventListener.bind(browser), - - sendAsyncMessage: dispatcher.sendAsyncMessage.bind(dispatcher), - addMessageListener: frameDispatcher.addMessageListener.bind(frameDispatcher), - removeMessageListener: frameDispatcher.removeMessageListener.bind(frameDispatcher), - } - } - - loadFrameScript(url) { - Services.scriptloader.loadSubScript(url, Object.create(this.frame)); - } -} - -var gPendingInitializations = 1; -Object.defineProperty(this, "gIsInitializing", { - get: () => gPendingInitializations > 0 -}); - -function initialize(event) { - // XXXbz this listener gets _all_ load events for all nodes in the - // document... but relies on not being called "too early". - if (event.target instanceof XMLStylesheetProcessingInstruction) { - return; - } - 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 detailScreenshot = document.getElementById("detail-screenshot"); - detailScreenshot.addEventListener("load", function(event) { - this.removeAttribute("loading"); - }); - detailScreenshot.addEventListener("error", function(event) { - this.setAttribute("loading", "error"); - }); - - 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) { - gDragDrop.onDrop(event); - }); - addonPage.addEventListener("keypress", function(event) { - gHeader.onKeyPress(event); - }); - - if (!isDiscoverEnabled()) { - gViewDefault = "addons://list/extension"; - } - - gViewController.initialize(); - gCategories.initialize(); - gHeader.initialize(); - gEventManager.initialize(); - Services.obs.addObserver(sendEMPong, "EM-ping", false); - Services.obs.notifyObservers(window, "EM-loaded", ""); - - // If the initial view has already been selected (by a call to loadView from - // the above notifications) then bail out now - if (gViewController.initialViewSelected) - return; - - // If there is a history state to restore then use that - if (window.history.state) { - gViewController.updateState(window.history.state); - return; - } - - // Default to the last selected category - var view = gCategories.node.value; - - // Allow passing in a view through the window arguments - if ("arguments" in window && window.arguments.length > 0 && - window.arguments[0] !== null && "view" in window.arguments[0]) { - view = window.arguments[0].view; - } - - gViewController.loadInitialView(view); -} - -function notifyInitialized() { - if (!gIsInitializing) - return; - - gPendingInitializations--; - if (!gIsInitializing) { - var event = document.createEvent("Events"); - event.initEvent("Initialized", true, true); - document.dispatchEvent(event); - } -} - -function shutdown() { - gCategories.shutdown(); - gSearchView.shutdown(); - gEventManager.shutdown(); - gViewController.shutdown(); - Services.obs.removeObserver(sendEMPong, "EM-ping"); -} - -function sendEMPong(aSubject, aTopic, aData) { - Services.obs.notifyObservers(window, "EM-pong", ""); -} - -// Used by external callers to load a specific view into the manager -function loadView(aViewId) { - if (!gViewController.initialViewSelected) { - // The caller opened the window and immediately loaded the view so it - // should be the initial history entry - - gViewController.loadInitialView(aViewId); - } else { - gViewController.loadView(aViewId); - } -} - -function isCorrectlySigned(aAddon) { - // Add-ons without an "isCorrectlySigned" property are correctly signed as - // they aren't the correct type for signing. - return aAddon.isCorrectlySigned !== false; -} - -function isDiscoverEnabled() { - if (Services.prefs.getPrefType(PREF_DISCOVERURL) == Services.prefs.PREF_INVALID) - return false; - - try { - if (!Services.prefs.getBoolPref(PREF_DISCOVER_ENABLED)) - return false; - } catch (e) {} - - try { - if (!Services.prefs.getBoolPref(PREF_XPI_ENABLED)) - return false; - } catch (e) {} - - return true; -} - -/** - * Obtain the main DOMWindow for the current context. - */ -function getMainWindow() { - return window.QueryInterface(Ci.nsIInterfaceRequestor) - .getInterface(Ci.nsIWebNavigation) - .QueryInterface(Ci.nsIDocShellTreeItem) - .rootTreeItem - .QueryInterface(Ci.nsIInterfaceRequestor) - .getInterface(Ci.nsIDOMWindow); -} - -function getBrowserElement() { - return window.QueryInterface(Ci.nsIInterfaceRequestor) - .getInterface(Ci.nsIDocShell) - .chromeEventHandler; -} - -/** - * Obtain the DOMWindow that can open a preferences pane. - * - * This is essentially "get the browser chrome window" with the added check - * that the supposed browser chrome window is capable of opening a preferences - * pane. - * - * This may return null if we can't find the browser chrome window. - */ -function getMainWindowWithPreferencesPane() { - let mainWindow = getMainWindow(); - if (mainWindow && "openAdvancedPreferences" in mainWindow) { - return mainWindow; - } - return null; -} - -/** - * A wrapper around the HTML5 session history service that allows the browser - * back/forward controls to work within the manager - */ -var HTML5History = { - get index() { - return window.QueryInterface(Ci.nsIInterfaceRequestor) - .getInterface(Ci.nsIWebNavigation) - .sessionHistory.index; - }, - - get canGoBack() { - return window.QueryInterface(Ci.nsIInterfaceRequestor) - .getInterface(Ci.nsIWebNavigation) - .canGoBack; - }, - - get canGoForward() { - return window.QueryInterface(Ci.nsIInterfaceRequestor) - .getInterface(Ci.nsIWebNavigation) - .canGoForward; - }, - - back: function() { - window.history.back(); - gViewController.updateCommand("cmd_back"); - gViewController.updateCommand("cmd_forward"); - }, - - forward: function() { - window.history.forward(); - gViewController.updateCommand("cmd_back"); - gViewController.updateCommand("cmd_forward"); - }, - - pushState: function(aState) { - window.history.pushState(aState, document.title); - }, - - replaceState: function(aState) { - window.history.replaceState(aState, document.title); - }, - - popState: function() { - function onStatePopped(aEvent) { - window.removeEventListener("popstate", onStatePopped, true); - // TODO To ensure we can't go forward again we put an additional entry - // for the current state into the history. Ideally we would just strip - // the history but there doesn't seem to be a way to do that. Bug 590661 - window.history.pushState(aEvent.state, document.title); - } - window.addEventListener("popstate", onStatePopped, true); - window.history.back(); - gViewController.updateCommand("cmd_back"); - gViewController.updateCommand("cmd_forward"); - } -}; - -/** - * A wrapper around a fake history service - */ -var FakeHistory = { - pos: 0, - states: [null], - - get index() { - return this.pos; - }, - - get canGoBack() { - return this.pos > 0; - }, - - get canGoForward() { - return (this.pos + 1) < this.states.length; - }, - - back: function() { - if (this.pos == 0) - throw Components.Exception("Cannot go back from this point"); - - this.pos--; - gViewController.updateState(this.states[this.pos]); - gViewController.updateCommand("cmd_back"); - gViewController.updateCommand("cmd_forward"); - }, - - forward: function() { - if ((this.pos + 1) >= this.states.length) - throw Components.Exception("Cannot go forward from this point"); - - this.pos++; - gViewController.updateState(this.states[this.pos]); - gViewController.updateCommand("cmd_back"); - gViewController.updateCommand("cmd_forward"); - }, - - pushState: function(aState) { - this.pos++; - this.states.splice(this.pos, this.states.length); - this.states.push(aState); - }, - - replaceState: function(aState) { - this.states[this.pos] = aState; - }, - - popState: function() { - if (this.pos == 0) - throw Components.Exception("Cannot popState from this view"); - - this.states.splice(this.pos, this.states.length); - this.pos--; - - gViewController.updateState(this.states[this.pos]); - gViewController.updateCommand("cmd_back"); - gViewController.updateCommand("cmd_forward"); - } -}; - -// If the window has a session history then use the HTML5 History wrapper -// otherwise use our fake history implementation -if (window.QueryInterface(Ci.nsIInterfaceRequestor) - .getInterface(Ci.nsIWebNavigation) - .sessionHistory) { - var gHistory = HTML5History; -} -else { - gHistory = FakeHistory; -} - -var gEventManager = { - _listeners: {}, - _installListeners: [], - - initialize: function() { - const ADDON_EVENTS = ["onEnabling", "onEnabled", "onDisabling", - "onDisabled", "onUninstalling", "onUninstalled", - "onInstalled", "onOperationCancelled", - "onUpdateAvailable", "onUpdateFinished", - "onCompatibilityUpdateAvailable", - "onPropertyChanged"]; - for (let evt of ADDON_EVENTS) { - let event = evt; - this[event] = (...aArgs) => this.delegateAddonEvent(event, aArgs); - } - - const INSTALL_EVENTS = ["onNewInstall", "onDownloadStarted", - "onDownloadEnded", "onDownloadFailed", - "onDownloadProgress", "onDownloadCancelled", - "onInstallStarted", "onInstallEnded", - "onInstallFailed", "onInstallCancelled", - "onExternalInstall"]; - for (let evt of INSTALL_EVENTS) { - let event = evt; - this[event] = (...aArgs) => this.delegateInstallEvent(event, aArgs); - } - - 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); - - }, false); - - 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; - }, false); - }, - - shutdown: function() { - AddonManager.removeManagerListener(this); - AddonManager.removeInstallListener(this); - AddonManager.removeAddonListener(this); - }, - - registerAddonListener: function(aListener, aAddonId) { - if (!(aAddonId in this._listeners)) - this._listeners[aAddonId] = []; - else if (this._listeners[aAddonId].indexOf(aListener) != -1) - return; - this._listeners[aAddonId].push(aListener); - }, - - unregisterAddonListener: function(aListener, aAddonId) { - if (!(aAddonId in this._listeners)) - return; - var index = this._listeners[aAddonId].indexOf(aListener); - if (index == -1) - return; - this._listeners[aAddonId].splice(index, 1); - }, - - registerInstallListener: function(aListener) { - if (this._installListeners.indexOf(aListener) != -1) - return; - this._installListeners.push(aListener); - }, - - unregisterInstallListener: function(aListener) { - var i = this._installListeners.indexOf(aListener); - if (i == -1) - return; - this._installListeners.splice(i, 1); - }, - - delegateAddonEvent: function(aEvent, aParams) { - var addon = aParams.shift(); - if (!(addon.id in this._listeners)) - return; - - var listeners = this._listeners[addon.id]; - for (let listener of listeners) { - if (!(aEvent in listener)) - continue; - try { - listener[aEvent].apply(listener, aParams); - } catch (e) { - // this shouldn't be fatal - Cu.reportError(e); - } - } - }, - - delegateInstallEvent: function(aEvent, aParams) { - var existingAddon = aEvent == "onExternalInstall" ? aParams[1] : aParams[0].existingAddon; - // If the install is an update then send the event to all listeners - // registered for the existing add-on - if (existingAddon) - this.delegateAddonEvent(aEvent, [existingAddon].concat(aParams)); - - for (let listener of this._installListeners) { - if (!(aEvent in listener)) - continue; - try { - listener[aEvent].apply(listener, aParams); - } catch (e) { - // this shouldn't be fatal - Cu.reportError(e); - } - } - }, - - refreshGlobalWarning: function() { - var page = document.getElementById("addons-page"); - - if (Services.appinfo.inSafeMode) { - page.setAttribute("warning", "safemode"); - return; - } - - if (AddonManager.checkUpdateSecurityDefault && - !AddonManager.checkUpdateSecurity) { - page.setAttribute("warning", "updatesecurity"); - return; - } - - if (!AddonManager.checkCompatibility) { - page.setAttribute("warning", "checkcompatibility"); - return; - } - - page.removeAttribute("warning"); - }, - - refreshAutoUpdateDefault: function() { - var updateEnabled = AddonManager.updateEnabled; - var autoUpdateDefault = AddonManager.autoUpdateDefault; - - // The checkbox needs to reflect that both prefs need to be true - // for updates to be checked for and applied automatically - document.getElementById("utils-autoUpdateDefault") - .setAttribute("checked", updateEnabled && autoUpdateDefault); - - document.getElementById("utils-resetAddonUpdatesToAutomatic").hidden = !autoUpdateDefault; - document.getElementById("utils-resetAddonUpdatesToManual").hidden = autoUpdateDefault; - }, - - onCompatibilityModeChanged: function() { - this.refreshGlobalWarning(); - }, - - onCheckUpdateSecurityChanged: function() { - this.refreshGlobalWarning(); - }, - - onUpdateModeChanged: function() { - this.refreshAutoUpdateDefault(); - } -}; - - -var gViewController = { - viewPort: null, - currentViewId: "", - currentViewObj: null, - currentViewRequest: 0, - viewObjects: {}, - viewChangeCallback: null, - initialViewSelected: false, - lastHistoryIndex: -1, - - initialize: function() { - this.viewPort = document.getElementById("view-port"); - this.headeredViews = document.getElementById("headered-views"); - this.headeredViewsDeck = document.getElementById("headered-views-content"); - - this.viewObjects["search"] = gSearchView; - this.viewObjects["discover"] = gDiscoverView; - this.viewObjects["list"] = gListView; - this.viewObjects["detail"] = gDetailView; - this.viewObjects["updates"] = gUpdatesView; - - for (let type in this.viewObjects) { - let view = this.viewObjects[type]; - view.initialize(); - } - - window.controllers.appendController(this); - - window.addEventListener("popstate", function(e) { - gViewController.updateState(e.state); - }, - false); - }, - - shutdown: function() { - if (this.currentViewObj) - this.currentViewObj.hide(); - this.currentViewRequest = 0; - - for (let type in this.viewObjects) { - let view = this.viewObjects[type]; - if ("shutdown" in view) { - try { - view.shutdown(); - } catch (e) { - // this shouldn't be fatal - Cu.reportError(e); - } - } - } - - window.controllers.removeController(this); - }, - - updateState: function(state) { - try { - this.loadViewInternal(state.view, state.previousView, state); - this.lastHistoryIndex = gHistory.index; - } - catch (e) { - // The attempt to load the view failed, try moving further along history - if (this.lastHistoryIndex > gHistory.index) { - if (gHistory.canGoBack) - gHistory.back(); - else - gViewController.replaceView(gViewDefault); - } else if (gHistory.canGoForward) { - gHistory.forward(); - } else { - gViewController.replaceView(gViewDefault); - } - } - }, - - parseViewId: function(aViewId) { - var matchRegex = /^addons:\/\/([^\/]+)\/(.*)$/; - var [, viewType, viewParam] = aViewId.match(matchRegex) || []; - return {type: viewType, param: decodeURIComponent(viewParam)}; - }, - - get isLoading() { - return !this.currentViewObj || this.currentViewObj.node.hasAttribute("loading"); - }, - - loadView: function(aViewId) { - var isRefresh = false; - if (aViewId == this.currentViewId) { - if (this.isLoading) - return; - if (!("refresh" in this.currentViewObj)) - return; - if (!this.currentViewObj.canRefresh()) - return; - isRefresh = true; - } - - var state = { - view: aViewId, - previousView: this.currentViewId - }; - if (!isRefresh) { - gHistory.pushState(state); - this.lastHistoryIndex = gHistory.index; - } - this.loadViewInternal(aViewId, this.currentViewId, state); - }, - - // Replaces the existing view with a new one, rewriting the current history - // entry to match. - replaceView: function(aViewId) { - if (aViewId == this.currentViewId) - return; - - var state = { - view: aViewId, - previousView: null - }; - gHistory.replaceState(state); - this.loadViewInternal(aViewId, null, state); - }, - - loadInitialView: function(aViewId) { - var state = { - view: aViewId, - previousView: null - }; - gHistory.replaceState(state); - - this.loadViewInternal(aViewId, null, state); - this.initialViewSelected = true; - notifyInitialized(); - }, - - get displayedView() { - if (this.viewPort.selectedPanel == this.headeredViews) { - return this.headeredViewsDeck.selectedPanel; - } - return this.viewPort.selectedPanel; - }, - - set displayedView(view) { - let node = view.node; - if (node.parentNode == this.headeredViewsDeck) { - this.headeredViewsDeck.selectedPanel = node; - this.viewPort.selectedPanel = this.headeredViews; - } else { - this.viewPort.selectedPanel = node; - } - }, - - loadViewInternal: function(aViewId, aPreviousView, aState) { - var view = this.parseViewId(aViewId); - - if (!view.type || !(view.type in this.viewObjects)) - throw Components.Exception("Invalid view: " + view.type); - - var viewObj = this.viewObjects[view.type]; - if (!viewObj.node) - throw Components.Exception("Root node doesn't exist for '" + view.type + "' view"); - - if (this.currentViewObj && aViewId != aPreviousView) { - try { - let canHide = this.currentViewObj.hide(); - if (canHide === false) - return; - this.displayedView.removeAttribute("loading"); - } catch (e) { - // this shouldn't be fatal - Cu.reportError(e); - } - } - - gCategories.select(aViewId, aPreviousView); - - this.currentViewId = aViewId; - this.currentViewObj = viewObj; - - this.displayedView = this.currentViewObj; - this.currentViewObj.node.setAttribute("loading", "true"); - this.currentViewObj.node.focus(); - - if (aViewId == aPreviousView) - this.currentViewObj.refresh(view.param, ++this.currentViewRequest, aState); - else - this.currentViewObj.show(view.param, ++this.currentViewRequest, aState); - }, - - // Moves back in the document history and removes the current history entry - popState: function(aCallback) { - this.viewChangeCallback = aCallback; - gHistory.popState(); - }, - - notifyViewChanged: function() { - this.displayedView.removeAttribute("loading"); - - if (this.viewChangeCallback) { - this.viewChangeCallback(); - this.viewChangeCallback = null; - } - - var event = document.createEvent("Events"); - event.initEvent("ViewChanged", true, true); - this.currentViewObj.node.dispatchEvent(event); - }, - - commands: { - cmd_back: { - isEnabled: function() { - return gHistory.canGoBack; - }, - doCommand: function() { - gHistory.back(); - } - }, - - cmd_forward: { - isEnabled: function() { - return gHistory.canGoForward; - }, - doCommand: function() { - gHistory.forward(); - } - }, - - cmd_focusSearch: { - isEnabled: () => true, - doCommand: function() { - gHeader.focusSearchBox(); - } - }, - - cmd_restartApp: { - isEnabled: function() { - return true; - }, - doCommand: function() { - let cancelQuit = Cc["@mozilla.org/supports-PRBool;1"]. - createInstance(Ci.nsISupportsPRBool); - Services.obs.notifyObservers(cancelQuit, "quit-application-requested", - "restart"); - if (cancelQuit.data) - return; // somebody canceled our quit request - - let appStartup = Cc["@mozilla.org/toolkit/app-startup;1"]. - getService(Ci.nsIAppStartup); - appStartup.quit(Ci.nsIAppStartup.eAttemptQuit | Ci.nsIAppStartup.eRestart); - } - }, - - cmd_enableCheckCompatibility: { - isEnabled: function() { - return true; - }, - doCommand: function() { - AddonManager.checkCompatibility = true; - } - }, - - cmd_enableUpdateSecurity: { - isEnabled: function() { - return true; - }, - doCommand: function() { - AddonManager.checkUpdateSecurity = true; - } - }, - - cmd_toggleAutoUpdateDefault: { - isEnabled: function() { - return true; - }, - doCommand: function() { - if (!AddonManager.updateEnabled || !AddonManager.autoUpdateDefault) { - // One or both of the prefs is false, i.e. the checkbox is not checked. - // Now toggle both to true. If the user wants us to auto-update - // add-ons, we also need to auto-check for updates. - AddonManager.updateEnabled = true; - AddonManager.autoUpdateDefault = true; - } else { - // Both prefs are true, i.e. the checkbox is checked. - // Toggle the auto pref to false, but don't touch the enabled check. - AddonManager.autoUpdateDefault = false; - } - } - }, - - cmd_resetAddonAutoUpdate: { - isEnabled: function() { - return true; - }, - doCommand: function() { - AddonManager.getAllAddons(function(aAddonList) { - for (let addon of aAddonList) { - if ("applyBackgroundUpdates" in addon) - addon.applyBackgroundUpdates = AddonManager.AUTOUPDATE_DEFAULT; - } - }); - } - }, - - cmd_goToDiscoverPane: { - isEnabled: function() { - return gDiscoverView.enabled; - }, - doCommand: function() { - gViewController.loadView("addons://discover/"); - } - }, - - cmd_goToRecentUpdates: { - isEnabled: function() { - return true; - }, - doCommand: function() { - gViewController.loadView("addons://updates/recent"); - } - }, - - cmd_goToAvailableUpdates: { - isEnabled: function() { - return true; - }, - doCommand: function() { - gViewController.loadView("addons://updates/available"); - } - }, - - cmd_showItemDetails: { - isEnabled: function(aAddon) { - return !!aAddon && (gViewController.currentViewObj != gDetailView); - }, - doCommand: function(aAddon, aScrollToPreferences) { - gViewController.loadView("addons://detail/" + - encodeURIComponent(aAddon.id) + - (aScrollToPreferences ? "/preferences" : "")); - } - }, - - cmd_findAllUpdates: { - inProgress: false, - isEnabled: function() { - return !this.inProgress; - }, - doCommand: function() { - this.inProgress = true; - gViewController.updateCommand("cmd_findAllUpdates"); - document.getElementById("updates-noneFound").hidden = true; - document.getElementById("updates-progress").hidden = false; - document.getElementById("updates-manualUpdatesFound-btn").hidden = true; - - var pendingChecks = 0; - var numUpdated = 0; - var numManualUpdates = 0; - var restartNeeded = false; - - let updateStatus = () => { - if (pendingChecks > 0) - return; - - this.inProgress = false; - gViewController.updateCommand("cmd_findAllUpdates"); - document.getElementById("updates-progress").hidden = true; - gUpdatesView.maybeRefresh(); - - if (numManualUpdates > 0 && numUpdated == 0) { - document.getElementById("updates-manualUpdatesFound-btn").hidden = false; - return; - } - - if (numUpdated == 0) { - document.getElementById("updates-noneFound").hidden = false; - return; - } - - if (restartNeeded) { - document.getElementById("updates-downloaded").hidden = false; - document.getElementById("updates-restart-btn").hidden = false; - } else { - document.getElementById("updates-installed").hidden = false; - } - } - - var updateInstallListener = { - onDownloadFailed: function() { - pendingChecks--; - updateStatus(); - }, - onInstallFailed: function() { - pendingChecks--; - updateStatus(); - }, - onInstallEnded: function(aInstall, aAddon) { - pendingChecks--; - numUpdated++; - if (isPending(aInstall.existingAddon, "upgrade")) - restartNeeded = true; - updateStatus(); - } - }; - - var updateCheckListener = { - onUpdateAvailable: function(aAddon, aInstall) { - gEventManager.delegateAddonEvent("onUpdateAvailable", - [aAddon, aInstall]); - if (AddonManager.shouldAutoUpdate(aAddon)) { - aInstall.addListener(updateInstallListener); - aInstall.install(); - } else { - pendingChecks--; - numManualUpdates++; - updateStatus(); - } - }, - onNoUpdateAvailable: function(aAddon) { - pendingChecks--; - updateStatus(); - }, - onUpdateFinished: function(aAddon, aError) { - gEventManager.delegateAddonEvent("onUpdateFinished", - [aAddon, aError]); - } - }; - - AddonManager.getAddonsByTypes(null, function(aAddonList) { - for (let addon of aAddonList) { - if (addon.permissions & AddonManager.PERM_CAN_UPGRADE) { - pendingChecks++; - addon.findUpdates(updateCheckListener, - AddonManager.UPDATE_WHEN_USER_REQUESTED); - } - } - - if (pendingChecks == 0) - updateStatus(); - }); - } - }, - - cmd_findItemUpdates: { - isEnabled: function(aAddon) { - if (!aAddon) - return false; - return hasPermission(aAddon, "upgrade"); - }, - doCommand: function(aAddon) { - var listener = { - onUpdateAvailable: function(aAddon, aInstall) { - gEventManager.delegateAddonEvent("onUpdateAvailable", - [aAddon, aInstall]); - if (AddonManager.shouldAutoUpdate(aAddon)) - aInstall.install(); - }, - onNoUpdateAvailable: function(aAddon) { - gEventManager.delegateAddonEvent("onNoUpdateAvailable", - [aAddon]); - } - }; - gEventManager.delegateAddonEvent("onCheckingUpdate", [aAddon]); - aAddon.findUpdates(listener, AddonManager.UPDATE_WHEN_USER_REQUESTED); - } - }, - - cmd_showItemPreferences: { - isEnabled: function(aAddon) { - if (!aAddon || - (!aAddon.isActive && !aAddon.isGMPlugin) || - !aAddon.optionsURL) { - return false; - } - if (gViewController.currentViewObj == gDetailView && - (aAddon.optionsType == AddonManager.OPTIONS_TYPE_INLINE || - aAddon.optionsType == AddonManager.OPTIONS_TYPE_INLINE_BROWSER)) { - return false; - } - if (aAddon.optionsType == AddonManager.OPTIONS_TYPE_INLINE_INFO) - return false; - return true; - }, - doCommand: function(aAddon) { - if (hasInlineOptions(aAddon)) { - gViewController.commands.cmd_showItemDetails.doCommand(aAddon, true); - return; - } - var optionsURL = aAddon.optionsURL; - if (aAddon.optionsType == AddonManager.OPTIONS_TYPE_TAB && - openOptionsInTab(optionsURL)) { - return; - } - var windows = Services.wm.getEnumerator(null); - while (windows.hasMoreElements()) { - var win = windows.getNext(); - if (win.closed) { - continue; - } - if (win.document.documentURI == optionsURL) { - win.focus(); - return; - } - } - var features = "chrome,titlebar,toolbar,centerscreen"; - try { - var instantApply = Services.prefs.getBoolPref("browser.preferences.instantApply"); - features += instantApply ? ",dialog=no" : ",modal"; - } catch (e) { - features += ",modal"; - } - openDialog(optionsURL, "", features); - } - }, - - cmd_showItemAbout: { - isEnabled: function(aAddon) { - // XXXunf This may be applicable to install items too. See bug 561260 - return !!aAddon; - }, - doCommand: function(aAddon) { - var aboutURL = aAddon.aboutURL; - if (aboutURL) - openDialog(aboutURL, "", "chrome,centerscreen,modal", aAddon); - else - openDialog("chrome://mozapps/content/extensions/about.xul", - "", "chrome,centerscreen,modal", aAddon); - } - }, - - cmd_enableItem: { - isEnabled: function(aAddon) { - if (!aAddon) - return false; - let addonType = AddonManager.addonTypes[aAddon.type]; - return (!(addonType.flags & AddonManager.TYPE_SUPPORTS_ASK_TO_ACTIVATE) && - hasPermission(aAddon, "enable")); - }, - doCommand: function(aAddon) { - aAddon.userDisabled = false; - }, - getTooltip: function(aAddon) { - if (!aAddon) - return ""; - if (aAddon.operationsRequiringRestart & AddonManager.OP_NEEDS_RESTART_ENABLE) - return gStrings.ext.GetStringFromName("enableAddonRestartRequiredTooltip"); - return gStrings.ext.GetStringFromName("enableAddonTooltip"); - } - }, - - cmd_disableItem: { - isEnabled: function(aAddon) { - if (!aAddon) - return false; - let addonType = AddonManager.addonTypes[aAddon.type]; - return (!(addonType.flags & AddonManager.TYPE_SUPPORTS_ASK_TO_ACTIVATE) && - hasPermission(aAddon, "disable")); - }, - doCommand: function(aAddon) { - aAddon.userDisabled = true; - }, - getTooltip: function(aAddon) { - if (!aAddon) - return ""; - if (aAddon.operationsRequiringRestart & AddonManager.OP_NEEDS_RESTART_DISABLE) - return gStrings.ext.GetStringFromName("disableAddonRestartRequiredTooltip"); - return gStrings.ext.GetStringFromName("disableAddonTooltip"); - } - }, - - cmd_installItem: { - isEnabled: function(aAddon) { - if (!aAddon) - return false; - return aAddon.install && aAddon.install.state == AddonManager.STATE_AVAILABLE; - }, - doCommand: function(aAddon) { - function doInstall() { - gViewController.currentViewObj.getListItemForID(aAddon.id)._installStatus.installRemote(); - } - - if (gViewController.currentViewObj == gDetailView) - gViewController.popState(doInstall); - else - doInstall(); - } - }, - - cmd_purchaseItem: { - isEnabled: function(aAddon) { - if (!aAddon) - return false; - return !!aAddon.purchaseURL; - }, - doCommand: function(aAddon) { - openURL(aAddon.purchaseURL); - } - }, - - cmd_uninstallItem: { - isEnabled: function(aAddon) { - if (!aAddon) - return false; - return hasPermission(aAddon, "uninstall"); - }, - doCommand: function(aAddon) { - if (gViewController.currentViewObj != gDetailView) { - aAddon.uninstall(); - return; - } - - gViewController.popState(function() { - gViewController.currentViewObj.getListItemForID(aAddon.id).uninstall(); - }); - }, - getTooltip: function(aAddon) { - if (!aAddon) - return ""; - if (aAddon.operationsRequiringRestart & AddonManager.OP_NEEDS_RESTART_UNINSTALL) - return gStrings.ext.GetStringFromName("uninstallAddonRestartRequiredTooltip"); - return gStrings.ext.GetStringFromName("uninstallAddonTooltip"); - } - }, - - cmd_cancelUninstallItem: { - isEnabled: function(aAddon) { - if (!aAddon) - return false; - return isPending(aAddon, "uninstall"); - }, - doCommand: function(aAddon) { - aAddon.cancelUninstall(); - } - }, - - cmd_installFromFile: { - isEnabled: function() { - return true; - }, - doCommand: function() { - const nsIFilePicker = Ci.nsIFilePicker; - var fp = Cc["@mozilla.org/filepicker;1"] - .createInstance(nsIFilePicker); - fp.init(window, - gStrings.ext.GetStringFromName("installFromFile.dialogTitle"), - nsIFilePicker.modeOpenMultiple); - try { - fp.appendFilter(gStrings.ext.GetStringFromName("installFromFile.filterName"), - "*.xpi;*.jar"); - fp.appendFilters(nsIFilePicker.filterAll); - } catch (e) { } - - if (fp.show() != nsIFilePicker.returnOK) - return; - - var files = fp.files; - var installs = []; - - function buildNextInstall() { - if (!files.hasMoreElements()) { - if (installs.length > 0) { - // Display the normal install confirmation for the installs - let webInstaller = Cc["@mozilla.org/addons/web-install-listener;1"]. - getService(Ci.amIWebInstallListener); - webInstaller.onWebInstallRequested(getBrowserElement(), - document.documentURIObject, - installs); - } - return; - } - - var file = files.getNext(); - AddonManager.getInstallForFile(file, function(aInstall) { - installs.push(aInstall); - buildNextInstall(); - }); - } - - buildNextInstall(); - } - }, - - cmd_debugAddons: { - isEnabled: function() { - return true; - }, - doCommand: function() { - let mainWindow = getMainWindow(); - if ("switchToTabHavingURI" in mainWindow) { - mainWindow.switchToTabHavingURI("about:debugging#addons", true); - } - }, - }, - - cmd_cancelOperation: { - isEnabled: function(aAddon) { - if (!aAddon) - return false; - return aAddon.pendingOperations != AddonManager.PENDING_NONE; - }, - doCommand: function(aAddon) { - if (isPending(aAddon, "install")) { - aAddon.install.cancel(); - } else if (isPending(aAddon, "upgrade")) { - aAddon.pendingUpgrade.install.cancel(); - } else if (isPending(aAddon, "uninstall")) { - aAddon.cancelUninstall(); - } else if (isPending(aAddon, "enable")) { - aAddon.userDisabled = true; - } else if (isPending(aAddon, "disable")) { - aAddon.userDisabled = false; - } - } - }, - - cmd_contribute: { - isEnabled: function(aAddon) { - if (!aAddon) - return false; - return ("contributionURL" in aAddon && aAddon.contributionURL); - }, - doCommand: function(aAddon) { - openURL(aAddon.contributionURL); - } - }, - - cmd_askToActivateItem: { - isEnabled: function(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: function(aAddon) { - aAddon.userDisabled = AddonManager.STATE_ASK_TO_ACTIVATE; - } - }, - - cmd_alwaysActivateItem: { - isEnabled: function(aAddon) { - if (!aAddon) - return false; - let addonType = AddonManager.addonTypes[aAddon.type]; - return ((addonType.flags & AddonManager.TYPE_SUPPORTS_ASK_TO_ACTIVATE) && - hasPermission(aAddon, "enable")); - }, - doCommand: function(aAddon) { - aAddon.userDisabled = false; - } - }, - - cmd_neverActivateItem: { - isEnabled: function(aAddon) { - if (!aAddon) - return false; - let addonType = AddonManager.addonTypes[aAddon.type]; - return ((addonType.flags & AddonManager.TYPE_SUPPORTS_ASK_TO_ACTIVATE) && - hasPermission(aAddon, "disable")); - }, - doCommand: function(aAddon) { - aAddon.userDisabled = true; - } - }, - - cmd_showUnsignedExtensions: { - isEnabled: function() { - return true; - }, - doCommand: function() { - gViewController.loadView("addons://list/extension?unsigned=true"); - }, - }, - - cmd_showAllExtensions: { - isEnabled: function() { - return true; - }, - doCommand: function() { - gViewController.loadView("addons://list/extension"); - }, - }, - }, - - supportsCommand: function(aCommand) { - return (aCommand in this.commands); - }, - - isCommandEnabled: function(aCommand) { - if (!this.supportsCommand(aCommand)) - return false; - var addon = this.currentViewObj.getSelectedAddon(); - return this.commands[aCommand].isEnabled(addon); - }, - - updateCommands: function() { - // wait until the view is initialized - if (!this.currentViewObj) - return; - var addon = this.currentViewObj.getSelectedAddon(); - for (let commandId in this.commands) - this.updateCommand(commandId, addon); - }, - - updateCommand: function(aCommandId, aAddon) { - if (typeof aAddon == "undefined") - aAddon = this.currentViewObj.getSelectedAddon(); - var cmd = this.commands[aCommandId]; - var cmdElt = document.getElementById(aCommandId); - cmdElt.setAttribute("disabled", !cmd.isEnabled(aAddon)); - if ("getTooltip" in cmd) { - let tooltip = cmd.getTooltip(aAddon); - if (tooltip) - cmdElt.setAttribute("tooltiptext", tooltip); - else - cmdElt.removeAttribute("tooltiptext"); - } - }, - - doCommand: function(aCommand, aAddon) { - if (!this.supportsCommand(aCommand)) - return; - var cmd = this.commands[aCommand]; - if (!aAddon) - aAddon = this.currentViewObj.getSelectedAddon(); - if (!cmd.isEnabled(aAddon)) - return; - cmd.doCommand(aAddon); - }, - - onEvent: function() {} -}; - -function hasInlineOptions(aAddon) { - return (aAddon.optionsType == AddonManager.OPTIONS_TYPE_INLINE || - aAddon.optionsType == AddonManager.OPTIONS_TYPE_INLINE_BROWSER || - aAddon.optionsType == AddonManager.OPTIONS_TYPE_INLINE_INFO); -} - -function openOptionsInTab(optionsURL) { - let mainWindow = getMainWindow(); - if ("switchToTabHavingURI" in mainWindow) { - mainWindow.switchToTabHavingURI(optionsURL, true); - return true; - } - return false; -} - -function formatDate(aDate) { - const locale = Cc["@mozilla.org/chrome/chrome-registry;1"] - .getService(Ci.nsIXULChromeRegistry) - .getSelectedLocale("global", true); - const dtOptions = { year: 'numeric', month: 'long', day: 'numeric' }; - return aDate.toLocaleDateString(locale, 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, aIsRemote) { - let item = document.createElement("richlistitem"); - - item.setAttribute("class", "addon addon-view"); - item.setAttribute("name", aObj.name); - item.setAttribute("type", aObj.type); - item.setAttribute("remote", !!aIsRemote); - - 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 = ["size", "relevancescore", "purchaseAmount"]; - - // 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)); - } - - 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.indexOf(sortBy) != -1) - aSortFuncs[i] = dateCompare; - else if (NUMERIC_FIELDS.indexOf(sortBy) != -1) - aSortFuncs[i] = numberCompare; - } - - - 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.slice(aList.childNodes, 0); - sortElements(elements, [aSortBy], aAscending); - - while (aList.listChild) - aList.removeChild(aList.lastChild); - - for (let element of elements) - aList.appendChild(element); -} - -function getAddonsAndInstalls(aType, aCallback) { - let addons = null, installs = null; - let types = (aType != null) ? [aType] : null; - - AddonManager.getAddonsByTypes(types, function(aAddonsList) { - addons = aAddonsList.filter(a => !a.hidden); - if (installs != null) - aCallback(addons, installs); - }); - - AddonManager.getInstallsByTypes(types, function(aInstallsList) { - // skip over upgrade installs and non-active installs - installs = aInstallsList.filter(function(aInstall) { - return !(aInstall.existingAddon || - aInstall.state == AddonManager.STATE_AVAILABLE); - }); - - 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" && - !(listitem.opRequiresRestart("UNINSTALL"))) - items.push(listitem.mAddon); - listitem = listitem.nextSibling; - } - - for (let addon of items) - addon.uninstall(); -} - -var gCategories = { - node: null, - _search: null, - - initialize: function() { - this.node = document.getElementById("categories"); - this._search = this.get("addons://search/"); - - var types = AddonManager.addonTypes; - for (var type in types) - this.onTypeAdded(types[type]); - - AddonManager.addTypeListener(this); - - try { - this.node.value = Services.prefs.getCharPref(PREF_UI_LASTCATEGORY); - } catch (e) { } - - // If there was no last view or no existing category matched the last view - // then the list will default to selecting the search category and we never - // want to show that as the first view so switch to the default category - if (!this.node.selectedItem || this.node.selectedItem == this._search) - this.node.value = gViewDefault; - - this.node.addEventListener("select", () => { - this.maybeHideSearch(); - gViewController.loadView(this.node.selectedItem.value); - }, false); - - this.node.addEventListener("click", (aEvent) => { - var selectedItem = this.node.selectedItem; - if (aEvent.target.localName == "richlistitem" && - aEvent.target == selectedItem) { - var viewId = selectedItem.value; - - if (gViewController.parseViewId(viewId).type == "search") { - viewId += encodeURIComponent(gHeader.searchQuery); - } - - gViewController.loadView(viewId); - } - }, false); - }, - - shutdown: function() { - AddonManager.removeTypeListener(this); - }, - - _insertCategory: function(aId, aName, aView, aPriority, aStartHidden) { - // If this category already exists then don't re-add it - if (document.getElementById("category-" + aId)) - return; - - var category = document.createElement("richlistitem"); - category.setAttribute("id", "category-" + aId); - category.setAttribute("value", aView); - category.setAttribute("class", "category"); - category.setAttribute("name", aName); - category.setAttribute("tooltiptext", aName); - category.setAttribute("priority", aPriority); - category.setAttribute("hidden", aStartHidden); - - var node; - for (node of this.node.children) { - var nodePriority = parseInt(node.getAttribute("priority")); - // If the new type's priority is higher than this one then this is the - // insertion point - if (aPriority < nodePriority) - break; - // If the new type's priority is lower than this one then this is isn't - // the insertion point - if (aPriority > nodePriority) - continue; - // If the priorities are equal and the new type's name is earlier - // alphabetically then this is the insertion point - if (String.localeCompare(aName, node.getAttribute("name")) < 0) - break; - } - - this.node.insertBefore(category, node); - }, - - _removeCategory: function(aId) { - var category = document.getElementById("category-" + aId); - if (!category) - return; - - // If this category is currently selected then switch to the default view - if (this.node.selectedItem == category) - gViewController.replaceView(gViewDefault); - - this.node.removeChild(category); - }, - - onTypeAdded: function(aType) { - // Ignore types that we don't have a view object for - if (!(aType.viewType in gViewController.viewObjects)) - return; - - var aViewId = "addons://" + aType.viewType + "/" + aType.id; - - var startHidden = false; - if (aType.flags & AddonManager.TYPE_UI_HIDE_EMPTY) { - var prefName = PREF_UI_TYPE_HIDDEN.replace("%TYPE%", aType.id); - try { - startHidden = Services.prefs.getBoolPref(prefName); - } - catch (e) { - // Default to hidden - startHidden = true; - } - - gPendingInitializations++; - getAddonsAndInstalls(aType.id, (aAddonsList, aInstallsList) => { - var hidden = (aAddonsList.length == 0 && aInstallsList.length == 0); - var item = this.get(aViewId); - - // Don't load view that is becoming hidden - if (hidden && aViewId == gViewController.currentViewId) - gViewController.loadView(gViewDefault); - - item.hidden = hidden; - Services.prefs.setBoolPref(prefName, hidden); - - if (aAddonsList.length > 0 || aInstallsList.length > 0) { - notifyInitialized(); - return; - } - - gEventManager.registerInstallListener({ - onDownloadStarted: function(aInstall) { - this._maybeShowCategory(aInstall); - }, - - onInstallStarted: function(aInstall) { - this._maybeShowCategory(aInstall); - }, - - onInstallEnded: function(aInstall, aAddon) { - this._maybeShowCategory(aAddon); - }, - - onExternalInstall: function(aAddon, aExistingAddon, aRequiresRestart) { - this._maybeShowCategory(aAddon); - }, - - _maybeShowCategory: aAddon => { - if (aType.id == aAddon.type) { - this.get(aViewId).hidden = false; - Services.prefs.setBoolPref(prefName, false); - gEventManager.unregisterInstallListener(this); - } - } - }); - - notifyInitialized(); - }); - } - - this._insertCategory(aType.id, aType.name, aViewId, aType.uiPriority, - startHidden); - }, - - onTypeRemoved: function(aType) { - this._removeCategory(aType.id); - }, - - get selected() { - return this.node.selectedItem ? this.node.selectedItem.value : null; - }, - - select: function(aId, aPreviousView) { - var view = gViewController.parseViewId(aId); - if (view.type == "detail" && aPreviousView) { - aId = aPreviousView; - view = gViewController.parseViewId(aPreviousView); - } - aId = aId.replace(/\?.*/, ""); - - Services.prefs.setCharPref(PREF_UI_LASTCATEGORY, aId); - - if (this.node.selectedItem && - this.node.selectedItem.value == aId) { - this.node.selectedItem.hidden = false; - this.node.selectedItem.disabled = false; - return; - } - - var item; - if (view.type == "search") - item = this._search; - else - item = this.get(aId); - - if (item) { - item.hidden = false; - item.disabled = false; - this.node.suppressOnSelect = true; - this.node.selectedItem = item; - this.node.suppressOnSelect = false; - this.node.ensureElementIsVisible(item); - - this.maybeHideSearch(); - } - }, - - get: function(aId) { - var items = document.getElementsByAttribute("value", aId); - if (items.length) - return items[0]; - return null; - }, - - setBadge: function(aId, aCount) { - let item = this.get(aId); - if (item) - item.badgeCount = aCount; - }, - - maybeHideSearch: function() { - var view = gViewController.parseViewId(this.node.selectedItem.value); - this._search.disabled = view.type != "search"; - } -}; - - -var gHeader = { - _search: null, - _dest: "", - - initialize: function() { - this._search = document.getElementById("header-search"); - - this._search.addEventListener("command", function(aEvent) { - var query = aEvent.target.value; - if (query.length == 0) - return; - - gViewController.loadView("addons://search/" + encodeURIComponent(query)); - }, false); - - function updateNavButtonVisibility() { - var shouldShow = gHeader.shouldShowNavButtons; - document.getElementById("back-btn").hidden = !shouldShow; - document.getElementById("forward-btn").hidden = !shouldShow; - } - - window.addEventListener("focus", function(aEvent) { - if (aEvent.target == window) - updateNavButtonVisibility(); - }, false); - - updateNavButtonVisibility(); - }, - - focusSearchBox: function() { - this._search.focus(); - }, - - onKeyPress: function(aEvent) { - if (String.fromCharCode(aEvent.charCode) == "/") { - this.focusSearchBox(); - return; - } - }, - - get shouldShowNavButtons() { - var docshellItem = window.QueryInterface(Ci.nsIInterfaceRequestor) - .getInterface(Ci.nsIWebNavigation) - .QueryInterface(Ci.nsIDocShellTreeItem); - - // If there is no outer frame then make the buttons visible - if (docshellItem.rootTreeItem == docshellItem) - return true; - - var outerWin = docshellItem.rootTreeItem.QueryInterface(Ci.nsIInterfaceRequestor) - .getInterface(Ci.nsIDOMWindow); - var outerDoc = outerWin.document; - var node = outerDoc.getElementById("back-button"); - // If the outer frame has no back-button then make the buttons visible - if (!node) - return true; - - // If the back-button or any of its parents are hidden then make the buttons - // visible - while (node != outerDoc) { - var style = outerWin.getComputedStyle(node, ""); - if (style.display == "none") - return true; - if (style.visibility != "visible") - return true; - node = node.parentNode; - } - - return false; - }, - - get searchQuery() { - return this._search.value; - }, - - set searchQuery(aQuery) { - this._search.value = aQuery; - }, -}; - - -var gDiscoverView = { - node: null, - enabled: true, - // Set to true after the view is first shown. If initialization completes - // after this then it must also load the discover homepage - loaded: false, - _browser: null, - _loading: null, - _error: null, - homepageURL: null, - _loadListeners: [], - hideHeader: true, - - initialize: function() { - this.enabled = isDiscoverEnabled(); - if (!this.enabled) { - gCategories.get("addons://discover/").hidden = true; - return; - } - - this.node = document.getElementById("discover-view"); - this._loading = document.getElementById("discover-loading"); - this._error = document.getElementById("discover-error"); - this._browser = document.getElementById("discover-browser"); - - let compatMode = "normal"; - if (!AddonManager.checkCompatibility) - compatMode = "ignore"; - else if (AddonManager.strictCompatibility) - compatMode = "strict"; - - var url = Services.prefs.getCharPref(PREF_DISCOVERURL); - url = url.replace("%COMPATIBILITY_MODE%", compatMode); - url = Services.urlFormatter.formatURL(url); - - let setURL = (aURL) => { - try { - this.homepageURL = Services.io.newURI(aURL, null, null); - } catch (e) { - this.showError(); - notifyInitialized(); - return; - } - - this._browser.homePage = this.homepageURL.spec; - this._browser.addProgressListener(this); - - if (this.loaded) - this._loadURL(this.homepageURL.spec, false, notifyInitialized); - else - notifyInitialized(); - } - - if (Services.prefs.getBoolPref(PREF_GETADDONS_CACHE_ENABLED) == false) { - setURL(url); - return; - } - - gPendingInitializations++; - AddonManager.getAllAddons(function(aAddons) { - var list = {}; - for (let addon of aAddons) { - var prefName = PREF_GETADDONS_CACHE_ID_ENABLED.replace("%ID%", - addon.id); - try { - if (!Services.prefs.getBoolPref(prefName)) - continue; - } catch (e) { } - list[addon.id] = { - name: addon.name, - version: addon.version, - type: addon.type, - userDisabled: addon.userDisabled, - isCompatible: addon.isCompatible, - isBlocklisted: addon.blocklistState == Ci.nsIBlocklistService.STATE_BLOCKED - } - } - - setURL(url + "#" + JSON.stringify(list)); - }); - }, - - destroy: function() { - try { - this._browser.removeProgressListener(this); - } - catch (e) { - // Ignore the case when the listener wasn't already registered - } - }, - - show: function(aParam, aRequest, aState, aIsRefresh) { - gViewController.updateCommands(); - - // If we're being told to load a specific URL then just do that - if (aState && "url" in aState) { - this.loaded = true; - this._loadURL(aState.url); - } - - // If the view has loaded before and still at the homepage (if refreshing), - // and the error page is not visible then there is nothing else to do - if (this.loaded && this.node.selectedPanel != this._error && - (!aIsRefresh || (this._browser.currentURI && - this._browser.currentURI.spec == this._browser.homePage))) { - gViewController.notifyViewChanged(); - return; - } - - this.loaded = true; - - // No homepage means initialization isn't complete, the browser will get - // loaded once initialization is complete - if (!this.homepageURL) { - this._loadListeners.push(gViewController.notifyViewChanged.bind(gViewController)); - return; - } - - this._loadURL(this.homepageURL.spec, aIsRefresh, - gViewController.notifyViewChanged.bind(gViewController)); - }, - - canRefresh: function() { - if (this._browser.currentURI && - this._browser.currentURI.spec == this._browser.homePage) - return false; - return true; - }, - - refresh: function(aParam, aRequest, aState) { - this.show(aParam, aRequest, aState, true); - }, - - hide: function() { }, - - showError: function() { - this.node.selectedPanel = this._error; - }, - - _loadURL: function(aURL, aKeepHistory, aCallback) { - if (this._browser.currentURI.spec == aURL) { - if (aCallback) - aCallback(); - return; - } - - if (aCallback) - this._loadListeners.push(aCallback); - - var flags = 0; - if (!aKeepHistory) - flags |= Ci.nsIWebNavigation.LOAD_FLAGS_REPLACE_HISTORY; - - this._browser.loadURIWithFlags(aURL, flags); - }, - - onLocationChange: function(aWebProgress, aRequest, aLocation, aFlags) { - // Ignore the about:blank load - if (aLocation.spec == "about:blank") - return; - - // When using the real session history the inner-frame will update the - // session history automatically, if using the fake history though it must - // be manually updated - if (gHistory == FakeHistory) { - var docshell = aWebProgress.QueryInterface(Ci.nsIDocShell); - - var state = { - view: "addons://discover/", - url: aLocation.spec - }; - - var replaceHistory = Ci.nsIWebNavigation.LOAD_FLAGS_REPLACE_HISTORY << 16; - if (docshell.loadType & replaceHistory) - gHistory.replaceState(state); - else - gHistory.pushState(state); - gViewController.lastHistoryIndex = gHistory.index; - } - - gViewController.updateCommands(); - - // If the hostname is the same as the new location's host and either the - // default scheme is insecure or the new location is secure then continue - // with the load - if (aLocation.host == this.homepageURL.host && - (!this.homepageURL.schemeIs("https") || aLocation.schemeIs("https"))) - return; - - // Canceling the request will send an error to onStateChange which will show - // the error page - aRequest.cancel(Components.results.NS_BINDING_ABORTED); - }, - - onSecurityChange: function(aWebProgress, aRequest, aState) { - // Don't care about security if the page is not https - if (!this.homepageURL.schemeIs("https")) - return; - - // If the request was secure then it is ok - if (aState & Ci.nsIWebProgressListener.STATE_IS_SECURE) - return; - - // Canceling the request will send an error to onStateChange which will show - // the error page - aRequest.cancel(Components.results.NS_BINDING_ABORTED); - }, - - onStateChange: function(aWebProgress, aRequest, aStateFlags, aStatus) { - let transferStart = Ci.nsIWebProgressListener.STATE_IS_DOCUMENT | - Ci.nsIWebProgressListener.STATE_IS_REQUEST | - Ci.nsIWebProgressListener.STATE_TRANSFERRING; - // Once transferring begins show the content - if ((aStateFlags & transferStart) === transferStart) - this.node.selectedPanel = this._browser; - - // Only care about the network events - if (!(aStateFlags & (Ci.nsIWebProgressListener.STATE_IS_NETWORK))) - return; - - // If this is the start of network activity then show the loading page - if (aStateFlags & (Ci.nsIWebProgressListener.STATE_START)) - this.node.selectedPanel = this._loading; - - // Ignore anything except stop events - if (!(aStateFlags & (Ci.nsIWebProgressListener.STATE_STOP))) - return; - - // Consider the successful load of about:blank as still loading - if (aRequest instanceof Ci.nsIChannel && aRequest.URI.spec == "about:blank") - return; - - // If there was an error loading the page or the new hostname is not the - // same as the default hostname or the default scheme is secure and the new - // scheme is insecure then show the error page - const NS_ERROR_PARSED_DATA_CACHED = 0x805D0021; - if (!(Components.isSuccessCode(aStatus) || aStatus == NS_ERROR_PARSED_DATA_CACHED) || - (aRequest && aRequest instanceof Ci.nsIHttpChannel && !aRequest.requestSucceeded)) { - this.showError(); - } else { - // Got a successful load, make sure the browser is visible - this.node.selectedPanel = this._browser; - gViewController.updateCommands(); - } - - var listeners = this._loadListeners; - this._loadListeners = []; - - for (let listener of listeners) - listener(); - }, - - onProgressChange: function() { }, - onStatusChange: function() { }, - - QueryInterface: XPCOMUtils.generateQI([Ci.nsIWebProgressListener, - Ci.nsISupportsWeakReference]), - - getSelectedAddon: function() { - return null; - } -}; - - -var gCachedAddons = {}; - -var gSearchView = { - node: null, - _filter: null, - _sorters: null, - _loading: null, - _listBox: null, - _emptyNotice: null, - _allResultsLink: null, - _lastQuery: null, - _lastRemoteTotal: 0, - _pendingSearches: 0, - - initialize: function() { - this.node = document.getElementById("search-view"); - this._filter = document.getElementById("search-filter-radiogroup"); - this._sorters = document.getElementById("search-sorters"); - this._sorters.handler = this; - this._loading = document.getElementById("search-loading"); - this._listBox = document.getElementById("search-list"); - this._emptyNotice = document.getElementById("search-list-empty"); - this._allResultsLink = document.getElementById("search-allresults-link"); - - if (!AddonManager.isInstallEnabled("application/x-xpinstall")) - this._filter.hidden = true; - - this._listBox.addEventListener("keydown", aEvent => { - if (aEvent.keyCode == aEvent.DOM_VK_RETURN) { - var item = this._listBox.selectedItem; - if (item) - item.showInDetailView(); - } - }, false); - - this._filter.addEventListener("command", () => this.updateView(), false); - }, - - shutdown: function() { - if (AddonRepository.isSearching) - AddonRepository.cancelSearch(); - }, - - get isSearching() { - return this._pendingSearches > 0; - }, - - show: function(aQuery, aRequest) { - gEventManager.registerInstallListener(this); - - this.showEmptyNotice(false); - this.showAllResultsLink(0); - this.showLoading(true); - this._sorters.showprice = false; - - gHeader.searchQuery = aQuery; - aQuery = aQuery.trim().toLocaleLowerCase(); - if (this._lastQuery == aQuery) { - this.updateView(); - gViewController.notifyViewChanged(); - return; - } - this._lastQuery = aQuery; - - if (AddonRepository.isSearching) - AddonRepository.cancelSearch(); - - while (this._listBox.firstChild.localName == "richlistitem") - this._listBox.removeChild(this._listBox.firstChild); - - gCachedAddons = {}; - this._pendingSearches = 2; - this._sorters.setSort("relevancescore", false); - - var elements = []; - - let createSearchResults = (aObjsList, aIsInstall, aIsRemote) => { - for (let index in aObjsList) { - let obj = aObjsList[index]; - let score = aObjsList.length - index; - if (!aIsRemote && aQuery.length > 0) { - score = this.getMatchScore(obj, aQuery); - if (score == 0) - continue; - } - - let item = createItem(obj, aIsInstall, aIsRemote); - item.setAttribute("relevancescore", score); - if (aIsRemote) { - gCachedAddons[obj.id] = obj; - if (obj.purchaseURL) - this._sorters.showprice = true; - } - - elements.push(item); - } - } - - let finishSearch = (createdCount) => { - if (elements.length > 0) { - sortElements(elements, [this._sorters.sortBy], this._sorters.ascending); - for (let element of elements) - this._listBox.insertBefore(element, this._listBox.lastChild); - this.updateListAttributes(); - } - - this._pendingSearches--; - this.updateView(); - - if (!this.isSearching) - gViewController.notifyViewChanged(); - } - - getAddonsAndInstalls(null, function(aAddons, aInstalls) { - if (gViewController && aRequest != gViewController.currentViewRequest) - return; - - createSearchResults(aAddons, false, false); - createSearchResults(aInstalls, true, false); - finishSearch(); - }); - - var maxRemoteResults = 0; - try { - maxRemoteResults = Services.prefs.getIntPref(PREF_MAXRESULTS); - } catch (e) {} - - if (maxRemoteResults <= 0) { - finishSearch(0); - return; - } - - AddonRepository.searchAddons(aQuery, maxRemoteResults, { - searchFailed: () => { - if (gViewController && aRequest != gViewController.currentViewRequest) - return; - - this._lastRemoteTotal = 0; - - // XXXunf Better handling of AMO search failure. See bug 579502 - finishSearch(0); // Silently fail - }, - - searchSucceeded: (aAddonsList, aAddonCount, aTotalResults) => { - if (gViewController && aRequest != gViewController.currentViewRequest) - return; - - if (aTotalResults > maxRemoteResults) - this._lastRemoteTotal = aTotalResults; - else - this._lastRemoteTotal = 0; - - var createdCount = createSearchResults(aAddonsList, false, true); - finishSearch(createdCount); - } - }); - }, - - showLoading: function(aLoading) { - this._loading.hidden = !aLoading; - this._listBox.hidden = aLoading; - }, - - updateView: function() { - var showLocal = this._filter.value == "local"; - - if (!showLocal && !AddonManager.isInstallEnabled("application/x-xpinstall")) - showLocal = true; - - this._listBox.setAttribute("local", showLocal); - this._listBox.setAttribute("remote", !showLocal); - - this.showLoading(this.isSearching && !showLocal); - if (!this.isSearching) { - var isEmpty = true; - var results = this._listBox.getElementsByTagName("richlistitem"); - for (let result of results) { - var isRemote = (result.getAttribute("remote") == "true"); - if ((isRemote && !showLocal) || (!isRemote && showLocal)) { - isEmpty = false; - break; - } - } - - this.showEmptyNotice(isEmpty); - this.showAllResultsLink(this._lastRemoteTotal); - } - - gViewController.updateCommands(); - }, - - hide: function() { - gEventManager.unregisterInstallListener(this); - doPendingUninstalls(this._listBox); - }, - - getMatchScore: function(aObj, aQuery) { - var score = 0; - score += this.calculateMatchScore(aObj.name, aQuery, - SEARCH_SCORE_MULTIPLIER_NAME); - score += this.calculateMatchScore(aObj.description, aQuery, - SEARCH_SCORE_MULTIPLIER_DESCRIPTION); - return score; - }, - - calculateMatchScore: function(aStr, aQuery, aMultiplier) { - var score = 0; - if (!aStr || aQuery.length == 0) - return score; - - aStr = aStr.trim().toLocaleLowerCase(); - var haystack = aStr.split(/\s+/); - var needles = aQuery.split(/\s+/); - - for (let needle of needles) { - for (let hay of haystack) { - if (hay == needle) { - // matching whole words is best - score += SEARCH_SCORE_MATCH_WHOLEWORD; - } else { - let i = hay.indexOf(needle); - if (i == 0) // matching on word boundries is also good - score += SEARCH_SCORE_MATCH_WORDBOUNDRY; - else if (i > 0) // substring matches not so good - score += SEARCH_SCORE_MATCH_SUBSTRING; - } - } - } - - // give progressively higher score for longer queries, since longer queries - // are more likely to be unique and therefore more relevant. - if (needles.length > 1 && aStr.indexOf(aQuery) != -1) - score += needles.length; - - return score * aMultiplier; - }, - - showEmptyNotice: function(aShow) { - this._emptyNotice.hidden = !aShow; - this._listBox.hidden = aShow; - }, - - showAllResultsLink: function(aTotalResults) { - if (aTotalResults == 0) { - this._allResultsLink.hidden = true; - return; - } - - var linkStr = gStrings.ext.GetStringFromName("showAllSearchResults"); - linkStr = PluralForm.get(aTotalResults, linkStr); - linkStr = linkStr.replace("#1", aTotalResults); - this._allResultsLink.setAttribute("value", linkStr); - - this._allResultsLink.setAttribute("href", - AddonRepository.getSearchURL(this._lastQuery)); - this._allResultsLink.hidden = false; - }, - - updateListAttributes: function() { - var item = this._listBox.querySelector("richlistitem[remote='true'][first]"); - if (item) - item.removeAttribute("first"); - item = this._listBox.querySelector("richlistitem[remote='true'][last]"); - if (item) - item.removeAttribute("last"); - var items = this._listBox.querySelectorAll("richlistitem[remote='true']"); - if (items.length > 0) { - items[0].setAttribute("first", true); - items[items.length - 1].setAttribute("last", true); - } - - item = this._listBox.querySelector("richlistitem:not([remote='true'])[first]"); - if (item) - item.removeAttribute("first"); - item = this._listBox.querySelector("richlistitem:not([remote='true'])[last]"); - if (item) - item.removeAttribute("last"); - items = this._listBox.querySelectorAll("richlistitem:not([remote='true'])"); - if (items.length > 0) { - items[0].setAttribute("first", true); - items[items.length - 1].setAttribute("last", true); - } - - }, - - onSortChanged: function(aSortBy, aAscending) { - var footer = this._listBox.lastChild; - this._listBox.removeChild(footer); - - sortList(this._listBox, aSortBy, aAscending); - this.updateListAttributes(); - - this._listBox.appendChild(footer); - }, - - onDownloadCancelled: function(aInstall) { - this.removeInstall(aInstall); - }, - - onInstallCancelled: function(aInstall) { - this.removeInstall(aInstall); - }, - - removeInstall: function(aInstall) { - for (let item of this._listBox.childNodes) { - if (item.mInstall == aInstall) { - this._listBox.removeChild(item); - return; - } - } - }, - - getSelectedAddon: function() { - var item = this._listBox.selectedItem; - if (item) - return item.mAddon; - return null; - }, - - getListItemForID: function(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, - - initialize: function() { - 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(); - } - }, false); - - document.getElementById("signing-learn-more").setAttribute("href", - Services.urlFormatter.formatURLPref("app.support.baseURL") + "unsigned-addons"); - - 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; - } - - // To-Do: remove deprecation notice content. - document.getElementById("plugindeprecation-notice").hidden = true; - }, - - show: function(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); - - while (this._listBox.itemCount > 0) - this._listBox.removeItemAt(0); - - if (aType == "plugin") { - navigator.plugins.refresh(false); - } - - getAddonsAndInstalls(aType, (aAddonsList, aInstallsList) => { - if (gViewController && aRequest != gViewController.currentViewRequest) - return; - - 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) { - sortElements(elements, ["uiState", "name"], true); - for (let element of elements) - this._listBox.appendChild(element); - } - - this.filterDisabledUnsigned(showOnlyDisabledUnsigned); - - gEventManager.registerInstallListener(this); - gViewController.updateCommands(); - gViewController.notifyViewChanged(); - }); - }, - - hide: function() { - gEventManager.unregisterInstallListener(this); - doPendingUninstalls(this._listBox); - }, - - filterDisabledUnsigned: function(aFilter = true) { - let foundDisabledUnsigned = false; - - if (SIGNING_REQUIRED) { - for (let item of this._listBox.childNodes) { - if (!isCorrectlySigned(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: function(aShow) { - this._emptyNotice.hidden = !aShow; - this._listBox.hidden = aShow; - }, - - onSortChanged: function(aSortBy, aAscending) { - sortList(this._listBox, aSortBy, aAscending); - }, - - onExternalInstall: function(aAddon, aExistingAddon, aRequiresRestart) { - // The existing list item will take care of upgrade installs - if (aExistingAddon) - return; - - if (aAddon.hidden) - return; - - this.addItem(aAddon); - }, - - onDownloadStarted: function(aInstall) { - this.addItem(aInstall, true); - }, - - onInstallStarted: function(aInstall) { - this.addItem(aInstall, true); - }, - - onDownloadCancelled: function(aInstall) { - this.removeItem(aInstall, true); - }, - - onInstallCancelled: function(aInstall) { - this.removeItem(aInstall, true); - }, - - onInstallEnded: function(aInstall) { - // Remove any install entries for upgrades, their status will appear against - // the existing item - if (aInstall.existingAddon) - this.removeItem(aInstall, true); - }, - - addItem: function(aObj, aIsInstall) { - if (aObj.type != this._type) - return; - - if (aIsInstall && aObj.existingAddon) - 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: function(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: function() { - var item = this._listBox.selectedItem; - if (item) - return item.mAddon; - return null; - }, - - getListItemForID: function(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, - - initialize: function() { - this.node = document.getElementById("detail-view"); - - this._autoUpdate = document.getElementById("detail-autoUpdate"); - - this._autoUpdate.addEventListener("command", () => { - this._addon.applyBackgroundUpdates = this._autoUpdate.value; - }, true); - }, - - shutdown: function() { - AddonManager.removeManagerListener(this); - }, - - onUpdateModeChanged: function() { - this.onPropertyChanged(["applyBackgroundUpdates"]); - }, - - _updateView: function(aAddon, aIsRemote, aScrollToPreferences) { - AddonManager.addManagerListener(this); - this.clearLoading(); - - this._addon = aAddon; - gEventManager.registerAddonListener(this, aAddon.id); - gEventManager.registerInstallListener(this); - - this.node.setAttribute("type", aAddon.type); - - // If the search category isn't selected then make sure to select the - // correct category - if (gCategories.selected != "addons://search/") - gCategories.select("addons://list/" + aAddon.type); - - document.getElementById("detail-name").textContent = aAddon.name; - var icon = AddonManager.getPreferredIconURL(aAddon, 64, 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 screenshotbox = document.getElementById("detail-screenshot-box"); - var screenshot = document.getElementById("detail-screenshot"); - if (aAddon.screenshots && aAddon.screenshots.length > 0) { - if (aAddon.screenshots[0].thumbnailURL) { - screenshot.src = aAddon.screenshots[0].thumbnailURL; - screenshot.width = aAddon.screenshots[0].thumbnailWidth; - screenshot.height = aAddon.screenshots[0].thumbnailHeight; - } else { - screenshot.src = aAddon.screenshots[0].url; - screenshot.width = aAddon.screenshots[0].width; - screenshot.height = aAddon.screenshots[0].height; - } - screenshot.setAttribute("loading", "true"); - screenshotbox.hidden = false; - } else { - screenshotbox.hidden = true; - } - - var desc = document.getElementById("detail-desc"); - desc.textContent = aAddon.description; - - var fullDesc = document.getElementById("detail-fulldesc"); - if (aAddon.fullDescription) { - // The following is part of an awful hack to include the licenses for GMP - // plugins without having bug 624602 fixed yet, and intentionally ignores - // localisation. - if (aAddon.isGMPlugin) { - fullDesc.innerHTML = aAddon.fullDescription; - } else { - 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; - var amount = document.getElementById("detail-contrib-suggested"); - if (aAddon.contributionAmount) { - amount.value = gStrings.ext.formatStringFromName("contributionAmount2", - [aAddon.contributionAmount], - 1); - amount.hidden = false; - } else { - amount.hidden = true; - } - } else { - contributions.hidden = true; - } - - if ("purchaseURL" in aAddon && aAddon.purchaseURL) { - var purchase = document.getElementById("detail-purchase-btn"); - purchase.label = gStrings.ext.formatStringFromName("cmd.purchaseAddon.label", - [aAddon.purchaseDisplayAmount], - 1); - purchase.accesskey = gStrings.ext.GetStringFromName("cmd.purchaseAddon.accesskey"); - } - - 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 sizeRow = document.getElementById("detail-size"); - if (aAddon.size && aIsRemote) { - let [size, unit] = DownloadUtils.convertByteUnits(parseInt(aAddon.size)); - let formatted = gStrings.dl.GetStringFromName("doneSize"); - formatted = formatted.replace("#1", size).replace("#2", unit); - sizeRow.value = formatted; - } else { - sizeRow.value = null; - } - - var downloadsRow = document.getElementById("detail-downloads"); - if (aAddon.totalDownloads && aIsRemote) { - var downloads = aAddon.totalDownloads; - downloadsRow.value = downloads; - } else { - downloadsRow.value = null; - } - - var canUpdate = !aIsRemote && hasPermission(aAddon, "upgrade") && aAddon.id != AddonManager.hotfixID; - 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; - } - - document.getElementById("detail-prefs-btn").hidden = !aIsRemote && - !gViewController.commands.cmd_showItemPreferences.isEnabled(aAddon); - - var gridRows = document.querySelectorAll("#detail-grid rows row"); - let first = true; - for (let gridRow of gridRows) { - if (first && window.getComputedStyle(gridRow, null).getPropertyValue("display") != "none") { - gridRow.setAttribute("first-row", true); - first = false; - } else { - gridRow.removeAttribute("first-row"); - } - } - - this.fillSettingsRows(aScrollToPreferences, (function() { - this.updateState(); - gViewController.notifyViewChanged(); - }).bind(this)); - }, - - show: function(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); - - var view = gViewController.currentViewId; - - AddonManager.getAddonByID(aAddonId, (aAddon) => { - if (gViewController && aRequest != gViewController.currentViewRequest) - return; - - if (aAddon) { - this._updateView(aAddon, false, scrollToPreferences); - return; - } - - // Look for an add-on pending install - AddonManager.getAllInstalls(aInstalls => { - for (let install of aInstalls) { - if (install.state == AddonManager.STATE_INSTALLED && - install.addon.id == aAddonId) { - this._updateView(install.addon, false); - return; - } - } - - if (aAddonId in gCachedAddons) { - this._updateView(gCachedAddons[aAddonId], true); - 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: function() { - 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: function() { - gViewController.updateCommands(); - - var pending = this._addon.pendingOperations; - if (pending != AddonManager.PENDING_NONE) { - this.node.removeAttribute("notification"); - - pending = null; - const PENDING_OPERATIONS = ["enable", "disable", "install", "uninstall", - "upgrade"]; - for (let op of PENDING_OPERATIONS) { - if (isPending(this._addon, op)) - pending = op; - } - - this.node.setAttribute("pending", pending); - document.getElementById("detail-pending").textContent = gStrings.ext.formatStringFromName( - "details.notification." + pending, - [this._addon.name, gStrings.brandShortName], 2 - ); - } 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], 1 - ); - var errorLink = document.getElementById("detail-error-link"); - errorLink.value = gStrings.ext.GetStringFromName("details.notification.blocked.link"); - errorLink.href = this._addon.blocklistURL; - errorLink.hidden = false; - } else if (!isCorrectlySigned(this._addon) && SIGNING_REQUIRED) { - this.node.setAttribute("notification", "error"); - document.getElementById("detail-error").textContent = gStrings.ext.formatStringFromName( - "details.notification.unsignedAndDisabled", [this._addon.name, gStrings.brandShortName], 2 - ); - let errorLink = document.getElementById("detail-error-link"); - errorLink.value = gStrings.ext.GetStringFromName("details.notification.unsigned.link"); - errorLink.href = Services.urlFormatter.formatURLPref("app.support.baseURL") + "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], 3 - ); - 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], 2 - ); - var warningLink = document.getElementById("detail-warning-link"); - warningLink.value = gStrings.ext.GetStringFromName("details.notification.unsigned.link"); - warningLink.href = Services.urlFormatter.formatURLPref("app.support.baseURL") + "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], 1 - ); - let warningLink = document.getElementById("detail-warning-link"); - warningLink.value = gStrings.ext.GetStringFromName("details.notification.softblocked.link"); - warningLink.href = this._addon.blocklistURL; - 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], 1 - ); - let warningLink = document.getElementById("detail-warning-link"); - warningLink.value = gStrings.ext.GetStringFromName("details.notification.outdated.link"); - warningLink.href = this._addon.blocklistURL; - 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], 1 - ); - let errorLink = document.getElementById("detail-error-link"); - errorLink.value = gStrings.ext.GetStringFromName("details.notification.vulnerableUpdatable.link"); - errorLink.href = this._addon.blocklistURL; - 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], 1 - ); - let errorLink = document.getElementById("detail-error-link"); - errorLink.value = gStrings.ext.GetStringFromName("details.notification.vulnerableNoUpdate.link"); - errorLink.href = this._addon.blocklistURL; - 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], 1); - } 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: function() { - if (this._loadingTimer) { - clearTimeout(this._loadingTimer); - this._loadingTimer = null; - } - - this.node.removeAttribute("loading-extended"); - }, - - emptySettingsRows: function() { - var lastRow = document.getElementById("detail-downloads"); - var rows = lastRow.parentNode; - while (lastRow.nextSibling) - rows.removeChild(rows.lastChild); - }, - - fillSettingsRows: function(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 viewChangedEventListener() { - gDetailView.node.removeEventListener("ViewChanged", viewChangedEventListener); - callback(); - }); - } 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(); - }); - } - - // This function removes and returns the text content of aNode without - // removing any child elements. Removing the text nodes ensures any XBL - // bindings apply properly. - function stripTextNodes(aNode) { - var text = ''; - for (var i = 0; i < aNode.childNodes.length; i++) { - if (aNode.childNodes[i].nodeType != document.ELEMENT_NODE) { - text += aNode.childNodes[i].textContent; - aNode.removeChild(aNode.childNodes[i--]); - } else { - text += stripTextNodes(aNode.childNodes[i]); - } - } - return text; - } - - var rows = document.getElementById("detail-downloads").parentNode; - - try { - if (this._addon.optionsType == AddonManager.OPTIONS_TYPE_INLINE_BROWSER) { - whenViewLoaded(() => { - this.createOptionsBrowser(rows).then(browser => { - // 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 viewChangedEventListener() { - document.removeEventListener("ViewChanged", viewChangedEventListener); - browser.remove(); - }); - - finish(browser); - }); - }); - - if (aCallback) - aCallback(); - } else { - var xhr = new XMLHttpRequest(); - xhr.open("GET", this._addon.optionsURL, true); - xhr.responseType = "xml"; - xhr.onload = (function() { - var xml = xhr.responseXML; - var settings = xml.querySelectorAll(":root > setting"); - - var firstSetting = null; - for (var setting of settings) { - - var desc = stripTextNodes(setting).trim(); - if (!setting.hasAttribute("desc")) - setting.setAttribute("desc", desc); - - var type = setting.getAttribute("type"); - if (type == "file" || type == "directory") - setting.setAttribute("fullpath", "true"); - - setting = document.importNode(setting, true); - var style = setting.getAttribute("style"); - if (style) { - setting.removeAttribute("style"); - setting.setAttribute("style", style); - } - - rows.appendChild(setting); - var visible = window.getComputedStyle(setting, null).getPropertyValue("display") != "none"; - if (!firstSetting && visible) { - setting.setAttribute("first-row", true); - firstSetting = setting; - } - } - - finish(firstSetting); - - if (aCallback) - aCallback(); - }).bind(this); - xhr.onerror = function(aEvent) { - Cu.reportError("Error " + aEvent.target.status + - " occurred while receiving " + this._addon.optionsURL); - if (aCallback) - aCallback(); - }; - xhr.send(); - } - } catch (e) { - Cu.reportError(e); - if (aCallback) - aCallback(); - } - }, - - scrollToPreferencesRows: function() { - // 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.boxObject.y; - top -= parseInt(window.getComputedStyle(firstRow, null).getPropertyValue("margin-top")); - - let detailViewBoxObject = gDetailView.node.boxObject; - top -= detailViewBoxObject.y; - - detailViewBoxObject.scrollTo(0, top); - } - }, - - createOptionsBrowser: function(parentNode) { - let browser = document.createElement("browser"); - browser.setAttribute("type", "content"); - browser.setAttribute("disableglobalhistory", "true"); - browser.setAttribute("class", "inline-options-browser"); - - return new Promise((resolve, reject) => { - let messageListener = { - receiveMessage({name, data}) { - if (name === "Extension:BrowserResized") - browser.style.height = `${data.height}px`; - else if (name === "Extension:BrowserContentLoaded") - resolve(browser); - }, - }; - - let onload = () => { - browser.removeEventListener("load", onload, true); - - let mm = new FakeFrameMessageManager(browser); - mm.loadFrameScript("chrome://extensions/content/ext-browser-content.js", - false); - mm.addMessageListener("Extension:BrowserContentLoaded", messageListener); - mm.addMessageListener("Extension:BrowserResized", messageListener); - mm.sendAsyncMessage("Extension:InitBrowser", {fixedWidth: true}); - - browser.setAttribute("src", this._addon.optionsURL); - }; - browser.addEventListener("load", onload, true); - browser.addEventListener("error", reject); - - parentNode.appendChild(browser); - }); - }, - - getSelectedAddon: function() { - return this._addon; - }, - - onEnabling: function() { - this.updateState(); - }, - - onEnabled: function() { - this.updateState(); - this.fillSettingsRows(); - }, - - onDisabling: function(aNeedsRestart) { - this.updateState(); - if (!aNeedsRestart && hasInlineOptions(this._addon)) { - Services.obs.notifyObservers(document, - AddonManager.OPTIONS_NOTIFICATION_HIDDEN, - this._addon.id); - } - }, - - onDisabled: function() { - this.updateState(); - this.emptySettingsRows(); - }, - - onUninstalling: function() { - this.updateState(); - }, - - onUninstalled: function() { - gViewController.popState(); - }, - - onOperationCancelled: function() { - this.updateState(); - }, - - onPropertyChanged: function(aProperties) { - if (aProperties.indexOf("applyBackgroundUpdates") != -1) { - this._autoUpdate.value = this._addon.applyBackgroundUpdates; - let hideFindUpdates = AddonManager.shouldAutoUpdate(this._addon); - document.getElementById("detail-findUpdates-btn").hidden = hideFindUpdates; - } - - if (aProperties.indexOf("appDisabled") != -1 || - aProperties.indexOf("signedState") != -1 || - aProperties.indexOf("userDisabled") != -1) - this.updateState(); - }, - - onExternalInstall: function(aAddon, aExistingAddon, aNeedsRestart) { - // Only care about upgrades for the currently displayed add-on - if (!aExistingAddon || aExistingAddon.id != this._addon.id) - return; - - if (!aNeedsRestart) - this._updateView(aAddon, false); - else - this.updateState(); - }, - - onInstallCancelled: function(aInstall) { - if (aInstall.addon.id == this._addon.id) - gViewController.popState(); - } -}; - - -var gUpdatesView = { - node: null, - _listBox: null, - _emptyNotice: null, - _sorters: null, - _updateSelected: null, - _categoryItem: null, - - initialize: function() { - this.node = document.getElementById("updates-view"); - this._listBox = document.getElementById("updates-list"); - this._emptyNotice = document.getElementById("updates-list-empty"); - this._sorters = document.getElementById("updates-sorters"); - this._sorters.handler = this; - - this._categoryItem = gCategories.get("addons://updates/available"); - - this._updateSelected = document.getElementById("update-selected-btn"); - this._updateSelected.addEventListener("command", function() { - gUpdatesView.installSelected(); - }, false); - - this.updateAvailableCount(true); - - AddonManager.addAddonListener(this); - AddonManager.addInstallListener(this); - }, - - shutdown: function() { - AddonManager.removeAddonListener(this); - AddonManager.removeInstallListener(this); - }, - - show: function(aType, aRequest) { - document.getElementById("empty-availableUpdates-msg").hidden = aType != "available"; - document.getElementById("empty-recentUpdates-msg").hidden = aType != "recent"; - this.showEmptyNotice(false); - - while (this._listBox.itemCount > 0) - this._listBox.removeItemAt(0); - - this.node.setAttribute("updatetype", aType); - if (aType == "recent") - this._showRecentUpdates(aRequest); - else - this._showAvailableUpdates(false, aRequest); - }, - - hide: function() { - this._updateSelected.hidden = true; - this._categoryItem.disabled = this._categoryItem.badgeCount == 0; - doPendingUninstalls(this._listBox); - }, - - _showRecentUpdates: function(aRequest) { - AddonManager.getAllAddons((aAddonsList) => { - 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, [this._sorters.sortBy], this._sorters.ascending); - for (let element of elements) - this._listBox.appendChild(element); - } - - gViewController.notifyViewChanged(); - }); - }, - - _showAvailableUpdates: function(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; - - AddonManager.getAllInstalls((aInstallsList) => { - 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.removeChild(this._listBox.firstChild); - } - - 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(); - }, false); - elements.push(item); - } - - this.showEmptyNotice(elements.length == 0); - if (elements.length > 0) { - this._updateSelected.hidden = false; - sortElements(elements, [this._sorters.sortBy], this._sorters.ascending); - for (let element of elements) - this._listBox.appendChild(element); - } - - // ensure badge count is in sync - this._categoryItem.badgeCount = this._listBox.itemCount; - - gViewController.notifyViewChanged(); - }); - }, - - showEmptyNotice: function(aShow) { - this._emptyNotice.hidden = !aShow; - this._listBox.hidden = aShow; - }, - - isManualUpdate: function(aInstall, aOnlyAvailable) { - var isManual = aInstall.existingAddon && - !AddonManager.shouldAutoUpdate(aInstall.existingAddon); - if (isManual && aOnlyAvailable) - return isInState(aInstall, "available"); - return isManual; - }, - - maybeRefresh: function() { - if (gViewController.currentViewId == "addons://updates/available") - this._showAvailableUpdates(true); - this.updateAvailableCount(); - }, - - updateAvailableCount: function(aInitializing) { - if (aInitializing) - gPendingInitializations++; - AddonManager.getAllInstalls((aInstallsList) => { - var count = aInstallsList.filter(aInstall => { - return this.isManualUpdate(aInstall, true); - }).length; - this._categoryItem.disabled = gViewController.currentViewId != "addons://updates/available" && - count == 0; - this._categoryItem.badgeCount = count; - if (aInitializing) - notifyInitialized(); - }); - }, - - maybeDisableUpdateSelected: function() { - for (let item of this._listBox.childNodes) { - if (item.includeUpdate) { - this._updateSelected.disabled = false; - return; - } - } - this._updateSelected.disabled = true; - }, - - installSelected: function() { - for (let item of this._listBox.childNodes) { - if (item.includeUpdate) - item.upgrade(); - } - - this._updateSelected.disabled = true; - }, - - getSelectedAddon: function() { - var item = this._listBox.selectedItem; - if (item) - return item.mAddon; - return null; - }, - - getListItemForID: function(aId) { - var listitem = this._listBox.firstChild; - while (listitem) { - if (listitem.mAddon.id == aId) - return listitem; - listitem = listitem.nextSibling; - } - return null; - }, - - onSortChanged: function(aSortBy, aAscending) { - sortList(this._listBox, aSortBy, aAscending); - }, - - onNewInstall: function(aInstall) { - if (!this.isManualUpdate(aInstall)) - return; - this.maybeRefresh(); - }, - - onInstallStarted: function(aInstall) { - this.updateAvailableCount(); - }, - - onInstallCancelled: function(aInstall) { - if (!this.isManualUpdate(aInstall)) - return; - this.maybeRefresh(); - }, - - onPropertyChanged: function(aAddon, aProperties) { - if (aProperties.indexOf("applyBackgroundUpdates") != -1) - this.updateAvailableCount(); - } -}; - -var gDragDrop = { - onDragOver: function(aEvent) { - var types = aEvent.dataTransfer.types; - if (types.includes("text/uri-list") || - types.includes("text/x-moz-url") || - types.includes("application/x-moz-file")) - aEvent.preventDefault(); - }, - - onDrop: function(aEvent) { - var dataTransfer = aEvent.dataTransfer; - var urls = []; - - // Convert every dropped item into a url - for (var i = 0; i < dataTransfer.mozItemCount; i++) { - var url = dataTransfer.mozGetDataAt("text/uri-list", i); - if (url) { - urls.push(url); - continue; - } - - url = dataTransfer.mozGetDataAt("text/x-moz-url", i); - if (url) { - urls.push(url.split("\n")[0]); - continue; - } - - var file = dataTransfer.mozGetDataAt("application/x-moz-file", i); - if (file) { - urls.push(Services.io.newFileURI(file).spec); - continue; - } - } - - var pos = 0; - var installs = []; - - function buildNextInstall() { - if (pos == urls.length) { - if (installs.length > 0) { - // Display the normal install confirmation for the installs - let webInstaller = Cc["@mozilla.org/addons/web-install-listener;1"]. - getService(Ci.amIWebInstallListener); - webInstaller.onWebInstallRequested(getBrowserElement(), - document.documentURIObject, - installs); - } - return; - } - - AddonManager.getInstallForURL(urls[pos++], function(aInstall) { - installs.push(aInstall); - buildNextInstall(); - }, "application/x-xpinstall"); - } - - buildNextInstall(); - - aEvent.preventDefault(); - } -}; diff --git a/toolkit/mozapps/webextensions/content/extensions.xml b/toolkit/mozapps/webextensions/content/extensions.xml deleted file mode 100644 index b49645cf0..000000000 --- a/toolkit/mozapps/webextensions/content/extensions.xml +++ /dev/null @@ -1,2008 +0,0 @@ -<?xml version="1.0"?> -<!-- This Source Code Form is subject to the terms of the Mozilla Public - - License, v. 2.0. If a copy of the MPL was not distributed with this - - file, You can obtain one at http://mozilla.org/MPL/2.0/. --> - - -<!DOCTYPE page [ -<!ENTITY % extensionsDTD SYSTEM "chrome://mozapps/locale/extensions/extensions.dtd"> -%extensionsDTD; -]> - -<!-- import-globals-from extensions.js --> - -<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"> - - - <!-- 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", Components.results.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"/> - <xul:progressmeter anonid="progress" class="progress" flex="1" - min="0" 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"> - <getter><![CDATA[ - return this._progress.value; - ]]></getter> - <setter><![CDATA[ - this._progress.value = val; - if (val == this._progress.max) - this.setAttribute("complete", true); - else - this.removeAttribute("complete"); - ]]></setter> - </property> - - <property name="maxProgress"> - <getter><![CDATA[ - return this._progress.max; - ]]></getter> - <setter><![CDATA[ - if (val == -1) { - this._progress.mode = "undetermined"; - } else { - this._progress.mode = "determined"; - this._progress.max = val; - } - this.setAttribute("mode", this._progress.mode); - ]]></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> - - - <!-- Sorters - displays and controls the sort state of a list. --> - <binding id="sorters"> - <content orient="horizontal"> - <xul:button anonid="name-btn" class="sorter" - label="&sort.name.label;" tooltiptext="&sort.name.tooltip;" - oncommand="this.parentNode._handleChange('name');"/> - <xul:button anonid="date-btn" class="sorter" - label="&sort.dateUpdated.label;" - tooltiptext="&sort.dateUpdated.tooltip;" - oncommand="this.parentNode._handleChange('updateDate');"/> - <xul:button anonid="price-btn" class="sorter" hidden="true" - label="&sort.price.label;" - tooltiptext="&sort.price.tooltip;" - oncommand="this.parentNode._handleChange('purchaseAmount');"/> - <xul:button anonid="relevance-btn" class="sorter" hidden="true" - label="&sort.relevance.label;" - tooltiptext="&sort.relevance.tooltip;" - oncommand="this.parentNode._handleChange('relevancescore');"/> - </content> - - <implementation> - <constructor><![CDATA[ - if (!this.hasAttribute("sortby")) - this.setAttribute("sortby", "name"); - - if (this.getAttribute("showrelevance") == "true") - this._btnRelevance.hidden = false; - - if (this.getAttribute("showprice") == "true") - this._btnPrice.hidden = false; - - this._refreshState(); - ]]></constructor> - - <field name="handler">null</field> - <field name="_btnName"> - document.getAnonymousElementByAttribute(this, "anonid", "name-btn"); - </field> - <field name="_btnDate"> - document.getAnonymousElementByAttribute(this, "anonid", "date-btn"); - </field> - <field name="_btnPrice"> - document.getAnonymousElementByAttribute(this, "anonid", "price-btn"); - </field> - <field name="_btnRelevance"> - document.getAnonymousElementByAttribute(this, "anonid", "relevance-btn"); - </field> - - <property name="sortBy"> - <getter><![CDATA[ - return this.getAttribute("sortby"); - ]]></getter> - <setter><![CDATA[ - if (val != this.sortBy) { - this.setAttribute("sortBy", val); - this._refreshState(); - } - ]]></setter> - </property> - - <property name="ascending"> - <getter><![CDATA[ - return (this.getAttribute("ascending") == "true"); - ]]></getter> - <setter><![CDATA[ - val = !!val; - if (val != this.ascending) { - this.setAttribute("ascending", val); - this._refreshState(); - } - ]]></setter> - </property> - - <property name="showrelevance"> - <getter><![CDATA[ - return (this.getAttribute("showrelevance") == "true"); - ]]></getter> - <setter><![CDATA[ - val = !!val; - this.setAttribute("showrelevance", val); - this._btnRelevance.hidden = !val; - ]]></setter> - </property> - - <property name="showprice"> - <getter><![CDATA[ - return (this.getAttribute("showprice") == "true"); - ]]></getter> - <setter><![CDATA[ - val = !!val; - this.setAttribute("showprice", val); - this._btnPrice.hidden = !val; - ]]></setter> - </property> - - <method name="setSort"> - <parameter name="aSort"/> - <parameter name="aAscending"/> - <body><![CDATA[ - var sortChanged = false; - if (aSort != this.sortBy) { - this.setAttribute("sortby", aSort); - sortChanged = true; - } - - aAscending = !!aAscending; - if (this.ascending != aAscending) { - this.setAttribute("ascending", aAscending); - sortChanged = true; - } - - if (sortChanged) - this._refreshState(); - ]]></body> - </method> - - <method name="_handleChange"> - <parameter name="aSort"/> - <body><![CDATA[ - const ASCENDING_SORT_FIELDS = ["name", "purchaseAmount"]; - - // Toggle ascending if sort by is not changing, otherwise - // name sorting defaults to ascending, others to descending - if (aSort == this.sortBy) - this.ascending = !this.ascending; - else - this.setSort(aSort, ASCENDING_SORT_FIELDS.indexOf(aSort) >= 0); - ]]></body> - </method> - - <method name="_refreshState"> - <body><![CDATA[ - var sortBy = this.sortBy; - var checkState = this.ascending ? 2 : 1; - - if (sortBy == "name") { - this._btnName.checkState = checkState; - this._btnName.checked = true; - } else { - this._btnName.checkState = 0; - this._btnName.checked = false; - } - - if (sortBy == "updateDate") { - this._btnDate.checkState = checkState; - this._btnDate.checked = true; - } else { - this._btnDate.checkState = 0; - this._btnDate.checked = false; - } - - if (sortBy == "purchaseAmount") { - this._btnPrice.checkState = checkState; - this._btnPrice.checked = true; - } else { - this._btnPrice.checkState = 0; - this._btnPrice.checked = false; - } - - if (sortBy == "relevancescore") { - this._btnRelevance.checkState = checkState; - this._btnRelevance.checked = true; - } else { - this._btnRelevance.checkState = 0; - this._btnRelevance.checked = false; - } - - if (this.handler && "onSortChanged" in this.handler) - this.handler.onSortChanged(sortBy, this.ascending); - ]]></body> - </method> - </implementation> - </binding> - - - <!-- Categories list - displays the list of categories on the left pane. --> - <binding id="categories-list" - extends="chrome://global/content/bindings/richlistbox.xml#richlistbox"> - <implementation> - <!-- This needs to be overridden to allow the fancy animation while not - allowing that item to be selected when hiding. --> - <method name="_canUserSelect"> - <parameter name="aItem"/> - <body> - <![CDATA[ - if (aItem.hasAttribute("disabled") && - aItem.getAttribute("disabled") == "true") - return false; - var style = document.defaultView.getComputedStyle(aItem, ""); - return style.display != "none" && style.visibility == "visible"; - ]]> - </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" flex="1" xbl:inherits="value=name"/> - <xul:label anonid="badge" class="category-badge" xbl:inherits="value=count"/> - </content> - - <implementation> - <constructor><![CDATA[ - if (!this.hasAttribute("count")) - this.setAttribute("count", 0); - ]]></constructor> - - <property name="badgeCount"> - <getter><![CDATA[ - return this.getAttribute("count"); - ]]></getter> - <setter><![CDATA[ - if (this.getAttribute("count") == val) - return; - - 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 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:progressmeter anonid="progress" class="download-progress"/> - <xul:button anonid="purchase-remote-btn" hidden="true" - class="addon-control" - oncommand="document.getBindingParent(this).purchaseRemote();"/> - <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="_purchaseRemote"> - document.getAnonymousElementByAttribute(this, "anonid", - "purchase-remote-btn"); - </field> - <field name="_installRemote"> - document.getAnonymousElementByAttribute(this, "anonid", - "install-remote-btn"); - </field> - <field name="_restartNeeded"> - document.getAnonymousElementByAttribute(this, "anonid", - "restart-needed"); - </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; - var showPurchase = 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; - } - - } else if (this.mControl.mAddon.purchaseURL) { - this._progress.hidden = true; - showPurchase = true; - this._purchaseRemote.label = - gStrings.ext.formatStringFromName("addon.purchase.label", - [this.mControl.mAddon.purchaseDisplayAmount], 1); - this._purchaseRemote.tooltiptext = - gStrings.ext.GetStringFromName("addon.purchase.tooltip"); - } - - this._purchaseRemote.hidden = !showPurchase; - 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="purchaseRemote"> - <body><![CDATA[ - openURL(this.mControl.mAddon.purchaseURL); - ]]></body> - </method> - - <method name="installRemote"> - <body><![CDATA[ - if (this.mControl.getAttribute("remote") != "true") - return; - - if (this.mControl.mAddon.eula) { - var data = { - addon: this.mControl.mAddon, - accepted: false - }; - window.openDialog("chrome://mozapps/content/extensions/eula.xul", "_blank", - "chrome,dialog,modal,centerscreen,resizable=no", data); - if (!data.accepted) - return; - } - - delete this.mControl.mAddon; - this.mControl.mInstall = this.mInstall; - this.mControl.setAttribute("status", "installing"); - this.mInstall.install(); - ]]></body> - </method> - - <method name="undoAction"> - <body><![CDATA[ - if (!this.mAddon) - return; - var pending = this.mAddon.pendingOperations; - if (pending & AddonManager.PENDING_ENABLE) - this.mAddon.userDisabled = true; - else if (pending & AddonManager.PENDING_DISABLE) - this.mAddon.userDisabled = false; - this.refreshState(); - ]]></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> - <method name="hasPermission"> - <parameter name="aPerm"/> - <body><![CDATA[ - var perm = AddonManager["PERM_CAN_" + aPerm.toUpperCase()]; - return !!(this.mAddon.permissions & perm); - ]]></body> - </method> - - <method name="opRequiresRestart"> - <parameter name="aOperation"/> - <body><![CDATA[ - var operation = AddonManager["OP_NEEDS_RESTART_" + aOperation.toUpperCase()]; - return !!(this.mAddon.operationsRequiringRestart & operation); - ]]></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.parentNode.removeChild(this); - ]]></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> - <xul:hbox anonid="warning-container" - class="warning"> - <xul:image class="warning-icon"/> - <xul:label anonid="warning" flex="1"/> - <xul:label anonid="warning-link" class="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" class="text-link" hidden="true"/> - <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="restart-btn" class="button-link" - label="&addon.restartNow.label;" - oncommand="document.getBindingParent(this).restart();"/> - <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:hbox class="content-container" align="center"> - <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="value=name"/> - <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="experiment-container"> - <svg width="6" height="6" viewBox="0 0 6 6" version="1.1" - xmlns="http://www.w3.org/2000/svg" - class="experiment-bullet-container"> - <circle cx="3" cy="3" r="3" class="experiment-bullet"/> - </svg> - <xul:label anonid="experiment-state" class="experiment-state"/> - <xul:label anonid="experiment-time" class="experiment-time"/> - </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:button anonid="details-btn" class="details button-link" - label="&addon.details.label;" - tooltiptext="&addon.details.tooltip;" - oncommand="document.getBindingParent(this).showInDetailView();"/> - <xul:spacer flex="5000"/> <!-- Necessary to make the description crop --> - </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: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> - </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"> - <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="remove-btn" class="addon-control remove" - label="&cmd.uninstallAddon.label;" - oncommand="document.getBindingParent(this).uninstall();"/> - <xul:menulist anonid="state-menulist" - class="addon-control state" - 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> - </content> - - <implementation> - <constructor><![CDATA[ - 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="_experimentState"> - document.getAnonymousElementByAttribute(this, "anonid", "experiment-state"); - </field> - <field name="_experimentTime"> - document.getAnonymousElementByAttribute(this, "anonid", "experiment-time"); - </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[ - 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, 48, 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; - - if (!("applyBackgroundUpdates" in this.mAddon) || - (this.mAddon.applyBackgroundUpdates == AddonManager.AUTOUPDATE_DISABLE || - (this.mAddon.applyBackgroundUpdates == AddonManager.AUTOUPDATE_DEFAULT && - !AddonManager.autoUpdateDefault))) { - AddonManager.getAllInstalls(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 locale = Components.classes["@mozilla.org/chrome/chrome-registry;1"] - .getService(Components.interfaces.nsIXULChromeRegistry) - .getSelectedLocale("global", true); - const dtOptions = { year: 'numeric', month: 'long', day: 'numeric' }; - return aDate.toLocaleDateString(locale, 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_NONE) { - this.removeAttribute("notification"); - - pending = null; - const PENDING_OPERATIONS = ["enable", "disable", "install", - "uninstall", "upgrade"]; - for (let op of PENDING_OPERATIONS) { - if (this.isPending(op)) - pending = op; - } - - this.setAttribute("pending", pending); - this._pending.textContent = gStrings.ext.formatStringFromName( - "notification." + pending, - [this.mAddon.name, gStrings.brandShortName], 2 - ); - } 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], 1 - ); - 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], 1 - ); - 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], 1 - ); - this._errorLink.value = gStrings.ext.GetStringFromName("notification.blocked.link"); - this._errorLink.href = this.mAddon.blocklistURL; - this._errorLink.hidden = false; - } else if (!isUpgrade && !isCorrectlySigned(this.mAddon) && SIGNING_REQUIRED) { - this.setAttribute("notification", "error"); - this._error.textContent = gStrings.ext.formatStringFromName( - "notification.unsignedAndDisabled", [this.mAddon.name, gStrings.brandShortName], 2 - ); - this._errorLink.value = gStrings.ext.GetStringFromName("notification.unsigned.link"); - this._errorLink.href = Services.urlFormatter.formatURLPref("app.support.baseURL") + "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], 3 - ); - 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], 2 - ); - this._warningLink.value = gStrings.ext.GetStringFromName("notification.unsigned.link"); - this._warningLink.href = Services.urlFormatter.formatURLPref("app.support.baseURL") + "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], 1 - ); - this._warningLink.value = gStrings.ext.GetStringFromName("notification.softblocked.link"); - this._warningLink.href = this.mAddon.blocklistURL; - 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], 1 - ); - this._warningLink.value = gStrings.ext.GetStringFromName("notification.outdated.link"); - this._warningLink.href = this.mAddon.blocklistURL; - 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], 1 - ); - this._errorLink.value = gStrings.ext.GetStringFromName("notification.vulnerableUpdatable.link"); - this._errorLink.href = this.mAddon.blocklistURL; - 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], 1 - ); - this._errorLink.value = gStrings.ext.GetStringFromName("notification.vulnerableNoUpdate.link"); - this._errorLink.href = this.mAddon.blocklistURL; - 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], 1); - } else { - this.removeAttribute("notification"); - } - } - - this._preferencesBtn.hidden = (!this.mAddon.optionsURL) || - this.mAddon.optionsType == AddonManager.OPTIONS_TYPE_INLINE_INFO; - - if (this.typeHasFlag("SUPPORTS_ASK_TO_ACTIVATE")) { - this._enableBtn.disabled = true; - this._disableBtn.disabled = true; - this._askToActivateMenuitem.disabled = !this.hasPermission("ask_to_activate"); - this._alwaysActivateMenuitem.disabled = !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._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.purchaseURL || (this.mAddon.install && - this.mAddon.install.state != AddonManager.STATE_INSTALLED); - this._showStatus(showProgress ? "progress" : "none"); - - if (this.mAddon.type == "experiment") { - this.removeAttribute("notification"); - let prefix = "experiment."; - let active = this.mAddon.isActive; - - if (!showProgress) { - let stateKey = prefix + "state." + (active ? "active" : "complete"); - this._experimentState.value = gStrings.ext.GetStringFromName(stateKey); - - let now = Date.now(); - let end = this.endDate; - let days = Math.abs(end - now) / (24 * 60 * 60 * 1000); - - let timeKey = prefix + "time."; - let timeMessage; - - if (days < 1) { - timeKey += (active ? "endsToday" : "endedToday"); - timeMessage = gStrings.ext.GetStringFromName(timeKey); - } else { - timeKey += (active ? "daysRemaining" : "daysPassed"); - days = Math.round(days); - let timeString = gStrings.ext.GetStringFromName(timeKey); - timeMessage = PluralForm.get(days, timeString) - .replace("#1", days); - } - - this._experimentTime.value = timeMessage; - } - } - ]]></body> - </method> - - <method name="_fetchReleaseNotes"> - <parameter name="aURI"/> - <body><![CDATA[ - if (!aURI || this._relNotesLoaded) { - sendToggleEvent(); - return; - } - - var relNotesData = null, transformData = null; - - this._relNotesLoaded = true; - this._relNotesLoading.hidden = false; - this._relNotesError.hidden = true; - - let sendToggleEvent = () => { - var event = document.createEvent("Events"); - event.initEvent("RelNotesToggle", true, true); - this.dispatchEvent(event); - } - - let showRelNotes = () => { - if (!relNotesData || !transformData) - return; - - this._relNotesLoading.hidden = true; - - var processor = Components.classes["@mozilla.org/document-transformer;1?type=xslt"] - .createInstance(Components.interfaces.nsIXSLTProcessor); - processor.flags |= Components.interfaces.nsIXSLTProcessorPrivate.DISABLE_ALL_LOADS; - - processor.importStylesheet(transformData); - var fragment = processor.transformToFragment(relNotesData, document); - this._relNotes.appendChild(fragment); - if (this.hasAttribute("show-relnotes")) { - var container = this._relNotesContainer; - container.style.height = container.scrollHeight + "px"; - } - sendToggleEvent(); - } - - let handleError = () => { - dataReq.abort(); - styleReq.abort(); - this._relNotesLoading.hidden = true; - this._relNotesError.hidden = false; - this._relNotesLoaded = false; // allow loading to be re-tried - sendToggleEvent(); - } - - function handleResponse(aEvent) { - var req = aEvent.target; - var ct = req.getResponseHeader("content-type"); - if ((!ct || ct.indexOf("text/html") < 0) && - req.responseXML && - req.responseXML.documentElement.namespaceURI != XMLURI_PARSE_ERROR) { - if (req == dataReq) - relNotesData = req.responseXML; - else - transformData = req.responseXML; - showRelNotes(); - } else { - handleError(); - } - } - - var dataReq = Components.classes["@mozilla.org/xmlextras/xmlhttprequest;1"] - .createInstance(Components.interfaces.nsIXMLHttpRequest); - dataReq.open("GET", aURI.spec, true); - dataReq.responseType = "document"; - dataReq.addEventListener("load", handleResponse, false); - dataReq.addEventListener("error", handleError, false); - dataReq.send(null); - - var styleReq = Components.classes["@mozilla.org/xmlextras/xmlhttprequest;1"] - .createInstance(Components.interfaces.nsIXMLHttpRequest); - styleReq.open("GET", UPDATES_RELEASENOTES_TRANSFORMFILE, true); - styleReq.responseType = "document"; - styleReq.addEventListener("load", handleResponse, false); - styleReq.addEventListener("error", handleError, false); - styleReq.send(null); - ]]></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") - ); - var 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); - } - ]]></body> - </method> - - <method name="restart"> - <body><![CDATA[ - gViewController.commands["cmd_restartApp"].doCommand(); - ]]></body> - </method> - - <method name="undo"> - <body><![CDATA[ - gViewController.commands["cmd_cancelOperation"].doCommand(this.mAddon); - ]]></body> - </method> - - <method name="uninstall"> - <body><![CDATA[ - // If uninstalling does not require a restart and 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.opRequiresRestart("uninstall") && - !this.typeHasFlag("SUPPORTS_UNDO_RESTARTLESS_UNINSTALL")) { - 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.userDisabled = true; - - // This won't update any other add-on manager views (bug 582002) - this.setAttribute("pending", "uninstall"); - } else { - this.mAddon.uninstall(true); - } - ]]></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="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"> - <parameter name="aRestartRequired"/> - <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.indexOf("appDisabled") != -1 || - aProperties.indexOf("signedState") != -1 || - aProperties.indexOf("userDisabled") != -1) - this._updateState(); - ]]></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"/> - <parameter name="aNeedsRestart"/> - <body><![CDATA[ - if (aExistingAddon.id != this.mAddon.id) - return; - - // If the install completed without needing a restart then switch to - // using the new Addon - if (!aNeedsRestart) - this._initWithAddon(aAddon); - else - this._updateState(); - ]]></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[ - // If the install completed without needing a restart then switch to - // using the new Addon - if (!(aAddon.pendingOperations & AddonManager.PENDING_INSTALL)) - this._initWithAddon(aAddon); - else - this._updateState(); - ]]></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[ - switch (event.detail) { - case 1: - // Prevent double-click where the UI changes on the first click - this._lastClickTarget = event.originalTarget; - break; - case 2: - if (event.originalTarget.localName != 'button' && - !event.originalTarget.classList.contains('text-link') && - event.originalTarget == this._lastClickTarget) { - this.showInDetailView(); - } - break; - } - ]]></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="restart-btn" class="button-link" - label="&addon.restartNow.label;" - command="cmd_restartApp"/> - <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], - 1); - - if (!this.opRequiresRestart("uninstall")) - this._restartBtn.setAttribute("hidden", true); - - 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> - <field name="_restartBtn" readonly="true"> - document.getAnonymousElementByAttribute(this, "anonid", "restart-btn"); - </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.userDisabled = false; - - this.removeAttribute("pending"); - ]]></body> - </method> - - <method name="onOperationCancelled"> - <body><![CDATA[ - if (!this.isPending("uninstall")) - this.removeAttribute("pending"); - ]]></body> - </method> - - <method name="onExternalInstall"> - <parameter name="aAddon"/> - <parameter name="aExistingAddon"/> - <parameter name="aNeedsRestart"/> - <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")) - aAddon.userDisabled = this.getAttribute("wasDisabled") == "true"; - - // If the install completed without needing a restart then switch to - // using the new Addon - if (!aNeedsRestart) - 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")) - aInstall.addon.userDisabled = this.getAttribute("wasDisabled") == "true"; - ]]></body> - </method> - - <method name="onInstallEnded"> - <parameter name="aInstall"/> - <parameter name="aAddon"/> - <body><![CDATA[ - // If the install completed without needing a restart then switch to - // using the new Addon - if (!(aAddon.pendingOperations & AddonManager.PENDING_INSTALL)) - 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 = Components.classes["@mozilla.org/network/standard-url;1"] - .createInstance(Components.interfaces.nsIStandardURL); - url.init(url.URLTYPE_STANDARD, 80, this.mInstall.sourceURI.spec, - null, null); - url.QueryInterface(Components.interfaces.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], 1 - ); - 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], 1 - ); - 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> diff --git a/toolkit/mozapps/webextensions/content/extensions.xul b/toolkit/mozapps/webextensions/content/extensions.xul deleted file mode 100644 index 70939d024..000000000 --- a/toolkit/mozapps/webextensions/content/extensions.xul +++ /dev/null @@ -1,715 +0,0 @@ -<?xml version="1.0"?> -<!-- This Source Code Form is subject to the terms of the Mozilla Public - - License, v. 2.0. If a copy of the MPL was not distributed with this - - file, You can obtain one at http://mozilla.org/MPL/2.0/. --> - -<?xml-stylesheet href="chrome://global/skin/" type="text/css"?> -<?xml-stylesheet href="chrome://mozapps/content/extensions/extensions.css"?> -<?xml-stylesheet href="chrome://mozapps/skin/extensions/extensions.css"?> - -<!DOCTYPE page [ -<!ENTITY % brandDTD SYSTEM "chrome://branding/locale/brand.dtd" > -%brandDTD; -<!ENTITY % extensionsDTD SYSTEM "chrome://mozapps/locale/extensions/extensions.dtd"> -%extensionsDTD; -]> - -<page xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" - xmlns:xhtml="http://www.w3.org/1999/xhtml" - id="addons-page" title="&addons.windowTitle;" - role="application" windowtype="Addons:Manager" - disablefastfind="true"> - - <xhtml:link rel="shortcut icon" - href="chrome://mozapps/skin/extensions/extensionGeneric-16.png"/> - - <script type="application/javascript" - src="chrome://mozapps/content/extensions/extensions.js"/> - <script type="application/javascript" - src="chrome://global/content/contentAreaUtils.js"/> - - <popupset> - <!-- menu for an addon item --> - <menupopup id="addonitem-popup"> - <menuitem id="menuitem_showDetails" command="cmd_showItemDetails" - default="true" label="&cmd.showDetails.label;" - accesskey="&cmd.showDetails.accesskey;"/> - <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" - label="&cmd.enableTheme.label;" - accesskey="&cmd.enableTheme.accesskey;"/> - <menuitem id="menuitem_disableTheme" command="cmd_disableItem" - label="&cmd.disableTheme.label;" - accesskey="&cmd.disableTheme.accesskey;"/> - <menuitem id="menuitem_installItem" command="cmd_installItem" - label="&cmd.installAddon.label;" - accesskey="&cmd.installAddon.accesskey;"/> - <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" -#ifdef XP_WIN - label="&cmd.preferencesWin.label;" - accesskey="&cmd.preferencesWin.accesskey;"/> -#else - label="&cmd.preferencesUnix.label;" - accesskey="&cmd.preferencesUnix.accesskey;"/> -#endif - <menuitem id="menuitem_findUpdates" command="cmd_findItemUpdates" - label="&cmd.findUpdates.label;" - accesskey="&cmd.findUpdates.accesskey;"/> - <menuitem id="menuitem_about" command="cmd_showItemAbout" - label="&cmd.about.label;" - accesskey="&cmd.about.accesskey;"/> - </menupopup> - - <tooltip id="addonitem-tooltip"/> - </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_experimentsLearnMore"/> - <command id="cmd_experimentsOpenTelemetryPreferences"/> - <command id="cmd_showUnsignedExtensions"/> - <command id="cmd_showAllExtensions"/> - </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_showItemAbout"/> - <command id="cmd_enableItem"/> - <command id="cmd_disableItem"/> - <command id="cmd_installItem"/> - <command id="cmd_purchaseItem"/> - <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" key="&search.commandkey;" modifiers="accel" - command="cmd_focusSearch"/> - </keyset> - <hbox flex="1"> - <vbox> - <hbox id="nav-header" - align="center" - pack="center"> - <toolbarbutton id="back-btn" - class="nav-button header-button" - command="cmd_back" - tooltiptext="&cmd.back.tooltip;" - hidden="true" - disabled="true"/> - <toolbarbutton id="forward-btn" - class="nav-button header-button" - command="cmd_forward" - tooltiptext="&cmd.forward.tooltip;" - hidden="true" - disabled="true"/> - </hbox> - <!-- category list --> - <richlistbox id="categories" flex="1"> - <richlistitem id="category-search" value="addons://search/" - class="category" - name="&view.search.label;" priority="0" - tooltiptext="&view.search.label;" disabled="true"/> - <richlistitem id="category-discover" value="addons://discover/" - class="category" - name="&view.discover.label;" priority="1000" - tooltiptext="&view.discover.label;"/> - <richlistitem id="category-availableUpdates" value="addons://updates/available" - class="category" - name="&view.availableUpdates.label;" priority="100000" - tooltiptext="&view.availableUpdates.label;" - disabled="true"/> - <richlistitem id="category-recentUpdates" value="addons://updates/recent" - class="category" - name="&view.recentUpdates.label;" priority="101000" - tooltiptext="&view.recentUpdates.label;" disabled="true"/> - </richlistbox> - </vbox> - <vbox class="main-content" flex="1"> - <!-- view port --> - <deck id="view-port" flex="1" selectedIndex="0"> - <!-- discover view --> - <deck id="discover-view" flex="1" class="view-pane" selectedIndex="0" tabindex="0"> - <vbox id="discover-loading" align="center" pack="stretch" flex="1" class="alert-container"> - <spacer class="alert-spacer-before"/> - <hbox class="alert loading" align="center"> - <image/> - <label value="&loading.label;"/> - </hbox> - <spacer class="alert-spacer-after"/> - </vbox> - <vbox id="discover-error" align="center" pack="stretch" flex="1" class="alert-container"> - <spacer class="alert-spacer-before"/> - <hbox> - <spacer class="discover-spacer-before"/> - <hbox class="alert" align="center"> - <image class="discover-logo"/> - <vbox flex="1" align="stretch"> - <label class="discover-title">&discover.title;</label> - <description class="discover-description">&discover.description2;</description> - <description class="discover-footer">&discover.footer;</description> - </vbox> - </hbox> - <spacer class="discover-spacer-after"/> - </hbox> - <spacer class="alert-spacer-after"/> - </vbox> - <browser id="discover-browser" type="content" flex="1" - disablehistory="true" homepage="about:blank"/> - </deck> - - <!-- container for views with the search/tools header --> - <vbox id="headered-views" flex="1"> - <!-- main header --> - <hbox id="header" align="center"> - <button id="show-all-extensions" hidden="true" - label="&showAllExtensions.button.label;" - command="cmd_showAllExtensions"/> - <spacer flex="1"/> - <hbox id="updates-container" align="center"> - <image class="spinner"/> - <label id="updates-noneFound" hidden="true" - value="&updates.noneFound.label;"/> - <button id="updates-manualUpdatesFound-btn" class="button-link" - hidden="true" label="&updates.manualUpdatesFound.label;" - command="cmd_goToAvailableUpdates"/> - <label id="updates-progress" hidden="true" - value="&updates.updating.label;"/> - <label id="updates-installed" hidden="true" - value="&updates.installed.label;"/> - <label id="updates-downloaded" hidden="true" - value="&updates.downloaded.label;"/> - <button id="updates-restart-btn" class="button-link" hidden="true" - label="&updates.restart.label;" - command="cmd_restartApp"/> - </hbox> - <button id="show-disabled-unsigned-extensions" hidden="true" - class="warning" - label="&showUnsignedExtensions.button.label;" - command="cmd_showUnsignedExtensions"/> - <toolbarbutton id="header-utils-btn" class="header-button" type="menu" - tooltiptext="&toolsMenu.tooltip;"> - <menupopup id="utils-menu"> - <menuitem id="utils-updateNow" - label="&updates.checkForUpdates.label;" - accesskey="&updates.checkForUpdates.accesskey;" - command="cmd_findAllUpdates"/> - <menuitem id="utils-viewUpdates" - label="&updates.viewUpdates.label;" - accesskey="&updates.viewUpdates.accesskey;" - command="cmd_goToRecentUpdates"/> - <menuseparator id="utils-installFromFile-separator"/> - <menuitem id="utils-installFromFile" - label="&installAddonFromFile.label;" - accesskey="&installAddonFromFile.accesskey;" - command="cmd_installFromFile"/> - <menuitem id="utils-debugAddons" - label="&debugAddons.label;" - accesskey="&debugAddons.accesskey;" - command="cmd_debugAddons"/> - <menuseparator/> - <menuitem id="utils-autoUpdateDefault" - label="&updates.updateAddonsAutomatically.label;" - accesskey="&updates.updateAddonsAutomatically.accesskey;" - type="checkbox" autocheck="false" - command="cmd_toggleAutoUpdateDefault"/> - <menuitem id="utils-resetAddonUpdatesToAutomatic" - label="&updates.resetUpdatesToAutomatic.label;" - accesskey="&updates.resetUpdatesToAutomatic.accesskey;" - command="cmd_resetAddonAutoUpdate"/> - <menuitem id="utils-resetAddonUpdatesToManual" - label="&updates.resetUpdatesToManual.label;" - accesskey="&updates.resetUpdatesToManual.accesskey;" - command="cmd_resetAddonAutoUpdate"/> - </menupopup> - </toolbarbutton> - <textbox id="header-search" type="search" searchbutton="true" - searchbuttonlabel="&search.buttonlabel;" - placeholder="&search.placeholder;"/> - </hbox> - - <deck id="headered-views-content" flex="1" selectedIndex="0"> - <!-- search view --> - <vbox id="search-view" flex="1" class="view-pane" tabindex="0"> - <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" - tooltiptext="&warning.safemode.label;"> - <image class="warning-icon"/> - <label class="global-warning-text" flex="1" crop="end" - value="&warning.safemode.label;"/> - </hbox> - <hbox class="global-warning-checkcompatibility" flex="1" align="center" - tooltiptext="&warning.checkcompatibility.label;"> - <image class="warning-icon"/> - <label class="global-warning-text" flex="1" crop="end" - value="&warning.checkcompatibility.label;"/> - </hbox> - <button class="button-link global-warning-checkcompatibility" - label="&warning.checkcompatibility.enable.label;" - tooltiptext="&warning.checkcompatibility.enable.tooltip;" - command="cmd_enableCheckCompatibility"/> - <hbox class="global-warning-updatesecurity" flex="1" align="center" - tooltiptext="&warning.updatesecurity.label;"> - <image class="warning-icon"/> - <label class="global-warning-text" flex="1" crop="end" - value="&warning.updatesecurity.label;"/> - </hbox> - <button class="button-link global-warning-updatesecurity" - label="&warning.updatesecurity.enable.label;" - tooltiptext="&warning.updatesecurity.enable.tooltip;" - command="cmd_enableUpdateSecurity"/> - <spacer flex="5000"/> <!-- Necessary to allow the message to wrap --> - </hbox> - <spacer flex="1"/> - <hbox id="search-sorters" class="sort-controls" - showrelevance="true" sortby="relevancescore" ascending="false"/> - </hbox> - <hbox id="search-filter" align="center"> - <label id="search-filter-label" value="&search.filter2.label;"/> - <radiogroup id="search-filter-radiogroup" orient="horizontal" - align="center" persist="value" value="remote"> - <radio id="search-filter-local" class="search-filter-radio" - label="&search.filter2.installed.label;" value="local" - tooltiptext="&search.filter2.installed.tooltip;"/> - <radio id="search-filter-remote" class="search-filter-radio" - label="&search.filter2.available.label;" value="remote" - tooltiptext="&search.filter2.available.tooltip;"/> - </radiogroup> - </hbox> - <vbox id="search-loading" class="alert-container" - flex="1" hidden="true"> - <spacer class="alert-spacer-before"/> - <hbox class="alert loading" align="center"> - <image/> - <label value="&loading.label;"/> - </hbox> - <spacer class="alert-spacer-after"/> - </vbox> - <vbox id="search-list-empty" class="alert-container" - flex="1" hidden="true"> - <spacer class="alert-spacer-before"/> - <vbox class="alert"> - <label value="&listEmpty.search.label;"/> - <button class="discover-button" - id="discover-button-search" - label="&listEmpty.button.label;" - command="cmd_goToDiscoverPane"/> - </vbox> - <spacer class="alert-spacer-after"/> - </vbox> - <richlistbox id="search-list" class="list" flex="1"> - <hbox pack="center"> - <label id="search-allresults-link" class="text-link"/> - </hbox> - </richlistbox> - </vbox> - - <!-- list view --> - <vbox id="list-view" flex="1" class="view-pane" align="stretch" tabindex="0"> - <!-- info UI for add-ons that have been disabled for being unsigned --> - <vbox id="disabled-unsigned-addons-info" hidden="true"> - <label id="disabled-unsigned-addons-heading" value="&disabledUnsigned.heading;"/> - <description> - &disabledUnsigned.description.start;<label class="text-link plain" id="find-alternative-addons">&disabledUnsigned.description.findAddonsLink;</label>&disabledUnsigned.description.end; - </description> - <hbox pack="start"><label class="text-link" id="signing-learn-more">&disabledUnsigned.learnMore;</label></hbox> - <description id="signing-dev-info"> - &disabledUnsigned.devInfo.start;<label class="text-link plain" id="signing-dev-manual-link">&disabledUnsigned.devInfo.linkToManual;</label>&disabledUnsigned.devInfo.end; - </description> - </vbox> - <vbox id="plugindeprecation-notice" class="alert-container"> - <hbox class="alert"> - <description>&pluginDeprecation.description;   - <label class="text-link plain" id="plugindeprecation-learnmore-link">&pluginDeprecation.learnMore;</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" - tooltiptext="&warning.safemode.label;"> - <image class="warning-icon"/> - <label class="global-warning-text" flex="1" crop="end" - value="&warning.safemode.label;"/> - </hbox> - <hbox class="global-warning-checkcompatibility" flex="1" align="center" - tooltiptext="&warning.checkcompatibility.label;"> - <image class="warning-icon"/> - <label class="global-warning-text" flex="1" crop="end" - value="&warning.checkcompatibility.label;"/> - </hbox> - <button class="button-link global-warning-checkcompatibility" - label="&warning.checkcompatibility.enable.label;" - tooltiptext="&warning.checkcompatibility.enable.tooltip;" - command="cmd_enableCheckCompatibility"/> - <hbox class="global-warning-updatesecurity" flex="1" align="center" - tooltiptext="&warning.updatesecurity.label;"> - <image class="warning-icon"/> - <label class="global-warning-text" flex="1" crop="end" - value="&warning.updatesecurity.label;"/> - </hbox> - <button class="button-link global-warning-updatesecurity" - label="&warning.updatesecurity.enable.label;" - tooltiptext="&warning.updatesecurity.enable.tooltip;" - command="cmd_enableUpdateSecurity"/> - <spacer flex="5000"/> <!-- Necessary to allow the message to wrap --> - </hbox> - </hbox> - <hbox class="view-header global-info-container experiment-info-container"> - <hbox class="global-info" flex="1" align="center"> - <label value="&experiment.info.label;"/> - <button id="experiments-learn-more" - label="&experiment.info.learnmore;" - tooltiptext="&experiment.info.learnmore;" - accesskey="&experiment.info.learnmore.accesskey;" - command="cmd_experimentsLearnMore"/> - <button id="experiments-change-telemetry" - label="&experiment.info.changetelemetry;" - tooltiptext="&experiment.info.changetelemetry;" - accesskey="&experiment.info.changetelemetry.accesskey;" - command="cmd_experimentsOpenTelemetryPreferences"/> - <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 value="&listEmpty.installed.label;"/> - <button class="discover-button" - id="discover-button-install" - label="&listEmpty.button.label;" - command="cmd_goToDiscoverPane"/> - </vbox> - <spacer class="alert-spacer-after"/> - </vbox> - <richlistbox id="addon-list" class="list" flex="1"/> - </vbox> - <!-- updates view --> - <vbox id="updates-view" flex="1" class="view-pane" tabindex="0"> - <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" - tooltiptext="&warning.safemode.label;"> - <image class="warning-icon"/> - <label class="global-warning-text" flex="1" crop="end" - value="&warning.safemode.label;"/> - </hbox> - <hbox class="global-warning-checkcompatibility" flex="1" align="center" - tooltiptext="&warning.checkcompatibility.label;"> - <image class="warning-icon"/> - <label class="global-warning-text" flex="1" crop="end" - value="&warning.checkcompatibility.label;"/> - </hbox> - <button class="button-link global-warning-checkcompatibility" - label="&warning.checkcompatibility.enable.label;" - tooltiptext="&warning.checkcompatibility.enable.tooltip;" - command="cmd_enableCheckCompatibility"/> - <hbox class="global-warning-updatesecurity" flex="1" align="center" - tooltiptext="&warning.updatesecurity.label;"> - <image class="warning-icon"/> - <label class="global-warning-text" flex="1" crop="end" - value="&warning.updatesecurity.label;"/> - </hbox> - <button class="button-link global-warning-updatesecurity" - label="&warning.updatesecurity.enable.label;" - tooltiptext="&warning.updatesecurity.enable.tooltip;" - command="cmd_enableUpdateSecurity"/> - <spacer flex="5000"/> <!-- Necessary to allow the message to wrap --> - </hbox> - <spacer flex="1"/> - <hbox id="updates-sorters" class="sort-controls" sortby="updateDate" - ascending="false"/> - </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" value="&listEmpty.availableUpdates.label;"/> - <label id="empty-recentUpdates-msg" value="&listEmpty.recentUpdates.label;"/> - <button label="&listEmpty.findUpdates.label;" - command="cmd_findAllUpdates"/> - </vbox> - <spacer class="alert-spacer-after"/> - </vbox> - <hbox id="update-actions" pack="center"> - <button id="update-selected-btn" hidden="true" - label="&updates.updateSelected.label;" - tooltiptext="&updates.updateSelected.tooltip;"/> - </hbox> - <richlistbox id="updates-list" class="list" flex="1"/> - </vbox> - - <!-- detail view --> - <scrollbox id="detail-view" flex="1" 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" - tooltiptext="&warning.safemode.label;"> - <image class="warning-icon"/> - <label class="global-warning-text" flex="1" crop="end" - value="&warning.safemode.label;"/> - </hbox> - <hbox class="global-warning-checkcompatibility" flex="1" align="center" - tooltiptext="&warning.checkcompatibility.label;"> - <image class="warning-icon"/> - <label class="global-warning-text" flex="1" crop="end" - value="&warning.checkcompatibility.label;"/> - </hbox> - <button class="button-link global-warning-checkcompatibility" - label="&warning.checkcompatibility.enable.label;" - tooltiptext="&warning.checkcompatibility.enable.tooltip;" - command="cmd_enableCheckCompatibility"/> - <hbox class="global-warning-updatesecurity" flex="1" align="center" - tooltiptext="&warning.updatesecurity.label;"> - <image class="warning-icon"/> - <label class="global-warning-text" flex="1" crop="end" - value="&warning.updatesecurity.label;"/> - </hbox> - <button class="button-link global-warning-updatesecurity" - label="&warning.updatesecurity.enable.label;" - tooltiptext="&warning.updatesecurity.enable.tooltip;" - command="cmd_enableUpdateSecurity"/> - <spacer flex="5000"/> <!-- Necessary to allow the message to wrap --> - </hbox> - <hbox flex="1"> - <spacer flex="1"/> - <!-- "loading" splash screen --> - <vbox class="alert-container"> - <spacer class="alert-spacer-before"/> - <hbox class="alert loading"> - <image/> - <label value="&loading.label;"/> - </hbox> - <spacer class="alert-spacer-after"/> - </vbox> - <!-- actual detail view --> - <vbox class="detail-view-container" flex="3" 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" class="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" class="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" - label="&addon.restartNow.label;" - 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 align="start"> - <vbox id="detail-icon-container" align="end"> - <image id="detail-icon" class="icon"/> - </vbox> - <vbox flex="1"> - <vbox id="detail-summary"> - <hbox id="detail-name-container" class="name-container" - align="start"> - <label id="detail-name" flex="1"/> - <label id="detail-version"/> - <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 id="detail-experiment-container"> - <svg width="8" height="8" viewBox="0 0 8 8" version="1.1" - xmlns="http://www.w3.org/2000/svg" - id="detail-experiment-bullet-container"> - <circle cx="4" cy="4" r="4" id="detail-experiment-bullet"/> - </svg> - <label id="detail-experiment-state"/> - <label id="detail-experiment-time"/> - </hbox> - <hbox id="detail-desc-container" align="start"> - <vbox id="detail-screenshot-box" pack="center" hidden="true"> <!-- Necessary to work around bug 394738 --> - <image id="detail-screenshot"/> - </vbox> - <vbox flex="1"> - <description id="detail-desc"/> - <description id="detail-fulldesc"/> - </vbox> - </hbox> - <vbox id="detail-contributions"> - <description id="detail-contrib-description"> - &detail.contributions.description; - </description> - <hbox align="center"> - <label id="detail-contrib-suggested"/> - <spacer flex="1"/> - <button id="detail-contrib-btn" - label="&cmd.contribute.label;" - accesskey="&cmd.contribute.accesskey;" - tooltiptext="&cmd.contribute.tooltip;" - 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" id="detail-updates-row"> - <label class="detail-row-label" value="&detail.updateType;"/> - <hbox align="center"> - <radiogroup id="detail-autoUpdate" orient="horizontal"> - <!-- The values here need to match the values of - AddonManager.AUTOUPDATE_* --> - <radio label="&detail.updateDefault.label;" - tooltiptext="&detail.updateDefault.tooltip;" - value="1"/> - <radio label="&detail.updateAutomatic.label;" - tooltiptext="&detail.updateAutomatic.tooltip;" - value="2"/> - <radio label="&detail.updateManual.label;" - tooltiptext="&detail.updateManual.tooltip;" - value="0"/> - </radiogroup> - <button id="detail-findUpdates-btn" class="button-link" - label="&detail.checkForUpdates.label;" - accesskey="&detail.checkForUpdates.accesskey;" - tooltiptext="&detail.checkForUpdates.tooltip;" - command="cmd_findItemUpdates"/> - </hbox> - </row> - <row class="detail-row" id="detail-dateUpdated" label="&detail.lastupdated.label;"/> - <row class="detail-row-complex" id="detail-homepage-row" label="&detail.home;"> - <label class="detail-row-label" value="&detail.home;"/> - <label id="detail-homepage" class="detail-row-value text-link" crop="end"/> - </row> - <row class="detail-row-complex" id="detail-repository-row" label="&detail.repository;"> - <label class="detail-row-label" value="&detail.repository;"/> - <label id="detail-repository" class="detail-row-value text-link"/> - </row> - <row class="detail-row" id="detail-size" label="&detail.size;"/> - <row class="detail-row-complex" id="detail-rating-row"> - <label class="detail-row-label" value="&rating2.label;"/> - <hbox> - <label id="detail-rating" class="meta-value meta-rating" - showrating="average"/> - <label id="detail-reviews" class="text-link"/> - </hbox> - </row> - <row class="detail-row" id="detail-downloads" label="&detail.numberOfDownloads.label;"/> - </rows> - </grid> - <hbox id="detail-controls"> - <button id="detail-prefs-btn" class="addon-control preferences" -#ifdef XP_WIN - label="&detail.showPreferencesWin.label;" - accesskey="&detail.showPreferencesWin.accesskey;" - tooltiptext="&detail.showPreferencesWin.tooltip;" -#else - label="&detail.showPreferencesUnix.label;" - accesskey="&detail.showPreferencesUnix.accesskey;" - tooltiptext="&detail.showPreferencesUnix.tooltip;" -#endif - 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-purchase-btn" class="addon-control purchase" - command="cmd_purchaseItem"/> - <button id="detail-install-btn" class="addon-control install" - label="&cmd.installAddon.label;" - accesskey="&cmd.installAddon.accesskey;" - 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> - </deck> - </vbox> - </deck> - </vbox> - </hbox> -</page> diff --git a/toolkit/mozapps/webextensions/content/newaddon.xul b/toolkit/mozapps/webextensions/content/newaddon.xul deleted file mode 100644 index 1d8545249..000000000 --- a/toolkit/mozapps/webextensions/content/newaddon.xul +++ /dev/null @@ -1,67 +0,0 @@ -<?xml version="1.0"?> -<!-- This Source Code Form is subject to the terms of the Mozilla Public - - License, v. 2.0. If a copy of the MPL was not distributed with this - - file, You can obtain one at http://mozilla.org/MPL/2.0/. --> - -<?xml-stylesheet href="chrome://global/skin/" type="text/css"?> -<?xml-stylesheet href="chrome://mozapps/skin/extensions/newaddon.css"?> - -<!DOCTYPE page [ -<!ENTITY % brandDTD SYSTEM "chrome://branding/locale/brand.dtd" > -%brandDTD; -<!ENTITY % newaddonDTD SYSTEM "chrome://mozapps/locale/extensions/newaddon.dtd"> -%newaddonDTD; -]> - -<page xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" - xmlns:xhtml="http://www.w3.org/1999/xhtml" title="&title;" - disablefastfind="true" id="addon-page" onload="initialize()" - onunload="unload()" role="application" align="stretch" pack="stretch"> - - <xhtml:link rel="shortcut icon" style="display: none" - href="chrome://mozapps/skin/extensions/extensionGeneric-16.png"/> - - <script type="application/javascript" - src="chrome://mozapps/content/extensions/newaddon.js"/> - - <scrollbox id="addon-scrollbox" align="center"> - <spacer id="spacer-start"/> - - <vbox id="addon-container" class="main-content"> - <description>&intro;</description> - - <hbox id="addon-info"> - <image id="icon"/> - <vbox flex="1"> - <label id="name"/> - <label id="author"/> - <label id="location" crop="end"/> - </vbox> - </hbox> - - <hbox id="warning"> - <image id="warning-icon"/> - <description flex="1">&warning;</description> - </hbox> - - <checkbox id="allow" label="&allow;"/> - <description id="later">&later;</description> - - <deck id="buttonDeck"> - <hbox id="continuePanel"> - <button id="continue-button" label="&continue;" - oncommand="continueClicked()"/> - </hbox> - <vbox id="restartPanel"> - <description id="restartMessage">&restartMessage;</description> - <hbox id="restartPanelButtons"> - <button id="restart-button" label="&restartButton;" oncommand="restartClicked()"/> - <button id="cancel-button" label="&cancelButton;" oncommand="cancelClicked()"/> - </hbox> - </vbox> - </deck> - </vbox> - - <spacer id="spacer-end"/> - </scrollbox> -</page> diff --git a/toolkit/mozapps/webextensions/content/setting.xml b/toolkit/mozapps/webextensions/content/setting.xml deleted file mode 100644 index 2b70eb0d0..000000000 --- a/toolkit/mozapps/webextensions/content/setting.xml +++ /dev/null @@ -1,486 +0,0 @@ -<?xml version="1.0"?> -<!-- This Source Code Form is subject to the terms of the Mozilla Public - - License, v. 2.0. If a copy of the MPL was not distributed with this - - file, You can obtain one at http://mozilla.org/MPL/2.0/. --> - -<!DOCTYPE page [ -<!ENTITY % extensionsDTD SYSTEM "chrome://mozapps/locale/extensions/extensions.dtd"> -%extensionsDTD; -]> - -<!-- import-globals-from extensions.js --> - -<bindings xmlns="http://www.mozilla.org/xbl" - xmlns:xbl="http://www.mozilla.org/xbl" - xmlns:html="http://www.w3.org/1999/xhtml" - xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> - - <binding id="setting-base"> - <implementation> - <constructor><![CDATA[ - this.preferenceChanged(); - - this.addEventListener("keypress", function(event) { - event.stopPropagation(); - }, false); - - if (this.usePref) - Services.prefs.addObserver(this.pref, this._observer, true); - ]]></constructor> - - <field name="_observer"><![CDATA[({ - _self: this, - - QueryInterface: function(aIID) { - const Ci = Components.interfaces; - if (aIID.equals(Ci.nsIObserver) || - aIID.equals(Ci.nsISupportsWeakReference) || - aIID.equals(Ci.nsISupports)) - return this; - - throw Components.Exception("No interface", Components.results.NS_ERROR_NO_INTERFACE); - }, - - observe: function(aSubject, aTopic, aPrefName) { - if (aTopic != "nsPref:changed") - return; - - if (this._self.pref == aPrefName) - this._self.preferenceChanged(); - } - })]]> - </field> - - <method name="fireEvent"> - <parameter name="eventName"/> - <parameter name="funcStr"/> - <body> - <![CDATA[ - let body = funcStr || this.getAttribute(eventName); - if (!body) - return; - - try { - let event = document.createEvent("Events"); - event.initEvent(eventName, true, true); - let f = new Function("event", body); - f.call(this, event); - } - catch (e) { - Cu.reportError(e); - } - ]]> - </body> - </method> - - <method name="valueFromPreference"> - <body> - <![CDATA[ - // Should be code to set the from the preference input.value - throw Components.Exception("No valueFromPreference implementation", - Components.results.NS_ERROR_NOT_IMPLEMENTED); - ]]> - </body> - </method> - - <method name="valueToPreference"> - <body> - <![CDATA[ - // Should be code to set the input.value from the preference - throw Components.Exception("No valueToPreference implementation", - Components.results.NS_ERROR_NOT_IMPLEMENTED); - ]]> - </body> - </method> - - <method name="inputChanged"> - <body> - <![CDATA[ - if (this.usePref && !this._updatingInput) { - this.valueToPreference(); - this.fireEvent("oninputchanged"); - } - ]]> - </body> - </method> - - <method name="preferenceChanged"> - <body> - <![CDATA[ - if (this.usePref) { - this._updatingInput = true; - try { - this.valueFromPreference(); - this.fireEvent("onpreferencechanged"); - } catch (e) {} - this._updatingInput = false; - } - ]]> - </body> - </method> - - <property name="usePref" readonly="true" onget="return this.hasAttribute('pref');"/> - <property name="pref" readonly="true" onget="return this.getAttribute('pref');"/> - <property name="type" readonly="true" onget="return this.getAttribute('type');"/> - <property name="value" onget="return this.input.value;" onset="return this.input.value = val;"/> - - <field name="_updatingInput">false</field> - <field name="input">document.getAnonymousElementByAttribute(this, "anonid", "input");</field> - <field name="settings"> - this.parentNode.localName == "settings" ? this.parentNode : null; - </field> - </implementation> - </binding> - - <binding id="setting-bool" extends="chrome://mozapps/content/extensions/setting.xml#setting-base"> - <content> - <xul:vbox> - <xul:hbox class="preferences-alignment"> - <xul:label class="preferences-title" flex="1" xbl:inherits="xbl:text=title"/> - </xul:hbox> - <xul:description class="preferences-description" flex="1" xbl:inherits="xbl:text=desc"/> - <xul:label class="preferences-learnmore text-link" - onclick="document.getBindingParent(this).openLearnMore()">&setting.learnmore;</xul:label> - </xul:vbox> - <xul:hbox class="preferences-alignment"> - <xul:checkbox anonid="input" xbl:inherits="disabled,onlabel,offlabel,label=checkboxlabel" oncommand="inputChanged();"/> - </xul:hbox> - </content> - - <implementation> - <method name="valueFromPreference"> - <body> - <![CDATA[ - let val = Services.prefs.getBoolPref(this.pref); - this.value = this.inverted ? !val : val; - ]]> - </body> - </method> - - <method name="valueToPreference"> - <body> - <![CDATA[ - let val = this.value; - Services.prefs.setBoolPref(this.pref, this.inverted ? !val : val); - ]]> - </body> - </method> - - <property name="value" onget="return this.input.checked;" onset="return this.input.setChecked(val);"/> - <property name="inverted" readonly="true" onget="return this.getAttribute('inverted');"/> - - <method name="openLearnMore"> - <body> - <![CDATA[ - window.open(this.getAttribute("learnmore"), "_blank"); - ]]> - </body> - </method> - </implementation> - </binding> - - <binding id="setting-boolint" extends="chrome://mozapps/content/extensions/setting.xml#setting-bool"> - <implementation> - <method name="valueFromPreference"> - <body> - <![CDATA[ - let val = Services.prefs.getIntPref(this.pref); - this.value = (val == this.getAttribute("on")); - ]]> - </body> - </method> - - <method name="valueToPreference"> - <body> - <![CDATA[ - Services.prefs.setIntPref(this.pref, this.getAttribute(this.value ? "on" : "off")); - ]]> - </body> - </method> - </implementation> - </binding> - - <binding id="setting-localized-bool" extends="chrome://mozapps/content/extensions/setting.xml#setting-bool"> - <implementation> - <method name="valueFromPreference"> - <body> - <![CDATA[ - let val = Services.prefs.getComplexValue(this.pref, Components.interfaces.nsIPrefLocalizedString).data; - if (this.inverted) val = !val; - this.value = (val == "true"); - ]]> - </body> - </method> - - <method name="valueToPreference"> - <body> - <![CDATA[ - let val = this.value; - if (this.inverted) val = !val; - let pref = Components.classes["@mozilla.org/pref-localizedstring;1"].createInstance(Components.interfaces.nsIPrefLocalizedString); - pref.data = this.inverted ? (!val).toString() : val.toString(); - Services.prefs.setComplexValue(this.pref, Components.interfaces.nsIPrefLocalizedString, pref); - ]]> - </body> - </method> - </implementation> - </binding> - - <binding id="setting-integer" extends="chrome://mozapps/content/extensions/setting.xml#setting-base"> - <content> - <xul:vbox> - <xul:hbox class="preferences-alignment"> - <xul:label class="preferences-title" flex="1" xbl:inherits="xbl:text=title"/> - </xul:hbox> - <xul:description class="preferences-description" flex="1" xbl:inherits="xbl:text=desc"/> - </xul:vbox> - <xul:hbox class="preferences-alignment"> - <xul:textbox type="number" anonid="input" oninput="inputChanged();" onchange="inputChanged();" - xbl:inherits="disabled,emptytext,min,max,increment,hidespinbuttons,wraparound,size"/> - </xul:hbox> - </content> - - <implementation> - <method name="valueFromPreference"> - <body> - <![CDATA[ - let val = Services.prefs.getIntPref(this.pref); - this.value = val; - ]]> - </body> - </method> - - <method name="valueToPreference"> - <body> - <![CDATA[ - Services.prefs.setIntPref(this.pref, this.value); - ]]> - </body> - </method> - </implementation> - </binding> - - <binding id="setting-control" extends="chrome://mozapps/content/extensions/setting.xml#setting-base"> - <content> - <xul:vbox> - <xul:hbox class="preferences-alignment"> - <xul:label class="preferences-title" flex="1" xbl:inherits="xbl:text=title"/> - </xul:hbox> - <xul:description class="preferences-description" flex="1" xbl:inherits="xbl:text=desc"/> - </xul:vbox> - <xul:hbox class="preferences-alignment"> - <children/> - </xul:hbox> - </content> - </binding> - - <binding id="setting-string" extends="chrome://mozapps/content/extensions/setting.xml#setting-base"> - <content> - <xul:vbox> - <xul:hbox class="preferences-alignment"> - <xul:label class="preferences-title" flex="1" xbl:inherits="xbl:text=title"/> - </xul:hbox> - <xul:description class="preferences-description" flex="1" xbl:inherits="xbl:text=desc"/> - </xul:vbox> - <xul:hbox class="preferences-alignment"> - <xul:textbox anonid="input" flex="1" oninput="inputChanged();" - xbl:inherits="disabled,emptytext,type=inputtype,min,max,increment,hidespinbuttons,decimalplaces,wraparound"/> - </xul:hbox> - </content> - - <implementation> - <method name="valueFromPreference"> - <body> - <![CDATA[ - this.value = Preferences.get(this.pref, ""); - ]]> - </body> - </method> - - <method name="valueToPreference"> - <body> - <![CDATA[ - Preferences.set(this.pref, this.value); - ]]> - </body> - </method> - </implementation> - </binding> - - <binding id="setting-color" extends="chrome://mozapps/content/extensions/setting.xml#setting-base"> - <content> - <xul:vbox> - <xul:hbox class="preferences-alignment"> - <xul:label class="preferences-title" flex="1" xbl:inherits="xbl:text=title"/> - </xul:hbox> - <xul:description class="preferences-description" flex="1" xbl:inherits="xbl:text=desc"/> - </xul:vbox> - <xul:hbox class="preferences-alignment"> - <xul:colorpicker type="button" anonid="input" xbl:inherits="disabled" onchange="document.getBindingParent(this).inputChanged();"/> - </xul:hbox> - </content> - - <implementation> - <method name="valueFromPreference"> - <body> - <![CDATA[ - // We must wait for the colorpicker's binding to be applied before setting the value - if (!this.input.color) - this.input.initialize(); - this.value = Services.prefs.getCharPref(this.pref); - ]]> - </body> - </method> - - <method name="valueToPreference"> - <body> - <![CDATA[ - Services.prefs.setCharPref(this.pref, this.value); - ]]> - </body> - </method> - - <property name="value" onget="return this.input.color;" onset="return this.input.color = val;"/> - </implementation> - </binding> - - <binding id="setting-path" extends="chrome://mozapps/content/extensions/setting.xml#setting-base"> - <content> - <xul:vbox> - <xul:hbox class="preferences-alignment"> - <xul:label class="preferences-title" flex="1" xbl:inherits="xbl:text=title"/> - </xul:hbox> - <xul:description class="preferences-description" flex="1" xbl:inherits="xbl:text=desc"/> - </xul:vbox> - <xul:hbox class="preferences-alignment"> - <xul:button type="button" anonid="button" label="&settings.path.button.label;" xbl:inherits="disabled" oncommand="showPicker();"/> - <xul:label anonid="input" flex="1" crop="center" xbl:inherits="disabled"/> - </xul:hbox> - </content> - - <implementation> - <method name="showPicker"> - <body> - <![CDATA[ - var filePicker = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker); - filePicker.init(window, this.getAttribute("title"), - this.type == "file" ? Ci.nsIFilePicker.modeOpen : Ci.nsIFilePicker.modeGetFolder); - if (this.value) { - try { - let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile); - file.initWithPath(this.value); - filePicker.displayDirectory = this.type == "file" ? file.parent : file; - if (this.type == "file") { - filePicker.defaultString = file.leafName; - } - } catch (e) {} - } - if (filePicker.show() != Ci.nsIFilePicker.returnCancel) { - this.value = filePicker.file.path; - this.inputChanged(); - } - ]]> - </body> - </method> - - <method name="valueFromPreference"> - <body> - <![CDATA[ - this.value = Preferences.get(this.pref, ""); - ]]> - </body> - </method> - - <method name="valueToPreference"> - <body> - <![CDATA[ - Preferences.set(this.pref, this.value); - ]]> - </body> - </method> - - <field name="_value"></field> - - <property name="value"> - <getter> - <![CDATA[ - return this._value; - ]]> - </getter> - <setter> - <![CDATA[ - this._value = val; - let label = ""; - if (val) { - try { - let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile); - file.initWithPath(val); - label = this.hasAttribute("fullpath") ? file.path : file.leafName; - } catch (e) {} - } - this.input.tooltipText = val; - return this.input.value = label; - ]]> - </setter> - </property> - </implementation> - </binding> - - <binding id="setting-multi" extends="chrome://mozapps/content/extensions/setting.xml#setting-base"> - <content> - <xul:vbox> - <xul:hbox class="preferences-alignment"> - <xul:label class="preferences-title" flex="1" xbl:inherits="xbl:text=title"/> - </xul:hbox> - <xul:description class="preferences-description" flex="1" xbl:inherits="xbl:text=desc"/> - </xul:vbox> - <xul:hbox class="preferences-alignment"> - <children includes="radiogroup|menulist"/> - </xul:hbox> - </content> - - <implementation> - <constructor> - <![CDATA[ - this.control.addEventListener("command", this.inputChanged.bind(this), false); - ]]> - </constructor> - - <method name="valueFromPreference"> - <body> - <![CDATA[ - let val = Preferences.get(this.pref, "").toString(); - - if ("itemCount" in this.control) { - for (let i = 0; i < this.control.itemCount; i++) { - if (this.control.getItemAtIndex(i).value == val) { - this.control.selectedIndex = i; - break; - } - } - } else { - this.control.setAttribute("value", val); - } - ]]> - </body> - </method> - - <method name="valueToPreference"> - <body> - <![CDATA[ - // We might not have a pref already set, so we guess the type from the value attribute - let val = this.control.selectedItem.value; - if (val == "true" || val == "false") { - val = val == "true"; - } else if (/^-?\d+$/.test(val)) { - val = parseInt(val, 10); - } - Preferences.set(this.pref, val); - ]]> - </body> - </method> - - <field name="control">this.getElementsByTagName(this.getAttribute("type") == "radio" ? "radiogroup" : "menulist")[0];</field> - </implementation> - </binding> -</bindings> diff --git a/toolkit/mozapps/webextensions/content/update.js b/toolkit/mozapps/webextensions/content/update.js deleted file mode 100644 index 80d0fa688..000000000 --- a/toolkit/mozapps/webextensions/content/update.js +++ /dev/null @@ -1,663 +0,0 @@ -// -*- indent-tabs-mode: nil; js-indent-level: 2 -*- - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -// This UI is only opened from the Extension Manager when the app is upgraded. - -"use strict"; - -const PREF_UPDATE_EXTENSIONS_ENABLED = "extensions.update.enabled"; -const PREF_XPINSTALL_ENABLED = "xpinstall.enabled"; - -// timeout (in milliseconds) to wait for response to the metadata ping -const METADATA_TIMEOUT = 30000; - -Components.utils.import("resource://gre/modules/XPCOMUtils.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "AddonManager", "resource://gre/modules/AddonManager.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "AddonManagerPrivate", "resource://gre/modules/AddonManager.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "Services", "resource://gre/modules/Services.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "AddonRepository", "resource://gre/modules/addons/AddonRepository.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "Task", "resource://gre/modules/Task.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "Promise", "resource://gre/modules/Promise.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "Log", "resource://gre/modules/Log.jsm"); -var logger = null; - -var gUpdateWizard = { - // When synchronizing app compatibility info this contains all installed - // add-ons. When checking for compatible versions this contains only - // incompatible add-ons. - addons: [], - // Contains a Set of IDs for add-on that were disabled by the application update. - affectedAddonIDs: null, - // The add-ons that we found updates available for - addonsToUpdate: [], - shouldSuggestAutoChecking: false, - shouldAutoCheck: false, - xpinstallEnabled: true, - xpinstallLocked: false, - // cached AddonInstall entries for add-ons we might want to update, - // keyed by add-on ID - addonInstalls: new Map(), - shuttingDown: false, - // Count the add-ons disabled by this update, enabled/disabled by - // metadata checks, and upgraded. - disabled: 0, - metadataEnabled: 0, - metadataDisabled: 0, - upgraded: 0, - upgradeFailed: 0, - upgradeDeclined: 0, - - init: function() - { - logger = Log.repository.getLogger("addons.update-dialog"); - // XXX could we pass the addons themselves rather than the IDs? - this.affectedAddonIDs = new Set(window.arguments[0]); - - try { - this.shouldSuggestAutoChecking = - !Services.prefs.getBoolPref(PREF_UPDATE_EXTENSIONS_ENABLED); - } - catch (e) { - } - - try { - this.xpinstallEnabled = Services.prefs.getBoolPref(PREF_XPINSTALL_ENABLED); - this.xpinstallLocked = Services.prefs.prefIsLocked(PREF_XPINSTALL_ENABLED); - } - catch (e) { - } - - if (Services.io.offline) - document.documentElement.currentPage = document.getElementById("offline"); - else - document.documentElement.currentPage = document.getElementById("versioninfo"); - }, - - onWizardFinish: function gUpdateWizard_onWizardFinish () - { - if (this.shouldSuggestAutoChecking) - Services.prefs.setBoolPref(PREF_UPDATE_EXTENSIONS_ENABLED, this.shouldAutoCheck); - }, - - _setUpButton: function(aButtonID, aButtonKey, aDisabled) - { - var strings = document.getElementById("updateStrings"); - var button = document.documentElement.getButton(aButtonID); - if (aButtonKey) { - button.label = strings.getString(aButtonKey); - try { - button.setAttribute("accesskey", strings.getString(aButtonKey + "Accesskey")); - } - catch (e) { - } - } - button.disabled = aDisabled; - }, - - setButtonLabels: function(aBackButton, aBackButtonIsDisabled, - aNextButton, aNextButtonIsDisabled, - aCancelButton, aCancelButtonIsDisabled) - { - this._setUpButton("back", aBackButton, aBackButtonIsDisabled); - this._setUpButton("next", aNextButton, aNextButtonIsDisabled); - this._setUpButton("cancel", aCancelButton, aCancelButtonIsDisabled); - }, - - // Update Errors - errorItems: [], - - checkForErrors: function(aElementIDToShow) - { - if (this.errorItems.length > 0) - document.getElementById(aElementIDToShow).hidden = false; - }, - - onWizardClose: function(aEvent) - { - return this.onWizardCancel(); - }, - - onWizardCancel: function() - { - gUpdateWizard.shuttingDown = true; - // Allow add-ons to continue downloading and installing - // in the background, though some may require a later restart - // Pages that are waiting for user input go into the background - // on cancel - if (gMismatchPage.waiting) { - logger.info("Dialog closed in mismatch page"); - if (gUpdateWizard.addonInstalls.size > 0) { - gInstallingPage.startInstalls( - Array.from(gUpdateWizard.addonInstalls.values())); - } - return true; - } - - // Pages that do asynchronous things will just keep running and check - // gUpdateWizard.shuttingDown to trigger background behaviour - if (!gInstallingPage.installing) { - logger.info("Dialog closed while waiting for updated compatibility information"); - } - else { - logger.info("Dialog closed while downloading and installing updates"); - } - return true; - } -}; - -var gOfflinePage = { - onPageAdvanced: function() - { - Services.io.offline = false; - return true; - }, - - toggleOffline: function() - { - var nextbtn = document.documentElement.getButton("next"); - nextbtn.disabled = !nextbtn.disabled; - } -} - -// Addon listener to count addons enabled/disabled by metadata checks -var listener = { - onDisabled: function(aAddon) { - gUpdateWizard.affectedAddonIDs.add(aAddon.id); - gUpdateWizard.metadataDisabled++; - }, - onEnabled: function(aAddon) { - gUpdateWizard.affectedAddonIDs.delete(aAddon.id); - gUpdateWizard.metadataEnabled++; - } -}; - -var gVersionInfoPage = { - _completeCount: 0, - _totalCount: 0, - _versionInfoDone: false, - onPageShow: Task.async(function*() { - gUpdateWizard.setButtonLabels(null, true, - "nextButtonText", true, - "cancelButtonText", false); - - gUpdateWizard.disabled = gUpdateWizard.affectedAddonIDs.size; - - // Ensure compatibility overrides are up to date before checking for - // individual addon updates. - AddonManager.addAddonListener(listener); - if (AddonRepository.isMetadataStale()) { - // Do the metadata ping, listening for any newly enabled/disabled add-ons. - yield AddonRepository.repopulateCache(METADATA_TIMEOUT); - if (gUpdateWizard.shuttingDown) { - logger.debug("repopulateCache completed after dialog closed"); - } - } - // Fetch the add-ons that are still affected by this update, - // excluding the hotfix add-on. - let idlist = Array.from(gUpdateWizard.affectedAddonIDs).filter( - a => a.id != AddonManager.hotfixID); - if (idlist.length < 1) { - gVersionInfoPage.onAllUpdatesFinished(); - return; - } - - logger.debug("Fetching affected addons " + idlist.toSource()); - let fetchedAddons = yield new Promise((resolve, reject) => - AddonManager.getAddonsByIDs(idlist, resolve)); - // We shouldn't get nulls here, but let's be paranoid... - gUpdateWizard.addons = fetchedAddons.filter(a => a); - if (gUpdateWizard.addons.length < 1) { - gVersionInfoPage.onAllUpdatesFinished(); - return; - } - - gVersionInfoPage._totalCount = gUpdateWizard.addons.length; - - for (let addon of gUpdateWizard.addons) { - logger.debug("VersionInfo Finding updates for ${id}", addon); - addon.findUpdates(gVersionInfoPage, AddonManager.UPDATE_WHEN_NEW_APP_INSTALLED); - } - }), - - onAllUpdatesFinished: function() { - AddonManager.removeAddonListener(listener); - AddonManagerPrivate.recordSimpleMeasure("appUpdate_disabled", - gUpdateWizard.disabled); - AddonManagerPrivate.recordSimpleMeasure("appUpdate_metadata_enabled", - gUpdateWizard.metadataEnabled); - AddonManagerPrivate.recordSimpleMeasure("appUpdate_metadata_disabled", - gUpdateWizard.metadataDisabled); - // Record 0 for these here in case we exit early; values will be replaced - // later if we actually upgrade any. - AddonManagerPrivate.recordSimpleMeasure("appUpdate_upgraded", 0); - AddonManagerPrivate.recordSimpleMeasure("appUpdate_upgradeFailed", 0); - AddonManagerPrivate.recordSimpleMeasure("appUpdate_upgradeDeclined", 0); - // Filter out any add-ons that are now enabled. - let addonList = gUpdateWizard.addons.map(a => a.id + ":" + a.appDisabled); - logger.debug("VersionInfo updates finished: found " + addonList.toSource()); - let filteredAddons = []; - for (let a of gUpdateWizard.addons) { - if (a.appDisabled) { - logger.debug("Continuing with add-on " + a.id); - filteredAddons.push(a); - } - else if (gUpdateWizard.addonInstalls.has(a.id)) { - gUpdateWizard.addonInstalls.get(a.id).cancel(); - gUpdateWizard.addonInstalls.delete(a.id); - } - } - gUpdateWizard.addons = filteredAddons; - - if (gUpdateWizard.shuttingDown) { - // jump directly to updating auto-update add-ons in the background - if (gUpdateWizard.addonInstalls.size > 0) { - let installs = Array.from(gUpdateWizard.addonInstalls.values()); - gInstallingPage.startInstalls(installs); - } - return; - } - - if (filteredAddons.length > 0) { - if (!gUpdateWizard.xpinstallEnabled && gUpdateWizard.xpinstallLocked) { - document.documentElement.currentPage = document.getElementById("adminDisabled"); - return; - } - document.documentElement.currentPage = document.getElementById("mismatch"); - } - else { - logger.info("VersionInfo: No updates require further action"); - // VersionInfo compatibility updates resolved all compatibility problems, - // close this window and continue starting the application... - // XXX Bug 314754 - We need to use setTimeout to close the window due to - // the EM using xmlHttpRequest when checking for updates. - setTimeout(close, 0); - } - }, - - // UpdateListener - onUpdateFinished: function(aAddon, status) { - ++this._completeCount; - - if (status != AddonManager.UPDATE_STATUS_NO_ERROR) { - logger.debug("VersionInfo update " + this._completeCount + " of " + this._totalCount + - " failed for " + aAddon.id + ": " + status); - gUpdateWizard.errorItems.push(aAddon); - } - else { - logger.debug("VersionInfo update " + this._completeCount + " of " + this._totalCount + - " finished for " + aAddon.id); - } - - // If we're not in the background, just make a list of add-ons that have - // updates available - if (!gUpdateWizard.shuttingDown) { - // If we're still in the update check window and the add-on is now active - // then it won't have been disabled by startup - if (aAddon.active) { - AddonManagerPrivate.removeStartupChange(AddonManager.STARTUP_CHANGE_DISABLED, aAddon.id); - gUpdateWizard.metadataEnabled++; - } - - // Update the status text and progress bar - var updateStrings = document.getElementById("updateStrings"); - var statusElt = document.getElementById("versioninfo.status"); - var statusString = updateStrings.getFormattedString("statusPrefix", [aAddon.name]); - statusElt.setAttribute("value", statusString); - - // Update the status text and progress bar - var progress = document.getElementById("versioninfo.progress"); - progress.mode = "normal"; - progress.value = Math.ceil((this._completeCount / this._totalCount) * 100); - } - - if (this._completeCount == this._totalCount) - this.onAllUpdatesFinished(); - }, - - onUpdateAvailable: function(aAddon, aInstall) { - logger.debug("VersionInfo got an install for " + aAddon.id + ": " + aAddon.version); - gUpdateWizard.addonInstalls.set(aAddon.id, aInstall); - }, -}; - -var gMismatchPage = { - waiting: false, - - onPageShow: function() - { - gMismatchPage.waiting = true; - gUpdateWizard.setButtonLabels(null, true, - "mismatchCheckNow", false, - "mismatchDontCheck", false); - document.documentElement.getButton("next").focus(); - - var incompatible = document.getElementById("mismatch.incompatible"); - for (let addon of gUpdateWizard.addons) { - var listitem = document.createElement("listitem"); - listitem.setAttribute("label", addon.name + " " + addon.version); - incompatible.appendChild(listitem); - } - } -}; - -var gUpdatePage = { - _totalCount: 0, - _completeCount: 0, - onPageShow: function() - { - gMismatchPage.waiting = false; - gUpdateWizard.setButtonLabels(null, true, - "nextButtonText", true, - "cancelButtonText", false); - document.documentElement.getButton("next").focus(); - - gUpdateWizard.errorItems = []; - - this._totalCount = gUpdateWizard.addons.length; - for (let addon of gUpdateWizard.addons) { - logger.debug("UpdatePage requesting update for " + addon.id); - // Redundant call to find updates again here when we already got them - // in the VersionInfo page: https://bugzilla.mozilla.org/show_bug.cgi?id=960597 - addon.findUpdates(this, AddonManager.UPDATE_WHEN_NEW_APP_INSTALLED); - } - }, - - onAllUpdatesFinished: function() { - if (gUpdateWizard.shuttingDown) - return; - - var nextPage = document.getElementById("noupdates"); - if (gUpdateWizard.addonsToUpdate.length > 0) - nextPage = document.getElementById("found"); - document.documentElement.currentPage = nextPage; - }, - - // UpdateListener - onUpdateAvailable: function(aAddon, aInstall) { - logger.debug("UpdatePage got an update for " + aAddon.id + ": " + aAddon.version); - gUpdateWizard.addonsToUpdate.push(aInstall); - }, - - onUpdateFinished: function(aAddon, status) { - if (status != AddonManager.UPDATE_STATUS_NO_ERROR) - gUpdateWizard.errorItems.push(aAddon); - - ++this._completeCount; - - if (!gUpdateWizard.shuttingDown) { - // Update the status text and progress bar - var updateStrings = document.getElementById("updateStrings"); - var statusElt = document.getElementById("checking.status"); - var statusString = updateStrings.getFormattedString("statusPrefix", [aAddon.name]); - statusElt.setAttribute("value", statusString); - - var progress = document.getElementById("checking.progress"); - progress.value = Math.ceil((this._completeCount / this._totalCount) * 100); - } - - if (this._completeCount == this._totalCount) - this.onAllUpdatesFinished() - }, -}; - -var gFoundPage = { - onPageShow: function() - { - gUpdateWizard.setButtonLabels(null, true, - "installButtonText", false, - null, false); - - var foundUpdates = document.getElementById("found.updates"); - var itemCount = gUpdateWizard.addonsToUpdate.length; - for (let install of gUpdateWizard.addonsToUpdate) { - let listItem = foundUpdates.appendItem(install.name + " " + install.version); - listItem.setAttribute("type", "checkbox"); - listItem.setAttribute("checked", "true"); - listItem.install = install; - } - - if (!gUpdateWizard.xpinstallEnabled) { - document.getElementById("xpinstallDisabledAlert").hidden = false; - document.getElementById("enableXPInstall").focus(); - document.documentElement.getButton("next").disabled = true; - } - else { - document.documentElement.getButton("next").focus(); - document.documentElement.getButton("next").disabled = false; - } - }, - - toggleXPInstallEnable: function(aEvent) - { - var enabled = aEvent.target.checked; - gUpdateWizard.xpinstallEnabled = enabled; - var pref = Components.classes["@mozilla.org/preferences-service;1"] - .getService(Components.interfaces.nsIPrefBranch); - pref.setBoolPref(PREF_XPINSTALL_ENABLED, enabled); - this.updateNextButton(); - }, - - updateNextButton: function() - { - if (!gUpdateWizard.xpinstallEnabled) { - document.documentElement.getButton("next").disabled = true; - return; - } - - var oneChecked = false; - var foundUpdates = document.getElementById("found.updates"); - var updates = foundUpdates.getElementsByTagName("listitem"); - for (let update of updates) { - if (!update.checked) - continue; - oneChecked = true; - break; - } - - gUpdateWizard.setButtonLabels(null, true, - "installButtonText", true, - null, false); - document.getElementById("found").setAttribute("next", "installing"); - document.documentElement.getButton("next").disabled = !oneChecked; - } -}; - -var gInstallingPage = { - _installs : [], - _errors : [], - _strings : null, - _currentInstall : -1, - _installing : false, - - // Initialize fields we need for installing and tracking progress, - // and start iterating through the installations - startInstalls: function(aInstallList) { - if (!gUpdateWizard.xpinstallEnabled) { - return; - } - - let installs = Array.from(aInstallList).map(a => a.existingAddon.id); - logger.debug("Start installs for " + installs.toSource()); - this._errors = []; - this._installs = aInstallList; - this._installing = true; - this.startNextInstall(); - }, - - onPageShow: function() - { - gUpdateWizard.setButtonLabels(null, true, - "nextButtonText", true, - null, true); - - var foundUpdates = document.getElementById("found.updates"); - var updates = foundUpdates.getElementsByTagName("listitem"); - let toInstall = []; - for (let update of updates) { - if (!update.checked) { - logger.info("User chose to cancel update of " + update.label); - gUpdateWizard.upgradeDeclined++; - update.install.cancel(); - continue; - } - toInstall.push(update.install); - } - this._strings = document.getElementById("updateStrings"); - - this.startInstalls(toInstall); - }, - - startNextInstall: function() { - if (this._currentInstall >= 0) { - this._installs[this._currentInstall].removeListener(this); - } - - this._currentInstall++; - - if (this._installs.length == this._currentInstall) { - Services.obs.notifyObservers(null, "TEST:all-updates-done", null); - AddonManagerPrivate.recordSimpleMeasure("appUpdate_upgraded", - gUpdateWizard.upgraded); - AddonManagerPrivate.recordSimpleMeasure("appUpdate_upgradeFailed", - gUpdateWizard.upgradeFailed); - AddonManagerPrivate.recordSimpleMeasure("appUpdate_upgradeDeclined", - gUpdateWizard.upgradeDeclined); - this._installing = false; - if (gUpdateWizard.shuttingDown) { - return; - } - var nextPage = this._errors.length > 0 ? "installerrors" : "finished"; - document.getElementById("installing").setAttribute("next", nextPage); - document.documentElement.advance(); - return; - } - - let install = this._installs[this._currentInstall]; - - if (gUpdateWizard.shuttingDown && !AddonManager.shouldAutoUpdate(install.existingAddon)) { - logger.debug("Don't update " + install.existingAddon.id + " in background"); - gUpdateWizard.upgradeDeclined++; - install.cancel(); - this.startNextInstall(); - return; - } - install.addListener(this); - install.install(); - }, - - // InstallListener - onDownloadStarted: function(aInstall) { - if (gUpdateWizard.shuttingDown) { - return; - } - var strings = document.getElementById("updateStrings"); - var label = strings.getFormattedString("downloadingPrefix", [aInstall.name]); - var actionItem = document.getElementById("actionItem"); - actionItem.value = label; - }, - - onDownloadProgress: function(aInstall) { - if (gUpdateWizard.shuttingDown) { - return; - } - var downloadProgress = document.getElementById("downloadProgress"); - downloadProgress.value = Math.ceil(100 * aInstall.progress / aInstall.maxProgress); - }, - - onDownloadEnded: function(aInstall) { - }, - - onDownloadFailed: function(aInstall) { - this._errors.push(aInstall); - - gUpdateWizard.upgradeFailed++; - this.startNextInstall(); - }, - - onInstallStarted: function(aInstall) { - if (gUpdateWizard.shuttingDown) { - return; - } - var strings = document.getElementById("updateStrings"); - var label = strings.getFormattedString("installingPrefix", [aInstall.name]); - var actionItem = document.getElementById("actionItem"); - actionItem.value = label; - }, - - onInstallEnded: function(aInstall, aAddon) { - if (!gUpdateWizard.shuttingDown) { - // Remember that this add-on was updated during startup - AddonManagerPrivate.addStartupChange(AddonManager.STARTUP_CHANGE_CHANGED, - aAddon.id); - } - - gUpdateWizard.upgraded++; - this.startNextInstall(); - }, - - onInstallFailed: function(aInstall) { - this._errors.push(aInstall); - - gUpdateWizard.upgradeFailed++; - this.startNextInstall(); - } -}; - -var gInstallErrorsPage = { - onPageShow: function() - { - gUpdateWizard.setButtonLabels(null, true, null, true, null, true); - document.documentElement.getButton("finish").focus(); - }, -}; - -// Displayed when there are incompatible add-ons and the xpinstall.enabled -// pref is false and locked. -var gAdminDisabledPage = { - onPageShow: function() - { - gUpdateWizard.setButtonLabels(null, true, null, true, - "cancelButtonText", true); - document.documentElement.getButton("finish").focus(); - } -}; - -// Displayed when selected add-on updates have been installed without error. -// There can still be add-ons that are not compatible and don't have an update. -var gFinishedPage = { - onPageShow: function() - { - gUpdateWizard.setButtonLabels(null, true, null, true, null, true); - document.documentElement.getButton("finish").focus(); - - if (gUpdateWizard.shouldSuggestAutoChecking) { - document.getElementById("finishedCheckDisabled").hidden = false; - gUpdateWizard.shouldAutoCheck = true; - } - else - document.getElementById("finishedCheckEnabled").hidden = false; - - document.documentElement.getButton("finish").focus(); - } -}; - -// Displayed when there are incompatible add-ons and there are no available -// updates. -var gNoUpdatesPage = { - onPageShow: function(aEvent) - { - gUpdateWizard.setButtonLabels(null, true, null, true, null, true); - if (gUpdateWizard.shouldSuggestAutoChecking) { - document.getElementById("noupdatesCheckDisabled").hidden = false; - gUpdateWizard.shouldAutoCheck = true; - } - else - document.getElementById("noupdatesCheckEnabled").hidden = false; - - gUpdateWizard.checkForErrors("updateCheckErrorNotFound"); - document.documentElement.getButton("finish").focus(); - } -}; diff --git a/toolkit/mozapps/webextensions/content/update.xul b/toolkit/mozapps/webextensions/content/update.xul deleted file mode 100644 index 745983814..000000000 --- a/toolkit/mozapps/webextensions/content/update.xul +++ /dev/null @@ -1,194 +0,0 @@ -<?xml version="1.0"?> - -# -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -<?xml-stylesheet href="chrome://global/skin/" type="text/css"?> -<?xml-stylesheet href="chrome://mozapps/skin/extensions/update.css" type="text/css"?> - -<!DOCTYPE wizard [ -<!ENTITY % updateDTD SYSTEM "chrome://mozapps/locale/extensions/update.dtd"> -<!ENTITY % brandDTD SYSTEM "chrome://branding/locale/brand.dtd"> -%updateDTD; -%brandDTD; -]> - -<wizard id="updateWizard" - xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" - title="&updateWizard.title;" - windowtype="Addons:Compatibility" - branded="true" - onload="gUpdateWizard.init();" - onwizardfinish="gUpdateWizard.onWizardFinish();" - onwizardcancel="return gUpdateWizard.onWizardCancel();" - onclose="return gUpdateWizard.onWizardClose(event);" - buttons="accept,cancel"> - - <script type="application/javascript" src="chrome://mozapps/content/extensions/update.js"/> - - <stringbundleset id="updateSet"> - <stringbundle id="brandStrings" src="chrome://branding/locale/brand.properties"/> - <stringbundle id="updateStrings" src="chrome://mozapps/locale/extensions/update.properties"/> - </stringbundleset> - - <wizardpage id="dummy" pageid="dummy"/> - - <wizardpage id="offline" pageid="offline" next="versioninfo" - label="&offline.title;" - onpageadvanced="return gOfflinePage.onPageAdvanced();"> - <description>&offline.description;</description> - <checkbox id="toggleOffline" - checked="true" - label="&offline.toggleOffline.label;" - accesskey="&offline.toggleOffline.accesskey;" - oncommand="gOfflinePage.toggleOffline();"/> - </wizardpage> - - <wizardpage id="versioninfo" pageid="versioninfo" next="mismatch" - label="&versioninfo.wizard.title;" - onpageshow="gVersionInfoPage.onPageShow();"> - <label>&versioninfo.top.label;</label> - <separator class="thin"/> - <progressmeter id="versioninfo.progress" mode="undetermined"/> - <hbox align="center"> - <image id="versioninfo.throbber" class="throbber"/> - <label flex="1" id="versioninfo.status" crop="right">&versioninfo.waiting;</label> - </hbox> - <separator/> - </wizardpage> - - <wizardpage id="mismatch" pageid="mismatch" next="checking" - label="&mismatch.win.title;" - onpageshow="gMismatchPage.onPageShow();"> - <label>&mismatch.top.label;</label> - <separator class="thin"/> - <listbox id="mismatch.incompatible" flex="1"/> - <separator class="thin"/> - <label>&mismatch.bottom.label;</label> - </wizardpage> - - <wizardpage id="checking" pageid="checking" next="noupdates" - label="&checking.wizard.title;" - onpageshow="gUpdatePage.onPageShow();"> - <label>&checking.top.label;</label> - <separator class="thin"/> - <progressmeter id="checking.progress"/> - <hbox align="center"> - <image id="checking.throbber" class="throbber"/> - <label id="checking.status" flex="1" crop="right">&checking.status;</label> - </hbox> - </wizardpage> - - <wizardpage id="noupdates" pageid="noupdates" - label="&noupdates.wizard.title;" - onpageshow="gNoUpdatesPage.onPageShow();"> - <description>&noupdates.intro.desc;</description> - <separator class="thin"/> - <hbox id="updateCheckErrorNotFound" class="alertBox" hidden="true" align="top"> - <description flex="1">&noupdates.error.desc;</description> - </hbox> - <separator class="thin"/> - <description id="noupdatesCheckEnabled" hidden="true"> - &noupdates.checkEnabled.desc; - </description> - <vbox id="noupdatesCheckDisabled" hidden="true"> - <description>&finished.checkDisabled.desc;</description> - <checkbox label="&enableChecking.label;" checked="true" - oncommand="gUpdateWizard.shouldAutoCheck = this.checked;"/> - </vbox> - <separator flex="1"/> -#ifndef XP_MACOSX - <label>&clickFinish.label;</label> -#else - <label>&clickFinish.labelMac;</label> -#endif - <separator class="thin"/> - </wizardpage> - - <wizardpage id="found" pageid="found" next="installing" - label="&found.wizard.title;" - onpageshow="gFoundPage.onPageShow();"> - <label>&found.top.label;</label> - <separator class="thin"/> - <listbox id="found.updates" flex="1" seltype="multiple" - onclick="gFoundPage.updateNextButton();"/> - <separator class="thin"/> - <vbox align="left" id="xpinstallDisabledAlert" hidden="true"> - <description>&found.disabledXPinstall.label;</description> - <checkbox label="&found.enableXPInstall.label;" - id="enableXPInstall" - accesskey="&found.enableXPInstall.accesskey;" - oncommand="gFoundPage.toggleXPInstallEnable(event);"/> - </vbox> - </wizardpage> - - <wizardpage id="installing" pageid="installing" next="finished" - label="&installing.wizard.title;" - onpageshow="gInstallingPage.onPageShow();"> - <label>&installing.top.label;</label> - <progressmeter id="downloadProgress"/> - <hbox align="center"> - <image id="installing.throbber" class="throbber"/> - <label id="actionItem" flex="1" crop="right"/> - </hbox> - <separator/> - </wizardpage> - - <wizardpage id="installerrors" pageid="installerrors" - label="&installerrors.wizard.title;" - onpageshow="gInstallErrorsPage.onPageShow();"> - <hbox align="top" class="alertBox"> - <description flex="1">&installerrors.intro.label;</description> - </hbox> - <separator flex="1"/> -#ifndef XP_MACOSX - <label>&clickFinish.label;</label> -#else - <label>&clickFinish.labelMac;</label> -#endif - <separator class="thin"/> - </wizardpage> - - <wizardpage id="adminDisabled" pageid="adminDisabled" - label="&adminDisabled.wizard.title;" - onpageshow="gAdminDisabledPage.onPageShow();"> - <separator/> - <hbox class="alertBox" align="top"> - <description flex="1">&adminDisabled.warning.label;</description> - </hbox> - <separator flex="1"/> -#ifndef XP_MACOSX - <label>&clickFinish.label;</label> -#else - <label>&clickFinish.labelMac;</label> -#endif - <separator class="thin"/> - </wizardpage> - - <wizardpage id="finished" pageid="finished" - label="&finished.wizard.title;" - onpageshow="gFinishedPage.onPageShow();"> - - <label>&finished.top.label;</label> - <separator/> - <description id="finishedCheckEnabled" hidden="true"> - &finished.checkEnabled.desc; - </description> - <vbox id="finishedCheckDisabled" hidden="true"> - <description>&finished.checkDisabled.desc;</description> - <checkbox label="&enableChecking.label;" checked="true" - oncommand="gUpdateWizard.shouldAutoCheck = this.checked;"/> - </vbox> - <separator flex="1"/> -#ifndef XP_MACOSX - <label>&clickFinish.label;</label> -#else - <label>&clickFinish.labelMac;</label> -#endif - <separator class="thin"/> - </wizardpage> - -</wizard> - |