luci-base: revise array sorting
authorJo-Philipp Wich <jo@mein.io>
Wed, 27 Jul 2022 15:19:08 +0000 (17:19 +0200)
committerJo-Philipp Wich <jo@mein.io>
Wed, 27 Jul 2022 15:32:58 +0000 (17:32 +0200)
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>
modules/luci-base/htdocs/luci-static/resources/form.js
modules/luci-base/htdocs/luci-static/resources/network.js
modules/luci-base/htdocs/luci-static/resources/tools/widgets.js
modules/luci-base/htdocs/luci-static/resources/ui.js

index aae8b3684a0cce56518df5299bfbb9fa74b829c2..2d540420bca5f53e1a933c697896e5170661636d 100644 (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() {
index 864cbba52c900c48f0acee6fef2414fbee649992..e0013c8ec05ab7715d409cc3a012578a79b547ee 100644 (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;
-
-    if (weightA != weightB)
-       return weightA - weightB;
+       var typeWeigth = { wifi: 2, alias: 3 };
 
-       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());
        },
 
        /**
index ae17d8197d5dd207df3165947ab4593eb1deb533..14948bbf0f8f9764f286e086ad9d7ad3b1a5b4be 100644 (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]))
index 2c4a9bf39561524671c46e2e68093fc002776c31..ef6e33421614bf3c24e0793d165cca43f50777f6 100644 (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;