зеркало из https://github.com/mozilla/gecko-dev.git
Bug 572561: Addons Manager hides Language category if there are no locale packs installed but some are pending install. r=Unfocused, r=dtownsend
This commit is contained in:
Родитель
4170a7ca93
Коммит
fce042dceb
|
@ -88,6 +88,9 @@ XPCOMUtils.defineLazyGetter(gStrings, "appVersion", function() {
|
|||
window.addEventListener("load", initialize, false);
|
||||
window.addEventListener("unload", shutdown, false);
|
||||
|
||||
var gPendingInitializations = 1;
|
||||
__defineGetter__("gIsInitializing", function() gPendingInitializations > 0);
|
||||
|
||||
function initialize() {
|
||||
gCategories.initialize();
|
||||
gHeader.initialize();
|
||||
|
@ -105,6 +108,19 @@ function initialize() {
|
|||
}
|
||||
|
||||
gViewController.loadView(view);
|
||||
notifyInitialized();
|
||||
}
|
||||
|
||||
function notifyInitialized() {
|
||||
if (!gIsInitializing)
|
||||
return;
|
||||
|
||||
gPendingInitializations--;
|
||||
if (!gIsInitializing) {
|
||||
var event = document.createEvent("Events");
|
||||
event.initEvent("Initialized", true, true);
|
||||
document.dispatchEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
function shutdown() {
|
||||
|
@ -258,6 +274,10 @@ var gViewController = {
|
|||
return {type: viewType, param: decodeURIComponent(viewParam)};
|
||||
},
|
||||
|
||||
get isLoading() {
|
||||
return this.currentViewObj.node.hasAttribute("loading");
|
||||
},
|
||||
|
||||
loadView: function(aViewId) {
|
||||
if (aViewId == this.currentViewId)
|
||||
return;
|
||||
|
@ -616,6 +636,39 @@ function createItem(aObj, aIsInstall, aRequiresRestart) {
|
|||
return item;
|
||||
}
|
||||
|
||||
function getAddonsAndInstalls(aType, aCallback) {
|
||||
var addonTypes = null, installTypes = null;
|
||||
if (aType != null) {
|
||||
addonTypes = [aType];
|
||||
installTypes = [aType];
|
||||
if (aType == "extension") {
|
||||
addonTypes.push("bootstrapped");
|
||||
installTypes = addonTypes.concat("");
|
||||
}
|
||||
}
|
||||
|
||||
var addons = null, installs = null;
|
||||
|
||||
AddonManager.getAddonsByTypes(addonTypes, function(aAddonsList) {
|
||||
addons = aAddonsList;
|
||||
if (installs != null)
|
||||
aCallback(addons, installs);
|
||||
});
|
||||
|
||||
AddonManager.getInstallsByTypes(installTypes, 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)
|
||||
});
|
||||
|
||||
return {addon: addonTypes, install: installTypes};
|
||||
}
|
||||
|
||||
|
||||
var gCategories = {
|
||||
node: null,
|
||||
|
@ -648,16 +701,18 @@ var gCategories = {
|
|||
}, false);
|
||||
|
||||
var maybeHidden = ["addons://list/locale", "addons://list/searchengine"];
|
||||
gPendingInitializations += maybeHidden.length;
|
||||
maybeHidden.forEach(function(aId) {
|
||||
var type = gViewController.parseViewId(aId).param;
|
||||
AddonManager.getAddonsByTypes([type], function(aAddonsList) {
|
||||
if (aAddonsList.length > 0) {
|
||||
getAddonsAndInstalls(type, function(aAddonsList, aInstallsList) {
|
||||
if (aAddonsList.length > 0 || aInstallsList.length > 0) {
|
||||
self.get(aId).hidden = false;
|
||||
notifyInitialized();
|
||||
return;
|
||||
}
|
||||
|
||||
gEventManager.registerInstallListener({
|
||||
onNewInstall: function(aInstall) {
|
||||
onDownloadStarted: function(aInstall) {
|
||||
this._maybeShowCategory(aInstall);
|
||||
},
|
||||
|
||||
|
@ -680,6 +735,8 @@ var gCategories = {
|
|||
}
|
||||
}
|
||||
});
|
||||
|
||||
notifyInitialized();
|
||||
});
|
||||
});
|
||||
},
|
||||
|
@ -795,6 +852,7 @@ var gDiscoverView = {
|
|||
.getService(Ci.nsIURLFormatter)
|
||||
.formatURLPref(PREF_DISCOVERURL);
|
||||
|
||||
gPendingInitializations++;
|
||||
AddonManager.getAllAddons(function(aAddons) {
|
||||
var list = {};
|
||||
aAddons.forEach(function(aAddon) {
|
||||
|
@ -809,6 +867,7 @@ var gDiscoverView = {
|
|||
});
|
||||
|
||||
gDiscoverView._browser.homePage = url + "#" + JSON.stringify(list);
|
||||
notifyInitialized();
|
||||
});
|
||||
},
|
||||
|
||||
|
@ -996,33 +1055,21 @@ var gListView = {
|
|||
gHeader.setName(gStrings.ext.GetStringFromName("header-" + aType));
|
||||
this.showEmptyNotice(false);
|
||||
|
||||
this._types = [aType];
|
||||
this._installTypes = [aType];
|
||||
if (aType == "extension") {
|
||||
this._types.push("bootstrapped");
|
||||
this._installTypes = this._types.concat("");
|
||||
}
|
||||
|
||||
while (this._listBox.itemCount > 0)
|
||||
this._listBox.removeItemAt(0);
|
||||
|
||||
var self = this;
|
||||
var addons = null, installs = null;
|
||||
|
||||
function updateList() {
|
||||
if (addons == null || installs == null)
|
||||
var types = getAddonsAndInstalls(aType, function(aAddonsList, aInstallsList) {
|
||||
if (gViewController && aRequest != gViewController.currentViewRequest)
|
||||
return;
|
||||
|
||||
for (let i = 0; i < addons.length; i++) {
|
||||
let item = createItem(addons[i]);
|
||||
for (let i = 0; i < aAddonsList.length; i++) {
|
||||
let item = createItem(aAddonsList[i]);
|
||||
self._listBox.appendChild(item);
|
||||
}
|
||||
|
||||
for (let i = 0; i < installs.length; i++) {
|
||||
// skip over upgrade installs
|
||||
if (installs[i].existingAddon)
|
||||
continue;
|
||||
let item = createItem(installs[i], true);
|
||||
for (let i = 0; i < aInstallsList.length; i++) {
|
||||
let item = createItem(aInstallsList[i], true);
|
||||
self._listBox.appendChild(item);
|
||||
}
|
||||
|
||||
|
@ -1031,25 +1078,13 @@ var gListView = {
|
|||
else
|
||||
self.showEmptyNotice(true);
|
||||
|
||||
gEventManager.registerInstallListener(self);
|
||||
gViewController.updateCommands();
|
||||
gViewController.notifyViewChanged();
|
||||
}
|
||||
|
||||
|
||||
AddonManager.getAddonsByTypes(this._types, function(aAddonsList) {
|
||||
if (gViewController && aRequest != gViewController.currentViewRequest)
|
||||
return;
|
||||
addons = aAddonsList;
|
||||
updateList();
|
||||
});
|
||||
|
||||
AddonManager.getInstallsByTypes(this._installTypes, function(aInstallsList) {
|
||||
if (gViewController && aRequest != gViewController.currentViewRequest)
|
||||
return;
|
||||
installs = aInstallsList;
|
||||
updateList();
|
||||
gEventManager.registerInstallListener(self);
|
||||
});
|
||||
this._types = types.addon;
|
||||
this._installTypes = types.install;
|
||||
},
|
||||
|
||||
hide: function() {
|
||||
|
@ -1277,7 +1312,7 @@ var gDragDrop = {
|
|||
},
|
||||
|
||||
onDrop: function(aEvent) {
|
||||
var dataTransfer = aEvent.dataTransfer;
|
||||
var dataTransfer = aEvent.dataTransfer;
|
||||
var urls = [];
|
||||
|
||||
// Convert every dropped item into a url
|
||||
|
|
|
@ -49,6 +49,7 @@ _TEST_FILES = \
|
|||
head.js \
|
||||
browser_bug562890.js \
|
||||
browser_bug562899.js \
|
||||
browser_bug572561.js \
|
||||
browser_dragdrop.js \
|
||||
browser_sorting.js \
|
||||
browser_updatessl.js \
|
||||
|
|
|
@ -28,10 +28,10 @@ function test() {
|
|||
}
|
||||
|
||||
function end_test() {
|
||||
gManagerWindow.close();
|
||||
LightweightThemeManager.forgetUsedTheme("test");
|
||||
|
||||
finish();
|
||||
close_manager(gManagerWindow, function() {
|
||||
LightweightThemeManager.forgetUsedTheme("test");
|
||||
finish();
|
||||
});
|
||||
}
|
||||
|
||||
// Tests that loading a second view before the first has not finished loading
|
||||
|
|
|
@ -0,0 +1,94 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
// Tests that the locale category is shown if there are no locale packs
|
||||
// installed but some are pending install
|
||||
|
||||
var gManagerWindow;
|
||||
var gProvider;
|
||||
var gInstallProperties = [{
|
||||
name: "Locale Category Test",
|
||||
type: "locale"
|
||||
}];
|
||||
var gInstall;
|
||||
var gExpectedCancel = false;
|
||||
var gTestInstallListener = {
|
||||
onInstallStarted: function(aInstall) {
|
||||
check_hidden(false);
|
||||
},
|
||||
|
||||
onInstallEnded: function(aInstall) {
|
||||
check_hidden(false);
|
||||
run_next_test();
|
||||
},
|
||||
|
||||
onInstallCancelled: function(aInstall) {
|
||||
ok(gExpectedCancel, "Should expect install cancel");
|
||||
check_hidden(false);
|
||||
run_next_test();
|
||||
},
|
||||
|
||||
onInstallFailed: function(aInstall) {
|
||||
ok(false, "Did not expect onInstallFailed");
|
||||
}
|
||||
};
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
|
||||
gProvider = new MockProvider();
|
||||
|
||||
open_manager(null, function(aWindow) {
|
||||
gManagerWindow = aWindow;
|
||||
run_next_test();
|
||||
});
|
||||
}
|
||||
|
||||
function end_test() {
|
||||
close_manager(gManagerWindow, function() {
|
||||
finish();
|
||||
});
|
||||
}
|
||||
|
||||
function check_hidden(aExpectedHidden) {
|
||||
var category = gManagerWindow.gCategories.get("addons://list/locale");
|
||||
is(category.hidden, aExpectedHidden, "Should have correct hidden state");
|
||||
}
|
||||
|
||||
// Tests that a non-active install does not make the locale category show
|
||||
add_test(function() {
|
||||
check_hidden(true);
|
||||
gInstall = gProvider.createInstalls(gInstallProperties)[0];
|
||||
gInstall.addTestListener(gTestInstallListener);
|
||||
check_hidden(true);
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
// Test that restarting the add-on manager with a non-active install
|
||||
// does not cause the locale category to show
|
||||
add_test(function() {
|
||||
restart_manager(gManagerWindow, null, function(aWindow) {
|
||||
gManagerWindow = aWindow;
|
||||
check_hidden(true);
|
||||
run_next_test();
|
||||
});
|
||||
});
|
||||
|
||||
// Test that installing the install shows the locale category
|
||||
add_test(function() {
|
||||
gInstall.install();
|
||||
});
|
||||
|
||||
// Test that restarting the add-on manager does not cause the locale category
|
||||
// to become hidden
|
||||
add_test(function() {
|
||||
restart_manager(gManagerWindow, null, function(aWindow) {
|
||||
gManagerWindow = aWindow;
|
||||
check_hidden(false);
|
||||
|
||||
gExpectedCancel = true;
|
||||
gInstall.cancel();
|
||||
});
|
||||
});
|
||||
|
|
@ -79,9 +79,9 @@ function test() {
|
|||
}
|
||||
|
||||
function end_test() {
|
||||
gManagerWindow.close();
|
||||
|
||||
finish();
|
||||
close_manager(gManagerWindow, function() {
|
||||
finish();
|
||||
});
|
||||
}
|
||||
|
||||
function test_confirmation(aWindow, aExpectedURLs) {
|
||||
|
|
|
@ -49,9 +49,9 @@ function test() {
|
|||
}
|
||||
|
||||
function end_test() {
|
||||
gManagerWindow.close();
|
||||
|
||||
finish();
|
||||
close_manager(gManagerWindow, function() {
|
||||
finish();
|
||||
});
|
||||
}
|
||||
|
||||
function check_order(aExpectedOrder) {
|
||||
|
|
|
@ -48,7 +48,7 @@ function get_addon_file_url(aFilename) {
|
|||
}
|
||||
|
||||
function wait_for_view_load(aManagerWindow, aCallback) {
|
||||
if (!aManagerWindow.gViewController.currentViewObj.node.hasAttribute("loading")) {
|
||||
if (!aManagerWindow.gViewController.isLoading) {
|
||||
aCallback(aManagerWindow);
|
||||
return;
|
||||
}
|
||||
|
@ -67,7 +67,15 @@ function open_manager(aView, aCallback) {
|
|||
ok(aManagerWindow != null, "Should have an add-ons manager window");
|
||||
is(aManagerWindow.location, MANAGER_URI, "Should be displaying the correct UI");
|
||||
|
||||
wait_for_view_load(aManagerWindow, aCallback);
|
||||
if (!aManagerWindow.gIsInitializing) {
|
||||
wait_for_view_load(aManagerWindow, aCallback);
|
||||
return;
|
||||
}
|
||||
|
||||
aManagerWindow.document.addEventListener("Initialized", function() {
|
||||
aManagerWindow.document.removeEventListener("Initialized", arguments.callee, false);
|
||||
wait_for_view_load(aManagerWindow, aCallback);
|
||||
}, false);
|
||||
}
|
||||
|
||||
if ("switchToTabHavingURI" in window) {
|
||||
|
@ -77,12 +85,28 @@ function open_manager(aView, aCallback) {
|
|||
return;
|
||||
}
|
||||
|
||||
openDialog("about:addons").addEventListener("load", function() {
|
||||
openDialog(MANAGER_URI).addEventListener("load", function() {
|
||||
this.removeEventListener("load", arguments.callee, false);
|
||||
setup_manager(this);
|
||||
}, false);
|
||||
}
|
||||
|
||||
function close_manager(aManagerWindow, aCallback) {
|
||||
ok(aManagerWindow != null, "Should have an add-ons manager window to close");
|
||||
is(aManagerWindow.location, MANAGER_URI, "Should be closing window with correct URI");
|
||||
|
||||
aManagerWindow.addEventListener("unload", function() {
|
||||
this.removeEventListener("unload", arguments.callee, false);
|
||||
aCallback();
|
||||
}, false);
|
||||
|
||||
aManagerWindow.close();
|
||||
}
|
||||
|
||||
function restart_manager(aManagerWindow, aView, aCallback) {
|
||||
close_manager(aManagerWindow, function() { open_manager(aView, aCallback); });
|
||||
}
|
||||
|
||||
function CertOverrideListener(host, bits) {
|
||||
this.host = host;
|
||||
this.bits = bits;
|
||||
|
@ -186,14 +210,32 @@ MockProvider.prototype = {
|
|||
null, false)
|
||||
},
|
||||
|
||||
/**
|
||||
* Adds an add-on install to the list of installs that this provider exposes
|
||||
* to the AddonManager, dispatching appropriate events in the process.
|
||||
*
|
||||
* @param aInstall
|
||||
* The add-on install to add
|
||||
*/
|
||||
addInstall: function MP_addInstall(aInstall) {
|
||||
this.installs.push(aInstall);
|
||||
|
||||
if (!this.started)
|
||||
return;
|
||||
|
||||
aInstall.callListeners("onNewInstall");
|
||||
},
|
||||
|
||||
/**
|
||||
* Creates a set of mock add-on objects and adds them to the list of add-ons
|
||||
* managed by this provider.
|
||||
*
|
||||
* @param aAddonProperties
|
||||
* An array of objects containing properties describing the add-ons
|
||||
* @return Array of the new MockAddons
|
||||
*/
|
||||
createAddons: function MP_createAddons(aAddonProperties) {
|
||||
var newAddons = [];
|
||||
aAddonProperties.forEach(function(aAddonProp) {
|
||||
var addon = new MockAddon(aAddonProp.id);
|
||||
for (var prop in aAddonProp) {
|
||||
|
@ -202,7 +244,32 @@ MockProvider.prototype = {
|
|||
addon[prop] = aAddonProp[prop];
|
||||
}
|
||||
this.addAddon(addon);
|
||||
newAddons.push(addon);
|
||||
}, this);
|
||||
|
||||
return newAddons;
|
||||
},
|
||||
|
||||
/**
|
||||
* Creates a set of mock add-on install objects and adds them to the list
|
||||
* of installs managed by this provider.
|
||||
*
|
||||
* @param aInstallProperties
|
||||
* An array of objects containing properties describing the installs
|
||||
* @return Array of the new MockInstalls
|
||||
*/
|
||||
createInstalls: function MP_createInstalls(aInstallProperties) {
|
||||
var newInstalls = [];
|
||||
aInstallProperties.forEach(function(aInstallProp) {
|
||||
var install = new MockInstall();
|
||||
for (var prop in aInstallProp) {
|
||||
install[prop] = aInstallProp[prop];
|
||||
}
|
||||
this.addInstall(install);
|
||||
newInstalls.push(install);
|
||||
}, this);
|
||||
|
||||
return newInstalls;
|
||||
},
|
||||
|
||||
/***** AddonProvider implementation *****/
|
||||
|
@ -287,8 +354,13 @@ MockProvider.prototype = {
|
|||
*/
|
||||
getInstallsByTypes: function MP_getInstallsByTypes(aTypes, aCallback) {
|
||||
var installs = this.installs.filter(function(aInstall) {
|
||||
// Appear to have actually removed cancelled installs from the provider
|
||||
if (aInstall.state == AddonManager.STATE_CANCELLED)
|
||||
return false;
|
||||
|
||||
if (aTypes && aTypes.length > 0 && aTypes.indexOf(aInstall.type) == -1)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
});
|
||||
this._delayCallback(aCallback, installs);
|
||||
|
@ -454,3 +526,109 @@ MockAddon.prototype = {
|
|||
// To be implemented when needed
|
||||
}
|
||||
};
|
||||
|
||||
/***** Mock AddonInstall object for the Mock Provider *****/
|
||||
|
||||
function MockInstall(aName, aType) {
|
||||
this.name = aName || "";
|
||||
this.type = aType || "extension";
|
||||
this.version = "1.0";
|
||||
this.iconURL = "";
|
||||
this.infoURL = "";
|
||||
this.state = AddonManager.STATE_AVAILABLE;
|
||||
this.error = 0;
|
||||
this.sourceURL = "";
|
||||
this.file = null;
|
||||
this.progress = 0;
|
||||
this.maxProgress = -1;
|
||||
this.certificate = null;
|
||||
this.certName = "";
|
||||
this.existingAddon = null;
|
||||
this.addon = null;
|
||||
this.listeners = [];
|
||||
|
||||
// Another type of install listener for tests that want to check the results
|
||||
// of code run from standard install listeners
|
||||
this.testListeners = [];
|
||||
}
|
||||
|
||||
MockInstall.prototype = {
|
||||
install: function() {
|
||||
switch (this.state) {
|
||||
case AddonManager.STATE_AVAILABLE:
|
||||
case AddonManager.STATE_DOWNLOADED:
|
||||
// Downloading to be implemented when needed
|
||||
|
||||
this.state = AddonManager.STATE_INSTALLING;
|
||||
if (!this.callListeners("onInstallStarted")) {
|
||||
// Reverting to STATE_DOWNLOADED instead to be implemented when needed
|
||||
this.state = AddonManager.STATE_CANCELLED;
|
||||
this.callListeners("onInstallCancelled");
|
||||
return;
|
||||
}
|
||||
|
||||
// Adding addon to MockProvider to be implemented when needed
|
||||
this.addon = new MockAddon("", this.name, this.type);
|
||||
this.state = AddonManager.STATE_INSTALLED;
|
||||
this.callListeners("onInstallEnded");
|
||||
break;
|
||||
case AddonManager.STATE_DOWNLOADING:
|
||||
case AddonManager.STATE_CHECKING:
|
||||
case AddonManger.STATE_INSTALLING:
|
||||
// Installation is already running
|
||||
return;
|
||||
default:
|
||||
ok(false, "Cannot start installing when state = " + this.state);
|
||||
}
|
||||
},
|
||||
|
||||
cancel: function() {
|
||||
switch (this.state) {
|
||||
case AddonManager.STATE_AVAILABLE:
|
||||
this.state = AddonManager.STATE_CANCELLED;
|
||||
break;
|
||||
case AddonManager.STATE_INSTALLED:
|
||||
this.state = AddonManager.STATE_CANCELLED;
|
||||
this.callListeners("onInstallCancelled");
|
||||
break;
|
||||
default:
|
||||
// Handling cancelling when downloading to be implemented when needed
|
||||
ok(false, "Cannot cancel when state = " + this.state);
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
addListener: function(aListener) {
|
||||
if (!this.listeners.some(function(i) i == aListener))
|
||||
this.listeners.push(aListener);
|
||||
},
|
||||
|
||||
removeListener: function(aListener) {
|
||||
this.listeners = this.listeners.filter(function(i) i != aListener);
|
||||
},
|
||||
|
||||
addTestListener: function(aListener) {
|
||||
if (!this.testListeners.some(function(i) i == aListener))
|
||||
this.testListeners.push(aListener);
|
||||
},
|
||||
|
||||
removeTestListener: function(aListener) {
|
||||
this.testListeners = this.testListeners.filter(function(i) i != aListener);
|
||||
},
|
||||
|
||||
callListeners: function(aMethod) {
|
||||
var result = AddonManagerPrivate.callInstallListeners(aMethod, this.listeners,
|
||||
this, this.addon);
|
||||
|
||||
// Call test listeners after standard listeners to remove race condition
|
||||
// between standard and test listeners
|
||||
this.testListeners.forEach(function(aListener) {
|
||||
if (aMethod in aListener)
|
||||
if (aListener[aMethod].call(aListener, this, this.addon) === false)
|
||||
result = false;
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче