diff --git a/toolkit/mozapps/extensions/content/extensions.js b/toolkit/mozapps/extensions/content/extensions.js
index 4ee1362137b..d3a5a7b3dbf 100644
--- a/toolkit/mozapps/extensions/content/extensions.js
+++ b/toolkit/mozapps/extensions/content/extensions.js
@@ -74,8 +74,6 @@ const XMLURI_PARSE_ERROR = "http://www.mozilla.org/newlayout/xml/parsererror.xml
const VIEW_DEFAULT = "addons://list/extension";
-const INTEGER_FIELDS = ["dateUpdated", "size", "relevancescore"];
-
var gStrings = {};
XPCOMUtils.defineLazyServiceGetter(gStrings, "bundleSvc",
"@mozilla.org/intl/stringbundle;1",
@@ -1163,16 +1161,81 @@ function createItem(aObj, aIsInstall, aIsRemote) {
// the binding handles the rest
item.setAttribute("value", aObj.id);
- // The XUL sort service only supports 32 bit integers so we strip the
- // milliseconds to make this small enough
- if (aObj.updateDate)
- item.setAttribute("dateUpdated", aObj.updateDate.getTime() / 1000);
-
- if (aObj.size)
- item.setAttribute("size", aObj.size);
return item;
}
+function sortElements(aElements, aSortBy, aAscending) {
+ const DATE_FIELDS = ["updateDate"];
+ const INTEGER_FIELDS = ["size", "relevancescore"];
+
+ function dateCompare(a, b) {
+ var aTime = a.getTime();
+ var bTime = b.getTime();
+ if (aTime < bTime)
+ return -1;
+ if (aTime > bTime)
+ return 1;
+ return 0;
+ }
+
+ function intCompare(a, b) {
+ return a - b;
+ }
+
+ function stringCompare(a, b) {
+ return a.localeCompare(b);
+ }
+
+ function getValue(aObj) {
+ if (!aObj)
+ return null;
+
+ if (aObj.hasAttribute(aSortBy))
+ return aObj.getAttribute(aSortBy);
+
+ addon = aObj.mAddon || aObj.mInstall;
+ if (!addon)
+ return null;
+
+ return addon[aSortBy];
+ }
+
+ var sortFunc = stringCompare;
+ if (DATE_FIELDS.indexOf(aSortBy) != -1)
+ sortFunc = dateCompare;
+ else if (INTEGER_FIELDS.indexOf(aSortBy) != -1)
+ sortFunc = intCompare;
+
+ aElements.sort(function(a, b) {
+ if (!aAscending)
+ [a, b] = [b, a];
+
+ var aValue = getValue(a);
+ var bValue = getValue(b);
+
+ if (!aValue && !bValue)
+ return 0;
+ if (!aValue)
+ return -1;
+ if (!bValue)
+ return 1;
+
+ return sortFunc(aValue, bValue);
+ });
+}
+
+function sortList(aList, aSortBy, aAscending) {
+ var elements = Array.slice(aList.childNodes, 0);
+ sortElements(elements, aSortBy, aAscending);
+
+ while (aList.listChild)
+ aList.removeChild(aList.lastChild);
+
+ elements.forEach(function(aElement) {
+ aList.appendChild(aElement);
+ });
+}
+
function getAddonsAndInstalls(aType, aCallback) {
var addonTypes = null, installTypes = null;
if (aType != null) {
@@ -1562,8 +1625,9 @@ var gSearchView = {
this._pendingSearches = 2;
this._sorters.setSort("relevancescore", false);
+ var elements = [];
+
function createSearchResults(aObjsList, aIsInstall, aIsRemote) {
- var createdCount = 0;
aObjsList.forEach(function(aObj) {
let score = 0;
if (aQuery.length > 0) {
@@ -1577,16 +1641,18 @@ var gSearchView = {
if (aIsRemote)
gCachedAddons[aObj.id] = aObj;
- self._listBox.insertBefore(item, self._listBox.lastChild);
- createdCount++;
+ elements.push(item);
});
-
- return createdCount;
}
function finishSearch(createdCount) {
- if (createdCount > 0)
- self.onSortChanged(self._sorters.sortBy, self._sorters.ascending);
+ if (elements.length > 0) {
+ sortElements(elements, self._sorters.sortBy, self._sorters.ascending);
+ elements.forEach(function(aElement) {
+ self._listBox.insertBefore(aElement, self._listBox.lastChild);
+ });
+ self.updateListAttributes();
+ }
self._pendingSearches--;
self.updateView();
@@ -1599,9 +1665,9 @@ var gSearchView = {
if (gViewController && aRequest != gViewController.currentViewRequest)
return;
- var createdCount = createSearchResults(aAddons, false, false);
- createdCount += createSearchResults(aInstalls, true, false);
- finishSearch(createdCount);
+ createSearchResults(aAddons, false, false);
+ createSearchResults(aInstalls, true, false);
+ finishSearch();
});
var maxRemoteResults = 0;
@@ -1748,18 +1814,7 @@ var gSearchView = {
this._allResultsLink.hidden = false;
},
- onSortChanged: function(aSortBy, aAscending) {
- var footer = this._listBox.lastChild;
- this._listBox.removeChild(footer);
-
- var hints = aAscending ? "ascending" : "descending";
- if (INTEGER_FIELDS.indexOf(aSortBy) >= 0)
- hints += " integer";
-
- var sortService = Cc["@mozilla.org/xul/xul-sort-service;1"].
- getService(Ci.nsIXULSortService);
- sortService.sort(this._listBox, aSortBy, hints);
-
+ updateListAttributes: function() {
var item = this._listBox.querySelector("richlistitem[remote='true'][first]");
if (item)
item.removeAttribute("first");
@@ -1784,6 +1839,15 @@ var gSearchView = {
items[items.length - 1].setAttribute("last", true);
}
+ },
+
+ onSortChanged: function(aSortBy, aAscending) {
+ var footer = this._listBox.lastChild;
+ this._listBox.removeChild(footer);
+
+ sortList(this._listBox, aSortBy, aAscending);
+ this.updateListAttributes();
+
this._listBox.appendChild(footer);
},
@@ -1860,20 +1924,22 @@ var gListView = {
if (gViewController && aRequest != gViewController.currentViewRequest)
return;
- for (let i = 0; i < aAddonsList.length; i++) {
- let item = createItem(aAddonsList[i]);
- self._listBox.appendChild(item);
- }
+ var elements = [];
- for (let i = 0; i < aInstallsList.length; i++) {
- let item = createItem(aInstallsList[i], true);
- self._listBox.appendChild(item);
- }
+ for (let i = 0; i < aAddonsList.length; i++)
+ elements.push(createItem(aAddonsList[i]));
- if (self._listBox.childElementCount > 0)
- self.onSortChanged(self._sorters.sortBy, self._sorters.ascending);
- else
+ for (let i = 0; i < aInstallsList.length; i++)
+ elements.push(createItem(aInstallsList[i], true));
+
+ if (elements.length > 0) {
+ sortElements(elements, self._sorters.sortBy, self._sorters.ascending);
+ elements.forEach(function(aElement) {
+ self._listBox.appendChild(aElement);
+ });
+ } else {
self.showEmptyNotice(true);
+ }
gEventManager.registerInstallListener(self);
gViewController.updateCommands();
@@ -1906,13 +1972,7 @@ var gListView = {
},
onSortChanged: function(aSortBy, aAscending) {
- var hints = aAscending ? "ascending" : "descending";
- if (INTEGER_FIELDS.indexOf(aSortBy) >= 0)
- hints += " integer";
-
- var sortService = Cc["@mozilla.org/xul/xul-sort-service;1"].
- getService(Ci.nsIXULSortService);
- sortService.sort(this._listBox, aSortBy, hints);
+ sortList(this._listBox, aSortBy, aAscending);
},
onNewInstall: function(aInstall) {
@@ -2402,19 +2462,23 @@ var gUpdatesView = {
if (gViewController && aRequest != gViewController.currentViewRequest)
return;
+ var elements = [];
let threshold = Date.now() - UPDATES_RECENT_TIMESPAN;
aAddonsList.forEach(function(aAddon) {
if (!aAddon.updateDate || aAddon.updateDate.getTime() < threshold)
return;
- let item = createItem(aAddon);
- self._listBox.appendChild(item);
+ elements.push(createItem(aAddon));
});
- if (self._listBox.itemCount > 0)
- self.onSortChanged(self._sorters.sortBy, self._sorters.ascending);
- else
+ if (elements.length > 0) {
+ sortElements(elements, self._sorters.sortBy, self._sorters.ascending);
+ elements.forEach(function(aElement) {
+ self._listBox.appendChild(aElement);
+ });
+ } else {
self.showEmptyNotice(true);
+ }
gViewController.notifyViewChanged();
});
@@ -2440,6 +2504,8 @@ var gUpdatesView = {
self._listBox.removeItemAt(0);
}
+ var elements = [];
+
aInstallsList.forEach(function(aInstall) {
if (!self.isManualUpdate(aInstall))
return;
@@ -2449,12 +2515,15 @@ var gUpdatesView = {
item.addEventListener("IncludeUpdateChanged", function() {
self.maybeDisableUpdateSelected();
}, false);
- self._listBox.appendChild(item);
+ elements.push(item);
});
- if (self._listBox.itemCount > 0) {
+ if (elements.length > 0) {
self._updateSelected.hidden = false;
- self.onSortChanged(self._sorters.sortBy, self._sorters.ascending);
+ sortElements(elements, self._sorters.sortBy, self._sorters.ascending);
+ elements.forEach(function(aElement) {
+ self._listBox.appendChild(aElement);
+ });
} else {
self.showEmptyNotice(true);
}
@@ -2575,13 +2644,7 @@ var gUpdatesView = {
},
onSortChanged: function(aSortBy, aAscending) {
- var hints = aAscending ? "ascending" : "descending";
- if (INTEGER_FIELDS.indexOf(aSortBy) >= 0)
- hints += " integer";
-
- var sortService = Cc["@mozilla.org/xul/xul-sort-service;1"].
- getService(Ci.nsIXULSortService);
- sortService.sort(this._listBox, aSortBy, hints);
+ sortList(this._listBox, aSortBy, aAscending);
},
onNewInstall: function(aInstall) {
diff --git a/toolkit/mozapps/extensions/content/extensions.xml b/toolkit/mozapps/extensions/content/extensions.xml
index d27d33f3182..f2a2a4fe9b3 100644
--- a/toolkit/mozapps/extensions/content/extensions.xml
+++ b/toolkit/mozapps/extensions/content/extensions.xml
@@ -246,7 +246,7 @@
+ oncommand="this.parentNode._handleChange('updateDate');"/>