Bug 540030 - Display the error and hide the progress bar if an add-on install fails in the Add-on Manager [r=gavin.sharp]
--- a/chrome/content/bindings/extensions.xml
+++ b/chrome/content/bindings/extensions.xml
@@ -16,22 +16,22 @@
<content orient="vertical">
<xul:hbox align="start">
<xul:image xbl:inherits="src=iconURL"/>
<xul:vbox flex="1">
<xul:hbox align="center">
<xul:label class="title" xbl:inherits="value=name"/>
<xul:label class="normal" xbl:inherits="value=version"/>
<xul:spacer flex="1"/>
- <xul:label class="normal" crop="end" xbl:inherits="value=typeLabel"/>
+ <xul:label class="normal" crop="end" xbl:inherits="value=typeLabel"/>
</xul:hbox>
<xul:vbox>
<xul:label class="normal hide-on-select" xbl:inherits="value=description" crop="end" flex="1"/>
<xul:description class="normal show-on-select" xbl:inherits="xbl:text=description" flex="1"/>
- <xul:label class="normal-bold" xbl:inherits="value=updateStatus"/>
+ <xul:label class="normal-bold" xbl:inherits="value=updateStatus"/>
</xul:vbox>
</xul:vbox>
</xul:hbox>
<xul:hbox class="show-on-select buttons-box">
<xul:button anonid="options-button" type="checkbox" class="addon-options" label="&addonOptions.label;"
oncommand="document.getBindingParent(this).toggleOptions();"/>
<xul:spacer flex="1"/>
<xul:button anonid="enable-button" class="show-on-disable hide-on-enable hide-on-uninstall addon-enable" label="&addonEnable.label;"
@@ -94,33 +94,33 @@
// retrieve the extensions prefs
let optionsURL = this.getAttribute("optionsURL");
let xhr = new XMLHttpRequest();
xhr.open("GET", optionsURL, false);
xhr.send();
if (!xhr.responseXML)
return;
-
+
let currentNode;
let nodeIterator = xhr.responseXML.createNodeIterator(xhr.responseXML,
NodeFilter.SHOW_TEXT,
null,
false);
while (currentNode = nodeIterator.nextNode()) {
let trimmed = currentNode.nodeValue.replace(/^\s\s*/, "").replace(/\s\s*$/, "");
if (!trimmed.length)
currentNode.parentNode.removeChild(currentNode);
}
// Only allow <setting> for now
let prefs = xhr.responseXML.querySelectorAll(":root > setting");
for (let i = 0; i < prefs.length; i++)
box.appendChild(prefs.item(i));
-
+
// Send an event so add-ons can prepopulate any non-preference based
// settings
let event = document.createEvent("Events");
event.initEvent("AddonOptionsLoad", true, false);
this.dispatchEvent(event);
]]>
</body>
</method>
@@ -130,17 +130,17 @@
<binding id="extension-searchplugin" extends="chrome://browser/content/bindings.xml#richlistitem">
<content orient="vertical">
<xul:hbox align="start">
<xul:image width="32" height="32" xbl:inherits="src=iconURL"/>
<xul:vbox flex="1">
<xul:hbox align="center">
<xul:label class="title" xbl:inherits="value=name"/>
<xul:spacer flex="1"/>
- <xul:label class="normal" crop="end" xbl:inherits="value=typeLabel"/>
+ <xul:label class="normal" crop="end" xbl:inherits="value=typeLabel"/>
</xul:hbox>
<xul:vbox>
<xul:label class="normal hide-on-select" xbl:inherits="value=description" crop="end" flex="1"/>
<xul:description class="normal show-on-select" xbl:inherits="xbl:text=description" flex="1"/>
</xul:vbox>
</xul:vbox>
</xul:hbox>
<xul:hbox class="show-on-select">
@@ -150,17 +150,17 @@
<xul:button class="show-on-enable hide-on-disable hide-on-uninstall addon-disable" label="&addonDisable.label;"
oncommand="ExtensionsView.disable(document.getBindingParent(this));"/>
<xul:button anonid="uninstall-button" class="hide-on-uninstall addon-uninstall" label="&addonUninstall.label;"
oncommand="ExtensionsView.uninstall(document.getBindingParent(this));"/>
<xul:button class="show-on-uninstall addon-cancel" label="&addonCancel.label;"
oncommand="ExtensionsView.cancelUninstall(document.getBindingParent(this));"/>
</xul:hbox>
</content>
-
+
<implementation>
<constructor>
<![CDATA[
let appManaged = this.getAttribute("appManaged");
if (appManaged == "true")
document.getAnonymousElementByAttribute(this, "anonid", "uninstall-button").setAttribute("disabled", "true");
]]>
</constructor>
@@ -171,21 +171,22 @@
<content orient="vertical">
<xul:hbox align="start">
<xul:image xbl:inherits="src=iconURL"/>
<xul:vbox flex="1">
<xul:hbox align="center">
<xul:label class="title" xbl:inherits="value=name"/>
<xul:label class="normal" xbl:inherits="value=version"/>
<xul:spacer flex="1"/>
- <xul:hbox class="addon-type-or-rating" align="center" xbl:inherits="rating"/>
+ <xul:hbox class="addon-type-or-rating" align="center" xbl:inherits="rating"/>
</xul:hbox>
<xul:vbox>
<xul:label class="normal hide-on-select" xbl:inherits="value=description" crop="end" flex="1"/>
<xul:description class="normal show-on-select" xbl:inherits="xbl:text=description" flex="1"/>
+ <xul:label class="normal-bold show-on-error" xbl:inherits="value=error"/>
</xul:vbox>
</xul:vbox>
</xul:hbox>
<xul:vbox flex="1">
<xul:hbox class="show-on-select">
<xul:button class="addon-install hide-on-install hide-on-restart" label="&addonShowPage.label;"
oncommand="ExtensionsView.showPage(document.getBindingParent(this));"/>
<xul:spacer flex="1"/>
--- a/chrome/content/browser.css
+++ b/chrome/content/browser.css
@@ -144,23 +144,25 @@ richlistitem[typeName="download"][state=
}
richlistitem[typeName="download"][state="4"] {
-moz-binding: url("chrome://browser/content/bindings/downloads.xml#download-paused");
}
/* addons states ----------------------------------------------------------- */
.hide-on-enable,
+.show-on-error,
.show-on-uninstall,
.show-on-install,
.show-on-restart,
richlistitem[isDisabled="true"] .hide-on-disable {
display: none;
}
+richlistitem[error] .show-on-error,
richlistitem[opType="needs-restart"] .show-on-restart,
richlistitem[opType="needs-uninstall"] .show-on-uninstall,
richlistitem[opType="needs-install"] .show-on-install,
richlistitem[opType="needs-enable"] .show-on-enable,
richlistitem[opType="needs-disable"] .show-on-disable,
richlistitem[isDisabled="true"] .show-on-disable {
display: -moz-box;
}
--- a/chrome/content/extensions.js
+++ b/chrome/content/extensions.js
@@ -189,24 +189,24 @@ var ExtensionsView = {
let item = this.getElementForAddon(aID);
if (!item)
return;
// if the element is not the selected element, select it
if (item != this._list.selectedItem)
this._list.selectedItem = item;
-
+
item.showOptions();
},
hideOptions: function ev_hideOptions() {
if (!this._list)
return;
-
+
let items = this._list.childNodes;
for (let i = 0; i < items.length; i++) {
let item = items[i];
if (item.hideOptions)
item.hideOptions();
}
this._list.ensureSelectedElementIsVisible();
},
@@ -284,17 +284,17 @@ var ExtensionsView = {
},
uninit: function ev_uninit() {
var os = Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService);
os.removeObserver(this._dloadmgr, "xpinstall-download-started");
this._extmgr.removeInstallListenerAt(this._observerIndex);
},
-
+
hideOnSelect: function ev_handleEvent(aEvent) {
// When list selection changes, be sure to close up any open options sections
if (aEvent.target == this._list)
this.hideOptions();
},
getAddonsFromLocal: function ev_getAddonsFromLocal() {
this.clearSection("local");
@@ -318,17 +318,17 @@ var ExtensionsView = {
listitem.setAttribute("appDisabled", appDisabled);
listitem.setAttribute("appManaged", appManaged);
listitem.setAttribute("description", desc);
listitem.setAttribute("optionsURL", optionsURL);
listitem.setAttribute("opType", opType);
listitem.setAttribute("updateable", updateable);
this._list.insertBefore(listitem, this._repoItem);
}
-
+
// Load the search engines
let defaults = this._search.getDefaultEngines({ }).map(function (e) e.name);
function isDefault(aEngine)
defaults.indexOf(aEngine.name) != -1
let strings = Elements.browserBundle;
let defaultDescription = strings.getString("addonsSearchEngine.description");
@@ -389,17 +389,17 @@ var ExtensionsView = {
this._extmgr.disableItem(id);
opType = this._getRDFProperty(id, "opType");
if (opType == "needs-disable")
this.showRestart();
else
this.hideRestart();
}
-
+
aItem.setAttribute("opType", opType);
},
uninstall: function ev_uninstall(aItem) {
let opType;
if (aItem.getAttribute("type") == "1024") {
// Make sure the engine isn't hidden before removing it, to make sure it's
// visible if the user later re-adds it (works around bug 341833)
@@ -425,20 +425,31 @@ var ExtensionsView = {
this.hideRestart();
let opType = this._getRDFProperty(id, "opType");
aItem.setAttribute("opType", opType);
},
_installCallback: function ev__installCallback(aItem, aStatus) {
if (aStatus == -210) {
- // TODO: User cancelled
+ // User cancelled
+ aItem.removeAttribute("opType");
}
else if (aStatus < 0) {
- // TODO: Some other error
+ // Some other error
+ aItem.removeAttribute("opType");
+ let bundles = Cc["@mozilla.org/intl/stringbundle;1"].getService(Ci.nsIStringBundleService);
+ let strings = bundles.createBundle("chrome://global/locale/xpinstall/xpinstall.properties");
+
+ try {
+ var msg = strings.GetStringFromName("error" + aStatus);
+ } catch (ex) {
+ msg = strings.formatStringFromName("unknown.error", [aStatus]);
+ }
+ aItem.setAttribute("error", msg);
}
else {
// Success
aItem.setAttribute("opType", "needs-restart");
}
},
installFromRepo: function ev_installFromRepo(aItem) {
@@ -536,17 +547,17 @@ var ExtensionsView = {
let strings = Elements.browserBundle;
if (aAddons.length == 0) {
let msg = aIsRecommended ? strings.getString("addonsSearchNone.recommended") :
strings.getString("addonsSearchNone.search");
let button = aIsRecommended ? strings.getString("addonsSearchNone.button") :
strings.getString("addonsSearchSuccess2.button");
let item = this.displaySectionMessage("repo", msg, button, true);
-
+
if (aSelectFirstResult)
this._list.scrollBoxObject.scrollToElement(item);
return;
}
if (aIsRecommended) {
// Locale sensitive sort
function compare(a, b) {
@@ -600,17 +611,17 @@ var ExtensionsView = {
this.searchBox.value = aTerms;
this.getAddonsFromRepo(aTerms, true);
},
resetSearch: function ev_resetSearch() {
this.searchBox.value = "";
this.getAddonsFromRepo("");
},
-
+
updateAll: function ev_updateAll() {
if (!this._isXPInstallEnabled())
return;
// Make sure we're online before attempting to load
Util.forceOnline();
// To support custom views we check the add-ons displayed in the list
@@ -618,25 +629,25 @@ var ExtensionsView = {
let start = this._localItem.nextSibling;
let end = this._repoItem;
while (start != end) {
if (start.getAttribute("updateable") == "true")
items.push(this._extmgr.getItemForID(start.getAttribute("addonID")));
start = start.nextSibling;
}
-
+
if (items.length > 0) {
let listener = new UpdateCheckListener();
this._extmgr.update(items, items.length, Ci.nsIExtensionManager.UPDATE_CHECK_NEWVERSION, listener);
}
-
+
if (this._list.selectedItem)
this._list.selectedItem.focus();
-
+
this._pref.setBoolPref("extensions.update.notifyUser", false);
}
};
function searchFailed() {
ExtensionsView.clearSection("repo");
@@ -752,17 +763,17 @@ XPInstallDownloadManager.prototype = {
if (!ExtensionsView.visible)
return;
var element = ExtensionsView.getElementForAddon(aAddon.id);
if (!element)
return;
element.setAttribute("status", (Components.isSuccessCode(aStatus) ? "success" : "fail"));
-
+
// If we are updating an add-on, change the status
if (element.hasAttribute("updating")) {
let strings = Elements.browserBundle;
element.setAttribute("updateStatus", strings.getFormattedString("addonUpdate.updated", [aAddon.version]));
element.removeAttribute("updating");
}
},
@@ -848,17 +859,17 @@ UpdateCheckListener.prototype = {
let strings = Elements.browserBundle;
let element = document.getElementById(PREFIX_ITEM_URI + aAddon.id);
element.setAttribute("updateStatus", strings.getString("addonUpdate.checking"));
},
onAddonUpdateEnded: function ucl_onAddonUpdateEnded(aAddon, aStatus) {
if (!document)
return;
-
+
let strings = Elements.browserBundle;
let element = document.getElementById(PREFIX_ITEM_URI + aAddon.id);
let updateable = false;
const nsIAUCL = Ci.nsIAddonUpdateCheckListener;
switch (aStatus) {
case nsIAUCL.STATUS_UPDATE:
var statusMsg = strings.getFormattedString("addonUpdate.updating", [aAddon.version]);
updateable = true;
@@ -896,9 +907,8 @@ UpdateCheckListener.prototype = {
QueryInterface: function ucl_QueryInterface(aIID) {
if (!aIID.equals(Ci.nsIAddonUpdateCheckListener) &&
!aIID.equals(Ci.nsISupports))
throw Components.results.NS_ERROR_NO_INTERFACE;
return this;
}
};
-