Bug 587970 - Provide ability "Update all now" within 'Available Updates' screen. r=dtownsend, a=blocking-beta6

This commit is contained in:
Blair McBride 2010-09-10 20:20:12 +12:00
Родитель ec09081ccf
Коммит 7594d0dea2
11 изменённых файлов: 275 добавлений и 16 удалений

Просмотреть файл

@ -48,6 +48,8 @@
<!ENTITY updates.restart.label "Restart now to complete installation">
<!ENTITY updates.noneFound.label "No updates found">
<!ENTITY updates.manualUpdatesFound.label "View Available Updates">
<!ENTITY updates.updateSelected.label "Install Updates">
<!ENTITY updates.updateSelected.tooltip "Install available updates in this list">
<!-- addon actions -->
<!ENTITY cmd.showDetails.label "Show More Information">
@ -159,6 +161,8 @@
<!ENTITY addon.install.tooltip "Install this add-on">
<!ENTITY addon.updateNow.label "Update Now">
<!ENTITY addon.updateNow.tooltip "Install the update for this add-on">
<!ENTITY addon.includeUpdate.label "Include in Update">
<!ENTITY addon.updateAvailable.label "An update is available">
<!ENTITY addon.checkingForUpdates.label "Checking for updates…">
<!ENTITY addon.releaseNotes.label "Release Notes:">
<!ENTITY addon.loadingReleaseNotes.label "Loading…">

Просмотреть файл

@ -131,7 +131,10 @@ xhtml|link {
display: none;
}
.view-pane:not(#updates-view) .addon .relnotes-toggle {
.view-pane:not(#updates-view) .addon .relnotes-toggle,
.view-pane:not(#updates-view) .addon .include-update,
#updates-view:not([updatetype="available"]) .addon .include-update,
#updates-view[updatetype="available"] .addon .update-available-notice {
display: none;
}

Просмотреть файл

@ -2008,6 +2008,7 @@ var gUpdatesView = {
_listBox: null,
_emptyNotice: null,
_sorters: null,
_updateSelected: null,
_updatePrefs: null,
_backgroundUpdateCheck: null,
_categoryItem: null,
@ -2023,6 +2024,11 @@ var gUpdatesView = {
this._backgroundUpdateCheck = document.getElementById("utils-backgroudUpdateCheck");
this._categoryItem = gCategories.get("addons://updates/available");
this._updateSelected = document.getElementById("update-selected");
this._updateSelected.addEventListener("command", function() {
gUpdatesView.installSelected();
}, false);
this._updatePrefs = Services.prefs.getBranch("extensions.update.");
this._updatePrefs.QueryInterface(Ci.nsIPrefBranch2);
this._updatePrefs.addObserver("", this, false);
@ -2049,6 +2055,7 @@ var gUpdatesView = {
while (this._listBox.itemCount > 0)
this._listBox.removeItemAt(0);
this.node.setAttribute("updatetype", aType);
if (aType == "recent")
this._showRecentUpdates(aRequest);
else
@ -2056,7 +2063,7 @@ var gUpdatesView = {
},
hide: function() {
// do nothing
this._updateSelected.hidden = true;
},
_showRecentUpdates: function(aRequest) {
@ -2084,12 +2091,20 @@ var gUpdatesView = {
},
_showAvailableUpdates: function(aIsRefresh, aRequest) {
/* Disable the Update Selected button so it can't get clicked
before everything is initialized asynchronously.
It will get re-enabled by maybeDisableUpdateSelected(). */
this._updateSelected.disabled = true;
var self = this;
AddonManager.getAllInstalls(function(aInstallsList) {
if (!aIsRefresh && gViewController && aRequest != gViewController.currentViewRequest)
return;
if (aIsRefresh) {
self.showEmptyNotice(false);
self._updateSelected.hidden = true;
while (self._listBox.itemCount > 0)
self._listBox.removeItemAt(0);
}
@ -2100,19 +2115,23 @@ var gUpdatesView = {
let item = createItem(aInstall.existingAddon);
item.setAttribute("upgrade", true);
item.addEventListener("IncludeUpdateChanged", function() {
self.maybeDisableUpdateSelected();
}, false);
self._listBox.appendChild(item);
});
if (self._listBox.itemCount > 0)
if (self._listBox.itemCount > 0) {
self._updateSelected.hidden = false;
self.onSortChanged(self._sorters.sortBy, self._sorters.ascending);
else
} else {
self.showEmptyNotice(true);
}
// ensure badge count is in sync
self._categoryItem.badgeCount = self._listBox.itemCount;
if (!aIsRefresh)
gViewController.notifyViewChanged();
gViewController.notifyViewChanged();
});
},
@ -2185,6 +2204,30 @@ var gUpdatesView = {
notifyInitialized();
});
},
maybeDisableUpdateSelected: function() {
for (let i = 0; i < this._listBox.childNodes.length; i++) {
let item = this._listBox.childNodes[i];
if (item.includeUpdate) {
this._updateSelected.disabled = false;
return;
}
}
this._updateSelected.disabled = true;
},
installSelected: function() {
/* Starting the update of one item will refresh the list,
which can cause problems while we're iterating over it.
So we update only after we've finished iterating over the list. */
var toUpgrade = [];
for (let i = 0; i < this._listBox.childNodes.length; i++) {
let item = this._listBox.childNodes[i];
if (item.includeUpdate)
toUpgrade.push(item);
}
toUpgrade.forEach(function(aItem) aItem.upgrade());
},
getSelectedAddon: function() {
var item = this._listBox.selectedItem;

Просмотреть файл

@ -791,13 +791,20 @@
<xul:image class="spinner"/>
<xul:label value="&addon.checkingForUpdates.label;"/>
</xul:hbox>
<xul:hbox anonid="update-available" hidden="true" align="center">
<xul:label value="An update is available"/>
<xul:button anonid="update-btn" class="addon-control"
label="&addon.updateNow.label;"
tooltiptext="&addon.updateNow.tooltip;"
oncommand="document.getBindingParent(this).upgrade();"/>
</xul:hbox>
<xul:vbox anonid="update-available" class="update-available"
hidden="true" align="end">
<xul:checkbox anonid="include-update" class="include-update"
label="&addon.includeUpdate.label;" checked="true"
oncommand="document.getBindingParent(this).onIncludeUpdateChanged();"/>
<xul:hbox align="center">
<xul:label class="update-available-notice"
value="&addon.updateAvailable.label;"/>
<xul:button anonid="update-btn" class="addon-control"
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>
@ -855,12 +862,17 @@
if (!this.mAddon.applyBackgroundUpdates) {
var self = this;
AddonManager.getAllInstalls(function(aInstallsList) {
// This can return after the binding has been destroyed,
// so try to detect that and return early
if (!("onNewInstall" in self))
return;
for (let i = 0; i < aInstallsList.length; i++) {
let install = aInstallsList[i];
if (install.existingAddon &&
install.existingAddon.id == self.mAddon.id &&
install.state == AddonManager.STATE_AVAILABLE) {
self.onNewInstall(install);
self.onIncludeUpdateChanged();
}
}
});
@ -967,6 +979,10 @@
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",
@ -998,6 +1014,17 @@
]]></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="_showStatus">
<parameter name="aType"/>
<body><![CDATA[
@ -1306,6 +1333,14 @@
]]></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();

Просмотреть файл

@ -362,8 +362,10 @@
command="cmd_findAllUpdates"/>
<spacer flex="3"/>
</vbox>
<hbox id="update-all-container" hidden="true">
<button label="Update these add-ons" class="addon-control"/>
<hbox id="update-actions" pack="center">
<button id="update-selected" hidden="true"
label="&updates.updateSelected.label;"
tooltiptext="&updates.updateSelected.tooltip;"/>
</hbox>
<richlistbox id="updates-list" class="list" flex="1"/>
</vbox>

Просмотреть файл

@ -61,6 +61,7 @@ _TEST_FILES = \
browser_bug572561.js \
browser_bug577990.js \
browser_bug581076.js \
browser_bug587970.js \
browser_bug591465.js \
browser_bug591465.xml \
browser_details.js \

Просмотреть файл

@ -0,0 +1,152 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
// Bug 587970 - Provide ability "Update all now" within 'Available Updates' screen
var gManagerWindow;
var gProvider;
function test() {
waitForExplicitFinish();
gProvider = new MockProvider();
gProvider.createAddons([{
id: "addon1@tests.mozilla.org",
name: "addon 1",
version: "1.0",
applyBackgroundUpdates: false
}, {
id: "addon2@tests.mozilla.org",
name: "addon 2",
version: "2.0",
applyBackgroundUpdates: false
}]);
open_manager("addons://updates/available", function(aWindow) {
gManagerWindow = aWindow;
run_next_test();
});
}
function end_test() {
close_manager(gManagerWindow, finish);
}
add_test(function() {
var list = gManagerWindow.document.getElementById("updates-list");
is(list.childNodes.length, 0, "Available updates list should be empty");
var emptyNotice = gManagerWindow.document.getElementById("empty-availableUpdates-msg");
is_element_visible(emptyNotice, "Empty notice should be visible");
var updateSelected = gManagerWindow.document.getElementById("update-selected");
is_element_hidden(updateSelected, "Update Selected button should be hidden");
info("Adding updates");
gProvider.createInstalls([{
name: "addon 1",
version: "1.1",
existingAddon: gProvider.addons[0]
}, {
name: "addon 2",
version: "2.1",
existingAddon: gProvider.addons[1]
}]);
function wait_for_refresh() {
if (list.childNodes.length == 2 &&
list.childNodes[0].mManualUpdate &&
list.childNodes[1].mManualUpdate) {
run_next_test();
} else {
info("Waiting for pane to refresh");
setTimeout(wait_for_refresh, 10);
}
}
info("Waiting for pane to refresh");
setTimeout(wait_for_refresh, 10);
});
add_test(function() {
var list = gManagerWindow.document.getElementById("updates-list");
is(list.childNodes.length, 2, "Available updates list should have 2 items");
var item1 = get_addon_element(gManagerWindow, "addon1@tests.mozilla.org");
isnot(item1, null, "Item for addon1@tests.mozilla.org should be in list");
var item2 = get_addon_element(gManagerWindow, "addon2@tests.mozilla.org");
isnot(item2, null, "Item for addon2@tests.mozilla.org should be in list");
var emptyNotice = gManagerWindow.document.getElementById("empty-availableUpdates-msg");
is_element_hidden(emptyNotice, "Empty notice should be hidden");
var updateSelected = gManagerWindow.document.getElementById("update-selected");
is_element_visible(updateSelected, "Update Selected button should be visible");
is(updateSelected.disabled, false, "Update Selected button should be enabled by default");
is(item1._includeUpdate.checked, true, "Include Update checkbox should be checked by default for addon1");
is(item2._includeUpdate.checked, true, "Include Update checkbox should be checked by default for addon2");
info("Unchecking Include Update checkbox for addon1");
EventUtils.synthesizeMouse(item1._includeUpdate, 2, 2, { }, gManagerWindow);
is(item1._includeUpdate.checked, false, "Include Update checkbox should now be be unchecked for addon1");
is(updateSelected.disabled, false, "Update Selected button should still be enabled");
info("Unchecking Include Update checkbox for addon2");
EventUtils.synthesizeMouse(item2._includeUpdate, 2, 2, { }, gManagerWindow);
is(item2._includeUpdate.checked, false, "Include Update checkbox should now be be unchecked for addon2");
is(updateSelected.disabled, true, "Update Selected button should now be disabled");
info("Checking Include Update checkbox for addon2");
EventUtils.synthesizeMouse(item2._includeUpdate, 2, 2, { }, gManagerWindow);
is(item2._includeUpdate.checked, true, "Include Update checkbox should now be be checked for addon2");
is(updateSelected.disabled, false, "Update Selected button should now be enabled");
var listener = {
onInstallEnded: function() {
gProvider.installs[1].removeTestListener(listener);
is(gProvider.installs[0].state, AddonManager.STATE_AVAILABLE, "addon1 should not have been upgraded");
is(gProvider.installs[1].state, AddonManager.STATE_INSTALLED, "addon2 should have been upgraded");
}
}
gProvider.installs[1].addTestListener(listener);
info("Clicking Update Selected button");
EventUtils.synthesizeMouse(updateSelected, 2, 2, { }, gManagerWindow);
wait_for_view_load(gManagerWindow, function() {
function wait_for_refresh() {
var item = get_addon_element(gManagerWindow, "addon1@tests.mozilla.org");
if (item.mManualUpdate) {
run_next_test();
} else {
info("Waiting for pane to refresh");
setTimeout(wait_for_refresh, 10);
}
}
info("Waiting for pane to refresh");
setTimeout(wait_for_refresh, 10);
}, true);
});
add_test(function() {
var updateSelected = gManagerWindow.document.getElementById("update-selected");
is(updateSelected.disabled, false, "Update Selected button should now be enabled");
var item1 = get_addon_element(gManagerWindow, "addon1@tests.mozilla.org");
isnot(item1, null, "Item for addon1@tests.mozilla.org should be in list");
is(item1._includeUpdate.checked, true, "Include Update checkbox should be checked by default for addon1");
info("Unchecking Include Update checkbox for addon1");
EventUtils.synthesizeMouse(item1._includeUpdate, 2, 2, { }, gManagerWindow);
is(item1._includeUpdate.checked, false, "Include Update checkbox should now be be unchecked for addon1");
is(updateSelected.disabled, true, "Update Selected button should now be disabled");
run_next_test();
});

Просмотреть файл

@ -104,7 +104,11 @@ function check_all_in_list(aManager, aIds, aIgnoreExtras) {
function get_addon_element(aManager, aId) {
var doc = aManager.document;
var view = doc.getElementById("view-port").selectedPanel;
var listid = view.id == "search-view" ? "search-list" : "addon-list";
var listid = "addon-list";
if (view.id == "search-view")
listid = "search-list";
else if (view.id == "updates-view")
listid = "updates-list";
var list = doc.getElementById(listid);
var node = list.firstChild;

Просмотреть файл

@ -463,6 +463,7 @@
list-style-image: url("chrome://global/skin/arrow/arrow-up.gif");
}
/*** item - uninstalled ***/
.addon[status="uninstalled"] {
@ -744,6 +745,10 @@
font-weight: bold;
}
#update-selected {
margin: 12px;
}
/*** buttons ***/

Просмотреть файл

@ -493,6 +493,7 @@
list-style-image: url("chrome://global/skin/arrow/arrow-up.gif");
}
/*** item - uninstalled ***/
.addon[status="uninstalled"] {
@ -794,6 +795,10 @@
font-weight: bold;
}
#update-selected {
margin: 12px;
}
/*** buttons ***/

Просмотреть файл

@ -469,6 +469,7 @@
list-style-image: url("chrome://global/skin/arrow/arrow-up.gif");
}
/*** item - uninstalled ***/
.addon[status="uninstalled"] {
@ -776,6 +777,10 @@
font-weight: bold;
}
#update-selected {
margin: 12px;
}
/*** buttons ***/