From 15901c04013e6a1fef5a639661d297ed52aff955 Mon Sep 17 00:00:00 2001 From: systemcrash Date: Fri, 20 Dec 2024 00:14:58 +0000 Subject: [PATCH] deploy: 844c45076f4604385c38150b552e72fe3f651790 --- jsapi/LuCI.baseclass.html | 58 +- jsapi/LuCI.dom.html | 34 +- jsapi/LuCI.form.AbstractElement.html | 16 +- jsapi/LuCI.form.AbstractSection.html | 36 +- jsapi/LuCI.form.AbstractValue.html | 64 +- jsapi/LuCI.form.ButtonValue.html | 62 +- jsapi/LuCI.form.DummyValue.html | 62 +- jsapi/LuCI.form.DynamicList.html | 62 +- jsapi/LuCI.form.FileUpload.html | 62 +- jsapi/LuCI.form.FlagValue.html | 62 +- jsapi/LuCI.form.GridSection.html | 34 +- jsapi/LuCI.form.HiddenValue.html | 62 +- jsapi/LuCI.form.JSONMap.html | 32 +- jsapi/LuCI.form.ListValue.html | 62 +- jsapi/LuCI.form.Map.html | 32 +- jsapi/LuCI.form.MultiValue.html | 62 +- jsapi/LuCI.form.NamedSection.html | 36 +- jsapi/LuCI.form.RichListValue.html | 62 +- jsapi/LuCI.form.SectionValue.html | 62 +- jsapi/LuCI.form.TableSection.html | 34 +- jsapi/LuCI.form.TextValue.html | 60 +- jsapi/LuCI.form.TypedSection.html | 36 +- jsapi/LuCI.form.Value.html | 64 +- jsapi/LuCI.form.html | 10 +- jsapi/LuCI.fs.html | 4 +- jsapi/LuCI.headers.html | 10 +- jsapi/LuCI.html | 205 +++- jsapi/LuCI.network.Device.html | 4 +- jsapi/LuCI.network.Hosts.html | 4 +- jsapi/LuCI.network.Protocol.html | 4 +- jsapi/LuCI.network.WifiDevice.html | 4 +- jsapi/LuCI.network.WifiNetwork.html | 4 +- jsapi/LuCI.network.html | 4 +- jsapi/LuCI.poll.html | 16 +- jsapi/LuCI.request.html | 20 +- jsapi/LuCI.request.poll.html | 18 +- jsapi/LuCI.response.html | 14 +- jsapi/LuCI.rpc.html | 26 +- jsapi/LuCI.session.html | 14 +- jsapi/LuCI.uci.html | 38 +- jsapi/LuCI.ui.AbstractElement.html | 8 +- jsapi/LuCI.ui.Checkbox.html | 16 +- jsapi/LuCI.ui.ComboButton.html | 14 +- jsapi/LuCI.ui.Combobox.html | 14 +- jsapi/LuCI.ui.Dropdown.html | 20 +- jsapi/LuCI.ui.DynamicList.html | 18 +- jsapi/LuCI.ui.FileUpload.html | 14 +- jsapi/LuCI.ui.Hiddenfield.html | 14 +- jsapi/LuCI.ui.Select.html | 14 +- jsapi/LuCI.ui.Textarea.html | 14 +- jsapi/LuCI.ui.Textfield.html | 14 +- jsapi/LuCI.ui.changes.html | 16 +- jsapi/LuCI.ui.html | 30 +- jsapi/LuCI.ui.menu.html | 12 +- jsapi/LuCI.ui.tabs.html | 10 +- jsapi/LuCI.view.html | 18 +- jsapi/LuCI.xhr.html | 18 +- jsapi/form.js.html | 1324 ++++++++++---------- jsapi/fs.js.html | 4 +- jsapi/index.html | 4 +- jsapi/luci.js.html | 787 ++++++------ jsapi/network.js.html | 4 +- jsapi/rpc.js.html | 94 +- jsapi/uci.js.html | 297 +++-- jsapi/ui.js.html | 1669 +++++++++++++------------- 65 files changed, 3114 insertions(+), 2888 deletions(-) diff --git a/jsapi/LuCI.baseclass.html b/jsapi/LuCI.baseclass.html index c14e9c0ce9..8d89c0465e 100644 --- a/jsapi/LuCI.baseclass.html +++ b/jsapi/LuCI.baseclass.html @@ -86,6 +86,8 @@
  • hasViewPermission
  • +
  • isArguments
  • +
  • isObject
  • location
  • @@ -3664,7 +3666,7 @@ implements prototypal inheritance.

    - luci.js, line 61 + luci.js, line 23
    @@ -3749,7 +3751,7 @@ implements prototypal inheritance.

    - luci.js, line 89 + luci.js, line 55
    @@ -3894,12 +3896,12 @@ class constructor and can be instantiated with new.

    - staticLuCI.baseclass.instantiate(params, new_args){LuCI.baseclass} + staticLuCI.baseclass.instantiate(params){LuCI.baseclass}

    @@ -3958,49 +3960,11 @@ array being passed as variadic parameters to the constructor.

    - - - - -

    An array of arbitrary values which will be passed as arguments to the constructor function.

    - - - - new_args - - - - - -* - - - - - - - - - - - optional - - - - - repeatable - - -

    Specifies arguments to be passed to the subclass constructor -as-is in order to instantiate the new subclass.

    - - - @@ -4086,7 +4050,7 @@ enable inheritance.
    - luci.js, line 198 + luci.js, line 158
    @@ -4233,7 +4197,7 @@ a subclass of this class'.
    - luci.js, line 148 + luci.js, line 114
    @@ -4425,7 +4389,7 @@ enable inheritance.
    - luci.js, line 270 + luci.js, line 227
    @@ -4655,7 +4619,7 @@ superclass method returned null.
    - luci.js, line 228 + luci.js, line 186
    @@ -4878,7 +4842,7 @@ and the values extracted from the args array beginning with diff --git a/jsapi/LuCI.dom.html b/jsapi/LuCI.dom.html index 1844b1f65a..76d07aa733 100644 --- a/jsapi/LuCI.dom.html +++ b/jsapi/LuCI.dom.html @@ -86,6 +86,8 @@
  • hasViewPermission
  • +
  • isArguments
  • +
  • isObject
  • location
  • @@ -3665,7 +3667,7 @@ external JavaScript, use L.require("dom").then(...).

    <
    - luci.js, line 1207 + luci.js, line 1160
    @@ -3750,7 +3752,7 @@ external JavaScript, use L.require("dom").then(...).

    <
    - luci.js, line 1361 + luci.js, line 1311
    @@ -3951,7 +3953,7 @@ if either the node argument was no valid DOM node or i
    - luci.js, line 1476 + luci.js, line 1426
    @@ -4149,7 +4151,7 @@ call implicitly turning it into a string.

    - luci.js, line 1713 + luci.js, line 1663
    @@ -4350,7 +4352,7 @@ a valid Class instance.

    - luci.js, line 1767 + luci.js, line 1717
    @@ -4566,7 +4568,7 @@ instance didn't have the requested method.
    - luci.js, line 1428 + luci.js, line 1378
    @@ -4770,7 +4772,7 @@ if either the node argument was no valid DOM node or i
    - luci.js, line 1554 + luci.js, line 1504
    @@ -5030,7 +5032,7 @@ element names, such as spaces.

    - luci.js, line 1630 + luci.js, line 1580
    @@ -5269,7 +5271,7 @@ be found.
    - luci.js, line 1233 + luci.js, line 1186
    @@ -5414,7 +5416,7 @@ be found.
    - luci.js, line 1733 + luci.js, line 1683
    @@ -5564,7 +5566,7 @@ class could be found on the node itself or any of its parents.
    - luci.js, line 1813 + luci.js, line 1763
    @@ -5751,7 +5753,7 @@ result when testing it using the given ignoreFn.
    - luci.js, line 1285 + luci.js, line 1235
    @@ -5937,7 +5939,7 @@ selector didn't match.
    - luci.js, line 1312 + luci.js, line 1262
    @@ -6127,7 +6129,7 @@ selector didn't match any parent.
    - luci.js, line 1252 + luci.js, line 1205
    @@ -6282,7 +6284,7 @@ the first div element node.

    - luci.js, line 1776 + luci.js, line 1726
    @@ -6436,7 +6438,7 @@ ignored, else not.

    diff --git a/jsapi/LuCI.form.AbstractElement.html b/jsapi/LuCI.form.AbstractElement.html index adc7b05f60..a653d1fb86 100644 --- a/jsapi/LuCI.form.AbstractElement.html +++ b/jsapi/LuCI.form.AbstractElement.html @@ -86,6 +86,8 @@
  • hasViewPermission
  • +
  • isArguments
  • +
  • isObject
  • location
  • @@ -3666,7 +3668,7 @@ properties.

    - form.js, line 184 + form.js, line 186
    @@ -3751,7 +3753,7 @@ properties.

    - form.js, line 210 + form.js, line 212
    @@ -3867,7 +3869,7 @@ properties.

    - form.js, line 228 + form.js, line 230
    @@ -3973,7 +3975,7 @@ respective elements.
    - form.js, line 246 + form.js, line 248
    @@ -4079,7 +4081,7 @@ the form element's markup, including the markup of any child elements.
    - form.js, line 288 + form.js, line 289
    @@ -4226,7 +4228,7 @@ entities decoded.
    - form.js, line 327 + form.js, line 328
    @@ -4427,7 +4429,7 @@ was neither a string nor a function. diff --git a/jsapi/LuCI.form.AbstractSection.html b/jsapi/LuCI.form.AbstractSection.html index 8c8ffd73fd..7bfe00aec4 100644 --- a/jsapi/LuCI.form.AbstractSection.html +++ b/jsapi/LuCI.form.AbstractSection.html @@ -86,6 +86,8 @@
  • hasViewPermission
  • +
  • isArguments
  • +
  • isObject
  • location
  • @@ -3666,7 +3668,7 @@ form options and for handling tabs to segment child options.

    - form.js, line 815 + form.js, line 819
    @@ -3811,7 +3813,7 @@ this property will hold a reference to the parent option instance.

    - form.js, line 210 + form.js, line 212
    @@ -3927,7 +3929,7 @@ this property will hold a reference to the parent option instance.

    - form.js, line 866 + form.js, line 870
    @@ -4055,7 +4057,7 @@ The sections will be rendered in the same order as the returned array.
    - form.js, line 1085 + form.js, line 1090
    @@ -4251,7 +4253,7 @@ on the amount of passed arguments.
    - form.js, line 889 + form.js, line 893
    @@ -4403,7 +4405,7 @@ custom implementations.

    - form.js, line 1118 + form.js, line 1123
    @@ -4599,7 +4601,7 @@ on the amount of passed arguments.
    - form.js, line 1184 + form.js, line 1189
    @@ -4764,7 +4766,7 @@ depending on the amount of passed arguments.
    - form.js, line 1154 + form.js, line 1159
    @@ -4957,7 +4959,7 @@ on the amount of passed arguments.
    - form.js, line 904 + form.js, line 908
    @@ -5061,7 +5063,7 @@ elements load functions rejected with an error.
    - form.js, line 1017 + form.js, line 1021
    @@ -5276,7 +5278,7 @@ descendant of AbstractValue.

    - form.js, line 933 + form.js, line 937
    @@ -5384,7 +5386,7 @@ not meeting the validation constraints of their respective elements.
    - form.js, line 246 + form.js, line 248
    @@ -5492,7 +5494,7 @@ the form element's markup, including the markup of any child elements.
    - form.js, line 288 + form.js, line 289
    @@ -5639,7 +5641,7 @@ entities decoded.
    - form.js, line 974 + form.js, line 978
    @@ -5856,7 +5858,7 @@ contents. If omitted, no description will be rendered.

    - form.js, line 1054 + form.js, line 1058
    @@ -6125,7 +6127,7 @@ descendant of AbstractValue.

    - form.js, line 327 + form.js, line 328
    @@ -6326,7 +6328,7 @@ was neither a string nor a function. diff --git a/jsapi/LuCI.form.AbstractValue.html b/jsapi/LuCI.form.AbstractValue.html index b520ab1041..96f9381c9d 100644 --- a/jsapi/LuCI.form.AbstractValue.html +++ b/jsapi/LuCI.form.AbstractValue.html @@ -86,6 +86,8 @@
  • hasViewPermission
  • +
  • isArguments
  • +
  • isObject
  • location
  • @@ -3666,7 +3668,7 @@ validation constraints that should be applied to entered values.

    - form.js, line 1328 + form.js, line 1333
    @@ -4489,7 +4491,7 @@ table section elements.

    - form.js, line 210 + form.js, line 212
    @@ -4605,7 +4607,7 @@ table section elements.

    - form.js, line 1752 + form.js, line 1758
    @@ -4781,7 +4783,7 @@ within the given specific section.

    - form.js, line 1826 + form.js, line 1832
    @@ -4957,7 +4959,7 @@ different way.

    - form.js, line 1634 + form.js, line 1639
    @@ -4989,20 +4991,20 @@ constraint evaluation. The associated value of these special "tag" key is ignored. The recognized tags are:

    Examples:

    @@ -5026,7 +5028,7 @@ is ignored. The recognized tags are:

  • opt.depends({ foo: "test" })
    - opt.depends({ bar: "qrx" })

    + opt.depends({ bar: "qrx" })
    Require either foo to be set to test, or the bar option to be qrx.
  • @@ -5176,7 +5178,7 @@ argument, this parameter is ignored.

    - form.js, line 1854 + form.js, line 1860
    @@ -5351,7 +5353,7 @@ It may be overwritten by user code to handle input values differently.

    - form.js, line 1803 + form.js, line 1809
    @@ -5527,7 +5529,7 @@ option implementation does not use LuCI.ui widgets.
    - form.js, line 1941 + form.js, line 1947
    @@ -5672,7 +5674,7 @@ option implementation does not use LuCI.ui widgets.
    - form.js, line 1959 + form.js, line 1965
    @@ -5820,7 +5822,7 @@ returns false.
    - form.js, line 1927 + form.js, line 1933
    @@ -5966,7 +5968,7 @@ returns false.
    - form.js, line 1780 + form.js, line 1786
    @@ -6147,7 +6149,7 @@ so it may return promises if overridden by user code.
    - form.js, line 2000 + form.js, line 2006
    @@ -6296,7 +6298,7 @@ validation constraints.
    - form.js, line 2080 + form.js, line 2086
    @@ -6421,7 +6423,7 @@ implement alternative removal logic, e.g. to retain the original value.

    - form.js, line 246 + form.js, line 248
    @@ -6529,7 +6531,7 @@ the form element's markup, including the markup of any child elements.
    - form.js, line 288 + form.js, line 289
    @@ -6676,7 +6678,7 @@ entities decoded.
    - form.js, line 1878 + form.js, line 1884
    @@ -6856,7 +6858,7 @@ state of checkbox elements.

    - form.js, line 327 + form.js, line 328
    @@ -7049,7 +7051,7 @@ was neither a string nor a function.
    - form.js, line 1913 + form.js, line 1919
    @@ -7225,7 +7227,7 @@ as error message to the user.
    - form.js, line 2057 + form.js, line 2063
    @@ -7384,7 +7386,7 @@ before it is written.

    diff --git a/jsapi/LuCI.form.ButtonValue.html b/jsapi/LuCI.form.ButtonValue.html index 2eaa57a0e7..ebba9edda3 100644 --- a/jsapi/LuCI.form.ButtonValue.html +++ b/jsapi/LuCI.form.ButtonValue.html @@ -86,6 +86,8 @@
  • hasViewPermission
  • +
  • isArguments
  • +
  • isObject
  • location
  • @@ -3663,7 +3665,7 @@ renders the underlying UCI option or default value as readonly text.

    - form.js, line 4523 + form.js, line 4539
    @@ -4922,7 +4924,7 @@ table section elements.

    - form.js, line 210 + form.js, line 212
    @@ -5040,7 +5042,7 @@ table section elements.

    - form.js, line 1752 + form.js, line 1758
    @@ -5218,7 +5220,7 @@ within the given specific section.

    - form.js, line 1826 + form.js, line 1832
    @@ -5396,7 +5398,7 @@ different way.

    - form.js, line 1634 + form.js, line 1639
    @@ -5428,20 +5430,20 @@ constraint evaluation. The associated value of these special "tag" key is ignored. The recognized tags are:

    Examples:

    @@ -5465,7 +5467,7 @@ is ignored. The recognized tags are:

  • opt.depends({ foo: "test" })
    - opt.depends({ bar: "qrx" })

    + opt.depends({ bar: "qrx" })
    Require either foo to be set to test, or the bar option to be qrx.
  • @@ -5617,7 +5619,7 @@ argument, this parameter is ignored.

    - form.js, line 1854 + form.js, line 1860
    @@ -5794,7 +5796,7 @@ It may be overwritten by user code to handle input values differently.

    - form.js, line 1803 + form.js, line 1809
    @@ -5972,7 +5974,7 @@ option implementation does not use LuCI.ui widgets.
    - form.js, line 1941 + form.js, line 1947
    @@ -6119,7 +6121,7 @@ option implementation does not use LuCI.ui widgets.
    - form.js, line 1959 + form.js, line 1965
    @@ -6269,7 +6271,7 @@ returns false.
    - form.js, line 1927 + form.js, line 1933
    @@ -6417,7 +6419,7 @@ returns false.
    - form.js, line 1780 + form.js, line 1786
    @@ -6600,7 +6602,7 @@ so it may return promises if overridden by user code.
    - form.js, line 2000 + form.js, line 2006
    @@ -6751,7 +6753,7 @@ validation constraints.
    - form.js, line 2080 + form.js, line 2086
    @@ -6876,7 +6878,7 @@ implement alternative removal logic, e.g. to retain the original value.

    - form.js, line 288 + form.js, line 289
    @@ -7025,7 +7027,7 @@ entities decoded.
    - form.js, line 1878 + form.js, line 1884
    @@ -7205,7 +7207,7 @@ state of checkbox elements.

    - form.js, line 327 + form.js, line 328
    @@ -7400,7 +7402,7 @@ was neither a string nor a function.
    - form.js, line 3671 + form.js, line 3686
    @@ -7548,7 +7550,7 @@ or a plain text string. If omitted, the key value is used as captio
    - form.js, line 2057 + form.js, line 2063
    @@ -7707,7 +7709,7 @@ before it is written.

    diff --git a/jsapi/LuCI.form.DummyValue.html b/jsapi/LuCI.form.DummyValue.html index 199a48fb08..53ee030ea3 100644 --- a/jsapi/LuCI.form.DummyValue.html +++ b/jsapi/LuCI.form.DummyValue.html @@ -86,6 +86,8 @@
  • hasViewPermission
  • +
  • isArguments
  • +
  • isObject
  • location
  • @@ -3663,7 +3665,7 @@ renders the underlying UCI option or default value as readonly text.

    - form.js, line 4431 + form.js, line 4447
    @@ -4908,7 +4910,7 @@ table section elements.

    - form.js, line 210 + form.js, line 212
    @@ -5026,7 +5028,7 @@ table section elements.

    - form.js, line 1752 + form.js, line 1758
    @@ -5204,7 +5206,7 @@ within the given specific section.

    - form.js, line 1826 + form.js, line 1832
    @@ -5382,7 +5384,7 @@ different way.

    - form.js, line 1634 + form.js, line 1639
    @@ -5414,20 +5416,20 @@ constraint evaluation. The associated value of these special "tag" key is ignored. The recognized tags are:

    Examples:

    @@ -5451,7 +5453,7 @@ is ignored. The recognized tags are:

  • opt.depends({ foo: "test" })
    - opt.depends({ bar: "qrx" })

    + opt.depends({ bar: "qrx" })
    Require either foo to be set to test, or the bar option to be qrx.
  • @@ -5603,7 +5605,7 @@ argument, this parameter is ignored.

    - form.js, line 1854 + form.js, line 1860
    @@ -5780,7 +5782,7 @@ It may be overwritten by user code to handle input values differently.

    - form.js, line 1803 + form.js, line 1809
    @@ -5958,7 +5960,7 @@ option implementation does not use LuCI.ui widgets.
    - form.js, line 1941 + form.js, line 1947
    @@ -6105,7 +6107,7 @@ option implementation does not use LuCI.ui widgets.
    - form.js, line 1959 + form.js, line 1965
    @@ -6255,7 +6257,7 @@ returns false.
    - form.js, line 1927 + form.js, line 1933
    @@ -6403,7 +6405,7 @@ returns false.
    - form.js, line 1780 + form.js, line 1786
    @@ -6586,7 +6588,7 @@ so it may return promises if overridden by user code.
    - form.js, line 2000 + form.js, line 2006
    @@ -6737,7 +6739,7 @@ validation constraints.
    - form.js, line 4517 + form.js, line 4533
    @@ -6862,7 +6864,7 @@ implement alternative removal logic, e.g. to retain the original value.

    - form.js, line 288 + form.js, line 289
    @@ -7011,7 +7013,7 @@ entities decoded.
    - form.js, line 1878 + form.js, line 1884
    @@ -7191,7 +7193,7 @@ state of checkbox elements.

    - form.js, line 327 + form.js, line 328
    @@ -7386,7 +7388,7 @@ was neither a string nor a function.
    - form.js, line 3671 + form.js, line 3686
    @@ -7534,7 +7536,7 @@ or a plain text string. If omitted, the key value is used as captio
    - form.js, line 4520 + form.js, line 4536
    @@ -7693,7 +7695,7 @@ before it is written.

    diff --git a/jsapi/LuCI.form.DynamicList.html b/jsapi/LuCI.form.DynamicList.html index 6e8463afc6..7360661c87 100644 --- a/jsapi/LuCI.form.DynamicList.html +++ b/jsapi/LuCI.form.DynamicList.html @@ -86,6 +86,8 @@
  • hasViewPermission
  • +
  • isArguments
  • +
  • isObject
  • location
  • @@ -3664,7 +3666,7 @@ predefined choices. It builds upon the @@ -4759,7 +4761,7 @@ table section elements.

    @@ -4877,7 +4879,7 @@ table section elements.

    @@ -5055,7 +5057,7 @@ within the given specific section.

    @@ -5233,7 +5235,7 @@ different way.

    @@ -5265,20 +5267,20 @@ constraint evaluation. The associated value of these special "tag" key is ignored. The recognized tags are:

    Examples:

    @@ -5302,7 +5304,7 @@ is ignored. The recognized tags are:

  • opt.depends({ foo: "test" })
    - opt.depends({ bar: "qrx" })

    + opt.depends({ bar: "qrx" })

    Require either foo to be set to test, or the bar option to be qrx.
  • @@ -5454,7 +5456,7 @@ argument, this parameter is ignored.

    - form.js, line 1854 + form.js, line 1860
    @@ -5631,7 +5633,7 @@ It may be overwritten by user code to handle input values differently.

    - form.js, line 1803 + form.js, line 1809
    @@ -5809,7 +5811,7 @@ option implementation does not use LuCI.ui widgets.
    - form.js, line 1941 + form.js, line 1947
    @@ -5956,7 +5958,7 @@ option implementation does not use LuCI.ui widgets.
    - form.js, line 1959 + form.js, line 1965
    @@ -6106,7 +6108,7 @@ returns false.
    - form.js, line 1927 + form.js, line 1933
    @@ -6254,7 +6256,7 @@ returns false.
    - form.js, line 1780 + form.js, line 1786
    @@ -6437,7 +6439,7 @@ so it may return promises if overridden by user code.
    - form.js, line 2000 + form.js, line 2006
    @@ -6588,7 +6590,7 @@ validation constraints.
    - form.js, line 2080 + form.js, line 2086
    @@ -6713,7 +6715,7 @@ implement alternative removal logic, e.g. to retain the original value.

    - form.js, line 288 + form.js, line 289
    @@ -6862,7 +6864,7 @@ entities decoded.
    - form.js, line 1878 + form.js, line 1884
    @@ -7042,7 +7044,7 @@ state of checkbox elements.

    - form.js, line 327 + form.js, line 328
    @@ -7237,7 +7239,7 @@ was neither a string nor a function.
    - form.js, line 3671 + form.js, line 3686
    @@ -7385,7 +7387,7 @@ or a plain text string. If omitted, the key value is used as captio
    - form.js, line 2057 + form.js, line 2063
    @@ -7544,7 +7546,7 @@ before it is written.

    diff --git a/jsapi/LuCI.form.FileUpload.html b/jsapi/LuCI.form.FileUpload.html index 450e09707d..c7bf0b2451 100644 --- a/jsapi/LuCI.form.FileUpload.html +++ b/jsapi/LuCI.form.FileUpload.html @@ -86,6 +86,8 @@
  • hasViewPermission
  • +
  • isArguments
  • +
  • isObject
  • location
  • @@ -3663,7 +3665,7 @@ offers the ability to browse, upload and select remote files.

    - form.js, line 4690 + form.js, line 4706
    @@ -5066,7 +5068,7 @@ table section elements.

    - form.js, line 210 + form.js, line 212
    @@ -5184,7 +5186,7 @@ table section elements.

    - form.js, line 1752 + form.js, line 1758
    @@ -5362,7 +5364,7 @@ within the given specific section.

    - form.js, line 1826 + form.js, line 1832
    @@ -5540,7 +5542,7 @@ different way.

    - form.js, line 1634 + form.js, line 1639
    @@ -5572,20 +5574,20 @@ constraint evaluation. The associated value of these special "tag" key is ignored. The recognized tags are:

    Examples:

    @@ -5609,7 +5611,7 @@ is ignored. The recognized tags are:

  • opt.depends({ foo: "test" })
    - opt.depends({ bar: "qrx" })

    + opt.depends({ bar: "qrx" })
    Require either foo to be set to test, or the bar option to be qrx.
  • @@ -5761,7 +5763,7 @@ argument, this parameter is ignored.

    - form.js, line 1854 + form.js, line 1860
    @@ -5938,7 +5940,7 @@ It may be overwritten by user code to handle input values differently.

    - form.js, line 1803 + form.js, line 1809
    @@ -6116,7 +6118,7 @@ option implementation does not use LuCI.ui widgets.
    - form.js, line 1941 + form.js, line 1947
    @@ -6263,7 +6265,7 @@ option implementation does not use LuCI.ui widgets.
    - form.js, line 1959 + form.js, line 1965
    @@ -6413,7 +6415,7 @@ returns false.
    - form.js, line 1927 + form.js, line 1933
    @@ -6561,7 +6563,7 @@ returns false.
    - form.js, line 1780 + form.js, line 1786
    @@ -6744,7 +6746,7 @@ so it may return promises if overridden by user code.
    - form.js, line 2000 + form.js, line 2006
    @@ -6895,7 +6897,7 @@ validation constraints.
    - form.js, line 2080 + form.js, line 2086
    @@ -7020,7 +7022,7 @@ implement alternative removal logic, e.g. to retain the original value.

    - form.js, line 288 + form.js, line 289
    @@ -7169,7 +7171,7 @@ entities decoded.
    - form.js, line 1878 + form.js, line 1884
    @@ -7349,7 +7351,7 @@ state of checkbox elements.

    - form.js, line 327 + form.js, line 328
    @@ -7544,7 +7546,7 @@ was neither a string nor a function.
    - form.js, line 3671 + form.js, line 3686
    @@ -7692,7 +7694,7 @@ or a plain text string. If omitted, the key value is used as captio
    - form.js, line 2057 + form.js, line 2063
    @@ -7851,7 +7853,7 @@ before it is written.

    diff --git a/jsapi/LuCI.form.FlagValue.html b/jsapi/LuCI.form.FlagValue.html index 73fd622d73..c2332b0152 100644 --- a/jsapi/LuCI.form.FlagValue.html +++ b/jsapi/LuCI.form.FlagValue.html @@ -86,6 +86,8 @@
  • hasViewPermission
  • +
  • isArguments
  • +
  • isObject
  • location
  • @@ -3663,7 +3665,7 @@ implement a simple checkbox element.

    - form.js, line 4092 + form.js, line 4107
    @@ -4956,7 +4958,7 @@ table section elements.

    - form.js, line 210 + form.js, line 212
    @@ -5074,7 +5076,7 @@ table section elements.

    - form.js, line 1752 + form.js, line 1758
    @@ -5252,7 +5254,7 @@ within the given specific section.

    - form.js, line 1826 + form.js, line 1832
    @@ -5430,7 +5432,7 @@ different way.

    - form.js, line 1634 + form.js, line 1639
    @@ -5462,20 +5464,20 @@ constraint evaluation. The associated value of these special "tag" key is ignored. The recognized tags are:

    Examples:

    @@ -5499,7 +5501,7 @@ is ignored. The recognized tags are:

  • opt.depends({ foo: "test" })
    - opt.depends({ bar: "qrx" })

    + opt.depends({ bar: "qrx" })
    Require either foo to be set to test, or the bar option to be qrx.
  • @@ -5651,7 +5653,7 @@ argument, this parameter is ignored.

    - form.js, line 4204 + form.js, line 4219
    @@ -5827,7 +5829,7 @@ the checked state.

    - form.js, line 1803 + form.js, line 1809
    @@ -6005,7 +6007,7 @@ option implementation does not use LuCI.ui widgets.
    - form.js, line 1941 + form.js, line 1947
    @@ -6152,7 +6154,7 @@ option implementation does not use LuCI.ui widgets.
    - form.js, line 1959 + form.js, line 1965
    @@ -6302,7 +6304,7 @@ returns false.
    - form.js, line 1927 + form.js, line 1933
    @@ -6450,7 +6452,7 @@ returns false.
    - form.js, line 1780 + form.js, line 1786
    @@ -6633,7 +6635,7 @@ so it may return promises if overridden by user code.
    - form.js, line 4226 + form.js, line 4241
    @@ -6784,7 +6786,7 @@ validation constraints.
    - form.js, line 2080 + form.js, line 2086
    @@ -6909,7 +6911,7 @@ implement alternative removal logic, e.g. to retain the original value.

    - form.js, line 288 + form.js, line 289
    @@ -7058,7 +7060,7 @@ entities decoded.
    - form.js, line 4216 + form.js, line 4231
    @@ -7233,7 +7235,7 @@ either a localized Yes or No string, depending on the
    - form.js, line 327 + form.js, line 328
    @@ -7428,7 +7430,7 @@ was neither a string nor a function.
    - form.js, line 3671 + form.js, line 3686
    @@ -7576,7 +7578,7 @@ or a plain text string. If omitted, the key value is used as captio
    - form.js, line 2057 + form.js, line 2063
    @@ -7735,7 +7737,7 @@ before it is written.

    diff --git a/jsapi/LuCI.form.GridSection.html b/jsapi/LuCI.form.GridSection.html index 1725d59d70..c0ebcf3d3a 100644 --- a/jsapi/LuCI.form.GridSection.html +++ b/jsapi/LuCI.form.GridSection.html @@ -86,6 +86,8 @@
  • hasViewPermission
  • +
  • isArguments
  • +
  • isObject
  • location
  • @@ -3676,7 +3678,7 @@ documentation for details.

    - form.js, line 3282 + form.js, line 3294
    @@ -4637,7 +4639,7 @@ The default is null, means inheriting from the parent form.

    - form.js, line 3131 + form.js, line 3143
    @@ -4840,7 +4842,7 @@ is shown.
    - form.js, line 210 + form.js, line 212
    @@ -4958,7 +4960,7 @@ is shown.
    - form.js, line 1085 + form.js, line 1090
    @@ -5156,7 +5158,7 @@ on the amount of passed arguments.
    - form.js, line 889 + form.js, line 893
    @@ -5310,7 +5312,7 @@ custom implementations.

    - form.js, line 1118 + form.js, line 1123
    @@ -5508,7 +5510,7 @@ on the amount of passed arguments.
    - form.js, line 1184 + form.js, line 1189
    @@ -5675,7 +5677,7 @@ depending on the amount of passed arguments.
    - form.js, line 1154 + form.js, line 1159
    @@ -5870,7 +5872,7 @@ on the amount of passed arguments.
    - form.js, line 904 + form.js, line 908
    @@ -5976,7 +5978,7 @@ elements load functions rejected with an error.
    - form.js, line 1017 + form.js, line 1021
    @@ -6193,7 +6195,7 @@ descendant of AbstractValue.

    - form.js, line 3437 + form.js, line 3450
    @@ -6301,7 +6303,7 @@ not meeting the validation constraints of their respective elements.
    - form.js, line 288 + form.js, line 289
    @@ -6448,7 +6450,7 @@ entities decoded.
    - form.js, line 3351 + form.js, line 3363
    @@ -6666,7 +6668,7 @@ contents. If omitted, no description will be rendered.

    - form.js, line 1054 + form.js, line 1058
    @@ -6935,7 +6937,7 @@ descendant of AbstractValue.

    - form.js, line 327 + form.js, line 328
    @@ -7136,7 +7138,7 @@ was neither a string nor a function. diff --git a/jsapi/LuCI.form.HiddenValue.html b/jsapi/LuCI.form.HiddenValue.html index 883fe7cc14..1cf1775b87 100644 --- a/jsapi/LuCI.form.HiddenValue.html +++ b/jsapi/LuCI.form.HiddenValue.html @@ -86,6 +86,8 @@
  • hasViewPermission
  • +
  • isArguments
  • +
  • isObject
  • location
  • @@ -3668,7 +3670,7 @@ distorted form layout when rendering the option element.

    - form.js, line 4639 + form.js, line 4655
    @@ -4763,7 +4765,7 @@ table section elements.

    - form.js, line 210 + form.js, line 212
    @@ -4881,7 +4883,7 @@ table section elements.

    - form.js, line 1752 + form.js, line 1758
    @@ -5059,7 +5061,7 @@ within the given specific section.

    - form.js, line 1826 + form.js, line 1832
    @@ -5237,7 +5239,7 @@ different way.

    - form.js, line 1634 + form.js, line 1639
    @@ -5269,20 +5271,20 @@ constraint evaluation. The associated value of these special "tag" key is ignored. The recognized tags are:

    Examples:

    @@ -5306,7 +5308,7 @@ is ignored. The recognized tags are:

  • opt.depends({ foo: "test" })
    - opt.depends({ bar: "qrx" })

    + opt.depends({ bar: "qrx" })
    Require either foo to be set to test, or the bar option to be qrx.
  • @@ -5458,7 +5460,7 @@ argument, this parameter is ignored.

    - form.js, line 1854 + form.js, line 1860
    @@ -5635,7 +5637,7 @@ It may be overwritten by user code to handle input values differently.

    - form.js, line 1803 + form.js, line 1809
    @@ -5813,7 +5815,7 @@ option implementation does not use LuCI.ui widgets.
    - form.js, line 1941 + form.js, line 1947
    @@ -5960,7 +5962,7 @@ option implementation does not use LuCI.ui widgets.
    - form.js, line 1959 + form.js, line 1965
    @@ -6110,7 +6112,7 @@ returns false.
    - form.js, line 1927 + form.js, line 1933
    @@ -6258,7 +6260,7 @@ returns false.
    - form.js, line 1780 + form.js, line 1786
    @@ -6441,7 +6443,7 @@ so it may return promises if overridden by user code.
    - form.js, line 2000 + form.js, line 2006
    @@ -6592,7 +6594,7 @@ validation constraints.
    - form.js, line 2080 + form.js, line 2086
    @@ -6717,7 +6719,7 @@ implement alternative removal logic, e.g. to retain the original value.

    - form.js, line 288 + form.js, line 289
    @@ -6866,7 +6868,7 @@ entities decoded.
    - form.js, line 1878 + form.js, line 1884
    @@ -7046,7 +7048,7 @@ state of checkbox elements.

    - form.js, line 327 + form.js, line 328
    @@ -7241,7 +7243,7 @@ was neither a string nor a function.
    - form.js, line 3671 + form.js, line 3686
    @@ -7389,7 +7391,7 @@ or a plain text string. If omitted, the key value is used as captio
    - form.js, line 2057 + form.js, line 2063
    @@ -7548,7 +7550,7 @@ before it is written.

    diff --git a/jsapi/LuCI.form.JSONMap.html b/jsapi/LuCI.form.JSONMap.html index 3f061e21b9..dda8feb1a1 100644 --- a/jsapi/LuCI.form.JSONMap.html +++ b/jsapi/LuCI.form.JSONMap.html @@ -86,6 +86,8 @@
  • hasViewPermission
  • +
  • isArguments
  • +
  • isObject
  • location
  • @@ -3664,7 +3666,7 @@ as data source.

    - form.js, line 778 + form.js, line 782
    @@ -3928,7 +3930,7 @@ permissions are granted.

    - form.js, line 210 + form.js, line 212
    @@ -4046,7 +4048,7 @@ permissions are granted.

    - form.js, line 486 + form.js, line 487
    @@ -4170,7 +4172,7 @@ config already is in the list of required files, it will be ignored.

    - form.js, line 468 + form.js, line 469
    @@ -4395,7 +4397,7 @@ passed.

    - form.js, line 425 + form.js, line 426
    @@ -4617,7 +4619,7 @@ passed.

    - form.js, line 540 + form.js, line 541
    @@ -4725,7 +4727,7 @@ an error.
    - form.js, line 709 + form.js, line 710
    @@ -4944,7 +4946,7 @@ Returns null if the option could not be found.
    - form.js, line 570 + form.js, line 571
    @@ -5051,7 +5053,7 @@ not meeting the validation constraints of their respective elements.
    - form.js, line 641 + form.js, line 642
    @@ -5154,7 +5156,7 @@ rendering is complete.
    - form.js, line 630 + form.js, line 631
    @@ -5258,7 +5260,7 @@ re-rendering is complete.
    - form.js, line 600 + form.js, line 601
    @@ -5461,7 +5463,7 @@ failed.
    - form.js, line 518 + form.js, line 519
    @@ -5656,7 +5658,7 @@ documentation for details.

    - form.js, line 288 + form.js, line 289
    @@ -5805,7 +5807,7 @@ entities decoded.
    - form.js, line 327 + form.js, line 328
    @@ -6006,7 +6008,7 @@ was neither a string nor a function. diff --git a/jsapi/LuCI.form.ListValue.html b/jsapi/LuCI.form.ListValue.html index 274e521f3c..36b8370a0d 100644 --- a/jsapi/LuCI.form.ListValue.html +++ b/jsapi/LuCI.form.ListValue.html @@ -86,6 +86,8 @@
  • hasViewPermission
  • +
  • isArguments
  • +
  • isObject
  • location
  • @@ -3664,7 +3666,7 @@ It builds upon the LuCI.ui.Select
    - form.js, line 3871 + form.js, line 3886
    @@ -4908,7 +4910,7 @@ table section elements.

    - form.js, line 210 + form.js, line 212
    @@ -5026,7 +5028,7 @@ table section elements.

    - form.js, line 1752 + form.js, line 1758
    @@ -5204,7 +5206,7 @@ within the given specific section.

    - form.js, line 1826 + form.js, line 1832
    @@ -5382,7 +5384,7 @@ different way.

    - form.js, line 1634 + form.js, line 1639
    @@ -5414,20 +5416,20 @@ constraint evaluation. The associated value of these special "tag" key is ignored. The recognized tags are:

    Examples:

    @@ -5451,7 +5453,7 @@ is ignored. The recognized tags are:

  • opt.depends({ foo: "test" })
    - opt.depends({ bar: "qrx" })

    + opt.depends({ bar: "qrx" })
    Require either foo to be set to test, or the bar option to be qrx.
  • @@ -5603,7 +5605,7 @@ argument, this parameter is ignored.

    - form.js, line 1854 + form.js, line 1860
    @@ -5780,7 +5782,7 @@ It may be overwritten by user code to handle input values differently.

    - form.js, line 1803 + form.js, line 1809
    @@ -5958,7 +5960,7 @@ option implementation does not use LuCI.ui widgets.
    - form.js, line 1941 + form.js, line 1947
    @@ -6105,7 +6107,7 @@ option implementation does not use LuCI.ui widgets.
    - form.js, line 1959 + form.js, line 1965
    @@ -6255,7 +6257,7 @@ returns false.
    - form.js, line 1927 + form.js, line 1933
    @@ -6403,7 +6405,7 @@ returns false.
    - form.js, line 1780 + form.js, line 1786
    @@ -6586,7 +6588,7 @@ so it may return promises if overridden by user code.
    - form.js, line 2000 + form.js, line 2006
    @@ -6737,7 +6739,7 @@ validation constraints.
    - form.js, line 2080 + form.js, line 2086
    @@ -6862,7 +6864,7 @@ implement alternative removal logic, e.g. to retain the original value.

    - form.js, line 288 + form.js, line 289
    @@ -7011,7 +7013,7 @@ entities decoded.
    - form.js, line 1878 + form.js, line 1884
    @@ -7191,7 +7193,7 @@ state of checkbox elements.

    - form.js, line 327 + form.js, line 328
    @@ -7384,7 +7386,7 @@ was neither a string nor a function.
    - form.js, line 4075 + form.js, line 4090
    @@ -7560,7 +7562,7 @@ implemented as a simple ListValue entry.

    - form.js, line 2057 + form.js, line 2063
    @@ -7719,7 +7721,7 @@ before it is written.

    diff --git a/jsapi/LuCI.form.Map.html b/jsapi/LuCI.form.Map.html index 9db697df01..dab28cb597 100644 --- a/jsapi/LuCI.form.Map.html +++ b/jsapi/LuCI.form.Map.html @@ -86,6 +86,8 @@
  • hasViewPermission
  • +
  • isArguments
  • +
  • isObject
  • location
  • @@ -3665,7 +3667,7 @@ fields each.

    - form.js, line 345 + form.js, line 346
    @@ -3927,7 +3929,7 @@ permissions are granted.

    - form.js, line 210 + form.js, line 212
    @@ -4043,7 +4045,7 @@ permissions are granted.

    - form.js, line 486 + form.js, line 487
    @@ -4165,7 +4167,7 @@ config already is in the list of required files, it will be ignored.

    - form.js, line 468 + form.js, line 469
    @@ -4388,7 +4390,7 @@ passed.

    - form.js, line 425 + form.js, line 426
    @@ -4608,7 +4610,7 @@ passed.

    - form.js, line 540 + form.js, line 541
    @@ -4714,7 +4716,7 @@ an error.
    - form.js, line 709 + form.js, line 710
    @@ -4931,7 +4933,7 @@ Returns null if the option could not be found.
    - form.js, line 570 + form.js, line 571
    @@ -5036,7 +5038,7 @@ not meeting the validation constraints of their respective elements.
    - form.js, line 641 + form.js, line 642
    @@ -5137,7 +5139,7 @@ rendering is complete.
    - form.js, line 630 + form.js, line 631
    @@ -5239,7 +5241,7 @@ re-rendering is complete.
    - form.js, line 600 + form.js, line 601
    @@ -5440,7 +5442,7 @@ failed.
    - form.js, line 518 + form.js, line 519
    @@ -5635,7 +5637,7 @@ documentation for details.

    - form.js, line 288 + form.js, line 289
    @@ -5784,7 +5786,7 @@ entities decoded.
    - form.js, line 327 + form.js, line 328
    @@ -5985,7 +5987,7 @@ was neither a string nor a function. diff --git a/jsapi/LuCI.form.MultiValue.html b/jsapi/LuCI.form.MultiValue.html index 955df8f2f6..43175f00f6 100644 --- a/jsapi/LuCI.form.MultiValue.html +++ b/jsapi/LuCI.form.MultiValue.html @@ -86,6 +86,8 @@
  • hasViewPermission
  • +
  • isArguments
  • +
  • isObject
  • location
  • @@ -3664,7 +3666,7 @@ select dropdown element.

    - form.js, line 4248 + form.js, line 4264
    @@ -4907,7 +4909,7 @@ table section elements.

    - form.js, line 210 + form.js, line 212
    @@ -5025,7 +5027,7 @@ table section elements.

    - form.js, line 1752 + form.js, line 1758
    @@ -5203,7 +5205,7 @@ within the given specific section.

    - form.js, line 1826 + form.js, line 1832
    @@ -5381,7 +5383,7 @@ different way.

    - form.js, line 1634 + form.js, line 1639
    @@ -5413,20 +5415,20 @@ constraint evaluation. The associated value of these special "tag" key is ignored. The recognized tags are:

    Examples:

    @@ -5450,7 +5452,7 @@ is ignored. The recognized tags are:

  • opt.depends({ foo: "test" })
    - opt.depends({ bar: "qrx" })

    + opt.depends({ bar: "qrx" })
    Require either foo to be set to test, or the bar option to be qrx.
  • @@ -5602,7 +5604,7 @@ argument, this parameter is ignored.

    - form.js, line 1854 + form.js, line 1860
    @@ -5779,7 +5781,7 @@ It may be overwritten by user code to handle input values differently.

    - form.js, line 1803 + form.js, line 1809
    @@ -5957,7 +5959,7 @@ option implementation does not use LuCI.ui widgets.
    - form.js, line 1941 + form.js, line 1947
    @@ -6104,7 +6106,7 @@ option implementation does not use LuCI.ui widgets.
    - form.js, line 1959 + form.js, line 1965
    @@ -6254,7 +6256,7 @@ returns false.
    - form.js, line 1927 + form.js, line 1933
    @@ -6402,7 +6404,7 @@ returns false.
    - form.js, line 1780 + form.js, line 1786
    @@ -6585,7 +6587,7 @@ so it may return promises if overridden by user code.
    - form.js, line 2000 + form.js, line 2006
    @@ -6736,7 +6738,7 @@ validation constraints.
    - form.js, line 2080 + form.js, line 2086
    @@ -6861,7 +6863,7 @@ implement alternative removal logic, e.g. to retain the original value.

    - form.js, line 288 + form.js, line 289
    @@ -7010,7 +7012,7 @@ entities decoded.
    - form.js, line 1878 + form.js, line 1884
    @@ -7190,7 +7192,7 @@ state of checkbox elements.

    - form.js, line 327 + form.js, line 328
    @@ -7385,7 +7387,7 @@ was neither a string nor a function.
    - form.js, line 3671 + form.js, line 3686
    @@ -7533,7 +7535,7 @@ or a plain text string. If omitted, the key value is used as captio
    - form.js, line 2057 + form.js, line 2063
    @@ -7692,7 +7694,7 @@ before it is written.

    diff --git a/jsapi/LuCI.form.NamedSection.html b/jsapi/LuCI.form.NamedSection.html index 67e86e29de..9d834f951d 100644 --- a/jsapi/LuCI.form.NamedSection.html +++ b/jsapi/LuCI.form.NamedSection.html @@ -86,6 +86,8 @@
  • hasViewPermission
  • +
  • isArguments
  • +
  • isObject
  • location
  • @@ -3665,7 +3667,7 @@ specified when constructing the class instance.

    - form.js, line 3456 + form.js, line 3469
    @@ -4081,7 +4083,7 @@ this property will hold a reference to the parent option instance.

    - form.js, line 210 + form.js, line 212
    @@ -4197,7 +4199,7 @@ this property will hold a reference to the parent option instance.

    - form.js, line 3522 + form.js, line 3535
    @@ -4301,7 +4303,7 @@ section ID as sole element. User code should not normally change this.

    - form.js, line 1085 + form.js, line 1090
    @@ -4499,7 +4501,7 @@ on the amount of passed arguments.
    - form.js, line 889 + form.js, line 893
    @@ -4653,7 +4655,7 @@ custom implementations.

    - form.js, line 1118 + form.js, line 1123
    @@ -4851,7 +4853,7 @@ on the amount of passed arguments.
    - form.js, line 1184 + form.js, line 1189
    @@ -5018,7 +5020,7 @@ depending on the amount of passed arguments.
    - form.js, line 1154 + form.js, line 1159
    @@ -5213,7 +5215,7 @@ on the amount of passed arguments.
    - form.js, line 904 + form.js, line 908
    @@ -5319,7 +5321,7 @@ elements load functions rejected with an error.
    - form.js, line 1017 + form.js, line 1021
    @@ -5536,7 +5538,7 @@ descendant of AbstractValue.

    - form.js, line 933 + form.js, line 937
    @@ -5644,7 +5646,7 @@ not meeting the validation constraints of their respective elements.
    - form.js, line 3595 + form.js, line 3610
    @@ -5752,7 +5754,7 @@ the form element's markup, including the markup of any child elements.
    - form.js, line 288 + form.js, line 289
    @@ -5901,7 +5903,7 @@ entities decoded.
    - form.js, line 974 + form.js, line 978
    @@ -6120,7 +6122,7 @@ contents. If omitted, no description will be rendered.

    - form.js, line 1054 + form.js, line 1058
    @@ -6389,7 +6391,7 @@ descendant of AbstractValue.

    - form.js, line 327 + form.js, line 328
    @@ -6590,7 +6592,7 @@ was neither a string nor a function. diff --git a/jsapi/LuCI.form.RichListValue.html b/jsapi/LuCI.form.RichListValue.html index d7b6fe576b..21c2453436 100644 --- a/jsapi/LuCI.form.RichListValue.html +++ b/jsapi/LuCI.form.RichListValue.html @@ -86,6 +86,8 @@
  • hasViewPermission
  • +
  • isArguments
  • +
  • isObject
  • location
  • @@ -3665,7 +3667,7 @@ It builds upon the LuCI.form.ListValue< @@ -5058,7 +5060,7 @@ table section elements.

    @@ -5176,7 +5178,7 @@ table section elements.

    @@ -5354,7 +5356,7 @@ within the given specific section.

    @@ -5532,7 +5534,7 @@ different way.

    @@ -5564,20 +5566,20 @@ constraint evaluation. The associated value of these special "tag" key is ignored. The recognized tags are:

    Examples:

    @@ -5601,7 +5603,7 @@ is ignored. The recognized tags are:

  • opt.depends({ foo: "test" })
    - opt.depends({ bar: "qrx" })

    + opt.depends({ bar: "qrx" })

    Require either foo to be set to test, or the bar option to be qrx.
  • @@ -5753,7 +5755,7 @@ argument, this parameter is ignored.

    - form.js, line 1854 + form.js, line 1860
    @@ -5930,7 +5932,7 @@ It may be overwritten by user code to handle input values differently.

    - form.js, line 1803 + form.js, line 1809
    @@ -6108,7 +6110,7 @@ option implementation does not use LuCI.ui widgets.
    - form.js, line 1941 + form.js, line 1947
    @@ -6255,7 +6257,7 @@ option implementation does not use LuCI.ui widgets.
    - form.js, line 1959 + form.js, line 1965
    @@ -6405,7 +6407,7 @@ returns false.
    - form.js, line 1927 + form.js, line 1933
    @@ -6553,7 +6555,7 @@ returns false.
    - form.js, line 1780 + form.js, line 1786
    @@ -6736,7 +6738,7 @@ so it may return promises if overridden by user code.
    - form.js, line 2000 + form.js, line 2006
    @@ -6887,7 +6889,7 @@ validation constraints.
    - form.js, line 2080 + form.js, line 2086
    @@ -7012,7 +7014,7 @@ implement alternative removal logic, e.g. to retain the original value.

    - form.js, line 288 + form.js, line 289
    @@ -7161,7 +7163,7 @@ entities decoded.
    - form.js, line 1878 + form.js, line 1884
    @@ -7341,7 +7343,7 @@ state of checkbox elements.

    - form.js, line 327 + form.js, line 328
    @@ -7536,7 +7538,7 @@ was neither a string nor a function.
    - form.js, line 4075 + form.js, line 4090
    @@ -7712,7 +7714,7 @@ implemented as a simple ListValue entry.

    - form.js, line 2057 + form.js, line 2063
    @@ -7871,7 +7873,7 @@ before it is written.

    diff --git a/jsapi/LuCI.form.SectionValue.html b/jsapi/LuCI.form.SectionValue.html index f9ab5ae3dc..5eb0e8ffd0 100644 --- a/jsapi/LuCI.form.SectionValue.html +++ b/jsapi/LuCI.form.SectionValue.html @@ -86,6 +86,8 @@
  • hasViewPermission
  • +
  • isArguments
  • +
  • isObject
  • location
  • @@ -3663,7 +3665,7 @@ element container, allowing to nest form sections into other sections.

    - form.js, line 4830 + form.js, line 4846
    @@ -4811,7 +4813,7 @@ table section elements.

    - form.js, line 210 + form.js, line 212
    @@ -4929,7 +4931,7 @@ table section elements.

    - form.js, line 1752 + form.js, line 1758
    @@ -5107,7 +5109,7 @@ within the given specific section.

    - form.js, line 4942 + form.js, line 4958
    @@ -5282,7 +5284,7 @@ its cfgvalue() implementation will always return null.
    - form.js, line 1634 + form.js, line 1639
    @@ -5314,20 +5316,20 @@ constraint evaluation. The associated value of these special "tag" key is ignored. The recognized tags are:

    Examples:

    @@ -5351,7 +5353,7 @@ is ignored. The recognized tags are:

  • opt.depends({ foo: "test" })
    - opt.depends({ bar: "qrx" })

    + opt.depends({ bar: "qrx" })
    Require either foo to be set to test, or the bar option to be qrx.
  • @@ -5503,7 +5505,7 @@ argument, this parameter is ignored.

    - form.js, line 4951 + form.js, line 4967
    @@ -5678,7 +5680,7 @@ its formvalue() implementation will always return null
    - form.js, line 1803 + form.js, line 1809
    @@ -5856,7 +5858,7 @@ option implementation does not use LuCI.ui widgets.
    - form.js, line 1941 + form.js, line 1947
    @@ -6003,7 +6005,7 @@ option implementation does not use LuCI.ui widgets.
    - form.js, line 1959 + form.js, line 1965
    @@ -6153,7 +6155,7 @@ returns false.
    - form.js, line 1927 + form.js, line 1933
    @@ -6301,7 +6303,7 @@ returns false.
    - form.js, line 4891 + form.js, line 4907
    @@ -6484,7 +6486,7 @@ so it may return promises if overridden by user code.
    - form.js, line 4896 + form.js, line 4912
    @@ -6635,7 +6637,7 @@ validation constraints.
    - form.js, line 4933 + form.js, line 4949
    @@ -6754,7 +6756,7 @@ its remove() implementation is a no-op.

    - form.js, line 288 + form.js, line 289
    @@ -6903,7 +6905,7 @@ entities decoded.
    - form.js, line 1878 + form.js, line 1884
    @@ -7083,7 +7085,7 @@ state of checkbox elements.

    - form.js, line 327 + form.js, line 328
    @@ -7278,7 +7280,7 @@ was neither a string nor a function.
    - form.js, line 4917 + form.js, line 4933
    @@ -7424,7 +7426,7 @@ or a plain text string. If omitted, the key value is used as captio
    - form.js, line 4925 + form.js, line 4941
    @@ -7575,7 +7577,7 @@ its write() implementation is a no-op.

    diff --git a/jsapi/LuCI.form.TableSection.html b/jsapi/LuCI.form.TableSection.html index 0ddd85d3df..c5d6d4ace0 100644 --- a/jsapi/LuCI.form.TableSection.html +++ b/jsapi/LuCI.form.TableSection.html @@ -86,6 +86,8 @@
  • hasViewPermission
  • +
  • isArguments
  • +
  • isObject
  • location
  • @@ -3668,7 +3670,7 @@ value of the addremove property.

    - form.js, line 2348 + form.js, line 2355
    @@ -4627,7 +4629,7 @@ The default is null, means inheriting from the parent form.

    - form.js, line 3131 + form.js, line 3143
    @@ -4830,7 +4832,7 @@ is shown.
    - form.js, line 210 + form.js, line 212
    @@ -4948,7 +4950,7 @@ is shown.
    - form.js, line 1085 + form.js, line 1090
    @@ -5146,7 +5148,7 @@ on the amount of passed arguments.
    - form.js, line 889 + form.js, line 893
    @@ -5300,7 +5302,7 @@ custom implementations.

    - form.js, line 1118 + form.js, line 1123
    @@ -5498,7 +5500,7 @@ on the amount of passed arguments.
    - form.js, line 1184 + form.js, line 1189
    @@ -5665,7 +5667,7 @@ depending on the amount of passed arguments.
    - form.js, line 1154 + form.js, line 1159
    @@ -5860,7 +5862,7 @@ on the amount of passed arguments.
    - form.js, line 904 + form.js, line 908
    @@ -5966,7 +5968,7 @@ elements load functions rejected with an error.
    - form.js, line 1017 + form.js, line 1021
    @@ -6183,7 +6185,7 @@ descendant of AbstractValue.

    - form.js, line 933 + form.js, line 937
    @@ -6291,7 +6293,7 @@ not meeting the validation constraints of their respective elements.
    - form.js, line 288 + form.js, line 289
    @@ -6440,7 +6442,7 @@ entities decoded.
    - form.js, line 2488 + form.js, line 2495
    @@ -6638,7 +6640,7 @@ contents. If omitted, no description will be rendered.

    - form.js, line 1054 + form.js, line 1058
    @@ -6907,7 +6909,7 @@ descendant of AbstractValue.

    - form.js, line 327 + form.js, line 328
    @@ -7108,7 +7110,7 @@ was neither a string nor a function. diff --git a/jsapi/LuCI.form.TextValue.html b/jsapi/LuCI.form.TextValue.html index 0536cbc3b2..e983963d5b 100644 --- a/jsapi/LuCI.form.TextValue.html +++ b/jsapi/LuCI.form.TextValue.html @@ -86,6 +86,8 @@
  • hasViewPermission
  • +
  • isArguments
  • +
  • isObject
  • location
  • @@ -3663,7 +3665,7 @@
    - form.js, line 4338 + form.js, line 4354
    @@ -4954,7 +4956,7 @@ table section elements.

    - form.js, line 210 + form.js, line 212
    @@ -5072,7 +5074,7 @@ table section elements.

    - form.js, line 1752 + form.js, line 1758
    @@ -5250,7 +5252,7 @@ within the given specific section.

    - form.js, line 1826 + form.js, line 1832
    @@ -5428,7 +5430,7 @@ different way.

    - form.js, line 1634 + form.js, line 1639
    @@ -5460,20 +5462,20 @@ constraint evaluation. The associated value of these special "tag" key is ignored. The recognized tags are:

    Examples:

    @@ -5497,7 +5499,7 @@ is ignored. The recognized tags are:

  • opt.depends({ foo: "test" })
    - opt.depends({ bar: "qrx" })

    + opt.depends({ bar: "qrx" })
    Require either foo to be set to test, or the bar option to be qrx.
  • @@ -5649,7 +5651,7 @@ argument, this parameter is ignored.

    - form.js, line 1854 + form.js, line 1860
    @@ -5826,7 +5828,7 @@ It may be overwritten by user code to handle input values differently.

    - form.js, line 1803 + form.js, line 1809
    @@ -6004,7 +6006,7 @@ option implementation does not use LuCI.ui widgets.
    - form.js, line 1941 + form.js, line 1947
    @@ -6151,7 +6153,7 @@ option implementation does not use LuCI.ui widgets.
    - form.js, line 1959 + form.js, line 1965
    @@ -6301,7 +6303,7 @@ returns false.
    - form.js, line 1927 + form.js, line 1933
    @@ -6449,7 +6451,7 @@ returns false.
    - form.js, line 1780 + form.js, line 1786
    @@ -6632,7 +6634,7 @@ so it may return promises if overridden by user code.
    - form.js, line 2000 + form.js, line 2006
    @@ -6783,7 +6785,7 @@ validation constraints.
    - form.js, line 2080 + form.js, line 2086
    @@ -6908,7 +6910,7 @@ implement alternative removal logic, e.g. to retain the original value.

    - form.js, line 288 + form.js, line 289
    @@ -7057,7 +7059,7 @@ entities decoded.
    - form.js, line 1878 + form.js, line 1884
    @@ -7237,7 +7239,7 @@ state of checkbox elements.

    - form.js, line 327 + form.js, line 328
    @@ -7432,7 +7434,7 @@ was neither a string nor a function.
    - form.js, line 2057 + form.js, line 2063
    @@ -7591,7 +7593,7 @@ before it is written.

    diff --git a/jsapi/LuCI.form.TypedSection.html b/jsapi/LuCI.form.TypedSection.html index 70dceffae4..2598fe766a 100644 --- a/jsapi/LuCI.form.TypedSection.html +++ b/jsapi/LuCI.form.TypedSection.html @@ -86,6 +86,8 @@
  • hasViewPermission
  • +
  • isArguments
  • +
  • isObject
  • location
  • @@ -3668,7 +3670,7 @@ value of the addremove property.

    - form.js, line 2110 + form.js, line 2116
    @@ -4260,7 +4262,7 @@ this property will hold a reference to the parent option instance.

    - form.js, line 210 + form.js, line 212
    @@ -4378,7 +4380,7 @@ this property will hold a reference to the parent option instance.

    - form.js, line 2198 + form.js, line 2204
    @@ -4508,7 +4510,7 @@ The sections will be rendered in the same order as the returned array.
    - form.js, line 1085 + form.js, line 1090
    @@ -4706,7 +4708,7 @@ on the amount of passed arguments.
    - form.js, line 889 + form.js, line 893
    @@ -4860,7 +4862,7 @@ custom implementations.

    - form.js, line 1118 + form.js, line 1123
    @@ -5058,7 +5060,7 @@ on the amount of passed arguments.
    - form.js, line 1184 + form.js, line 1189
    @@ -5225,7 +5227,7 @@ depending on the amount of passed arguments.
    - form.js, line 1154 + form.js, line 1159
    @@ -5420,7 +5422,7 @@ on the amount of passed arguments.
    - form.js, line 904 + form.js, line 908
    @@ -5526,7 +5528,7 @@ elements load functions rejected with an error.
    - form.js, line 1017 + form.js, line 1021
    @@ -5743,7 +5745,7 @@ descendant of AbstractValue.

    - form.js, line 933 + form.js, line 937
    @@ -5851,7 +5853,7 @@ not meeting the validation constraints of their respective elements.
    - form.js, line 2337 + form.js, line 2344
    @@ -5959,7 +5961,7 @@ the form element's markup, including the markup of any child elements.
    - form.js, line 288 + form.js, line 289
    @@ -6108,7 +6110,7 @@ entities decoded.
    - form.js, line 974 + form.js, line 978
    @@ -6327,7 +6329,7 @@ contents. If omitted, no description will be rendered.

    - form.js, line 1054 + form.js, line 1058
    @@ -6596,7 +6598,7 @@ descendant of AbstractValue.

    - form.js, line 327 + form.js, line 328
    @@ -6797,7 +6799,7 @@ was neither a string nor a function. diff --git a/jsapi/LuCI.form.Value.html b/jsapi/LuCI.form.Value.html index e8d59647b7..dd5fbad531 100644 --- a/jsapi/LuCI.form.Value.html +++ b/jsapi/LuCI.form.Value.html @@ -86,6 +86,8 @@
  • hasViewPermission
  • +
  • isArguments
  • +
  • isObject
  • location
  • @@ -3664,7 +3666,7 @@
    - form.js, line 3606 + form.js, line 3621
    @@ -4759,7 +4761,7 @@ table section elements.

    - form.js, line 210 + form.js, line 212
    @@ -4877,7 +4879,7 @@ table section elements.

    - form.js, line 1752 + form.js, line 1758
    @@ -5055,7 +5057,7 @@ within the given specific section.

    - form.js, line 1826 + form.js, line 1832
    @@ -5233,7 +5235,7 @@ different way.

    - form.js, line 1634 + form.js, line 1639
    @@ -5265,20 +5267,20 @@ constraint evaluation. The associated value of these special "tag" key is ignored. The recognized tags are:

    Examples:

    @@ -5302,7 +5304,7 @@ is ignored. The recognized tags are:

  • opt.depends({ foo: "test" })
    - opt.depends({ bar: "qrx" })

    + opt.depends({ bar: "qrx" })
    Require either foo to be set to test, or the bar option to be qrx.
  • @@ -5454,7 +5456,7 @@ argument, this parameter is ignored.

    - form.js, line 1854 + form.js, line 1860
    @@ -5631,7 +5633,7 @@ It may be overwritten by user code to handle input values differently.

    - form.js, line 1803 + form.js, line 1809
    @@ -5809,7 +5811,7 @@ option implementation does not use LuCI.ui widgets.
    - form.js, line 1941 + form.js, line 1947
    @@ -5956,7 +5958,7 @@ option implementation does not use LuCI.ui widgets.
    - form.js, line 1959 + form.js, line 1965
    @@ -6106,7 +6108,7 @@ returns false.
    - form.js, line 1927 + form.js, line 1933
    @@ -6254,7 +6256,7 @@ returns false.
    - form.js, line 1780 + form.js, line 1786
    @@ -6437,7 +6439,7 @@ so it may return promises if overridden by user code.
    - form.js, line 2000 + form.js, line 2006
    @@ -6588,7 +6590,7 @@ validation constraints.
    - form.js, line 2080 + form.js, line 2086
    @@ -6713,7 +6715,7 @@ implement alternative removal logic, e.g. to retain the original value.

    - form.js, line 3680 + form.js, line 3695
    @@ -6821,7 +6823,7 @@ the form element's markup, including the markup of any child elements.
    - form.js, line 288 + form.js, line 289
    @@ -6970,7 +6972,7 @@ entities decoded.
    - form.js, line 1878 + form.js, line 1884
    @@ -7150,7 +7152,7 @@ state of checkbox elements.

    - form.js, line 327 + form.js, line 328
    @@ -7343,7 +7345,7 @@ was neither a string nor a function.
    - form.js, line 3671 + form.js, line 3686
    @@ -7491,7 +7493,7 @@ or a plain text string. If omitted, the key value is used as captio
    - form.js, line 2057 + form.js, line 2063
    @@ -7650,7 +7652,7 @@ before it is written.

    diff --git a/jsapi/LuCI.form.html b/jsapi/LuCI.form.html index aa886c0679..629411aa65 100644 --- a/jsapi/LuCI.form.html +++ b/jsapi/LuCI.form.html @@ -86,6 +86,8 @@
  • hasViewPermission
  • +
  • isArguments
  • +
  • isObject
  • location
  • @@ -3657,7 +3659,7 @@ assemble the HTML markup and insert it into the DOM.

    'use strict'; 'require form'; -var m, s, o; +let m, s, o; m = new form.Map('example', 'Example form', 'This is an example form mapping the contents of /etc/config/example'); @@ -3671,7 +3673,7 @@ o = s.option(form.ListValue, 'some_choice', 'A select element'); o.value('choice1', 'The first choice'); o.value('choice2', 'The second choice'); -m.render().then(function(node) { +m.render().then((node) => { document.body.appendChild(node); }); @@ -3693,7 +3695,7 @@ m.render().then(function(node) {
    - form.js, line 4954 + form.js, line 4970
    @@ -3849,7 +3851,7 @@ m.render().then(function(node) { diff --git a/jsapi/LuCI.fs.html b/jsapi/LuCI.fs.html index 0ec596ce78..2dce51f026 100644 --- a/jsapi/LuCI.fs.html +++ b/jsapi/LuCI.fs.html @@ -86,6 +86,8 @@
  • hasViewPermission
  • +
  • isArguments
  • +
  • isObject
  • location
  • @@ -6035,7 +6037,7 @@ the failure reason. diff --git a/jsapi/LuCI.headers.html b/jsapi/LuCI.headers.html index 3330c68fa1..f0ba952eb7 100644 --- a/jsapi/LuCI.headers.html +++ b/jsapi/LuCI.headers.html @@ -86,6 +86,8 @@
  • hasViewPermission
  • +
  • isArguments
  • +
  • isObject
  • location
  • @@ -3663,7 +3665,7 @@ response objects using the response.headers property.

    - luci.js, line 332 + luci.js, line 289
    @@ -3748,7 +3750,7 @@ response objects using the response.headers property.

    - luci.js, line 380 + luci.js, line 337
    @@ -3897,7 +3899,7 @@ Note: Header-Names are case-insensitive.

    - luci.js, line 364 + luci.js, line 321
    @@ -4051,7 +4053,7 @@ Note: Header-Names are case-insensitive.

    diff --git a/jsapi/LuCI.html b/jsapi/LuCI.html index 9a5c5ae325..bec1882d42 100644 --- a/jsapi/LuCI.html +++ b/jsapi/LuCI.html @@ -86,6 +86,8 @@
  • hasViewPermission
  • +
  • isArguments
  • +
  • isObject
  • location
  • @@ -4179,7 +4181,7 @@ to request the LuCI.view class.

    - luci.js, line 2393 + luci.js, line 2342
    @@ -4391,7 +4393,7 @@ as parameters.

    - luci.js, line 2352 + luci.js, line 2301
    @@ -4630,7 +4632,7 @@ argument or copied from the given error instance.

    - luci.js, line 2773 + luci.js, line 2715
    @@ -4785,7 +4787,7 @@ document root.

    - luci.js, line 3122 + luci.js, line 3074
    @@ -4997,7 +4999,7 @@ callback function. The function is a wrapper around
    - luci.js, line 3260 + luci.js, line 3209
    @@ -5100,7 +5102,7 @@ when it didn't run to begin with.
    - luci.js, line 2651 + luci.js, line 2597
    @@ -5293,7 +5295,7 @@ has no sub-features.
    - luci.js, line 3226 + luci.js, line 3175
    @@ -5386,6 +5388,159 @@ group is granted with write permissions. + + + + +
    +
    +

    + + isArguments(val){boolean} +

    + + + + +
    + + +
    +
    + + +
    +

    Tests whether the passed argument is a function arguments object.

    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    NameTypeDescription
    val + + +* + + + + + + + optional + + + + + +

    The value to test

    + + + +
    + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + + + + + +
    Returns:
    + + + + + + + + + + + + + + + + + + + + +
    TypeDescription
    + + boolean + + + Returns true if the given value is a function arguments object, +else returns false.
    + + + +
    @@ -5399,7 +5554,7 @@ group is granted with write permissions.
    - luci.js, line 2927 + luci.js, line 2868
    @@ -5554,7 +5709,7 @@ not null, else returns false.
    - luci.js, line 2907 + luci.js, line 2848
    @@ -5654,7 +5809,7 @@ not null, else returns false.
    - luci.js, line 2894 + luci.js, line 2835
    @@ -5813,7 +5968,7 @@ slashes and any of the other characters mentioned above.

    - luci.js, line 2813 + luci.js, line 2754
    @@ -6002,7 +6157,7 @@ slashes and any of the other characters mentioned above.

    - luci.js, line 3192 + luci.js, line 3144
    @@ -6307,7 +6462,7 @@ polling request.
    - luci.js, line 3150 + luci.js, line 3102
    @@ -6522,7 +6677,7 @@ by default.

    - luci.js, line 2286 + luci.js, line 2235
    @@ -6761,7 +6916,7 @@ argument or copied from the given error instance.

    - luci.js, line 2432 + luci.js, line 2381
    @@ -7019,7 +7174,7 @@ class instance.

    - luci.js, line 3077 + luci.js, line 3029
    @@ -7190,7 +7345,7 @@ to the given default value on error.
    - luci.js, line 2870 + luci.js, line 2811
    @@ -7349,7 +7504,7 @@ slashes and any of the other characters mentioned above.

    - luci.js, line 3273 + luci.js, line 3222
    @@ -7452,7 +7607,7 @@ when it was already running.
    - luci.js, line 3022 + luci.js, line 2974
    @@ -7609,7 +7764,7 @@ and the sorting is performed in-place.

    - luci.js, line 2956 + luci.js, line 2914
    @@ -7832,7 +7987,7 @@ addresses or numeric values respectively.

    - luci.js, line 3247 + luci.js, line 3196
    @@ -7980,7 +8135,7 @@ it could not be found.
    - luci.js, line 3043 + luci.js, line 2995
    @@ -8130,7 +8285,7 @@ space and returned as array.

    - luci.js, line 2846 + luci.js, line 2787
    @@ -8295,7 +8450,7 @@ slashes and any of the other characters mentioned above.

    - luci.js, line 3081 + luci.js, line 3033
    @@ -8466,7 +8621,7 @@ else null.

    diff --git a/jsapi/LuCI.network.Device.html b/jsapi/LuCI.network.Device.html index dbb51e93ea..420b72113f 100644 --- a/jsapi/LuCI.network.Device.html +++ b/jsapi/LuCI.network.Device.html @@ -86,6 +86,8 @@
  • hasViewPermission
  • +
  • isArguments
  • +
  • isObject
  • location
  • @@ -6416,7 +6418,7 @@ when it is down or absent. diff --git a/jsapi/LuCI.network.Hosts.html b/jsapi/LuCI.network.Hosts.html index b19d3d2f8a..35d46ba61e 100644 --- a/jsapi/LuCI.network.Hosts.html +++ b/jsapi/LuCI.network.Hosts.html @@ -86,6 +86,8 @@
  • hasViewPermission
  • +
  • isArguments
  • +
  • isObject
  • location
  • @@ -4977,7 +4979,7 @@ is used as hint. diff --git a/jsapi/LuCI.network.Protocol.html b/jsapi/LuCI.network.Protocol.html index 3f28281adc..03de36e219 100644 --- a/jsapi/LuCI.network.Protocol.html +++ b/jsapi/LuCI.network.Protocol.html @@ -86,6 +86,8 @@
  • hasViewPermission
  • +
  • isArguments
  • +
  • isObject
  • location
  • @@ -8313,7 +8315,7 @@ configuration.

    diff --git a/jsapi/LuCI.network.WifiDevice.html b/jsapi/LuCI.network.WifiDevice.html index ae58d88efb..83b3217874 100644 --- a/jsapi/LuCI.network.WifiDevice.html +++ b/jsapi/LuCI.network.WifiDevice.html @@ -86,6 +86,8 @@
  • hasViewPermission
  • +
  • isArguments
  • +
  • isObject
  • location
  • @@ -5354,7 +5356,7 @@ configuration.

    diff --git a/jsapi/LuCI.network.WifiNetwork.html b/jsapi/LuCI.network.WifiNetwork.html index 325747374e..78ad457df1 100644 --- a/jsapi/LuCI.network.WifiNetwork.html +++ b/jsapi/LuCI.network.WifiNetwork.html @@ -86,6 +86,8 @@
  • hasViewPermission
  • +
  • isArguments
  • +
  • isObject
  • location
  • @@ -7938,7 +7940,7 @@ configuration.

    diff --git a/jsapi/LuCI.network.html b/jsapi/LuCI.network.html index 85d88868f7..9881ec643d 100644 --- a/jsapi/LuCI.network.html +++ b/jsapi/LuCI.network.html @@ -86,6 +86,8 @@
  • hasViewPermission
  • +
  • isArguments
  • +
  • isObject
  • location
  • @@ -9881,7 +9883,7 @@ conjunction with quality to calculate a quality percentage.

    - Documentation generated by JSDoc 3.6.11 on Thu Dec 19 2024 19:20:36 GMT+0000 (Coordinated Universal Time) + Documentation generated by JSDoc 3.6.11 on Fri Dec 20 2024 00:14:55 GMT+0000 (Coordinated Universal Time) diff --git a/jsapi/LuCI.poll.html b/jsapi/LuCI.poll.html index b2d497afaa..eb6ea2845e 100644 --- a/jsapi/LuCI.poll.html +++ b/jsapi/LuCI.poll.html @@ -86,6 +86,8 @@
  • hasViewPermission
  • +
  • isArguments
  • +
  • isObject
  • location
  • @@ -3664,7 +3666,7 @@ loop.

    - luci.js, line 1041 + luci.js, line 994
    @@ -3749,7 +3751,7 @@ loop.

    - luci.js, line 1202 + luci.js, line 1155
    @@ -3851,7 +3853,7 @@ loop.

    - luci.js, line 1075 + luci.js, line 1028
    @@ -4048,7 +4050,7 @@ already is registered.
    - luci.js, line 1116 + luci.js, line 1069
    @@ -4222,7 +4224,7 @@ wasn't found.
    - luci.js, line 1142 + luci.js, line 1095
    @@ -4324,7 +4326,7 @@ where registered) or false when the polling loop already runs.
    - luci.js, line 1167 + luci.js, line 1120
    @@ -4434,7 +4436,7 @@ run to begin with. diff --git a/jsapi/LuCI.request.html b/jsapi/LuCI.request.html index f6bf7933dd..de4390beca 100644 --- a/jsapi/LuCI.request.html +++ b/jsapi/LuCI.request.html @@ -86,6 +86,8 @@
  • hasViewPermission
  • +
  • isArguments
  • +
  • isObject
  • location
  • @@ -3663,7 +3665,7 @@ for dealing with responses.

    - luci.js, line 604 + luci.js, line 560
    @@ -3755,7 +3757,7 @@ for dealing with responses.

    - luci.js, line 895 + luci.js, line 850
    @@ -3903,7 +3905,7 @@ implementing request retries before returning a failure.

    - luci.js, line 630 + luci.js, line 586
    @@ -4049,7 +4051,7 @@ if it already was absolute.
    - luci.js, line 848 + luci.js, line 803
    @@ -4229,7 +4231,7 @@ if it already was absolute.
    - luci.js, line 869 + luci.js, line 824
    @@ -4439,7 +4441,7 @@ if it already was absolute.
    - luci.js, line 914 + luci.js, line 869
    @@ -4586,7 +4588,7 @@ function.

    - luci.js, line 697 + luci.js, line 653
    @@ -4772,7 +4774,7 @@ function.

    - luci.js, line 873 + luci.js, line 828
    @@ -5369,7 +5371,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 0d4087859a..cea8fa27d2 100644 --- a/jsapi/LuCI.request.poll.html +++ b/jsapi/LuCI.request.poll.html @@ -86,6 +86,8 @@
  • hasViewPermission
  • +
  • isArguments
  • +
  • isObject
  • location
  • @@ -3664,7 +3666,7 @@ request calls as polling functions.

    - luci.js, line 932 + luci.js, line 888
    @@ -3749,7 +3751,7 @@ request calls as polling functions.

    - luci.js, line 1037 + luci.js, line 990
    @@ -3820,7 +3822,7 @@ request calls as polling functions.

    - luci.js, line 975 + luci.js, line 931
    @@ -4087,7 +4089,7 @@ invoke for each HTTP reply.

    - luci.js, line 1013 + luci.js, line 966
    @@ -4234,7 +4236,7 @@ This function is essentially a wrapper around
    - luci.js, line 1021 + luci.js, line 974
    @@ -4305,7 +4307,7 @@ This function is essentially a wrapper around
    - luci.js, line 1029 + luci.js, line 982
    @@ -4382,7 +4384,7 @@ This function is essentially a wrapper around
    - luci.js, line 933 + luci.js, line 889
    @@ -4553,7 +4555,7 @@ else null.

    diff --git a/jsapi/LuCI.response.html b/jsapi/LuCI.response.html index e525805711..4617a46850 100644 --- a/jsapi/LuCI.response.html +++ b/jsapi/LuCI.response.html @@ -86,6 +86,8 @@
  • hasViewPermission
  • +
  • isArguments
  • +
  • isObject
  • location
  • @@ -3662,7 +3664,7 @@
    - luci.js, line 386 + luci.js, line 343
    @@ -4021,7 +4023,7 @@
    - luci.js, line 548 + luci.js, line 505
    @@ -4121,7 +4123,7 @@
    - luci.js, line 497 + luci.js, line 454
    @@ -4276,7 +4278,7 @@ using String() and treated as response text.

    - luci.js, line 518 + luci.js, line 475
    @@ -4403,7 +4405,7 @@ using String() and treated as response text.

    - luci.js, line 533 + luci.js, line 490
    @@ -4511,7 +4513,7 @@ using String() and treated as response text.

    diff --git a/jsapi/LuCI.rpc.html b/jsapi/LuCI.rpc.html index 57516b9457..9762f9e761 100644 --- a/jsapi/LuCI.rpc.html +++ b/jsapi/LuCI.rpc.html @@ -86,6 +86,8 @@
  • hasViewPermission
  • +
  • isArguments
  • +
  • isObject
  • location
  • @@ -3748,7 +3750,7 @@ and means for listing and invoking remove RPC methods.

    - rpc.js, line 462 + rpc.js, line 458
    @@ -3893,7 +3895,7 @@ and means for listing and invoking remove RPC methods.

    - rpc.js, line 299 + rpc.js, line 296
    @@ -4041,7 +4043,7 @@ signatures of each given object.

    - rpc.js, line 375 + rpc.js, line 371
    @@ -4141,7 +4143,7 @@ signatures of each given object.

    - rpc.js, line 354 + rpc.js, line 350
    @@ -4242,7 +4244,7 @@ requests.
    - rpc.js, line 399 + rpc.js, line 395
    @@ -4555,7 +4557,7 @@ signatures of each requested ubus object name will be returned. - rpc.js, line 478 + rpc.js, line 475 @@ -4701,7 +4703,7 @@ if it has not been found.
    - rpc.js, line 385 + rpc.js, line 381
    @@ -4817,7 +4819,7 @@ if it has not been found.
    - rpc.js, line 365 + rpc.js, line 361
    @@ -5271,7 +5273,7 @@ behaviour is to resolve with the call return code value instead.

    - rpc.js, line 238 + rpc.js, line 235
    @@ -5484,7 +5486,7 @@ of the RPC method as-is.
    - rpc.js, line 416 + rpc.js, line 412
    @@ -5672,7 +5674,7 @@ function will fail too, forwarding the error to the caller.
    - rpc.js, line 261 + rpc.js, line 258
    @@ -5842,7 +5844,7 @@ to the expect and filter declarations. diff --git a/jsapi/LuCI.session.html b/jsapi/LuCI.session.html index 7f02bb26de..c25200bdbb 100644 --- a/jsapi/LuCI.session.html +++ b/jsapi/LuCI.session.html @@ -86,6 +86,8 @@
  • hasViewPermission
  • +
  • isArguments
  • +
  • isObject
  • location
  • @@ -3662,7 +3664,7 @@
    - luci.js, line 1822 + luci.js, line 1772
    @@ -3747,7 +3749,7 @@
    - luci.js, line 1839 + luci.js, line 1789
    @@ -3847,7 +3849,7 @@
    - luci.js, line 1864 + luci.js, line 1814
    @@ -4001,7 +4003,7 @@ found.
    - luci.js, line 1849 + luci.js, line 1799
    @@ -4104,7 +4106,7 @@ found.
    - luci.js, line 1898 + luci.js, line 1848
    @@ -4281,7 +4283,7 @@ being put in the session store.

    diff --git a/jsapi/LuCI.uci.html b/jsapi/LuCI.uci.html index a3b052d2ea..899f61a299 100644 --- a/jsapi/LuCI.uci.html +++ b/jsapi/LuCI.uci.html @@ -86,6 +86,8 @@
  • hasViewPermission
  • +
  • isArguments
  • +
  • isObject
  • location
  • @@ -3750,7 +3752,7 @@ UCI configuration data.

    - uci.js, line 291 + uci.js, line 289
    @@ -3961,7 +3963,7 @@ to the given name for non-anonymous sections.
    - uci.js, line 957 + uci.js, line 940
    @@ -4123,7 +4125,7 @@ operation to cancel the rollback timer.

    - uci.js, line 1037 + uci.js, line 1020
    @@ -4224,7 +4226,7 @@ names as keys and arrays of related change records as values.
    - uci.js, line 333 + uci.js, line 329
    @@ -4642,7 +4644,7 @@ where X denotes a hexadecimal digit.
    - uci.js, line 513 + uci.js, line 506
    @@ -4871,7 +4873,7 @@ found or if the corresponding configuration is not loaded.
    - uci.js, line 713 + uci.js, line 697
    @@ -5104,7 +5106,7 @@ found or if the corresponding configuration is not loaded.
    - uci.js, line 227 + uci.js, line 225
    @@ -5259,7 +5261,7 @@ that have been successfully loaded.
    - uci.js, line 813 + uci.js, line 795
    @@ -5528,7 +5530,7 @@ when either the section specified by sid1 or by sid2 i
    - uci.js, line 365 + uci.js, line 361
    @@ -5845,7 +5847,7 @@ not be resolved to existing section ID.
    - uci.js, line 867 + uci.js, line 850
    @@ -5949,7 +5951,7 @@ have been reloaded by the save operation.
    - uci.js, line 454 + uci.js, line 447
    @@ -6162,7 +6164,7 @@ configuration, filtered by type, if a type has been specified.
    - uci.js, line 601 + uci.js, line 591
    @@ -6358,7 +6360,7 @@ with the given value.

    - uci.js, line 748 + uci.js, line 731
    @@ -6579,7 +6581,7 @@ with the given value.

    - uci.js, line 259 + uci.js, line 257
    @@ -6699,7 +6701,7 @@ names to unload.

    - uci.js, line 682 + uci.js, line 666
    @@ -6864,7 +6866,7 @@ configuration.

    - uci.js, line 778 + uci.js, line 760
    @@ -7451,7 +7453,7 @@ underlying option is an UCI list.

    - uci.js, line 422 + uci.js, line 415
    @@ -7598,7 +7600,7 @@ associated name as arguments.

    diff --git a/jsapi/LuCI.ui.AbstractElement.html b/jsapi/LuCI.ui.AbstractElement.html index a75d8da5c0..dd99c4213c 100644 --- a/jsapi/LuCI.ui.AbstractElement.html +++ b/jsapi/LuCI.ui.AbstractElement.html @@ -86,6 +86,8 @@
  • hasViewPermission
  • +
  • isArguments
  • +
  • isObject
  • location
  • @@ -4340,7 +4342,7 @@ registered.

    - ui.js, line 304 + ui.js, line 303
    @@ -4441,7 +4443,7 @@ widget markup.
    - ui.js, line 285 + ui.js, line 284
    @@ -5385,7 +5387,7 @@ and are displayed in a slightly faded style.

    diff --git a/jsapi/LuCI.ui.Checkbox.html b/jsapi/LuCI.ui.Checkbox.html index 00952ffee9..e5968bf5ea 100644 --- a/jsapi/LuCI.ui.Checkbox.html +++ b/jsapi/LuCI.ui.Checkbox.html @@ -86,6 +86,8 @@
  • hasViewPermission
  • +
  • isArguments
  • +
  • isObject
  • location
  • @@ -3669,7 +3671,7 @@ external JavaScript, use L.require("ui").then(...) and ac
    - ui.js, line 548 + ui.js, line 546
    @@ -3962,7 +3964,7 @@ external JavaScript, use L.require("ui").then(...) and ac
    - ui.js, line 673 + ui.js, line 671
    @@ -4176,7 +4178,7 @@ as changed.
    - ui.js, line 668 + ui.js, line 666
    @@ -4553,7 +4555,7 @@ registered.

    - ui.js, line 602 + ui.js, line 600
    @@ -4656,7 +4658,7 @@ widget markup.
    - ui.js, line 285 + ui.js, line 284
    @@ -5097,7 +5099,7 @@ trigger input value validation.

    - ui.js, line 680 + ui.js, line 678
    @@ -5499,7 +5501,7 @@ it is required for HTML based form submissions.

    diff --git a/jsapi/LuCI.ui.ComboButton.html b/jsapi/LuCI.ui.ComboButton.html index c27e1eb985..618bc4de26 100644 --- a/jsapi/LuCI.ui.ComboButton.html +++ b/jsapi/LuCI.ui.ComboButton.html @@ -86,6 +86,8 @@
  • hasViewPermission
  • +
  • isArguments
  • +
  • isObject
  • location
  • @@ -3670,7 +3672,7 @@ external JavaScript, use L.require("ui").then(...) and ac
    - ui.js, line 2042 + ui.js, line 2067
    @@ -3898,7 +3900,7 @@ choice labels.

    - ui.js, line 1700 + ui.js, line 1712
    @@ -4044,7 +4046,7 @@ as label text. Choice labels may be any valid value accepted by
    - ui.js, line 1665 + ui.js, line 1677
    @@ -4181,7 +4183,7 @@ of keeping them.

    - ui.js, line 1733 + ui.js, line 1745
    @@ -4736,7 +4738,7 @@ registered.

    - ui.js, line 285 + ui.js, line 284
    @@ -5529,7 +5531,7 @@ choice value as second argument.

    diff --git a/jsapi/LuCI.ui.Combobox.html b/jsapi/LuCI.ui.Combobox.html index 469c79676e..752a283c77 100644 --- a/jsapi/LuCI.ui.Combobox.html +++ b/jsapi/LuCI.ui.Combobox.html @@ -86,6 +86,8 @@
  • hasViewPermission
  • +
  • isArguments
  • +
  • isObject
  • location
  • @@ -3672,7 +3674,7 @@ external JavaScript, use L.require("ui").then(...) and ac
    - ui.js, line 1973 + ui.js, line 1998
    @@ -3900,7 +3902,7 @@ choice labels.

    - ui.js, line 1700 + ui.js, line 1712
    @@ -4046,7 +4048,7 @@ as label text. Choice labels may be any valid value accepted by
    - ui.js, line 1665 + ui.js, line 1677
    @@ -4183,7 +4185,7 @@ of keeping them.

    - ui.js, line 1733 + ui.js, line 1745
    @@ -4738,7 +4740,7 @@ registered.

    - ui.js, line 285 + ui.js, line 284
    @@ -5432,7 +5434,7 @@ forcibly set to true.

    diff --git a/jsapi/LuCI.ui.Dropdown.html b/jsapi/LuCI.ui.Dropdown.html index 9ad5108772..6aa5db7682 100644 --- a/jsapi/LuCI.ui.Dropdown.html +++ b/jsapi/LuCI.ui.Dropdown.html @@ -86,6 +86,8 @@
  • hasViewPermission
  • +
  • isArguments
  • +
  • isObject
  • location
  • @@ -3670,7 +3672,7 @@ external JavaScript, use L.require("ui").then(...) and ac
    - ui.js, line 894 + ui.js, line 892
    @@ -3896,7 +3898,7 @@ choice labels.

    - ui.js, line 1700 + ui.js, line 1712
    @@ -4040,7 +4042,7 @@ as label text. Choice labels may be any valid value accepted by
    - ui.js, line 1665 + ui.js, line 1677
    @@ -4175,7 +4177,7 @@ of keeping them.

    - ui.js, line 1733 + ui.js, line 1745
    @@ -4350,7 +4352,7 @@ of keeping them.

    - ui.js, line 1961 + ui.js, line 1986
    @@ -4841,7 +4843,7 @@ registered.

    - ui.js, line 1048 + ui.js, line 1046
    @@ -4944,7 +4946,7 @@ widget markup.
    - ui.js, line 285 + ui.js, line 284
    @@ -5385,7 +5387,7 @@ trigger input value validation.

    - ui.js, line 1934 + ui.js, line 1959
    @@ -6230,7 +6232,7 @@ expression. Only applicable when create is true.

    - Documentation generated by JSDoc 3.6.11 on Thu Dec 19 2024 19:20:36 GMT+0000 (Coordinated Universal Time) + Documentation generated by JSDoc 3.6.11 on Fri Dec 20 2024 00:14:55 GMT+0000 (Coordinated Universal Time) diff --git a/jsapi/LuCI.ui.DynamicList.html b/jsapi/LuCI.ui.DynamicList.html index bb336225c2..297d902468 100644 --- a/jsapi/LuCI.ui.DynamicList.html +++ b/jsapi/LuCI.ui.DynamicList.html @@ -86,6 +86,8 @@
  • hasViewPermission
  • +
  • isArguments
  • +
  • isObject
  • location
  • @@ -3671,7 +3673,7 @@ external JavaScript, use L.require("ui").then(...) and ac
    - ui.js, line 2158 + ui.js, line 2183
    @@ -3901,7 +3903,7 @@ arbitrary values to the dynamic list.

    - ui.js, line 2594 + ui.js, line 2620
    @@ -4045,7 +4047,7 @@ as label text. Choice labels may be any valid value accepted by
    - ui.js, line 2607 + ui.js, line 2633
    @@ -4221,7 +4223,7 @@ as label text. Choice labels may be any valid value accepted by
    - ui.js, line 2545 + ui.js, line 2571
    @@ -4712,7 +4714,7 @@ registered.

    - ui.js, line 2227 + ui.js, line 2252
    @@ -4815,7 +4817,7 @@ widget markup.
    - ui.js, line 285 + ui.js, line 284
    @@ -5256,7 +5258,7 @@ trigger input value validation.

    - ui.js, line 2562 + ui.js, line 2588
    @@ -5607,7 +5609,7 @@ it to remain unselected.

    diff --git a/jsapi/LuCI.ui.FileUpload.html b/jsapi/LuCI.ui.FileUpload.html index 3ee7412d06..0e4e2d7256 100644 --- a/jsapi/LuCI.ui.FileUpload.html +++ b/jsapi/LuCI.ui.FileUpload.html @@ -86,6 +86,8 @@
  • hasViewPermission
  • +
  • isArguments
  • +
  • isObject
  • location
  • @@ -3670,7 +3672,7 @@ external JavaScript, use L.require("ui").then(...) and ac
    - ui.js, line 2679 + ui.js, line 2705
    @@ -3967,7 +3969,7 @@ upload control.

    - ui.js, line 3173 + ui.js, line 3199
    @@ -4458,7 +4460,7 @@ registered.

    - ui.js, line 2773 + ui.js, line 2799
    @@ -4561,7 +4563,7 @@ widget markup.
    - ui.js, line 285 + ui.js, line 284
    @@ -5002,7 +5004,7 @@ trigger input value validation.

    - ui.js, line 3178 + ui.js, line 3204
    @@ -5530,7 +5532,7 @@ ACL setup for the current session.

    diff --git a/jsapi/LuCI.ui.Hiddenfield.html b/jsapi/LuCI.ui.Hiddenfield.html index 6ec2678c97..0e951be9f6 100644 --- a/jsapi/LuCI.ui.Hiddenfield.html +++ b/jsapi/LuCI.ui.Hiddenfield.html @@ -86,6 +86,8 @@
  • hasViewPermission
  • +
  • isArguments
  • +
  • isObject
  • location
  • @@ -3670,7 +3672,7 @@ external JavaScript, use L.require("ui").then(...) and ac
    - ui.js, line 2613 + ui.js, line 2639
    @@ -3966,7 +3968,7 @@ external JavaScript, use L.require("ui").then(...) and ac
    - ui.js, line 2669 + ui.js, line 2695
    @@ -4457,7 +4459,7 @@ registered.

    - ui.js, line 2649 + ui.js, line 2675
    @@ -4560,7 +4562,7 @@ widget markup.
    - ui.js, line 285 + ui.js, line 284
    @@ -5001,7 +5003,7 @@ trigger input value validation.

    - ui.js, line 2674 + ui.js, line 2700
    @@ -5210,7 +5212,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 1f0b4ef828..2c380c6765 100644 --- a/jsapi/LuCI.ui.Select.html +++ b/jsapi/LuCI.ui.Select.html @@ -86,6 +86,8 @@
  • hasViewPermission
  • +
  • isArguments
  • +
  • isObject
  • location
  • @@ -3671,7 +3673,7 @@ external JavaScript, use L.require("ui").then(...) and ac
    - ui.js, line 685 + ui.js, line 683
    @@ -4001,7 +4003,7 @@ choice labels.

    - ui.js, line 864 + ui.js, line 862
    @@ -4492,7 +4494,7 @@ registered.

    - ui.js, line 776 + ui.js, line 774
    @@ -4595,7 +4597,7 @@ widget markup.
    - ui.js, line 285 + ui.js, line 284
    @@ -5036,7 +5038,7 @@ trigger input value validation.

    - ui.js, line 877 + ui.js, line 875
    @@ -5562,7 +5564,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 a7661870ed..45e1cdf0a3 100644 --- a/jsapi/LuCI.ui.Textarea.html +++ b/jsapi/LuCI.ui.Textarea.html @@ -86,6 +86,8 @@
  • hasViewPermission
  • +
  • isArguments
  • +
  • isObject
  • location
  • @@ -3669,7 +3671,7 @@ external JavaScript, use L.require("ui").then(...) and ac
    - ui.js, line 432 + ui.js, line 430
    @@ -3962,7 +3964,7 @@ external JavaScript, use L.require("ui").then(...) and ac
    - ui.js, line 538 + ui.js, line 536
    @@ -4453,7 +4455,7 @@ registered.

    - ui.js, line 499 + ui.js, line 497
    @@ -4556,7 +4558,7 @@ widget markup.
    - ui.js, line 285 + ui.js, line 284
    @@ -4997,7 +4999,7 @@ trigger input value validation.

    - ui.js, line 543 + ui.js, line 541
    @@ -5508,7 +5510,7 @@ contents.

    diff --git a/jsapi/LuCI.ui.Textfield.html b/jsapi/LuCI.ui.Textfield.html index 0b3c2a87d7..ac7b41c432 100644 --- a/jsapi/LuCI.ui.Textfield.html +++ b/jsapi/LuCI.ui.Textfield.html @@ -86,6 +86,8 @@
  • hasViewPermission
  • +
  • isArguments
  • +
  • isObject
  • location
  • @@ -3669,7 +3671,7 @@ external JavaScript, use L.require("ui").then(...) and ac
    - ui.js, line 307 + ui.js, line 306
    @@ -3962,7 +3964,7 @@ external JavaScript, use L.require("ui").then(...) and ac
    - ui.js, line 420 + ui.js, line 418
    @@ -4453,7 +4455,7 @@ registered.

    - ui.js, line 366 + ui.js, line 365
    @@ -4556,7 +4558,7 @@ widget markup.
    - ui.js, line 285 + ui.js, line 284
    @@ -4997,7 +4999,7 @@ trigger input value validation.

    - ui.js, line 426 + ui.js, line 424
    @@ -5436,7 +5438,7 @@ corresponding <input> element is empty.

    diff --git a/jsapi/LuCI.ui.changes.html b/jsapi/LuCI.ui.changes.html index d078d5d680..f61b72d5c1 100644 --- a/jsapi/LuCI.ui.changes.html +++ b/jsapi/LuCI.ui.changes.html @@ -86,6 +86,8 @@
  • hasViewPermission
  • +
  • isArguments
  • +
  • isObject
  • location
  • @@ -3667,7 +3669,7 @@ external JavaScript, use L.require("ui").then(...) and ac
    - ui.js, line 4511 + ui.js, line 4549
    @@ -3752,7 +3754,7 @@ external JavaScript, use L.require("ui").then(...) and ac
    - ui.js, line 4843 + ui.js, line 4879
    @@ -3893,7 +3895,7 @@ settings.

    - ui.js, line 4588 + ui.js, line 4626
    @@ -3966,7 +3968,7 @@ and offer options to revert or apply the shown changes.

    - ui.js, line 4554 + ui.js, line 4592
    @@ -4084,7 +4086,7 @@ UCI changeset structure.

    - ui.js, line 4919 + ui.js, line 4955
    @@ -4160,7 +4162,7 @@ complete.

    - ui.js, line 4532 + ui.js, line 4570
    @@ -4288,7 +4290,7 @@ is removed.

    diff --git a/jsapi/LuCI.ui.html b/jsapi/LuCI.ui.html index fbe8963de2..ce7b5a2e22 100644 --- a/jsapi/LuCI.ui.html +++ b/jsapi/LuCI.ui.html @@ -86,6 +86,8 @@
  • hasViewPermission
  • +
  • isArguments
  • +
  • isObject
  • location
  • @@ -3664,7 +3666,7 @@ external JavaScript, use L.require("ui").then(...).

    - ui.js, line 3618 + ui.js, line 3649 @@ -3795,7 +3797,7 @@ external JavaScript, use L.require("ui").then(...).

    - ui.js, line 3834 + ui.js, line 3863 @@ -4057,7 +4059,7 @@ banner element.

    - ui.js, line 4987 + ui.js, line 5023
    @@ -4371,7 +4373,7 @@ trigger field validation or to bind it to further events.
    - ui.js, line 4475 + ui.js, line 4512
    @@ -4508,7 +4510,7 @@ default.

    - ui.js, line 5038 + ui.js, line 5073
    @@ -4734,7 +4736,7 @@ valid function value.
    - ui.js, line 3974 + ui.js, line 4003
    @@ -4882,7 +4884,7 @@ requested indicator was not found.
    - ui.js, line 3720 + ui.js, line 3749
    @@ -4958,7 +4960,7 @@ handler as-is without the need to bind it first.

    - ui.js, line 5081 + ui.js, line 5114
    @@ -5110,7 +5112,7 @@ caught and rendered using LuCI.error() - ui.js, line 4017 + ui.js, line 4046 @@ -5352,7 +5354,7 @@ accepted by LuCI.dom.content().

    - ui.js, line 4449 + ui.js, line 4486
    @@ -5555,7 +5557,7 @@ or rejecting with null when the connectivity check timed out.
    - ui.js, line 3926 + ui.js, line 3955
    @@ -5829,7 +5831,7 @@ changes were made.
    - ui.js, line 3692 + ui.js, line 3723
    @@ -6058,7 +6060,7 @@ element.

    - ui.js, line 4332 + ui.js, line 4364
    @@ -6416,7 +6418,7 @@ cancelled by the user. diff --git a/jsapi/LuCI.ui.menu.html b/jsapi/LuCI.ui.menu.html index 66840d7477..b7ae801f65 100644 --- a/jsapi/LuCI.ui.menu.html +++ b/jsapi/LuCI.ui.menu.html @@ -86,6 +86,8 @@
  • hasViewPermission
  • +
  • isArguments
  • +
  • isObject
  • location
  • @@ -3662,7 +3664,7 @@
    - ui.js, line 3204 + ui.js, line 3230
    @@ -3751,7 +3753,7 @@
    - ui.js, line 3253 + ui.js, line 3279
    @@ -3823,7 +3825,7 @@ next page load.

    - ui.js, line 3265 + ui.js, line 3291
    @@ -3972,7 +3974,7 @@ internal root node if omitted.

    - ui.js, line 3233 + ui.js, line 3259
    @@ -4335,7 +4337,7 @@ internal root node if omitted.

    diff --git a/jsapi/LuCI.ui.tabs.html b/jsapi/LuCI.ui.tabs.html index 833d507362..59f08869a0 100644 --- a/jsapi/LuCI.ui.tabs.html +++ b/jsapi/LuCI.ui.tabs.html @@ -86,6 +86,8 @@
  • hasViewPermission
  • +
  • isArguments
  • +
  • isObject
  • location
  • @@ -3668,7 +3670,7 @@ external JavaScript, use L.require("ui").then(...) and ac
    - ui.js, line 4058 + ui.js, line 4087
    @@ -3753,7 +3755,7 @@ external JavaScript, use L.require("ui").then(...) and ac
    - ui.js, line 4113 + ui.js, line 4144
    @@ -3882,7 +3884,7 @@ DOM node.

    - ui.js, line 4185 + ui.js, line 4216
    @@ -4035,7 +4037,7 @@ DOM node.

    diff --git a/jsapi/LuCI.view.html b/jsapi/LuCI.view.html index e88bae4898..da7d39e7ae 100644 --- a/jsapi/LuCI.view.html +++ b/jsapi/LuCI.view.html @@ -86,6 +86,8 @@
  • hasViewPermission
  • +
  • isArguments
  • +
  • isObject
  • location
  • @@ -3663,7 +3665,7 @@ set of methods to inherit from.

    - luci.js, line 1927 + luci.js, line 1877
    @@ -3748,7 +3750,7 @@ set of methods to inherit from.

    - luci.js, line 2154 + luci.js, line 2104
    @@ -3861,7 +3863,7 @@ methods are overwritten with null.
    - luci.js, line 2120 + luci.js, line 2070
    @@ -4025,7 +4027,7 @@ is re-enabled.
    - luci.js, line 2039 + luci.js, line 1989
    @@ -4189,7 +4191,7 @@ is re-enabled.
    - luci.js, line 2083 + luci.js, line 2033
    @@ -4355,7 +4357,7 @@ is re-enabled.
    - luci.js, line 1974 + luci.js, line 1924
    @@ -4465,7 +4467,7 @@ the default implementation does nothing.

    - luci.js, line 2006 + luci.js, line 1956
    @@ -4639,7 +4641,7 @@ to a Node value. diff --git a/jsapi/LuCI.xhr.html b/jsapi/LuCI.xhr.html index 13473c180f..a06f13d60c 100644 --- a/jsapi/LuCI.xhr.html +++ b/jsapi/LuCI.xhr.html @@ -86,6 +86,8 @@
  • hasViewPermission
  • +
  • isArguments
  • +
  • isObject
  • location
  • @@ -3666,7 +3668,7 @@ request handling.

    - luci.js, line 3326 + luci.js, line 3275
    @@ -3753,7 +3755,7 @@ request handling.

    - luci.js, line 3442 + luci.js, line 3391
    @@ -3827,7 +3829,7 @@ request handling.

    - luci.js, line 3431 + luci.js, line 3380
    @@ -3930,7 +3932,7 @@ already completed.
    - luci.js, line 3418 + luci.js, line 3367
    @@ -4007,7 +4009,7 @@ finishes or timed out.

    - luci.js, line 3374 + luci.js, line 3323
    @@ -4250,7 +4252,7 @@ finishes or timed out.

    - luci.js, line 3401 + luci.js, line 3350
    @@ -4493,7 +4495,7 @@ finishes or timed out.

    - luci.js, line 3457 + luci.js, line 3406
    @@ -4603,7 +4605,7 @@ when invoked.

    diff --git a/jsapi/form.js.html b/jsapi/form.js.html index 51d4875139..f18856c0e3 100644 --- a/jsapi/form.js.html +++ b/jsapi/form.js.html @@ -86,6 +86,8 @@
  • hasViewPermission
  • +
  • isArguments
  • +
  • isObject
  • location
  • @@ -3643,32 +3645,33 @@ 'require dom'; 'require baseclass'; -var scope = this; +const scope = this; -var callSessionAccess = rpc.declare({ +const callSessionAccess = rpc.declare({ object: 'session', method: 'access', params: [ 'scope', 'object', 'function' ], expect: { 'access': false } }); -var CBIJSONConfig = baseclass.extend({ - __init__: function(data) { +const CBIJSONConfig = baseclass.extend({ + __init__(data) { data = Object.assign({}, data); this.data = {}; - var num_sections = 0, - section_ids = []; + let num_sections = 0; + const section_ids = []; - for (var sectiontype in data) { + for (const sectiontype in data) { if (!data.hasOwnProperty(sectiontype)) continue; if (Array.isArray(data[sectiontype])) { - for (var i = 0, index = 0; i < data[sectiontype].length; i++) { - var item = data[sectiontype][i], - anonymous, name; + for (let i = 0, index = 0; i < data[sectiontype].length; i++) { + const item = data[sectiontype][i]; + let anonymous; + let name; if (!L.isObject(item)) continue; @@ -3705,9 +3708,9 @@ var CBIJSONConfig = baseclass.extend({ } } - section_ids.sort(L.bind(function(a, b) { - var indexA = (this.data[a]['.index'] != null) ? +this.data[a]['.index'] : 9999, - indexB = (this.data[b]['.index'] != null) ? +this.data[b]['.index'] : 9999; + section_ids.sort(L.bind((a, b) => { + const indexA = (this.data[a]['.index'] != null) ? +this.data[a]['.index'] : 9999; + const indexB = (this.data[b]['.index'] != null) ? +this.data[b]['.index'] : 9999; if (indexA != indexB) return (indexA - indexB); @@ -3715,19 +3718,19 @@ var CBIJSONConfig = baseclass.extend({ return L.naturalCompare(a, b); }, this)); - for (var i = 0; i < section_ids.length; i++) + for (let i = 0; i < section_ids.length; i++) this.data[section_ids[i]]['.index'] = i; }, - load: function() { + load() { return Promise.resolve(this.data); }, - save: function() { + save() { return Promise.resolve(); }, - get: function(config, section, option) { + get(config, section, option) { if (section == null) return null; @@ -3737,7 +3740,7 @@ var CBIJSONConfig = baseclass.extend({ if (!this.data.hasOwnProperty(section)) return null; - var value = this.data[section][option]; + const value = this.data[section][option]; if (Array.isArray(value)) return value; @@ -3748,7 +3751,7 @@ var CBIJSONConfig = baseclass.extend({ return null; }, - set: function(config, section, option, value) { + set(config, section, option, value) { if (section == null || option == null || option.charAt(0) == '.') return; @@ -3763,35 +3766,36 @@ var CBIJSONConfig = baseclass.extend({ this.data[section][option] = String(value); }, - unset: function(config, section, option) { + unset(config, section, option) { return this.set(config, section, option, null); }, - sections: function(config, sectiontype, callback) { - var rv = []; + sections(config, sectiontype, callback) { + const rv = []; - for (var section_id in this.data) + for (const section_id in this.data) if (sectiontype == null || this.data[section_id]['.type'] == sectiontype) rv.push(this.data[section_id]); - rv.sort(function(a, b) { return a['.index'] - b['.index'] }); + rv.sort((a, b) => { return a['.index'] - b['.index'] }); if (typeof(callback) == 'function') - for (var i = 0; i < rv.length; i++) + for (let i = 0; i < rv.length; i++) callback.call(this, rv[i], rv[i]['.name']); return rv; }, - add: function(config, sectiontype, sectionname) { - var num_sections_type = 0, next_index = 0; + add(config, sectiontype, sectionname) { + let num_sections_type = 0; + let next_index = 0; - for (var name in this.data) { + for (const name in this.data) { num_sections_type += (this.data[name]['.type'] == sectiontype); next_index = Math.max(next_index, this.data[name]['.index']); } - var section_id = sectionname || sectiontype + num_sections_type; + const section_id = sectionname ?? (sectiontype + num_sections_type); if (!this.data.hasOwnProperty(section_id)) { this.data[section_id] = { @@ -3805,16 +3809,16 @@ var CBIJSONConfig = baseclass.extend({ return section_id; }, - remove: function(config, section) { + remove(config, section) { if (this.data.hasOwnProperty(section)) delete this.data[section]; }, - resolveSID: function(config, section_id) { + resolveSID(config, section_id) { return section_id; }, - move: function(config, section_id1, section_id2, after) { + move(config, section_id1, section_id2, after) { return uci.move.apply(this, [config, section_id1, section_id2, after]); } }); @@ -3832,10 +3836,10 @@ var CBIJSONConfig = baseclass.extend({ * * This class is private and not directly accessible by user code. */ -var CBIAbstractElement = baseclass.extend(/** @lends LuCI.form.AbstractElement.prototype */ { - __init__: function(title, description) { - this.title = title || ''; - this.description = description || ''; +const CBIAbstractElement = baseclass.extend(/** @lends LuCI.form.AbstractElement.prototype */ { + __init__(title, description) { + this.title = title ?? ''; + this.description = description ?? ''; this.children = []; }, @@ -3845,7 +3849,7 @@ var CBIAbstractElement = baseclass.extend(/** @lends LuCI.form.AbstractElement.p * @param {AbstractElement} obj * The form element to add. */ - append: function(obj) { + append(obj) { this.children.push(obj); }, @@ -3863,10 +3867,10 @@ var CBIAbstractElement = baseclass.extend(/** @lends LuCI.form.AbstractElement.p * if any parsed values are not meeting the validation constraints of their * respective elements. */ - parse: function() { - var args = arguments; - this.children.forEach(function(child) { - child.parse.apply(child, args); + parse() { + const args = arguments; + this.children.forEach((child) => { + child.parse(...args); }); }, @@ -3881,33 +3885,32 @@ var CBIAbstractElement = baseclass.extend(/** @lends LuCI.form.AbstractElement.p * May return a DOM Node or a promise resolving to a DOM node containing * the form element's markup, including the markup of any child elements. */ - render: function() { + render() { L.error('InternalError', 'Not implemented'); }, /** @private */ - loadChildren: function(/* ... */) { - var tasks = []; + loadChildren(...args) /* ... */{ + const tasks = []; if (Array.isArray(this.children)) - for (var i = 0; i < this.children.length; i++) + for (let i = 0; i < this.children.length; i++) if (!this.children[i].disable) - tasks.push(this.children[i].load.apply(this.children[i], arguments)); + tasks.push(this.children[i].load(...args)); return Promise.all(tasks); }, /** @private */ - renderChildren: function(tab_name /*, ... */) { - var tasks = [], - index = 0; + renderChildren(tab_name, ...args) { + const tasks = []; + let index = 0; if (Array.isArray(this.children)) - for (var i = 0; i < this.children.length; i++) + for (let i = 0; i < this.children.length; i++) if (tab_name === null || this.children[i].tab === tab_name) if (!this.children[i].disable) - tasks.push(this.children[i].render.apply( - this.children[i], this.varargs(arguments, 1, index++))); + tasks.push(this.children[i].render(index++, ...args)); return Promise.all(tasks); }, @@ -3923,17 +3926,17 @@ var CBIAbstractElement = baseclass.extend(/** @lends LuCI.form.AbstractElement.p * The cleaned input string with HTML tags removed, and HTML * entities decoded. */ - stripTags: function(s) { + stripTags(s) { if (typeof(s) == 'string' && !s.match(/[<>\&]/)) return s; - var x = dom.elem(s) ? s : dom.parse('<div>' + s + '</div>'); + const x = dom.elem(s) ? s : dom.parse(`<div>${s}</div>`); - x.querySelectorAll('br').forEach(function(br) { + x.querySelectorAll('br').forEach((br) => { x.replaceChild(document.createTextNode('\n'), br); }); - return (x.textContent || x.innerText || '').replace(/([ \t]*\n)+/g, '\n'); + return (x.textContent ?? x.innerText ?? '').replace(/([ \t]*\n)+/g, '\n'); }, /** @@ -3962,13 +3965,13 @@ var CBIAbstractElement = baseclass.extend(/** @lends LuCI.form.AbstractElement.p * The formatted title string or `null` if the property did not exist or * was neither a string nor a function. */ - titleFn: function(attr /*, ... */) { - var s = null; + titleFn(attr, ...args) { + let s = null; if (typeof(this[attr]) == 'function') - s = this[attr].apply(this, this.varargs(arguments, 1)); + s = this[attr](...args); else if (typeof(this[attr]) == 'string') - s = (arguments.length > 1) ? ''.format.apply(this[attr], this.varargs(arguments, 1)) : this[attr]; + s = args.length ? this[attr].format(...args) : this[attr]; if (s != null) s = this.stripTags(String(s)).trim(); @@ -4007,9 +4010,9 @@ var CBIAbstractElement = baseclass.extend(/** @lends LuCI.form.AbstractElement.p * paragraph below the form title and before the actual form contents. * If omitted, the corresponding paragraph element will not be rendered. */ -var CBIMap = CBIAbstractElement.extend(/** @lends LuCI.form.Map.prototype */ { - __init__: function(config /*, ... */) { - this.super('__init__', this.varargs(arguments, 1)); +const CBIMap = CBIAbstractElement.extend(/** @lends LuCI.form.Map.prototype */ { + __init__(config, ...args) { + this.super('__init__', args); this.config = config; this.parsechain = [ config ]; @@ -4060,13 +4063,13 @@ var CBIMap = CBIAbstractElement.extend(/** @lends LuCI.form.Map.prototype */ { * @returns {NodeList} * Returns a (possibly empty) DOM `NodeList` containing the found DOM nodes. */ - findElements: function(/* ... */) { - var q = null; + findElements(...args) /* ... */{ + let q = null; - if (arguments.length == 1) - q = arguments[0]; - else if (arguments.length == 2) - q = '[%s="%s"]'.format(arguments[0], arguments[1]); + if (args.length == 1) + q = args[0]; + else if (args.length == 2) + q = '[%s="%s"]'.format(args[0], args[1]); else L.error('InternalError', 'Expecting one or two arguments to findElements()'); @@ -4103,8 +4106,8 @@ var CBIMap = CBIAbstractElement.extend(/** @lends LuCI.form.Map.prototype */ { * @returns {Node|null} * Returns the first found DOM node or `null` if no element matched. */ - findElement: function(/* ... */) { - var res = this.findElements.apply(this, arguments); + findElement(...args) /* ... */{ + const res = this.findElements(...args); return res.length ? res[0] : null; }, @@ -4121,7 +4124,7 @@ var CBIMap = CBIAbstractElement.extend(/** @lends LuCI.form.Map.prototype */ { * The additional UCI configuration file to tie to the map. If the given * config already is in the list of required files, it will be ignored. */ - chain: function(config) { + chain(config) { if (this.parsechain.indexOf(config) == -1) this.parsechain.push(config); }, @@ -4153,11 +4156,11 @@ var CBIMap = CBIAbstractElement.extend(/** @lends LuCI.form.Map.prototype */ { * @returns {LuCI.form.AbstractSection} * Returns the instantiated section class instance. */ - section: function(cbiClass /*, ... */) { + section(cbiClass, ...args) { if (!CBIAbstractSection.isSubclass(cbiClass)) L.error('TypeError', 'Class must be a descendent of CBIAbstractSection'); - var obj = cbiClass.instantiate(this.varargs(arguments, 1, this)); + const obj = cbiClass.instantiate([this, ...args]); this.append(obj); return obj; }, @@ -4175,16 +4178,16 @@ var CBIMap = CBIAbstractElement.extend(/** @lends LuCI.form.Map.prototype */ { * to load or if any of the child elements load functions rejected with * an error. */ - load: function() { - var doCheckACL = (!(this instanceof CBIJSONMap) && this.readonly == null), - loadTasks = [ doCheckACL ? callSessionAccess('uci', this.config, 'write') : true ], - configs = this.parsechain || [ this.config ]; + load() { + const doCheckACL = (!(this instanceof CBIJSONMap) && this.readonly == null); + const loadTasks = [ doCheckACL ? callSessionAccess('uci', this.config, 'write') : true ]; + const configs = this.parsechain ?? [ this.config ]; - loadTasks.push.apply(loadTasks, configs.map(L.bind(function(config, i) { + loadTasks.push(...configs.map(L.bind((config, i) => { return i ? L.resolveDefault(this.data.load(config)) : this.data.load(config); }, this))); - return Promise.all(loadTasks).then(L.bind(function(res) { + return Promise.all(loadTasks).then(L.bind((res) => { if (res[0] === false) this.readonly = true; @@ -4205,11 +4208,11 @@ var CBIMap = CBIAbstractElement.extend(/** @lends LuCI.form.Map.prototype */ { * input values. The returned promise is rejected if any parsed values are * not meeting the validation constraints of their respective elements. */ - parse: function() { - var tasks = []; + parse() { + const tasks = []; if (Array.isArray(this.children)) - for (var i = 0; i < this.children.length; i++) + for (let i = 0; i < this.children.length; i++) tasks.push(this.children[i].parse()); return Promise.all(tasks); @@ -4235,14 +4238,14 @@ var CBIMap = CBIAbstractElement.extend(/** @lends LuCI.form.Map.prototype */ { * The returned promise is rejected if any step of the save operation * failed. */ - save: function(cb, silent) { + save(cb, silent) { this.checkDepends(); return this.parse() .then(cb) .then(this.data.save.bind(this.data)) .then(this.load.bind(this)) - .catch(function(e) { + .catch((e) => { if (!silent) { ui.showModal(_('Save error'), [ E('p', {}, [ _('An error occurred while saving the form:') ]), @@ -4265,7 +4268,7 @@ var CBIMap = CBIAbstractElement.extend(/** @lends LuCI.form.Map.prototype */ { * Returns a promise resolving to the toplevel form DOM node once the * re-rendering is complete. */ - reset: function() { + reset() { return this.renderContents(); }, @@ -4276,13 +4279,13 @@ var CBIMap = CBIAbstractElement.extend(/** @lends LuCI.form.Map.prototype */ { * Returns a promise resolving to the toplevel form DOM node once the * rendering is complete. */ - render: function() { + render() { return this.load().then(this.renderContents.bind(this)); }, /** @private */ - renderContents: function() { - var mapEl = this.root || (this.root = E('div', { + renderContents() { + const mapEl = (this.root ??= E('div', { 'id': 'cbi-%s'.format(this.config), 'class': 'cbi-map', 'cbi-dependency-check': L.bind(this.checkDepends, this) @@ -4290,8 +4293,8 @@ var CBIMap = CBIAbstractElement.extend(/** @lends LuCI.form.Map.prototype */ { dom.bindClassInstance(mapEl, this); - return this.renderChildren(null).then(L.bind(function(nodes) { - var initialRender = !mapEl.firstChild; + return this.renderChildren(null).then(L.bind((nodes) => { + const initialRender = !mapEl.firstChild; dom.content(mapEl, null); @@ -4309,16 +4312,16 @@ var CBIMap = CBIAbstractElement.extend(/** @lends LuCI.form.Map.prototype */ { if (!initialRender) { mapEl.classList.remove('flash'); - window.setTimeout(function() { + window.setTimeout(() => { mapEl.classList.add('flash'); }, 1); } this.checkDepends(); - var tabGroups = mapEl.querySelectorAll('.cbi-map-tabbed, .cbi-section-node-tabbed'); + const tabGroups = mapEl.querySelectorAll('.cbi-map-tabbed, .cbi-section-node-tabbed'); - for (var i = 0; i < tabGroups.length; i++) + for (let i = 0; i < tabGroups.length; i++) ui.tabs.initTabGroup(tabGroups[i].childNodes); return mapEl; @@ -4344,13 +4347,16 @@ var CBIMap = CBIAbstractElement.extend(/** @lends LuCI.form.Map.prototype */ { * first item and the corresponding UCI section ID as second item. * Returns `null` if the option could not be found. */ - lookupOption: function(name, section_id, config_name) { - var id, elem, sid, inst; + lookupOption(name, section_id, config_name) { + let id; + let elem; + let sid; + let inst; if (name.indexOf('.') > -1) id = 'cbid.%s'.format(name); else - id = 'cbid.%s.%s.%s'.format(config_name || this.config, section_id, name); + id = 'cbid.%s.%s.%s'.format(config_name ?? this.config, section_id, name); elem = this.findElement('data-field', id); sid = elem ? id.split(/\./)[2] : null; @@ -4360,32 +4366,32 @@ var CBIMap = CBIAbstractElement.extend(/** @lends LuCI.form.Map.prototype */ { }, /** @private */ - checkDepends: function(ev, n) { - var changed = false; + checkDepends(ev, n) { + let changed = false; - for (var i = 0, s = this.children[0]; (s = this.children[i]) != null; i++) + for (let i = 0, s = this.children[0]; (s = this.children[i]) != null; i++) if (s.checkDepends(ev, n)) changed = true; - if (changed && (n || 0) < 10) - this.checkDepends(ev, (n || 10) + 1); + if (changed && (n ?? 0) < 10) + this.checkDepends(ev, (n ?? 10) + 1); ui.tabs.updateTabs(ev, this.root); }, /** @private */ - isDependencySatisfied: function(depends, config_name, section_id) { - var def = false; + isDependencySatisfied(depends, config_name, section_id) { + let def = false; if (!Array.isArray(depends) || !depends.length) return true; - for (var i = 0; i < depends.length; i++) { - var istat = true, - reverse = depends[i]['!reverse'], - contains = depends[i]['!contains']; + for (let i = 0; i < depends.length; i++) { + let istat = true; + const reverse = depends[i]['!reverse']; + const contains = depends[i]['!contains']; - for (var dep in depends[i]) { + for (const dep in depends[i]) { if (dep == '!reverse' || dep == '!contains') { continue; } @@ -4394,10 +4400,10 @@ var CBIMap = CBIAbstractElement.extend(/** @lends LuCI.form.Map.prototype */ { istat = false; } else { - var res = this.lookupOption(dep, section_id, config_name), - val = (res && res[0].isActive(res[1])) ? res[0].formvalue(res[1]) : null; + const res = this.lookupOption(dep, section_id, config_name); + const val = (res && res[0].isActive(res[1])) ? res[0].formvalue(res[1]) : null; - var equal = contains + const equal = contains ? isContained(val, depends[i][dep]) : isEqual(val, depends[i][dep]); @@ -4440,9 +4446,9 @@ var CBIMap = CBIAbstractElement.extend(/** @lends LuCI.form.Map.prototype */ { * paragraph below the form title and before the actual form contents. * If omitted, the corresponding paragraph element will not be rendered. */ -var CBIJSONMap = CBIMap.extend(/** @lends LuCI.form.JSONMap.prototype */ { - __init__: function(data /*, ... */) { - this.super('__init__', this.varargs(arguments, 1, 'json')); +const CBIJSONMap = CBIMap.extend(/** @lends LuCI.form.JSONMap.prototype */ { + __init__(data, ...args) { + this.super('__init__', [ 'json', ...args ]); this.config = 'json'; this.parsechain = [ 'json' ]; @@ -4464,9 +4470,9 @@ var CBIJSONMap = CBIMap.extend(/** @lends LuCI.form.JSONMap.prototype */ { * * This class is private and not directly accessible by user code. */ -var CBIAbstractSection = CBIAbstractElement.extend(/** @lends LuCI.form.AbstractSection.prototype */ { - __init__: function(map, sectionType /*, ... */) { - this.super('__init__', this.varargs(arguments, 2)); +const CBIAbstractSection = CBIAbstractElement.extend(/** @lends LuCI.form.AbstractSection.prototype */ { + __init__(map, sectionType, ...args) { + this.super('__init__', args); this.sectiontype = sectionType; this.map = map; @@ -4501,7 +4507,7 @@ var CBIAbstractSection = CBIAbstractElement.extend(/** @lends LuCI.form.Abstract * Returns an array of UCI section IDs covered by this form element. * The sections will be rendered in the same order as the returned array. */ - cfgsections: function() { + cfgsections() { L.error('InternalError', 'Not implemented'); }, @@ -4524,7 +4530,7 @@ var CBIAbstractSection = CBIAbstractElement.extend(/** @lends LuCI.form.Abstract * Returns `true` when the given UCI section ID should be handled and * `false` when it should be ignored. */ - filter: function(section_id) { + filter(section_id) { return true; }, @@ -4539,15 +4545,15 @@ var CBIAbstractSection = CBIAbstractElement.extend(/** @lends LuCI.form.Abstract * been loaded. The promise may reject with an error if any of the child * elements load functions rejected with an error. */ - load: function() { - var section_ids = this.cfgsections(), - tasks = []; + load() { + const section_ids = this.cfgsections(); + const tasks = []; if (Array.isArray(this.children)) - for (var i = 0; i < section_ids.length; i++) + for (let i = 0; i < section_ids.length; i++) tasks.push(this.loadChildren(section_ids[i]) - .then(Function.prototype.bind.call(function(section_id, set_values) { - for (var i = 0; i < set_values.length; i++) + .then(Function.prototype.bind.call((section_id, set_values) => { + for (let i = 0; i < set_values.length; i++) this.children[i].cfgvalue(section_id, set_values[i]); }, this, section_ids[i]))); @@ -4568,13 +4574,13 @@ var CBIAbstractSection = CBIAbstractElement.extend(/** @lends LuCI.form.Abstract * been parsed. The returned promise is rejected if any parsed values are * not meeting the validation constraints of their respective elements. */ - parse: function() { - var section_ids = this.cfgsections(), - tasks = []; + parse() { + const section_ids = this.cfgsections(); + const tasks = []; if (Array.isArray(this.children)) - for (var i = 0; i < section_ids.length; i++) - for (var j = 0; j < this.children.length; j++) + for (let i = 0; i < section_ids.length; i++) + for (let j = 0; j < this.children.length; j++) tasks.push(this.children[j].parse(section_ids[i])); return Promise.all(tasks); @@ -4609,22 +4615,22 @@ var CBIAbstractSection = CBIAbstractElement.extend(/** @lends LuCI.form.Abstract * @throws {Error} * Throws an exception if a tab with the same `name` already exists. */ - tab: function(name, title, description) { + tab(name, title, description) { if (this.tabs && this.tabs[name]) throw 'Tab already declared'; - var entry = { - name: name, - title: title, - description: description, + const entry = { + name, + title, + description, children: [] }; - this.tabs = this.tabs || []; + this.tabs ??= []; this.tabs.push(entry); this.tabs[name] = entry; - this.tab_names = this.tab_names || []; + this.tab_names ??= []; this.tab_names.push(name); }, @@ -4652,11 +4658,11 @@ var CBIAbstractSection = CBIAbstractElement.extend(/** @lends LuCI.form.Abstract * @returns {LuCI.form.AbstractValue} * Returns the instantiated option class instance. */ - option: function(cbiClass /*, ... */) { + option(cbiClass, ...args) { if (!CBIAbstractValue.isSubclass(cbiClass)) throw L.error('TypeError', 'Class must be a descendant of CBIAbstractValue'); - var obj = cbiClass.instantiate(this.varargs(arguments, 1, this.map, this)); + const obj = cbiClass.instantiate([ this.map, this, ...args ]); this.append(obj); return obj; }, @@ -4689,13 +4695,14 @@ var CBIAbstractSection = CBIAbstractElement.extend(/** @lends LuCI.form.Abstract * @returns {LuCI.form.AbstractValue} * Returns the instantiated option class instance. */ - taboption: function(tabName /*, ... */) { - if (!this.tabs || !this.tabs[tabName]) + taboption(tabName, ...args) { + if (!this.tabs?.[tabName]) throw L.error('ReferenceError', 'Associated tab not declared'); - var obj = this.option.apply(this, this.varargs(arguments, 1)); + const obj = this.option(...args); obj.tab = tabName; this.tabs[tabName].children.push(obj); + return obj; }, @@ -4720,10 +4727,10 @@ var CBIAbstractSection = CBIAbstractElement.extend(/** @lends LuCI.form.Abstract * configuration values or just a single configuration value, depending * on the amount of passed arguments. */ - cfgvalue: function(section_id, option) { - var rv = (arguments.length == 1) ? {} : null; + cfgvalue(section_id, option) { + const rv = (arguments.length == 1) ? {} : null; - for (var i = 0, o; (o = this.children[i]) != null; i++) + for (let i = 0, o; (o = this.children[i]) != null; i++) if (rv) rv[o.option] = o.cfgvalue(section_id); else if (o.option == option) @@ -4753,11 +4760,11 @@ var CBIAbstractSection = CBIAbstractElement.extend(/** @lends LuCI.form.Abstract * widget input values or just a single widget input value, depending * on the amount of passed arguments. */ - formvalue: function(section_id, option) { - var rv = (arguments.length == 1) ? {} : null; + formvalue(section_id, option) { + const rv = (arguments.length == 1) ? {} : null; - for (var i = 0, o; (o = this.children[i]) != null; i++) { - var func = this.map.root ? this.children[i].formvalue : this.children[i].cfgvalue; + for (let i = 0, o; (o = this.children[i]) != null; i++) { + const func = this.map.root ? this.children[i].formvalue : this.children[i].cfgvalue; if (rv) rv[o.option] = func.call(o, section_id); @@ -4789,10 +4796,10 @@ var CBIAbstractSection = CBIAbstractElement.extend(/** @lends LuCI.form.Abstract * widget input values or just a single widget input value, depending * on the amount of passed arguments. */ - getUIElement: function(section_id, option) { - var rv = (arguments.length == 1) ? {} : null; + getUIElement(section_id, option) { + const rv = (arguments.length == 1) ? {} : null; - for (var i = 0, o; (o = this.children[i]) != null; i++) + for (let i = 0, o; (o = this.children[i]) != null; i++) if (rv) rv[o.option] = o.getUIElement(section_id); else if (o.option == option) @@ -4819,10 +4826,10 @@ var CBIAbstractSection = CBIAbstractElement.extend(/** @lends LuCI.form.Abstract * option instance objects or just a single object instance value, * depending on the amount of passed arguments. */ - getOption: function(option) { - var rv = (arguments.length == 0) ? {} : null; + getOption(option) { + const rv = (arguments.length == 0) ? {} : null; - for (var i = 0, o; (o = this.children[i]) != null; i++) + for (let i = 0, o; (o = this.children[i]) != null; i++) if (rv) rv[o.option] = o; else if (o.option == option) @@ -4832,13 +4839,13 @@ var CBIAbstractSection = CBIAbstractElement.extend(/** @lends LuCI.form.Abstract }, /** @private */ - renderUCISection: function(section_id) { - var renderTasks = []; + renderUCISection(section_id) { + const renderTasks = []; if (!this.tabs) return this.renderOptions(null, section_id); - for (var i = 0; i < this.tab_names.length; i++) + for (let i = 0; i < this.tab_names.length; i++) renderTasks.push(this.renderOptions(this.tab_names[i], section_id)); return Promise.all(renderTasks) @@ -4846,19 +4853,19 @@ var CBIAbstractSection = CBIAbstractElement.extend(/** @lends LuCI.form.Abstract }, /** @private */ - renderTabContainers: function(section_id, nodes) { - var config_name = this.uciconfig || this.map.config, - containerEls = E([]); - - for (var i = 0; i < nodes.length; i++) { - var tab_name = this.tab_names[i], - tab_data = this.tabs[tab_name], - containerEl = E('div', { - 'id': 'container.%s.%s.%s'.format(config_name, section_id, tab_name), - 'data-tab': tab_name, - 'data-tab-title': tab_data.title, - 'data-tab-active': tab_name === this.selected_tab - }); + renderTabContainers(section_id, nodes) { + const config_name = this.uciconfig ?? this.map.config; + const containerEls = E([]); + + for (let i = 0; i < nodes.length; i++) { + const tab_name = this.tab_names[i]; + const tab_data = this.tabs[tab_name]; + const containerEl = E('div', { + 'id': 'container.%s.%s.%s'.format(config_name, section_id, tab_name), + 'data-tab': tab_name, + 'data-tab-title': tab_data.title, + 'data-tab-active': tab_name === this.selected_tab + }); if (tab_data.description != null && tab_data.description != '') containerEl.appendChild( @@ -4872,25 +4879,25 @@ var CBIAbstractSection = CBIAbstractElement.extend(/** @lends LuCI.form.Abstract }, /** @private */ - renderOptions: function(tab_name, section_id) { - var in_table = (this instanceof CBITableSection); - return this.renderChildren(tab_name, section_id, in_table).then(function(nodes) { - var optionEls = E([]); - for (var i = 0; i < nodes.length; i++) + renderOptions(tab_name, section_id) { + const in_table = (this instanceof CBITableSection); + return this.renderChildren(tab_name, section_id, in_table).then((nodes) => { + const optionEls = E([]); + for (let i = 0; i < nodes.length; i++) optionEls.appendChild(nodes[i]); return optionEls; }); }, /** @private */ - checkDepends: function(ev, n) { - var changed = false, - sids = this.cfgsections(); + checkDepends(ev, n) { + let changed = false; + const sids = this.cfgsections(); - for (var i = 0, sid = sids[0]; (sid = sids[i]) != null; i++) { - for (var j = 0, o = this.children[0]; (o = this.children[j]) != null; j++) { - var isActive = o.isActive(sid), - isSatisified = o.checkDepends(sid); + for (let i = 0, sid = sids[0]; (sid = sids[i]) != null; i++) { + for (let j = 0, o = this.children[0]; (o = this.children[j]) != null; j++) { + let isActive = o.isActive(sid); + const isSatisified = o.checkDepends(sid); if (isActive != isSatisified) { o.setActive(sid, !isActive); @@ -4908,7 +4915,7 @@ var CBIAbstractSection = CBIAbstractElement.extend(/** @lends LuCI.form.Abstract }); -var isEqual = function(x, y) { +function isEqual(x, y) { if (typeof(y) == 'object' && y instanceof RegExp) return (x == null) ? false : y.test(x); @@ -4922,12 +4929,12 @@ var isEqual = function(x, y) { if (x.length != y.length) return false; - for (var i = 0; i < x.length; i++) + for (let i = 0; i < x.length; i++) if (!isEqual(x[i], y[i])) return false; } else if (typeof(x) == 'object') { - for (var k in x) { + for (const k in x) { if (x.hasOwnProperty(k) && !y.hasOwnProperty(k)) return false; @@ -4935,7 +4942,7 @@ var isEqual = function(x, y) { return false; } - for (var k in y) + for (const k in y) if (y.hasOwnProperty(k) && !x.hasOwnProperty(k)) return false; } @@ -4946,9 +4953,9 @@ var isEqual = function(x, y) { return true; }; -var isContained = function(x, y) { +function isContained(x, y) { if (Array.isArray(x)) { - for (var i = 0; i < x.length; i++) + for (let i = 0; i < x.length; i++) if (x[i] == y) return true; } @@ -4977,9 +4984,9 @@ var isContained = function(x, y) { * * This class is private and not directly accessible by user code. */ -var CBIAbstractValue = CBIAbstractElement.extend(/** @lends LuCI.form.AbstractValue.prototype */ { - __init__: function(map, section, option /*, ... */) { - this.super('__init__', this.varargs(arguments, 3)); +const CBIAbstractValue = CBIAbstractElement.extend(/** @lends LuCI.form.AbstractValue.prototype */ { + __init__(map, section, option, ...args) { + this.super('__init__', args); this.section = section; this.option = option; @@ -5206,20 +5213,20 @@ var CBIAbstractValue = CBIAbstractElement.extend(/** @lends LuCI.form.AbstractVa * * <ul> * <li> - * <code>!reverse</code><br> - * Invert the dependency, instead of requiring another option to be - * equal to the dependency value, that option should <em>not</em> be - * equal. + * <code>!reverse</code><br> + * Invert the dependency, instead of requiring another option to be + * equal to the dependency value, that option should <em>not</em> be + * equal. * </li> * <li> - * <code>!contains</code><br> - * Instead of requiring an exact match, the dependency is considered - * satisfied when the dependency value is contained within the option - * value. + * <code>!contains</code><br> + * Instead of requiring an exact match, the dependency is considered + * satisfied when the dependency value is contained within the option + * value. * </li> * <li> - * <code>!default</code><br> - * The dependency is always satisfied + * <code>!default</code><br> + * The dependency is always satisfied * </li> * </ul> * @@ -5245,7 +5252,7 @@ var CBIAbstractValue = CBIAbstractElement.extend(/** @lends LuCI.form.AbstractVa * </li> * <li> * <code>opt.depends({ foo: "test" })<br> - * opt.depends({ bar: "qrx" })</code><br> + * opt.depends({ bar: "qrx" })</code><br> * Require either <code>foo</code> to be set to <code>test</code>, * <em>or</em> the <code>bar</code> option to be <code>qrx</code>. * </li> @@ -5269,8 +5276,8 @@ var CBIAbstractValue = CBIAbstractElement.extend(/** @lends LuCI.form.AbstractVa * specifies the expected value. In case an object is passed as first * argument, this parameter is ignored. */ - depends: function(field, value) { - var deps; + depends(field, value) { + let deps; if (typeof(field) === 'string') deps = {}, deps[field] = value; @@ -5281,15 +5288,15 @@ var CBIAbstractValue = CBIAbstractElement.extend(/** @lends LuCI.form.AbstractVa }, /** @private */ - transformDepList: function(section_id, deplist) { - var list = deplist || this.deps, - deps = []; + transformDepList(section_id, deplist) { + const list = deplist ?? this.deps; + const deps = []; if (Array.isArray(list)) { - for (var i = 0; i < list.length; i++) { - var dep = {}; + for (let i = 0; i < list.length; i++) { + const dep = {}; - for (var k in list[i]) { + for (const k in list[i]) { if (list[i].hasOwnProperty(k)) { if (k.charAt(0) === '!') dep[k] = list[i][k]; @@ -5297,14 +5304,14 @@ var CBIAbstractValue = CBIAbstractElement.extend(/** @lends LuCI.form.AbstractVa dep['cbid.%s'.format(k)] = list[i][k]; else dep['cbid.%s.%s.%s'.format( - this.uciconfig || this.section.uciconfig || this.map.config, - this.ucisection || section_id, + this.uciconfig ?? this.section.uciconfig ?? this.map.config, + this.ucisection ?? section_id, k )] = list[i][k]; } } - for (var k in dep) { + for (const k in dep) { if (dep.hasOwnProperty(k)) { deps.push(dep); break; @@ -5317,22 +5324,22 @@ var CBIAbstractValue = CBIAbstractElement.extend(/** @lends LuCI.form.AbstractVa }, /** @private */ - transformChoices: function() { + transformChoices() { if (!Array.isArray(this.keylist) || this.keylist.length == 0) return null; - var choices = {}; + const choices = {}; - for (var i = 0; i < this.keylist.length; i++) + for (let i = 0; i < this.keylist.length; i++) choices[this.keylist[i]] = this.vallist[i]; return choices; }, /** @private */ - checkDepends: function(section_id) { - var config_name = this.uciconfig || this.section.uciconfig || this.map.config, - active = this.map.isDependencySatisfied(this.deps, config_name, section_id); + checkDepends(section_id) { + const config_name = this.uciconfig ?? this.section.uciconfig ?? this.map.config; + const active = this.map.isDependencySatisfied(this.deps, config_name, section_id); if (active) this.updateDefaultValue(section_id); @@ -5341,15 +5348,16 @@ var CBIAbstractValue = CBIAbstractElement.extend(/** @lends LuCI.form.AbstractVa }, /** @private */ - updateDefaultValue: function(section_id) { + updateDefaultValue(section_id) { if (!L.isObject(this.defaults)) return; - var config_name = this.uciconfig || this.section.uciconfig || this.map.config, - cfgvalue = L.toArray(this.cfgvalue(section_id))[0], - default_defval = null, satisified_defval = null; + const config_name = this.uciconfig ?? this.section.uciconfig ?? this.map.config; + const cfgvalue = L.toArray(this.cfgvalue(section_id))[0]; + let default_defval = null; + let satisified_defval = null; - for (var value in this.defaults) { + for (const value in this.defaults) { if (!this.defaults[value] || this.defaults[value].length == 0) { default_defval = value; continue; @@ -5363,7 +5371,7 @@ var CBIAbstractValue = CBIAbstractElement.extend(/** @lends LuCI.form.AbstractVa if (satisified_defval == null) satisified_defval = default_defval; - var node = this.map.findElement('id', this.cbid(section_id)); + const node = this.map.findElement('id', this.cbid(section_id)); if (node && node.getAttribute('data-changed') != 'true' && satisified_defval != null && cfgvalue == null) dom.callClassMethod(node, 'setValue', satisified_defval); @@ -5387,12 +5395,12 @@ var CBIAbstractValue = CBIAbstractElement.extend(/** @lends LuCI.form.AbstractVa * @returns {string} * Returns the element ID. */ - cbid: function(section_id) { + cbid(section_id) { if (section_id == null) L.error('TypeError', 'Section ID required'); return 'cbid.%s.%s.%s'.format( - this.uciconfig || this.section.uciconfig || this.map.config, + this.uciconfig ?? this.section.uciconfig ?? this.map.config, section_id, this.option); }, @@ -5415,14 +5423,14 @@ var CBIAbstractValue = CBIAbstractElement.extend(/** @lends LuCI.form.AbstractVa * The return value of this function is filtered through `Promise.resolve()` * so it may return promises if overridden by user code. */ - load: function(section_id) { + load(section_id) { if (section_id == null) L.error('TypeError', 'Section ID required'); return this.map.data.get( - this.uciconfig || this.section.uciconfig || this.map.config, - this.ucisection || section_id, - this.ucioption || this.option); + this.uciconfig ?? this.section.uciconfig ?? this.map.config, + this.ucisection ?? section_id, + this.ucioption ?? this.option); }, /** @@ -5438,9 +5446,9 @@ var CBIAbstractValue = CBIAbstractElement.extend(/** @lends LuCI.form.AbstractVa * Returns the `LuCI.ui` element instance or `null` in case the form * option implementation does not use `LuCI.ui` widgets. */ - getUIElement: function(section_id) { - var node = this.map.findElement('id', this.cbid(section_id)), - inst = node ? dom.findClassInstance(node) : null; + getUIElement(section_id) { + const node = this.map.findElement('id', this.cbid(section_id)); + const inst = node ? dom.findClassInstance(node) : null; return (inst instanceof ui.AbstractElement) ? inst : null; }, @@ -5461,16 +5469,16 @@ var CBIAbstractValue = CBIAbstractElement.extend(/** @lends LuCI.form.AbstractVa * @returns {*} * Returns the configuration value. */ - cfgvalue: function(section_id, set_value) { + cfgvalue(section_id, set_value) { if (section_id == null) L.error('TypeError', 'Section ID required'); if (arguments.length == 2) { - this.data = this.data || {}; + this.data ??= {}; this.data[section_id] = set_value; } - return this.data ? this.data[section_id] : null; + return this.data?.[section_id]; }, /** @@ -5489,8 +5497,8 @@ var CBIAbstractValue = CBIAbstractElement.extend(/** @lends LuCI.form.AbstractVa * @returns {*} * Returns the current input value. */ - formvalue: function(section_id) { - var elem = this.getUIElement(section_id); + formvalue(section_id) { + const elem = this.getUIElement(section_id); return elem ? elem.getValue() : null; }, @@ -5513,8 +5521,8 @@ var CBIAbstractValue = CBIAbstractElement.extend(/** @lends LuCI.form.AbstractVa * @returns {string} * Returns the text representation of the current input value. */ - textvalue: function(section_id) { - var cval = this.cfgvalue(section_id); + textvalue(section_id) { + let cval = this.cfgvalue(section_id); if (cval == null) cval = this.default; @@ -5548,7 +5556,7 @@ var CBIAbstractValue = CBIAbstractElement.extend(/** @lends LuCI.form.AbstractVa * return value is treated as failure, converted to a string and displayed * as error message to the user. */ - validate: function(section_id, value) { + validate(section_id, value) { return true; }, @@ -5562,8 +5570,8 @@ var CBIAbstractValue = CBIAbstractElement.extend(/** @lends LuCI.form.AbstractVa * Returns `true` if the input value currently is valid, otherwise it * returns `false`. */ - isValid: function(section_id) { - var elem = this.getUIElement(section_id); + isValid(section_id) { + const elem = this.getUIElement(section_id); return elem ? elem.isValid() : true; }, @@ -5576,8 +5584,8 @@ var CBIAbstractValue = CBIAbstractElement.extend(/** @lends LuCI.form.AbstractVa * @returns {string} * The validation error at this time */ - getValidationError: function (section_id) { - var elem = this.getUIElement(section_id); + getValidationError(section_id) { + const elem = this.getUIElement(section_id); return elem ? elem.getValidationError() : ''; }, @@ -5594,14 +5602,14 @@ var CBIAbstractValue = CBIAbstractElement.extend(/** @lends LuCI.form.AbstractVa * Returns `true` if the option element currently is active, otherwise it * returns `false`. */ - isActive: function(section_id) { - var field = this.map.findElement('data-field', this.cbid(section_id)); + isActive(section_id) { + const field = this.map.findElement('data-field', this.cbid(section_id)); return (field != null && !field.classList.contains('hidden')); }, /** @private */ - setActive: function(section_id, active) { - var field = this.map.findElement('data-field', this.cbid(section_id)); + setActive(section_id, active) { + const field = this.map.findElement('data-field', this.cbid(section_id)); if (field && field.classList.contains('hidden') == active) { field.classList[active ? 'remove' : 'add']('hidden'); @@ -5616,8 +5624,8 @@ var CBIAbstractValue = CBIAbstractElement.extend(/** @lends LuCI.form.AbstractVa }, /** @private */ - triggerValidation: function(section_id) { - var elem = this.getUIElement(section_id); + triggerValidation(section_id) { + const elem = this.getUIElement(section_id); return elem ? elem.triggerValidation() : true; }, @@ -5635,27 +5643,27 @@ var CBIAbstractValue = CBIAbstractElement.extend(/** @lends LuCI.form.AbstractVa * validated or rejecting in case the input value does not meet the * validation constraints. */ - parse: function(section_id) { - var active = this.isActive(section_id); + parse(section_id) { + const active = this.isActive(section_id); if (active && !this.isValid(section_id)) { - var title = this.stripTags(this.title).trim(), - error = this.getValidationError(section_id); + const title = this.stripTags(this.title).trim(); + const error = this.getValidationError(section_id); return Promise.reject(new TypeError( - _('Option "%s" contains an invalid input value.').format(title || this.option) + ' ' + error)); + `${_('Option "%s" contains an invalid input value.').format(title || this.option)} ${error}`)); } if (active) { - var cval = this.cfgvalue(section_id), - fval = this.formvalue(section_id); + const cval = this.cfgvalue(section_id); + const fval = this.formvalue(section_id); if (fval == null || fval == '') { if (this.rmempty || this.optional) { return Promise.resolve(this.remove(section_id)); } else { - var title = this.stripTags(this.title).trim(); + const title = this.stripTags(this.title).trim(); return Promise.reject(new TypeError( _('Option "%s" must not be empty.').format(title || this.option))); @@ -5692,11 +5700,11 @@ var CBIAbstractValue = CBIAbstractElement.extend(/** @lends LuCI.form.AbstractVa * @param {string|string[]} formvalue * The input value to write. */ - write: function(section_id, formvalue) { + write(section_id, formvalue) { return this.map.data.set( - this.uciconfig || this.section.uciconfig || this.map.config, - this.ucisection || section_id, - this.ucioption || this.option, + this.uciconfig ?? this.section.uciconfig ?? this.map.config, + this.ucisection ?? section_id, + this.ucioption ?? this.option, formvalue); }, @@ -5715,20 +5723,20 @@ var CBIAbstractValue = CBIAbstractElement.extend(/** @lends LuCI.form.AbstractVa * @param {string} section_id * The configuration section ID */ - remove: function(section_id) { - var this_cfg = this.uciconfig || this.section.uciconfig || this.map.config, - this_sid = this.ucisection || section_id, - this_opt = this.ucioption || this.option; + remove(section_id) { + const this_cfg = this.uciconfig ?? this.section.uciconfig ?? this.map.config; + const this_sid = this.ucisection ?? section_id; + const this_opt = this.ucioption ?? this.option; - for (var i = 0; i < this.section.children.length; i++) { - var sibling = this.section.children[i]; + for (let i = 0; i < this.section.children.length; i++) { + const sibling = this.section.children[i]; if (sibling === this || sibling.ucioption == null) continue; - var sibling_cfg = sibling.uciconfig || sibling.section.uciconfig || sibling.map.config, - sibling_sid = sibling.ucisection || section_id, - sibling_opt = sibling.ucioption || sibling.option; + const sibling_cfg = sibling.uciconfig ?? sibling.section.uciconfig ?? sibling.map.config; + const sibling_sid = sibling.ucisection ?? section_id; + const sibling_opt = sibling.ucioption ?? sibling.option; if (this_cfg != sibling_cfg || this_sid != sibling_sid || this_opt != sibling_opt) continue; @@ -5774,7 +5782,7 @@ var CBIAbstractValue = CBIAbstractElement.extend(/** @lends LuCI.form.AbstractVa * @param {string} [description] * The description text of the form section element. */ -var CBITypedSection = CBIAbstractSection.extend(/** @lends LuCI.form.TypedSection.prototype */ { +const CBITypedSection = CBIAbstractSection.extend(/** @lends LuCI.form.TypedSection.prototype */ { __name__: 'CBI.TypedSection', /** @@ -5833,36 +5841,36 @@ var CBITypedSection = CBIAbstractSection.extend(/** @lends LuCI.form.TypedSectio */ /** @override */ - cfgsections: function() { - return this.map.data.sections(this.uciconfig || this.map.config, this.sectiontype) - .map(function(s) { return s['.name'] }) + cfgsections() { + return this.map.data.sections(this.uciconfig ?? this.map.config, this.sectiontype) + .map((s) => { return s['.name'] }) .filter(L.bind(this.filter, this)); }, /** @private */ - handleAdd: function(ev, name) { - var config_name = this.uciconfig || this.map.config; + handleAdd(ev, name) { + const config_name = this.uciconfig ?? this.map.config; this.map.data.add(config_name, this.sectiontype, name); return this.map.save(null, true); }, /** @private */ - handleRemove: function(section_id, ev) { - var config_name = this.uciconfig || this.map.config; + handleRemove(section_id, ev) { + const config_name = this.uciconfig ?? this.map.config; this.map.data.remove(config_name, section_id); return this.map.save(null, true); }, /** @private */ - renderSectionAdd: function(extra_class) { + renderSectionAdd(extra_class) { if (!this.addremove) return E([]); - var createEl = E('div', { 'class': 'cbi-section-create' }), - config_name = this.uciconfig || this.map.config, - btn_title = this.titleFn('addbtntitle'); + const createEl = E('div', { 'class': 'cbi-section-create' }); + const config_name = this.uciconfig ?? this.map.config; + const btn_title = this.titleFn('addbtntitle'); if (extra_class != null) createEl.classList.add(extra_class); @@ -5870,13 +5878,13 @@ var CBITypedSection = CBIAbstractSection.extend(/** @lends LuCI.form.TypedSectio if (this.anonymous) { createEl.appendChild(E('button', { 'class': 'cbi-button cbi-button-add', - 'title': btn_title || _('Add'), + 'title': btn_title ?? _('Add'), 'click': ui.createHandlerFn(this, 'handleAdd'), 'disabled': this.map.readonly || null - }, [ btn_title || _('Add') ])); + }, [ btn_title ?? _('Add') ])); } else { - var nameEl = E('input', { + const nameEl = E('input', { 'type': 'text', 'class': 'cbi-section-create-name', 'disabled': this.map.readonly || null @@ -5886,20 +5894,20 @@ var CBITypedSection = CBIAbstractSection.extend(/** @lends LuCI.form.TypedSectio E('div', {}, nameEl), E('button', { 'class': 'cbi-button cbi-button-add', - 'title': btn_title || _('Add'), - 'click': ui.createHandlerFn(this, function(ev) { + 'title': btn_title ?? _('Add'), + 'click': ui.createHandlerFn(this, (ev) => { if (nameEl.classList.contains('cbi-input-invalid')) return; return this.handleAdd(ev, nameEl.value); }), 'disabled': this.map.readonly || true - }, [ btn_title || _('Add') ]) + }, [ btn_title ?? _('Add') ]) ]); if (this.map.readonly !== true) { - ui.addValidator(nameEl, 'uciname', true, function(v) { - var button = createEl.querySelector('.cbi-section-create > .cbi-button-add'); + ui.addValidator(nameEl, 'uciname', true, (v) => { + const button = createEl.querySelector('.cbi-section-create > .cbi-button-add'); if (v !== '') { button.disabled = null; return true; @@ -5916,20 +5924,21 @@ var CBITypedSection = CBIAbstractSection.extend(/** @lends LuCI.form.TypedSectio }, /** @private */ - renderSectionPlaceholder: function() { + renderSectionPlaceholder() { return E('em', _('This section contains no values yet')); }, /** @private */ - renderContents: function(cfgsections, nodes) { - var section_id = null, - config_name = this.uciconfig || this.map.config, - sectionEl = E('div', { - 'id': 'cbi-%s-%s'.format(config_name, this.sectiontype), - 'class': 'cbi-section', - 'data-tab': (this.map.tabbed && !this.parentoption) ? this.sectiontype : null, - 'data-tab-title': (this.map.tabbed && !this.parentoption) ? this.title || this.sectiontype : null - }); + renderContents(cfgsections, nodes) { + const section_id = null; + const config_name = this.uciconfig ?? this.map.config; + + const sectionEl = E('div', { + 'id': 'cbi-%s-%s'.format(config_name, this.sectiontype), + 'class': 'cbi-section', + 'data-tab': (this.map.tabbed && !this.parentoption) ? this.sectiontype : null, + 'data-tab-title': (this.map.tabbed && !this.parentoption) ? this.title || this.sectiontype : null + }); if (this.title != null && this.title != '') sectionEl.appendChild(E('h3', {}, this.title)); @@ -5937,7 +5946,7 @@ var CBITypedSection = CBIAbstractSection.extend(/** @lends LuCI.form.TypedSectio if (this.description != null && this.description != '') sectionEl.appendChild(E('div', { 'class': 'cbi-section-descr' }, this.description)); - for (var i = 0; i < nodes.length; i++) { + for (let i = 0; i < nodes.length; i++) { if (this.addremove) { sectionEl.appendChild( E('div', { 'class': 'cbi-section-remove right' }, @@ -5972,11 +5981,11 @@ var CBITypedSection = CBIAbstractSection.extend(/** @lends LuCI.form.TypedSectio }, /** @override */ - render: function() { - var cfgsections = this.cfgsections(), - renderTasks = []; + render() { + const cfgsections = this.cfgsections(); + const renderTasks = []; - for (var i = 0; i < cfgsections.length; i++) + for (let i = 0; i < cfgsections.length; i++) renderTasks.push(this.renderUCISection(cfgsections[i])); return Promise.all(renderTasks).then(this.renderContents.bind(this, cfgsections)); @@ -6012,7 +6021,7 @@ var CBITypedSection = CBIAbstractSection.extend(/** @lends LuCI.form.TypedSectio * @param {string} [description] * The description text of the form section element. */ -var CBITableSection = CBITypedSection.extend(/** @lends LuCI.form.TableSection.prototype */ { +const CBITableSection = CBITypedSection.extend(/** @lends LuCI.form.TableSection.prototype */ { __name__: 'CBI.TableSection', /** @@ -6123,7 +6132,7 @@ var CBITableSection = CBITypedSection.extend(/** @lends LuCI.form.TableSection.p * @override * @throws Throws an exception when invoked. */ - tab: function() { + tab() { throw 'Tabs are not supported by TableSection'; }, @@ -6133,7 +6142,7 @@ var CBITableSection = CBITypedSection.extend(/** @lends LuCI.form.TableSection.p * is true. Optionally supply a name for the new section_id. */ /** @private */ - handleClone: function(section_id, put_next, name) { + handleClone(section_id, put_next, name) { let config_name = this.uciconfig || this.map.config; this.map.data.clone(config_name, this.sectiontype, section_id, put_next, name); @@ -6141,23 +6150,25 @@ var CBITableSection = CBITypedSection.extend(/** @lends LuCI.form.TableSection.p }, /** @private */ - renderContents: function(cfgsections, nodes) { - var section_id = null, - config_name = this.uciconfig || this.map.config, - max_cols = isNaN(this.max_cols) ? this.children.length : this.max_cols, - cloneable = this.cloneable, - has_more = max_cols < this.children.length, - drag_sort = this.sortable && !('ontouchstart' in window), - touch_sort = this.sortable && ('ontouchstart' in window), - sectionEl = E('div', { - 'id': 'cbi-%s-%s'.format(config_name, this.sectiontype), - 'class': 'cbi-section cbi-tblsection', - 'data-tab': (this.map.tabbed && !this.parentoption) ? this.sectiontype : null, - 'data-tab-title': (this.map.tabbed && !this.parentoption) ? this.title || this.sectiontype : null - }), - tableEl = E('table', { - 'class': 'table cbi-section-table' - }); + renderContents(cfgsections, nodes) { + const section_id = null; + const config_name = this.uciconfig ?? this.map.config; + const max_cols = this.max_cols ?? this.children.length; + const cloneable = this.cloneable; + const has_more = max_cols < this.children.length; + const drag_sort = this.sortable && !('ontouchstart' in window); + const touch_sort = this.sortable && ('ontouchstart' in window); + + const sectionEl = E('div', { + 'id': 'cbi-%s-%s'.format(config_name, this.sectiontype), + 'class': 'cbi-section cbi-tblsection', + 'data-tab': (this.map.tabbed && !this.parentoption) ? this.sectiontype : null, + 'data-tab-title': (this.map.tabbed && !this.parentoption) ? this.title || this.sectiontype : null + }); + + const tableEl = E('table', { + 'class': 'table cbi-section-table' + }); if (this.title != null && this.title != '') sectionEl.appendChild(E('h3', {}, this.title)); @@ -6165,15 +6176,15 @@ var CBITableSection = CBITypedSection.extend(/** @lends LuCI.form.TableSection.p if (this.description != null && this.description != '') sectionEl.appendChild(E('div', { 'class': 'cbi-section-descr' }, this.description)); - tableEl.appendChild(this.renderHeaderRows(max_cols)); + tableEl.appendChild(this.renderHeaderRows(false)); - for (var i = 0; i < nodes.length; i++) { - var sectionname = this.titleFn('sectiontitle', cfgsections[i]); + for (let i = 0; i < nodes.length; i++) { + let sectionname = this.titleFn('sectiontitle', cfgsections[i]); if (sectionname == null) sectionname = cfgsections[i]; - var trEl = E('tr', { + const trEl = E('tr', { 'id': 'cbi-%s-%s'.format(config_name, cfgsections[i]), 'class': 'tr cbi-section-table-row', 'data-sid': cfgsections[i], @@ -6195,7 +6206,7 @@ var CBITableSection = CBITypedSection.extend(/** @lends LuCI.form.TableSection.p trEl.classList.add(!(tableEl.childNodes.length % 2) ? 'cbi-rowstyle-1' : 'cbi-rowstyle-2'); - for (var j = 0; j < max_cols && nodes[i].firstChild; j++) + for (let j = 0; j < max_cols && nodes[i].firstChild; j++) trEl.appendChild(nodes[i].firstChild); trEl.appendChild(this.renderRowActions(cfgsections[i], has_more ? _('More…') : null)); @@ -6216,15 +6227,15 @@ var CBITableSection = CBITypedSection.extend(/** @lends LuCI.form.TableSection.p }, /** @private */ - renderHeaderRows: function(max_cols, has_action) { - var has_titles = false, - has_descriptions = false, - max_cols = isNaN(this.max_cols) ? this.children.length : this.max_cols, - has_more = max_cols < this.children.length, - anon_class = (!this.anonymous || this.sectiontitle) ? 'named' : 'anonymous', - trEls = E([]); - - for (var i = 0, opt; i < max_cols && (opt = this.children[i]) != null; i++) { + renderHeaderRows(has_action) { + let has_titles = false; + let has_descriptions = false; + const max_cols = this.max_cols ?? this.children.length; + const has_more = max_cols < this.children.length; + const anon_class = (!this.anonymous || this.sectiontitle) ? 'named' : 'anonymous'; + const trEls = E([]); + + for (let i = 0, opt; i < max_cols && (opt = this.children[i]) != null; i++) { if (opt.modalonly) continue; @@ -6233,13 +6244,13 @@ var CBITableSection = CBITypedSection.extend(/** @lends LuCI.form.TableSection.p } if (has_titles) { - var trEl = E('tr', { - 'class': 'tr cbi-section-table-titles ' + anon_class, + const trEl = E('tr', { + 'class': `tr cbi-section-table-titles ${anon_class}`, '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++) { + for (let i = 0, opt; i < max_cols && (opt = this.children[i]) != null; i++) { if (opt.modalonly) continue; @@ -6251,13 +6262,13 @@ var CBITableSection = CBITypedSection.extend(/** @lends LuCI.form.TableSection.p if (opt.width != null) trEl.lastElementChild.style.width = - (typeof(opt.width) == 'number') ? opt.width+'px' : opt.width; + (typeof(opt.width) == 'number') ? `${opt.width}px` : opt.width; if (opt.titleref) trEl.lastElementChild.appendChild(E('a', { 'href': opt.titleref, 'class': 'cbi-title-ref', - 'title': this.titledesc || _('Go to relevant configuration page') + 'title': this.titledesc ?? _('Go to relevant configuration page') }, opt.title)); else dom.content(trEl.lastElementChild, opt.title); @@ -6272,11 +6283,11 @@ var CBITableSection = CBITypedSection.extend(/** @lends LuCI.form.TableSection.p } if (has_descriptions && !this.nodescriptions) { - var trEl = E('tr', { - 'class': 'tr cbi-section-table-descr ' + anon_class + const trEl = E('tr', { + 'class': `tr cbi-section-table-descr ${anon_class}` }); - for (var i = 0, opt; i < max_cols && (opt = this.children[i]) != null; i++) { + for (let i = 0, opt; i < max_cols && (opt = this.children[i]) != null; i++) { if (opt.modalonly) continue; @@ -6287,7 +6298,7 @@ var CBITableSection = CBITypedSection.extend(/** @lends LuCI.form.TableSection.p if (opt.width != null) trEl.lastElementChild.style.width = - (typeof(opt.width) == 'number') ? opt.width+'px' : opt.width; + (typeof(opt.width) == 'number') ? `${opt.width}px` : opt.width; } if (this.sortable || this.extedit || this.addremove || has_more || has_action || this.cloneable) @@ -6302,13 +6313,13 @@ var CBITableSection = CBITypedSection.extend(/** @lends LuCI.form.TableSection.p }, /** @private */ - renderRowActions: function(section_id, more_label) { - var config_name = this.uciconfig || this.map.config; + renderRowActions(section_id, more_label) { + const config_name = this.uciconfig ?? this.map.config; if (!this.sortable && !this.extedit && !this.addremove && !more_label && !this.cloneable) return E([]); - var tdEl = E('td', { + const tdEl = E('td', { 'class': 'td cbi-section-table-cell nowrap cbi-section-actions' }, E('div')); @@ -6324,12 +6335,12 @@ var CBITableSection = CBITypedSection.extend(/** @lends LuCI.form.TableSection.p } if (this.extedit) { - var evFn = null; + let evFn = null; if (typeof(this.extedit) == 'function') evFn = L.bind(this.extedit, this); else if (typeof(this.extedit) == 'string') - evFn = L.bind(function(sid, ev) { + evFn = L.bind((sid, ev) => { location.href = this.extedit.format(sid); }, this, section_id); @@ -6353,7 +6364,7 @@ var CBITableSection = CBITypedSection.extend(/** @lends LuCI.form.TableSection.p } if (this.cloneable) { - var btn_title = this.titleFn('clonebtntitle', section_id); + const btn_title = this.titleFn('clonebtntitle', section_id); dom.append(tdEl.lastElementChild, E('button', { @@ -6366,15 +6377,15 @@ var CBITableSection = CBITypedSection.extend(/** @lends LuCI.form.TableSection.p } if (this.addremove) { - var btn_title = this.titleFn('removebtntitle', section_id); + const btn_title = this.titleFn('removebtntitle', section_id); dom.append(tdEl.lastElementChild, E('button', { - 'title': btn_title || _('Delete'), + 'title': btn_title ?? _('Delete'), 'class': 'btn cbi-button cbi-button-remove', 'click': ui.createHandlerFn(this, 'handleRemove', section_id), 'disabled': this.map.readonly || null - }, [ btn_title || _('Delete') ]) + }, [ btn_title ?? _('Delete') ]) ); } @@ -6382,13 +6393,13 @@ var CBITableSection = CBITypedSection.extend(/** @lends LuCI.form.TableSection.p }, /** @private */ - handleDragInit: function(ev) { + handleDragInit(ev) { scope.dragState = { node: ev.target }; }, /** @private */ - handleDragStart: function(ev) { - if (!scope.dragState || !scope.dragState.node.classList.contains('drag-handle')) { + handleDragStart(ev) { + if (!scope.dragState?.node.classList.contains('drag-handle')) { scope.dragState = null; return false; } @@ -6399,11 +6410,11 @@ var CBITableSection = CBITypedSection.extend(/** @lends LuCI.form.TableSection.p }, /** @private */ - handleDragOver: function(ev) { + handleDragOver(ev) { if (scope.dragState === null ) return; - var n = scope.dragState.targetNode, - r = scope.dragState.rect, - t = r.top + r.height / 2; + const n = scope.dragState.targetNode; + const r = scope.dragState.rect; + const t = r.top + r.height / 2; if (ev.clientY <= t) { n.classList.remove('drag-over-below'); @@ -6420,51 +6431,51 @@ var CBITableSection = CBITypedSection.extend(/** @lends LuCI.form.TableSection.p }, /** @private */ - handleDragEnter: function(ev) { + handleDragEnter(ev) { if (scope.dragState === null ) return; scope.dragState.rect = ev.currentTarget.getBoundingClientRect(); scope.dragState.targetNode = ev.currentTarget; }, /** @private */ - handleDragLeave: function(ev) { + handleDragLeave(ev) { ev.currentTarget.classList.remove('drag-over-above'); ev.currentTarget.classList.remove('drag-over-below'); }, /** @private */ - handleDragEnd: function(ev) { - var n = ev.target; + handleDragEnd(ev) { + const n = ev.target; n.style.opacity = ''; n.classList.add('flash'); n.parentNode.querySelectorAll('.drag-over-above, .drag-over-below') - .forEach(function(tr) { + .forEach((tr) => { tr.classList.remove('drag-over-above'); tr.classList.remove('drag-over-below'); }); }, /** @private */ - handleDrop: function(ev) { - if (scope.dragState === null ) return; - var s = scope.dragState; + handleDrop(ev) { + const s = scope.dragState; + if (!s) return; if (s.node && s.targetNode) { - var config_name = this.uciconfig || this.map.config, - ref_node = s.targetNode, - after = false; + const config_name = this.uciconfig ?? this.map.config; + let ref_node = s.targetNode; + let after = false; - if (ref_node.classList.contains('drag-over-below')) { - ref_node = ref_node.nextElementSibling; - after = true; - } + if (ref_node.classList.contains('drag-over-below')) { + ref_node = ref_node.nextElementSibling; + after = true; + } - var sid1 = s.node.getAttribute('data-sid'), - sid2 = s.targetNode.getAttribute('data-sid'); + const sid1 = s.node.getAttribute('data-sid'); + const sid2 = s.targetNode.getAttribute('data-sid'); - s.node.parentNode.insertBefore(s.node, ref_node); - this.map.data.move(config_name, sid1, sid2, after); + s.node.parentNode.insertBefore(s.node, ref_node); + this.map.data.move(config_name, sid1, sid2, after); } scope.dragState = null; @@ -6475,12 +6486,14 @@ var CBITableSection = CBITypedSection.extend(/** @lends LuCI.form.TableSection.p }, /** @private */ - determineBackgroundColor: function(node) { - var r = 255, g = 255, b = 255; + determineBackgroundColor(node) { + let r = 255; + let g = 255; + let b = 255; while (node) { - var s = window.getComputedStyle(node), - c = (s.getPropertyValue('background-color') || '').replace(/ /g, ''); + const s = window.getComputedStyle(node); + const c = (s.getPropertyValue('background-color') ?? '').replace(/ /g, ''); if (c != '' && c != 'transparent' && c != 'rgba(0,0,0,0)') { if (/^#([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})$/i.test(c)) { @@ -6504,24 +6517,24 @@ var CBITableSection = CBITypedSection.extend(/** @lends LuCI.form.TableSection.p }, /** @private */ - handleTouchMove: function(ev) { + handleTouchMove(ev) { if (!ev.target.classList.contains('drag-handle')) return; - var touchLoc = ev.targetTouches[0], - rowBtn = ev.target, - rowElem = dom.parent(rowBtn, '.tr'), - htmlElem = document.querySelector('html'), - dragHandle = document.querySelector('.touchsort-element'), - viewportHeight = Math.max(document.documentElement.clientHeight, window.innerHeight || 0); + const touchLoc = ev.targetTouches[0]; + const rowBtn = ev.target; + const rowElem = dom.parent(rowBtn, '.tr'); + const htmlElem = document.querySelector('html'); + let dragHandle = document.querySelector('.touchsort-element'); + const viewportHeight = Math.max(document.documentElement.clientHeight, window.innerHeight ?? 0); if (!dragHandle) { - var rowRect = rowElem.getBoundingClientRect(), - btnRect = rowBtn.getBoundingClientRect(), - paddingLeft = btnRect.left - rowRect.left, - paddingRight = rowRect.right - btnRect.right, - colorBg = this.determineBackgroundColor(rowElem), - colorFg = (colorBg[0] * 0.299 + colorBg[1] * 0.587 + colorBg[2] * 0.114) > 186 ? [ 0, 0, 0 ] : [ 255, 255, 255 ]; + const rowRect = rowElem.getBoundingClientRect(); + const btnRect = rowBtn.getBoundingClientRect(); + const paddingLeft = btnRect.left - rowRect.left; + const paddingRight = rowRect.right - btnRect.right; + const colorBg = this.determineBackgroundColor(rowElem); + const colorFg = (colorBg[0] * 0.299 + colorBg[1] * 0.587 + colorBg[2] * 0.114) > 186 ? [ 0, 0, 0 ] : [ 255, 255, 255 ]; dragHandle = E('div', { 'class': 'touchsort-element' }, [ E('strong', [ rowElem.getAttribute('data-title') ]), @@ -6532,10 +6545,10 @@ var CBITableSection = CBITypedSection.extend(/** @lends LuCI.form.TableSection.p position: 'absolute', boxShadow: '0 0 3px rgba(%d, %d, %d, 1)'.format(colorFg[0], colorFg[1], colorFg[2]), background: 'rgba(%d, %d, %d, 0.8)'.format(colorBg[0], colorBg[1], colorBg[2]), - top: rowRect.top + 'px', - left: rowRect.left + 'px', - width: rowRect.width + 'px', - height: (rowBtn.offsetHeight + 4) + 'px' + top: `${rowRect.top}px`, + left: `${rowRect.left}px`, + width: `${rowRect.width}px`, + height: `${rowBtn.offsetHeight + 4}px` }); Object.assign(dragHandle.firstElementChild.style, { @@ -6546,14 +6559,14 @@ var CBITableSection = CBITypedSection.extend(/** @lends LuCI.form.TableSection.p textOverflow: 'ellipsis', left: (paddingRight > paddingLeft) ? '' : '5px', right: (paddingRight > paddingLeft) ? '5px' : '', - width: (Math.max(paddingLeft, paddingRight) - 10) + 'px' + width: `${Math.max(paddingLeft, paddingRight) - 10}px` }); Object.assign(dragHandle.lastElementChild.style, { position: 'absolute', top: '2px', - left: paddingLeft + 'px', - width: rowBtn.offsetWidth + 'px' + left: `${paddingLeft}px`, + width: `${rowBtn.offsetWidth}px` }); document.body.appendChild(dragHandle); @@ -6562,13 +6575,13 @@ var CBITableSection = CBITypedSection.extend(/** @lends LuCI.form.TableSection.p rowBtn.blur(); } - dragHandle.style.top = (touchLoc.pageY - (parseInt(dragHandle.style.height) / 2)) + 'px'; + dragHandle.style.top = `${touchLoc.pageY - (parseInt(dragHandle.style.height) / 2)}px`; - rowElem.parentNode.querySelectorAll('[draggable]').forEach(function(tr, i, trs) { - var trRect = tr.getBoundingClientRect(), - yTop = trRect.top + window.scrollY, - yBottom = trRect.bottom + window.scrollY, - yMiddle = yTop + ((yBottom - yTop) / 2); + rowElem.parentNode.querySelectorAll('[draggable]').forEach((tr, i, trs) => { + const trRect = tr.getBoundingClientRect(); + const yTop = trRect.top + window.scrollY; + const yBottom = trRect.bottom + window.scrollY; + const yMiddle = yTop + ((yBottom - yTop) / 2); tr.classList.remove('drag-over-above', 'drag-over-below'); @@ -6584,35 +6597,35 @@ var CBITableSection = CBITypedSection.extend(/** @lends LuCI.form.TableSection.p ev.preventDefault(); if (touchLoc.clientY < 30) - window.requestAnimationFrame(function() { htmlElem.scrollTop -= 30 }); + window.requestAnimationFrame(() => { htmlElem.scrollTop -= 30 }); else if (touchLoc.clientY > viewportHeight - 30) - window.requestAnimationFrame(function() { htmlElem.scrollTop += 30 }); + window.requestAnimationFrame(() => { htmlElem.scrollTop += 30 }); }, /** @private */ - handleTouchEnd: function(ev) { - var rowElem = dom.parent(ev.target, '.tr'), - htmlElem = document.querySelector('html'), - dragHandle = document.querySelector('.touchsort-element'), - targetElem = rowElem.parentNode.querySelector('.drag-over-above, .drag-over-below'), - viewportHeight = Math.max(document.documentElement.clientHeight, window.innerHeight || 0); + handleTouchEnd(ev) { + const rowElem = dom.parent(ev.target, '.tr'); + const htmlElem = document.querySelector('html'); + const dragHandle = document.querySelector('.touchsort-element'); + const targetElem = rowElem.parentNode.querySelector('.drag-over-above, .drag-over-below'); + const viewportHeight = Math.max(document.documentElement.clientHeight, window.innerHeight ?? 0); if (!dragHandle) return; if (targetElem) { - var isBelow = targetElem.classList.contains('drag-over-below'); + const isBelow = targetElem.classList.contains('drag-over-below'); rowElem.parentNode.insertBefore(rowElem, isBelow ? targetElem.nextElementSibling : targetElem); this.map.data.move( - this.uciconfig || this.map.config, + this.uciconfig ?? this.map.config, rowElem.getAttribute('data-sid'), targetElem.getAttribute('data-sid'), isBelow); - window.requestAnimationFrame(function() { - var rowRect = rowElem.getBoundingClientRect(); + window.requestAnimationFrame(() => { + const rowRect = rowElem.getBoundingClientRect(); if (rowRect.top < 50) htmlElem.scrollTop = (htmlElem.scrollTop + rowRect.top - 50); @@ -6629,13 +6642,13 @@ var CBITableSection = CBITypedSection.extend(/** @lends LuCI.form.TableSection.p }, /** @private */ - handleModalCancel: function(modalMap, ev) { - var prevNode = this.getPreviousModalMap(), - resetTasks = Promise.resolve(); + handleModalCancel(modalMap, ev) { + const prevNode = this.getPreviousModalMap(); + let resetTasks = Promise.resolve(); if (prevNode) { - var heading = prevNode.parentNode.querySelector('h4'), - prevMap = dom.findClassInstance(prevNode); + const heading = prevNode.parentNode.querySelector('h4'); + let prevMap = dom.findClassInstance(prevNode); while (prevMap) { resetTasks = resetTasks @@ -6664,10 +6677,10 @@ var CBITableSection = CBITypedSection.extend(/** @lends LuCI.form.TableSection.p }, /** @private */ - handleModalSave: function(modalMap, ev) { - var mapNode = this.getActiveModalMap(), - activeMap = dom.findClassInstance(mapNode), - saveTasks = activeMap.save(null, true); + handleModalSave(modalMap, ev) { + const mapNode = this.getActiveModalMap(); + let activeMap = dom.findClassInstance(mapNode); + let saveTasks = activeMap.save(null, true); while (activeMap.parent) { activeMap = activeMap.parent; @@ -6678,33 +6691,33 @@ var CBITableSection = CBITypedSection.extend(/** @lends LuCI.form.TableSection.p return saveTasks .then(L.bind(this.handleModalCancel, this, modalMap, ev, true)) - .catch(function() {}); + .catch(() => {}); }, /** @private */ - handleSort: function(ev) { + handleSort(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 = []; + const th = ev.target; + const descending = (th.getAttribute('data-sort-direction') == 'desc'); + const config_name = this.uciconfig ?? this.map.config; + let index = 0; + const list = []; - ev.currentTarget.querySelectorAll('th').forEach(function(other_th, i) { + ev.currentTarget.querySelectorAll('th').forEach((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); + ev.currentTarget.parentNode.querySelectorAll('tr.cbi-section-table-row').forEach(L.bind((tr, i) => { + const sid = tr.getAttribute('data-sid'); + const opt = tr.childNodes[index].getAttribute('data-name'); + const val = this.cfgvalue(sid, opt); - tr.querySelectorAll('.flash').forEach(function(n) { + tr.querySelectorAll('.flash').forEach((n) => { n.classList.remove('flash') }); @@ -6716,16 +6729,17 @@ var CBITableSection = CBITypedSection.extend(/** @lends LuCI.form.TableSection.p ]); }, this)); - list.sort(function(a, b) { + list.sort((a, b) => { return descending ? -L.naturalCompare(a[0], b[0]) : L.naturalCompare(a[0], b[0]); }); - window.requestAnimationFrame(L.bind(function() { - var ref_sid, cur_sid; + window.requestAnimationFrame(L.bind(() => { + let ref_sid; + let cur_sid; - for (var i = 0; i < list.length; i++) { + for (let i = 0; i < list.length; i++) { list[i][1].childNodes[index].classList.add('flash'); th.parentNode.parentNode.appendChild(list[i][1]); @@ -6766,37 +6780,37 @@ var CBITableSection = CBITypedSection.extend(/** @lends LuCI.form.TableSection.p * custom logic to perform asynchronous work before the modal dialog * is shown. */ - addModalOptions: function(modalSection, section_id, ev) { + addModalOptions(modalSection, section_id, ev) { }, /** @private */ - getActiveModalMap: function() { + getActiveModalMap() { return document.querySelector('body.modal-overlay-active > #modal_overlay > .modal.cbi-modal > .cbi-map:not(.hidden)'); }, /** @private */ - getPreviousModalMap: function() { - var mapNode = this.getActiveModalMap(), - prevNode = mapNode ? mapNode.previousElementSibling : null; + getPreviousModalMap() { + const mapNode = this.getActiveModalMap(); + const prevNode = mapNode ? mapNode.previousElementSibling : null; return (prevNode && prevNode.matches('.cbi-map.hidden')) ? prevNode : null; }, /** @private */ - cloneOptions: function(src_section, dest_section) { - for (var i = 0; i < src_section.children.length; i++) { - var o1 = src_section.children[i]; + cloneOptions(src_section, dest_section) { + for (let i = 0; i < src_section.children.length; i++) { + const o1 = src_section.children[i]; if (o1.modalonly === false && src_section === this) continue; - var o2; + let o2; if (o1.subsection) { o2 = dest_section.option(o1.constructor, o1.option, o1.subsection.constructor, o1.subsection.sectiontype, o1.subsection.title, o1.subsection.description); - for (var k in o1.subsection) { + for (const k in o1.subsection) { if (!o1.subsection.hasOwnProperty(k)) continue; @@ -6817,7 +6831,7 @@ var CBITableSection = CBITypedSection.extend(/** @lends LuCI.form.TableSection.p o2 = dest_section.option(o1.constructor, o1.option, o1.title, o1.description); } - for (var k in o1) { + for (const k in o1) { if (!o1.hasOwnProperty(k)) continue; @@ -6838,17 +6852,17 @@ var CBITableSection = CBITypedSection.extend(/** @lends LuCI.form.TableSection.p }, /** @private */ - renderMoreOptionsModal: function(section_id, ev) { - var parent = this.map, - sref = parent.data.get(parent.config, section_id), - mapNode = this.getActiveModalMap(), - activeMap = mapNode ? dom.findClassInstance(mapNode) : null, - stackedMap = activeMap && (activeMap.parent !== parent || activeMap.section !== section_id); - - return (stackedMap ? activeMap.save(null, true) : Promise.resolve()).then(L.bind(function() { + renderMoreOptionsModal(section_id, ev) { + const parent = this.map; + const sref = parent.data.get(parent.config, section_id); + const mapNode = this.getActiveModalMap(); + const activeMap = mapNode ? dom.findClassInstance(mapNode) : null; + const stackedMap = activeMap && (activeMap.parent !== parent || activeMap.section !== section_id); + + return (stackedMap ? activeMap.save(null, true) : Promise.resolve()).then(L.bind(() => { section_id = sref['.name']; - var m; + let m; if (parent instanceof CBIJSONMap) { m = new CBIJSONMap(null, null, null); @@ -6858,7 +6872,7 @@ var CBITableSection = CBITypedSection.extend(/** @lends LuCI.form.TableSection.p m = new CBIMap(parent.config, null, null); } - var s = m.section(CBINamedSection, section_id, this.sectiontype); + const s = m.section(CBINamedSection, section_id, this.sectiontype); m.parent = parent; m.section = section_id; @@ -6869,11 +6883,11 @@ var CBITableSection = CBITypedSection.extend(/** @lends LuCI.form.TableSection.p this.cloneOptions(this, s); - return Promise.resolve(this.addModalOptions(s, section_id, ev)).then(function() { + return Promise.resolve(this.addModalOptions(s, section_id, ev)).then(() => { return m.render(); - }).then(L.bind(function(nodes) { - var title = parent.title, - name = null; + }).then(L.bind((nodes) => { + let title = parent.title; + let name = null; if ((name = this.titleFn('modaltitle', section_id)) != null) title = name; @@ -6885,7 +6899,7 @@ var CBITableSection = CBITypedSection.extend(/** @lends LuCI.form.TableSection.p if (stackedMap) { mapNode.parentNode .querySelector('h4') - .appendChild(E('span', title ? ' » ' + title : '')); + .appendChild(E('span', title ? ` » ${title}` : '')); mapNode.parentNode .querySelector('div.button-row > button') @@ -6957,7 +6971,7 @@ var CBITableSection = CBITypedSection.extend(/** @lends LuCI.form.TableSection.p * @param {string} [description] * The description text of the form section element. */ -var CBIGridSection = CBITableSection.extend(/** @lends LuCI.form.GridSection.prototype */ { +const CBIGridSection = CBITableSection.extend(/** @lends LuCI.form.GridSection.prototype */ { /** * Add an option tab to the section. * @@ -6986,16 +7000,16 @@ var CBIGridSection = CBITableSection.extend(/** @lends LuCI.form.GridSection.pro * @throws {Error} * Throws an exception if a tab with the same `name` already exists. */ - tab: function(name, title, description) { + tab(name, title, description) { CBIAbstractSection.prototype.tab.call(this, name, title, description); }, /** @private */ - handleAdd: function(ev, name) { - var config_name = this.uciconfig || this.map.config, - section_id = this.map.data.add(config_name, this.sectiontype, name), - mapNode = this.getPreviousModalMap(), - prevMap = mapNode ? dom.findClassInstance(mapNode) : this.map; + handleAdd(ev, name) { + const config_name = this.uciconfig ?? this.map.config; + const section_id = this.map.data.add(config_name, this.sectiontype, name); + const mapNode = this.getPreviousModalMap(); + const prevMap = mapNode ? dom.findClassInstance(mapNode) : this.map; prevMap.addedSection = section_id; @@ -7003,18 +7017,18 @@ var CBIGridSection = CBITableSection.extend(/** @lends LuCI.form.GridSection.pro }, /** @private */ - handleModalSave: function(/* ... */) { - var mapNode = this.getPreviousModalMap(), - prevMap = mapNode ? dom.findClassInstance(mapNode) : this.map; + handleModalSave(...args) /* ... */{ + const mapNode = this.getPreviousModalMap(); + const prevMap = mapNode ? dom.findClassInstance(mapNode) : this.map; - return this.super('handleModalSave', arguments); + return this.super('handleModalSave', args); }, /** @private */ - handleModalCancel: function(modalMap, ev, isSaving) { - var config_name = this.uciconfig || this.map.config, - mapNode = this.getPreviousModalMap(), - prevMap = mapNode ? dom.findClassInstance(mapNode) : this.map; + handleModalCancel(modalMap, ev, isSaving) { + const config_name = this.uciconfig ?? this.map.config; + const mapNode = this.getPreviousModalMap(); + const prevMap = mapNode ? dom.findClassInstance(mapNode) : this.map; if (prevMap.addedSection != null && !isSaving) this.map.data.remove(config_name, prevMap.addedSection); @@ -7025,15 +7039,16 @@ var CBIGridSection = CBITableSection.extend(/** @lends LuCI.form.GridSection.pro }, /** @private */ - renderUCISection: function(section_id) { + renderUCISection(section_id) { return this.renderOptions(null, section_id); }, /** @private */ - renderChildren: function(tab_name, section_id, in_table) { - var tasks = [], index = 0; + renderChildren(tab_name, section_id, in_table) { + const tasks = []; + let index = 0; - for (var i = 0, opt; (opt = this.children[i]) != null; i++) { + for (let i = 0, opt; (opt = this.children[i]) != null; i++) { if (opt.disable || opt.modalonly) continue; @@ -7047,10 +7062,10 @@ var CBIGridSection = CBITableSection.extend(/** @lends LuCI.form.GridSection.pro }, /** @private */ - renderTextValue: function(section_id, opt) { - var title = this.stripTags(opt.title).trim(), - descr = this.stripTags(opt.description).trim(), - value = opt.textvalue(section_id); + renderTextValue(section_id, opt) { + const title = this.stripTags(opt.title).trim(); + const descr = this.stripTags(opt.description).trim(); + const value = opt.textvalue(section_id); return E('td', { 'class': 'td cbi-value-field', @@ -7062,23 +7077,23 @@ var CBIGridSection = CBITableSection.extend(/** @lends LuCI.form.GridSection.pro }, /** @private */ - renderHeaderRows: function(section_id) { - return this.super('renderHeaderRows', [ NaN, true ]); + renderHeaderRows(section_id) { + return this.super('renderHeaderRows', [ true ]); }, /** @private */ - renderRowActions: function(section_id) { + renderRowActions(section_id) { return this.super('renderRowActions', [ section_id, _('Edit') ]); }, /** @override */ - parse: function() { - var section_ids = this.cfgsections(), - tasks = []; + parse() { + const section_ids = this.cfgsections(); + const tasks = []; if (Array.isArray(this.children)) { - for (var i = 0; i < section_ids.length; i++) { - for (var j = 0; j < this.children.length; j++) { + for (let i = 0; i < section_ids.length; i++) { + for (let j = 0; j < this.children.length; j++) { if (!this.children[j].editable || this.children[j].modalonly) continue; @@ -7120,10 +7135,10 @@ var CBIGridSection = CBITableSection.extend(/** @lends LuCI.form.GridSection.pro * @param {string} [description] * The description text of the form section element. */ -var CBINamedSection = CBIAbstractSection.extend(/** @lends LuCI.form.NamedSection.prototype */ { +const CBINamedSection = CBIAbstractSection.extend(/** @lends LuCI.form.NamedSection.prototype */ { __name__: 'CBI.NamedSection', - __init__: function(map, section_id /*, ... */) { - this.super('__init__', this.varargs(arguments, 2, map)); + __init__(map, section_id, ...args) { + this.super('__init__', [ map, ...args ]); this.section = section_id; }, @@ -7157,39 +7172,41 @@ var CBINamedSection = CBIAbstractSection.extend(/** @lends LuCI.form.NamedSectio * @returns {string[]} * Returns a one-element array containing the mapped section ID. */ - cfgsections: function() { + cfgsections() { return [ this.section ]; }, /** @private */ - handleAdd: function(ev) { - var section_id = this.section, - config_name = this.uciconfig || this.map.config; + handleAdd(ev) { + const section_id = this.section; + const config_name = this.uciconfig ?? this.map.config; this.map.data.add(config_name, this.sectiontype, section_id); return this.map.save(null, true); }, /** @private */ - handleRemove: function(ev) { - var section_id = this.section, - config_name = this.uciconfig || this.map.config; + handleRemove(ev) { + const section_id = this.section; + const config_name = this.uciconfig ?? this.map.config; this.map.data.remove(config_name, section_id); return this.map.save(null, true); }, /** @private */ - renderContents: function(data) { - var ucidata = data[0], nodes = data[1], - section_id = this.section, - config_name = this.uciconfig || this.map.config, - sectionEl = E('div', { - 'id': ucidata ? null : 'cbi-%s-%s'.format(config_name, section_id), - 'class': 'cbi-section', - 'data-tab': (this.map.tabbed && !this.parentoption) ? this.sectiontype : null, - 'data-tab-title': (this.map.tabbed && !this.parentoption) ? this.title || this.sectiontype : null - }); + renderContents(data) { + const ucidata = data[0]; + const nodes = data[1]; + const section_id = this.section; + const config_name = this.uciconfig ?? this.map.config; + + const sectionEl = E('div', { + 'id': ucidata ? null : 'cbi-%s-%s'.format(config_name, section_id), + 'class': 'cbi-section', + 'data-tab': (this.map.tabbed && !this.parentoption) ? this.sectiontype : null, + 'data-tab-title': (this.map.tabbed && !this.parentoption) ? this.title || this.sectiontype : null + }); if (typeof(this.title) === 'string' && this.title !== '') sectionEl.appendChild(E('h3', {}, this.title)); @@ -7230,9 +7247,9 @@ var CBINamedSection = CBIAbstractSection.extend(/** @lends LuCI.form.NamedSectio }, /** @override */ - render: function() { - var config_name = this.uciconfig || this.map.config, - section_id = this.section; + render() { + const config_name = this.uciconfig ?? this.map.config; + const section_id = this.section; return Promise.all([ this.map.data.get(config_name, section_id), @@ -7273,7 +7290,7 @@ var CBINamedSection = CBIAbstractSection.extend(/** @lends LuCI.form.NamedSectio * @param {string} [description] * The description text of the option element. */ -var CBIValue = CBIAbstractValue.extend(/** @lends LuCI.form.Value.prototype */ { +const CBIValue = CBIAbstractValue.extend(/** @lends LuCI.form.Value.prototype */ { __name__: 'CBI.Value', /** @@ -7306,27 +7323,27 @@ var CBIValue = CBIAbstractValue.extend(/** @lends LuCI.form.Value.prototype */ { * The caption for the choice value. May be a DOM node, a document fragment * or a plain text string. If omitted, the `key` value is used as caption. */ - value: function(key, val) { - this.keylist = this.keylist || []; + value(key, val) { + this.keylist ??= []; this.keylist.push(String(key)); - this.vallist = this.vallist || []; + this.vallist ??= []; this.vallist.push(dom.elem(val) ? val : String(val != null ? val : key)); }, /** @override */ - render: function(option_index, section_id, in_table) { + render(option_index, section_id, in_table) { return Promise.resolve(this.cfgvalue(section_id)) .then(this.renderWidget.bind(this, section_id, option_index)) .then(this.renderFrame.bind(this, section_id, in_table, option_index)); }, /** @private */ - handleValueChange: function(section_id, state, ev) { + handleValueChange(section_id, state, ev) { if (typeof(this.onchange) != 'function') return; - var value = this.formvalue(section_id); + const value = this.formvalue(section_id); if (isEqual(value, state.previousValue)) return; @@ -7336,13 +7353,13 @@ var CBIValue = CBIAbstractValue.extend(/** @lends LuCI.form.Value.prototype */ { }, /** @private */ - renderFrame: function(section_id, in_table, option_index, nodes) { - var config_name = this.uciconfig || this.section.uciconfig || this.map.config, - depend_list = this.transformDepList(section_id), - optionEl; + renderFrame(section_id, in_table, option_index, nodes) { + const config_name = this.uciconfig ?? this.section.uciconfig ?? this.map.config; + const depend_list = this.transformDepList(section_id); + let optionEl; if (in_table) { - var title = this.stripTags(this.title).trim(); + const title = this.stripTags(this.title).trim(); optionEl = E('td', { 'class': 'td cbi-value-field', 'data-title': (title != '') ? title : null, @@ -7374,9 +7391,9 @@ var CBIValue = CBIAbstractValue.extend(/** @lends LuCI.form.Value.prototype */ { optionEl.appendChild(E('label', { 'class': 'cbi-value-title', 'for': 'widget.cbid.%s.%s.%s'.format(config_name, section_id, this.option), - 'click': function(ev) { - var node = ev.currentTarget, - elem = node.nextElementSibling.querySelector('#' + node.getAttribute('for')) || node.nextElementSibling.querySelector('[data-widget-id="' + node.getAttribute('for') + '"]'); + 'click': (ev) => { + const node = ev.currentTarget; + const elem = node.nextElementSibling.querySelector(`#${node.getAttribute('for')}`) ?? node.nextElementSibling.querySelector(`[data-widget-id="${node.getAttribute('for')}"]`); if (elem) { elem.click(); @@ -7387,7 +7404,7 @@ var CBIValue = CBIAbstractValue.extend(/** @lends LuCI.form.Value.prototype */ { this.titleref ? E('a', { 'class': 'cbi-title-ref', 'href': this.titleref, - 'title': this.titledesc || _('Go to relevant configuration page') + 'title': this.titledesc ?? _('Go to relevant configuration page') }, this.title) : this.title)); optionEl.appendChild(E('div', { 'class': 'cbi-value-field' })); @@ -7395,10 +7412,10 @@ var CBIValue = CBIAbstractValue.extend(/** @lends LuCI.form.Value.prototype */ { } if (nodes) - (optionEl.lastChild || optionEl).appendChild(nodes); + (optionEl.lastChild ?? optionEl).appendChild(nodes); if (!in_table && typeof(this.description) === 'string' && this.description !== '') - dom.append(optionEl.lastChild || optionEl, + dom.append(optionEl.lastChild ?? optionEl, E('div', { 'class': 'cbi-value-description' }, this.description.trim())); if (depend_list && depend_list.length) @@ -7416,13 +7433,13 @@ var CBIValue = CBIAbstractValue.extend(/** @lends LuCI.form.Value.prototype */ { }, /** @private */ - renderWidget: function(section_id, option_index, cfgvalue) { - var value = (cfgvalue != null) ? cfgvalue : this.default, - choices = this.transformChoices(), - widget; + renderWidget(section_id, option_index, cfgvalue) { + const value = (cfgvalue != null) ? cfgvalue : this.default; + const choices = this.transformChoices(); + let widget; if (choices) { - var placeholder = (this.optional || this.rmempty) + const placeholder = (this.optional || this.rmempty) ? E('em', _('unspecified')) : _('-- Please choose --'); widget = new ui.Combobox(Array.isArray(value) ? value.join(' ') : value, choices, { @@ -7430,7 +7447,7 @@ var CBIValue = CBIAbstractValue.extend(/** @lends LuCI.form.Value.prototype */ { sort: this.keylist, optional: this.optional || this.rmempty, datatype: this.datatype, - select_placeholder: this.placeholder || placeholder, + select_placeholder: this.placeholder ?? placeholder, validate: L.bind(this.validate, this, section_id), disabled: (this.readonly != null) ? this.readonly : this.map.readonly }); @@ -7483,16 +7500,16 @@ var CBIValue = CBIAbstractValue.extend(/** @lends LuCI.form.Value.prototype */ { * @param {string} [description] * The description text of the option element. */ -var CBIDynamicList = CBIValue.extend(/** @lends LuCI.form.DynamicList.prototype */ { +const CBIDynamicList = CBIValue.extend(/** @lends LuCI.form.DynamicList.prototype */ { __name__: 'CBI.DynamicList', /** @private */ - renderWidget: function(section_id, option_index, cfgvalue) { - var value = (cfgvalue != null) ? cfgvalue : this.default, - choices = this.transformChoices(), - items = L.toArray(value); + renderWidget(section_id, option_index, cfgvalue) { + const value = (cfgvalue != null) ? cfgvalue : this.default; + const choices = this.transformChoices(); + const items = L.toArray(value); - var widget = new ui.DynamicList(items, choices, { + const widget = new ui.DynamicList(items, choices, { id: this.cbid(section_id), sort: this.keylist, optional: this.optional || this.rmempty, @@ -7538,11 +7555,11 @@ var CBIDynamicList = CBIValue.extend(/** @lends LuCI.form.DynamicList.prototype * @param {string} [description] * The description text of the option element. */ -var CBIListValue = CBIValue.extend(/** @lends LuCI.form.ListValue.prototype */ { +const CBIListValue = CBIValue.extend(/** @lends LuCI.form.ListValue.prototype */ { __name__: 'CBI.ListValue', - __init__: function() { - this.super('__init__', arguments); + __init__(...args) { + this.super('__init__', args); this.widget = 'select'; this.orientation = 'horizontal'; this.deplist = []; @@ -7580,9 +7597,9 @@ var CBIListValue = CBIValue.extend(/** @lends LuCI.form.ListValue.prototype */ { */ /** @private */ - renderWidget: function(section_id, option_index, cfgvalue) { - var choices = this.transformChoices(); - var widget = new ui.Select((cfgvalue != null) ? cfgvalue : this.default, choices, { + renderWidget(section_id, option_index, cfgvalue) { + const choices = this.transformChoices(); + const widget = new ui.Select((cfgvalue != null) ? cfgvalue : this.default, choices, { id: this.cbid(section_id), size: this.size, sort: this.keylist, @@ -7631,10 +7648,10 @@ var CBIListValue = CBIValue.extend(/** @lends LuCI.form.ListValue.prototype */ { * @param {string} [description] * The description text of the option element. */ -var CBIRichListValue = CBIListValue.extend(/** @lends LuCI.form.ListValue.prototype */ { +const CBIRichListValue = CBIListValue.extend(/** @lends LuCI.form.ListValue.prototype */ { __name__: 'CBI.RichListValue', - __init__: function() { + __init__() { this.super('__init__', arguments); this.widget = 'select'; this.orientation = 'horizontal'; @@ -7673,9 +7690,9 @@ var CBIRichListValue = CBIListValue.extend(/** @lends LuCI.form.ListValue.protot */ /** @private */ - renderWidget: function(section_id, option_index, cfgvalue) { - var choices = this.transformChoices(); - var widget = new ui.Dropdown((cfgvalue != null) ? cfgvalue : this.default, choices, { + renderWidget(section_id, option_index, cfgvalue) { + const choices = this.transformChoices(); + const widget = new ui.Dropdown((cfgvalue != null) ? cfgvalue : this.default, choices, { id: this.cbid(section_id), size: this.size, sort: this.keylist, @@ -7710,7 +7727,7 @@ var CBIRichListValue = CBIListValue.extend(/** @lends LuCI.form.ListValue.protot * implemented as a simple ListValue entry. * */ - value: function(value, title, description) { + value(value, title, description) { if (description) { CBIListValue.prototype.value.call(this, value, E([], [ E('span', { 'class': 'hide-open' }, [ title ]), @@ -7758,11 +7775,11 @@ var CBIRichListValue = CBIListValue.extend(/** @lends LuCI.form.ListValue.protot * @param {string} [description] * The description text of the option element. */ -var CBIFlagValue = CBIValue.extend(/** @lends LuCI.form.FlagValue.prototype */ { +const CBIFlagValue = CBIValue.extend(/** @lends LuCI.form.FlagValue.prototype */ { __name__: 'CBI.FlagValue', - __init__: function() { - this.super('__init__', arguments); + __init__(...args) { + this.super('__init__', args); this.enabled = '1'; this.disabled = '0'; @@ -7811,20 +7828,20 @@ var CBIFlagValue = CBIValue.extend(/** @lends LuCI.form.FlagValue.prototype */ { */ /** @private */ - renderWidget: function(section_id, option_index, cfgvalue) { - var tooltip = null; + renderWidget(section_id, option_index, cfgvalue) { + let tooltip = null; if (typeof(this.tooltip) == 'function') - tooltip = this.tooltip.apply(this, [section_id]); + tooltip = this.tooltip(section_id); else if (typeof(this.tooltip) == 'string') - tooltip = (arguments.length > 1) ? ''.format.apply(this.tooltip, this.varargs(arguments, 1)) : this.tooltip; + tooltip = this.tooltip.format(section_id); - var widget = new ui.Checkbox((cfgvalue != null) ? cfgvalue : this.default, { + const widget = new ui.Checkbox((cfgvalue != null) ? cfgvalue : this.default, { id: this.cbid(section_id), value_enabled: this.enabled, value_disabled: this.disabled, validate: L.bind(this.validate, this, section_id), - tooltip: tooltip, + tooltip, tooltipicon: this.tooltipicon, disabled: (this.readonly != null) ? this.readonly : this.map.readonly }); @@ -7839,9 +7856,9 @@ var CBIFlagValue = CBIValue.extend(/** @lends LuCI.form.FlagValue.prototype */ { * * @override */ - formvalue: function(section_id) { - var elem = this.getUIElement(section_id), - checked = elem ? elem.isChecked() : false; + formvalue(section_id) { + const elem = this.getUIElement(section_id); + const checked = elem ? elem.isChecked() : false; return checked ? this.enabled : this.disabled; }, @@ -7851,8 +7868,8 @@ var CBIFlagValue = CBIValue.extend(/** @lends LuCI.form.FlagValue.prototype */ { * * @override */ - textvalue: function(section_id) { - var cval = this.cfgvalue(section_id); + textvalue(section_id) { + let cval = this.cfgvalue(section_id); if (cval == null) cval = this.default; @@ -7861,15 +7878,16 @@ var CBIFlagValue = CBIValue.extend(/** @lends LuCI.form.FlagValue.prototype */ { }, /** @override */ - parse: function(section_id) { + parse(section_id) { if (this.isActive(section_id)) { - var fval = this.formvalue(section_id); + const fval = this.formvalue(section_id); if (!this.isValid(section_id)) { - var title = this.stripTags(this.title).trim(); - var error = this.getValidationError(section_id); + const title = this.stripTags(this.title).trim(); + const error = this.getValidationError(section_id); + return Promise.reject(new TypeError( - _('Option "%s" contains an invalid input value.').format(title || this.option) + ' ' + error)); + `${_('Option "%s" contains an invalid input value.').format(title || this.option)} ${error}`)); } if (fval == this.default && (this.optional || this.rmempty)) @@ -7915,11 +7933,11 @@ var CBIFlagValue = CBIValue.extend(/** @lends LuCI.form.FlagValue.prototype */ { * @param {string} [description] * The description text of the option element. */ -var CBIMultiValue = CBIDynamicList.extend(/** @lends LuCI.form.MultiValue.prototype */ { +const CBIMultiValue = CBIDynamicList.extend(/** @lends LuCI.form.MultiValue.prototype */ { __name__: 'CBI.MultiValue', - __init__: function() { - this.super('__init__', arguments); + __init__(...args) { + this.super('__init__', args); this.placeholder = _('-- Please choose --'); }, @@ -7952,19 +7970,19 @@ var CBIMultiValue = CBIDynamicList.extend(/** @lends LuCI.form.MultiValue.protot */ /** @private */ - renderWidget: function(section_id, option_index, cfgvalue) { - var value = (cfgvalue != null) ? cfgvalue : this.default, - choices = this.transformChoices(); + renderWidget(section_id, option_index, cfgvalue) { + const value = (cfgvalue != null) ? cfgvalue : this.default; + const choices = this.transformChoices(); - var widget = new ui.Dropdown(L.toArray(value), choices, { + const widget = new ui.Dropdown(L.toArray(value), choices, { id: this.cbid(section_id), sort: this.keylist, multiple: true, optional: this.optional || this.rmempty, select_placeholder: this.placeholder, - create: this.create, - display_items: this.display_size || this.size || 3, - dropdown_items: this.dropdown_size || this.size || -1, + create: this.create, + display_items: this.display_size ?? this.size ?? 3, + dropdown_items: this.dropdown_size ?? this.size ?? -1, validate: L.bind(this.validate, this, section_id), disabled: (this.readonly != null) ? this.readonly : this.map.readonly }); @@ -8004,7 +8022,7 @@ var CBIMultiValue = CBIDynamicList.extend(/** @lends LuCI.form.MultiValue.protot * @param {string} [description] * The description text of the option element. */ -var CBITextValue = CBIValue.extend(/** @lends LuCI.form.TextValue.prototype */ { +const CBITextValue = CBIValue.extend(/** @lends LuCI.form.TextValue.prototype */ { __name__: 'CBI.TextValue', /** @ignore */ @@ -8047,10 +8065,10 @@ var CBITextValue = CBIValue.extend(/** @lends LuCI.form.TextValue.prototype */ { */ /** @private */ - renderWidget: function(section_id, option_index, cfgvalue) { - var value = (cfgvalue != null) ? cfgvalue : this.default; + renderWidget(section_id, option_index, cfgvalue) { + const value = (cfgvalue != null) ? cfgvalue : this.default; - var widget = new ui.Textarea(value, { + const widget = new ui.Textarea(value, { id: this.cbid(section_id), optional: this.optional || this.rmempty, placeholder: this.placeholder, @@ -8097,7 +8115,7 @@ var CBITextValue = CBIValue.extend(/** @lends LuCI.form.TextValue.prototype */ { * @param {string} [description] * The description text of the option element. */ -var CBIDummyValue = CBIValue.extend(/** @lends LuCI.form.DummyValue.prototype */ { +const CBIDummyValue = CBIValue.extend(/** @lends LuCI.form.DummyValue.prototype */ { __name__: 'CBI.DummyValue', /** @@ -8123,7 +8141,7 @@ var CBIDummyValue = CBIValue.extend(/** @lends LuCI.form.DummyValue.prototype */ * @default null */ - /** + /** * Render the UCI option value as hidden using the HTML display: none style property. * * By default, the value is displayed @@ -8134,15 +8152,15 @@ var CBIDummyValue = CBIValue.extend(/** @lends LuCI.form.DummyValue.prototype */ */ /** @private */ - renderWidget: function(section_id, option_index, cfgvalue) { - var value = (cfgvalue != null) ? cfgvalue : this.default, - hiddenEl = new ui.Hiddenfield(value, { id: this.cbid(section_id) }), - outputEl = E('div', { 'style': this.hidden ? 'display:none' : null }); + renderWidget(section_id, option_index, cfgvalue) { + const value = (cfgvalue != null) ? cfgvalue : this.default; + const hiddenEl = new ui.Hiddenfield(value, { id: this.cbid(section_id) }); + const outputEl = E('div', { 'style': this.hidden ? 'display:none' : null }); if (this.href && !((this.readonly != null) ? this.readonly : this.map.readonly)) outputEl.appendChild(E('a', { 'href': this.href })); - dom.append(outputEl.lastChild || outputEl, + dom.append(outputEl.lastChild ?? outputEl, this.rawhtml ? value : [ value ]); return E([ @@ -8152,10 +8170,10 @@ var CBIDummyValue = CBIValue.extend(/** @lends LuCI.form.DummyValue.prototype */ }, /** @override */ - remove: function() {}, + remove() {}, /** @override */ - write: function() {} + write() {} }); /** @@ -8189,7 +8207,7 @@ var CBIDummyValue = CBIValue.extend(/** @lends LuCI.form.DummyValue.prototype */ * @param {string} [description] * The description text of the option element. */ -var CBIButtonValue = CBIValue.extend(/** @lends LuCI.form.ButtonValue.prototype */ { +const CBIButtonValue = CBIValue.extend(/** @lends LuCI.form.ButtonValue.prototype */ { __name__: 'CBI.ButtonValue', /** @@ -8244,24 +8262,24 @@ var CBIButtonValue = CBIValue.extend(/** @lends LuCI.form.ButtonValue.prototype */ /** @private */ - renderWidget: function(section_id, option_index, cfgvalue) { - var value = (cfgvalue != null) ? cfgvalue : this.default, - hiddenEl = new ui.Hiddenfield(value, { id: this.cbid(section_id) }), - outputEl = E('div'), - btn_title = this.titleFn('inputtitle', section_id) || this.titleFn('title', section_id); + renderWidget(section_id, option_index, cfgvalue) { + const value = (cfgvalue != null) ? cfgvalue : this.default; + const hiddenEl = new ui.Hiddenfield(value, { id: this.cbid(section_id) }); + const outputEl = E('div'); + const btn_title = this.titleFn('inputtitle', section_id) ?? this.titleFn('title', section_id); if (value !== false) dom.content(outputEl, [ E('button', { - 'class': 'cbi-button cbi-button-%s'.format(this.inputstyle || 'button'), - 'click': ui.createHandlerFn(this, function(section_id, ev) { + 'class': 'cbi-button cbi-button-%s'.format(this.inputstyle ?? 'button'), + 'click': ui.createHandlerFn(this, (section_id, ev) => { if (this.onclick) return this.onclick(ev, section_id); ev.currentTarget.parentNode.nextElementSibling.value = value; return this.map.save(); }, section_id), - 'disabled': ((this.readonly != null) ? this.readonly : this.map.readonly) || null + 'disabled': (this.readonly ?? this.map.readonly) || null }, [ btn_title ]) ]); else @@ -8312,12 +8330,12 @@ var CBIButtonValue = CBIValue.extend(/** @lends LuCI.form.ButtonValue.prototype * @param {string} [description] * The description text of the option element. */ -var CBIHiddenValue = CBIValue.extend(/** @lends LuCI.form.HiddenValue.prototype */ { +const CBIHiddenValue = CBIValue.extend(/** @lends LuCI.form.HiddenValue.prototype */ { __name__: 'CBI.HiddenValue', /** @private */ - renderWidget: function(section_id, option_index, cfgvalue) { - var widget = new ui.Hiddenfield((cfgvalue != null) ? cfgvalue : this.default, { + renderWidget(section_id, option_index, cfgvalue) { + const widget = new ui.Hiddenfield((cfgvalue != null) ? cfgvalue : this.default, { id: this.cbid(section_id) }); @@ -8356,11 +8374,11 @@ var CBIHiddenValue = CBIValue.extend(/** @lends LuCI.form.HiddenValue.prototype * @param {string} [description] * The description text of the option element. */ -var CBIFileUpload = CBIValue.extend(/** @lends LuCI.form.FileUpload.prototype */ { +const CBIFileUpload = CBIValue.extend(/** @lends LuCI.form.FileUpload.prototype */ { __name__: 'CBI.FileSelect', - __init__: function(/* ... */) { - this.super('__init__', arguments); + __init__(...args) { + this.super('__init__', args); this.browser = false; this.show_hidden = false; @@ -8448,8 +8466,8 @@ var CBIFileUpload = CBIValue.extend(/** @lends LuCI.form.FileUpload.prototype */ */ /** @private */ - renderWidget: function(section_id, option_index, cfgvalue) { - var browserEl = new ui.FileUpload((cfgvalue != null) ? cfgvalue : this.default, { + renderWidget(section_id, option_index, cfgvalue) { + const browserEl = new ui.FileUpload((cfgvalue != null) ? cfgvalue : this.default, { id: this.cbid(section_id), name: this.cbid(section_id), browser: this.browser, @@ -8503,15 +8521,15 @@ var CBIFileUpload = CBIValue.extend(/** @lends LuCI.form.FileUpload.prototype */ * All further arguments are passed as-is to the subclass constructor. Refer * to the corresponding class constructor documentations for details. */ -var CBISectionValue = CBIValue.extend(/** @lends LuCI.form.SectionValue.prototype */ { +const CBISectionValue = CBIValue.extend(/** @lends LuCI.form.SectionValue.prototype */ { __name__: 'CBI.ContainerValue', - __init__: function(map, section, option, cbiClass /*, ... */) { - this.super('__init__', [map, section, option]); + __init__(map, section, option, cbiClass, ...args) { + this.super('__init__', [ map, section, option ]); if (!CBIAbstractSection.isSubclass(cbiClass)) throw 'Sub section must be a descendent of CBIAbstractSection'; - this.subsection = cbiClass.instantiate(this.varargs(arguments, 4, this.map)); + this.subsection = cbiClass.instantiate([ this.map, ...args ]); this.subsection.parentoption = this; }, @@ -8526,22 +8544,22 @@ var CBISectionValue = CBIValue.extend(/** @lends LuCI.form.SectionValue.prototyp */ /** @override */ - load: function(section_id) { + load(section_id) { return this.subsection.load(section_id); }, /** @override */ - parse: function(section_id) { + parse(section_id) { return this.subsection.parse(section_id); }, /** @private */ - renderWidget: function(section_id, option_index, cfgvalue) { + renderWidget(section_id, option_index, cfgvalue) { return this.subsection.render(section_id); }, /** @private */ - checkDepends: function(section_id) { + checkDepends(section_id) { this.subsection.checkDepends(section_id); return CBIValue.prototype.checkDepends.apply(this, [ section_id ]); }, @@ -8552,7 +8570,7 @@ var CBISectionValue = CBIValue.extend(/** @lends LuCI.form.SectionValue.prototyp * * @override */ - value: function() {}, + value() {}, /** * Since the section container is not tied to any UCI configuration, @@ -8560,7 +8578,7 @@ var CBISectionValue = CBIValue.extend(/** @lends LuCI.form.SectionValue.prototyp * * @override */ - write: function() {}, + write() {}, /** * Since the section container is not tied to any UCI configuration, @@ -8568,7 +8586,7 @@ var CBISectionValue = CBIValue.extend(/** @lends LuCI.form.SectionValue.prototyp * * @override */ - remove: function() {}, + remove() {}, /** * Since the section container is not tied to any UCI configuration, @@ -8577,7 +8595,7 @@ var CBISectionValue = CBIValue.extend(/** @lends LuCI.form.SectionValue.prototyp * @override * @returns {null} */ - cfgvalue: function() { return null }, + cfgvalue() { return null }, /** * Since the section container is not tied to any UCI configuration, @@ -8586,7 +8604,7 @@ var CBISectionValue = CBIValue.extend(/** @lends LuCI.form.SectionValue.prototyp * @override * @returns {null} */ - formvalue: function() { return null } + formvalue() { return null } }); /** @@ -8613,7 +8631,7 @@ var CBISectionValue = CBIValue.extend(/** @lends LuCI.form.SectionValue.prototyp * 'use strict'; * 'require form'; * - * var m, s, o; + * let m, s, o; * * m = new form.Map('example', 'Example form', * 'This is an example form mapping the contents of /etc/config/example'); @@ -8627,7 +8645,7 @@ var CBISectionValue = CBIValue.extend(/** @lends LuCI.form.SectionValue.prototyp * o.value('choice1', 'The first choice'); * o.value('choice2', 'The second choice'); * - * m.render().then(function(node) { + * m.render().then((node) => { * document.body.appendChild(node); * }); * </pre> @@ -8668,7 +8686,7 @@ return baseclass.extend(/** @lends LuCI.form.prototype */ { diff --git a/jsapi/fs.js.html b/jsapi/fs.js.html index 8bf92b5ac0..589d722b14 100644 --- a/jsapi/fs.js.html +++ b/jsapi/fs.js.html @@ -86,6 +86,8 @@
  • hasViewPermission
  • +
  • isArguments
  • +
  • isObject
  • location
  • @@ -4077,7 +4079,7 @@ return FileSystem; diff --git a/jsapi/index.html b/jsapi/index.html index 3718ef5bc8..8e9e3c4fc2 100644 --- a/jsapi/index.html +++ b/jsapi/index.html @@ -86,6 +86,8 @@
  • hasViewPermission
  • +
  • isArguments
  • +
  • isObject
  • location
  • @@ -3664,7 +3666,7 @@ is the central JSDoc 3.6.11 on Thu Dec 19 2024 19:20:35 GMT+0000 (Coordinated Universal Time) + Documentation generated by JSDoc 3.6.11 on Fri Dec 20 2024 00:14:55 GMT+0000 (Coordinated Universal Time) diff --git a/jsapi/luci.js.html b/jsapi/luci.js.html index c8f8e28f54..a8f7a92dc3 100644 --- a/jsapi/luci.js.html +++ b/jsapi/luci.js.html @@ -86,6 +86,8 @@
  • hasViewPermission
  • +
  • isArguments
  • +
  • isObject
  • location
  • @@ -3647,54 +3649,16 @@ * The environment settings to use for the LuCI runtime. */ -(function(window, document, undefined) { +((window, document, undefined) => { 'use strict'; - var env = {}; - - /* Object.assign polyfill for IE */ - if (typeof Object.assign !== 'function') { - Object.defineProperty(Object, 'assign', { - value: function assign(target, varArgs) { - if (target == null) - throw new TypeError('Cannot convert undefined or null to object'); - - var to = Object(target); - - for (var index = 1; index < arguments.length; index++) - if (arguments[index] != null) - for (var nextKey in arguments[index]) - if (Object.prototype.hasOwnProperty.call(arguments[index], nextKey)) - to[nextKey] = arguments[index][nextKey]; - - return to; - }, - writable: true, - configurable: true - }); - } - - /* Promise.finally polyfill */ - if (typeof Promise.prototype.finally !== 'function') { - Promise.prototype.finally = function(fn) { - var onFinally = function(cb) { - return Promise.resolve(fn.call(this)).then(cb); - }; - - return this.then( - function(result) { return onFinally.call(this, function() { return result }) }, - function(reason) { return onFinally.call(this, function() { return Promise.reject(reason) }) } - ); - }; - } + const env = {}; /* * Class declaration and inheritance helper */ - var toCamelCase = function(s) { - return s.replace(/(?:^|[\. -])(.)/g, function(m0, m1) { return m1.toUpperCase() }); - }; + const toCamelCase = s => s.replace(/(?:^|[\. -])(.)/g, (m0, m1) => m1.toUpperCase()); /** * @class baseclass @@ -3707,7 +3671,11 @@ * It provides simple means to create subclasses of given classes and * implements prototypal inheritance. */ - var superContext = {}, classIndex = 0, Class = Object.assign(function() {}, { + const superContext = {}; + + let classIndex = 0; + + const Class = Object.assign(function() {}, { /** * Extends this base class with the properties described in * `properties` and returns a new subclassed Class instance @@ -3724,14 +3692,14 @@ * class to enable inheritance. The resulting value represents a * class constructor and can be instantiated with `new`. */ - extend: function(properties) { - var props = { + extend(properties) { + const props = { __id__: { value: classIndex }, __base__: { value: this.prototype }, - __name__: { value: properties.__name__ || 'anonymous' + classIndex++ } + __name__: { value: properties.__name__ ?? `anonymous${classIndex++}` } }; - var ClassConstructor = function() { + const ClassConstructor = function() { if (!(this instanceof ClassConstructor)) throw new TypeError('Constructor must not be called without "new"'); @@ -3746,14 +3714,14 @@ } }; - for (var key in properties) + for (const key in properties) if (!props[key] && properties.hasOwnProperty(key)) props[key] = { value: properties[key], writable: true }; ClassConstructor.prototype = Object.create(this.prototype, props); ClassConstructor.prototype.constructor = ClassConstructor; Object.assign(ClassConstructor, this); - ClassConstructor.displayName = toCamelCase(props.__name__.value + 'Class'); + ClassConstructor.displayName = toCamelCase(`${props.__name__.value}Class`); return ClassConstructor; }, @@ -3783,9 +3751,8 @@ * properties with its prototype set to this base class to * enable inheritance. */ - singleton: function(properties /*, ... */) { - return Class.extend(properties) - .instantiate(Class.prototype.varargs(arguments, 1)); + singleton(properties, ...new_args) { + return Class.extend(properties).instantiate(new_args); }, /** @@ -3798,26 +3765,21 @@ * An array of arbitrary values which will be passed as arguments * to the constructor function. * - * @param {...*} [new_args] - * Specifies arguments to be passed to the subclass constructor - * as-is in order to instantiate the new subclass. - * * @returns {LuCI.baseclass} * Returns a new LuCI.baseclass instance extended by the given * properties with its prototype set to this base class to * enable inheritance. */ - instantiate: function(args) { - return new (Function.prototype.bind.apply(this, - Class.prototype.varargs(args, 0, null)))(); + instantiate(args) { + return new (Function.prototype.bind.call(this, null, ...args))(); }, /* unused */ - call: function(self, method) { + call(self, method, ...args) { if (typeof(this.prototype[method]) != 'function') - throw new ReferenceError(method + ' is not defined in class'); + throw new ReferenceError(`${method} is not defined in class`); - return this.prototype[method].apply(self, self.varargs(arguments, 1)); + return this.prototype[method].call(self, method, ...args); }, /** @@ -3833,10 +3795,8 @@ * class or `false` if the given value is not a valid class or not * a subclass of this class'. */ - isSubclass: function(classValue) { - return (classValue != null && - typeof(classValue) == 'function' && - classValue.prototype instanceof this); + isSubclass(classValue) { + return (typeof(classValue) == 'function' && classValue.prototype instanceof this); }, prototype: { @@ -3863,9 +3823,8 @@ * and the values extracted from the `args` array beginning with * `offset`. */ - varargs: function(args, offset /*, ... */) { - return Array.prototype.slice.call(arguments, 2) - .concat(Array.prototype.slice.call(args, offset)); + varargs(args, offset, ...extra_args) { + return extra_args.concat(Array.prototype.slice.call(args, offset)); }, /** @@ -3878,11 +3837,11 @@ * This function has two signatures and is sensitive to the * amount of arguments passed to it: * - `super('key')` - - * Returns the value of `key` when found within one of the - * parent classes. + * Returns the value of `key` when found within one of the + * parent classes. * - `super('key', ['arg1', 'arg2'])` - - * Calls the `key()` method with parameters `arg1` and `arg2` - * when found within one of the parent classes. + * Calls the `key()` method with parameters `arg1` and `arg2` + * when found within one of the parent classes. * * @memberof LuCI.baseclass * @instance @@ -3905,29 +3864,29 @@ * was found in the parent class chain or when the call to the * superclass method returned `null`. */ - super: function(key, callArgs) { + super(key, ...callArgs) { if (key == null) return null; - var slotIdx = this.__id__ + '.' + key, - symStack = superContext[slotIdx], - protoCtx = null; + const slotIdx = `${this.__id__}.${key}`; + const symStack = superContext[slotIdx]; + let protoCtx = null; for (protoCtx = Object.getPrototypeOf(symStack ? symStack[0] : Object.getPrototypeOf(this)); - protoCtx != null && !protoCtx.hasOwnProperty(key); - protoCtx = Object.getPrototypeOf(protoCtx)) {} + protoCtx != null && !protoCtx.hasOwnProperty(key); + protoCtx = Object.getPrototypeOf(protoCtx)) {} if (protoCtx == null) return null; - var res = protoCtx[key]; + let res = protoCtx[key]; - if (arguments.length > 1) { + if (callArgs.length > 0) { if (typeof(res) != 'function') - throw new ReferenceError(key + ' is not a function in base class'); + throw new ReferenceError(`${key} is not a function in base class`); - if (typeof(callArgs) != 'object') - callArgs = this.varargs(arguments, 1); + if (Array.isArray(callArgs[0]) || LuCI.prototype.isArguments(callArgs[0])) + callArgs = callArgs[0]; if (symStack) symStack.unshift(protoCtx); @@ -3953,11 +3912,11 @@ * constructor functions `displayName` and describing the class * members and their respective types. */ - toString: function() { - var s = '[' + this.constructor.displayName + ']', f = true; - for (var k in this) { + toString() { + let s = `[${this.constructor.displayName}]`, f = true; + for (const k in this) { if (this.hasOwnProperty(k)) { - s += (f ? ' {\n' : '') + ' ' + k + ': ' + typeof(this[k]) + '\n'; + s += `${f ? ' {\n' : ''} ${k}: ${typeof(this[k])}\n`; f = false; } } @@ -3976,12 +3935,12 @@ * The `Headers` class is an internal utility class exposed in HTTP * response objects using the `response.headers` property. */ - var Headers = Class.extend(/** @lends LuCI.headers.prototype */ { + const Headers = Class.extend(/** @lends LuCI.headers.prototype */ { __name__: 'LuCI.headers', - __init__: function(xhr) { - var hdrs = this.headers = {}; - xhr.getAllResponseHeaders().split(/\r\n/).forEach(function(line) { - var m = /^([^:]+):(.*)$/.exec(line); + __init__(xhr) { + const hdrs = this.headers = {}; + xhr.getAllResponseHeaders().split(/\r\n/).forEach(line => { + const m = /^([^:]+):(.*)$/.exec(line); if (m != null) hdrs[m[1].trim().toLowerCase()] = m[2].trim(); }); @@ -3999,7 +3958,7 @@ * @returns {boolean} * Returns `true` if the header name is present, `false` otherwise */ - has: function(name) { + has(name) { return this.headers.hasOwnProperty(String(name).toLowerCase()); }, @@ -4015,8 +3974,8 @@ * @returns {string|null} * The value of the given header name or `null` if the header isn't present. */ - get: function(name) { - var key = String(name).toLowerCase(); + get(name) { + const key = String(name).toLowerCase(); return this.headers.hasOwnProperty(key) ? this.headers[key] : null; } }); @@ -4029,9 +3988,9 @@ * * The `Response` class is an internal utility class representing HTTP responses. */ - var Response = Class.extend({ + const Response = Class.extend({ __name__: 'LuCI.response', - __init__: function(xhr, url, duration, headers, content) { + __init__(xhr, url, duration, headers, content) { /** * Describes whether the response is successful (status codes `200..299`) or not * @instance @@ -4132,8 +4091,8 @@ * @returns {LuCI.response} * The cloned `Response` instance. */ - clone: function(content) { - var copy = new Response(this.xhr, this.url, this.duration, this.headers, content); + clone(content) { + const copy = new Response(this.xhr, this.url, this.duration, this.headers, content); copy.ok = this.ok; copy.status = this.status; @@ -4153,7 +4112,7 @@ * @returns {*} * The parsed JSON data. */ - json: function() { + json() { if (this.responseJSON == null) this.responseJSON = JSON.parse(this.responseText); @@ -4168,7 +4127,7 @@ * @returns {string} * The response content. */ - text: function() { + text() { if (this.responseText == null && this.responseJSON != null) this.responseText = JSON.stringify(this.responseJSON); @@ -4183,13 +4142,13 @@ * @returns {Blob} * The response content as blob. */ - blob: function() { + blob() { return this.responseBlob; } }); - var requestQueue = []; + const requestQueue = []; function isQueueableRequest(opt) { if (!classes.rpc) @@ -4201,7 +4160,7 @@ if (opt.nobatch === true) return false; - var rpcBaseURL = Request.expandURL(classes.rpc.getBaseURL()); + const rpcBaseURL = Request.expandURL(classes.rpc.getBaseURL()); return (rpcBaseURL != null && opt.url.indexOf(rpcBaseURL) == 0); } @@ -4210,18 +4169,17 @@ if (!requestQueue.length) return; - var reqopt = Object.assign({}, requestQueue[0][0], { content: [], nobatch: true }), - batch = []; + const reqopt = Object.assign({}, requestQueue[0][0], { content: [], nobatch: true }), batch = []; - for (var i = 0; i < requestQueue.length; i++) { + for (let i = 0; i < requestQueue.length; i++) { batch[i] = requestQueue[i]; reqopt.content[i] = batch[i][0].content; } requestQueue.length = 0; - Request.request(rpcBaseURL, reqopt).then(function(reply) { - var json = null, req = null; + Request.request(rpcBaseURL, reqopt).then(reply => { + let json = null, req = null; try { json = reply.json() } catch(e) { } @@ -4231,8 +4189,8 @@ req[2].call(reqopt, reply.clone(json.shift())); else req[1].call(reqopt, new Error('No related RPC reply')); - }).catch(function(error) { - var req = null; + }).catch(error => { + let req = null; while ((req = batch.shift()) != null) req[1].call(reqopt, error); @@ -4248,7 +4206,7 @@ * The `Request` class allows initiating HTTP requests and provides utilities * for dealing with responses. */ - var Request = Class.singleton(/** @lends LuCI.request.prototype */ { + const Request = Class.singleton(/** @lends LuCI.request.prototype */ { __name__: 'LuCI.request', interceptors: [], @@ -4265,9 +4223,9 @@ * The absolute URL derived from the given one, or the original URL * if it already was absolute. */ - expandURL: function(url) { + expandURL(url) { if (!/^(?:[^/]+:)?\/\//.test(url)) - url = location.protocol + '//' + location.host + url; + url = `${location.protocol}//${location.host}${url}`; return url; }, @@ -4332,22 +4290,22 @@ * @returns {Promise<LuCI.response>} * The resulting HTTP response. */ - request: function(target, options) { - return Promise.resolve(target).then((function(url) { - var state = { xhr: new XMLHttpRequest(), url: this.expandURL(url), start: Date.now() }, - opt = Object.assign({}, options, state), - content = null, - contenttype = null, - callback = this.handleReadyStateChange; - - return new Promise(function(resolveFn, rejectFn) { + request(target, options) { + return Promise.resolve(target).then(url => { + const state = { xhr: new XMLHttpRequest(), url: this.expandURL(url), start: Date.now() }; + const opt = Object.assign({}, options, state); + let content = null; + let contenttype = null; + const callback = this.handleReadyStateChange; + + return new Promise((resolveFn, rejectFn) => { opt.xhr.onreadystatechange = callback.bind(opt, resolveFn, rejectFn); - opt.method = String(opt.method || 'GET').toUpperCase(); + opt.method = String(opt.method ?? 'GET').toUpperCase(); if ('query' in opt) { - var q = (opt.query != null) ? Object.keys(opt.query).map(function(k) { + const q = (opt.query != null) ? Object.keys(opt.query).map(k => { if (opt.query[k] != null) { - var v = (typeof(opt.query[k]) == 'object') + const v = (typeof(opt.query[k]) == 'object') ? JSON.stringify(opt.query[k]) : String(opt.query[k]); @@ -4389,7 +4347,7 @@ else opt.xhr.open(opt.method, opt.url, true); - opt.xhr.responseType = opt.responseType || 'text'; + opt.xhr.responseType = opt.responseType ?? 'text'; if ('overrideMimeType' in opt.xhr) opt.xhr.overrideMimeType('application/octet-stream'); @@ -4422,7 +4380,7 @@ } if ('headers' in opt) - for (var header in opt.headers) + for (const header in opt.headers) if (opt.headers.hasOwnProperty(header)) { if (header.toLowerCase() != 'content-type') opt.xhr.setRequestHeader(header, opt.headers[header]); @@ -4443,12 +4401,11 @@ rejectFn.call(opt, e); } }); - }).bind(this)); + }); }, - handleReadyStateChange: function(resolveFn, rejectFn, ev) { - var xhr = this.xhr, - duration = Date.now() - this.start; + handleReadyStateChange(resolveFn, rejectFn, ev) { + const xhr = this.xhr, duration = Date.now() - this.start; if (xhr.readyState !== 4) return; @@ -4460,10 +4417,10 @@ rejectFn.call(this, new Error('XHR request aborted by browser')); } else { - var response = new Response( - xhr, xhr.responseURL || this.url, duration); + const response = new Response( + xhr, xhr.responseURL ?? this.url, duration); - Promise.all(Request.interceptors.map(function(fn) { return fn(response) })) + Promise.all(Request.interceptors.map(fn => fn(response))) .then(resolveFn.bind(this, response)) .catch(rejectFn.bind(this)); } @@ -4483,7 +4440,7 @@ * @returns {Promise<LuCI.response>} * The resulting HTTP response. */ - get: function(url, options) { + get(url, options) { return this.request(url, Object.assign({ method: 'GET' }, options)); }, @@ -4504,7 +4461,7 @@ * @returns {Promise<LuCI.response>} * The resulting HTTP response. */ - post: function(url, data, options) { + post(url, data, options) { return this.request(url, Object.assign({ method: 'POST', content: data }, options)); }, @@ -4530,7 +4487,7 @@ * @returns {LuCI.request.interceptorFn} * The registered function. */ - addInterceptor: function(interceptorFn) { + addInterceptor(interceptorFn) { if (typeof(interceptorFn) == 'function') this.interceptors.push(interceptorFn); return interceptorFn; @@ -4549,8 +4506,9 @@ * @returns {boolean} * Returns `true` if any function has been removed, else `false`. */ - removeInterceptor: function(interceptorFn) { - var oldlen = this.interceptors.length, i = oldlen; + removeInterceptor(interceptorFn) { + const oldlen = this.interceptors.length; + let i = oldlen; while (i--) if (this.interceptors[i] === interceptorFn) this.interceptors.splice(i, 1); @@ -4610,27 +4568,24 @@ * @returns {function} * Returns the internally created poll function. */ - add: function(interval, url, options, callback) { + add(interval, url, options, callback) { if (isNaN(interval) || interval <= 0) throw new TypeError('Invalid poll interval'); - var ival = interval >>> 0, - opts = Object.assign({}, options, { timeout: ival * 1000 - 5 }); + const ival = interval >>> 0, opts = Object.assign({}, options, { timeout: ival * 1000 - 5 }); - var fn = function() { - return Request.request(url, opts).then(function(res) { - if (!Poll.active()) - return; + const fn = () => Request.request(url, opts).then(res => { + if (!Poll.active()) + return; - var res_json = null; - try { - res_json = res.json(); - } - catch (err) {} + let res_json = null; + try { + res_json = res.json(); + } + catch (err) {} - callback(res, res_json, res.duration); - }); - }; + callback(res, res_json, res.duration); + }); return (Poll.add(fn, ival) ? fn : null); }, @@ -4648,7 +4603,7 @@ * @returns {boolean} * Returns `true` if any function has been removed, else `false`. */ - remove: function(entry) { return Poll.remove(entry) }, + remove(entry) { return Poll.remove(entry) }, /** * Alias for {@link LuCI.poll.start LuCI.poll.start()}. @@ -4656,7 +4611,7 @@ * @instance * @memberof LuCI.request.poll */ - start: function() { return Poll.start() }, + start() { return Poll.start() }, /** * Alias for {@link LuCI.poll.stop LuCI.poll.stop()}. @@ -4664,7 +4619,7 @@ * @instance * @memberof LuCI.request.poll */ - stop: function() { return Poll.stop() }, + stop() { return Poll.stop() }, /** * Alias for {@link LuCI.poll.active LuCI.poll.active()}. @@ -4672,7 +4627,7 @@ * @instance * @memberof LuCI.request.poll */ - active: function() { return Poll.active() } + active() { return Poll.active() } } }); @@ -4686,7 +4641,7 @@ * as well as starting, stopping and querying the state of the polling * loop. */ - var Poll = Class.singleton(/** @lends LuCI.poll.prototype */ { + const Poll = Class.singleton(/** @lends LuCI.poll.prototype */ { __name__: 'LuCI.poll', queue: [], @@ -4710,21 +4665,21 @@ * Returns `true` if the function has been added or `false` if it * already is registered. */ - add: function(fn, interval) { + add(fn, interval) { if (interval == null || interval <= 0) interval = env.pollinterval || null; if (isNaN(interval) || typeof(fn) != 'function') throw new TypeError('Invalid argument to LuCI.poll.add()'); - for (var i = 0; i < this.queue.length; i++) + for (let i = 0; i < this.queue.length; i++) if (this.queue[i].fn === fn) return false; - var e = { + const e = { r: true, i: interval >>> 0, - fn: fn + fn }; this.queue.push(e); @@ -4751,13 +4706,13 @@ * Returns `true` if the function has been removed or `false` if it * wasn't found. */ - remove: function(fn) { + remove(fn) { if (typeof(fn) != 'function') throw new TypeError('Invalid argument to LuCI.poll.remove()'); - var len = this.queue.length; + const len = this.queue.length; - for (var i = len; i > 0; i--) + for (let i = len; i > 0; i--) if (this.queue[i-1].fn === fn) this.queue.splice(i-1, 1); @@ -4777,7 +4732,7 @@ * Returns `true` if polling has been started (or if no functions * where registered) or `false` when the polling loop already runs. */ - start: function() { + start() { if (this.active()) return false; @@ -4802,7 +4757,7 @@ * Returns `true` if polling has been stopped or `false` if it didn't * run to begin with. */ - stop: function() { + stop() { if (!this.active()) return false; @@ -4814,8 +4769,8 @@ }, /* private */ - step: function() { - for (var i = 0, e = null; (e = Poll.queue[i]) != null; i++) { + step() { + for (let i = 0, e = null; (e = Poll.queue[i]) != null; i++) { if ((Poll.tick % e.i) != 0) continue; @@ -4837,7 +4792,7 @@ * @memberof LuCI.poll * @returns {boolean} - Returns `true` if polling is active, else `false`. */ - active: function() { + active() { return (this.timer != null); } }); @@ -4854,7 +4809,7 @@ * To import the class in views, use `'require dom'`, to import it in * external JavaScript, use `L.require("dom").then(...)`. */ - var DOM = Class.singleton(/** @lends LuCI.dom.prototype */ { + const DOM = Class.singleton(/** @lends LuCI.dom.prototype */ { __name__: 'LuCI.dom', /** @@ -4868,7 +4823,7 @@ * @returns {boolean} * Returns `true` if the value is a DOM `Node`, else `false`. */ - elem: function(e) { + elem(e) { return (e != null && typeof(e) == 'object' && 'nodeType' in e); }, @@ -4887,16 +4842,13 @@ * Returns the first DOM `Node` extracted from the HTML fragment or * `null` on parsing failures or if no element could be found. */ - parse: function(s) { - var elem = null; - + parse(s) { try { - domParser = domParser || new DOMParser(); - elem = domParser.parseFromString(s, 'text/html').body.firstChild; + return domParser.parseFromString(s, 'text/html').body.firstChild; + } + catch(e) { + return null; } - catch(e) {} - - return elem; }, /** @@ -4920,8 +4872,8 @@ * or `false` when the node argument is no valid DOM `Node` or the * selector didn't match. */ - matches: function(node, selector) { - var m = this.elem(node) ? node.matches || node.msMatchesSelector : null; + matches(node, selector) { + const m = this.elem(node) ? (node.matches ?? node.msMatchesSelector) : null; return m ? m.call(node, selector) : false; }, @@ -4947,7 +4899,7 @@ * `null` when the node argument is no valid DOM `Node` or the * selector didn't match any parent. */ - parent: function(node, selector) { + parent(node, selector) { if (this.elem(node) && node.closest) return node.closest(selector); @@ -4996,16 +4948,16 @@ * if either the `node` argument was no valid DOM `node` or if the * `children` was `null` or didn't result in further DOM nodes. */ - append: function(node, children) { + append(node, children) { if (!this.elem(node)) return null; if (Array.isArray(children)) { - for (var i = 0; i < children.length; i++) + for (let i = 0; i < children.length; i++) if (this.elem(children[i])) node.appendChild(children[i]); else if (children !== null && children !== undefined) - node.appendChild(document.createTextNode('' + children[i])); + node.appendChild(document.createTextNode(`${children[i]}`)); return node.lastChild; } @@ -5016,7 +4968,7 @@ return node.appendChild(children); } else if (children !== null && children !== undefined) { - node.innerHTML = '' + children; + node.innerHTML = `${children}`; return node.lastChild; } @@ -5063,13 +5015,13 @@ * if either the `node` argument was no valid DOM `node` or if the * `children` was `null` or didn't result in further DOM nodes. */ - content: function(node, children) { + content(node, children) { if (!this.elem(node)) return null; - var dataNodes = node.querySelectorAll('[data-idref]'); + const dataNodes = node.querySelectorAll('[data-idref]'); - for (var i = 0; i < dataNodes.length; i++) + for (let i = 0; i < dataNodes.length; i++) delete this.registry[dataNodes[i].getAttribute('data-idref')]; while (node.firstChild) @@ -5111,11 +5063,11 @@ * to the given `node` as-is, with the underlying `setAttribute()` * call implicitly turning it into a string. */ - attr: function(node, key, val) { + attr(node, key, val) { if (!this.elem(node)) return null; - var attr = null; + let attr = null; if (typeof(key) === 'object' && key !== null) attr = key; @@ -5189,18 +5141,18 @@ * @returns {Node} * Returns the newly created `Node`. */ - create: function() { - var html = arguments[0], - attr = arguments[1], - data = arguments[2], - elem; + create() { + const html = arguments[0]; + let attr = arguments[1]; + let data = arguments[2]; + let elem; if (!(attr instanceof Object) || Array.isArray(attr)) data = attr, attr = null; if (Array.isArray(html)) { elem = document.createDocumentFragment(); - for (var i = 0; i < html.length; i++) + for (let i = 0; i < html.length; i++) elem.appendChild(this.create(html[i])); } else if (this.elem(html)) { @@ -5237,16 +5189,16 @@ * number of arguments passed to it. * * - `dom.data(node)` - - * Fetches all data associated with the given node. + * Fetches all data associated with the given node. * - `dom.data(node, key)` - - * Fetches a specific key associated with the given node. + * Fetches a specific key associated with the given node. * - `dom.data(node, key, val)` - - * Sets a specific key to the given value associated with the - * given node. + * Sets a specific key to the given value associated with the + * given node. * - `dom.data(node, null)` - - * Clears any data associated with the node. + * Clears any data associated with the node. * - `dom.data(node, key, null)` - - * Clears the given key associated with the node. + * Clears the given key associated with the node. * * @instance * @memberof LuCI.dom @@ -5265,11 +5217,11 @@ * Returns the get or set value, or `null` when no value could * be found. */ - data: function(node, key, val) { - if (!node || !node.getAttribute) + data(node, key, val) { + if (!node?.getAttribute) return null; - var id = node.getAttribute('data-idref'); + let id = node.getAttribute('data-idref'); /* clear all data */ if (arguments.length > 1 && key == null) { @@ -5348,7 +5300,7 @@ * @returns {Class} * Returns the bound class instance. */ - bindClassInstance: function(node, inst) { + bindClassInstance(node, inst) { if (!(inst instanceof Class)) LuCI.prototype.error('TypeError', 'Argument must be a class instance'); @@ -5368,8 +5320,8 @@ * Returns the founds class instance if any or `null` if no bound * class could be found on the node itself or any of its parents. */ - findClassInstance: function(node) { - var inst = null; + findClassInstance(node) { + let inst = null; do { inst = this.data(node, '_class'); @@ -5402,13 +5354,13 @@ * no bound class instance could be found, or if the found * instance didn't have the requested `method`. */ - callClassMethod: function(node, method /*, ... */) { - var inst = this.findClassInstance(node); + callClassMethod(node, method, ...args) { + const inst = this.findClassInstance(node); - if (inst == null || typeof(inst[method]) != 'function') + if (typeof(inst?.[method]) != 'function') return null; - return inst[method].apply(inst, inst.varargs(arguments, 2)); + return inst[method].call(inst, ...args); }, /** @@ -5448,9 +5400,9 @@ * any children node either has a `hidden` CSS class or a `false` * result when testing it using the given `ignoreFn`. */ - isEmpty: function(node, ignoreFn) { - for (var child = node.firstElementChild; child != null; child = child.nextElementSibling) - if (!child.classList.contains('hidden') && (!ignoreFn || !ignoreFn(child))) + isEmpty(node, ignoreFn) { + for (let child = node?.firstElementChild; child != null; child = child.nextElementSibling) + if (!child.classList.contains('hidden') && !ignoreFn?.(child)) return false; return true; @@ -5465,7 +5417,7 @@ * * The `session` class provides various session related functionality. */ - var Session = Class.singleton(/** @lends LuCI.session.prototype */ { + const Session = Class.singleton(/** @lends LuCI.session.prototype */ { __name__: 'LuCI.session', /** @@ -5474,8 +5426,8 @@ * @returns {string} * Returns the current session ID. */ - getID: function() { - return env.sessionid || '00000000000000000000000000000000'; + getID() { + return env.sessionid ?? '00000000000000000000000000000000'; }, /** @@ -5484,8 +5436,8 @@ * @returns {string|null} * Returns the current session token or `null` if not logged in. */ - getToken: function() { - return env.token || null; + getToken() { + return env.token ?? null; }, /** @@ -5499,11 +5451,11 @@ * Returns the stored session data or `null` if the given key wasn't * found. */ - getLocalData: function(key) { + getLocalData(key) { try { - var sid = this.getID(), - item = 'luci-session-store', - data = JSON.parse(window.sessionStorage.getItem(item)); + const sid = this.getID(); + const item = 'luci-session-store'; + let data = JSON.parse(window.sessionStorage.getItem(item)); if (!LuCI.prototype.isObject(data) || !data.hasOwnProperty(sid)) { data = {}; @@ -5533,14 +5485,14 @@ * @returns {boolean} * Returns `true` if the data could be stored or `false` on error. */ - setLocalData: function(key, value) { + setLocalData(key, value) { if (key == null) return false; try { - var sid = this.getID(), - item = 'luci-session-store', - data = JSON.parse(window.sessionStorage.getItem(item)); + const sid = this.getID(); + const item = 'luci-session-store'; + let data = JSON.parse(window.sessionStorage.getItem(item)); if (!LuCI.prototype.isObject(data) || !data.hasOwnProperty(sid)) { data = {}; @@ -5571,18 +5523,18 @@ * The `view` class forms the basis of views and provides a standard * set of methods to inherit from. */ - var View = Class.extend(/** @lends LuCI.view.prototype */ { + const View = Class.extend(/** @lends LuCI.view.prototype */ { __name__: 'LuCI.view', - __init__: function() { - var vp = document.getElementById('view'); + __init__() { + const vp = document.getElementById('view'); DOM.content(vp, E('div', { 'class': 'spinning' }, _('Loading view…'))); return Promise.resolve(this.load()) .then(LuCI.prototype.bind(this.render, this)) .then(LuCI.prototype.bind(function(nodes) { - var vp = document.getElementById('view'); + const vp = document.getElementById('view'); DOM.content(vp, nodes); DOM.append(vp, this.addFooter()); @@ -5609,7 +5561,7 @@ * @returns {*|Promise<*>} * May return any value or a Promise resolving to any value. */ - load: function() {}, + load() {}, /** * The render function is invoked after the @@ -5641,7 +5593,7 @@ * Should return a DOM `Node` value or a `Promise` resolving * to a `Node` value. */ - render: function() {}, + render() {}, /** * The handleSave function is invoked when the user clicks @@ -5674,11 +5626,11 @@ * returned promise runs to completion before the button * is re-enabled. */ - handleSave: function(ev) { - var tasks = []; + handleSave(ev) { + const tasks = []; document.getElementById('maincontent') - .querySelectorAll('.cbi-map').forEach(function(map) { + .querySelectorAll('.cbi-map').forEach(map => { tasks.push(DOM.callClassMethod(map, 'save')); }); @@ -5718,8 +5670,8 @@ * returned promise runs to completion before the button * is re-enabled. */ - handleSaveApply: function(ev, mode) { - return this.handleSave(ev).then(function() { + handleSaveApply(ev, mode) { + return this.handleSave(ev).then(() => { classes.ui.changes.apply(mode == '0'); }); }, @@ -5755,11 +5707,11 @@ * returned promise runs to completion before the button * is re-enabled. */ - handleReset: function(ev) { - var tasks = []; + handleReset(ev) { + const tasks = []; document.getElementById('maincontent') - .querySelectorAll('.cbi-map').forEach(function(map) { + .querySelectorAll('.cbi-map').forEach(map => { tasks.push(DOM.callClassMethod(map, 'reset')); }); @@ -5789,14 +5741,14 @@ * or an empty `DocumentFragment` if all three `handle*()` * methods are overwritten with `null`. */ - addFooter: function() { - var footer = E([]), - vp = document.getElementById('view'), - hasmap = false, - readonly = true; - - vp.querySelectorAll('.cbi-map').forEach(function(map) { - var m = DOM.findClassInstance(map); + addFooter() { + const footer = E([]); + const vp = document.getElementById('view'); + let hasmap = false; + let readonly = true; + + vp.querySelectorAll('.cbi-map').forEach(map => { + const m = DOM.findClassInstance(map); if (m) { hasmap = true; @@ -5808,7 +5760,7 @@ if (!hasmap) readonly = !LuCI.prototype.hasViewPermission(); - var saveApplyBtn = this.handleSaveApply ? new classes.ui.ComboButton('0', { + const saveApplyBtn = this.handleSaveApply ? new classes.ui.ComboButton('0', { 0: [ _('Save & Apply') ], 1: [ _('Apply unchecked') ] }, { @@ -5841,15 +5793,14 @@ }); - var dummyElem = null, - domParser = null, - originalCBIInit = null, - rpcBaseURL = null, - sysFeatures = null, - preloadClasses = null; + const domParser = new DOMParser(); + let originalCBIInit = null; + let rpcBaseURL = null; + let sysFeatures = null; + let preloadClasses = null; /* "preload" builtin classes to make the available via require */ - var classes = { + const classes = { baseclass: Class, dom: DOM, poll: Poll, @@ -5858,15 +5809,15 @@ view: View }; - var naturalCompare = new Intl.Collator(undefined, { numeric: true }).compare; + const naturalCompare = new Intl.Collator(undefined, { numeric: true }).compare; - var LuCI = Class.extend(/** @lends LuCI.prototype */ { + const LuCI = Class.extend(/** @lends LuCI.prototype */ { __name__: 'LuCI', - __init__: function(setenv) { + __init__(setenv) { - document.querySelectorAll('script[src*="/luci.js"]').forEach(function(s) { + document.querySelectorAll('script[src*="/luci.js"]').forEach(s => { if (setenv.base_url == null || setenv.base_url == '') { - var m = (s.getAttribute('src') || '').match(/^(.*)\/luci\.js(?:\?v=([^?]+))?$/); + const m = (s.getAttribute('src') ?? '').match(/^(.*)\/luci\.js(?:\?v=([^?]+))?$/); if (m) { setenv.base_url = m[1]; setenv.resource_version = m[2]; @@ -5881,7 +5832,7 @@ Object.assign(env, setenv); - var domReady = new Promise(function(resolveFn, rejectFn) { + const domReady = new Promise((resolveFn, rejectFn) => { document.addEventListener('DOMContentLoaded', resolveFn); }); @@ -5894,7 +5845,7 @@ ]).then(this.setupDOM.bind(this)).catch(this.error); originalCBIInit = window.cbi_init; - window.cbi_init = function() {}; + window.cbi_init = () => {}; }, /** @@ -5921,29 +5872,29 @@ * appended to the message and the type set to the given type * argument or copied from the given error instance. */ - raise: function(type, fmt /*, ...*/) { - var e = null, - msg = fmt ? String.prototype.format.apply(fmt, this.varargs(arguments, 2)) : null, - stack = null; + raise(type, fmt, ...args) { + let e = null; + const msg = fmt ? String.prototype.format.call(fmt, ...args) : null; + const stack = []; if (type instanceof Error) { e = type; if (msg) - e.message = msg + ': ' + e.message; + e.message = `${msg}: ${e.message}`; } else { try { throw new Error('stacktrace') } - catch (e2) { stack = (e2.stack || '').split(/\n/) } + catch (e2) { stack.push(...(e2.stack ?? '').split(/\n/)) } - e = new (window[type || 'Error'] || Error)(msg || 'Unspecified error'); - e.name = type || 'Error'; + e = new (window[type ?? 'Error'] ?? Error)(msg ?? 'Unspecified error'); + e.name = type ?? 'Error'; } - stack = (stack || []).map(function(frame) { - frame = frame.replace(/(.*?)@(.+):(\d+):(\d+)/g, 'at $1 ($2:$3:$4)').trim(); - return frame ? ' ' + frame : ''; - }); + for (let i = 0; i < stack.length; i++) { + const frame = stack[i].replace(/(.*?)@(.+):(\d+):(\d+)/g, 'at $1 ($2:$3:$4)').trim(); + stack[i] = frame ? ` ${frame}` : ''; + } if (!/^ at /.test(stack[0])) stack.shift(); @@ -5955,7 +5906,7 @@ stack.shift(); if (stack.length) - e.message += '\n' + stack.join('\n'); + e.message += `\n${stack.join('\n')}`; if (window.console && console.debug) console.debug(e); @@ -5987,7 +5938,7 @@ * appended to the message and the type set to the given type * argument or copied from the given error instance. */ - error: function(type, fmt /*, ...*/) { + error(type, fmt /*, ...*/) { try { LuCI.prototype.raise.apply(LuCI.prototype, Array.prototype.slice.call(arguments)); @@ -6028,8 +5979,8 @@ * @returns {function} * Returns the bound function. */ - bind: function(fn, self /*, ... */) { - return Function.prototype.bind.apply(fn, this.varargs(arguments, 2, self)); + bind(fn, self, ...args) { + return Function.prototype.bind.call(fn, self, ...args); }, /** @@ -6067,8 +6018,9 @@ * @returns {Promise<LuCI.baseclass>} * Returns the instantiated class. */ - require: function(name, from) { - var L = this, url = null, from = from || []; + require(name, from = []) { + const L = this; + let url = null; /* Class already loaded */ if (classes[name] != null) { @@ -6081,23 +6033,23 @@ return Promise.resolve(classes[name]); } - url = '%s/%s.js%s'.format(env.base_url, name.replace(/\./g, '/'), (env.resource_version ? '?v=' + env.resource_version : '')); + url = '%s/%s.js%s'.format(env.base_url, name.replace(/\./g, '/'), (env.resource_version ? `?v=${env.resource_version}` : '')); from = [ name ].concat(from); - var compileClass = function(res) { + const compileClass = res => { if (!res.ok) LuCI.prototype.raise('NetworkError', 'HTTP error %d while loading class file "%s"', res.status, url); - var source = res.text(), - requirematch = /^require[ \t]+(\S+)(?:[ \t]+as[ \t]+([a-zA-Z_]\S*))?$/, - strictmatch = /^use[ \t]+strict$/, - depends = [], - args = ''; + const source = res.text(); + const requirematch = /^require[ \t]+(\S+)(?:[ \t]+as[ \t]+([a-zA-Z_]\S*))?$/; + const strictmatch = /^use[ \t]+strict$/; + const depends = []; + let args = ''; /* find require statements in source */ - for (var i = 0, off = -1, prev = -1, quote = -1, comment = -1, esc = false; i < source.length; i++) { - var chr = source.charCodeAt(i); + for (let i = 0, off = -1, prev = -1, quote = -1, comment = -1, esc = false; i < source.length; i++) { + const chr = source.charCodeAt(i); if (esc) { esc = false; @@ -6113,13 +6065,12 @@ esc = true; } else if (chr == quote) { - var s = source.substring(off, i), - m = requirematch.exec(s); + const s = source.substring(off, i), m = requirematch.exec(s); if (m) { - var dep = m[1], as = m[2] || dep.replace(/[^a-zA-Z0-9_]/g, '_'); + const dep = m[1], as = m[2] || dep.replace(/[^a-zA-Z0-9_]/g, '_'); depends.push(LuCI.prototype.require(dep, from)); - args += ', ' + as; + args += `, ${as}`; } else if (!strictmatch.exec(s)) { break; @@ -6137,8 +6088,8 @@ } /* load dependencies and instantiate class */ - return Promise.all(depends).then(function(instances) { - var _factory, _class; + return Promise.all(depends).then(instances => { + let _factory, _class; try { _factory = eval( @@ -6147,27 +6098,28 @@ } catch (error) { LuCI.prototype.raise('SyntaxError', '%s\n in %s:%s', - error.message, res.url, error.lineNumber || '?'); + error.message, res.url, error.lineNumber ?? '?'); } - _factory.displayName = toCamelCase(name + 'ClassFactory'); + _factory.displayName = toCamelCase(`${name}ClassFactory`); _class = _factory.apply(_factory, [window, document, L].concat(instances)); if (!Class.isSubclass(_class)) - LuCI.prototype.error('TypeError', '"%s" factory yields invalid constructor', name); + LuCI.prototype.error('TypeError', '"%s" factory yields invalid constructor', name); if (_class.displayName == 'AnonymousClass') - _class.displayName = toCamelCase(name + 'Class'); + _class.displayName = toCamelCase(`${name}Class`); - var ptr = Object.getPrototypeOf(L), - parts = name.split(/\./), - instance = new _class(); + let ptr = Object.getPrototypeOf(L); + let idx = 0; + const parts = name.split(/\./); + const instance = new _class(); - for (var i = 0; ptr && i < parts.length - 1; i++) - ptr = ptr[parts[i]]; + while (ptr && idx < parts.length - 1) + ptr = ptr[parts[idx++]]; if (ptr) - ptr[parts[i]] = instance; + ptr[parts[idx]] = instance; classes[name] = instance; @@ -6182,24 +6134,20 @@ }, /* DOM setup */ - probeRPCBaseURL: function() { + probeRPCBaseURL() { if (rpcBaseURL == null) rpcBaseURL = Session.getLocalData('rpcBaseURL'); if (rpcBaseURL == null) { - var msg = { + const msg = { jsonrpc: '2.0', - id: 'init', + id: 'init', method: 'list', params: undefined }; - var rpcFallbackURL = this.url('admin/ubus'); + const rpcFallbackURL = this.url('admin/ubus'); - rpcBaseURL = Request.post(env.ubuspath, msg, { nobatch: true }).then(function(res) { - return (rpcBaseURL = res.status == 200 ? env.ubuspath : rpcFallbackURL); - }, function() { - return (rpcBaseURL = rpcFallbackURL); - }).then(function(url) { + rpcBaseURL = Request.post(env.ubuspath, msg, { nobatch: true }).then(res => rpcBaseURL = res.status == 200 ? env.ubuspath : rpcFallbackURL, () => rpcBaseURL = rpcFallbackURL).then(url => { Session.setLocalData('rpcBaseURL', url); return url; }); @@ -6208,7 +6156,7 @@ return Promise.resolve(rpcBaseURL); }, - probeSystemFeatures: function() { + probeSystemFeatures() { if (sysFeatures == null) sysFeatures = Session.getLocalData('features'); @@ -6217,7 +6165,7 @@ object: 'luci', method: 'getFeatures', expect: { '': {} } - })().then(function(features) { + })().then(features => { Session.setLocalData('features', features); sysFeatures = features; @@ -6228,7 +6176,7 @@ return Promise.resolve(sysFeatures); }, - probePreloadClasses: function() { + probePreloadClasses() { if (preloadClasses == null) preloadClasses = Session.getLocalData('preload'); @@ -6238,14 +6186,14 @@ method: 'list', params: [ 'path' ], expect: { 'entries': [] } - })(this.fspath(this.resource('preload'))), []).then(function(entries) { - var classes = []; + })(this.fspath(this.resource('preload'))), []).then(entries => { + const classes = []; - for (var i = 0; i < entries.length; i++) { + for (let i = 0; i < entries.length; i++) { if (entries[i].type != 'file') continue; - var m = entries[i].name.match(/(.+)\.js$/); + const m = entries[i].name.match(/(.+)\.js$/); if (m) classes.push('preload.%s'.format(m[1])); @@ -6286,8 +6234,8 @@ * Return `null` when a sub-feature was queried for a feature which * has no sub-features. */ - hasSystemFeature: function() { - var ft = sysFeatures[arguments[0]]; + hasSystemFeature() { + const ft = sysFeatures[arguments[0]]; if (arguments.length == 2) return this.isObject(ft) ? ft[arguments[1]] : null; @@ -6296,7 +6244,7 @@ }, /* private */ - notifySessionExpiry: function() { + notifySessionExpiry() { Poll.stop(); classes.ui.showModal(_('Session expired'), [ @@ -6305,9 +6253,9 @@ E('div', { class: 'right' }, E('div', { class: 'btn primary', - click: function() { - var loc = window.location; - window.location = loc.protocol + '//' + loc.host + loc.pathname + loc.search; + click() { + const loc = window.location; + window.location = `${loc.protocol}//${loc.host}${loc.pathname}${loc.search}`; } }, _('Log in…'))) ]); @@ -6316,23 +6264,19 @@ }, /* private */ - setupDOM: function(res) { - var domEv = res[0], - uiClass = res[1], - rpcClass = res[2], - formClass = res[3], - rpcBaseURL = res[4]; + setupDOM(res) { + const domEv = res[0], uiClass = res[1], rpcClass = res[2], formClass = res[3], rpcBaseURL = res[4]; rpcClass.setBaseURL(rpcBaseURL); - rpcClass.addInterceptor(function(msg, req) { + rpcClass.addInterceptor((msg, req) => { if (!LuCI.prototype.isObject(msg) || - !LuCI.prototype.isObject(msg.error) || - msg.error.code != -32002) + !LuCI.prototype.isObject(msg.error) || + msg.error.code != -32002) return; if (!LuCI.prototype.isObject(req) || - (req.object == 'session' && req.method == 'access')) + (req.object == 'session' && req.method == 'access')) return; return rpcClass.declare({ @@ -6343,8 +6287,8 @@ })('uci', 'luci', 'read').catch(LuCI.prototype.notifySessionExpiry); }); - Request.addInterceptor(function(res) { - var isDenied = false; + Request.addInterceptor(res => { + let isDenied = false; if (res.status == 403 && res.headers.get('X-LuCI-Login-Required') == 'yes') isDenied = true; @@ -6355,13 +6299,13 @@ LuCI.prototype.notifySessionExpiry(); }); - document.addEventListener('poll-start', function(ev) { - uiClass.showIndicator('poll-status', _('Refreshing'), function(ev) { + document.addEventListener('poll-start', ev => { + uiClass.showIndicator('poll-status', _('Refreshing'), ev => { Request.poll.active() ? Request.poll.stop() : Request.poll.start(); }); }); - document.addEventListener('poll-stop', function(ev) { + document.addEventListener('poll-stop', ev => { uiClass.showIndicator('poll-status', _('Paused'), null, 'inactive'); }); @@ -6369,10 +6313,10 @@ this.probeSystemFeatures(), this.probePreloadClasses() ]).finally(LuCI.prototype.bind(function() { - var tasks = []; + const tasks = []; if (Array.isArray(preloadClasses)) - for (var i = 0; i < preloadClasses.length; i++) + for (let i = 0; i < preloadClasses.length; i++) tasks.push(this.require(preloadClasses[i])); return Promise.all(tasks); @@ -6380,7 +6324,7 @@ }, /* private */ - initDOM: function() { + initDOM() { originalCBIInit(); Poll.start(); document.dispatchEvent(new CustomEvent('luci-loaded')); @@ -6393,7 +6337,7 @@ * @instance * @memberof LuCI */ - env: env, + env, /** * Construct an absolute filesystem path relative to the server @@ -6408,16 +6352,15 @@ * @return {string} * Return the joined path. */ - fspath: function(/* ... */) { - var path = env.documentroot; + fspath() /* ... */{ + let path = env.documentroot; - for (var i = 0; i < arguments.length; i++) - path += '/' + arguments[i]; + for (let i = 0; i < arguments.length; i++) + path += `/${arguments[i]}`; - var p = path.replace(/\/+$/, '').replace(/\/+/g, '/').split(/\//), - res = []; + const p = path.replace(/\/+$/, '').replace(/\/+/g, '/').split(/\//), res = []; - for (var i = 0; i < p.length; i++) + for (let i = 0; i < p.length; i++) if (p[i] == '..') res.pop(); else if (p[i] != '.') @@ -6448,10 +6391,10 @@ * @return {string} * Return the joined URL path. */ - path: function(prefix, parts) { - var url = [ prefix || '' ]; + path(prefix = '', parts) { + const url = [ prefix ]; - for (var i = 0; i < parts.length; i++) + for (let i = 0; i < parts.length; i++) if (/^(?:[a-zA-Z0-9_.%,;-]+\/)*[a-zA-Z0-9_.%,;-]+$/.test(parts[i]) || /^\?[a-zA-Z0-9_.%=&;-]+$/.test(parts[i])) url.push(parts[i].startsWith('?') ? parts[i] : '/' + parts[i]); @@ -6481,7 +6424,7 @@ * @return {string} * Returns the resulting URL path. */ - url: function() { + url() { return this.path(env.scriptname, arguments); }, @@ -6505,7 +6448,7 @@ * @return {string} * Returns the resulting URL path. */ - resource: function() { + resource() { return this.path(env.resource, arguments); }, @@ -6529,7 +6472,7 @@ * @return {string} * Returns the resulting URL path. */ - media: function() { + media() { return this.path(env.media, arguments); }, @@ -6542,7 +6485,7 @@ * @return {string} * Returns the URL path to the current view. */ - location: function() { + location() { return this.path(env.scriptname, env.requestpath); }, @@ -6562,10 +6505,27 @@ * Returns `true` if the given value is of type object and * not `null`, else returns `false`. */ - isObject: function(val) { + isObject(val) { return (val != null && typeof(val) == 'object'); }, + /** + * Tests whether the passed argument is a function arguments object. + * + * @instance + * @memberof LuCI + * + * @param {*} [val] + * The value to test + * + * @return {boolean} + * Returns `true` if the given value is a function arguments object, + * else returns `false`. + */ + isArguments(val) { + return (Object.prototype.toString.call(val) == '[object Arguments]'); + }, + /** * Return an array of sorted object keys, optionally sorted by * a different key or a different sorting mode. @@ -6591,17 +6551,17 @@ * @return {string[]} * Returns an array containing the sorted keys of the given object. */ - sortedKeys: function(obj, key, sortmode) { + sortedKeys(obj, key, sortmode) { if (obj == null || typeof(obj) != 'object') return []; - return Object.keys(obj).map(function(e) { - var v = (key != null) ? obj[e][key] : e; + return Object.keys(obj).map(e => { + let v = (key != null) ? obj[e][key] : e; switch (sortmode) { case 'addr': v = (v != null) ? v.replace(/(?:^|[.:])([0-9a-fA-F]{1,4})/g, - function(m0, m1) { return ('000' + m1.toLowerCase()).substr(-4) }) : null; + (m0, m1) => (`000${m1.toLowerCase()}`).substr(-4)) : null; break; case 'num': @@ -6610,13 +6570,7 @@ } return [ e, v ]; - }).filter(function(e) { - return (e[1] != null); - }).sort(function(a, b) { - return naturalCompare(a[1], b[1]); - }).map(function(e) { - return e[0]; - }); + }).filter(e => e[1] != null).sort((a, b) => naturalCompare(a[1], b[1])).map(e => e[0]); }, /** @@ -6640,7 +6594,7 @@ * Returns 0 if both values are equal. * Returns 1 if the first value is larger than the second one. */ - naturalCompare: naturalCompare, + naturalCompare, /** * Converts the given value to an array using toArray() if needed, @@ -6657,7 +6611,7 @@ * @return {Array<*>} * Returns the resulting, numerically sorted array. */ - sortedArray: function(val) { + sortedArray(val) { return this.toArray(val).sort(naturalCompare); }, @@ -6678,7 +6632,7 @@ * @return {Array<*>} * Returns the resulting array. */ - toArray: function(val) { + toArray(val) { if (val == null) return []; else if (Array.isArray(val)) @@ -6686,7 +6640,7 @@ else if (typeof(val) == 'object') return [ val ]; - var s = String(val).trim(); + const s = String(val).trim(); if (s == '') return []; @@ -6712,8 +6666,8 @@ * Returns a new promise resolving either to the given input value or * to the given default value on error. */ - resolveDefault: function(value, defvalue) { - return Promise.resolve(value).catch(function() { return defvalue }); + resolveDefault(value, defvalue) { + return Promise.resolve(value).catch(() => defvalue); }, /** @@ -6757,7 +6711,7 @@ * @return {Promise<null>} * Returns a promise resolving to `null` when concluded. */ - get: function(url, args, cb) { + get(url, args, cb) { return this.poll(null, url, args, cb, false); }, @@ -6785,7 +6739,7 @@ * @return {Promise<null>} * Returns a promise resolving to `null` when concluded. */ - post: function(url, args, cb) { + post(url, args, cb) { return this.poll(null, url, args, cb, true); }, @@ -6827,25 +6781,22 @@ * be passed to {@link LuCI.poll.remove Poll.remove()} to remove the * polling request. */ - poll: function(interval, url, args, cb, post) { + poll(interval, url, args, cb, post) { if (interval !== null && interval <= 0) interval = env.pollinterval; - var data = post ? { token: env.token } : null, - method = post ? 'POST' : 'GET'; + const data = Object.assign(post ? { token: env.token } : {}, args); + const method = post ? 'POST' : 'GET'; if (!/^(?:\/|\S+:\/\/)/.test(url)) url = this.url(url); - if (args != null) - data = Object.assign(data || {}, args); - if (interval !== null) - return Request.poll.add(interval, url, { method: method, query: data }, cb); + return Request.poll.add(interval, url, { method, query: data }, cb); else - return Request.request(url, { method: method, query: data }) - .then(function(res) { - var json = null; + return Request.request(url, { method, query: data }) + .then(res => { + let json = null; if (/^application\/json\b/.test(res.headers.get('Content-Type'))) try { json = res.json() } catch(e) {} cb(res.xhr, json, res.duration); @@ -6861,9 +6812,9 @@ * permissions are granted or `true` if at least one required ACL * group is granted with write permissions. */ - hasViewPermission: function() { + hasViewPermission() { if (!this.isObject(env.nodespec) || !env.nodespec.satisfied) - return null; + return null; return !env.nodespec.readonly; }, @@ -6882,7 +6833,7 @@ * Returns `true` when the function has been removed or `false` if * it could not be found. */ - stop: function(entry) { return Poll.remove(entry) }, + stop(entry) { return Poll.remove(entry) }, /** * Deprecated wrapper around {@link LuCI.poll.stop Poll.stop()}. @@ -6895,7 +6846,7 @@ * Returns `true` when the polling loop has been stopped or `false` * when it didn't run to begin with. */ - halt: function() { return Poll.stop() }, + halt() { return Poll.stop() }, /** * Deprecated wrapper around {@link LuCI.poll.start Poll.start()}. @@ -6908,7 +6859,7 @@ * Returns `true` when the polling loop has been started or `false` * when it was already running. */ - run: function() { return Poll.start() }, + run() { return Poll.start() }, /** * Legacy `L.dom` class alias. New view code should use `'require dom';` @@ -6938,7 +6889,7 @@ * @memberof LuCI * @deprecated */ - Poll: Poll, + Poll, /** * Legacy `L.Request` class alias. New view code should use `'require request';` @@ -6948,7 +6899,7 @@ * @memberof LuCI * @deprecated */ - Request: Request, + Request, /** * Legacy `L.Class` class alias. New view code should use `'require baseclass';` @@ -6958,7 +6909,7 @@ * @memberof LuCI * @deprecated */ - Class: Class + Class }); /** @@ -6974,14 +6925,14 @@ * New code should use {@link LuCI.request} instead to implement HTTP * request handling. */ - var XHR = Class.extend(/** @lends LuCI.xhr.prototype */ { + const XHR = Class.extend(/** @lends LuCI.xhr.prototype */ { __name__: 'LuCI.xhr', - __init__: function() { + __init__() { if (window.console && console.debug) console.debug('Direct use XHR() is deprecated, please use L.Request instead'); }, - _response: function(cb, res, json, duration) { + _response(cb, res, json, duration) { if (this.active) cb(res, json, duration); delete this.active; @@ -7009,7 +6960,7 @@ * * @return {Promise<null>} */ - get: function(url, data, callback, timeout) { + get(url, data, callback, timeout) { this.active = true; LuCI.prototype.get(url, data, this._response.bind(this, callback), timeout); }, @@ -7036,7 +6987,7 @@ * * @return {Promise<null>} */ - post: function(url, data, callback, timeout) { + post(url, data, callback, timeout) { this.active = true; LuCI.prototype.post(url, data, this._response.bind(this, callback), timeout); }, @@ -7053,7 +7004,7 @@ * @deprecated * @memberof LuCI.xhr */ - cancel: function() { delete this.active }, + cancel() { delete this.active }, /** * Checks the running state of the request. @@ -7066,7 +7017,7 @@ * Returns `true` if the request is still running or `false` if it * already completed. */ - busy: function() { return (this.active === true) }, + busy() { return (this.active === true) }, /** * Ignored for backwards compatibility. @@ -7077,7 +7028,7 @@ * @deprecated * @memberof LuCI.xhr */ - abort: function() {}, + abort() {}, /** * Existing for backwards compatibility. @@ -7092,12 +7043,12 @@ * Throws an `InternalError` with the message `Not implemented` * when invoked. */ - send_form: function() { LuCI.prototype.error('InternalError', 'Not implemented') }, + send_form() { LuCI.prototype.error('InternalError', 'Not implemented') }, }); - XHR.get = function() { return LuCI.prototype.get.apply(LuCI.prototype, arguments) }; - XHR.post = function() { return LuCI.prototype.post.apply(LuCI.prototype, arguments) }; - XHR.poll = function() { return LuCI.prototype.poll.apply(LuCI.prototype, arguments) }; + XHR.get = (...args) => LuCI.prototype.get.call(LuCI.prototype, ...args); + XHR.post = (...args) => LuCI.prototype.post.call(LuCI.prototype, ...args); + XHR.poll = (...args) => LuCI.prototype.poll.call(LuCI.prototype, ...args); XHR.stop = Request.poll.remove.bind(Request.poll); XHR.halt = Request.poll.stop.bind(Request.poll); XHR.run = Request.poll.start.bind(Request.poll); @@ -7118,7 +7069,7 @@ diff --git a/jsapi/network.js.html b/jsapi/network.js.html index f21257d410..7b91dfbd12 100644 --- a/jsapi/network.js.html +++ b/jsapi/network.js.html @@ -86,6 +86,8 @@
  • hasViewPermission
  • +
  • isArguments
  • +
  • isObject
  • location
  • @@ -8087,7 +8089,7 @@ return Network; diff --git a/jsapi/rpc.js.html b/jsapi/rpc.js.html index e32c3ca020..531f6911d6 100644 --- a/jsapi/rpc.js.html +++ b/jsapi/rpc.js.html @@ -86,6 +86,8 @@
  • hasViewPermission
  • +
  • isArguments
  • +
  • isObject
  • location
  • @@ -3640,10 +3642,10 @@ 'require baseclass'; 'require request'; -var rpcRequestID = 1, - rpcSessionID = L.env.sessionid || '00000000000000000000000000000000', - rpcBaseURL = L.url('admin/ubus'), - rpcInterceptorFns = []; +let rpcRequestID = 1; +let rpcSessionID = L.env.sessionid ?? '00000000000000000000000000000000'; +let rpcBaseURL = L.url('admin/ubus'); +const rpcInterceptorFns = []; /** * @class rpc @@ -3656,14 +3658,14 @@ var rpcRequestID = 1, */ return baseclass.extend(/** @lends LuCI.rpc.prototype */ { /* privates */ - call: function(req, cb, nobatch) { - var q = ''; + call(req, cb, nobatch) { + let q = ''; if (Array.isArray(req)) { if (req.length == 0) return Promise.resolve([]); - for (var i = 0; i < req.length; i++) + for (let i = 0; i < req.length; i++) if (req[i].params) q += '%s%s.%s'.format( q ? ';' : '/', @@ -3673,14 +3675,14 @@ return baseclass.extend(/** @lends LuCI.rpc.prototype */ { } return request.post(rpcBaseURL + q, req, { - timeout: (L.env.rpctimeout || 20) * 1000, - nobatch: nobatch, + timeout: (L.env.rpctimeout ?? 20) * 1000, + nobatch, credentials: true }).then(cb, cb); }, - parseCallReply: function(req, res) { - var msg = null; + parseCallReply(req, res) { + let msg = null; if (res instanceof Error) return req.reject(res); @@ -3700,14 +3702,14 @@ return baseclass.extend(/** @lends LuCI.rpc.prototype */ { * The interceptor args are intentionally swapped. * Response is passed as first arg to align with Request class interceptors */ - Promise.all(rpcInterceptorFns.map(function(fn) { return fn(msg, req) })) + Promise.all(rpcInterceptorFns.map(fn => fn(msg, req))) .then(this.handleCallReply.bind(this, req, msg)) .catch(req.reject); }, - handleCallReply: function(req, msg) { - var type = Object.prototype.toString, - ret = null; + handleCallReply(req, msg) { + const type = Object.prototype.toString; + let ret = null; try { /* verify message frame */ @@ -3736,7 +3738,7 @@ return baseclass.extend(/** @lends LuCI.rpc.prototype */ { } if (req.expect) { - for (var key in req.expect) { + for (const key in req.expect) { if (ret != null && key != '') ret = ret[key]; @@ -3778,20 +3780,17 @@ return baseclass.extend(/** @lends LuCI.rpc.prototype */ { * more arguments, a promise resolving to an object describing the method * signatures of each requested `ubus` object name will be returned. */ - list: function() { - var msg = { + list(...args) { + const msg = { jsonrpc: '2.0', id: rpcRequestID++, method: 'list', - params: arguments.length ? this.varargs(arguments) : undefined + params: args.length ? args : undefined }; - return new Promise(L.bind(function(resolveFn, rejectFn) { + return new Promise(L.bind(function(resolve, reject) { /* store request info */ - var req = { - resolve: resolveFn, - reject: rejectFn - }; + const req = { resolve, reject }; /* call rpc */ this.call(msg, this.parseCallReply.bind(this, req)); @@ -3934,37 +3933,36 @@ return baseclass.extend(/** @lends LuCI.rpc.prototype */ { * Returns a new function implementing the method call described in * `options`. */ - declare: function(options) { - return Function.prototype.bind.call(function(rpc, options) { - var args = this.varargs(arguments, 2); - return new Promise(function(resolveFn, rejectFn) { + declare(options) { + return Function.prototype.bind.call(function(rpc, options, ...args) { + return new Promise((resolve, reject) => { /* build parameter object */ - var p_off = 0; - var params = { }; + let p_off = 0; + const params = { }; if (Array.isArray(options.params)) for (p_off = 0; p_off < options.params.length; p_off++) params[options.params[p_off]] = args[p_off]; /* all remaining arguments are private args */ - var priv = [ undefined, undefined ]; + const priv = [ undefined, undefined ]; for (; p_off < args.length; p_off++) priv.push(args[p_off]); /* store request info */ - var req = { + const req = { expect: options.expect, filter: options.filter, - resolve: resolveFn, - reject: rejectFn, - params: params, - priv: priv, + resolve, + reject, + params, + priv, object: options.object, method: options.method, raise: options.reject }; /* build message object */ - var msg = { + const msg = { jsonrpc: '2.0', id: rpcRequestID++, method: 'call', @@ -3989,7 +3987,7 @@ return baseclass.extend(/** @lends LuCI.rpc.prototype */ { * Returns the 32 byte session ID string used for authenticating remote * requests. */ - getSessionID: function() { + getSessionID() { return rpcSessionID; }, @@ -4000,7 +3998,7 @@ return baseclass.extend(/** @lends LuCI.rpc.prototype */ { * Sets the 32 byte session ID string used for authenticating remote * requests. */ - setSessionID: function(sid) { + setSessionID(sid) { rpcSessionID = sid; }, @@ -4010,7 +4008,7 @@ return baseclass.extend(/** @lends LuCI.rpc.prototype */ { * @returns {string} * Returns the RPC URL endpoint to issue requests against. */ - getBaseURL: function() { + getBaseURL() { return rpcBaseURL; }, @@ -4020,7 +4018,7 @@ return baseclass.extend(/** @lends LuCI.rpc.prototype */ { * @param {string} url * Sets the RPC URL endpoint to issue requests against. */ - setBaseURL: function(url) { + setBaseURL(url) { rpcBaseURL = url; }, @@ -4034,7 +4032,7 @@ return baseclass.extend(/** @lends LuCI.rpc.prototype */ { * @returns {string} * Returns the textual description of the code. */ - getStatusText: function(statusCode) { + getStatusText(statusCode) { switch (statusCode) { case 0: return _('Command OK'); case 1: return _('Invalid command'); @@ -4097,9 +4095,10 @@ return baseclass.extend(/** @lends LuCI.rpc.prototype */ { * @returns {LuCI.rpc~interceptorFn} * Returns the given function value. */ - addInterceptor: function(interceptorFn) { + addInterceptor(interceptorFn) { if (typeof(interceptorFn) == 'function') rpcInterceptorFns.push(interceptorFn); + return interceptorFn; }, @@ -4113,11 +4112,14 @@ return baseclass.extend(/** @lends LuCI.rpc.prototype */ { * Returns `true` if the given function has been removed or `false` * if it has not been found. */ - removeInterceptor: function(interceptorFn) { - var oldlen = rpcInterceptorFns.length, i = oldlen; + removeInterceptor(interceptorFn) { + const oldlen = rpcInterceptorFns.length; + let i = oldlen; + while (i--) if (rpcInterceptorFns[i] === interceptorFn) rpcInterceptorFns.splice(i, 1); + return (rpcInterceptorFns.length < oldlen); } }); @@ -4133,7 +4135,7 @@ return baseclass.extend(/** @lends LuCI.rpc.prototype */ { diff --git a/jsapi/uci.js.html b/jsapi/uci.js.html index 580895d2e5..baaf206a1c 100644 --- a/jsapi/uci.js.html +++ b/jsapi/uci.js.html @@ -86,6 +86,8 @@
  • hasViewPermission
  • +
  • isArguments
  • +
  • isObject
  • location
  • @@ -3641,7 +3643,7 @@ 'require baseclass'; function isEmpty(object, ignore) { - for (var property in object) + for (const property in object) if (object.hasOwnProperty(property) && property != ignore) return false; @@ -3660,7 +3662,7 @@ function isEmpty(object, ignore) { * UCI configuration data. */ return baseclass.extend(/** @lends LuCI.uci.prototype */ { - __init__: function() { + __init__() { this.state = { newidx: 0, values: { }, @@ -3738,14 +3740,14 @@ return baseclass.extend(/** @lends LuCI.uci.prototype */ { * A newly generated, unique section ID in the form `newXXXXXX` * where `X` denotes a hexadecimal digit. */ - createSID: function(conf) { - var v = this.state.values, - n = this.state.creates, - sid; + createSID(conf) { + const v = this.state.values; + const n = this.state.creates; + let sid; do { sid = "new%06x".format(Math.random() * 0xFFFFFF); - } while ((n[conf] && n[conf][sid]) || (v[conf] && v[conf][sid])); + } while ((n[conf]?.[sid]) || (v[conf]?.[sid])); return sid; }, @@ -3769,31 +3771,31 @@ return baseclass.extend(/** @lends LuCI.uci.prototype */ { * not in extended notation. Returns `null` when an extended ID could * not be resolved to existing section ID. */ - resolveSID: function(conf, sid) { + resolveSID(conf, sid) { if (typeof(sid) != 'string') return sid; - var m = /^@([a-zA-Z0-9_-]+)\[(-?[0-9]+)\]$/.exec(sid); + const m = /^@([a-zA-Z0-9_-]+)\[(-?[0-9]+)\]$/.exec(sid); if (m) { - var type = m[1], - pos = +m[2], - sections = this.sections(conf, type), - section = sections[pos >= 0 ? pos : sections.length + pos]; + const type = m[1]; + const pos = +m[2]; + const sections = this.sections(conf, type); + const section = sections[pos >= 0 ? pos : sections.length + pos]; - return section ? section['.name'] : null; + return section?.['.name'] ?? null; } return sid; }, /* private */ - reorderSections: function() { - var v = this.state.values, - n = this.state.creates, - d = this.state.deletes, - r = this.state.reorder, - tasks = []; + reorderSections() { + const v = this.state.values; + const n = this.state.creates; + const d = this.state.deletes; + const r = this.state.reorder; + const tasks = []; if (Object.keys(r).length === 0) return Promise.resolve(); @@ -3802,8 +3804,8 @@ return baseclass.extend(/** @lends LuCI.uci.prototype */ { gather all created and existing sections, sort them according to their index value and issue an uci order call */ - for (var c in r) { - var o = [ ]; + for (const c in r) { + const o = [ ]; // skip deletes within re-orders if (d[c]) @@ -3811,21 +3813,19 @@ return baseclass.extend(/** @lends LuCI.uci.prototype */ { // push creates if (n[c]) - for (var s in n[c]) + for (const s in n[c]) o.push(n[c][s]); // push values - for (var s in v[c]) + for (const s in v[c]) o.push(v[c][s]); if (o.length > 0) { - o.sort(function(a, b) { - return (a['.index'] - b['.index']); - }); + o.sort((a, b) => a['.index'] - b['.index']); - var sids = [ ]; + const sids = [ ]; - for (var i = 0; i < o.length; i++) + for (let i = 0; i < o.length; i++) sids.push(o[i]['.name']); tasks.push(this.callOrder(c, sids)); @@ -3837,7 +3837,7 @@ return baseclass.extend(/** @lends LuCI.uci.prototype */ { }, /* private */ - loadPackage: function(packageName) { + loadPackage(packageName) { if (this.loaded[packageName] == null) return (this.loaded[packageName] = this.callLoad(packageName)); @@ -3862,22 +3862,22 @@ return baseclass.extend(/** @lends LuCI.uci.prototype */ { * Returns a promise resolving to the names of the configurations * that have been successfully loaded. */ - load: function(packages) { - var self = this, - pkgs = [ ], - tasks = []; + load(packages) { + const self = this; + const pkgs = [ ]; + const tasks = []; if (!Array.isArray(packages)) packages = [ packages ]; - for (var i = 0; i < packages.length; i++) + for (let i = 0; i < packages.length; i++) if (!self.state.values[packages[i]]) { pkgs.push(packages[i]); tasks.push(self.loadPackage(packages[i])); } - return Promise.all(tasks).then(function(responses) { - for (var i = 0; i < responses.length; i++) + return Promise.all(tasks).then(responses => { + for (let i = 0; i < responses.length; i++) self.state.values[pkgs[i]] = responses[i]; if (responses.length) @@ -3894,11 +3894,11 @@ return baseclass.extend(/** @lends LuCI.uci.prototype */ { * The name of the configuration or an array of configuration * names to unload. */ - unload: function(packages) { + unload(packages) { if (!Array.isArray(packages)) packages = [ packages ]; - for (var i = 0; i < packages.length; i++) { + for (let i = 0; i < packages.length; i++) { delete this.state.values[packages[i]]; delete this.state.creates[packages[i]]; delete this.state.changes[packages[i]]; @@ -3926,13 +3926,11 @@ return baseclass.extend(/** @lends LuCI.uci.prototype */ { * Returns the section ID of the newly added section which is equivalent * to the given name for non-anonymous sections. */ - add: function(conf, type, name) { - var n = this.state.creates, - sid = name || this.createSID(conf); - - if (!n[conf]) - n[conf] = { }; + add(conf, type, name) { + const n = this.state.creates; + const sid = name || this.createSID(conf); + n[conf] ??= { }; n[conf][sid] = { '.type': type, '.name': sid, @@ -3968,7 +3966,7 @@ return baseclass.extend(/** @lends LuCI.uci.prototype */ { * Returns the section ID of the newly cloned section which is equivalent * to the given name for non-anonymous sections. */ - clone: function(conf, type, srcsid, put_next, name) { + clone(conf, type, srcsid, put_next, name) { let n = this.state.creates; let sid = this.createSID(conf); let v = this.state.values; @@ -4000,23 +3998,20 @@ return baseclass.extend(/** @lends LuCI.uci.prototype */ { * @param {string} sid * The ID of the section to remove. */ - remove: function(conf, sid) { - var v = this.state.values, - n = this.state.creates, - c = this.state.changes, - d = this.state.deletes; + remove(conf, sid) { + const v = this.state.values; + const n = this.state.creates; + const c = this.state.changes; + const d = this.state.deletes; /* requested deletion of a just created section */ - if (n[conf] && n[conf][sid]) { + if (n[conf]?.[sid]) { delete n[conf][sid]; } - else if (v[conf] && v[conf][sid]) { - if (c[conf]) - delete c[conf][sid]; - - if (!d[conf]) - d[conf] = { }; + else if (v[conf]?.[sid]) { + delete c[conf]?.[sid]; + d[conf] ??= { }; d[conf][sid] = true; } }, @@ -4089,35 +4084,35 @@ return baseclass.extend(/** @lends LuCI.uci.prototype */ { * Returns a sorted array of the section objects within the given * configuration, filtered by type, if a type has been specified. */ - sections: function(conf, type, cb) { - var sa = [ ], - v = this.state.values[conf], - n = this.state.creates[conf], - c = this.state.changes[conf], - d = this.state.deletes[conf]; + sections(conf, type, cb) { + const sa = [ ]; + const v = this.state.values[conf]; + const n = this.state.creates[conf]; + const c = this.state.changes[conf]; + const d = this.state.deletes[conf]; if (!v) return sa; - for (var s in v) + for (const s in v) if (!d || d[s] !== true) if (!type || v[s]['.type'] == type) sa.push(Object.assign({ }, v[s], c ? c[s] : null)); if (n) - for (var s in n) + for (const s in n) if (!type || n[s]['.type'] == type) sa.push(Object.assign({ }, n[s])); - sa.sort(function(a, b) { + sa.sort((a, b) => { return a['.index'] - b['.index']; }); - for (var i = 0; i < sa.length; i++) + for (let i = 0; i < sa.length; i++) sa[i]['.index'] = i; if (typeof(cb) == 'function') - for (var i = 0; i < sa.length; i++) + for (let i = 0; i < sa.length; i++) cb.call(this, sa[i], sa[i]['.name']); return sa; @@ -4148,11 +4143,11 @@ return baseclass.extend(/** @lends LuCI.uci.prototype */ { * - Returns `null` if the config, section or option has not been * found or if the corresponding configuration is not loaded. */ - get: function(conf, sid, opt) { - var v = this.state.values, - n = this.state.creates, - c = this.state.changes, - d = this.state.deletes; + get(conf, sid, opt) { + const v = this.state.values; + const n = this.state.creates; + const c = this.state.changes; + const d = this.state.deletes; sid = this.resolveSID(conf, sid); @@ -4160,10 +4155,7 @@ return baseclass.extend(/** @lends LuCI.uci.prototype */ { return null; /* requested option in a just created section */ - if (n[conf] && n[conf][sid]) { - if (!n[conf]) - return null; - + if (n[conf]?.[sid]) { if (opt == null) return n[conf][sid]; @@ -4173,16 +4165,16 @@ return baseclass.extend(/** @lends LuCI.uci.prototype */ { /* requested an option value */ if (opt != null) { /* check whether option was deleted */ - if (d[conf] && d[conf][sid]) + if (d[conf]?.[sid]) if (d[conf][sid] === true || d[conf][sid][opt]) return null; /* check whether option was changed */ - if (c[conf] && c[conf][sid] && c[conf][sid][opt] != null) + if (c[conf]?.[sid][opt] != null) return c[conf][sid][opt]; /* return base value */ - if (v[conf] && v[conf][sid]) + if (v[conf]?.[sid]) return v[conf][sid][opt]; return null; @@ -4191,21 +4183,21 @@ return baseclass.extend(/** @lends LuCI.uci.prototype */ { /* requested an entire section */ if (v[conf]) { /* check whether entire section was deleted */ - if (d[conf] && d[conf][sid] === true) + if (d[conf]?.[sid] === true) return null; - var s = v[conf][sid] || null; + const s = v[conf][sid] || null; if (s) { /* merge changes */ - if (c[conf] && c[conf][sid]) - for (var opt in c[conf][sid]) + if (c[conf]?.[sid]) + for (const opt in c[conf][sid]) if (c[conf][sid][opt] != null) s[opt] = c[conf][sid][opt]; /* merge deletions */ - if (d[conf] && d[conf][sid]) - for (var opt in d[conf][sid]) + if (d[conf]?.[sid]) + for (const opt in d[conf][sid]) delete s[opt]; } @@ -4236,18 +4228,18 @@ return baseclass.extend(/** @lends LuCI.uci.prototype */ { * the option will be removed, otherwise it will be set or overwritten * with the given value. */ - set: function(conf, sid, opt, val) { - var v = this.state.values, - n = this.state.creates, - c = this.state.changes, - d = this.state.deletes; + set(conf, sid, opt, val) { + const v = this.state.values; + const n = this.state.creates; + const c = this.state.changes; + const d = this.state.deletes; sid = this.resolveSID(conf, sid); if (sid == null || opt == null || opt.charAt(0) == '.') return; - if (n[conf] && n[conf][sid]) { + if (n[conf]?.[sid]) { if (val != null) n[conf][sid][opt] = val; else @@ -4259,17 +4251,14 @@ return baseclass.extend(/** @lends LuCI.uci.prototype */ { return; /* only set in existing sections */ - if (!v[conf] || !v[conf][sid]) + if (!v[conf]?.[sid]) return; - if (!c[conf]) - c[conf] = {}; - - if (!c[conf][sid]) - c[conf][sid] = {}; + c[conf] ??= {}; + c[conf][sid] ??= {}; /* undelete option */ - if (d[conf] && d[conf][sid]) { + if (d[conf]?.[sid]) { if (isEmpty(d[conf][sid], opt)) delete d[conf][sid]; else @@ -4280,7 +4269,7 @@ return baseclass.extend(/** @lends LuCI.uci.prototype */ { } else { /* revert any change for to-be-deleted option */ - if (c[conf] && c[conf][sid]) { + if (c[conf]?.[sid]) { if (isEmpty(c[conf][sid], opt)) delete c[conf][sid]; else @@ -4288,12 +4277,9 @@ return baseclass.extend(/** @lends LuCI.uci.prototype */ { } /* only delete existing options */ - if (v[conf] && v[conf][sid] && v[conf][sid].hasOwnProperty(opt)) { - if (!d[conf]) - d[conf] = { }; - - if (!d[conf][sid]) - d[conf][sid] = { }; + if (v[conf]?.[sid].hasOwnProperty(opt)) { + d[conf] ??= { }; + d[conf][sid] ??= { }; if (d[conf][sid] !== true) d[conf][sid][opt] = true; @@ -4317,7 +4303,7 @@ return baseclass.extend(/** @lends LuCI.uci.prototype */ { * @param {string} opt * The name of the option to remove. */ - unset: function(conf, sid, opt) { + unset(conf, sid, opt) { return this.set(conf, sid, opt, null); }, @@ -4348,12 +4334,11 @@ return baseclass.extend(/** @lends LuCI.uci.prototype */ { * - Returns `null` if the config, section or option has not been * found or if the corresponding configuration is not loaded. */ - get_first: function(conf, type, opt) { - var sid = null; + get_first(conf, type, opt) { + let sid = null; - this.sections(conf, type, function(s) { - if (sid == null) - sid = s['.name']; + this.sections(conf, type, s => { + sid ??= s['.name']; }); return this.get(conf, sid, opt); @@ -4383,12 +4368,11 @@ return baseclass.extend(/** @lends LuCI.uci.prototype */ { * the option will be removed, otherwise it will be set or overwritten * with the given value. */ - set_first: function(conf, type, opt, val) { - var sid = null; + set_first(conf, type, opt, val) { + let sid = null; - this.sections(conf, type, function(s) { - if (sid == null) - sid = s['.name']; + this.sections(conf, type, s => { + sid ??= s['.name']; }); return this.set(conf, sid, opt, val); @@ -4413,7 +4397,7 @@ return baseclass.extend(/** @lends LuCI.uci.prototype */ { * @param {string} opt * The option name to set the value for. */ - unset_first: function(conf, type, opt) { + unset_first(conf, type, opt) { return this.set_first(conf, type, opt, null); }, @@ -4448,14 +4432,15 @@ return baseclass.extend(/** @lends LuCI.uci.prototype */ { * Returns `true` when the section was successfully moved, or `false` * when either the section specified by `sid1` or by `sid2` is not found. */ - move: function(conf, sid1, sid2, after) { - var sa = this.sections(conf), - s1 = null, s2 = null; + move(conf, sid1, sid2, after) { + const sa = this.sections(conf); + let s1 = null; + let s2 = null; sid1 = this.resolveSID(conf, sid1); sid2 = this.resolveSID(conf, sid2); - for (var i = 0; i < sa.length; i++) { + for (let i = 0; i < sa.length; i++) { if (sa[i]['.name'] != sid1) continue; @@ -4471,7 +4456,7 @@ return baseclass.extend(/** @lends LuCI.uci.prototype */ { sa.push(s1); } else { - for (var i = 0; i < sa.length; i++) { + for (let i = 0; i < sa.length; i++) { if (sa[i]['.name'] != sid2) continue; @@ -4484,7 +4469,7 @@ return baseclass.extend(/** @lends LuCI.uci.prototype */ { return false; } - for (var i = 0; i < sa.length; i++) + for (let i = 0; i < sa.length; i++) this.get(conf, sa[i]['.name'])['.index'] = i; this.state.reorder[conf] = true; @@ -4502,21 +4487,21 @@ return baseclass.extend(/** @lends LuCI.uci.prototype */ { * Returns a promise resolving to an array of configuration names which * have been reloaded by the save operation. */ - save: function() { - var v = this.state.values, - n = this.state.creates, - c = this.state.changes, - d = this.state.deletes, - r = this.state.reorder, - self = this, - snew = [ ], - pkgs = { }, - tasks = []; + save() { + const v = this.state.values; + const n = this.state.creates; + const c = this.state.changes; + const d = this.state.deletes; + const r = this.state.reorder; + const self = this; + const snew = [ ]; + let pkgs = { }; + const tasks = []; if (d) - for (var conf in d) { - for (var sid in d[conf]) { - var o = d[conf][sid]; + for (const conf in d) { + for (const sid in d[conf]) { + const o = d[conf][sid]; if (o === true) tasks.push(self.callDelete(conf, sid, null)); @@ -4528,14 +4513,14 @@ return baseclass.extend(/** @lends LuCI.uci.prototype */ { } if (n) - for (var conf in n) { - for (var sid in n[conf]) { - var p = { + for (const conf in n) { + for (const sid in n[conf]) { + const p = { config: conf, values: { } }; - for (var k in n[conf][sid]) { + for (const k in n[conf][sid]) { if (k == '.type') p.type = n[conf][sid][k]; else if (k == '.create') @@ -4552,27 +4537,27 @@ return baseclass.extend(/** @lends LuCI.uci.prototype */ { } if (c) - for (var conf in c) { - for (var sid in c[conf]) + for (const conf in c) { + for (const sid in c[conf]) tasks.push(self.callSet(conf, sid, c[conf][sid])); pkgs[conf] = true; } if (r) - for (var conf in r) + for (const conf in r) pkgs[conf] = true; - return Promise.all(tasks).then(function(responses) { + return Promise.all(tasks).then(responses => { /* array "snew" holds references to the created uci sections, use it to assign the returned names of the new sections */ - for (var i = 0; i < snew.length; i++) + for (let i = 0; i < snew.length; i++) snew[i]['.name'] = responses[i]; return self.reorderSections(); - }).then(function() { + }).then(() => { pkgs = Object.keys(pkgs); self.unload(pkgs); @@ -4592,20 +4577,20 @@ return baseclass.extend(/** @lends LuCI.uci.prototype */ { * @returns {Promise<number>} * Returns a promise resolving/rejecting with the `ubus` RPC status code. */ - apply: function(timeout) { - var self = this, - date = new Date(); + apply(timeout) { + const self = this; + const date = new Date(); if (typeof(timeout) != 'number' || timeout < 1) timeout = 10; - return self.callApply(timeout, true).then(function(rv) { + return self.callApply(timeout, true).then(rv => { if (rv != 0) return Promise.reject(rv); - var try_deadline = date.getTime() + 1000 * timeout; - var try_confirm = function() { - return self.callConfirm().then(function(rv) { + const try_deadline = date.getTime() + 1000 * timeout; + const try_confirm = () => { + return self.callConfirm().then(rv => { if (rv != 0) { if (date.getTime() < try_deadline) window.setTimeout(try_confirm, 250); @@ -4690,7 +4675,7 @@ return baseclass.extend(/** @lends LuCI.uci.prototype */ { diff --git a/jsapi/ui.js.html b/jsapi/ui.js.html index 49fc1b93a5..f0aadb7ed4 100644 --- a/jsapi/ui.js.html +++ b/jsapi/ui.js.html @@ -86,6 +86,8 @@
  • hasViewPermission
  • +
  • isArguments
  • +
  • isObject
  • location
  • @@ -3647,10 +3649,10 @@ 'require uci'; 'require fs'; -var modalDiv = null, - tooltipDiv = null, - indicatorDiv = null, - tooltipTimeout = null; +let modalDiv = null; +let tooltipDiv = null; +let indicatorDiv = null; +let tooltipTimeout = null; /** * @class AbstractElement @@ -3672,7 +3674,7 @@ var modalDiv = null, * it in external JavaScript, use `L.require("ui").then(...)` and access the * `AbstractElement` property of the class instance value. */ -var UIElement = baseclass.extend(/** @lends LuCI.ui.AbstractElement.prototype */ { +const UIElement = baseclass.extend(/** @lends LuCI.ui.AbstractElement.prototype */ { /** * @typedef {Object} InitOptions * @memberof LuCI.ui.AbstractElement @@ -3716,7 +3718,7 @@ var UIElement = baseclass.extend(/** @lends LuCI.ui.AbstractElement.prototype */ * string. Complex widgets such as `DynamicList` instances may result in * an array of strings or `null` for unset values. */ - getValue: function() { + getValue() { if (dom.matches(this.node, 'select') || dom.matches(this.node, 'input')) return this.node.value; @@ -3734,7 +3736,7 @@ var UIElement = baseclass.extend(/** @lends LuCI.ui.AbstractElement.prototype */ * Complex widgets such as `DynamicList` instances may accept string array * or `null` values. */ - setValue: function(value) { + setValue(value) { if (dom.matches(this.node, 'select') || dom.matches(this.node, 'input')) this.node.value = value; }, @@ -3748,10 +3750,10 @@ var UIElement = baseclass.extend(/** @lends LuCI.ui.AbstractElement.prototype */ * The placeholder to set for the input element. Only applicable to text * inputs, not to radio buttons, selects or similar. */ - setPlaceholder: function(value) { - var node = this.node ? this.node.querySelector('input,textarea') : null; + setPlaceholder(value) { + const node = this.node ? this.node.querySelector('input,textarea') : null; if (node) { - switch (node.getAttribute('type') || 'text') { + switch (node.getAttribute('type') ?? 'text') { case 'password': case 'search': case 'tel': @@ -3776,7 +3778,7 @@ var UIElement = baseclass.extend(/** @lends LuCI.ui.AbstractElement.prototype */ * value and changes it back to the original state, it is still reported * as changed. */ - isChanged: function() { + isChanged() { return (this.node ? this.node.getAttribute('data-changed') : null) == 'true'; }, @@ -3789,7 +3791,7 @@ var UIElement = baseclass.extend(/** @lends LuCI.ui.AbstractElement.prototype */ * Returns `true` if the current input value is valid or `false` if it does * not meet the validation constraints. */ - isValid: function() { + isValid() { return (this.validState !== false); }, @@ -3801,8 +3803,8 @@ var UIElement = baseclass.extend(/** @lends LuCI.ui.AbstractElement.prototype */ * @returns {string} * The validation error at this time */ - getValidationError: function() { - return this.validationError || ''; + getValidationError() { + return this.validationError ?? ''; }, /** @@ -3815,11 +3817,11 @@ var UIElement = baseclass.extend(/** @lends LuCI.ui.AbstractElement.prototype */ * @instance * @memberof LuCI.ui.AbstractElement */ - triggerValidation: function() { + triggerValidation() { if (typeof(this.vfunc) != 'function') return false; - var wasValid = this.isValid(); + const wasValid = this.isValid(); this.vfunc(); @@ -3850,12 +3852,12 @@ var UIElement = baseclass.extend(/** @lends LuCI.ui.AbstractElement.prototype */ * @param {string[]} events * The native DOM events for which event handlers should be registered. */ - registerEvents: function(targetNode, synevent, events) { - var dispatchFn = L.bind(function(ev) { + registerEvents(targetNode, synevent, events) { + const dispatchFn = L.bind((ev) => { this.node.dispatchEvent(new CustomEvent(synevent, { bubbles: true })); }, this); - for (var i = 0; i < events.length; i++) + for (let i = 0; i < events.length; i++) targetNode.addEventListener(events[i], dispatchFn); }, @@ -3875,28 +3877,27 @@ var UIElement = baseclass.extend(/** @lends LuCI.ui.AbstractElement.prototype */ * @param {...string} events * The DOM events for which event handlers should be registered. */ - setUpdateEvents: function(targetNode /*, ... */) { - var datatype = this.options.datatype, - optional = this.options.hasOwnProperty('optional') ? this.options.optional : true, - validate = this.options.validate, - events = this.varargs(arguments, 1); + setUpdateEvents(targetNode, ...events) { + const datatype = this.options.datatype; + const optional = this.options.hasOwnProperty('optional') ? this.options.optional : true; + const validate = this.options.validate; this.registerEvents(targetNode, 'widget-update', events); if (!datatype && !validate) return; - this.vfunc = UI.prototype.addValidator.apply(UI.prototype, [ - targetNode, datatype || 'string', + this.vfunc = UI.prototype.addValidator(...[ + targetNode, datatype ?? 'string', optional, validate ].concat(events)); - this.node.addEventListener('validation-success', L.bind(function(ev) { + this.node.addEventListener('validation-success', L.bind((ev) => { this.validState = true; this.validationError = ''; }, this)); - this.node.addEventListener('validation-failure', L.bind(function(ev) { + this.node.addEventListener('validation-failure', L.bind((ev) => { this.validState = false; this.validationError = ev.detail.message; }, this)); @@ -3920,13 +3921,13 @@ var UIElement = baseclass.extend(/** @lends LuCI.ui.AbstractElement.prototype */ * @param {...string} events * The DOM events for which event handlers should be registered. */ - setChangeEvents: function(targetNode /*, ... */) { - var tag_changed = L.bind(function(ev) { this.setAttribute('data-changed', true) }, this.node); + setChangeEvents(targetNode, ...events) { + const tag_changed = L.bind(function(ev) { this.setAttribute('data-changed', true) }, this.node); - for (var i = 1; i < arguments.length; i++) - targetNode.addEventListener(arguments[i], tag_changed); + for (let i = 0; i < events.length; i++) + targetNode.addEventListener(events[i], tag_changed); - this.registerEvents(targetNode, 'widget-change', this.varargs(arguments, 1)); + this.registerEvents(targetNode, 'widget-change', events); }, /** @@ -3939,7 +3940,7 @@ var UIElement = baseclass.extend(/** @lends LuCI.ui.AbstractElement.prototype */ * Returns a DOM Node or DocumentFragment containing the rendered * widget markup. */ - render: function() {} + render() {} }); /** @@ -3968,7 +3969,7 @@ var UIElement = baseclass.extend(/** @lends LuCI.ui.AbstractElement.prototype */ * @param {LuCI.ui.Textfield.InitOptions} [options] * Object describing the widget specific options to initialize the input. */ -var UITextfield = UIElement.extend(/** @lends LuCI.ui.Textfield.prototype */ { +const UITextfield = UIElement.extend(/** @lends LuCI.ui.Textfield.prototype */ { /** * In addition to the [AbstractElement.InitOptions]{@link LuCI.ui.AbstractElement.InitOptions} * the following properties are recognized: @@ -3992,7 +3993,7 @@ var UITextfield = UIElement.extend(/** @lends LuCI.ui.Textfield.prototype */ { * Specifies the HTML `placeholder` attribute which is displayed when the * corresponding `<input>` element is empty. */ - __init__: function(value, options) { + __init__(value, options) { this.value = value; this.options = Object.assign({ optional: true, @@ -4001,10 +4002,10 @@ var UITextfield = UIElement.extend(/** @lends LuCI.ui.Textfield.prototype */ { }, /** @override */ - render: function() { - var frameEl = E('div', { 'id': this.options.id }); - var inputEl = E('input', { - 'id': this.options.id ? 'widget.' + this.options.id : null, + render() { + const frameEl = E('div', { 'id': this.options.id }); + const inputEl = E('input', { + 'id': this.options.id ? `widget.${this.options.id}` : null, 'name': this.options.name, 'type': 'text', 'class': this.options.password ? 'cbi-input-password' : 'cbi-input-text', @@ -4012,7 +4013,6 @@ var UITextfield = UIElement.extend(/** @lends LuCI.ui.Textfield.prototype */ { 'disabled': this.options.disabled ? '' : null, 'maxlength': this.options.maxlength, 'placeholder': this.options.placeholder, - 'autocomplete': this.options.password ? 'new-password' : null, 'value': this.value, }); @@ -4024,14 +4024,14 @@ var UITextfield = UIElement.extend(/** @lends LuCI.ui.Textfield.prototype */ { 'title': _('Reveal/hide password'), 'aria-label': _('Reveal/hide password'), 'click': function(ev) { - var e = this.previousElementSibling; + const e = this.previousElementSibling; e.type = (e.type === 'password') ? 'text' : 'password'; ev.preventDefault(); } }, '∗') ])); - window.requestAnimationFrame(function() { inputEl.type = 'password' }); + window.requestAnimationFrame(() => { inputEl.type = 'password' }); } else { frameEl.appendChild(inputEl); @@ -4041,8 +4041,8 @@ var UITextfield = UIElement.extend(/** @lends LuCI.ui.Textfield.prototype */ { }, /** @private */ - bind: function(frameEl) { - var inputEl = frameEl.querySelector('input'); + bind(frameEl) { + const inputEl = frameEl.querySelector('input'); this.node = frameEl; @@ -4055,14 +4055,14 @@ var UITextfield = UIElement.extend(/** @lends LuCI.ui.Textfield.prototype */ { }, /** @override */ - getValue: function() { - var inputEl = this.node.querySelector('input'); + getValue() { + const inputEl = this.node.querySelector('input'); return inputEl.value; }, /** @override */ - setValue: function(value) { - var inputEl = this.node.querySelector('input'); + setValue(value) { + const inputEl = this.node.querySelector('input'); inputEl.value = value; } }); @@ -4093,7 +4093,7 @@ var UITextfield = UIElement.extend(/** @lends LuCI.ui.Textfield.prototype */ { * @param {LuCI.ui.Textarea.InitOptions} [options] * Object describing the widget specific options to initialize the input. */ -var UITextarea = UIElement.extend(/** @lends LuCI.ui.Textarea.prototype */ { +const UITextarea = UIElement.extend(/** @lends LuCI.ui.Textarea.prototype */ { /** * In addition to the [AbstractElement.InitOptions]{@link LuCI.ui.AbstractElement.InitOptions} * the following properties are recognized: @@ -4123,7 +4123,7 @@ var UITextarea = UIElement.extend(/** @lends LuCI.ui.Textarea.prototype */ { * @property {boolean} [wrap=false] * Specifies whether the HTML `wrap` attribute should be set. */ - __init__: function(value, options) { + __init__(value, options) { this.value = value; this.options = Object.assign({ optional: true, @@ -4134,13 +4134,13 @@ var UITextarea = UIElement.extend(/** @lends LuCI.ui.Textarea.prototype */ { }, /** @override */ - render: function() { - var style = !this.options.cols ? 'width:100%' : null, - frameEl = E('div', { 'id': this.options.id, 'style': style }), - value = (this.value != null) ? String(this.value) : ''; + render() { + const style = !this.options.cols ? 'width:100%' : null; + const frameEl = E('div', { 'id': this.options.id, 'style': style }); + const value = (this.value != null) ? String(this.value) : ''; frameEl.appendChild(E('textarea', { - 'id': this.options.id ? 'widget.' + this.options.id : null, + 'id': this.options.id ? `widget.${this.options.id}` : null, 'name': this.options.name, 'class': 'cbi-input-textarea', 'readonly': this.options.readonly ? '' : null, @@ -4159,8 +4159,8 @@ var UITextarea = UIElement.extend(/** @lends LuCI.ui.Textarea.prototype */ { }, /** @private */ - bind: function(frameEl) { - var inputEl = frameEl.firstElementChild; + bind(frameEl) { + const inputEl = frameEl.firstElementChild; this.node = frameEl; @@ -4173,12 +4173,12 @@ var UITextarea = UIElement.extend(/** @lends LuCI.ui.Textarea.prototype */ { }, /** @override */ - getValue: function() { + getValue() { return this.node.firstElementChild.value; }, /** @override */ - setValue: function(value) { + setValue(value) { this.node.firstElementChild.value = value; } }); @@ -4209,7 +4209,7 @@ var UITextarea = UIElement.extend(/** @lends LuCI.ui.Textarea.prototype */ { * @param {LuCI.ui.Checkbox.InitOptions} [options] * Object describing the widget specific options to initialize the input. */ -var UICheckbox = UIElement.extend(/** @lends LuCI.ui.Checkbox.prototype */ { +const UICheckbox = UIElement.extend(/** @lends LuCI.ui.Checkbox.prototype */ { /** * In addition to the [AbstractElement.InitOptions]{@link LuCI.ui.AbstractElement.InitOptions} * the following properties are recognized: @@ -4228,7 +4228,7 @@ var UICheckbox = UIElement.extend(/** @lends LuCI.ui.Checkbox.prototype */ { * checkbox. This is a legacy property existing for compatibility reasons, * it is required for HTML based form submissions. */ - __init__: function(value, options) { + __init__(value, options) { this.value = value; this.options = Object.assign({ value_enabled: '1', @@ -4237,9 +4237,9 @@ var UICheckbox = UIElement.extend(/** @lends LuCI.ui.Checkbox.prototype */ { }, /** @override */ - render: function() { - var id = 'cb%08x'.format(Math.random() * 0xffffffff); - var frameEl = E('div', { + render() { + const id = 'cb%08x'.format(Math.random() * 0xffffffff); + const frameEl = E('div', { 'id': this.options.id, 'class': 'cbi-checkbox' }); @@ -4258,13 +4258,13 @@ var UICheckbox = UIElement.extend(/** @lends LuCI.ui.Checkbox.prototype */ { 'value': this.options.value_enabled, 'checked': (this.value == this.options.value_enabled) ? '' : null, 'disabled': this.options.disabled ? '' : null, - 'data-widget-id': this.options.id ? 'widget.' + this.options.id : null + 'data-widget-id': this.options.id ? `widget.${this.options.id}` : null })); frameEl.appendChild(E('label', { 'for': id })); if (this.options.tooltip != null) { - var icon = "⚠️"; + let icon = "⚠️"; if (this.options.tooltipicon != null) icon = this.options.tooltipicon; @@ -4283,10 +4283,10 @@ var UICheckbox = UIElement.extend(/** @lends LuCI.ui.Checkbox.prototype */ { }, /** @private */ - bind: function(frameEl) { + bind(frameEl) { this.node = frameEl; - var input = frameEl.querySelector('input[type="checkbox"]'); + const input = frameEl.querySelector('input[type="checkbox"]'); this.setUpdateEvents(input, 'click', 'blur'); this.setChangeEvents(input, 'change'); @@ -4303,19 +4303,19 @@ var UICheckbox = UIElement.extend(/** @lends LuCI.ui.Checkbox.prototype */ { * @returns {boolean} * Returns `true` when the checkbox is currently checked, otherwise `false`. */ - isChecked: function() { + isChecked() { return this.node.querySelector('input[type="checkbox"]').checked; }, /** @override */ - getValue: function() { + getValue() { return this.isChecked() ? this.options.value_enabled : this.options.value_disabled; }, /** @override */ - setValue: function(value) { + setValue(value) { this.node.querySelector('input[type="checkbox"]').checked = (value == this.options.value_enabled); } }); @@ -4353,7 +4353,7 @@ var UICheckbox = UIElement.extend(/** @lends LuCI.ui.Checkbox.prototype */ { * @param {LuCI.ui.Select.InitOptions} [options] * Object describing the widget specific options to initialize the inputs. */ -var UISelect = UIElement.extend(/** @lends LuCI.ui.Select.prototype */ { +const UISelect = UIElement.extend(/** @lends LuCI.ui.Select.prototype */ { /** * In addition to the [AbstractElement.InitOptions]{@link LuCI.ui.AbstractElement.InitOptions} * the following properties are recognized: @@ -4388,7 +4388,7 @@ var UISelect = UIElement.extend(/** @lends LuCI.ui.Select.prototype */ { * Specifies a placeholder text which is displayed when no choice is * selected yet. Only applicable to the `select` widget type. */ - __init__: function(value, choices, options) { + __init__(value, choices, options) { if (!L.isObject(choices)) choices = {}; @@ -4411,9 +4411,9 @@ var UISelect = UIElement.extend(/** @lends LuCI.ui.Select.prototype */ { }, /** @override */ - render: function() { - var frameEl = E('div', { 'id': this.options.id }), - keys = Object.keys(this.choices); + render() { + const frameEl = E('div', { 'id': this.options.id }); + let keys = Object.keys(this.choices); if (this.options.sort === true) keys.sort(L.naturalCompare); @@ -4422,7 +4422,7 @@ var UISelect = UIElement.extend(/** @lends LuCI.ui.Select.prototype */ { if (this.options.widget != 'radio' && this.options.widget != 'checkbox') { frameEl.appendChild(E('select', { - 'id': this.options.id ? 'widget.' + this.options.id : null, + 'id': this.options.id ? `widget.${this.options.id}` : null, 'name': this.options.name, 'size': this.options.size, 'class': 'cbi-input-select', @@ -4434,28 +4434,28 @@ var UISelect = UIElement.extend(/** @lends LuCI.ui.Select.prototype */ { frameEl.lastChild.appendChild(E('option', { 'value': '', 'selected': (this.values.length == 0 || this.values[0] == '') ? '' : null - }, [ this.choices[''] || this.options.placeholder || _('-- Please choose --') ])); + }, [ this.choices[''] ?? this.options.placeholder ?? _('-- Please choose --') ])); - for (var i = 0; i < keys.length; i++) { + for (let i = 0; i < keys.length; i++) { if (keys[i] == null || keys[i] == '') continue; frameEl.lastChild.appendChild(E('option', { 'value': keys[i], 'selected': (this.values.indexOf(keys[i]) > -1) ? '' : null - }, [ this.choices[keys[i]] || keys[i] ])); + }, [ this.choices[keys[i]] ?? keys[i] ])); } } else { - var brEl = (this.options.orientation === 'horizontal') ? document.createTextNode(' \xa0 ') : E('br'); + const brEl = (this.options.orientation === 'horizontal') ? document.createTextNode(' \xa0 ') : E('br'); - for (var i = 0; i < keys.length; i++) { + for (let i = 0; i < keys.length; i++) { frameEl.appendChild(E('span', { 'class': 'cbi-%s'.format(this.options.multiple ? 'checkbox' : 'radio') }, [ E('input', { 'id': this.options.id ? 'widget.%s.%d'.format(this.options.id, i) : null, - 'name': this.options.id || this.options.name, + 'name': this.options.id ?? this.options.name, 'type': this.options.multiple ? 'checkbox' : 'radio', 'class': this.options.multiple ? 'cbi-input-checkbox' : 'cbi-input-radio', 'value': keys[i], @@ -4467,7 +4467,7 @@ var UISelect = UIElement.extend(/** @lends LuCI.ui.Select.prototype */ { 'click': function(ev) { ev.currentTarget.previousElementSibling.previousElementSibling.click(); } - }, [ this.choices[keys[i]] || keys[i] ]) + }, [ this.choices[keys[i]] ?? keys[i] ]) ])); frameEl.appendChild(brEl.cloneNode()); @@ -4478,7 +4478,7 @@ var UISelect = UIElement.extend(/** @lends LuCI.ui.Select.prototype */ { }, /** @private */ - bind: function(frameEl) { + bind(frameEl) { this.node = frameEl; if (this.options.widget != 'radio' && this.options.widget != 'checkbox') { @@ -4486,8 +4486,8 @@ var UISelect = UIElement.extend(/** @lends LuCI.ui.Select.prototype */ { this.setChangeEvents(frameEl.firstChild, 'change'); } else { - var radioEls = frameEl.querySelectorAll('input[type="radio"]'); - for (var i = 0; i < radioEls.length; i++) { + const radioEls = frameEl.querySelectorAll('input[type="radio"]'); + for (let i = 0; i < radioEls.length; i++) { this.setUpdateEvents(radioEls[i], 'change', 'click', 'blur'); this.setChangeEvents(radioEls[i], 'change', 'click', 'blur'); } @@ -4499,12 +4499,12 @@ var UISelect = UIElement.extend(/** @lends LuCI.ui.Select.prototype */ { }, /** @override */ - getValue: function() { + getValue() { if (this.options.widget != 'radio' && this.options.widget != 'checkbox') return this.node.firstChild.value; - var radioEls = this.node.querySelectorAll('input[type="radio"]'); - for (var i = 0; i < radioEls.length; i++) + const radioEls = this.node.querySelectorAll('input[type="radio"]'); + for (let i = 0; i < radioEls.length; i++) if (radioEls[i].checked) return radioEls[i].value; @@ -4512,19 +4512,19 @@ var UISelect = UIElement.extend(/** @lends LuCI.ui.Select.prototype */ { }, /** @override */ - setValue: function(value) { + setValue(value) { if (this.options.widget != 'radio' && this.options.widget != 'checkbox') { if (value == null) value = ''; - for (var i = 0; i < this.node.firstChild.options.length; i++) + for (let i = 0; i < this.node.firstChild.options.length; i++) this.node.firstChild.options[i].selected = (this.node.firstChild.options[i].value == value); return; } - var radioEls = frameEl.querySelectorAll('input[type="radio"]'); - for (var i = 0; i < radioEls.length; i++) + const radioEls = frameEl.querySelectorAll('input[type="radio"]'); + for (let i = 0; i < radioEls.length; i++) radioEls[i].checked = (radioEls[i].value == value); } }); @@ -4561,7 +4561,7 @@ var UISelect = UIElement.extend(/** @lends LuCI.ui.Select.prototype */ { * @param {LuCI.ui.Dropdown.InitOptions} [options] * Object describing the widget specific options to initialize the dropdown. */ -var UIDropdown = UIElement.extend(/** @lends LuCI.ui.Dropdown.prototype */ { +const UIDropdown = UIElement.extend(/** @lends LuCI.ui.Dropdown.prototype */ { /** * In addition to the [AbstractElement.InitOptions]{@link LuCI.ui.AbstractElement.InitOptions} * the following properties are recognized: @@ -4658,7 +4658,7 @@ var UIDropdown = UIElement.extend(/** @lends LuCI.ui.Dropdown.prototype */ { * compatibility reasons. It is usually better to `maxlength(N)` validation * expression. Only applicable when `create` is `true`. */ - __init__: function(value, choices, options) { + __init__(value, choices, options) { if (typeof(choices) != 'object') choices = {}; @@ -4683,8 +4683,8 @@ var UIDropdown = UIElement.extend(/** @lends LuCI.ui.Dropdown.prototype */ { }, /** @override */ - render: function() { - var sb = E('div', { + render() { + const sb = E('div', { 'id': this.options.id, 'class': 'cbi-dropdown', 'multiple': this.options.multiple ? '' : null, @@ -4693,7 +4693,7 @@ var UIDropdown = UIElement.extend(/** @lends LuCI.ui.Dropdown.prototype */ { 'tabindex': -1 }, E('ul')); - var keys = Object.keys(this.choices); + let keys = Object.keys(this.choices); if (this.options.sort === true) keys.sort(L.naturalCompare); @@ -4701,12 +4701,12 @@ var UIDropdown = UIElement.extend(/** @lends LuCI.ui.Dropdown.prototype */ { keys = this.options.sort; if (this.options.create) - for (var i = 0; i < this.values.length; i++) + for (let i = 0; i < this.values.length; i++) if (!this.choices.hasOwnProperty(this.values[i])) keys.push(this.values[i]); - for (var i = 0; i < keys.length; i++) { - var label = this.choices[keys[i]]; + for (let i = 0; i < keys.length; i++) { + let label = this.choices[keys[i]]; if (dom.elem(label)) label = label.cloneNode(true); @@ -4714,20 +4714,20 @@ var UIDropdown = UIElement.extend(/** @lends LuCI.ui.Dropdown.prototype */ { sb.lastElementChild.appendChild(E('li', { 'data-value': keys[i], 'selected': (this.values.indexOf(keys[i]) > -1) ? '' : null - }, [ label || keys[i] ])); + }, [ label ?? keys[i] ])); } if (this.options.create) { - var createEl = E('input', { + const createEl = E('input', { 'type': 'text', 'class': 'create-item-input', 'readonly': this.options.readonly ? '' : null, 'maxlength': this.options.maxlength, - 'placeholder': this.options.custom_placeholder || this.options.placeholder + 'placeholder': this.options.custom_placeholder ?? this.options.placeholder }); if (this.options.datatype || this.options.validate) - UI.prototype.addValidator(createEl, this.options.datatype || 'string', + UI.prototype.addValidator(createEl, this.options.datatype ?? 'string', true, this.options.validate, 'blur', 'keyup'); sb.lastElementChild.appendChild(E('li', { 'data-value': '-' }, createEl)); @@ -4741,29 +4741,29 @@ var UIDropdown = UIElement.extend(/** @lends LuCI.ui.Dropdown.prototype */ { }, /** @private */ - bind: function(sb) { - var o = this.options; + bind(sb) { + const o = this.options; o.multiple = sb.hasAttribute('multiple'); o.optional = sb.hasAttribute('optional'); - o.placeholder = sb.getAttribute('placeholder') || o.placeholder; - o.display_items = parseInt(sb.getAttribute('display-items') || o.display_items); - o.dropdown_items = parseInt(sb.getAttribute('dropdown-items') || o.dropdown_items); - o.create_query = sb.getAttribute('item-create') || o.create_query; - o.create_template = sb.getAttribute('item-template') || o.create_template; - - var ul = sb.querySelector('ul'), - more = sb.appendChild(E('span', { class: 'more', tabindex: -1 }, '···')), - open = sb.appendChild(E('span', { class: 'open', tabindex: -1 }, '▾')), - canary = sb.appendChild(E('div')), - create = sb.querySelector(this.options.create_query), - ndisplay = this.options.display_items, - n = 0; + o.placeholder = sb.getAttribute('placeholder') ?? o.placeholder; + o.display_items = parseInt(sb.getAttribute('display-items') ?? o.display_items); + o.dropdown_items = parseInt(sb.getAttribute('dropdown-items') ?? o.dropdown_items); + o.create_query = sb.getAttribute('item-create') ?? o.create_query; + o.create_template = sb.getAttribute('item-template') ?? o.create_template; + + const ul = sb.querySelector('ul'); + const more = sb.appendChild(E('span', { class: 'more', tabindex: -1 }, '···')); + const open = sb.appendChild(E('span', { class: 'open', tabindex: -1 }, '▾')); + const canary = sb.appendChild(E('div')); + const create = sb.querySelector(this.options.create_query); + let ndisplay = this.options.display_items; + let n = 0; if (this.options.multiple) { - var items = ul.querySelectorAll('li'); + let items = ul.querySelectorAll('li'); - for (var i = 0; i < items.length; i++) { + for (let i = 0; i < items.length; i++) { this.transformItem(sb, items[i]); if (items[i].hasAttribute('selected') && ndisplay-- > 0) @@ -4772,22 +4772,22 @@ var UIDropdown = UIElement.extend(/** @lends LuCI.ui.Dropdown.prototype */ { } else { if (this.options.optional && !ul.querySelector('li[data-value=""]')) { - var placeholder = E('li', { placeholder: '' }, - this.options.select_placeholder || this.options.placeholder); + const placeholder = E('li', { placeholder: '' }, + this.options.select_placeholder ?? this.options.placeholder); ul.firstChild ? ul.insertBefore(placeholder, ul.firstChild) : ul.appendChild(placeholder); } - var items = ul.querySelectorAll('li'), - sel = sb.querySelectorAll('[selected]'); + let items = ul.querySelectorAll('li'); + const sel = sb.querySelectorAll('[selected]'); - sel.forEach(function(s) { + sel.forEach(s => { s.removeAttribute('selected'); }); - var s = sel[0] || items[0]; + const s = sel[0] ?? items[0]; if (s) { s.setAttribute('selected', ''); s.setAttribute('display', n++); @@ -4812,7 +4812,7 @@ var UIDropdown = UIElement.extend(/** @lends LuCI.ui.Dropdown.prototype */ { sb.removeAttribute('empty'); dom.content(more, (ndisplay == this.options.display_items) - ? (this.options.select_placeholder || this.options.placeholder) : '···'); + ? (this.options.select_placeholder ?? this.options.placeholder) : '···'); sb.addEventListener('click', this.handleClick.bind(this)); @@ -4821,7 +4821,7 @@ var UIDropdown = UIElement.extend(/** @lends LuCI.ui.Dropdown.prototype */ { sb.addEventListener('cbi-dropdown-select', this.handleDropdownSelect.bind(this)); if ('ontouchstart' in window) { - sb.addEventListener('touchstart', function(ev) { ev.stopPropagation(); }); + sb.addEventListener('touchstart', ev => ev.stopPropagation()); window.addEventListener('touchstart', this.closeAllDropdowns); } else { @@ -4837,7 +4837,7 @@ var UIDropdown = UIElement.extend(/** @lends LuCI.ui.Dropdown.prototype */ { create.addEventListener('focus', this.handleCreateFocus.bind(this)); create.addEventListener('blur', this.handleCreateBlur.bind(this)); - var li = findParent(create, 'li'); + const li = findParent(create, 'li'); li.setAttribute('unselectable', ''); li.addEventListener('click', this.handleCreateClick.bind(this)); @@ -4854,10 +4854,10 @@ var UIDropdown = UIElement.extend(/** @lends LuCI.ui.Dropdown.prototype */ { }, /** @private */ - getScrollParent: function(element) { - var parent = element, - style = getComputedStyle(element), - excludeStaticParent = (style.position === 'absolute'); + getScrollParent(element) { + let parent = element; + let style = getComputedStyle(element); + const excludeStaticParent = (style.position === 'absolute'); if (style.position === 'fixed') return document.body; @@ -4876,49 +4876,49 @@ var UIDropdown = UIElement.extend(/** @lends LuCI.ui.Dropdown.prototype */ { }, /** @private */ - openDropdown: function(sb) { - var st = window.getComputedStyle(sb, null), - ul = sb.querySelector('ul'), - li = ul.querySelectorAll('li'), - fl = findParent(sb, '.cbi-value-field'), - sel = ul.querySelector('[selected]'), - rect = sb.getBoundingClientRect(), - items = Math.min(this.options.dropdown_items, li.length), - scrollParent = this.getScrollParent(sb); - - document.querySelectorAll('.cbi-dropdown[open]').forEach(function(s) { + openDropdown(sb) { + const st = window.getComputedStyle(sb, null); + const ul = sb.querySelector('ul'); + const li = ul.querySelectorAll('li'); + const fl = findParent(sb, '.cbi-value-field'); + const sel = ul.querySelector('[selected]'); + const rect = sb.getBoundingClientRect(); + const items = Math.min(this.options.dropdown_items, li.length); + const scrollParent = this.getScrollParent(sb); + + document.querySelectorAll('.cbi-dropdown[open]').forEach(s => { s.dispatchEvent(new CustomEvent('cbi-dropdown-close', {})); }); sb.setAttribute('open', ''); - var pv = ul.cloneNode(true); + const pv = ul.cloneNode(true); pv.classList.add('preview'); if (fl) fl.classList.add('cbi-dropdown-open'); if ('ontouchstart' in window) { - var vpWidth = Math.max(document.documentElement.clientWidth, window.innerWidth || 0), - vpHeight = Math.max(document.documentElement.clientHeight, window.innerHeight || 0), - start = null; - - ul.style.top = sb.offsetHeight + 'px'; - ul.style.left = -rect.left + 'px'; - ul.style.right = (rect.right - vpWidth) + 'px'; - ul.style.maxHeight = (vpHeight * 0.5) + 'px'; + const vpWidth = Math.max(document.documentElement.clientWidth, window.innerWidth ?? 0); + const vpHeight = Math.max(document.documentElement.clientHeight, window.innerHeight ?? 0); + let start = null; + + ul.style.top = `${sb.offsetHeight}px`; + ul.style.left = `${-rect.left}px`; + ul.style.right = `${rect.right - vpWidth}px`; + ul.style.maxHeight = `${vpHeight * 0.5}px`; ul.style.WebkitOverflowScrolling = 'touch'; - var scrollFrom = scrollParent.scrollTop, - scrollTo = scrollFrom + rect.top - vpHeight * 0.5; + const scrollFrom = scrollParent.scrollTop; + const scrollTo = scrollFrom + rect.top - vpHeight * 0.5; - var scrollStep = function(timestamp) { + const scrollStep = timestamp => { if (!start) { start = timestamp; ul.scrollTop = sel ? Math.max(sel.offsetTop - sel.offsetHeight, 0) : 0; } - var duration = Math.max(timestamp - start, 1); + const duration = Math.max(timestamp - start, 1); if (duration < 100) { scrollParent.scrollTop = scrollFrom + (scrollTo - scrollFrom) * (duration / 100); window.requestAnimationFrame(scrollStep); @@ -4934,73 +4934,73 @@ var UIDropdown = UIElement.extend(/** @lends LuCI.ui.Dropdown.prototype */ { ul.style.maxHeight = '1px'; ul.style.top = ul.style.bottom = ''; - window.requestAnimationFrame(function() { - var containerRect = scrollParent.getBoundingClientRect(), - itemHeight = li[Math.max(0, li.length - 2)].getBoundingClientRect().height, - fullHeight = 0, - spaceAbove = rect.top - containerRect.top, - spaceBelow = containerRect.bottom - rect.bottom; + window.requestAnimationFrame(() => { + const containerRect = scrollParent.getBoundingClientRect(); + const itemHeight = li[Math.max(0, li.length - 2)].getBoundingClientRect().height; + let fullHeight = 0; + const spaceAbove = rect.top - containerRect.top; + const spaceBelow = containerRect.bottom - rect.bottom; - for (var i = 0; i < (items == -1 ? li.length : items); i++) + for (let i = 0; i < (items == -1 ? li.length : items); i++) fullHeight += li[i].getBoundingClientRect().height; if (fullHeight <= spaceBelow) { - ul.style.top = rect.height + 'px'; - ul.style.maxHeight = spaceBelow + 'px'; + ul.style.top = `${rect.height}px`; + ul.style.maxHeight = `${spaceBelow}px`; } else if (fullHeight <= spaceAbove) { - ul.style.bottom = rect.height + 'px'; - ul.style.maxHeight = spaceAbove + 'px'; + ul.style.bottom = `${rect.height}px`; + ul.style.maxHeight = `${spaceAbove}px`; } else if (spaceBelow >= spaceAbove) { - ul.style.top = rect.height + 'px'; - ul.style.maxHeight = (spaceBelow - (spaceBelow % itemHeight)) + 'px'; + ul.style.top = `${rect.height}px`; + ul.style.maxHeight = `${spaceBelow - (spaceBelow % itemHeight)}px`; } else { - ul.style.bottom = rect.height + 'px'; - ul.style.maxHeight = (spaceAbove - (spaceAbove % itemHeight)) + 'px'; + ul.style.bottom = `${rect.height}px`; + ul.style.maxHeight = `${spaceAbove - (spaceAbove % itemHeight)}px`; } ul.scrollTop = sel ? Math.max(sel.offsetTop - sel.offsetHeight, 0) : 0; }); } - var cboxes = ul.querySelectorAll('[selected] input[type="checkbox"]'); - for (var i = 0; i < cboxes.length; i++) { + const cboxes = ul.querySelectorAll('[selected] input[type="checkbox"]'); + for (let i = 0; i < cboxes.length; i++) { cboxes[i].checked = true; cboxes[i].disabled = (cboxes.length == 1 && !this.options.optional); - }; + } ul.classList.add('dropdown'); sb.insertBefore(pv, ul.nextElementSibling); - li.forEach(function(l) { + li.forEach(l => { if (!l.hasAttribute('unselectable')) l.setAttribute('tabindex', 0); }); sb.lastElementChild.setAttribute('tabindex', 0); - var focusFn = L.bind(function(el) { + const focusFn = L.bind((el) => { this.setFocus(sb, el, true); ul.removeEventListener('transitionend', focusFn); - }, this, sel || li[0]); + }, this, sel ?? li[0]); ul.addEventListener('transitionend', focusFn); }, /** @private */ - closeDropdown: function(sb, no_focus) { + closeDropdown(sb, no_focus) { if (!sb.hasAttribute('open')) return; - var pv = sb.querySelector('ul.preview'), - ul = sb.querySelector('ul.dropdown'), - li = ul.querySelectorAll('li'), - fl = findParent(sb, '.cbi-value-field'); + const pv = sb.querySelector('ul.preview'); + const ul = sb.querySelector('ul.dropdown'); + const li = ul.querySelectorAll('li'); + const fl = findParent(sb, '.cbi-value-field'); - li.forEach(function(l) { l.removeAttribute('tabindex'); }); + li.forEach(l => l.removeAttribute('tabindex')); sb.lastElementChild.removeAttribute('tabindex'); sb.removeChild(pv); @@ -5020,20 +5020,20 @@ var UIDropdown = UIElement.extend(/** @lends LuCI.ui.Dropdown.prototype */ { }, /** @private */ - toggleItem: function(sb, li, force_state) { - var ul = li.parentNode; + toggleItem(sb, li, force_state) { + const ul = li.parentNode; if (li.hasAttribute('unselectable')) return; if (this.options.multiple) { - var cbox = li.querySelector('input[type="checkbox"]'), - items = li.parentNode.querySelectorAll('li'), - label = sb.querySelector('ul.preview'), - sel = li.parentNode.querySelectorAll('[selected]').length, - more = sb.querySelector('.more'), - ndisplay = this.options.display_items, - n = 0; + const cbox = li.querySelector('input[type="checkbox"]'); + const items = li.parentNode.querySelectorAll('li'); + const label = sb.querySelector('ul.preview'); + let sel = li.parentNode.querySelectorAll('[selected]').length; + const more = sb.querySelector('.more'); + let ndisplay = this.options.display_items; + let n = 0; if (li.hasAttribute('selected')) { if (force_state !== true) { @@ -5059,7 +5059,7 @@ var UIDropdown = UIElement.extend(/** @lends LuCI.ui.Dropdown.prototype */ { while (label && label.firstElementChild) label.removeChild(label.firstElementChild); - for (var i = 0; i < items.length; i++) { + for (let i = 0; i < items.length; i++) { items[i].removeAttribute('display'); if (items[i].hasAttribute('selected')) { if (ndisplay-- > 0) { @@ -5067,7 +5067,7 @@ var UIDropdown = UIElement.extend(/** @lends LuCI.ui.Dropdown.prototype */ { if (label) label.appendChild(items[i].cloneNode(true)); } - var c = items[i].querySelector('input[type="checkbox"]'); + const c = items[i].querySelector('input[type="checkbox"]'); if (c) c.disabled = (sel == 1 && !this.options.optional); } @@ -5084,10 +5084,10 @@ var UIDropdown = UIElement.extend(/** @lends LuCI.ui.Dropdown.prototype */ { sb.removeAttribute('empty'); dom.content(more, (ndisplay === this.options.display_items) - ? (this.options.select_placeholder || this.options.placeholder) : '···'); + ? (this.options.select_placeholder ?? this.options.placeholder) : '···'); } else { - var sel = li.parentNode.querySelector('[selected]'); + let sel = li.parentNode.querySelector('[selected]'); if (sel) { sel.removeAttribute('display'); sel.removeAttribute('selected'); @@ -5103,9 +5103,9 @@ var UIDropdown = UIElement.extend(/** @lends LuCI.ui.Dropdown.prototype */ { }, /** @private */ - transformItem: function(sb, li) { - var cbox = E('form', {}, E('input', { type: 'checkbox', tabindex: -1, onclick: 'event.preventDefault()' })), - label = E('label'); + transformItem(sb, li) { + const cbox = E('form', {}, E('input', { type: 'checkbox', tabindex: -1, onclick: 'event.preventDefault()' })); + const label = E('label'); while (li.firstChild) label.appendChild(li.firstChild); @@ -5115,21 +5115,21 @@ var UIDropdown = UIElement.extend(/** @lends LuCI.ui.Dropdown.prototype */ { }, /** @private */ - saveValues: function(sb, ul) { - var sel = ul.querySelectorAll('li[selected]'), - div = sb.lastElementChild, - name = this.options.name, - strval = '', - values = []; + saveValues(sb, ul) { + const sel = ul.querySelectorAll('li[selected]'); + const div = sb.lastElementChild; + const name = this.options.name; + let strval = ''; + const values = []; while (div.lastElementChild) div.removeChild(div.lastElementChild); - sel.forEach(function (s) { + sel.forEach(s => { if (s.hasAttribute('placeholder')) return; - var v = { + const v = { text: s.innerText, value: s.hasAttribute('data-value') ? s.getAttribute('data-value') : s.innerText, element: s @@ -5143,10 +5143,10 @@ var UIDropdown = UIElement.extend(/** @lends LuCI.ui.Dropdown.prototype */ { values.push(v); - strval += strval.length ? ' ' + v.value : v.value; + strval += strval.length ? ` ${v.value}` : v.value; }); - var detail = { + const detail = { instance: this, element: sb }; @@ -5165,11 +5165,11 @@ var UIDropdown = UIElement.extend(/** @lends LuCI.ui.Dropdown.prototype */ { }, /** @private */ - setValues: function(sb, values) { - var ul = sb.querySelector('ul'); + setValues(sb, values) { + const ul = sb.querySelector('ul'); if (this.options.create) { - for (var value in values) { + for (const value in values) { this.createItems(sb, value); if (!this.options.multiple) @@ -5178,9 +5178,9 @@ var UIDropdown = UIElement.extend(/** @lends LuCI.ui.Dropdown.prototype */ { } if (this.options.multiple) { - var lis = ul.querySelectorAll('li[data-value]'); - for (var i = 0; i < lis.length; i++) { - var value = lis[i].getAttribute('data-value'); + const lis = ul.querySelectorAll('li[data-value]'); + for (let i = 0; i < lis.length; i++) { + const value = lis[i].getAttribute('data-value'); if (values === null || !(value in values)) this.toggleItem(sb, lis[i], false); else @@ -5188,13 +5188,13 @@ var UIDropdown = UIElement.extend(/** @lends LuCI.ui.Dropdown.prototype */ { } } else { - var ph = ul.querySelector('li[placeholder]'); + const ph = ul.querySelector('li[placeholder]'); if (ph) this.toggleItem(sb, ph); - var lis = ul.querySelectorAll('li[data-value]'); - for (var i = 0; i < lis.length; i++) { - var value = lis[i].getAttribute('data-value'); + const lis = ul.querySelectorAll('li[data-value]'); + for (let i = 0; i < lis.length; i++) { + const value = lis[i].getAttribute('data-value'); if (values !== null && (value in values)) this.toggleItem(sb, lis[i]); } @@ -5202,11 +5202,11 @@ var UIDropdown = UIElement.extend(/** @lends LuCI.ui.Dropdown.prototype */ { }, /** @private */ - setFocus: function(sb, elem, scroll) { + setFocus(sb, elem, scroll) { if (sb.hasAttribute('locked-in')) return; - sb.querySelectorAll('.focus').forEach(function(e) { + sb.querySelectorAll('.focus').forEach(e => { e.classList.remove('focus'); }); @@ -5219,20 +5219,34 @@ var UIDropdown = UIElement.extend(/** @lends LuCI.ui.Dropdown.prototype */ { }, /** @private */ - createChoiceElement: function(sb, value, label) { - var tpl = sb.querySelector(this.options.create_template), - markup = null; + handleMouseout(ev) { + const sb = ev.currentTarget; + + if (!sb.hasAttribute('open')) + return; + + sb.querySelectorAll('.focus').forEach(e => { + e.classList.remove('focus'); + }); + + sb.querySelector('ul.dropdown').focus(); + }, + + /** @private */ + createChoiceElement(sb, value, label) { + const tpl = sb.querySelector(this.options.create_template); + let markup = null; if (tpl) - markup = (tpl.textContent || tpl.innerHTML || tpl.firstChild.data).replace(/^<!--|--!?>$/, '').trim(); + markup = (tpl.textContent ?? tpl.innerHTML ?? tpl.firstChild.data).replace(/^<!--|-->$/, '').trim(); else markup = '<li data-value="{{value}}"><span data-label-placeholder="true" /></li>'; - var new_item = E(markup.replace(/{{value}}/g, '%h'.format(value))), - placeholder = new_item.querySelector('[data-label-placeholder]'); + const new_item = E(markup.replace(/{{value}}/g, '%h'.format(value))); + const placeholder = new_item.querySelector('[data-label-placeholder]'); if (placeholder) { - var content = E('span', {}, label || this.choices[value] || [ value ]); + const content = E('span', {}, label ?? this.choices[value] ?? [ value ]); while (content.firstChild) placeholder.parentNode.insertBefore(content.firstChild, placeholder); @@ -5250,20 +5264,20 @@ var UIDropdown = UIElement.extend(/** @lends LuCI.ui.Dropdown.prototype */ { }, /** @private */ - createItems: function(sb, value) { - var sbox = this, - val = (value || '').trim(), - ul = sb.querySelector('ul'); + createItems(sb, value) { + const sbox = this; + let val = (value ?? '').trim(); + const ul = sb.querySelector('ul'); if (!sbox.options.multiple) val = val.length ? [ val ] : []; else val = val.length ? val.split(/\s+/) : []; - val.forEach(function(item) { - var new_item = null; + val.forEach(item => { + let new_item = null; - ul.childNodes.forEach(function(li) { + ul.childNodes.forEach(li => { if (li.getAttribute && li.getAttribute('data-value') === item) new_item = li; }); @@ -5272,7 +5286,7 @@ var UIDropdown = UIElement.extend(/** @lends LuCI.ui.Dropdown.prototype */ { new_item = sbox.createChoiceElement(sb, item); if (!sbox.options.multiple) { - var old = ul.querySelector('li[created]'); + const old = ul.querySelector('li[created]'); if (old) ul.removeChild(old); @@ -5300,14 +5314,14 @@ var UIDropdown = UIElement.extend(/** @lends LuCI.ui.Dropdown.prototype */ { * If set to `true`, deselect and remove selected choices as well instead * of keeping them. */ - clearChoices: function(reset_value) { - var ul = this.node.querySelector('ul'), - lis = ul ? ul.querySelectorAll('li[data-value]') : [], - len = lis.length - (this.options.create ? 1 : 0), - val = reset_value ? null : this.getValue(); - - for (var i = 0; i < len; i++) { - var lival = lis[i].getAttribute('data-value'); + clearChoices(reset_value) { + const ul = this.node.querySelector('ul'); + const lis = ul ? ul.querySelectorAll('li[data-value]') : []; + const len = lis.length - (this.options.create ? 1 : 0); + const val = reset_value ? null : this.getValue(); + + for (let i = 0; i < len; i++) { + const lival = lis[i].getAttribute('data-value'); if (val == null || (!this.options.multiple && val != lival) || (this.options.multiple && val.indexOf(lival) == -1)) @@ -5335,10 +5349,10 @@ var UIDropdown = UIElement.extend(/** @lends LuCI.ui.Dropdown.prototype */ { * as label text. Choice labels may be any valid value accepted by * {@link LuCI.dom#content}. */ - addChoices: function(values, labels) { - var sb = this.node, - ul = sb.querySelector('ul'), - lis = ul ? ul.querySelectorAll('li[data-value]') : []; + addChoices(values, labels) { + const sb = this.node; + const ul = sb.querySelector('ul'); + const lis = ul ? ul.querySelectorAll('li[data-value]') : []; if (!Array.isArray(values)) values = L.toArray(values); @@ -5346,10 +5360,10 @@ var UIDropdown = UIElement.extend(/** @lends LuCI.ui.Dropdown.prototype */ { if (!L.isObject(labels)) labels = {}; - for (var i = 0; i < values.length; i++) { - var found = false; + for (let i = 0; i < values.length; i++) { + let found = false; - for (var j = 0; j < lis.length; j++) { + for (let j = 0; j < lis.length; j++) { if (lis[j].getAttribute('data-value') === values[i]) { found = true; break; @@ -5368,22 +5382,22 @@ var UIDropdown = UIElement.extend(/** @lends LuCI.ui.Dropdown.prototype */ { /** * Close all open dropdown widgets in the current document. */ - closeAllDropdowns: function() { - document.querySelectorAll('.cbi-dropdown[open]').forEach(function(s) { + closeAllDropdowns() { + document.querySelectorAll('.cbi-dropdown[open]').forEach(s => { s.dispatchEvent(new CustomEvent('cbi-dropdown-close', {})); }); }, /** @private */ - handleClick: function(ev) { - var sb = ev.currentTarget; + handleClick(ev) { + const sb = ev.currentTarget; if (!sb.hasAttribute('open')) { if (!matchesElem(ev.target, 'input')) this.openDropdown(sb); } else { - var li = findParent(ev.target, 'li'); + const li = findParent(ev.target, 'li'); if (li && li.parentNode.classList.contains('dropdown')) this.toggleItem(sb, li); else if (li && li.parentNode.classList.contains('preview')) @@ -5397,9 +5411,9 @@ var UIDropdown = UIElement.extend(/** @lends LuCI.ui.Dropdown.prototype */ { }, /** @private */ - handleKeydown: function(ev) { - var sb = ev.currentTarget, - ul = sb.querySelector('ul.dropdown'); + handleKeydown(ev) { + const sb = ev.currentTarget; + const ul = sb.querySelector('ul.dropdown'); if (matchesElem(ev.target, 'input')) return; @@ -5415,7 +5429,7 @@ var UIDropdown = UIElement.extend(/** @lends LuCI.ui.Dropdown.prototype */ { } } else { - var active = findParent(document.activeElement, 'li'); + const active = findParent(document.activeElement, 'li'); switch (ev.keyCode) { case 27: @@ -5452,10 +5466,10 @@ var UIDropdown = UIElement.extend(/** @lends LuCI.ui.Dropdown.prototype */ { case 40: if (active && active.nextElementSibling) { - var li = active.nextElementSibling; + const li = active.nextElementSibling; this.setFocus(sb, li); if (this.options.create && li == li.parentNode.lastElementChild) { - var input = li.querySelector('input:not([type="hidden"]):not([type="checkbox"]'); + const input = li.querySelector('input:not([type="hidden"]):not([type="checkbox"]'); if (input) input.focus(); } ev.preventDefault(); @@ -5470,16 +5484,16 @@ var UIDropdown = UIElement.extend(/** @lends LuCI.ui.Dropdown.prototype */ { }, /** @private */ - handleDropdownClose: function(ev) { - var sb = ev.currentTarget; + handleDropdownClose(ev) { + const sb = ev.currentTarget; this.closeDropdown(sb, true); }, /** @private */ - handleDropdownSelect: function(ev) { - var sb = ev.currentTarget, - li = findParent(ev.target, 'li'); + handleDropdownSelect(ev) { + const sb = ev.currentTarget; + const li = findParent(ev.target, 'li'); if (!li) return; @@ -5489,25 +5503,38 @@ var UIDropdown = UIElement.extend(/** @lends LuCI.ui.Dropdown.prototype */ { }, /** @private */ - handleFocus: function(ev) { - var sb = ev.currentTarget; + handleMouseover(ev) { + const sb = ev.currentTarget; + + if (!sb.hasAttribute('open')) + return; + + const li = findParent(ev.target, 'li'); + + if (li && li.parentNode.classList.contains('dropdown')) + this.setFocus(sb, li); + }, + + /** @private */ + handleFocus(ev) { + const sb = ev.currentTarget; - document.querySelectorAll('.cbi-dropdown[open]').forEach(function(s) { + document.querySelectorAll('.cbi-dropdown[open]').forEach(s => { if (s !== sb || sb.hasAttribute('open')) s.dispatchEvent(new CustomEvent('cbi-dropdown-close', {})); }); }, /** @private */ - handleCanaryFocus: function(ev) { + handleCanaryFocus(ev) { this.closeDropdown(ev.currentTarget.parentNode); }, /** @private */ - handleCreateKeydown: function(ev) { - var input = ev.currentTarget, - li = findParent(input, 'li'), - sb = findParent(li, '.cbi-dropdown'); + handleCreateKeydown(ev) { + const input = ev.currentTarget; + const li = findParent(input, 'li'); + const sb = findParent(li, '.cbi-dropdown'); switch (ev.keyCode) { case 13: @@ -5538,11 +5565,11 @@ var UIDropdown = UIElement.extend(/** @lends LuCI.ui.Dropdown.prototype */ { }, /** @private */ - handleCreateFocus: function(ev) { - var input = ev.currentTarget, - li = findParent(input, 'li'), - cbox = li.querySelector('input[type="checkbox"]'), - sb = findParent(input, '.cbi-dropdown'); + handleCreateFocus(ev) { + const input = ev.currentTarget; + const li = findParent(input, 'li'); + const cbox = li.querySelector('input[type="checkbox"]'); + const sb = findParent(input, '.cbi-dropdown'); if (cbox) cbox.checked = true; @@ -5552,10 +5579,10 @@ var UIDropdown = UIElement.extend(/** @lends LuCI.ui.Dropdown.prototype */ { }, /** @private */ - handleCreateBlur: function(ev) { - var input = ev.currentTarget, - cbox = findParent(input, 'li').querySelector('input[type="checkbox"]'), - sb = findParent(input, '.cbi-dropdown'); + handleCreateBlur(ev) { + const input = ev.currentTarget; + const cbox = findParent(input, 'li').querySelector('input[type="checkbox"]'); + const sb = findParent(input, '.cbi-dropdown'); if (cbox) cbox.checked = false; @@ -5564,25 +5591,25 @@ var UIDropdown = UIElement.extend(/** @lends LuCI.ui.Dropdown.prototype */ { }, /** @private */ - handleCreateClick: function(ev) { + handleCreateClick(ev) { ev.currentTarget.querySelector(this.options.create_query).focus(); }, /** @override */ - setValue: function(values) { + setValue(values) { if (this.options.multiple) { if (!Array.isArray(values)) values = (values != null && values != '') ? [ values ] : []; - var v = {}; + const v = {}; - for (var i = 0; i < values.length; i++) + for (let i = 0; i < values.length; i++) v[values[i]] = true; this.setValues(this.node, v); } else { - var v = {}; + const v = {}; if (values != null) { if (Array.isArray(values)) @@ -5596,12 +5623,12 @@ var UIDropdown = UIElement.extend(/** @lends LuCI.ui.Dropdown.prototype */ { }, /** @override */ - getValue: function() { - var div = this.node.lastElementChild, - h = div.querySelectorAll('input[type="hidden"]'), - v = []; + getValue() { + const div = this.node.lastElementChild; + const h = div.querySelectorAll('input[type="hidden"]'); + const v = []; - for (var i = 0; i < h.length; i++) + for (let i = 0; i < h.length; i++) v.push(h[i].value); return this.options.multiple ? v : v[0]; @@ -5642,7 +5669,7 @@ var UIDropdown = UIElement.extend(/** @lends LuCI.ui.Dropdown.prototype */ { * @param {LuCI.ui.Combobox.InitOptions} [options] * Object describing the widget specific options to initialize the dropdown. */ -var UICombobox = UIDropdown.extend(/** @lends LuCI.ui.Combobox.prototype */ { +const UICombobox = UIDropdown.extend(/** @lends LuCI.ui.Combobox.prototype */ { /** * Comboboxes support the same properties as * [Dropdown.InitOptions]{@link LuCI.ui.Dropdown.InitOptions} but enforce @@ -5663,7 +5690,7 @@ var UICombobox = UIDropdown.extend(/** @lends LuCI.ui.Combobox.prototype */ { * Since Comboboxes are always optional, this property is forcibly set to * `true`. */ - __init__: function(value, choices, options) { + __init__(value, choices, options) { this.super('__init__', [ value, choices, Object.assign({ select_placeholder: _('-- Please choose --'), custom_placeholder: _('-- custom --'), @@ -5709,7 +5736,7 @@ var UICombobox = UIDropdown.extend(/** @lends LuCI.ui.Combobox.prototype */ { * @param {LuCI.ui.ComboButton.InitOptions} [options] * Object describing the widget specific options to initialize the button. */ -var UIComboButton = UIDropdown.extend(/** @lends LuCI.ui.ComboButton.prototype */ { +const UIComboButton = UIDropdown.extend(/** @lends LuCI.ui.ComboButton.prototype */ { /** * ComboButtons support the same properties as * [Dropdown.InitOptions]{@link LuCI.ui.Dropdown.InitOptions} but enforce @@ -5746,7 +5773,7 @@ var UIComboButton = UIDropdown.extend(/** @lends LuCI.ui.ComboButton.prototype * * and receive the DOM click event as first as well as the selected action * choice value as second argument. */ - __init__: function(value, choices, options) { + __init__(value, choices, options) { this.super('__init__', [ value, choices, Object.assign({ sort: true }, options, { @@ -5757,35 +5784,35 @@ var UIComboButton = UIDropdown.extend(/** @lends LuCI.ui.ComboButton.prototype * }, /** @override */ - render: function(/* ... */) { - var node = UIDropdown.prototype.render.apply(this, arguments), - val = this.getValue(); + render(...args) { + const node = UIDropdown.prototype.render.call(this, ...args); + const val = this.getValue(); if (L.isObject(this.options.classes) && this.options.classes.hasOwnProperty(val)) - node.setAttribute('class', 'cbi-dropdown ' + this.options.classes[val]); + node.setAttribute('class', `cbi-dropdown ${this.options.classes[val]}`); return node; }, /** @private */ - handleClick: function(ev) { - var sb = ev.currentTarget, - t = ev.target; + handleClick(ev, ...args) { + const sb = ev.currentTarget; + const t = ev.target; if (sb.hasAttribute('open') || dom.matches(t, '.cbi-dropdown > span.open')) - return UIDropdown.prototype.handleClick.apply(this, arguments); + return UIDropdown.prototype.handleClick.call(this, ev, ...args); if (this.options.click) return this.options.click.call(sb, ev, this.getValue()); }, /** @private */ - toggleItem: function(sb /*, ... */) { - var rv = UIDropdown.prototype.toggleItem.apply(this, arguments), - val = this.getValue(); + toggleItem(sb, ...args) { + const rv = UIDropdown.prototype.toggleItem.call(this, sb, ...args); + const val = this.getValue(); if (L.isObject(this.options.classes) && this.options.classes.hasOwnProperty(val)) - sb.setAttribute('class', 'cbi-dropdown ' + this.options.classes[val]); + sb.setAttribute('class', `cbi-dropdown ${this.options.classes[val]}`); else sb.setAttribute('class', 'cbi-dropdown'); @@ -5828,7 +5855,7 @@ var UIComboButton = UIDropdown.extend(/** @lends LuCI.ui.ComboButton.prototype * * @param {LuCI.ui.DynamicList.InitOptions} [options] * Object describing the widget specific options to initialize the dynamic list. */ -var UIDynamicList = UIElement.extend(/** @lends LuCI.ui.DynamicList.prototype */ { +const UIDynamicList = UIElement.extend(/** @lends LuCI.ui.DynamicList.prototype */ { /** * In case choices are passed to the dynamic list constructor, the widget * supports the same properties as [Dropdown.InitOptions]{@link LuCI.ui.Dropdown.InitOptions} @@ -5846,7 +5873,7 @@ var UIDynamicList = UIElement.extend(/** @lends LuCI.ui.DynamicList.prototype */ * predefined choice values, the dropdown must be made optional to allow * it to remain unselected. */ - __init__: function(values, choices, options) { + __init__(values, choices, options) { if (!Array.isArray(values)) values = (values != null && values != '') ? [ values ] : []; @@ -5862,8 +5889,8 @@ var UIDynamicList = UIElement.extend(/** @lends LuCI.ui.DynamicList.prototype */ }, /** @override */ - render: function() { - var dl = E('div', { + render() { + const dl = E('div', { 'id': this.options.id, 'class': 'cbi-dynlist', 'disabled': this.options.disabled ? '' : null @@ -5873,13 +5900,13 @@ var UIDynamicList = UIElement.extend(/** @lends LuCI.ui.DynamicList.prototype */ if (this.options.placeholder != null) this.options.select_placeholder = this.options.placeholder; - var cbox = new UICombobox(null, this.choices, this.options); + const cbox = new UICombobox(null, this.choices, this.options); dl.lastElementChild.appendChild(cbox.render()); } else { - var inputEl = E('input', { - 'id': this.options.id ? 'widget.' + this.options.id : null, + const inputEl = E('input', { + 'id': this.options.id ? `widget.${this.options.id}` : null, 'type': 'text', 'class': 'cbi-input-text', 'placeholder': this.options.placeholder, @@ -5890,12 +5917,12 @@ var UIDynamicList = UIElement.extend(/** @lends LuCI.ui.DynamicList.prototype */ dl.lastElementChild.appendChild(E('div', { 'class': 'btn cbi-button cbi-button-add' }, '+')); if (this.options.datatype || this.options.validate) - UI.prototype.addValidator(inputEl, this.options.datatype || 'string', + UI.prototype.addValidator(inputEl, this.options.datatype ?? 'string', true, this.options.validate, 'blur', 'keyup'); } - for (var i = 0; i < this.values.length; i++) { - var label = this.choices ? this.choices[this.values[i]] : null; + for (let i = 0; i < this.values.length; i++) { + let label = this.choices ? this.choices[this.values[i]] : null; if (dom.elem(label)) label = label.cloneNode(true); @@ -5909,7 +5936,7 @@ var UIDynamicList = UIElement.extend(/** @lends LuCI.ui.DynamicList.prototype */ }, /** @private */ - initDragAndDrop: function(dl) { + initDragAndDrop(dl) { let draggedItem = null; let placeholder = null; @@ -5996,7 +6023,7 @@ var UIDynamicList = UIElement.extend(/** @lends LuCI.ui.DynamicList.prototype */ }, /** @private */ - bind: function(dl) { + bind(dl) { dl.addEventListener('click', L.bind(this.handleClick, this)); dl.addEventListener('keydown', L.bind(this.handleKeydown, this)); dl.addEventListener('cbi-dropdown-change', L.bind(this.handleDropdownChange, this)); @@ -6012,20 +6039,21 @@ var UIDynamicList = UIElement.extend(/** @lends LuCI.ui.DynamicList.prototype */ }, /** @private */ - addItem: function(dl, value, text, flash) { - var exists = false, - new_item = E('div', { 'class': flash ? 'item flash' : 'item', 'tabindex': 0, 'draggable': true }, [ - E('span', {}, [ text || value ]), - E('input', { - 'type': 'hidden', - 'name': this.options.name, - 'value': value })]); + addItem(dl, value, text, flash) { + let exists = false; - dl.querySelectorAll('.item').forEach(function(item) { + const new_item = E('div', { 'class': flash ? 'item flash' : 'item', 'tabindex': 0, 'draggable': true }, [ + E('span', {}, [ text ?? value ]), + E('input', { + 'type': 'hidden', + 'name': this.options.name, + 'value': value })]); + + dl.querySelectorAll('.item').forEach(item => { if (exists) return; - var hidden = item.querySelector('input[type="hidden"]'); + let hidden = item.querySelector('input[type="hidden"]'); if (hidden && hidden.parentNode !== item) hidden = null; @@ -6035,7 +6063,7 @@ var UIDynamicList = UIElement.extend(/** @lends LuCI.ui.DynamicList.prototype */ }); if (!exists) { - var ai = dl.querySelector('.add-item'); + const ai = dl.querySelector('.add-item'); ai.parentNode.insertBefore(new_item, ai); } @@ -6051,11 +6079,11 @@ var UIDynamicList = UIElement.extend(/** @lends LuCI.ui.DynamicList.prototype */ }, /** @private */ - removeItem: function(dl, item) { - var value = item.querySelector('input[type="hidden"]').value; - var sb = dl.querySelector('.cbi-dropdown'); + removeItem(dl, item) { + const value = item.querySelector('input[type="hidden"]').value; + const sb = dl.querySelector('.cbi-dropdown'); if (sb) - sb.querySelectorAll('ul > li').forEach(function(li) { + sb.querySelectorAll('ul > li').forEach(li => { if (li.getAttribute('data-value') === value) { if (li.hasAttribute('dynlistcustom')) li.parentNode.removeChild(li); @@ -6078,20 +6106,20 @@ var UIDynamicList = UIElement.extend(/** @lends LuCI.ui.DynamicList.prototype */ }, /** @private */ - handleClick: function(ev) { - var dl = ev.currentTarget, - item = findParent(ev.target, '.item'); + handleClick(ev) { + const dl = ev.currentTarget; + const item = findParent(ev.target, '.item'); if (this.options.disabled) return; if (item) { // Get bounding rectangle of the item - var rect = item.getBoundingClientRect(); + const rect = item.getBoundingClientRect(); // Get computed styles for the ::after pseudo-element - var afterStyles = window.getComputedStyle(item, '::after'); - var afterWidth = parseFloat(afterStyles.width) || 0; + const afterStyles = window.getComputedStyle(item, '::after'); + const afterWidth = parseFloat(afterStyles.width) || 0; // Check if the click is within the ::after region if (rect.right - ev.clientX <= afterWidth) { @@ -6099,7 +6127,7 @@ var UIDynamicList = UIElement.extend(/** @lends LuCI.ui.DynamicList.prototype */ } } else if (matchesElem(ev.target, '.cbi-button-add')) { - var input = ev.target.previousElementSibling; + const input = ev.target.previousElementSibling; if (input.value.length && !input.classList.contains('cbi-input-invalid')) { this.addItem(dl, input.value, null, true); input.value = ''; @@ -6108,11 +6136,11 @@ var UIDynamicList = UIElement.extend(/** @lends LuCI.ui.DynamicList.prototype */ }, /** @private */ - handleDropdownChange: function(ev) { - var dl = ev.currentTarget, - sbIn = ev.detail.instance, - sbEl = ev.detail.element, - sbVal = ev.detail.value; + handleDropdownChange(ev) { + const dl = ev.currentTarget; + const sbIn = ev.detail.instance; + const sbEl = ev.detail.element; + const sbVal = ev.detail.value; if (sbVal === null) return; @@ -6125,12 +6153,12 @@ var UIDynamicList = UIElement.extend(/** @lends LuCI.ui.DynamicList.prototype */ sbVal.element.setAttribute('dynlistcustom', ''); } - var label = sbVal.text; + let label = sbVal.text; if (sbVal.element) { label = E([]); - for (var i = 0; i < sbVal.element.childNodes.length; i++) + for (let i = 0; i < sbVal.element.childNodes.length; i++) label.appendChild(sbVal.element.childNodes[i].cloneNode(true)); } @@ -6138,9 +6166,9 @@ var UIDynamicList = UIElement.extend(/** @lends LuCI.ui.DynamicList.prototype */ }, /** @private */ - handleKeydown: function(ev) { - var dl = ev.currentTarget, - item = findParent(ev.target, '.item'); + handleKeydown(ev) { + const dl = ev.currentTarget; + const item = findParent(ev.target, '.item'); if (item) { switch (ev.keyCode) { @@ -6180,34 +6208,34 @@ var UIDynamicList = UIElement.extend(/** @lends LuCI.ui.DynamicList.prototype */ }, /** @override */ - getValue: function() { - var items = this.node.querySelectorAll('.item > input[type="hidden"]'), - input = this.node.querySelector('.add-item > input[type="text"]'), - v = []; + getValue() { + const items = this.node.querySelectorAll('.item > input[type="hidden"]'); + const input = this.node.querySelector('.add-item > input[type="text"]'); + const v = []; - for (var i = 0; i < items.length; i++) + for (let i = 0; i < items.length; i++) v.push(items[i].value); if (input && input.value != null && input.value.match(/\S/) && input.classList.contains('cbi-input-invalid') == false && - v.filter(function(s) { return s == input.value }).length == 0) + v.filter(s => s == input.value).length == 0) v.push(input.value); return v; }, /** @override */ - setValue: function(values) { + setValue(values) { if (!Array.isArray(values)) values = (values != null && values != '') ? [ values ] : []; - var items = this.node.querySelectorAll('.item'); + const items = this.node.querySelectorAll('.item'); - for (var i = 0; i < items.length; i++) + for (let i = 0; i < items.length; i++) if (items[i].parentNode === this.node) this.removeItem(this.node, items[i]); - for (var i = 0; i < values.length; i++) + for (let i = 0; i < values.length; i++) this.addItem(this.node, values[i], this.choices ? this.choices[values[i]] : null); }, @@ -6229,8 +6257,8 @@ var UIDynamicList = UIElement.extend(/** @lends LuCI.ui.DynamicList.prototype */ * as label text. Choice labels may be any valid value accepted by * {@link LuCI.dom#content}. */ - addChoices: function(values, labels) { - var dl = this.node.lastElementChild.firstElementChild; + addChoices(values, labels) { + const dl = this.node.lastElementChild.firstElementChild; dom.callClassMethod(dl, 'addChoices', values, labels); }, @@ -6242,8 +6270,8 @@ var UIDynamicList = UIElement.extend(/** @lends LuCI.ui.DynamicList.prototype */ * @instance * @memberof LuCI.ui.DynamicList */ - clearChoices: function() { - var dl = this.node.lastElementChild.firstElementChild; + clearChoices() { + const dl = this.node.lastElementChild.firstElementChild; dom.callClassMethod(dl, 'clearChoices'); } }); @@ -6275,8 +6303,8 @@ var UIDynamicList = UIElement.extend(/** @lends LuCI.ui.DynamicList.prototype */ * @param {LuCI.ui.AbstractElement.InitOptions} [options] * Object describing the widget specific options to initialize the hidden input. */ -var UIHiddenfield = UIElement.extend(/** @lends LuCI.ui.Hiddenfield.prototype */ { - __init__: function(value, options) { +const UIHiddenfield = UIElement.extend(/** @lends LuCI.ui.Hiddenfield.prototype */ { + __init__(value, options) { this.value = value; this.options = Object.assign({ @@ -6284,8 +6312,8 @@ var UIHiddenfield = UIElement.extend(/** @lends LuCI.ui.Hiddenfield.prototype */ }, /** @override */ - render: function() { - var hiddenEl = E('input', { + render() { + const hiddenEl = E('input', { 'id': this.options.id, 'type': 'hidden', 'value': this.value @@ -6295,7 +6323,7 @@ var UIHiddenfield = UIElement.extend(/** @lends LuCI.ui.Hiddenfield.prototype */ }, /** @private */ - bind: function(hiddenEl) { + bind(hiddenEl) { this.node = hiddenEl; dom.bindClassInstance(hiddenEl, this); @@ -6304,12 +6332,12 @@ var UIHiddenfield = UIElement.extend(/** @lends LuCI.ui.Hiddenfield.prototype */ }, /** @override */ - getValue: function() { + getValue() { return this.node.value; }, /** @override */ - setValue: function(value) { + setValue(value) { this.node.value = value; } }); @@ -6342,7 +6370,7 @@ var UIHiddenfield = UIElement.extend(/** @lends LuCI.ui.Hiddenfield.prototype */ * Object describing the widget specific options to initialize the file * upload control. */ -var UIFileUpload = UIElement.extend(/** @lends LuCI.ui.FileUpload.prototype */ { +const UIFileUpload = UIElement.extend(/** @lends LuCI.ui.FileUpload.prototype */ { /** * In addition to the [AbstractElement.InitOptions]{@link LuCI.ui.AbstractElement.InitOptions} * the following properties are recognized: @@ -6383,7 +6411,7 @@ var UIFileUpload = UIElement.extend(/** @lends LuCI.ui.FileUpload.prototype */ { * Whether remote directories are browsable or not solely depends on the * ACL setup for the current session. */ - __init__: function(value, options) { + __init__(value, options) { this.value = value; this.options = Object.assign({ browser: false, @@ -6396,7 +6424,7 @@ var UIFileUpload = UIElement.extend(/** @lends LuCI.ui.FileUpload.prototype */ { }, /** @private */ - bind: function(browserEl) { + bind(browserEl) { this.node = browserEl; this.setUpdateEvents(browserEl, 'cbi-fileupload-select', 'cbi-fileupload-cancel'); @@ -6408,9 +6436,9 @@ var UIFileUpload = UIElement.extend(/** @lends LuCI.ui.FileUpload.prototype */ { }, /** @override */ - render: function() { - var renderFileBrowser = L.resolveDefault(this.value != null ? fs.stat(this.value) : null).then(L.bind(function(stat) { - var label; + render() { + const renderFileBrowser = L.resolveDefault(this.value != null ? fs.stat(this.value) : null).then(L.bind((stat) => { + let label; if (L.isObject(stat) && stat.type != 'directory') this.stat = stat; @@ -6426,7 +6454,7 @@ var UIFileUpload = UIElement.extend(/** @lends LuCI.ui.FileUpload.prototype */ { 'click': UI.prototype.createHandlerFn(this, 'handleFileBrowser'), 'disabled': this.options.disabled ? '' : null }, label); - var fileBrowserEl = E('div', { 'id': this.options.id }, [ + const fileBrowserEl = E('div', { 'id': this.options.id }, [ btnOpenFileBrowser, E('div', { 'class': 'cbi-filebrowser' @@ -6441,8 +6469,8 @@ var UIFileUpload = UIElement.extend(/** @lends LuCI.ui.FileUpload.prototype */ { }, this)); // in a browser mode open dir listing after render by clicking on a Select button if (this.options.browser) { - return renderFileBrowser.then(function (fileBrowserEl) { - var btnOpenFileBrowser = fileBrowserEl.getElementsByClassName('open-file-browser').item(0); + return renderFileBrowser.then((fileBrowserEl) => { + const btnOpenFileBrowser = fileBrowserEl.getElementsByClassName('open-file-browser').item(0); btnOpenFileBrowser.click(); return fileBrowserEl; }); @@ -6451,15 +6479,15 @@ var UIFileUpload = UIElement.extend(/** @lends LuCI.ui.FileUpload.prototype */ { }, /** @private */ - truncatePath: function(path) { + truncatePath(path) { if (path.length > 50) - path = path.substring(0, 25) + '…' + path.substring(path.length - 25); + path = `${path.substring(0, 25)}…${path.substring(path.length - 25)}`; return path; }, /** @private */ - iconForType: function(type) { + iconForType(type) { switch (type) { case 'symlink': return E('img', { @@ -6488,7 +6516,7 @@ var UIFileUpload = UIElement.extend(/** @lends LuCI.ui.FileUpload.prototype */ { }, /** @private */ - canonicalizePath: function(path) { + canonicalizePath(path) { return path.replace(/\/{2,}/, '/') .replace(/\/\.(\/|$)/g, '/') .replace(/[^\/]+\/\.\.(\/|$)/g, '/') @@ -6496,9 +6524,9 @@ var UIFileUpload = UIElement.extend(/** @lends LuCI.ui.FileUpload.prototype */ { }, /** @private */ - splitPath: function(path) { - var croot = this.canonicalizePath(this.options.root_directory || '/'), - cpath = this.canonicalizePath(path || '/'); + splitPath(path) { + const croot = this.canonicalizePath(this.options.root_directory ?? '/'); + const cpath = this.canonicalizePath(path ?? '/'); if (cpath.length <= croot.length) return [ croot ]; @@ -6506,7 +6534,7 @@ var UIFileUpload = UIElement.extend(/** @lends LuCI.ui.FileUpload.prototype */ { if (cpath.charAt(croot.length) != '/') return [ croot ]; - var parts = cpath.substring(croot.length + 1).split(/\//); + const parts = cpath.substring(croot.length + 1).split(/\//); parts.unshift(croot); @@ -6514,36 +6542,36 @@ var UIFileUpload = UIElement.extend(/** @lends LuCI.ui.FileUpload.prototype */ { }, /** @private */ - handleUpload: function(path, list, ev) { - var form = ev.target.parentNode, - fileinput = form.querySelector('input[type="file"]'), - nameinput = form.querySelector('input[type="text"]'), - filename = (nameinput.value != null ? nameinput.value : '').trim(); + handleUpload(path, list, ev) { + const form = ev.target.parentNode; + const fileinput = form.querySelector('input[type="file"]'); + const nameinput = form.querySelector('input[type="text"]'); + const filename = (nameinput.value != null ? nameinput.value : '').trim(); ev.preventDefault(); if (filename == '' || filename.match(/\//) || fileinput.files[0] == null) return; - var existing = list.filter(function(e) { return e.name == filename })[0]; + const existing = list.filter(e => e.name == filename)[0]; if (existing != null && existing.type == 'directory') return alert(_('A directory with the same name already exists.')); else if (existing != null && !confirm(_('Overwrite existing file "%s" ?').format(filename))) return; - var data = new FormData(); + const data = new FormData(); data.append('sessionid', L.env.sessionid); - data.append('filename', path + '/' + filename); + data.append('filename', `${path}/${filename}`); data.append('filedata', fileinput.files[0]); - return request.post(L.env.cgi_base + '/cgi-upload', data, { - progress: L.bind(function(btn, ev) { + return request.post(`${L.env.cgi_base}/cgi-upload`, data, { + progress: L.bind((btn, ev) => { btn.firstChild.data = '%.2f%%'.format((ev.loaded / ev.total) * 100); }, this, ev.target) - }).then(L.bind(function(path, ev, res) { - var reply = res.json(); + }).then(L.bind((path, ev, res) => { + const reply = res.json(); if (L.isObject(reply) && reply.failure) alert(_('Upload request failed: %s').format(reply.message)); @@ -6553,10 +6581,10 @@ var UIFileUpload = UIElement.extend(/** @lends LuCI.ui.FileUpload.prototype */ { }, /** @private */ - handleDelete: function(path, fileStat, ev) { - var parent = path.replace(/\/[^\/]+$/, '') || '/', - name = path.replace(/^.+\//, ''), - msg; + handleDelete(path, fileStat, ev) { + const parent = path.replace(/\/[^\/]+$/, '') ?? '/'; + const name = path.replace(/^.+\//, ''); + let msg; ev.preventDefault(); @@ -6566,24 +6594,24 @@ var UIFileUpload = UIElement.extend(/** @lends LuCI.ui.FileUpload.prototype */ { msg = _('Do you really want to delete "%s" ?').format(name); if (confirm(msg)) { - var button = this.node.firstElementChild, - hidden = this.node.lastElementChild; + const button = this.node.firstElementChild; + const hidden = this.node.lastElementChild; if (path == hidden.value) { dom.content(button, _('Select file…')); hidden.value = ''; } - return fs.remove(path).then(L.bind(function(parent, ev) { + return fs.remove(path).then(L.bind((parent, ev) => { return this.handleSelect(parent, null, ev); - }, this, parent, ev)).catch(function(err) { + }, this, parent, ev)).catch(err => { alert(_('Delete request failed: %s').format(err.message)); }); } }, /** @private */ - renderUpload: function(path, list) { + renderUpload(path, list) { if (!this.options.enable_upload) return E([]); @@ -6592,8 +6620,8 @@ var UIFileUpload = UIElement.extend(/** @lends LuCI.ui.FileUpload.prototype */ { 'href': '#', 'class': 'btn cbi-button-positive', 'click': function(ev) { - var uploadForm = ev.target.nextElementSibling, - fileInput = uploadForm.querySelector('input[type="file"]'); + const uploadForm = ev.target.nextElementSibling; + const fileInput = uploadForm.querySelector('input[type="file"]'); ev.target.style.display = 'none'; uploadForm.style.display = ''; @@ -6605,8 +6633,8 @@ var UIFileUpload = UIElement.extend(/** @lends LuCI.ui.FileUpload.prototype */ { 'type': 'file', 'style': 'display:none', 'change': function(ev) { - var nameinput = ev.target.parentNode.querySelector('input[type="text"]'), - uploadbtn = ev.target.parentNode.querySelector('button.cbi-button-save'); + const nameinput = ev.target.parentNode.querySelector('input[type="text"]'); + const uploadbtn = ev.target.parentNode.querySelector('button.cbi-button-save'); nameinput.value = ev.target.value.replace(/^.+[\/\\]/, ''); uploadbtn.disabled = false; @@ -6630,22 +6658,22 @@ var UIFileUpload = UIElement.extend(/** @lends LuCI.ui.FileUpload.prototype */ { }, /** @private */ - renderListing: function(container, path, list) { - var breadcrumb = E('p'), - rows = E('ul'); + renderListing(container, path, list) { + const breadcrumb = E('p'); + const rows = E('ul'); - list.sort(function(a, b) { + list.sort((a, b) => { return L.naturalCompare(a.type == 'directory', b.type == 'directory') || - L.naturalCompare(a.name, b.name); + L.naturalCompare(a.name, b.name); }); - for (var i = 0; i < list.length; i++) { + for (let i = 0; i < list.length; i++) { if (!this.options.show_hidden && list[i].name.charAt(0) == '.') continue; - var entrypath = this.canonicalizePath(path + '/' + list[i].name), - selected = (entrypath == this.node.lastElementChild.value), - mtime = new Date(list[i].mtime * 1000); + const entrypath = this.canonicalizePath(`${path}/${list[i].name}`); + const selected = (entrypath == this.node.lastElementChild.value); + const mtime = new Date(list[i].mtime * 1000); rows.appendChild(E('li', [ E('div', { 'class': 'name' }, [ @@ -6687,16 +6715,16 @@ var UIFileUpload = UIElement.extend(/** @lends LuCI.ui.FileUpload.prototype */ { if (!rows.firstElementChild) rows.appendChild(E('em', _('No entries in this directory'))); - var dirs = this.splitPath(path), - cur = ''; + const dirs = this.splitPath(path); + let cur = ''; - for (var i = 0; i < dirs.length; i++) { - cur = cur ? cur + '/' + dirs[i] : dirs[i]; + for (let i = 0; i < dirs.length; i++) { + cur = cur ? `${cur}/${dirs[i]}` : dirs[i]; dom.append(breadcrumb, [ i ? ' » ' : '', E('a', { 'href': '#', - 'click': UI.prototype.createHandlerFn(this, 'handleSelect', cur || '/', null) + 'click': UI.prototype.createHandlerFn(this, 'handleSelect', cur ?? '/', null) }, dirs[i] != '' ? '%h'.format(dirs[i]) : E('em', '(root)')), ]); } @@ -6716,9 +6744,9 @@ var UIFileUpload = UIElement.extend(/** @lends LuCI.ui.FileUpload.prototype */ { }, /** @private */ - handleCancel: function(ev) { - var button = this.node.firstElementChild, - browser = button.nextElementSibling; + handleCancel(ev) { + const button = this.node.firstElementChild; + const browser = button.nextElementSibling; browser.classList.remove('open'); button.style.display = ''; @@ -6729,9 +6757,9 @@ var UIFileUpload = UIElement.extend(/** @lends LuCI.ui.FileUpload.prototype */ { }, /** @private */ - handleReset: function(ev) { - var button = this.node.firstElementChild, - hidden = this.node.lastElementChild; + handleReset(ev) { + const button = this.node.firstElementChild; + const hidden = this.node.lastElementChild; hidden.value = ''; dom.content(button, _('Select file…')); @@ -6740,33 +6768,33 @@ var UIFileUpload = UIElement.extend(/** @lends LuCI.ui.FileUpload.prototype */ { }, /** @private */ - handleDownload: function(path, fileStat, ev) { - fs.read_direct(path, 'blob').then(function (blob) { - var url = window.URL.createObjectURL(blob); - var a = document.createElement('a'); + handleDownload(path, fileStat, ev) { + fs.read_direct(path, 'blob').then((blob) => { + const url = window.URL.createObjectURL(blob); + let a = document.createElement('a'); a.style.display = 'none'; a.href = url; a.download = fileStat.name; document.body.appendChild(a); a.click(); window.URL.revokeObjectURL(url); - }).catch(function(err) { + }).catch((err) => { alert(_('Download failed: %s').format(err.message)); }); }, /** @private */ - handleSelect: function(path, fileStat, ev) { - var browser = dom.parent(ev.target, '.cbi-filebrowser'), - ul = browser.querySelector('ul'); + handleSelect(path, fileStat, ev) { + const browser = dom.parent(ev.target, '.cbi-filebrowser'); + const ul = browser.querySelector('ul'); if (fileStat == null) { dom.content(ul, E('em', { 'class': 'spinning' }, _('Loading directory contents…'))); L.resolveDefault(fs.list(path), []).then(L.bind(this.renderListing, this, browser, path)); } else if (!this.options.browser) { - var button = this.node.firstElementChild, - hidden = this.node.lastElementChild; + const button = this.node.firstElementChild; + const hidden = this.node.lastElementChild; path = this.canonicalizePath(path); @@ -6785,18 +6813,18 @@ var UIFileUpload = UIElement.extend(/** @lends LuCI.ui.FileUpload.prototype */ { }, /** @private */ - handleFileBrowser: function(ev) { - var button = ev.target, - browser = button.nextElementSibling, - path = this.stat ? this.stat.path.replace(/\/[^\/]+$/, '') : (this.options.initial_directory || this.options.root_directory); + handleFileBrowser(ev) { + const button = ev.target; + const browser = button.nextElementSibling; + let path = this.stat ? this.stat.path.replace(/\/[^\/]+$/, '') : (this.options.initial_directory ?? this.options.root_directory); if (path.indexOf(this.options.root_directory) != 0) path = this.options.root_directory; ev.preventDefault(); - return L.resolveDefault(fs.list(path), []).then(L.bind(function(button, browser, path, list) { - document.querySelectorAll('.cbi-filebrowser.open').forEach(function(browserEl) { + return L.resolveDefault(fs.list(path), []).then(L.bind((button, browser, path, list) => { + document.querySelectorAll('.cbi-filebrowser.open').forEach(browserEl => { dom.findClassInstance(browserEl).handleCancel(ev); }); @@ -6808,36 +6836,36 @@ var UIFileUpload = UIElement.extend(/** @lends LuCI.ui.FileUpload.prototype */ { }, /** @override */ - getValue: function() { + getValue() { return this.node.lastElementChild.value; }, /** @override */ - setValue: function(value) { + setValue(value) { this.node.lastElementChild.value = value; } }); function scrubMenu(node) { - var hasSatisfiedChild = false; + let hasSatisfiedChild = false; if (L.isObject(node.children)) { - for (var k in node.children) { - var child = scrubMenu(node.children[k]); + for (const k in node.children) { + const child = scrubMenu(node.children[k]); if (child.title && !child.firstchild_ineligible) - hasSatisfiedChild = hasSatisfiedChild || child.satisfied; + hasSatisfiedChild ||= child.satisfied; } } if (L.isObject(node.action) && - node.action.type == 'firstchild' && - hasSatisfiedChild == false) + node.action.type == 'firstchild' && + hasSatisfiedChild == false) node.satisfied = false; return node; -}; +} /** * Handle menu. @@ -6849,7 +6877,7 @@ function scrubMenu(node) { * * Handles menus. */ -var UIMenu = baseclass.singleton(/** @lends LuCI.ui.menu.prototype */ { +const UIMenu = baseclass.singleton(/** @lends LuCI.ui.menu.prototype */ { /** * @typedef {Object} MenuNode * @memberof LuCI.ui.menu @@ -6868,12 +6896,12 @@ var UIMenu = baseclass.singleton(/** @lends LuCI.ui.menu.prototype */ { * @returns {Promise<LuCI.ui.menu.MenuNode>} * Returns a promise resolving to the root element of the menu tree. */ - load: function() { + load() { if (this.menu == null) this.menu = session.getLocalData('menu'); if (!L.isObject(this.menu)) { - this.menu = request.get(L.url('admin/menu')).then(L.bind(function(menu) { + this.menu = request.get(L.url('admin/menu')).then(L.bind((menu) => { this.menu = scrubMenu(menu.json()); session.setLocalData('menu', this.menu); @@ -6888,7 +6916,7 @@ var UIMenu = baseclass.singleton(/** @lends LuCI.ui.menu.prototype */ { * Flush the internal menu cache to force loading a new structure on the * next page load. */ - flushCache: function() { + flushCache() { session.setLocalData('menu', null); }, @@ -6900,13 +6928,13 @@ var UIMenu = baseclass.singleton(/** @lends LuCI.ui.menu.prototype */ { * @returns {LuCI.ui.menu.MenuNode[]} * Returns an array of child menu nodes. */ - getChildren: function(node) { - var children = []; + getChildren(node) { + const children = []; if (node == null) node = this.menu; - for (var k in node.children) { + for (const k in node.children) { if (!node.children.hasOwnProperty(k)) continue; @@ -6916,14 +6944,14 @@ var UIMenu = baseclass.singleton(/** @lends LuCI.ui.menu.prototype */ { if (!node.children[k].hasOwnProperty('title')) continue; - var subnode = Object.assign(node.children[k], { name: k }); + let subnode = Object.assign(node.children[k], { name: k }); if (L.isObject(subnode.action) && subnode.action.path != null && - (subnode.action.type == 'alias' || subnode.action.type == 'rewrite')) { - var root = this.menu, - path = subnode.action.path.split('/'); + (subnode.action.type == 'alias' || subnode.action.type == 'rewrite')) { + let root = this.menu; + const path = subnode.action.path.split('/'); - for (var i = 0; root != null && i < path.length; i++) + for (let i = 0; root != null && i < path.length; i++) root = L.isObject(root.children) ? root.children[path[i]] : null; if (root) @@ -6936,9 +6964,9 @@ var UIMenu = baseclass.singleton(/** @lends LuCI.ui.menu.prototype */ { children.push(subnode); } - return children.sort(function(a, b) { - var wA = a.order || 1000, - wB = b.order || 1000; + return children.sort((a, b) => { + const wA = a.order ?? 1000; + const wB = b.order ?? 1000; if (wA != wB) return wA - wB; @@ -6948,17 +6976,17 @@ var UIMenu = baseclass.singleton(/** @lends LuCI.ui.menu.prototype */ { } }); -var UITable = baseclass.extend(/** @lends LuCI.ui.table.prototype */ { - __init__: function(captions, options, placeholder) { +const UITable = baseclass.extend(/** @lends LuCI.ui.table.prototype */ { + __init__(captions, options, placeholder) { if (!Array.isArray(captions)) { this.initFromMarkup(captions); return; } - var id = options.id || 'table%08x'.format(Math.random() * 0xffffffff); + const id = options.id ?? 'table%08x'.format(Math.random() * 0xffffffff); - var table = E('table', { 'id': id, 'class': 'table' }, [ + const table = E('table', { 'id': id, 'class': 'table' }, [ E('tr', { 'class': 'tr table-titles', 'click': UI.prototype.createHandlerFn(this, 'handleSort') }) ]); @@ -6966,13 +6994,13 @@ var UITable = baseclass.extend(/** @lends LuCI.ui.table.prototype */ { this.node = table this.options = options; - var sorting = this.getActiveSortState(); + const sorting = this.getActiveSortState(); - for (var i = 0; i < captions.length; i++) { + for (let i = 0; i < captions.length; i++) { if (captions[i] == null) continue; - var th = E('th', { 'class': 'th' }, [ captions[i] ]); + const th = E('th', { 'class': 'th' }, [ captions[i] ]); if (typeof(options.captionClasses) == 'object') DOMTokenList.prototype.add.apply(th.classList, L.toArray(options.captionClasses[i])); @@ -6988,8 +7016,8 @@ var UITable = baseclass.extend(/** @lends LuCI.ui.table.prototype */ { } if (placeholder) { - var trow = table.appendChild(E('tr', { 'class': 'tr placeholder' })), - td = trow.appendChild(E('td', { 'class': 'td' }, placeholder)); + const trow = table.appendChild(E('tr', { 'class': 'tr placeholder' })); + const td = trow.appendChild(E('td', { 'class': 'td' }, placeholder)); if (typeof(captionClasses) == 'object') DOMTokenList.prototype.add.apply(td.classList, L.toArray(captionClasses[0])); @@ -6998,30 +7026,21 @@ var UITable = baseclass.extend(/** @lends LuCI.ui.table.prototype */ { 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(); + update(data, placeholderText) { + const placeholder = placeholderText ?? this.options.placeholder ?? _('No data', 'empty table placeholder'); + const sorting = this.getActiveSortState(); if (!Array.isArray(data)) return; - this.data = data; - this.placeholder = placeholder; - - var n = 0, - rows = this.node.querySelectorAll('tr, .tr'), - trows = [], - headings = [].slice.call(this.node.firstElementChild.querySelectorAll('th, .th')), - captionClasses = this.options.captionClasses, - trTag = (rows[0] && rows[0].nodeName == 'DIV') ? 'div' : 'tr', - tdTag = (headings[0] && headings[0].nodeName == 'DIV') ? 'div' : 'td'; + const headings = [].slice.call(this.node.firstElementChild.querySelectorAll('th, .th')); if (sorting) { - var list = data.map(L.bind(function(row) { + const list = data.map(L.bind((row) => { return [ this.deriveSortKey(row[sorting[0]], sorting[0]), row ]; }, this)); - list.sort(function(a, b) { + list.sort((a, b) => { return sorting[1] ? -L.naturalCompare(a[0], b[0]) : L.naturalCompare(a[0], b[0]); @@ -7029,11 +7048,11 @@ var UITable = baseclass.extend(/** @lends LuCI.ui.table.prototype */ { data.length = 0; - list.forEach(function(item) { + list.forEach(item => { data.push(item[1]); }); - headings.forEach(function(th, i) { + headings.forEach((th, i) => { if (i == sorting[0]) th.setAttribute('data-sort-direction', sorting[1] ? 'desc' : 'asc'); else @@ -7041,14 +7060,24 @@ var UITable = baseclass.extend(/** @lends LuCI.ui.table.prototype */ { }); } - data.forEach(function(row) { + this.data = data; + this.placeholder = placeholder; + + let n = 0; + const rows = this.node.querySelectorAll('tr, .tr'); + const trows = []; + const captionClasses = this.options.captionClasses; + const trTag = (rows[0] && rows[0].nodeName == 'DIV') ? 'div' : 'tr'; + const tdTag = (headings[0] && headings[0].nodeName == 'DIV') ? 'div' : 'td'; + + data.forEach(row => { trows[n] = E(trTag, { 'class': 'tr' }); - for (var i = 0; i < headings.length; i++) { - var text = (headings[i].innerText || '').trim(); - var raw_val = Array.isArray(row[i]) ? row[i][0] : null; - var disp_val = Array.isArray(row[i]) ? row[i][1] : row[i]; - var td = trows[n].appendChild(E(tdTag, { + for (let i = 0; i < headings.length; i++) { + const text = (headings[i].innerText ?? '').trim(); + const raw_val = Array.isArray(row[i]) ? row[i][0] : null; + const disp_val = Array.isArray(row[i]) ? row[i][1] : row[i]; + const td = trows[n].appendChild(E(tdTag, { 'class': 'td', 'data-title': (text !== '') ? text : null, 'data-value': raw_val @@ -7064,7 +7093,7 @@ var UITable = baseclass.extend(/** @lends LuCI.ui.table.prototype */ { trows[n].classList.add('cbi-rowstyle-%d'.format((n++ % 2) ? 2 : 1)); }); - for (var i = 0; i < n; i++) { + for (let i = 0; i < n; i++) { if (rows[i+1]) this.node.replaceChild(trows[i], rows[i+1]); else @@ -7075,8 +7104,8 @@ var UITable = baseclass.extend(/** @lends LuCI.ui.table.prototype */ { this.node.removeChild(rows[n]); if (placeholder && this.node.firstElementChild === this.node.lastElementChild) { - var trow = this.node.appendChild(E(trTag, { 'class': 'tr placeholder' })), - td = trow.appendChild(E(tdTag, { 'class': 'td' }, placeholder)); + const trow = this.node.appendChild(E(trTag, { 'class': 'tr placeholder' })); + const td = trow.appendChild(E(tdTag, { 'class': 'td' }, placeholder)); if (typeof(captionClasses) == 'object') DOMTokenList.prototype.add.apply(td.classList, L.toArray(captionClasses[0])); @@ -7085,32 +7114,32 @@ var UITable = baseclass.extend(/** @lends LuCI.ui.table.prototype */ { return this.node; }, - render: function() { + render() { return this.node; }, /** @private */ - initFromMarkup: function(node) { + initFromMarkup(node) { if (!dom.elem(node)) node = document.querySelector(node); if (!node) throw 'Invalid table selector'; - var options = {}, - headrow = node.querySelector('tr, .tr'); + const options = {}; + const headrow = node.querySelector('tr, .tr'); if (!headrow) return; options.id = node.id; - options.classes = [].slice.call(node.classList).filter(function(c) { return c != 'table' }); + options.classes = [].slice.call(node.classList).filter(c => c != 'table'); options.sortable = []; options.captionClasses = []; - headrow.querySelectorAll('th, .th').forEach(function(th, i) { + headrow.querySelectorAll('th, .th').forEach((th, i) => { options.sortable[i] = !th.classList.contains('cbi-section-actions'); - options.captionClasses[i] = [].slice.call(th.classList).filter(function(c) { return c != 'th' }); + options.captionClasses[i] = [].slice.call(th.classList).filter(c => c != 'th'); }); headrow.addEventListener('click', UI.prototype.createHandlerFn(this, 'handleSort')); @@ -7121,9 +7150,10 @@ var UITable = baseclass.extend(/** @lends LuCI.ui.table.prototype */ { }, /** @private */ - deriveSortKey: function(value, index) { - var opts = this.options || {}, - hint, m; + deriveSortKey(value, index) { + const opts = this.options ?? {}; + let hint; + let m; if (opts.sortable == true || opts.sortable == null) hint = 'auto'; @@ -7134,16 +7164,17 @@ var UITable = baseclass.extend(/** @lends LuCI.ui.table.prototype */ { if (value.hasAttribute('data-value')) value = value.getAttribute('data-value'); else - value = (value.innerText || '').trim(); + value = (value.innerText ?? '').trim(); } - switch (hint || 'auto') { + switch (hint ?? 'auto') { case true: case 'auto': m = /^([0-9a-fA-F:.]+)(?:\/([0-9a-fA-F:.]+))?$/.exec(value); if (m) { - var addr, mask; + let addr; + let mask; addr = validation.parseIPv6(m[1]); mask = m[2] ? validation.parseIPv6(m[2]) : null; @@ -7198,16 +7229,16 @@ var UITable = baseclass.extend(/** @lends LuCI.ui.table.prototype */ { }, /** @private */ - getActiveSortState: function() { + getActiveSortState() { if (this.sortState) return this.sortState; if (!this.options.id) return null; - var page = document.body.getAttribute('data-page'), - key = page + '.' + this.options.id, - state = session.getLocalData('tablesort'); + const page = document.body.getAttribute('data-page'); + const key = `${page}.${this.id}`; + const state = session.getLocalData('tablesort'); if (L.isObject(state) && Array.isArray(state[key])) return state[key]; @@ -7216,15 +7247,15 @@ var UITable = baseclass.extend(/** @lends LuCI.ui.table.prototype */ { }, /** @private */ - setActiveSortState: function(index, descending) { + setActiveSortState(index, descending) { this.sortState = [ index, descending ]; if (!this.options.id) return; - var page = document.body.getAttribute('data-page'), - key = page + '.' + this.options.id, - state = session.getLocalData('tablesort'); + const page = document.body.getAttribute('data-page'); + const key = `${page}.${this.options.id}`; + let state = session.getLocalData('tablesort'); if (!L.isObject(state)) state = {}; @@ -7235,17 +7266,19 @@ var UITable = baseclass.extend(/** @lends LuCI.ui.table.prototype */ { }, /** @private */ - handleSort: function(ev) { + handleSort(ev) { if (!ev.target.matches('th[data-sortable-row]')) return; - var index, direction; + const th = ev.target; + const direction = (th.getAttribute('data-sort-direction') == 'asc'); + let index = 0; - this.node.firstElementChild.querySelectorAll('th, .th').forEach(function(th, i) { - if (th === ev.target) { + this.node.firstElementChild.querySelectorAll('th').forEach((other_th, i) => { + if (other_th !== th) + other_th.removeAttribute('data-sort-direction'); + else index = i; - direction = th.getAttribute('data-sort-direction') == 'asc'; - } }); this.setActiveSortState(index, direction); @@ -7263,8 +7296,8 @@ var UITable = baseclass.extend(/** @lends LuCI.ui.table.prototype */ { * To import the class in views, use `'require ui'`, to import it in * external JavaScript, use `L.require("ui").then(...)`. */ -var UI = baseclass.extend(/** @lends LuCI.ui.prototype */ { - __init__: function() { +const UI = baseclass.extend(/** @lends LuCI.ui.prototype */ { + __init__() { modalDiv = document.body.appendChild( dom.create('div', { id: 'modal_overlay', @@ -7327,13 +7360,11 @@ var UI = baseclass.extend(/** @lends LuCI.ui.prototype */ { * @returns {Node} * Returns a DOM Node representing the modal dialog element. */ - showModal: function(title, children /* , ... */) { - var dlg = modalDiv.firstElementChild; + showModal(title, children, ...classes) { + const dlg = modalDiv.firstElementChild; dlg.setAttribute('class', 'modal'); - - for (var i = 2; i < arguments.length; i++) - dlg.classList.add(arguments[i]); + dlg.classList.add(...classes); dom.content(dlg, dom.create('h4', {}, title)); dom.append(dlg, children); @@ -7355,15 +7386,15 @@ var UI = baseclass.extend(/** @lends LuCI.ui.prototype */ { * will not invoke other class functions so it is suitable to be used as event * handler as-is without the need to bind it first. */ - hideModal: function() { + hideModal() { document.body.classList.remove('modal-overlay-active'); modalDiv.blur(); }, /** @private */ - cancelModal: function(ev) { + cancelModal(ev) { if (ev.key == 'Escape') { - var btn = modalDiv.querySelector('.right > button, .right > .btn, .button-row > .btn'); + const btn = modalDiv.querySelector('.right > button, .right > .btn, .button-row > .btn'); if (btn) btn.click(); @@ -7371,8 +7402,8 @@ var UI = baseclass.extend(/** @lends LuCI.ui.prototype */ { }, /** @private */ - showTooltip: function(ev) { - var target = findParent(ev.target, '[data-tooltip]'); + showTooltip(ev) { + const target = findParent(ev.target, '[data-tooltip]'); if (!target) return; @@ -7382,10 +7413,10 @@ var UI = baseclass.extend(/** @lends LuCI.ui.prototype */ { tooltipTimeout = null; } - var rect = target.getBoundingClientRect(), - x = rect.left + window.pageXOffset, - y = rect.top + rect.height + window.pageYOffset, - above = false; + const rect = target.getBoundingClientRect(); + const x = rect.left + window.pageXOffset; + let y = rect.top + rect.height + window.pageYOffset; + let above = false; tooltipDiv.className = 'cbi-tooltip'; tooltipDiv.innerHTML = '▲ '; @@ -7397,18 +7428,18 @@ var UI = baseclass.extend(/** @lends LuCI.ui.prototype */ { if ((y + tooltipDiv.offsetHeight) > (window.innerHeight + window.pageYOffset)) above = true; - var dropdown = target.querySelector('ul.dropdown[style]:first-child'); + const dropdown = target.querySelector('ul.dropdown[style]:first-child'); if (dropdown && dropdown.style.top) above = true; if (above) { y -= (tooltipDiv.offsetHeight + target.offsetHeight); - tooltipDiv.firstChild.data = '▼ ' + tooltipDiv.firstChild.data.substr(2); + tooltipDiv.firstChild.data = `▼ ${tooltipDiv.firstChild.data.substr(2)}`; } - tooltipDiv.style.top = y + 'px'; - tooltipDiv.style.left = x + 'px'; + tooltipDiv.style.top = `${y}px`; + tooltipDiv.style.left = `${x}px`; tooltipDiv.style.opacity = 1; tooltipDiv.dispatchEvent(new CustomEvent('tooltip-open', { @@ -7418,7 +7449,7 @@ var UI = baseclass.extend(/** @lends LuCI.ui.prototype */ { }, /** @private */ - hideTooltip: function(ev) { + hideTooltip(ev) { if (ev.target === tooltipDiv || ev.relatedTarget === tooltipDiv || tooltipDiv.contains(ev.target) || tooltipDiv.contains(ev.relatedTarget)) return; @@ -7429,7 +7460,7 @@ var UI = baseclass.extend(/** @lends LuCI.ui.prototype */ { } tooltipDiv.style.opacity = 0; - tooltipTimeout = window.setTimeout(function() { tooltipDiv.removeAttribute('style'); }, 250); + tooltipTimeout = window.setTimeout(() => tooltipDiv.removeAttribute('style'), 250); tooltipDiv.dispatchEvent(new CustomEvent('tooltip-close', { bubbles: true })); }, @@ -7469,13 +7500,13 @@ var UI = baseclass.extend(/** @lends LuCI.ui.prototype */ { * @returns {Node} * Returns a DOM Node representing the notification banner element. */ - addNotification: function(title, children, timeout, ...classes) { - var mc = document.querySelector('#maincontent') || document.body; - var msg = E('div', { + addNotification(title, children, timeout, ...classes) { + const mc = document.querySelector('#maincontent') ?? document.body; + const msg = E('div', { 'class': 'alert-message fade-in', 'style': 'display:flex', 'transitionend': function(ev) { - var node = ev.currentTarget; + const node = ev.currentTarget; if (node.parentNode && node.classList.contains('fade-out')) node.parentNode.removeChild(node); } @@ -7498,12 +7529,12 @@ var UI = baseclass.extend(/** @lends LuCI.ui.prototype */ { dom.append(msg.firstElementChild, children); - classes.forEach(cls => msg.classList.add(cls)); + msg.classList.add(...classes); mc.insertBefore(msg, mc.firstElementChild); function fadeOutNotification(element) { - var notification = dom.parent(element, '.alert-message'); + const notification = dom.parent(element, '.alert-message'); if (notification) { notification.classList.add('fade-out'); notification.classList.remove('fade-in'); @@ -7516,7 +7547,7 @@ var UI = baseclass.extend(/** @lends LuCI.ui.prototype */ { } if (typeof timeout === 'number' && timeout > 0) { - setTimeout(function() { + setTimeout(() => { if (msg && msg.parentNode) { fadeOutNotification(msg); } @@ -7561,7 +7592,7 @@ var UI = baseclass.extend(/** @lends LuCI.ui.prototype */ { * Returns `true` when the indicator has been updated or `false` when no * changes were made. */ - showIndicator: function(id, label, handler, style) { + showIndicator(id, label, handler, style) { if (indicatorDiv == null) { indicatorDiv = document.body.querySelector('#indicators'); @@ -7569,11 +7600,11 @@ var UI = baseclass.extend(/** @lends LuCI.ui.prototype */ { return false; } - var handlerFn = (typeof(handler) == 'function') ? handler : null, - indicatorElem = indicatorDiv.querySelector('span[data-indicator="%s"]'.format(id)); + const handlerFn = (typeof(handler) == 'function') ? handler : null; + let indicatorElem = indicatorDiv.querySelector('span[data-indicator="%s"]'.format(id)); if (indicatorElem == null) { - var beforeElem = null; + let beforeElem = null; for (beforeElem = indicatorDiv.firstElementChild; beforeElem != null; @@ -7609,8 +7640,8 @@ var UI = baseclass.extend(/** @lends LuCI.ui.prototype */ { * Returns `true` when the indicator has been removed or `false` when the * requested indicator was not found. */ - hideIndicator: function(id) { - var indicatorElem = indicatorDiv ? indicatorDiv.querySelector('span[data-indicator="%s"]'.format(id)) : null; + hideIndicator(id) { + const indicatorElem = indicatorDiv ? indicatorDiv.querySelector('span[data-indicator="%s"]'.format(id)) : null; if (indicatorElem == null) return false; @@ -7652,19 +7683,19 @@ var UI = baseclass.extend(/** @lends LuCI.ui.prototype */ { * @returns {Node} * Returns the parent DOM node the formatted markup has been added to. */ - itemlist: function(node, items, separators) { - var children = []; + itemlist(node, items, separators) { + const children = []; if (!Array.isArray(separators)) - separators = [ separators || E('br') ]; + separators = [ separators ?? E('br') ]; - for (var i = 0; i < items.length; i += 2) { + for (let i = 0; i < items.length; i += 2) { if (items[i+1] !== null && items[i+1] !== undefined) { - var sep = separators[(i/2) % separators.length], - cld = []; + const sep = separators[(i/2) % separators.length]; + const cld = []; children.push(E('span', { class: 'nowrap' }, [ - items[i] ? E('strong', items[i] + ': ') : '', + items[i] ? E('strong', `${items[i]}: `) : '', items[i+1] ])); @@ -7695,11 +7726,13 @@ var UI = baseclass.extend(/** @lends LuCI.ui.prototype */ { */ tabs: baseclass.singleton(/* @lends LuCI.ui.tabs.prototype */ { /** @private */ - init: function() { - var groups = [], prevGroup = null, currGroup = null; + init() { + const groups = []; + let prevGroup = null; + let currGroup = null; - document.querySelectorAll('[data-tab]').forEach(function(tab) { - var parent = tab.parentNode; + document.querySelectorAll('[data-tab]').forEach(tab => { + const parent = tab.parentNode; if (dom.matches(tab, 'li') && dom.matches(parent, 'ul.cbi-tabmenu')) return; @@ -7719,7 +7752,7 @@ var UI = baseclass.extend(/** @lends LuCI.ui.prototype */ { groups[currGroup].push(tab); }); - for (var i = 0; i < groups.length; i++) + for (let i = 0; i < groups.length; i++) this.initTabGroup(groups[i]); document.addEventListener('dependency-update', this.updateTabs.bind(this)); @@ -7748,22 +7781,22 @@ var UI = baseclass.extend(/** @lends LuCI.ui.prototype */ { * of a `querySelectorAll()` call or the `.childNodes` property of a * DOM node. */ - initTabGroup: function(panes) { + initTabGroup(panes) { if (typeof(panes) != 'object' || !('length' in panes) || panes.length === 0) return; - var menu = E('ul', { 'class': 'cbi-tabmenu' }), - group = panes[0].parentNode, - groupId = +group.getAttribute('data-tab-group'), - selected = null; + const menu = E('ul', { 'class': 'cbi-tabmenu' }); + const group = panes[0].parentNode; + const groupId = +group.getAttribute('data-tab-group'); + let selected = null; if (group.getAttribute('data-initialized') === 'true') return; - for (var i = 0, pane; pane = panes[i]; i++) { - var name = pane.getAttribute('data-tab'), - title = pane.getAttribute('data-tab-title'), - active = pane.getAttribute('data-tab-active') === 'true'; + for (let i = 0, pane; pane = panes[i]; i++) { + const name = pane.getAttribute('data-tab'); + const title = pane.getAttribute('data-tab-title'); + const active = pane.getAttribute('data-tab-active') === 'true'; menu.appendChild(E('li', { 'style': this.isEmptyPane(pane) ? 'display:none' : null, @@ -7785,7 +7818,7 @@ var UI = baseclass.extend(/** @lends LuCI.ui.prototype */ { selected = this.getActiveTabId(panes[0]); if (selected < 0 || selected >= panes.length || this.isEmptyPane(panes[selected])) { - for (var i = 0; i < panes.length; i++) { + for (let i = 0; i < panes.length; i++) { if (!this.isEmptyPane(panes[i])) { selected = i; break; @@ -7800,7 +7833,7 @@ var UI = baseclass.extend(/** @lends LuCI.ui.prototype */ { this.setActiveTabId(panes[selected], selected); } - requestAnimationFrame(L.bind(function(pane) { + requestAnimationFrame(L.bind(pane => { pane.dispatchEvent(new CustomEvent('cbi-tab-active', { detail: { tab: pane.getAttribute('data-tab') } })); @@ -7820,13 +7853,14 @@ var UI = baseclass.extend(/** @lends LuCI.ui.prototype */ { * @returns {boolean} * Returns `true` if the pane is empty, else `false`. */ - isEmptyPane: function(pane) { - return dom.isEmpty(pane, function(n) { return n.classList.contains('cbi-tab-descr') }); + isEmptyPane(pane) { + return dom.isEmpty(pane, n => n.classList.contains('cbi-tab-descr')); }, /** @private */ - getPathForPane: function(pane) { - var path = [], node = null; + getPathForPane(pane) { + const path = []; + let node = null; for (node = pane ? pane.parentNode : null; node != null && node.hasAttribute != null; @@ -7842,9 +7876,9 @@ var UI = baseclass.extend(/** @lends LuCI.ui.prototype */ { }, /** @private */ - getActiveTabState: function() { - var page = document.body.getAttribute('data-page'), - state = session.getLocalData('tab'); + getActiveTabState() { + const page = document.body.getAttribute('data-page'); + const state = session.getLocalData('tab'); if (L.isObject(state) && state.page === page && L.isObject(state.paths)) return state; @@ -7855,15 +7889,15 @@ var UI = baseclass.extend(/** @lends LuCI.ui.prototype */ { }, /** @private */ - getActiveTabId: function(pane) { - var path = this.getPathForPane(pane); - return +this.getActiveTabState().paths[path] || 0; + getActiveTabId(pane) { + const path = this.getPathForPane(pane); + return +this.getActiveTabState().paths[path] ?? 0; }, /** @private */ - setActiveTabId: function(pane, tabIndex) { - var path = this.getPathForPane(pane), - state = this.getActiveTabState(); + setActiveTabId(pane, tabIndex) { + const path = this.getPathForPane(pane); + const state = this.getActiveTabState(); state.paths[path] = tabIndex; @@ -7871,11 +7905,11 @@ var UI = baseclass.extend(/** @lends LuCI.ui.prototype */ { }, /** @private */ - updateTabs: function(ev, root) { - (root || document).querySelectorAll('[data-tab-title]').forEach(L.bind(function(pane) { - var menu = pane.parentNode.previousElementSibling, - tab = menu ? menu.querySelector('[data-tab="%s"]'.format(pane.getAttribute('data-tab'))) : null, - n_errors = pane.querySelectorAll('.cbi-input-invalid').length; + updateTabs(ev, root) { + (root ?? document).querySelectorAll('[data-tab-title]').forEach(L.bind((pane) => { + const menu = pane.parentNode.previousElementSibling; + const tab = menu ? menu.querySelector('[data-tab="%s"]'.format(pane.getAttribute('data-tab'))) : null; + const n_errors = pane.querySelectorAll('.cbi-input-invalid').length; if (!menu || !tab) return; @@ -7886,7 +7920,7 @@ var UI = baseclass.extend(/** @lends LuCI.ui.prototype */ { } else if (tab.style.display === 'none') { tab.style.display = ''; - requestAnimationFrame(function() { tab.classList.add('flash') }); + requestAnimationFrame(() => tab.classList.add('flash')); } if (n_errors) { @@ -7902,27 +7936,27 @@ var UI = baseclass.extend(/** @lends LuCI.ui.prototype */ { }, /** @private */ - switchTab: function(ev) { - var tab = ev.target.parentNode, - name = tab.getAttribute('data-tab'), - menu = tab.parentNode, - group = menu.nextElementSibling, - groupId = +group.getAttribute('data-tab-group'), - index = 0; + switchTab(ev) { + const tab = ev.target.parentNode; + const name = tab.getAttribute('data-tab'); + const menu = tab.parentNode; + const group = menu.nextElementSibling; + const groupId = +group.getAttribute('data-tab-group'); + let index = 0; ev.preventDefault(); if (!tab.classList.contains('cbi-tab-disabled')) return; - menu.querySelectorAll('[data-tab]').forEach(function(tab) { + menu.querySelectorAll('[data-tab]').forEach(tab => { tab.classList.remove('cbi-tab'); tab.classList.remove('cbi-tab-disabled'); tab.classList.add( tab.getAttribute('data-tab') === name ? 'cbi-tab' : 'cbi-tab-disabled'); }); - group.childNodes.forEach(function(pane) { + group.childNodes.forEach(pane => { if (dom.matches(pane, '[data-tab]')) { if (pane.getAttribute('data-tab') === name) { pane.setAttribute('data-tab-active', 'true'); @@ -7967,98 +8001,103 @@ var UI = baseclass.extend(/** @lends LuCI.ui.prototype */ { * or rejecting with an error in case the upload failed or has been * cancelled by the user. */ - uploadFile: function(path, progressStatusNode) { - return new Promise(function(resolveFn, rejectFn) { + uploadFile(path, progressStatusNode) { + return new Promise((resolveFn, rejectFn) => { UI.prototype.showModal(_('Uploading file…'), [ E('p', _('Please select the file to upload.')), - E('div', { 'class': 'button-row' }, [ - E('button', { - 'class': 'btn cbi-button', - 'click': function() { - UI.prototype.hideModal(); - rejectFn(new Error(_('Upload has been cancelled'))); - } - }, [ _('Cancel') ]), - E('input', { - type: 'file', - style: 'display:none', - change: function(ev) { - var modal = dom.parent(ev.target, '.modal'), - body = modal.querySelector('p'), - upload = modal.querySelector('.cbi-button-action.important'), - file = ev.currentTarget.files[0]; - - if (file == null) - return; - - dom.content(body, [ - E('ul', {}, [ - E('li', {}, [ '%s: %s'.format(_('Name'), file.name.replace(/^.*[\\\/]/, '')) ]), - E('li', {}, [ '%s: %1024mB'.format(_('Size'), file.size) ]) - ]) - ]); - - upload.disabled = false; - upload.focus(); - } - }), - E('button', { - 'class': 'btn cbi-button', - 'click': function(ev) { - ev.target.previousElementSibling.click(); - } - }, [ _('Browse…') ]), - E('button', { - 'class': 'btn cbi-button-action important', - 'disabled': true, - 'click': function(ev) { - var input = dom.parent(ev.target, '.modal').querySelector('input[type="file"]'); - - if (!input.files[0]) - return; - - var progress = E('div', { 'class': 'cbi-progressbar', 'title': '0%' }, E('div', { 'style': 'width:0' })); - - UI.prototype.showModal(_('Uploading file…'), [ progress ]); - - var data = new FormData(); - - data.append('sessionid', rpc.getSessionID()); - data.append('filename', path); - data.append('filedata', input.files[0]); - - var filename = input.files[0].name; - - request.post(L.env.cgi_base + '/cgi-upload', data, { - timeout: 0, - progress: function(pev) { - var percent = (pev.loaded / pev.total) * 100; - - if (progressStatusNode) - progressStatusNode.data = '%.2f%%'.format(percent); - - progress.setAttribute('title', '%.2f%%'.format(percent)); - progress.firstElementChild.style.width = '%.2f%%'.format(percent); - } - }).then(function(res) { - var reply = res.json(); - + E('div', { 'style': 'display:flex' }, [ + E('div', { 'class': 'left', 'style': 'flex:1' }, [ + E('input', { + type: 'file', + style: 'display:none', + change(ev) { + const modal = dom.parent(ev.target, '.modal'); + const body = modal.querySelector('p'); + const upload = modal.querySelector('.cbi-button-action.important'); + const file = ev.currentTarget.files[0]; + + if (file == null) + return; + + dom.content(body, [ + E('ul', {}, [ + E('li', {}, [ '%s: %s'.format(_('Name'), file.name.replace(/^.*[\\\/]/, '')) ]), + E('li', {}, [ '%s: %1024mB'.format(_('Size'), file.size) ]) + ]) + ]); + + upload.disabled = false; + upload.focus(); + } + }), + E('button', { + 'class': 'btn cbi-button', + 'click': function(ev) { + ev.target.previousElementSibling.click(); + } + }, [ _('Browse…') ]) + ]), + E('div', { 'class': 'right', 'style': 'flex:1' }, [ + E('button', { + 'class': 'btn', + 'click': function() { UI.prototype.hideModal(); - - if (L.isObject(reply) && reply.failure) { - UI.prototype.addNotification(null, E('p', _('Upload request failed: %s').format(reply.message))); - rejectFn(new Error(reply.failure)); - } - else { - reply.name = filename; - resolveFn(reply); - } - }, function(err) { - UI.prototype.hideModal(); - rejectFn(err); - }); - } - }, [ _('Upload') ]) + rejectFn(new Error(_('Upload has been cancelled'))); + } + }, [ _('Cancel') ]), + ' ', + E('button', { + 'class': 'btn cbi-button-action important', + 'disabled': true, + 'click': function(ev) { + const input = dom.parent(ev.target, '.modal').querySelector('input[type="file"]'); + + if (!input.files[0]) + return; + + const progress = E('div', { 'class': 'cbi-progressbar', 'title': '0%' }, E('div', { 'style': 'width:0' })); + + UI.prototype.showModal(_('Uploading file…'), [ progress ]); + + const data = new FormData(); + + data.append('sessionid', rpc.getSessionID()); + data.append('filename', path); + data.append('filedata', input.files[0]); + + const filename = input.files[0].name; + + request.post(`${L.env.cgi_base}/cgi-upload`, data, { + timeout: 0, + progress(pev) { + const percent = (pev.loaded / pev.total) * 100; + + if (progressStatusNode) + progressStatusNode.data = '%.2f%%'.format(percent); + + progress.setAttribute('title', '%.2f%%'.format(percent)); + progress.firstElementChild.style.width = '%.2f%%'.format(percent); + } + }).then(res => { + const reply = res.json(); + + UI.prototype.hideModal(); + + if (L.isObject(reply) && reply.failure) { + UI.prototype.addNotification(null, E('p', _('Upload request failed: %s').format(reply.message))); + rejectFn(new Error(reply.failure)); + } + else { + reply.name = filename; + resolveFn(reply); + } + }, err => { + UI.prototype.hideModal(); + rejectFn(err); + }); + } + }, [ _('Upload') ]) + ]) ]) ]); }); @@ -8084,11 +8123,11 @@ var UI = baseclass.extend(/** @lends LuCI.ui.prototype */ { * reachable or rejecting with an `error` event in case it is not reachable * or rejecting with `null` when the connectivity check timed out. */ - pingDevice: function(proto, ipaddr) { - var target = '%s://%s%s?%s'.format(proto || 'http', ipaddr || window.location.host, L.resource('icons/loading.gif'), Math.random()); + pingDevice(proto, ipaddr) { + const target = '%s://%s%s?%s'.format(proto ?? 'http', ipaddr ?? window.location.host, L.resource('icons/loading.gif'), Math.random()); - return new Promise(function(resolveFn, rejectFn) { - var img = new Image(); + return new Promise((resolveFn, rejectFn) => { + const img = new Image(); img.onload = resolveFn; img.onerror = rejectFn; @@ -8110,19 +8149,20 @@ var UI = baseclass.extend(/** @lends LuCI.ui.prototype */ { * If omitted, the current value of `window.location.host` is used by * default. */ - awaitReconnect: function(/* ... */) { - var ipaddrs = arguments.length ? arguments : [ window.location.host ]; + awaitReconnect(...hosts) { + const ipaddrs = hosts.length ? hosts : [ window.location.host ]; - window.setTimeout(L.bind(function() { - poll.add(L.bind(function() { - var tasks = [], reachable = false; + window.setTimeout(L.bind(() => { + poll.add(L.bind(() => { + const tasks = []; + let reachable = false; - for (var i = 0; i < 2; i++) - for (var j = 0; j < ipaddrs.length; j++) + for (let i = 0; i < 2; i++) + for (let j = 0; j < ipaddrs.length; j++) tasks.push(this.pingDevice(i ? 'https' : 'http', ipaddrs[j]) - .then(function(ev) { reachable = ev.target.src.replace(/^(https?:\/\/[^\/]+).*$/, '$1/') }, function() {})); + .then(ev => { reachable = ev.target.src.replace(/^(https?:\/\/[^\/]+).*$/, '$1/') }, () => {})); - return Promise.all(tasks).then(function() { + return Promise.all(tasks).then(() => { if (reachable) { poll.stop(); window.location = reachable; @@ -8147,7 +8187,7 @@ var UI = baseclass.extend(/** @lends LuCI.ui.prototype */ { * `changes` property of the class instance value. */ changes: baseclass.singleton(/* @lends LuCI.ui.changes.prototype */ { - init: function() { + init() { if (!L.env.sessionid) return; @@ -8167,7 +8207,7 @@ var UI = baseclass.extend(/** @lends LuCI.ui.prototype */ { * @param {number} n * The number of changes to indicate. */ - setIndicator: function(n) { + setIndicator(n) { if (n > 0) { UI.prototype.showIndicator('uci-changes', '%s: %d'.format(_('Unsaved Changes'), n), @@ -8189,10 +8229,10 @@ var UI = baseclass.extend(/** @lends LuCI.ui.prototype */ { * @param {Object<string, Array<LuCI.uci.ChangeRecord>>} changes * The UCI changeset to count. */ - renderChangeIndicator: function(changes) { - var n_changes = 0; + renderChangeIndicator(changes) { + let n_changes = 0; - for (var config in changes) + for (const config in changes) if (changes.hasOwnProperty(config)) n_changes += changes[config].length; @@ -8223,24 +8263,23 @@ var UI = baseclass.extend(/** @lends LuCI.ui.prototype */ { * @instance * @memberof LuCI.ui.changes */ - displayChanges: function() { - var list = E('div', { 'class': 'uci-change-list' }), - dlg = UI.prototype.showModal(_('Configuration') + ' / ' + _('Changes'), [ - E('div', { 'class': 'cbi-section' }, [ - E('strong', _('Legend:')), - E('div', { 'class': 'uci-change-legend' }, [ - E('div', { 'class': 'uci-change-legend-label' }, [ - E('ins', '&#160;'), ' ', _('Section added') ]), - E('div', { 'class': 'uci-change-legend-label' }, [ - E('del', '&#160;'), ' ', _('Section removed') ]), - E('div', { 'class': 'uci-change-legend-label' }, [ - E('var', {}, E('ins', '&#160;')), ' ', _('Option changed') ]), - E('div', { 'class': 'uci-change-legend-label' }, [ - E('var', {}, E('del', '&#160;')), ' ', _('Option removed') ])]), - E('br'), - list, - ]), - E('div', { 'class': 'button-row' }, [ + displayChanges() { + const list = E('div', { 'class': 'uci-change-list' }); + + const dlg = UI.prototype.showModal(`${_('Configuration')} / ${_('Changes')}`, [ + E('div', { 'class': 'cbi-section' }, [ + E('strong', _('Legend:')), + E('div', { 'class': 'uci-change-legend' }, [ + E('div', { 'class': 'uci-change-legend-label' }, [ + E('ins', '&#160;'), ' ', _('Section added') ]), + E('div', { 'class': 'uci-change-legend-label' }, [ + E('del', '&#160;'), ' ', _('Section removed') ]), + E('div', { 'class': 'uci-change-legend-label' }, [ + E('var', {}, E('ins', '&#160;')), ' ', _('Option changed') ]), + E('div', { 'class': 'uci-change-legend-label' }, [ + E('var', {}, E('del', '&#160;')), ' ', _('Option removed') ])]), + E('br'), list, + E('div', { 'class': 'right' }, [ //button-row? E('button', { 'class': 'btn cbi-button', 'click': UI.prototype.hideModal @@ -8253,33 +8292,32 @@ var UI = baseclass.extend(/** @lends LuCI.ui.prototype */ { 0: 'btn cbi-button cbi-button-positive important', 1: 'btn cbi-button cbi-button-negative important' }, - click: L.bind(function(ev, mode) { this.apply(mode == '0') }, this) + click: L.bind((ev, mode) => { this.apply(mode == '0') }, this) }).render(), ' ', E('button', { 'class': 'btn cbi-button cbi-button-reset', 'click': L.bind(this.revert, this) - }, [ _('Revert') ]) - ]) - ]); + }, [ _('Revert') ])])]) + ]); - for (var config in this.changes) { + for (const config in this.changes) { if (!this.changes.hasOwnProperty(config)) continue; list.appendChild(E('h5', '# /etc/config/%s'.format(config))); - for (var i = 0, added = null; i < this.changes[config].length; i++) { - var chg = this.changes[config][i], - tpl = this.changeTemplates['%s-%d'.format(chg[0], chg.length)]; + for (let i = 0, added = null; i < this.changes[config].length; i++) { + const chg = this.changes[config][i]; + const tpl = this.changeTemplates['%s-%d'.format(chg[0], chg.length)]; - list.appendChild(E(tpl.replace(/%([01234])/g, function(m0, m1) { + list.appendChild(E(tpl.replace(/%([01234])/g, (m0, m1) => { switch (+m1) { case 0: return config; case 2: if (added != null && chg[1] == added[0]) - return '@' + added[1] + '[-1]'; + return `@${added[1]}[-1]`; else return chg[1]; @@ -8301,9 +8339,9 @@ var UI = baseclass.extend(/** @lends LuCI.ui.prototype */ { }, /** @private */ - displayStatus: function(type, content) { + displayStatus(type, content) { if (type) { - var message = UI.prototype.showModal('', ''); + const message = UI.prototype.showModal('', ''); message.classList.add('alert-message'); DOMTokenList.prototype.add.apply(message.classList, type.split(/\s+/)); @@ -8325,14 +8363,14 @@ var UI = baseclass.extend(/** @lends LuCI.ui.prototype */ { }, /** @private */ - checkConnectivityAffected: function() { - return L.resolveDefault(fs.exec_direct('/usr/libexec/luci-peeraddr', null, 'json')).then(L.bind(function(info) { + checkConnectivityAffected() { + return L.resolveDefault(fs.exec_direct('/usr/libexec/luci-peeraddr', null, 'json')).then(L.bind((info) => { if (L.isObject(info) && Array.isArray(info.inbound_interfaces)) { - for (var i = 0; i < info.inbound_interfaces.length; i++) { - var iif = info.inbound_interfaces[i]; + for (let i = 0; i < info.inbound_interfaces.length; i++) { + const iif = info.inbound_interfaces[i]; - for (var j = 0; this.changes && this.changes.network && j < this.changes.network.length; j++) { - var chg = this.changes.network[j]; + for (let j = 0; this.changes && this.changes.network && j < this.changes.network.length; j++) { + const chg = this.changes.network[j]; if (chg[0] == 'set' && chg[1] == iif && ((chg[2] == 'disabled' && chg[3] == '1') || chg[2] == 'proto' || chg[2] == 'ipaddr' || chg[2] == 'netmask')) @@ -8346,13 +8384,13 @@ var UI = baseclass.extend(/** @lends LuCI.ui.prototype */ { }, /** @private */ - rollback: function(checked) { + rollback(checked) { if (checked) { this.displayStatus('warning spinning', E('p', _('Failed to confirm apply within %ds, waiting for rollback…') .format(L.env.apply_rollback))); - var call = function(r) { + const call = (r, data, duration) => { if (r.status === 204) { UI.prototype.changes.displayStatus('warning', [ E('h4', _('Configuration changes have been rolled back!')), @@ -8376,8 +8414,8 @@ var UI = baseclass.extend(/** @lends LuCI.ui.prototype */ { return; } - var delay = isNaN(r.duration) ? 0 : Math.max(1000 - r.duration, 0); - window.setTimeout(function() { + const delay = isNaN(duration) ? 0 : Math.max(1000 - duration, 0); + window.setTimeout(() => { request.request(L.url('admin/uci/confirm'), { method: 'post', timeout: L.env.apply_timeout * 1000, @@ -8397,16 +8435,16 @@ var UI = baseclass.extend(/** @lends LuCI.ui.prototype */ { }, /** @private */ - confirm: function(checked, deadline, override_token) { - var tt; - var ts = Date.now(); + confirm(checked, deadline, override_token) { + let tt; + let ts = Date.now(); this.displayStatus('notice'); if (override_token) this.confirm_auth = { token: override_token }; - var call = function(r) { + const call = (r, data, duration) => { if (Date.now() >= deadline) { window.clearTimeout(tt); UI.prototype.changes.rollback(checked); @@ -8420,7 +8458,7 @@ var UI = baseclass.extend(/** @lends LuCI.ui.prototype */ { E('p', _('Configuration changes applied.'))); window.clearTimeout(tt); - window.setTimeout(function() { + window.setTimeout(() => { //UI.prototype.changes.displayStatus(false); window.location = window.location.href.split('#')[0]; }, L.env.apply_display * 1000); @@ -8428,8 +8466,8 @@ var UI = baseclass.extend(/** @lends LuCI.ui.prototype */ { return; } - var delay = isNaN(r.duration) ? 0 : Math.max(1000 - r.duration, 0); - window.setTimeout(function() { + const delay = isNaN(duration) ? 0 : Math.max(1000 - duration, 0); + window.setTimeout(() => { request.request(L.url('admin/uci/confirm'), { method: 'post', timeout: L.env.apply_timeout * 1000, @@ -8438,8 +8476,8 @@ var UI = baseclass.extend(/** @lends LuCI.ui.prototype */ { }, delay); }; - var tick = function() { - var now = Date.now(); + const tick = () => { + const now = Date.now(); UI.prototype.changes.displayStatus('notice spinning', E('p', _('Applying configuration changes… %ds') @@ -8478,15 +8516,15 @@ var UI = baseclass.extend(/** @lends LuCI.ui.prototype */ { * will begin to roll back the changes in order to restore the previous * settings. */ - apply: function(checked) { + apply(checked) { this.displayStatus('notice spinning', E('p', _('Starting configuration apply…'))); - (new Promise(function(resolveFn, rejectFn) { + (new Promise((resolveFn, rejectFn) => { if (!checked) return resolveFn(false); - UI.prototype.changes.checkConnectivityAffected().then(function(affected) { + UI.prototype.changes.checkConnectivityAffected().then(affected => { if (!affected) return resolveFn(true); @@ -8509,13 +8547,13 @@ var UI = baseclass.extend(/** @lends LuCI.ui.prototype */ { ]) ]); }); - })).then(function(checked) { + })).then(checked => { request.request(L.url('admin/uci', checked ? 'apply_rollback' : 'apply_unchecked'), { method: 'post', query: { sid: L.env.sessionid, token: L.env.token } - }).then(function(r) { + }).then(r => { if (r.status === (checked ? 200 : 204)) { - var tok = null; try { tok = r.json(); } catch(e) {} + let tok = null; try { tok = r.json(); } catch(e) {} if (checked && tok !== null && typeof(tok) === 'object' && typeof(tok.token) === 'string') UI.prototype.changes.confirm_auth = tok; @@ -8525,16 +8563,16 @@ var UI = baseclass.extend(/** @lends LuCI.ui.prototype */ { UI.prototype.changes.displayStatus('notice', E('p', _('There are no changes to apply'))); - window.setTimeout(function() { + window.setTimeout(() => { UI.prototype.changes.displayStatus(false); }, L.env.apply_display * 1000); } else { UI.prototype.changes.displayStatus('warning', E('p', _('Apply request failed with status <code>%h</code>') - .format(r.responseText || r.statusText || r.status))); + .format(r.responseText ?? r.statusText ?? r.status))); - window.setTimeout(function() { + window.setTimeout(() => { UI.prototype.changes.displayStatus(false); }, L.env.apply_display * 1000); } @@ -8554,14 +8592,14 @@ var UI = baseclass.extend(/** @lends LuCI.ui.prototype */ { * @instance * @memberof LuCI.ui.changes */ - revert: function() { + revert() { this.displayStatus('notice spinning', E('p', _('Reverting configuration…'))); request.request(L.url('admin/uci/revert'), { method: 'post', query: { sid: L.env.sessionid, token: L.env.token } - }).then(function(r) { + }).then(r => { if (r.status === 200) { document.dispatchEvent(new CustomEvent('uci-reverted')); @@ -8569,7 +8607,7 @@ var UI = baseclass.extend(/** @lends LuCI.ui.prototype */ { UI.prototype.changes.displayStatus('notice', E('p', _('Changes have been reverted.'))); - window.setTimeout(function() { + window.setTimeout(() => { //UI.prototype.changes.displayStatus(false); window.location = window.location.href.split('#')[0]; }, L.env.apply_display * 1000); @@ -8577,9 +8615,9 @@ var UI = baseclass.extend(/** @lends LuCI.ui.prototype */ { else { UI.prototype.changes.displayStatus('warning', E('p', _('Revert request failed with status <code>%h</code>') - .format(r.statusText || r.status))); + .format(r.statusText ?? r.status))); - window.setTimeout(function() { + window.setTimeout(() => { UI.prototype.changes.displayStatus(false); }, L.env.apply_display * 1000); } @@ -8622,19 +8660,18 @@ var UI = baseclass.extend(/** @lends LuCI.ui.prototype */ { * * @see LuCI.validation */ - addValidator: function(field, type, optional, vfunc /*, ... */) { + addValidator(field, type, optional, vfunc, ...events) { if (type == null) return; - var events = this.varargs(arguments, 3); if (events.length == 0) events.push('blur', 'keyup'); try { - var cbiValidator = validation.create(field, type, optional, vfunc), - validatorFn = cbiValidator.validate.bind(cbiValidator); + const cbiValidator = validation.create(field, type, optional, vfunc); + const validatorFn = cbiValidator.validate.bind(cbiValidator); - for (var i = 0; i < events.length; i++) + for (let i = 0; i < events.length; i++) field.addEventListener(events[i], validatorFn); validatorFn(); @@ -8673,17 +8710,15 @@ var UI = baseclass.extend(/** @lends LuCI.ui.prototype */ { * a string which could not be found in `ctx` or if `ctx[fn]` is not a * valid function value. */ - createHandlerFn: function(ctx, fn /*, ... */) { + createHandlerFn(ctx, fn, ...args) { if (typeof(fn) == 'string') fn = ctx[fn]; if (typeof(fn) != 'function') return null; - var arg_offset = arguments.length - 2; - - return Function.prototype.bind.apply(function() { - var t = arguments[arg_offset].currentTarget; + return L.bind(function() { + const t = arguments[args.length].currentTarget; t.classList.add('spinning'); t.disabled = true; @@ -8691,11 +8726,11 @@ var UI = baseclass.extend(/** @lends LuCI.ui.prototype */ { if (t.blur) t.blur(); - Promise.resolve(fn.apply(ctx, arguments)).finally(function() { + Promise.resolve(fn.apply(ctx, arguments)).finally(() => { t.classList.remove('spinning'); t.disabled = false; }); - }, this.varargs(arguments, 2, ctx)); + }, ctx, ...args); }, /** @@ -8716,15 +8751,15 @@ var UI = baseclass.extend(/** @lends LuCI.ui.prototype */ { * @returns {Promise<LuCI.view>} * Returns a promise resolving to the loaded view instance. */ - instantiateView: function(path) { - var className = 'view.%s'.format(path.replace(/\//g, '.')); + instantiateView(path) { + const className = 'view.%s'.format(path.replace(/\//g, '.')); - return L.require(className).then(function(view) { + return L.require(className).then(view => { if (!(view instanceof View)) throw new TypeError('Loaded class %s is not a descendant of View'.format(className)); return view; - }).catch(function(err) { + }).catch(err => { dom.content(document.querySelector('#view'), null); L.error(err); }); @@ -8762,7 +8797,7 @@ return UI; -- 2.30.2