luci-base: revise array sorting

Refactor various sort operations throughout luci-base to use the new
L.naturalCompare() comparator function.

This primarily ensures that embedded numbers are sorted numerically and
not in a lexicographical way.

It also simplifies some code as a side effect.

Ref: #5899
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
This commit is contained in:
Jo-Philipp Wich 2022-07-27 17:19:08 +02:00
parent 8199b2ce9a
commit 37422e891a
4 changed files with 25 additions and 66 deletions

View file

@ -74,7 +74,7 @@ var CBIJSONConfig = baseclass.extend({
if (indexA != indexB)
return (indexA - indexB);
return (a > b);
return L.naturalCompare(a, b);
}, this));
for (var i = 0; i < section_ids.length; i++)
@ -3080,13 +3080,9 @@ var CBITableSection = CBITypedSection.extend(/** @lends LuCI.form.TableSection.p
}, this));
list.sort(function(a, b) {
if (a[0] < b[0])
return descending ? 1 : -1;
if (a[0] > b[0])
return descending ? -1 : 1;
return 0;
return descending
? -L.naturalCompare(a[0], b[0])
: L.naturalCompare(a[0], b[0]);
});
window.requestAnimationFrame(L.bind(function() {

View file

@ -101,15 +101,6 @@ var _init = null,
_protocols = {},
_protospecs = {};
function strcmp(a, b) {
if (a > b)
return 1;
else if (a < b)
return -1;
else
return 0;
}
function getProtocolHandlers(cache) {
return callNetworkProtoHandlers().then(function(protos) {
/* Register "none" protocol */
@ -485,10 +476,7 @@ function initNetworkState(refresh) {
}
ports.sort(function(a, b) {
if (a.role != b.role)
return (a.role < b.role) ? -1 : 1;
return (a.index - b.index);
return L.naturalCompare(a.role, b.role) || L.naturalCompare(a.index, b.index);
});
for (var i = 0, port; (port = ports[i]) != null; i++) {
@ -562,18 +550,14 @@ function ifnameOf(obj) {
}
function networkSort(a, b) {
return strcmp(a.getName(), b.getName());
return L.naturalCompare(a.getName(), b.getName());
}
function deviceSort(a, b) {
var typeWeigth = { wifi: 2, alias: 3 },
weightA = typeWeigth[a.getType()] || 1,
weightB = typeWeigth[b.getType()] || 1;
var typeWeigth = { wifi: 2, alias: 3 };
if (weightA != weightB)
return weightA - weightB;
return strcmp(a.getName(), b.getName());
return L.naturalCompare(typeWeigth[a.getType()] || 1, typeWeigth[b.getType()] || 1) ||
L.naturalCompare(a.getName(), b.getName());
}
function formatWifiEncryption(enc) {
@ -1441,7 +1425,7 @@ Network = baseclass.extend(/** @lends LuCI.network.prototype */ {
rv.push(this.lookupWifiNetwork(wifiIfaces[i]['.name']));
rv.sort(function(a, b) {
return strcmp(a.getID(), b.getID());
return L.naturalCompare(a.getID(), b.getID());
});
return rv;
@ -1539,10 +1523,7 @@ Network = baseclass.extend(/** @lends LuCI.network.prototype */ {
}
rv.sort(function(a, b) {
if (a.metric != b.metric)
return (a.metric - b.metric);
return strcmp(a.interface, b.interface);
return L.naturalCompare(a.metric, b.metric) || L.naturalCompare(a.interface, b.interface);
});
return rv;
@ -1990,7 +1971,7 @@ Hosts = baseclass.extend(/** @lends LuCI.network.Hosts.prototype */ {
}
return rv.sort(function(a, b) {
return strcmp(a[0], b[0]);
return L.naturalCompare(a[0], b[0]);
});
}
});
@ -3419,19 +3400,10 @@ WifiDevice = baseclass.extend(/** @lends LuCI.network.WifiDevice.prototype */ {
if (this.ubus('dev', 'iwinfo', 'type') == 'wl')
type = 'Broadcom';
var hwmodes = this.getHWModes(),
modestr = '';
hwmodes.sort(function(a, b) {
if (a.length != b.length)
return a.length - b.length;
return strcmp(a, b);
});
modestr = hwmodes.join('');
return '%s 802.11%s Wireless Controller (%s)'.format(type || 'Generic', modestr, this.getName());
return '%s 802.11%s Wireless Controller (%s)'.format(
type || 'Generic',
this.getHWModes().sort(L.naturalCompare).join(''),
this.getName());
},
/**

View file

@ -537,7 +537,7 @@ var CBIDeviceSelect = form.ListValue.extend({
}
if (!this.nocreate) {
var keys = Object.keys(checked).sort();
var keys = Object.keys(checked).sort(L.naturalCompare);
for (var i = 0; i < keys.length; i++) {
if (choices.hasOwnProperty(keys[i]))

View file

@ -777,7 +777,7 @@ var UISelect = UIElement.extend(/** @lends LuCI.ui.Select.prototype */ {
keys = Object.keys(this.choices);
if (this.options.sort === true)
keys.sort();
keys.sort(L.naturalCompare);
else if (Array.isArray(this.options.sort))
keys = this.options.sort;
@ -1056,7 +1056,7 @@ var UIDropdown = UIElement.extend(/** @lends LuCI.ui.Dropdown.prototype */ {
var keys = Object.keys(this.choices);
if (this.options.sort === true)
keys.sort();
keys.sort(L.naturalCompare);
else if (Array.isArray(this.options.sort))
keys = this.options.sort;
@ -2859,13 +2859,8 @@ var UIFileUpload = UIElement.extend(/** @lends LuCI.ui.FileUpload.prototype */ {
rows = E('ul');
list.sort(function(a, b) {
var isDirA = (a.type == 'directory'),
isDirB = (b.type == 'directory');
if (isDirA != isDirB)
return isDirA < isDirB;
return a.name > b.name;
return L.naturalCompare(a.type == 'directory', b.type == 'directory') ||
L.naturalCompare(a.name, b.name);
});
for (var i = 0; i < list.length; i++) {
@ -3152,7 +3147,7 @@ var UIMenu = baseclass.singleton(/** @lends LuCI.ui.menu.prototype */ {
if (wA != wB)
return wA - wB;
return a.name > b.name;
return L.naturalCompare(a.name, b.name);
});
}
});
@ -3220,13 +3215,9 @@ var UITable = baseclass.extend(/** @lends LuCI.ui.table.prototype */ {
}, this));
list.sort(function(a, b) {
if (a[0] < b[0])
return sorting[1] ? 1 : -1;
if (a[0] > b[0])
return sorting[1] ? -1 : 1;
return 0;
return sorting[1]
? -L.naturalCompare(a[0], b[0])
: L.naturalCompare(a[0], b[0]);
});
data.length = 0;