luci-base: form.js: implement JSONMap
Implement a new map type JSONMap which uses a JSON data structure instead of uci as configuration data backend. Signed-off-by: Jo-Philipp Wich <jo@mein.io>
This commit is contained in:
parent
f67a9c8bf8
commit
96fbca76c8
1 changed files with 194 additions and 15 deletions
|
@ -4,6 +4,173 @@
|
||||||
|
|
||||||
var scope = this;
|
var scope = this;
|
||||||
|
|
||||||
|
var CBIJSONConfig = Class.extend({
|
||||||
|
__init__: function(data) {
|
||||||
|
data = Object.assign({}, data);
|
||||||
|
|
||||||
|
this.data = {};
|
||||||
|
|
||||||
|
var num_sections = 0,
|
||||||
|
section_ids = [];
|
||||||
|
|
||||||
|
for (var sectiontype in data) {
|
||||||
|
if (!data.hasOwnProperty(sectiontype))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (L.isObject(data[sectiontype])) {
|
||||||
|
this.data[sectiontype] = Object.assign(data[sectiontype], {
|
||||||
|
'.anonymous': false,
|
||||||
|
'.name': sectiontype,
|
||||||
|
'.type': sectiontype
|
||||||
|
});
|
||||||
|
|
||||||
|
section_ids.push(sectiontype);
|
||||||
|
num_sections++;
|
||||||
|
}
|
||||||
|
else if (Array.isArray(data[sectiontype])) {
|
||||||
|
for (var i = 0, index = 0; i < data[sectiontype].length; i++) {
|
||||||
|
var item = data[sectiontype][i],
|
||||||
|
anonymous, name;
|
||||||
|
|
||||||
|
if (!L.isObject(item))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (typeof(item['.name']) == 'string') {
|
||||||
|
name = item['.name'];
|
||||||
|
anonymous = false;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
name = sectiontype + num_sections;
|
||||||
|
anonymous = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.data.hasOwnProperty(name))
|
||||||
|
section_ids.push(name);
|
||||||
|
|
||||||
|
this.data[name] = Object.assign(item, {
|
||||||
|
'.index': num_sections++,
|
||||||
|
'.anonymous': anonymous,
|
||||||
|
'.name': name,
|
||||||
|
'.type': sectiontype
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
if (indexA != indexB)
|
||||||
|
return (indexA - indexB);
|
||||||
|
|
||||||
|
return (a > b);
|
||||||
|
}, this));
|
||||||
|
|
||||||
|
for (var i = 0; i < section_ids.length; i++)
|
||||||
|
this.data[section_ids[i]]['.index'] = i;
|
||||||
|
},
|
||||||
|
|
||||||
|
load: function() {
|
||||||
|
return Promise.resolve(this.data);
|
||||||
|
},
|
||||||
|
|
||||||
|
save: function() {
|
||||||
|
return Promise.resolve();
|
||||||
|
},
|
||||||
|
|
||||||
|
get: function(config, section, option) {
|
||||||
|
if (section == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
if (option == null)
|
||||||
|
return this.data[section];
|
||||||
|
|
||||||
|
if (!this.data.hasOwnProperty(section))
|
||||||
|
return null;
|
||||||
|
|
||||||
|
var value = this.data[section][option];
|
||||||
|
|
||||||
|
if (Array.isArray(value))
|
||||||
|
return value;
|
||||||
|
|
||||||
|
if (value != null)
|
||||||
|
return String(value);
|
||||||
|
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
|
||||||
|
set: function(config, section, option, value) {
|
||||||
|
if (section == null || option == null || option.charAt(0) == '.')
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!this.data.hasOwnProperty(section))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (value == null)
|
||||||
|
delete this.data[section][option];
|
||||||
|
else if (Array.isArray(value))
|
||||||
|
this.data[section][option] = value;
|
||||||
|
else
|
||||||
|
this.data[section][option] = String(value);
|
||||||
|
},
|
||||||
|
|
||||||
|
unset: function(config, section, option) {
|
||||||
|
return this.set(config, section, option, null);
|
||||||
|
},
|
||||||
|
|
||||||
|
sections: function(config, sectiontype, callback) {
|
||||||
|
var rv = [];
|
||||||
|
|
||||||
|
for (var 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'] });
|
||||||
|
|
||||||
|
if (typeof(callback) == 'function')
|
||||||
|
for (var 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;
|
||||||
|
|
||||||
|
for (var 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;
|
||||||
|
|
||||||
|
if (!this.data.hasOwnProperty(section_id)) {
|
||||||
|
this.data[section_id] = {
|
||||||
|
'.name': section_id,
|
||||||
|
'.type': sectiontype,
|
||||||
|
'.anonymous': (sectionname == null),
|
||||||
|
'.index': next_index + 1
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return section_id;
|
||||||
|
},
|
||||||
|
|
||||||
|
remove: function(config, section) {
|
||||||
|
if (this.data.hasOwnProperty(section))
|
||||||
|
delete this.data[section];
|
||||||
|
},
|
||||||
|
|
||||||
|
resolveSID: function(config, section_id) {
|
||||||
|
return section_id;
|
||||||
|
},
|
||||||
|
|
||||||
|
move: function(config, section_id1, section_id2, after) {
|
||||||
|
return uci.move.apply(this, [config, section_id1, section_id2, after]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
var CBINode = Class.extend({
|
var CBINode = Class.extend({
|
||||||
__init__: function(title, description) {
|
__init__: function(title, description) {
|
||||||
this.title = title || '';
|
this.title = title || '';
|
||||||
|
@ -83,6 +250,7 @@ var CBIMap = CBINode.extend({
|
||||||
|
|
||||||
this.config = config;
|
this.config = config;
|
||||||
this.parsechain = [ config ];
|
this.parsechain = [ config ];
|
||||||
|
this.data = uci;
|
||||||
},
|
},
|
||||||
|
|
||||||
findElements: function(/* ... */) {
|
findElements: function(/* ... */) {
|
||||||
|
@ -118,7 +286,7 @@ var CBIMap = CBINode.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
load: function() {
|
load: function() {
|
||||||
return uci.load(this.parsechain || [ this.config ])
|
return this.data.load(this.parsechain || [ this.config ])
|
||||||
.then(this.loadChildren.bind(this));
|
.then(this.loadChildren.bind(this));
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -137,7 +305,7 @@ var CBIMap = CBINode.extend({
|
||||||
|
|
||||||
return this.parse()
|
return this.parse()
|
||||||
.then(cb)
|
.then(cb)
|
||||||
.then(uci.save.bind(uci))
|
.then(this.data.save.bind(this.data))
|
||||||
.then(this.load.bind(this))
|
.then(this.load.bind(this))
|
||||||
.catch(function(e) {
|
.catch(function(e) {
|
||||||
if (!silent)
|
if (!silent)
|
||||||
|
@ -228,6 +396,16 @@ var CBIMap = CBINode.extend({
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
var CBIJSONMap = CBIMap.extend({
|
||||||
|
__init__: function(data /*, ... */) {
|
||||||
|
this.super('__init__', this.varargs(arguments, 1, 'json'));
|
||||||
|
|
||||||
|
this.config = 'json';
|
||||||
|
this.parsechain = [ 'json' ];
|
||||||
|
this.data = new CBIJSONConfig(data);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
var CBIAbstractSection = CBINode.extend({
|
var CBIAbstractSection = CBINode.extend({
|
||||||
__init__: function(map, sectionType /*, ... */) {
|
__init__: function(map, sectionType /*, ... */) {
|
||||||
this.super('__init__', this.varargs(arguments, 2));
|
this.super('__init__', this.varargs(arguments, 2));
|
||||||
|
@ -543,7 +721,7 @@ var CBIAbstractValue = CBINode.extend({
|
||||||
if (section_id == null)
|
if (section_id == null)
|
||||||
L.error('TypeError', 'Section ID required');
|
L.error('TypeError', 'Section ID required');
|
||||||
|
|
||||||
return uci.get(
|
return this.map.data.get(
|
||||||
this.uciconfig || this.section.uciconfig || this.map.config,
|
this.uciconfig || this.section.uciconfig || this.map.config,
|
||||||
this.ucisection || section_id,
|
this.ucisection || section_id,
|
||||||
this.ucioption || this.option);
|
this.ucioption || this.option);
|
||||||
|
@ -631,7 +809,7 @@ var CBIAbstractValue = CBINode.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
write: function(section_id, formvalue) {
|
write: function(section_id, formvalue) {
|
||||||
return uci.set(
|
return this.map.data.set(
|
||||||
this.uciconfig || this.section.uciconfig || this.map.config,
|
this.uciconfig || this.section.uciconfig || this.map.config,
|
||||||
this.ucisection || section_id,
|
this.ucisection || section_id,
|
||||||
this.ucioption || this.option,
|
this.ucioption || this.option,
|
||||||
|
@ -639,7 +817,7 @@ var CBIAbstractValue = CBINode.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
remove: function(section_id) {
|
remove: function(section_id) {
|
||||||
return uci.unset(
|
return this.map.data.unset(
|
||||||
this.uciconfig || this.section.uciconfig || this.map.config,
|
this.uciconfig || this.section.uciconfig || this.map.config,
|
||||||
this.ucisection || section_id,
|
this.ucisection || section_id,
|
||||||
this.ucioption || this.option);
|
this.ucioption || this.option);
|
||||||
|
@ -650,7 +828,7 @@ var CBITypedSection = CBIAbstractSection.extend({
|
||||||
__name__: 'CBI.TypedSection',
|
__name__: 'CBI.TypedSection',
|
||||||
|
|
||||||
cfgsections: function() {
|
cfgsections: function() {
|
||||||
return uci.sections(this.uciconfig || this.map.config, this.sectiontype)
|
return this.map.data.sections(this.uciconfig || this.map.config, this.sectiontype)
|
||||||
.map(function(s) { return s['.name'] })
|
.map(function(s) { return s['.name'] })
|
||||||
.filter(L.bind(this.filter, this));
|
.filter(L.bind(this.filter, this));
|
||||||
},
|
},
|
||||||
|
@ -658,14 +836,14 @@ var CBITypedSection = CBIAbstractSection.extend({
|
||||||
handleAdd: function(ev, name) {
|
handleAdd: function(ev, name) {
|
||||||
var config_name = this.uciconfig || this.map.config;
|
var config_name = this.uciconfig || this.map.config;
|
||||||
|
|
||||||
uci.add(config_name, this.sectiontype, name);
|
this.map.data.add(config_name, this.sectiontype, name);
|
||||||
return this.map.save(null, true);
|
return this.map.save(null, true);
|
||||||
},
|
},
|
||||||
|
|
||||||
handleRemove: function(section_id, ev) {
|
handleRemove: function(section_id, ev) {
|
||||||
var config_name = this.uciconfig || this.map.config;
|
var config_name = this.uciconfig || this.map.config;
|
||||||
|
|
||||||
uci.remove(config_name, section_id);
|
this.map.data.remove(config_name, section_id);
|
||||||
return this.map.save(null, true);
|
return this.map.save(null, true);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -998,7 +1176,7 @@ var CBITableSection = CBITypedSection.extend({
|
||||||
'title': btn_title || _('Delete'),
|
'title': btn_title || _('Delete'),
|
||||||
'class': 'cbi-button cbi-button-remove',
|
'class': 'cbi-button cbi-button-remove',
|
||||||
'click': L.ui.createHandlerFn(this, function(sid, ev) {
|
'click': L.ui.createHandlerFn(this, function(sid, ev) {
|
||||||
uci.remove(config_name, sid);
|
this.map.data.remove(config_name, sid);
|
||||||
return this.map.save(null, true);
|
return this.map.save(null, true);
|
||||||
}, section_id)
|
}, section_id)
|
||||||
}, [ btn_title || _('Delete') ])
|
}, [ btn_title || _('Delete') ])
|
||||||
|
@ -1082,7 +1260,7 @@ var CBITableSection = CBITypedSection.extend({
|
||||||
sid2 = s.targetNode.getAttribute('data-sid');
|
sid2 = s.targetNode.getAttribute('data-sid');
|
||||||
|
|
||||||
s.node.parentNode.insertBefore(s.node, ref_node);
|
s.node.parentNode.insertBefore(s.node, ref_node);
|
||||||
uci.move(config_name, sid1, sid2, after);
|
this.map.data.move(config_name, sid1, sid2, after);
|
||||||
}
|
}
|
||||||
|
|
||||||
scope.dragState = null;
|
scope.dragState = null;
|
||||||
|
@ -1178,7 +1356,7 @@ var CBIGridSection = CBITableSection.extend({
|
||||||
|
|
||||||
handleAdd: function(ev) {
|
handleAdd: function(ev) {
|
||||||
var config_name = this.uciconfig || this.map.config,
|
var config_name = this.uciconfig || this.map.config,
|
||||||
section_id = uci.add(config_name, this.sectiontype);
|
section_id = this.map.data.add(config_name, this.sectiontype);
|
||||||
|
|
||||||
this.addedSection = section_id;
|
this.addedSection = section_id;
|
||||||
return this.renderMoreOptionsModal(section_id);
|
return this.renderMoreOptionsModal(section_id);
|
||||||
|
@ -1193,7 +1371,7 @@ var CBIGridSection = CBITableSection.extend({
|
||||||
var config_name = this.uciconfig || this.map.config;
|
var config_name = this.uciconfig || this.map.config;
|
||||||
|
|
||||||
if (this.addedSection != null) {
|
if (this.addedSection != null) {
|
||||||
uci.remove(config_name, this.addedSection);
|
this.map.data.remove(config_name, this.addedSection);
|
||||||
this.addedSection = null;
|
this.addedSection = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1273,7 +1451,7 @@ var CBINamedSection = CBIAbstractSection.extend({
|
||||||
var section_id = this.section,
|
var section_id = this.section,
|
||||||
config_name = this.uciconfig || this.map.config;
|
config_name = this.uciconfig || this.map.config;
|
||||||
|
|
||||||
uci.add(config_name, this.sectiontype, section_id);
|
this.map.data.add(config_name, this.sectiontype, section_id);
|
||||||
return this.map.save(null, true);
|
return this.map.save(null, true);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -1281,7 +1459,7 @@ var CBINamedSection = CBIAbstractSection.extend({
|
||||||
var section_id = this.section,
|
var section_id = this.section,
|
||||||
config_name = this.uciconfig || this.map.config;
|
config_name = this.uciconfig || this.map.config;
|
||||||
|
|
||||||
uci.remove(config_name, section_id);
|
this.map.data.remove(config_name, section_id);
|
||||||
return this.map.save(null, true);
|
return this.map.save(null, true);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -1337,7 +1515,7 @@ var CBINamedSection = CBIAbstractSection.extend({
|
||||||
section_id = this.section;
|
section_id = this.section;
|
||||||
|
|
||||||
return Promise.all([
|
return Promise.all([
|
||||||
uci.get(config_name, section_id),
|
this.map.data.get(config_name, section_id),
|
||||||
this.renderUCISection(section_id)
|
this.renderUCISection(section_id)
|
||||||
]).then(this.renderContents.bind(this));
|
]).then(this.renderContents.bind(this));
|
||||||
}
|
}
|
||||||
|
@ -1737,6 +1915,7 @@ var CBISectionValue = CBIValue.extend({
|
||||||
|
|
||||||
return L.Class.extend({
|
return L.Class.extend({
|
||||||
Map: CBIMap,
|
Map: CBIMap,
|
||||||
|
JSONMap: CBIJSONMap,
|
||||||
AbstractSection: CBIAbstractSection,
|
AbstractSection: CBIAbstractSection,
|
||||||
AbstractValue: CBIAbstractValue,
|
AbstractValue: CBIAbstractValue,
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue