if (indexA != indexB)
return (indexA - indexB);
- return (a > b);
+ return L.naturalCompare(a, b);
}, this));
for (var i = 0; i < section_ids.length; i++)
/**
* Add another form element as children to this element.
*
- * @param {AbstractElement} element
+ * @param {AbstractElement} obj
* The form element to add.
*/
append: function(obj) {
* The `parse()` function recursively walks the form element tree and
* triggers input value reading and validation for each encountered element.
*
- * Elements which are hidden due to unsatisified dependencies are skipped.
+ * Elements which are hidden due to unsatisfied dependencies are skipped.
*
* @returns {Promise<void>}
* Returns a promise resolving once this element's value and the values of
/**
* Strip any HTML tags from the given input string.
*
- * @param {string} input
+ * @param {string} s
* The input string to clean.
*
* @returns {string}
- * The cleaned input string with HTML removes removed.
+ * The cleaned input string with HTML tags removed.
*/
stripTags: function(s) {
if (typeof(s) == 'string' && !s.match(/[<>]/))
* @classdesc
*
* The `Map` class represents one complete form. A form usually maps one UCI
- * configuraton file and is divided into multiple sections containing multiple
+ * configuration file and is divided into multiple sections containing multiple
* fields each.
*
* It serves as main entry point into the `LuCI.form` for typical view code.
*
* @param {string} [description]
* The description text of the form which is usually rendered as text
- * paragraph below the form title and before the actual form conents.
+ * 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 */ {
* @param {LuCI.form.AbstractSection} sectionclass
* The section class to use for rendering the configuration section.
* Note that this value must be the class itself, not a class instance
- * obtained from calling `new`. It must also be a class dervied from
+ * obtained from calling `new`. It must also be a class derived from
* `LuCI.form.AbstractSection`.
*
* @param {...string} classargs
- * Additional arguments which are passed as-is to the contructor of the
+ * Additional arguments which are passed as-is to the constructor of the
* given section class. Refer to the class specific constructor
* documentation for details.
*
* The `parse()` function recursively walks the form element tree and
* triggers input value reading and validation for each child element.
*
- * Elements which are hidden due to unsatisified dependencies are skipped.
+ * Elements which are hidden due to unsatisfied dependencies are skipped.
*
* @returns {Promise<void>}
* Returns a promise resolving once the entire form completed parsing all
*
* @param {boolean} [silent=false]
* If set to `true`, trigger an alert message to the user in case saving
- * the form data failes. Otherwise fail silently.
+ * the form data failures. Otherwise fail silently.
*
* @returns {Promise<void>}
* Returns a promise resolving once the entire save operation is complete.
/**
* Find a form option element instance.
*
- * @param {string} name_or_id
+ * @param {string} name
* The name or the full ID of the option element to look up.
*
* @param {string} [section_id]
* The ID of the UCI section containing the option to look up. May be
* omitted if a full ID is passed as first argument.
*
- * @param {string} [config]
- * The name of the UCI configuration the option instance is belonging to.
+ * @param {string} [config_name]
+ * The name of the UCI configuration the option instance belongs to.
* Defaults to the main UCI configuration of the map if omitted.
*
* @returns {Array<LuCI.form.AbstractValue,string>|null}
*
* @param {string} [description]
* The description text of the form which is usually rendered as text
- * paragraph below the form title and before the actual form conents.
+ * 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 */ {
* triggers input value reading and validation for each encountered child
* option element.
*
- * Options which are hidden due to unsatisified dependencies are skipped.
+ * Options which are hidden due to unsatisfied dependencies are skipped.
*
* @returns {Promise<void>}
* Returns a promise resolving once the values of all child elements have
* contents. If omitted, no description will be rendered.
*
* @throws {Error}
- * Throws an exeption if a tab with the same `name` already exists.
+ * Throws an exception if a tab with the same `name` already exists.
*/
tab: function(name, title, description) {
if (this.tabs && this.tabs[name])
* @param {LuCI.form.AbstractValue} optionclass
* The option class to use for rendering the configuration option. Note
* that this value must be the class itself, not a class instance obtained
- * from calling `new`. It must also be a class dervied from
+ * from calling `new`. It must also be a class derived from
* [LuCI.form.AbstractSection]{@link LuCI.form.AbstractSection}.
*
* @param {...*} classargs
- * Additional arguments which are passed as-is to the contructor of the
+ * Additional arguments which are passed as-is to the constructor of the
* given option class. Refer to the class specific constructor
* documentation for details.
*
/**
* Add a configuration option widget to a tab of the section.
*
- * @param {string} tabname
+ * @param {string} tabName
* The name of the section tab to add the option element to.
*
* @param {LuCI.form.AbstractValue} optionclass
* The option class to use for rendering the configuration option. Note
* that this value must be the class itself, not a class instance obtained
- * from calling `new`. It must also be a class dervied from
+ * from calling `new`. It must also be a class derived from
* [LuCI.form.AbstractSection]{@link LuCI.form.AbstractSection}.
*
* @param {...*} classargs
- * Additional arguments which are passed as-is to the contructor of the
+ * Additional arguments which are passed as-is to the constructor of the
* given option class. Refer to the class specific constructor
* documentation for details.
*
/**
* If set to `true`, the underlying ui input widget value is not cleared
- * from the configuration on unsatisfied depedencies. The default behavior
+ * from the configuration on unsatisfied dependencies. The default behavior
* is to remove the values of all options whose dependencies are not
* fulfilled.
*
*/
/**
- * Add a dependency contraint to the option.
+ * Add a dependency constraint to the option.
*
* Dependency constraints allow making the presence of option elements
- * dependant on the current values of certain other options within the
+ * dependent on the current values of certain other options within the
* same form. An option element with unsatisfied dependencies will be
* hidden from the view and its current value is omitted when saving.
*
* a logical "and" expression.
*
* Option names may be given in "dot notation" which allows to reference
- * option elements outside of the current form section. If a name without
+ * option elements outside the current form section. If a name without
* dot is specified, it refers to an option within the same configuration
* section. If specified as <code>configname.sectionid.optionname</code>,
* options anywhere within the same form may be specified.
* </li>
* </ul>
*
- * @param {string|Object<string, string|RegExp>} optionname_or_depends
+ * @param {string|Object<string, string|RegExp>} field
* The name of the option to depend on or an object describing multiple
- * dependencies which must be satified (a logical "and" expression).
+ * dependencies which must be satisfied (a logical "and" expression).
*
- * @param {string} optionvalue|RegExp
+ * @param {string|RegExp} value
* When invoked with a plain option name as first argument, this parameter
* specifies the expected value. In case an object is passed as first
* argument, this parameter is ignored.
if (this.map.readonly !== true) {
ui.addValidator(nameEl, 'uciname', true, function(v) {
- var button = document.querySelector('.cbi-section-create > .cbi-button-add');
+ var button = createEl.querySelector('.cbi-section-create > .cbi-button-add');
if (v !== '') {
button.disabled = null;
return true;
}
return saveTasks
- .then(L.bind(this.handleModalCancel, this, modalMap, ev))
+ .then(L.bind(this.handleModalCancel, this, modalMap, ev, true))
.catch(function() {});
},
}, this));
list.sort(function(a, b) {
- if (a[0] < b[0])
- return descending ? 1 : -1;
-
- if (a[0] > b[0])
- return descending ? -1 : 1;
-
- return 0;
+ return descending
+ ? -L.naturalCompare(a[0], b[0])
+ : L.naturalCompare(a[0], b[0]);
});
window.requestAnimationFrame(L.bind(function() {
* @returns {*|Promise<*>}
* Return values of this function are ignored but if a promise is returned,
* it is run to completion before the rendering is continued, allowing
- * custom logic to perform asynchroneous work before the modal dialog
+ * custom logic to perform asynchronous work before the modal dialog
* is shown.
*/
addModalOptions: function(modalSection, section_id, ev) {
return (stackedMap ? activeMap.save(null, true) : Promise.resolve()).then(L.bind(function() {
section_id = sref['.name'];
- var m = new CBIMap(parent.config, null, null),
- s = m.section(CBINamedSection, section_id, this.sectiontype);
+ var m;
+
+ if (parent instanceof CBIJSONMap) {
+ m = new CBIJSONMap(null, null, null);
+ m.data = parent.data;
+ }
+ else {
+ m = new CBIMap(parent.config, null, null);
+ }
+
+ var s = m.section(CBINamedSection, section_id, this.sectiontype);
m.parent = parent;
m.section = section_id;
*
* Another important difference is that the table cells show a readonly text
* preview of the corresponding option elements by default, unless the child
- * option element is explicitely made writable by setting the `editable`
+ * option element is explicitly made writable by setting the `editable`
* property to `true`.
*
* Additionally, the grid section honours a `modalonly` property of child
* contents. If omitted, no description will be rendered.
*
* @throws {Error}
- * Throws an exeption if a tab with the same `name` already exists.
+ * Throws an exception if a tab with the same `name` already exists.
*/
tab: function(name, title, description) {
CBIAbstractSection.prototype.tab.call(this, name, title, description);
var mapNode = this.getPreviousModalMap(),
prevMap = mapNode ? dom.findClassInstance(mapNode) : this.map;
- return this.super('handleModalSave', arguments)
- .then(function() { delete prevMap.addedSection });
+ return this.super('handleModalSave', arguments);
},
/** @private */
- handleModalCancel: function(/* ... */) {
+ handleModalCancel: function(modalMap, ev, isSaving) {
var config_name = this.uciconfig || this.map.config,
mapNode = this.getPreviousModalMap(),
prevMap = mapNode ? dom.findClassInstance(mapNode) : this.map;
- if (prevMap.addedSection != null) {
+ if (prevMap.addedSection != null && !isSaving)
this.map.data.remove(config_name, prevMap.addedSection);
- delete prevMap.addedSection;
- }
+
+ delete prevMap.addedSection;
return this.super('handleModalCancel', arguments);
},
* @param {string} key
* The choice value to add.
*
- * @param {Node|string} value
+ * @param {Node|string} val
* 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.
*/
* @classdesc
*
* The `ListValue` class implements a simple static HTML select element
- * allowing the user to chose a single value from a set of predefined choices.
+ * allowing the user chose a single value from a set of predefined choices.
* It builds upon the {@link LuCI.ui.Select} widget.
*
* @param {LuCI.form.Map|LuCI.form.JSONMap} form
* Sets the input value to use for the checkbox checked state.
*
* @name LuCI.form.FlagValue.prototype#enabled
- * @type number
+ * @type string
* @default 1
*/
* Sets the input value to use for the checkbox unchecked state.
*
* @name LuCI.form.FlagValue.prototype#disabled
- * @type number
+ * @type string
* @default 0
*/
__name__: 'CBI.DummyValue',
/**
- * Set an URL which is opened when clicking on the dummy value text.
+ * Set a URL which is opened when clicking on the dummy value text.
*
* By setting this property, the dummy value text is wrapped in an `<a>`
* element with the property value used as `href` attribute.
* @hideconstructor
* @classdesc
*
- * The LuCI form class provides high level abstractions for creating creating
+ * The LuCI form class provides high level abstractions for creating
* UCI- or JSON backed configurations forms.
*
* To import the class in views, use `'require form'`, to import it in