summaryrefslogtreecommitdiffhomepage
path: root/modules/luci-base/htdocs/luci-static/resources/uci.js
diff options
context:
space:
mode:
Diffstat (limited to 'modules/luci-base/htdocs/luci-static/resources/uci.js')
-rw-r--r--modules/luci-base/htdocs/luci-static/resources/uci.js141
1 files changed, 87 insertions, 54 deletions
diff --git a/modules/luci-base/htdocs/luci-static/resources/uci.js b/modules/luci-base/htdocs/luci-static/resources/uci.js
index 640661f0f5..76b274470b 100644
--- a/modules/luci-base/htdocs/luci-static/resources/uci.js
+++ b/modules/luci-base/htdocs/luci-static/resources/uci.js
@@ -2,6 +2,14 @@
'require rpc';
'require baseclass';
+function isEmpty(object, ignore) {
+ for (var property in object)
+ if (object.hasOwnProperty(property) && property != ignore)
+ return false;
+
+ return true;
+}
+
/**
* @class uci
* @memberof LuCI
@@ -10,7 +18,7 @@
*
* The `LuCI.uci` class utilizes {@link LuCI.rpc} to declare low level
* remote UCI `ubus` procedures and implements a local caching and data
- * manipulation layer on top to allow for synchroneous operations on
+ * manipulation layer on top to allow for synchronous operations on
* UCI configuration data.
*/
return baseclass.extend(/** @lends LuCI.uci.prototype */ {
@@ -85,7 +93,7 @@ return baseclass.extend(/** @lends LuCI.uci.prototype */ {
* identifier in the form `cfgXXXXXX` once the configuration is saved
* by the remote `ubus` UCI api.
*
- * @param {string} config
+ * @param {string} conf
* The configuration to generate the new section ID for.
*
* @returns {string}
@@ -108,7 +116,7 @@ return baseclass.extend(/** @lends LuCI.uci.prototype */ {
* Resolves a given section ID in extended notation to the internal
* section ID value.
*
- * @param {string} config
+ * @param {string} conf
* The configuration to resolve the section ID for.
*
* @param {string} sid
@@ -201,7 +209,7 @@ return baseclass.extend(/** @lends LuCI.uci.prototype */ {
* To force reloading a configuration, it has to be unloaded with
* {@link LuCI.uci#unload uci.unload()} first.
*
- * @param {string|string[]} config
+ * @param {string|string[]} packages
* The name of the configuration or an array of configuration
* names to load.
*
@@ -237,7 +245,7 @@ return baseclass.extend(/** @lends LuCI.uci.prototype */ {
/**
* Unloads the given UCI configurations from the local cache.
*
- * @param {string|string[]} config
+ * @param {string|string[]} packages
* The name of the configuration or an array of configuration
* names to unload.
*/
@@ -259,7 +267,7 @@ return baseclass.extend(/** @lends LuCI.uci.prototype */ {
* Adds a new section of the given type to the given configuration,
* optionally named according to the given name.
*
- * @param {string} config
+ * @param {string} conf
* The name of the configuration to add the section to.
*
* @param {string} type
@@ -294,7 +302,7 @@ return baseclass.extend(/** @lends LuCI.uci.prototype */ {
/**
* Removes the section with the given ID from the given configuration.
*
- * @param {string} config
+ * @param {string} conf
* The name of the configuration to remove the section from.
*
* @param {string} sid
@@ -326,7 +334,7 @@ return baseclass.extend(/** @lends LuCI.uci.prototype */ {
* enclosed within a configuration section, as well as some additional
* meta data such as sort indexes and internal ID.
*
- * Any internal metadata fields are prefixed with a dot which is isn't
+ * Any internal metadata fields are prefixed with a dot which isn't
* an allowed character for normal option names.
*
* @typedef {Object<string, boolean|number|string|string[]>} SectionObject
@@ -337,7 +345,7 @@ return baseclass.extend(/** @lends LuCI.uci.prototype */ {
* anonymous (`true`) or named (`false`).
*
* @property {number} .index
- * The `.index` property specifes the sort order of the section.
+ * The `.index` property specifies the sort order of the section.
*
* @property {string} .name
* The `.name` property holds the name of the section object. It may be
@@ -375,7 +383,7 @@ return baseclass.extend(/** @lends LuCI.uci.prototype */ {
* Enumerates the sections of the given configuration, optionally
* filtered by type.
*
- * @param {string} config
+ * @param {string} conf
* The name of the configuration to enumerate the sections for.
*
* @param {string} [type]
@@ -402,7 +410,7 @@ return baseclass.extend(/** @lends LuCI.uci.prototype */ {
for (var s in v)
if (!d || d[s] !== true)
if (!type || v[s]['.type'] == type)
- sa.push(Object.assign({ }, v[s], c ? c[s] : undefined));
+ sa.push(Object.assign({ }, v[s], c ? c[s] : null));
if (n)
for (var s in n)
@@ -428,13 +436,13 @@ return baseclass.extend(/** @lends LuCI.uci.prototype */ {
* of the given configuration or the entire section object if the
* option name is omitted.
*
- * @param {string} config
+ * @param {string} conf
* The name of the configuration to read the value from.
*
* @param {string} sid
* The name or ID of the section to read.
*
- * @param {string} [option]
+ * @param {string} [opt]
* The option name to read the value from. If the option name is
* omitted or `null`, the entire section is returned instead.
*
@@ -462,7 +470,7 @@ return baseclass.extend(/** @lends LuCI.uci.prototype */ {
/* requested option in a just created section */
if (n[conf] && n[conf][sid]) {
if (!n[conf])
- return undefined;
+ return null;
if (opt == null)
return n[conf][sid];
@@ -473,14 +481,9 @@ 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] === true)
- return undefined;
-
- for (var i = 0; i < d[conf][sid].length; i++)
- if (d[conf][sid][i] == opt)
- return undefined;
- }
+ if (d[conf] && 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)
@@ -490,14 +493,34 @@ return baseclass.extend(/** @lends LuCI.uci.prototype */ {
if (v[conf] && v[conf][sid])
return v[conf][sid][opt];
- return undefined;
+ return null;
}
/* requested an entire section */
- if (v[conf])
- return v[conf][sid];
+ if (v[conf]) {
+ /* check whether entire section was deleted */
+ if (d[conf] && d[conf][sid] === true)
+ return null;
+
+ var 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][opt] != null)
+ s[opt] = c[conf][sid][opt];
- return undefined;
+ /* merge deletions */
+ if (d[conf] && d[conf][sid])
+ for (var opt in d[conf][sid])
+ delete s[opt];
+ }
+
+ return s;
+ }
+
+ return null;
},
/**
@@ -507,16 +530,16 @@ return baseclass.extend(/** @lends LuCI.uci.prototype */ {
* If either config, section or option is null, or if `option` begins
* with a dot, the function will do nothing.
*
- * @param {string} config
+ * @param {string} conf
* The name of the configuration to set the option value in.
*
* @param {string} sid
* The name or ID of the section to set the option value in.
*
- * @param {string} option
+ * @param {string} opt
* The option name to set the value for.
*
- * @param {null|string|string[]} value
+ * @param {null|string|string[]} val
* The option value to set. If the value is `null` or an empty string,
* the option will be removed, otherwise it will be set or overwritten
* with the given value.
@@ -555,28 +578,34 @@ return baseclass.extend(/** @lends LuCI.uci.prototype */ {
/* undelete option */
if (d[conf] && d[conf][sid]) {
- d[conf][sid] = d[conf][sid].filter(function(o) { return o !== opt });
-
- if (d[conf][sid].length == 0)
+ if (isEmpty(d[conf][sid], opt))
delete d[conf][sid];
+ else
+ delete d[conf][sid][opt];
}
c[conf][sid][opt] = val;
}
else {
- /* only delete in existing sections */
- if (!(v[conf] && v[conf][sid] && v[conf][sid].hasOwnProperty(opt)) &&
- !(c[conf] && c[conf][sid] && c[conf][sid].hasOwnProperty(opt)))
- return;
+ /* revert any change for to-be-deleted option */
+ if (c[conf] && c[conf][sid]) {
+ if (isEmpty(c[conf][sid], opt))
+ delete c[conf][sid];
+ else
+ delete c[conf][sid][opt];
+ }
- if (!d[conf])
- d[conf] = { };
+ /* 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 (!d[conf][sid])
+ d[conf][sid] = { };
- if (d[conf][sid] !== true)
- d[conf][sid].push(opt);
+ if (d[conf][sid] !== true)
+ d[conf][sid][opt] = true;
+ }
}
},
@@ -587,13 +616,13 @@ return baseclass.extend(/** @lends LuCI.uci.prototype */ {
* This function is a convenience wrapper around
* `uci.set(config, section, option, null)`.
*
- * @param {string} config
+ * @param {string} conf
* The name of the configuration to remove the option from.
*
* @param {string} sid
* The name or ID of the section to remove the option from.
*
- * @param {string} option
+ * @param {string} opt
* The name of the option to remove.
*/
unset: function(conf, sid, opt) {
@@ -603,9 +632,9 @@ return baseclass.extend(/** @lends LuCI.uci.prototype */ {
/**
* Gets the value of the given option or the entire section object of
* the first found section of the specified type or the first found
- * section of the entire configuration if no type is specfied.
+ * section of the entire configuration if no type is specified.
*
- * @param {string} config
+ * @param {string} conf
* The name of the configuration to read the value from.
*
* @param {string} [type]
@@ -613,7 +642,7 @@ return baseclass.extend(/** @lends LuCI.uci.prototype */ {
* section of the entire config is read, otherwise the first section
* matching the given type.
*
- * @param {string} [option]
+ * @param {string} [opt]
* The option name to read the value from. If the option name is
* omitted or `null`, the entire section is returned instead.
*
@@ -646,7 +675,7 @@ return baseclass.extend(/** @lends LuCI.uci.prototype */ {
* If either config, type or option is null, or if `option` begins
* with a dot, the function will do nothing.
*
- * @param {string} config
+ * @param {string} conf
* The name of the configuration to set the option value in.
*
* @param {string} [type]
@@ -654,10 +683,10 @@ return baseclass.extend(/** @lends LuCI.uci.prototype */ {
* section of the entire config is written to, otherwise the first
* section matching the given type is used.
*
- * @param {string} option
+ * @param {string} opt
* The option name to set the value for.
*
- * @param {null|string|string[]} value
+ * @param {null|string|string[]} val
* The option value to set. If the value is `null` or an empty string,
* the option will be removed, otherwise it will be set or overwritten
* with the given value.
@@ -681,7 +710,7 @@ return baseclass.extend(/** @lends LuCI.uci.prototype */ {
* This function is a convenience wrapper around
* `uci.set_first(config, type, option, null)`.
*
- * @param {string} config
+ * @param {string} conf
* The name of the configuration to set the option value in.
*
* @param {string} [type]
@@ -689,7 +718,7 @@ return baseclass.extend(/** @lends LuCI.uci.prototype */ {
* section of the entire config is written to, otherwise the first
* section matching the given type is used.
*
- * @param {string} option
+ * @param {string} opt
* The option name to set the value for.
*/
unset_first: function(conf, type, opt) {
@@ -700,7 +729,7 @@ return baseclass.extend(/** @lends LuCI.uci.prototype */ {
* Move the first specified section within the given configuration
* before or after the second specified section.
*
- * @param {string} config
+ * @param {string} conf
* The configuration to move the section within.
*
* @param {string} sid1
@@ -796,7 +825,11 @@ return baseclass.extend(/** @lends LuCI.uci.prototype */ {
for (var conf in d) {
for (var sid in d[conf]) {
var o = d[conf][sid];
- tasks.push(self.callDelete(conf, sid, (o === true) ? null : o));
+
+ if (o === true)
+ tasks.push(self.callDelete(conf, sid, null));
+ else
+ tasks.push(self.callDelete(conf, sid, Object.keys(o)));
}
pkgs[conf] = true;