зеркало из https://github.com/mozilla/pjs.git
Bug 553494: Support undo uninstall for restartless and already disabled add-ons. r=Unfocused
This commit is contained in:
Родитель
bd43b606f3
Коммит
7f36d053d4
|
@ -133,8 +133,8 @@ function shutdown() {
|
|||
}
|
||||
|
||||
// Used by external callers to load a specific view into the manager
|
||||
function loadView(url) {
|
||||
gViewController.loadView(url);
|
||||
function loadView(aViewId, aCallback) {
|
||||
gViewController.loadView(aViewId, aCallback);
|
||||
}
|
||||
|
||||
var gEventManager = {
|
||||
|
@ -253,6 +253,7 @@ var gViewController = {
|
|||
currentViewRequest: 0,
|
||||
previousViewId: "",
|
||||
viewObjects: {},
|
||||
viewChangeCallback: null,
|
||||
|
||||
initialize: function() {
|
||||
this.viewPort = document.getElementById("view-port");
|
||||
|
@ -269,6 +270,8 @@ var gViewController = {
|
|||
},
|
||||
|
||||
shutdown: function() {
|
||||
if (this.currentViewObj)
|
||||
this.currentViewObj.hide();
|
||||
this.currentViewRequest = 0;
|
||||
},
|
||||
|
||||
|
@ -282,7 +285,7 @@ var gViewController = {
|
|||
return this.currentViewObj.node.hasAttribute("loading");
|
||||
},
|
||||
|
||||
loadView: function(aViewId) {
|
||||
loadView: function(aViewId, aCallback) {
|
||||
if (aViewId == this.currentViewId)
|
||||
return;
|
||||
|
||||
|
@ -314,6 +317,8 @@ var gViewController = {
|
|||
this.currentViewId = aViewId;
|
||||
this.currentViewObj = viewObj;
|
||||
|
||||
this.viewChangeCallback = aCallback;
|
||||
|
||||
this.viewPort.selectedPanel = this.currentViewObj.node;
|
||||
this.viewPort.selectedPanel.setAttribute("loading", "true");
|
||||
this.currentViewObj.show(view.param, ++this.currentViewRequest);
|
||||
|
@ -321,6 +326,10 @@ var gViewController = {
|
|||
|
||||
notifyViewChanged: function() {
|
||||
this.viewPort.selectedPanel.removeAttribute("loading");
|
||||
|
||||
if (this.viewChangeCallback)
|
||||
this.viewChangeCallback();
|
||||
|
||||
var event = document.createEvent("Events");
|
||||
event.initEvent("ViewChanged", true, true);
|
||||
this.currentViewObj.node.dispatchEvent(event);
|
||||
|
@ -527,7 +536,14 @@ var gViewController = {
|
|||
return hasPermission(aAddon, "uninstall");
|
||||
},
|
||||
doCommand: function(aAddon) {
|
||||
aAddon.uninstall();
|
||||
if (gViewController.currentViewObj != gDetailView) {
|
||||
aAddon.uninstall();
|
||||
return;
|
||||
}
|
||||
|
||||
gViewController.loadView(gViewController.previousViewId, function() {
|
||||
gViewController.currentViewObj.getListItemForID(aAddon.id).uninstall();
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -1077,7 +1093,15 @@ var gSearchView = {
|
|||
gViewController.updateCommands();
|
||||
},
|
||||
|
||||
hide: function() { },
|
||||
hide: function() {
|
||||
var listitem = this._listBox.firstChild;
|
||||
while (listitem) {
|
||||
if (listitem.getAttribute("status") == "uninstalled" &&
|
||||
!listitem.isPending("uninstall"))
|
||||
listitem.mAddon.uninstall();
|
||||
listitem = listitem.nextSibling;
|
||||
}
|
||||
},
|
||||
|
||||
getMatchScore: function(aObj, aQuery) {
|
||||
var score = 0;
|
||||
|
@ -1144,8 +1168,16 @@ var gSearchView = {
|
|||
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;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
@ -1213,6 +1245,14 @@ var gListView = {
|
|||
|
||||
hide: function() {
|
||||
gEventManager.unregisterInstallListener(this);
|
||||
|
||||
var listitem = this._listBox.firstChild;
|
||||
while (listitem) {
|
||||
if (listitem.getAttribute("status") == "uninstalled" &&
|
||||
!listitem.isPending("uninstall"))
|
||||
listitem.mAddon.uninstall();
|
||||
listitem = listitem.nextSibling;
|
||||
}
|
||||
},
|
||||
|
||||
showEmptyNotice: function(aShow) {
|
||||
|
@ -1266,6 +1306,15 @@ var gListView = {
|
|||
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;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -711,6 +711,14 @@
|
|||
]]></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[
|
||||
|
@ -718,6 +726,12 @@
|
|||
return !!(this.mAddon.pendingOperations & action);
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
<method name="onUninstalled">
|
||||
<body><![CDATA[
|
||||
this.parentNode.removeChild(this);
|
||||
]]></body>
|
||||
</method>
|
||||
</implementation>
|
||||
</binding>
|
||||
|
||||
|
@ -1031,8 +1045,18 @@
|
|||
|
||||
<method name="uninstall">
|
||||
<body><![CDATA[
|
||||
this.mAddon.uninstall();
|
||||
]]></body>
|
||||
// If uninstalling does not require a restart then just disable it
|
||||
// and show the undo UI.
|
||||
if (!this.opRequiresRestart("uninstall")) {
|
||||
// This won't update any other add-on manager views (bug 582002)
|
||||
this.setAttribute("wasDisabled", this.mAddon.userDisabled);
|
||||
this.setAttribute("restartrequired", false);
|
||||
this.setAttribute("status", "uninstalled");
|
||||
this.mAddon.userDisabled = true;
|
||||
} else {
|
||||
this.mAddon.uninstall();
|
||||
}
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
<method name="showPreferences">
|
||||
|
@ -1175,9 +1199,17 @@
|
|||
|
||||
<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("restartrequired");
|
||||
this.mAddon.userDisabled = false;
|
||||
this.mAddon.cancelUninstall();
|
||||
this.setAttribute("status", "installed");
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
|
|
|
@ -56,6 +56,7 @@ _TEST_FILES = \
|
|||
browser_searching.xml \
|
||||
browser_searching_empty.xml \
|
||||
browser_sorting.js \
|
||||
browser_uninstalling.js \
|
||||
browser_updatessl.js \
|
||||
browser_updatessl.rdf \
|
||||
browser_installssl.js \
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -282,6 +282,7 @@ MockProvider.prototype = {
|
|||
*/
|
||||
addAddon: function MP_addAddon(aAddon) {
|
||||
this.addons.push(aAddon);
|
||||
aAddon._provider = this;
|
||||
|
||||
if (!this.started)
|
||||
return;
|
||||
|
@ -292,6 +293,28 @@ MockProvider.prototype = {
|
|||
null, requiresRestart)
|
||||
},
|
||||
|
||||
/**
|
||||
* Removes an add-on from the list of add-ons that this provider exposes to
|
||||
* the AddonManager, dispatching the onUninstalled event in the process.
|
||||
*
|
||||
* @param aAddon
|
||||
* The add-on to add
|
||||
*/
|
||||
removeAddon: function MP_removeAddon(aAddon) {
|
||||
var pos = this.addons.indexOf(aAddon);
|
||||
if (pos == -1) {
|
||||
ok(false, "Tried to remove an add-on that wasn't registered with the mock provider");
|
||||
return;
|
||||
}
|
||||
|
||||
this.addons.splice(pos, 1);
|
||||
|
||||
if (!this.started)
|
||||
return;
|
||||
|
||||
AddonManagerPrivate.callAddonListeners("onUninstalled", aAddon);
|
||||
},
|
||||
|
||||
/**
|
||||
* Adds an add-on install to the list of installs that this provider exposes
|
||||
* to the AddonManager, dispatching appropriate events in the process.
|
||||
|
@ -588,12 +611,15 @@ function MockAddon(aId, aName, aType, aOperationsRequiringRestart) {
|
|||
this.providesUpdatesSecurely = true;
|
||||
this.blocklistState = 0;
|
||||
this.appDisabled = false;
|
||||
this.userDisabled = false;
|
||||
this._userDisabled = false;
|
||||
this.scope = AddonManager.SCOPE_PROFILE;
|
||||
this.isActive = true;
|
||||
this.creator = "";
|
||||
this.pendingOperations = 0;
|
||||
this.permissions = 0;
|
||||
this.permissions = AddonManager.PERM_CAN_UNINSTALL |
|
||||
AddonManager.PERM_CAN_ENABLE |
|
||||
AddonManager.PERM_CAN_DISABLE |
|
||||
AddonManager.PERM_CAN_UPGRADE;
|
||||
this.operationsRequiringRestart = aOperationsRequiringRestart ||
|
||||
(AddonManager.OP_NEEDS_RESTART_INSTALL |
|
||||
AddonManager.OP_NEEDS_RESTART_UNINSTALL |
|
||||
|
@ -602,6 +628,26 @@ function MockAddon(aId, aName, aType, aOperationsRequiringRestart) {
|
|||
}
|
||||
|
||||
MockAddon.prototype = {
|
||||
get shouldBeActive() {
|
||||
return !this.appDisabled && !this._userDisabled;
|
||||
},
|
||||
|
||||
get userDisabled() {
|
||||
return this._userDisabled;
|
||||
},
|
||||
|
||||
set userDisabled(val) {
|
||||
if (val == this._userDisabled)
|
||||
return val;
|
||||
|
||||
var currentActive = this.shouldBeActive;
|
||||
this._userDisabled = val;
|
||||
var newActive = this.shouldBeActive;
|
||||
this._updateActiveState(currentActive, newActive);
|
||||
|
||||
return val;
|
||||
},
|
||||
|
||||
isCompatibleWith: function(aAppVersion, aPlatformVersion) {
|
||||
return true;
|
||||
},
|
||||
|
@ -611,11 +657,53 @@ MockAddon.prototype = {
|
|||
},
|
||||
|
||||
uninstall: function() {
|
||||
// To be implemented when needed
|
||||
if (this.pendingOperations & AddonManager.PENDING_UNINSTALL)
|
||||
throw new Error("Add-on is already pending uninstall");
|
||||
|
||||
var needsRestart = !!(this.operationsRequiringRestart & AddonManager.OP_NEEDS_RESTART_UNINSTALL);
|
||||
this.pendingOperations |= AddonManager.PENDING_UNINSTALL;
|
||||
AddonManagerPrivate.callAddonListeners("onUninstalling", this, needsRestart);
|
||||
if (!needsRestart) {
|
||||
this.pendingOperations -= AddonManager.PENDING_UNINSTALL;
|
||||
this._provider.removeAddon(this);
|
||||
}
|
||||
},
|
||||
|
||||
cancelUninstall: function() {
|
||||
// To be implemented when needed
|
||||
if (!(this.pendingOperations & AddonManager.PENDING_UNINSTALL))
|
||||
throw new Error("Add-on is not pending uninstall");
|
||||
|
||||
this.pendingOperations -= AddonManager.PENDING_UNINSTALL;
|
||||
AddonManagerPrivate.callAddonListeners("onOperationCancelled", this);
|
||||
},
|
||||
|
||||
_updateActiveState: function(currentActive, newActive) {
|
||||
if (currentActive == newActive)
|
||||
return;
|
||||
|
||||
if (newActive == this.isActive) {
|
||||
AddonManagerPrivate.callAddonListeners("onOperationCancelled", this);
|
||||
}
|
||||
else if (newActive) {
|
||||
var needsRestart = !!(this.operationsRequiringRestart & AddonManager.OP_NEEDS_RESTART_ENABLE);
|
||||
this.pendingOperations |= AddonManager.PENDING_ENABLE;
|
||||
AddonManagerPrivate.callAddonListeners("onEnabling", this, needsRestart);
|
||||
if (!needsRestart) {
|
||||
this.isActive = newActive;
|
||||
this.pendingOperations -= AddonManager.PENDING_ENABLE;
|
||||
AddonManagerPrivate.callAddonListeners("onEnabled", this);
|
||||
}
|
||||
}
|
||||
else {
|
||||
var needsRestart = !!(this.operationsRequiringRestart & AddonManager.OP_NEEDS_RESTART_DISABLE);
|
||||
this.pendingOperations |= AddonManager.PENDING_DISABLE;
|
||||
AddonManagerPrivate.callAddonListeners("onDisabling", this, needsRestart);
|
||||
if (!needsRestart) {
|
||||
this.isActive = newActive;
|
||||
this.pendingOperations -= AddonManager.PENDING_DISABLE;
|
||||
AddonManagerPrivate.callAddonListeners("onDisabled", this);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче