From: jow- args
array beginning with
diff --git a/jsapi/LuCI.dom.html b/jsapi/LuCI.dom.html
index 7b351c48e6..ccf13652ae 100644
--- a/jsapi/LuCI.dom.html
+++ b/jsapi/LuCI.dom.html
@@ -6328,7 +6328,7 @@ ignored, else not.
key
value is used as captio
@@ -7580,7 +7580,7 @@ before it is written.
diff --git a/jsapi/LuCI.form.DynamicList.html b/jsapi/LuCI.form.DynamicList.html
index f1a9747cb2..f53bef5c52 100644
--- a/jsapi/LuCI.form.DynamicList.html
+++ b/jsapi/LuCI.form.DynamicList.html
@@ -3556,7 +3556,7 @@ predefined choices. It builds upon the
@@ -7124,7 +7124,7 @@ was neither a string nor a function.
@@ -7431,7 +7431,7 @@ before it is written.
diff --git a/jsapi/LuCI.form.FileUpload.html b/jsapi/LuCI.form.FileUpload.html
index 437c752363..a20e5c985f 100644
--- a/jsapi/LuCI.form.FileUpload.html
+++ b/jsapi/LuCI.form.FileUpload.html
@@ -3555,7 +3555,7 @@ offers the ability to browse, upload and select remote files.
@@ -7335,7 +7335,7 @@ was neither a string nor a function.
@@ -7642,7 +7642,7 @@ before it is written.
diff --git a/jsapi/LuCI.form.FlagValue.html b/jsapi/LuCI.form.FlagValue.html
index 9640d8d915..597f7de355 100644
--- a/jsapi/LuCI.form.FlagValue.html
+++ b/jsapi/LuCI.form.FlagValue.html
@@ -3555,7 +3555,7 @@ implement a simple checkbox element.
@@ -5438,7 +5438,7 @@ argument, this parameter is ignored.
@@ -6420,7 +6420,7 @@ so it may return promises if overridden by user code.
@@ -6843,7 +6843,7 @@ implement alternative removal logic, e.g. to retain the original value.
@@ -7213,7 +7213,7 @@ was neither a string nor a function.
@@ -7520,7 +7520,7 @@ before it is written.
diff --git a/jsapi/LuCI.form.GridSection.html b/jsapi/LuCI.form.GridSection.html
index 55f77df215..ff9bd24bf8 100644
--- a/jsapi/LuCI.form.GridSection.html
+++ b/jsapi/LuCI.form.GridSection.html
@@ -3568,7 +3568,7 @@ documentation for details.
@@ -4581,7 +4581,7 @@ The default is null
, means inheriting from the parent form.
@@ -6137,7 +6137,7 @@ descendent of AbstractValue
.
@@ -6390,7 +6390,7 @@ not meeting the validation constraints of their respective elements.
@@ -7078,7 +7078,7 @@ was neither a string nor a function.
diff --git a/jsapi/LuCI.form.HiddenValue.html b/jsapi/LuCI.form.HiddenValue.html
index 85e11a689a..1c664eddf7 100644
--- a/jsapi/LuCI.form.HiddenValue.html
+++ b/jsapi/LuCI.form.HiddenValue.html
@@ -3560,7 +3560,7 @@ distorted form layout when rendering the option element.
@@ -7128,7 +7128,7 @@ was neither a string nor a function.
@@ -7435,7 +7435,7 @@ before it is written.
diff --git a/jsapi/LuCI.form.JSONMap.html b/jsapi/LuCI.form.JSONMap.html
index 4fc5f1d334..ba3355e4ea 100644
--- a/jsapi/LuCI.form.JSONMap.html
+++ b/jsapi/LuCI.form.JSONMap.html
@@ -5896,7 +5896,7 @@ was neither a string nor a function.
diff --git a/jsapi/LuCI.form.ListValue.html b/jsapi/LuCI.form.ListValue.html
index 7b00e17b00..e6d4673340 100644
--- a/jsapi/LuCI.form.ListValue.html
+++ b/jsapi/LuCI.form.ListValue.html
@@ -3556,7 +3556,7 @@ It builds upon the LuCI.ui.Select
@@ -7273,7 +7273,7 @@ was neither a string nor a function.
@@ -7580,7 +7580,7 @@ before it is written.
diff --git a/jsapi/LuCI.form.Map.html b/jsapi/LuCI.form.Map.html
index c7b1f50bbf..094487196b 100644
--- a/jsapi/LuCI.form.Map.html
+++ b/jsapi/LuCI.form.Map.html
@@ -5875,7 +5875,7 @@ was neither a string nor a function.
diff --git a/jsapi/LuCI.form.MultiValue.html b/jsapi/LuCI.form.MultiValue.html
index 70ba05e5c3..e0cd6372d2 100644
--- a/jsapi/LuCI.form.MultiValue.html
+++ b/jsapi/LuCI.form.MultiValue.html
@@ -3556,7 +3556,7 @@ select dropdown element.
@@ -7224,7 +7224,7 @@ was neither a string nor a function.
@@ -7531,7 +7531,7 @@ before it is written.
diff --git a/jsapi/LuCI.form.NamedSection.html b/jsapi/LuCI.form.NamedSection.html
index 24575f86ec..ca0f4b3ea6 100644
--- a/jsapi/LuCI.form.NamedSection.html
+++ b/jsapi/LuCI.form.NamedSection.html
@@ -3557,7 +3557,7 @@ specified when constructing the class instance.
@@ -4089,7 +4089,7 @@ this property will hold a reference to the parent option instance.
@@ -5536,7 +5536,7 @@ not meeting the validation constraints of their respective elements.
@@ -6480,7 +6480,7 @@ was neither a string nor a function.
diff --git a/jsapi/LuCI.form.SectionValue.html b/jsapi/LuCI.form.SectionValue.html
index dbfa3603ff..8540e633b3 100644
--- a/jsapi/LuCI.form.SectionValue.html
+++ b/jsapi/LuCI.form.SectionValue.html
@@ -3555,7 +3555,7 @@ element container, allowing to nest form sections into other sections.
@@ -4999,7 +4999,7 @@ within the given specific section.
@@ -5392,7 +5392,7 @@ argument, this parameter is ignored.
@@ -6190,7 +6190,7 @@ returns false
.
@@ -6373,7 +6373,7 @@ so it may return promises if overridden by user code.
@@ -6524,7 +6524,7 @@ validation constraints.
@@ -7165,7 +7165,7 @@ was neither a string nor a function.
@@ -7311,7 +7311,7 @@ or a plain text string. If omitted, the key
value is used as captio
@@ -7462,7 +7462,7 @@ its write()
implementation is a no-op.
diff --git a/jsapi/LuCI.form.TableSection.html b/jsapi/LuCI.form.TableSection.html
index 5704533c12..d7e31c7dd7 100644
--- a/jsapi/LuCI.form.TableSection.html
+++ b/jsapi/LuCI.form.TableSection.html
@@ -4775,7 +4775,7 @@ The default is null
, means inheriting from the parent form.
@@ -7254,7 +7254,7 @@ was neither a string nor a function.
diff --git a/jsapi/LuCI.form.TextValue.html b/jsapi/LuCI.form.TextValue.html
index dd8a082000..686fa6693a 100644
--- a/jsapi/LuCI.form.TextValue.html
+++ b/jsapi/LuCI.form.TextValue.html
@@ -3555,7 +3555,7 @@
@@ -7478,7 +7478,7 @@ before it is written.
diff --git a/jsapi/LuCI.form.TypedSection.html b/jsapi/LuCI.form.TypedSection.html
index 9c9dc526f8..a8d0e95a8b 100644
--- a/jsapi/LuCI.form.TypedSection.html
+++ b/jsapi/LuCI.form.TypedSection.html
@@ -6739,7 +6739,7 @@ was neither a string nor a function.
diff --git a/jsapi/LuCI.form.Value.html b/jsapi/LuCI.form.Value.html
index 5f64a3c796..48cf13121d 100644
--- a/jsapi/LuCI.form.Value.html
+++ b/jsapi/LuCI.form.Value.html
@@ -3556,7 +3556,7 @@
@@ -6602,7 +6602,7 @@ implement alternative removal logic, e.g. to retain the original value.
@@ -7230,7 +7230,7 @@ was neither a string nor a function.
@@ -7537,7 +7537,7 @@ before it is written.
diff --git a/jsapi/LuCI.form.html b/jsapi/LuCI.form.html
index f592a5df85..8d69e3b823 100644
--- a/jsapi/LuCI.form.html
+++ b/jsapi/LuCI.form.html
@@ -3585,7 +3585,7 @@ m.render().then(function(node) {
@@ -3738,7 +3738,7 @@ m.render().then(function(node) {
diff --git a/jsapi/LuCI.fs.html b/jsapi/LuCI.fs.html
index 8133ace978..6e43c20750 100644
--- a/jsapi/LuCI.fs.html
+++ b/jsapi/LuCI.fs.html
@@ -5915,7 +5915,7 @@ the failure reason.
diff --git a/jsapi/LuCI.headers.html b/jsapi/LuCI.headers.html
index 353d58c4d2..d7323795d3 100644
--- a/jsapi/LuCI.headers.html
+++ b/jsapi/LuCI.headers.html
@@ -3943,7 +3943,7 @@ Note: Header-Names are case-insensitive.
diff --git a/jsapi/LuCI.html b/jsapi/LuCI.html
index e2542ee764..5385c85f41 100644
--- a/jsapi/LuCI.html
+++ b/jsapi/LuCI.html
@@ -8138,7 +8138,7 @@ else null
.
diff --git a/jsapi/LuCI.network.Device.html b/jsapi/LuCI.network.Device.html
index 0f079fbde2..737f9efc42 100644
--- a/jsapi/LuCI.network.Device.html
+++ b/jsapi/LuCI.network.Device.html
@@ -6308,7 +6308,7 @@ when it is down or absent.
diff --git a/jsapi/LuCI.network.Hosts.html b/jsapi/LuCI.network.Hosts.html
index e0bd0acc89..58156bd714 100644
--- a/jsapi/LuCI.network.Hosts.html
+++ b/jsapi/LuCI.network.Hosts.html
@@ -4869,7 +4869,7 @@ is used as hint.
diff --git a/jsapi/LuCI.network.Protocol.html b/jsapi/LuCI.network.Protocol.html
index a72485a6da..a524a99f83 100644
--- a/jsapi/LuCI.network.Protocol.html
+++ b/jsapi/LuCI.network.Protocol.html
@@ -8099,7 +8099,7 @@ configuration.
diff --git a/jsapi/LuCI.network.WifiDevice.html b/jsapi/LuCI.network.WifiDevice.html
index 70aae969ac..cf11cd3ca6 100644
--- a/jsapi/LuCI.network.WifiDevice.html
+++ b/jsapi/LuCI.network.WifiDevice.html
@@ -5240,7 +5240,7 @@ configuration.
diff --git a/jsapi/LuCI.network.WifiNetwork.html b/jsapi/LuCI.network.WifiNetwork.html
index b898728b7c..ab51422f5e 100644
--- a/jsapi/LuCI.network.WifiNetwork.html
+++ b/jsapi/LuCI.network.WifiNetwork.html
@@ -7830,7 +7830,7 @@ configuration.
diff --git a/jsapi/LuCI.network.html b/jsapi/LuCI.network.html
index f1486bd9d0..70e48cb434 100644
--- a/jsapi/LuCI.network.html
+++ b/jsapi/LuCI.network.html
@@ -9678,7 +9678,7 @@ conjunction with quality
to calculate a quality percentage.
- Documentation generated by JSDoc 3.6.10 on Thu Feb 24 2022 08:05:08 GMT+0000 (Coordinated Universal Time)
+ Documentation generated by JSDoc 3.6.10 on Fri Feb 25 2022 11:36:33 GMT+0000 (Coordinated Universal Time)
diff --git a/jsapi/LuCI.poll.html b/jsapi/LuCI.poll.html
index 2b6cb9cfb1..e406feb373 100644
--- a/jsapi/LuCI.poll.html
+++ b/jsapi/LuCI.poll.html
@@ -4326,7 +4326,7 @@ run to begin with.
diff --git a/jsapi/LuCI.request.html b/jsapi/LuCI.request.html
index 2c8185a7ad..7053e64137 100644
--- a/jsapi/LuCI.request.html
+++ b/jsapi/LuCI.request.html
@@ -5261,7 +5261,7 @@ instances as sole argument during the HTTP request transfer.
diff --git a/jsapi/LuCI.request.poll.html b/jsapi/LuCI.request.poll.html
index 77387becdd..9a3a47ff78 100644
--- a/jsapi/LuCI.request.poll.html
+++ b/jsapi/LuCI.request.poll.html
@@ -4445,7 +4445,7 @@ else null
.
diff --git a/jsapi/LuCI.response.html b/jsapi/LuCI.response.html
index 905fa02d15..8a4ac78248 100644
--- a/jsapi/LuCI.response.html
+++ b/jsapi/LuCI.response.html
@@ -4403,7 +4403,7 @@ using String()
and treated as response text.
diff --git a/jsapi/LuCI.rpc.html b/jsapi/LuCI.rpc.html
index 6d3274e6f2..f1c05449bd 100644
--- a/jsapi/LuCI.rpc.html
+++ b/jsapi/LuCI.rpc.html
@@ -5734,7 +5734,7 @@ to the expect
and filter
declarations.
diff --git a/jsapi/LuCI.session.html b/jsapi/LuCI.session.html
index 739343d0a8..ea5d089c85 100644
--- a/jsapi/LuCI.session.html
+++ b/jsapi/LuCI.session.html
@@ -4173,7 +4173,7 @@ being put in the session store.
diff --git a/jsapi/LuCI.uci.html b/jsapi/LuCI.uci.html
index 2033b85ba4..9073f2a15a 100644
--- a/jsapi/LuCI.uci.html
+++ b/jsapi/LuCI.uci.html
@@ -7221,7 +7221,7 @@ associated name as arguments.
diff --git a/jsapi/LuCI.ui.AbstractElement.html b/jsapi/LuCI.ui.AbstractElement.html
index 8b6a1c39ea..472dfcbf1b 100644
--- a/jsapi/LuCI.ui.AbstractElement.html
+++ b/jsapi/LuCI.ui.AbstractElement.html
@@ -5277,7 +5277,7 @@ and are displayed in a slightly faded style.
diff --git a/jsapi/LuCI.ui.Checkbox.html b/jsapi/LuCI.ui.Checkbox.html
index 32d2fb80e5..8f3d26bfb4 100644
--- a/jsapi/LuCI.ui.Checkbox.html
+++ b/jsapi/LuCI.ui.Checkbox.html
@@ -5391,7 +5391,7 @@ it is required for HTML based form submissions.
diff --git a/jsapi/LuCI.ui.ComboButton.html b/jsapi/LuCI.ui.ComboButton.html
index d99302ed7c..6f6b8a49f4 100644
--- a/jsapi/LuCI.ui.ComboButton.html
+++ b/jsapi/LuCI.ui.ComboButton.html
@@ -5421,7 +5421,7 @@ choice value as second argument.
diff --git a/jsapi/LuCI.ui.Combobox.html b/jsapi/LuCI.ui.Combobox.html
index ec87e8e86b..db997bad77 100644
--- a/jsapi/LuCI.ui.Combobox.html
+++ b/jsapi/LuCI.ui.Combobox.html
@@ -5324,7 +5324,7 @@ forcibly set to true
.
diff --git a/jsapi/LuCI.ui.Dropdown.html b/jsapi/LuCI.ui.Dropdown.html
index b385f02124..792bfd1f12 100644
--- a/jsapi/LuCI.ui.Dropdown.html
+++ b/jsapi/LuCI.ui.Dropdown.html
@@ -6122,7 +6122,7 @@ expression. Only applicable when create
is true
.
diff --git a/jsapi/LuCI.ui.DynamicList.html b/jsapi/LuCI.ui.DynamicList.html
index add391693b..ac4a153257 100644
--- a/jsapi/LuCI.ui.DynamicList.html
+++ b/jsapi/LuCI.ui.DynamicList.html
@@ -5499,7 +5499,7 @@ it to remain unselected.
diff --git a/jsapi/LuCI.ui.FileUpload.html b/jsapi/LuCI.ui.FileUpload.html
index 9bf09378c5..0ca176437d 100644
--- a/jsapi/LuCI.ui.FileUpload.html
+++ b/jsapi/LuCI.ui.FileUpload.html
@@ -5348,7 +5348,7 @@ ACL setup for the current session.
diff --git a/jsapi/LuCI.ui.Hiddenfield.html b/jsapi/LuCI.ui.Hiddenfield.html
index c5f1913317..f3ebc6035a 100644
--- a/jsapi/LuCI.ui.Hiddenfield.html
+++ b/jsapi/LuCI.ui.Hiddenfield.html
@@ -5102,7 +5102,7 @@ trigger validation runs, e.g. when programmatically altering values.
diff --git a/jsapi/LuCI.ui.Select.html b/jsapi/LuCI.ui.Select.html
index 93f57e9275..d91663b3f3 100644
--- a/jsapi/LuCI.ui.Select.html
+++ b/jsapi/LuCI.ui.Select.html
@@ -5451,7 +5451,7 @@ selected yet. Only applicable to the select
widget type.
diff --git a/jsapi/LuCI.ui.Textarea.html b/jsapi/LuCI.ui.Textarea.html
index dab554af43..22bbe20731 100644
--- a/jsapi/LuCI.ui.Textarea.html
+++ b/jsapi/LuCI.ui.Textarea.html
@@ -5400,7 +5400,7 @@ contents.
diff --git a/jsapi/LuCI.ui.Textfield.html b/jsapi/LuCI.ui.Textfield.html
index 2354730068..dfe7879246 100644
--- a/jsapi/LuCI.ui.Textfield.html
+++ b/jsapi/LuCI.ui.Textfield.html
@@ -5328,7 +5328,7 @@ corresponding <input>
element is empty.
diff --git a/jsapi/LuCI.ui.changes.html b/jsapi/LuCI.ui.changes.html
index 2f34af3366..9bd242600b 100644
--- a/jsapi/LuCI.ui.changes.html
+++ b/jsapi/LuCI.ui.changes.html
@@ -3559,7 +3559,7 @@ external JavaScript, use L.require("ui").then(...)
and ac
@@ -3644,7 +3644,7 @@ external JavaScript, use L.require("ui").then(...)
and ac
@@ -3785,7 +3785,7 @@ settings.
@@ -3858,7 +3858,7 @@ and offer options to revert or apply the shown changes.
@@ -3976,7 +3976,7 @@ UCI changeset structure.
@@ -4052,7 +4052,7 @@ complete.
@@ -4180,7 +4180,7 @@ is removed.
diff --git a/jsapi/LuCI.ui.html b/jsapi/LuCI.ui.html
index aab3a4c7db..5bec35fd9e 100644
--- a/jsapi/LuCI.ui.html
+++ b/jsapi/LuCI.ui.html
@@ -3556,7 +3556,7 @@ external JavaScript, use L.require("ui").then(...)
.
@@ -3687,7 +3687,7 @@ external JavaScript, use L.require("ui").then(...)
.
@@ -3917,7 +3917,7 @@ banner element.
@@ -4231,7 +4231,7 @@ trigger field validation or to bind it to further events.
@@ -4368,7 +4368,7 @@ default.
@@ -4594,7 +4594,7 @@ valid function value.
@@ -4742,7 +4742,7 @@ requested indicator was not found.
@@ -4818,7 +4818,7 @@ handler as-is without the need to bind it first.
@@ -4970,7 +4970,7 @@ catched and rendered using LuCI.error()
@@ -5212,7 +5212,7 @@ accepted by LuCI.dom.content()
.
@@ -5415,7 +5415,7 @@ or rejecting with null
when the connectivity check timed out.
@@ -5686,7 +5686,7 @@ changes were made.
@@ -5915,7 +5915,7 @@ element.
@@ -6273,7 +6273,7 @@ cancelled by the user.
diff --git a/jsapi/LuCI.ui.menu.html b/jsapi/LuCI.ui.menu.html
index 82f1b74738..07d3582520 100644
--- a/jsapi/LuCI.ui.menu.html
+++ b/jsapi/LuCI.ui.menu.html
@@ -4227,7 +4227,7 @@ internal root node if omitted.
diff --git a/jsapi/LuCI.ui.tabs.html b/jsapi/LuCI.ui.tabs.html
index ce784b9fb5..924dfd84ab 100644
--- a/jsapi/LuCI.ui.tabs.html
+++ b/jsapi/LuCI.ui.tabs.html
@@ -3560,7 +3560,7 @@ external JavaScript, use L.require("ui").then(...)
and ac
@@ -3645,7 +3645,7 @@ external JavaScript, use L.require("ui").then(...)
and ac
@@ -3774,7 +3774,7 @@ DOM node.
@@ -3927,7 +3927,7 @@ DOM node.
diff --git a/jsapi/LuCI.view.html b/jsapi/LuCI.view.html
index 6d895faaeb..217c0a3931 100644
--- a/jsapi/LuCI.view.html
+++ b/jsapi/LuCI.view.html
@@ -4531,7 +4531,7 @@ to a Node
value.
diff --git a/jsapi/LuCI.xhr.html b/jsapi/LuCI.xhr.html
index fe962babdb..62d54337af 100644
--- a/jsapi/LuCI.xhr.html
+++ b/jsapi/LuCI.xhr.html
@@ -4495,7 +4495,7 @@ when invoked.
diff --git a/jsapi/form.js.html b/jsapi/form.js.html
index d872107c35..c893af2ac4 100644
--- a/jsapi/form.js.html
+++ b/jsapi/form.js.html
@@ -6145,7 +6145,8 @@ var CBITableSection = CBITypedSection.extend(/** @lends LuCI.form.TableSection.p
if (has_titles) {
var trEl = E('tr', {
'class': 'tr cbi-section-table-titles ' + anon_class,
- 'data-title': (!this.anonymous || this.sectiontitle) ? _('Name') : null
+ 'data-title': (!this.anonymous || this.sectiontitle) ? _('Name') : null,
+ 'click': this.sortable ? ui.createHandlerFn(this, 'handleSort') : null
});
for (var i = 0, opt; i < max_cols && (opt = this.children[i]) != null; i++) {
@@ -6154,7 +6155,8 @@ var CBITableSection = CBITypedSection.extend(/** @lends LuCI.form.TableSection.p
trEl.appendChild(E('th', {
'class': 'th cbi-section-table-cell',
- 'data-widget': opt.__name__
+ 'data-widget': opt.__name__,
+ 'data-sortable-row': this.sortable ? '' : null
}));
if (opt.width != null)
@@ -6564,6 +6566,68 @@ var CBITableSection = CBITypedSection.extend(/** @lends LuCI.form.TableSection.p
.catch(function() {});
},
+ /** @private */
+ handleSort: function(ev) {
+ if (!ev.target.matches('th[data-sortable-row]'))
+ return;
+
+ var th = ev.target,
+ descending = (th.getAttribute('data-sort-direction') == 'desc'),
+ config_name = this.uciconfig || this.map.config,
+ index = 0,
+ list = [];
+
+ ev.currentTarget.querySelectorAll('th').forEach(function(other_th, i) {
+ if (other_th !== th)
+ other_th.removeAttribute('data-sort-direction');
+ else
+ index = i;
+ });
+
+ ev.currentTarget.parentNode.querySelectorAll('tr.cbi-section-table-row').forEach(L.bind(function(tr, i) {
+ var sid = tr.getAttribute('data-sid'),
+ opt = tr.childNodes[index].getAttribute('data-name'),
+ val = this.cfgvalue(sid, opt);
+
+ tr.querySelectorAll('.flash').forEach(function(n) {
+ n.classList.remove('flash')
+ });
+
+ list.push([
+ ui.Table.prototype.deriveSortKey((val != null) ? val.trim() : ''),
+ tr
+ ]);
+ }, 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;
+ });
+
+ window.requestAnimationFrame(L.bind(function() {
+ var ref_sid, cur_sid;
+
+ for (var i = 0; i < list.length; i++) {
+ list[i][1].childNodes[index].classList.add('flash');
+ th.parentNode.parentNode.appendChild(list[i][1]);
+
+ cur_sid = list[i][1].getAttribute('data-sid');
+
+ if (ref_sid)
+ this.map.data.move(config_name, cur_sid, ref_sid, true);
+
+ ref_sid = cur_sid;
+ }
+
+ th.setAttribute('data-sort-direction', descending ? 'asc' : 'desc');
+ }, this));
+ },
+
/**
* Add further options to the per-section instanced modal popup.
*
@@ -8281,7 +8345,7 @@ return baseclass.extend(/** @lends LuCI.form.prototype */ {
diff --git a/jsapi/fs.js.html b/jsapi/fs.js.html
index 2d962a0264..ecae9b7b08 100644
--- a/jsapi/fs.js.html
+++ b/jsapi/fs.js.html
@@ -3969,7 +3969,7 @@ return FileSystem;
diff --git a/jsapi/index.html b/jsapi/index.html
index 0bb21ead7c..dc2e3bb3ec 100644
--- a/jsapi/index.html
+++ b/jsapi/index.html
@@ -3556,7 +3556,7 @@ is the central JSDoc 3.6.10 on Thu Feb 24 2022 08:05:08 GMT+0000 (Coordinated Universal Time)
+ Documentation generated by JSDoc 3.6.10 on Fri Feb 25 2022 11:36:32 GMT+0000 (Coordinated Universal Time)
diff --git a/jsapi/luci.js.html b/jsapi/luci.js.html
index 73d8a256f6..c1c865047a 100644
--- a/jsapi/luci.js.html
+++ b/jsapi/luci.js.html
@@ -6963,7 +6963,7 @@
diff --git a/jsapi/network.js.html b/jsapi/network.js.html
index feb734a465..0d4ddd1734 100644
--- a/jsapi/network.js.html
+++ b/jsapi/network.js.html
@@ -7929,7 +7929,7 @@ return Network;
diff --git a/jsapi/rpc.js.html b/jsapi/rpc.js.html
index ecbe60b237..a0287d1d5e 100644
--- a/jsapi/rpc.js.html
+++ b/jsapi/rpc.js.html
@@ -4025,7 +4025,7 @@ return baseclass.extend(/** @lends LuCI.rpc.prototype */ {
diff --git a/jsapi/uci.js.html b/jsapi/uci.js.html
index ac4003575e..0132423368 100644
--- a/jsapi/uci.js.html
+++ b/jsapi/uci.js.html
@@ -4525,7 +4525,7 @@ return baseclass.extend(/** @lends LuCI.uci.prototype */ {
diff --git a/jsapi/ui.js.html b/jsapi/ui.js.html
index f684412de4..f4fb72fbb4 100644
--- a/jsapi/ui.js.html
+++ b/jsapi/ui.js.html
@@ -6670,6 +6670,299 @@ var UIMenu = baseclass.singleton(/** @lends LuCI.ui.menu.prototype */ {
}
});
+var UITable = baseclass.extend(/** @lends LuCI.ui.table.prototype */ {
+ __init__: function(captions, options, placeholder) {
+ if (!Array.isArray(captions)) {
+ this.initFromMarkup(captions);
+
+ return;
+ }
+
+ var id = options.id || 'table%08x'.format(Math.random() * 0xffffffff);
+
+ var table = E('table', { 'id': id, 'class': 'table' }, [
+ E('tr', { 'class': 'tr table-titles', 'click': UI.prototype.createHandlerFn(this, 'handleSort') })
+ ]);
+
+ this.id = id;
+ this.node = table
+ this.options = options;
+
+ var sorting = this.getActiveSortState();
+
+ for (var i = 0; i < captions.length; i++) {
+ if (captions[i] == null)
+ continue;
+
+ var th = E('th', { 'class': 'th' }, [ captions[i] ]);
+
+ if (typeof(options.captionClasses) == 'object')
+ DOMTokenList.prototype.add.apply(th.classList, L.toArray(options.captionClasses[i]));
+
+ if (options.sortable !== false && (typeof(options.sortable) != 'object' || options.sortable[i] !== false)) {
+ th.setAttribute('data-sortable-row', true);
+
+ if (sorting && sorting[0] == i)
+ th.setAttribute('data-sort-direction', sorting[1] ? 'desc' : 'asc');
+ }
+
+ table.firstElementChild.appendChild(th);
+ }
+
+ if (placeholder) {
+ var trow = table.appendChild(E('tr', { 'class': 'tr placeholder' })),
+ td = trow.appendChild(E('td', { 'class': 'td' }, placeholder));
+
+ if (typeof(captionClasses) == 'object')
+ DOMTokenList.prototype.add.apply(td.classList, L.toArray(captionClasses[0]));
+ }
+
+ DOMTokenList.prototype.add.apply(table.classList, L.toArray(options.classes));
+ },
+
+ update: function(data, placeholder) {
+ var placeholder = placeholder || this.options.placeholder || _('No data', 'empty table placeholder'),
+ sorting = this.getActiveSortState();
+
+ if (!Array.isArray(data))
+ return;
+
+ if (sorting) {
+ var list = data.map(L.bind(function(row) {
+ return [ this.deriveSortKey(row[sorting[0]], sorting[0]), row ];
+ }, 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;
+ });
+
+ data.length = 0;
+
+ list.forEach(function(item) {
+ data.push(item[1]);
+ });
+ }
+
+ this.data = data;
+ this.placeholder = placeholder;
+
+ var n = 0,
+ rows = this.node.querySelectorAll('tr'),
+ trows = [],
+ headings = [].slice.call(this.node.firstElementChild.querySelectorAll('th')),
+ captionClasses = this.options.captionClasses;
+
+ data.forEach(function(row) {
+ trows[n] = E('tr', { 'class': 'tr' });
+
+ for (var i = 0; i < headings.length; i++) {
+ var text = (headings[i].innerText || '').trim();
+ var td = trows[n].appendChild(E('td', {
+ 'class': 'td',
+ 'data-title': (text !== '') ? text : null
+ }, (row[i] != null) ? row[i] : ''));
+
+ if (typeof(captionClasses) == 'object')
+ DOMTokenList.prototype.add.apply(td.classList, L.toArray(captionClasses[i]));
+
+ if (!td.classList.contains('cbi-section-actions'))
+ headings[i].setAttribute('data-sortable-row', true);
+ }
+
+ trows[n].classList.add('cbi-rowstyle-%d'.format((n++ % 2) ? 2 : 1));
+ });
+
+ for (var i = 0; i < n; i++) {
+ if (rows[i+1])
+ this.node.replaceChild(trows[i], rows[i+1]);
+ else
+ this.node.appendChild(trows[i]);
+ }
+
+ while (rows[++n])
+ target.removeChild(rows[n]);
+
+ if (placeholder && this.node.firstElementChild === this.node.lastElementChild) {
+ var trow = this.node.appendChild(E('tr', { 'class': 'tr placeholder' })),
+ td = trow.appendChild(E('td', { 'class': 'td' }, placeholder));
+
+ if (typeof(captionClasses) == 'object')
+ DOMTokenList.prototype.add.apply(td.classList, L.toArray(captionClasses[0]));
+ }
+
+ return this.node;
+ },
+
+ render: function() {
+ return this.node;
+ },
+
+ /** @private */
+ initFromMarkup: function(node) {
+ if (!dom.elem(node))
+ node = document.querySelector(node);
+
+ if (!node)
+ throw 'Invalid table selector';
+
+ var options = {},
+ headrow = node.querySelector('tr, .tr');
+
+ if (!headrow)
+ return;
+
+ options.classes = [].slice.call(node.classList).filter(function(c) { return c != 'table' });
+ options.sortable = [];
+ options.captionClasses = [];
+
+ headrow.querySelectorAll('th, .th').forEach(function(th, i) {
+ options.sortable[i] = !th.classList.contains('cbi-section-actions');
+ options.captionClasses[i] = [].slice.call(th.classList).filter(function(c) { return c != 'th' });
+ });
+
+ headrow.addEventListener('click', UI.prototype.createHandlerFn(this, 'handleSort'));
+
+ this.id = node.id;
+ this.node = node;
+ this.options = options;
+ },
+
+ /** @private */
+ deriveSortKey: function(value, index) {
+ var opts = this.options || {},
+ hint, m;
+
+ if (opts.sortable == true || opts.sortable == null)
+ hint = 'auto';
+ else if (typeof( opts.sortable) == 'object')
+ hint = opts.sortable[index];
+
+ if (dom.elem(value))
+ value = value.innerText.trim();
+
+ switch (hint || 'auto') {
+ case true:
+ case 'auto':
+ m = /^([0-9a-fA-F:.]+)(?:\/([0-9a-fA-F:.]+))?$/.exec(value);
+
+ if (m) {
+ var addr, mask;
+
+ addr = validation.parseIPv6(m[1]);
+ mask = m[2] ? validation.parseIPv6(m[2]) : null;
+
+ if (addr && mask != null)
+ return '%04x%04x%04x%04x%04x%04x%04x%04x%04x%04x%04x%04x%04x%04x%04x%04x'.format(
+ addr[0], addr[1], addr[2], addr[3], addr[4], addr[5], addr[6], addr[7],
+ mask[0], mask[1], mask[2], mask[3], mask[4], mask[5], mask[6], mask[7]
+ );
+ else if (addr)
+ return '%04x%04x%04x%04x%04x%04x%04x%04x%02x'.format(
+ addr[0], addr[1], addr[2], addr[3], addr[4], addr[5], addr[6], addr[7],
+ m[2] ? +m[2] : 128
+ );
+
+ addr = validation.parseIPv4(m[1]);
+ mask = m[2] ? validation.parseIPv4(m[2]) : null;
+
+ if (addr && mask != null)
+ return '%03d%03d%03d%03d%03d%03d%03d%03d'.format(
+ addr[0], addr[1], addr[2], addr[3],
+ mask[0], mask[1], mask[2], mask[3]
+ );
+ else if (addr)
+ return '%03d%03d%03d%03d%02d'.format(
+ addr[0], addr[1], addr[2], addr[3],
+ m[2] ? +m[2] : 32
+ );
+ }
+
+ m = /^(?:(\d+)d )?(\d+)h (\d+)m (\d+)s$/.exec(value);
+
+ if (m)
+ return '%05d%02d%02d%02d'.format(+m[1], +m[2], +m[3], +m[4]);
+
+ m = /^(\d+)\b(\D*)$/.exec(value);
+
+ if (m)
+ return '%010d%s'.format(+m[1], m[2]);
+
+ return String(value);
+
+ case 'ignorecase':
+ return String(value).toLowerCase();
+
+ case 'numeric':
+ return +value;
+
+ default:
+ return String(value);
+ }
+ },
+
+ /** @private */
+ getActiveSortState: function() {
+ if (this.sortState)
+ return this.sortState;
+
+ var page = document.body.getAttribute('data-page'),
+ key = page + '.' + this.id,
+ state = session.getLocalData('tablesort');
+
+ if (L.isObject(state) && Array.isArray(state[key]))
+ return state[key];
+
+ return null;
+ },
+
+ /** @private */
+ setActiveSortState: function(index, descending) {
+ this.sortState = [ index, descending ];
+
+ if (!this.options.id)
+ return;
+
+ var page = document.body.getAttribute('data-page'),
+ key = page + '.' + this.id,
+ state = session.getLocalData('tablesort');
+
+ if (!L.isObject(state))
+ state = {};
+
+ state[key] = this.sortState;
+
+ session.setLocalData('tablesort', state);
+ },
+
+ /** @private */
+ handleSort: function(ev) {
+ if (!ev.target.matches('th[data-sortable-row]'))
+ return;
+
+ var th = ev.target,
+ direction = (th.getAttribute('data-sort-direction') == 'asc'),
+ index = 0;
+
+ this.node.firstElementChild.querySelectorAll('th').forEach(function(other_th, i) {
+ if (other_th !== th)
+ other_th.removeAttribute('data-sort-direction');
+ else
+ index = i;
+ });
+
+ th.setAttribute('data-sort-direction', direction ? 'desc' : 'asc');
+
+ this.setActiveSortState(index, direction);
+ this.update(this.data, this.placeholder);
+ }
+});
+
/**
* @class ui
* @memberof LuCI
@@ -8049,6 +8342,8 @@ var UI = baseclass.extend(/** @lends LuCI.ui.prototype */ {
menu: UIMenu,
+ Table: UITable,
+
AbstractElement: UIElement,
/* Widgets */
@@ -8077,7 +8372,7 @@ return UI;