summaryrefslogtreecommitdiffstats
path: root/toolkit/mozapps/webextensions/content/extensions.xml
diff options
context:
space:
mode:
authorMatt A. Tobin <email@mattatobin.com>2018-02-10 02:49:12 -0500
committerMatt A. Tobin <email@mattatobin.com>2018-02-10 02:49:12 -0500
commit4fb11cd5966461bccc3ed1599b808237be6b0de9 (patch)
treed7f0ccd49cebb3544d52635ff1bd6ed4d763823f /toolkit/mozapps/webextensions/content/extensions.xml
parentf164d9124708b50789dbb6959e1de96cc5697c48 (diff)
downloadUXP-4fb11cd5966461bccc3ed1599b808237be6b0de9.tar
UXP-4fb11cd5966461bccc3ed1599b808237be6b0de9.tar.gz
UXP-4fb11cd5966461bccc3ed1599b808237be6b0de9.tar.lz
UXP-4fb11cd5966461bccc3ed1599b808237be6b0de9.tar.xz
UXP-4fb11cd5966461bccc3ed1599b808237be6b0de9.zip
Move WebExtensions enabled Add-ons Manager
Diffstat (limited to 'toolkit/mozapps/webextensions/content/extensions.xml')
-rw-r--r--toolkit/mozapps/webextensions/content/extensions.xml2008
1 files changed, 2008 insertions, 0 deletions
diff --git a/toolkit/mozapps/webextensions/content/extensions.xml b/toolkit/mozapps/webextensions/content/extensions.xml
new file mode 100644
index 000000000..b49645cf0
--- /dev/null
+++ b/toolkit/mozapps/webextensions/content/extensions.xml
@@ -0,0 +1,2008 @@
+<?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>