summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJo-Philipp Wich <jow@openwrt.org>2014-05-30 18:48:58 +0200
committerJo-Philipp Wich <jow@openwrt.org>2014-05-30 18:48:58 +0200
commit7add1278c5fcbc24bb5773fbb70fb0cf7407b863 (patch)
treee3a14e8e6279d81d26e213e0ff4a7192ce2f095b
parent93d60ecdd50dc8812ba76468de65ec0c4cb14fba (diff)
downloadluci2-ui-7add1278c5fcbc24bb5773fbb70fb0cf7407b863.tar.gz
luci2: nested section support and initial code refactoring
Implement support for nested CBI sections and change the internal function naming in luci2.js for better clarity. Signed-off-by: Jo-Philipp Wich <jow@openwrt.org>
-rw-r--r--luci2/htdocs/luci2/luci2.js1397
-rw-r--r--luci2/htdocs/luci2/proto/6in4.js4
-rw-r--r--luci2/htdocs/luci2/proto/static.js4
-rw-r--r--luci2/htdocs/luci2/view/network.interfaces.js2
-rw-r--r--luci2/htdocs/luci2/view/network.switch.js28
-rw-r--r--luci2/htdocs/luci2/view/system.users.js36
6 files changed, 766 insertions, 705 deletions
diff --git a/luci2/htdocs/luci2/luci2.js b/luci2/htdocs/luci2/luci2.js
index 97e2642..6bf159d 100644
--- a/luci2/htdocs/luci2/luci2.js
+++ b/luci2/htdocs/luci2/luci2.js
@@ -1,7 +1,7 @@
/*
LuCI2 - OpenWrt Web Interface
- Copyright 2013 Jo-Philipp Wich <jow@openwrt.org>
+ Copyright 2013-2014 Jo-Philipp Wich <jow@openwrt.org>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -829,39 +829,50 @@ function LuCI2()
};
},
- _load: L.rpc.declare({
+ callLoad: L.rpc.declare({
object: 'uci',
method: 'get',
params: [ 'config' ],
expect: { values: { } }
}),
- _order: L.rpc.declare({
+ callOrder: L.rpc.declare({
object: 'uci',
method: 'order',
params: [ 'config', 'sections' ]
}),
- _add: L.rpc.declare({
+ callAdd: L.rpc.declare({
object: 'uci',
method: 'add',
params: [ 'config', 'type', 'name', 'values' ],
expect: { section: '' }
}),
- _set: L.rpc.declare({
+ callSet: L.rpc.declare({
object: 'uci',
method: 'set',
params: [ 'config', 'section', 'values' ]
}),
- _delete: L.rpc.declare({
+ callDelete: L.rpc.declare({
object: 'uci',
method: 'delete',
params: [ 'config', 'section', 'options' ]
}),
- _newid: function(conf)
+ callApply: L.rpc.declare({
+ object: 'uci',
+ method: 'apply',
+ params: [ 'timeout', 'rollback' ]
+ }),
+
+ callConfirm: L.rpc.declare({
+ object: 'uci',
+ method: 'confirm'
+ }),
+
+ createSID: function(conf)
{
var v = this.state.values;
var n = this.state.creates;
@@ -874,6 +885,51 @@ function LuCI2()
return sid;
},
+ reorderSections: function()
+ {
+ var v = this.state.values;
+ var n = this.state.creates;
+ var r = this.state.reorder;
+
+ if ($.isEmptyObject(r))
+ return L.deferrable();
+
+ L.rpc.batch();
+
+ /*
+ 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 = [ ];
+
+ if (n[c])
+ for (var s in n[c])
+ o.push(n[c][s]);
+
+ for (var s in v[c])
+ o.push(v[c][s]);
+
+ if (o.length > 0)
+ {
+ o.sort(function(a, b) {
+ return (a['.index'] - b['.index']);
+ });
+
+ var sids = [ ];
+
+ for (var i = 0; i < o.length; i++)
+ sids.push(o[i]['.name']);
+
+ this.callOrder(c, sids);
+ }
+ }
+
+ this.state.reorder = { };
+ return L.rpc.flush();
+ },
+
load: function(packages)
{
var self = this;
@@ -890,7 +946,7 @@ function LuCI2()
{
pkgs.push(packages[i]);
seen[packages[i]] = true;
- self._load(packages[i]);
+ self.callLoad(packages[i]);
}
return L.rpc.flush().then(function(responses) {
@@ -918,7 +974,7 @@ function LuCI2()
add: function(conf, type, name)
{
var n = this.state.creates;
- var sid = this._newid(conf);
+ var sid = this.createSID(conf);
if (!n[conf])
n[conf] = { };
@@ -1138,63 +1194,6 @@ function LuCI2()
return this.set_first(conf, type, opt, undefined);
},
- _reload: function()
- {
- var pkgs = [ ];
-
- for (var pkg in this.state.values)
- pkgs.push(pkg);
-
- this.init();
-
- return this.load(pkgs);
- },
-
- _reorder: function()
- {
- var v = this.state.values;
- var n = this.state.creates;
- var r = this.state.reorder;
-
- if ($.isEmptyObject(r))
- return L.deferrable();
-
- L.rpc.batch();
-
- /*
- 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 = [ ];
-
- if (n[c])
- for (var s in n[c])
- o.push(n[c][s]);
-
- for (var s in v[c])
- o.push(v[c][s]);
-
- if (o.length > 0)
- {
- o.sort(function(a, b) {
- return (a['.index'] - b['.index']);
- });
-
- var sids = [ ];
-
- for (var i = 0; i < o.length; i++)
- sids.push(o[i]['.name']);
-
- this._order(c, sids);
- }
- }
-
- this.state.reorder = { };
- return L.rpc.flush();
- },
-
swap: function(conf, sid1, sid2)
{
var s1 = this.get(conf, sid1);
@@ -1248,7 +1247,7 @@ function LuCI2()
snew.push(n[conf][sid]);
- self._add(r.config, r.type, r.name, r.values);
+ self.callAdd(r.config, r.type, r.name, r.values);
}
pkgs[conf] = true;
@@ -1258,7 +1257,7 @@ function LuCI2()
for (var conf in c)
{
for (var sid in c[conf])
- self._set(conf, sid, c[conf][sid]);
+ self.callSet(conf, sid, c[conf][sid]);
pkgs[conf] = true;
}
@@ -1269,7 +1268,7 @@ function LuCI2()
for (var sid in d[conf])
{
var o = d[conf][sid];
- self._delete(conf, sid, (o === true) ? undefined : o);
+ self.callDelete(conf, sid, (o === true) ? undefined : o);
}
pkgs[conf] = true;
@@ -1283,7 +1282,7 @@ function LuCI2()
for (var i = 0; i < snew.length; i++)
snew[i]['.name'] = responses[i];
- return self._reorder();
+ return self.reorderSections();
}).then(function() {
pkgs = L.toArray(pkgs);
@@ -1293,17 +1292,6 @@ function LuCI2()
});
},
- _apply: L.rpc.declare({
- object: 'uci',
- method: 'apply',
- params: [ 'timeout', 'rollback' ]
- }),
-
- _confirm: L.rpc.declare({
- object: 'uci',
- method: 'confirm'
- }),
-
apply: function(timeout)
{
var self = this;
@@ -1313,7 +1301,7 @@ function LuCI2()
if (typeof(timeout) != 'number' || timeout < 1)
timeout = 10;
- self._apply(timeout, true).then(function(rv) {
+ self.callApply(timeout, true).then(function(rv) {
if (rv != 0)
{
deferred.rejectWith(self, [ rv ]);
@@ -1323,7 +1311,7 @@ function LuCI2()
var try_deadline = date.getTime() + 1000 * timeout;
var try_confirm = function()
{
- return self._confirm().then(function(rv) {
+ return self.callConfirm().then(function(rv) {
if (rv != 0)
{
if (date.getTime() < try_deadline)
@@ -1572,7 +1560,7 @@ function LuCI2()
};
this.NetworkModel = {
- _device_blacklist: [
+ deviceBlacklist: [
/^gre[0-9]+$/,
/^gretap[0-9]+$/,
/^ifb[0-9]+$/,
@@ -1581,7 +1569,7 @@ function LuCI2()
/^wlan[0-9]+\.sta[0-9]+$/
],
- _cache_functions: [
+ rpcCacheFunctions: [
'protolist', 0, L.rpc.declare({
object: 'network',
method: 'get_proto_handlers',
@@ -1619,7 +1607,7 @@ function LuCI2()
})
],
- _fetch_protocol: function(proto)
+ loadProtocolHandler: function(proto)
{
var url = L.globals.resource + '/proto/' + proto + '.js';
var self = L.NetworkModel;
@@ -1641,7 +1629,7 @@ function LuCI2()
var protoClass = eval(protoConstructorSource);
- self._protos[proto] = new protoClass();
+ self.protocolHandlers[proto] = new protoClass();
}
catch(e) {
alert('Unable to instantiate proto "%s": %s'.format(url, e));
@@ -1655,36 +1643,36 @@ function LuCI2()
return def;
},
- _fetch_protocols: function()
+ loadProtocolHandlers: function()
{
var self = L.NetworkModel;
var deferreds = [
- self._fetch_protocol('none')
+ self.loadProtocolHandler('none')
];
- for (var proto in self._cache.protolist)
- deferreds.push(self._fetch_protocol(proto));
+ for (var proto in self.rpcCache.protolist)
+ deferreds.push(self.loadProtocolHandler(proto));
return $.when.apply($, deferreds);
},
- _fetch_swstate: L.rpc.declare({
+ callSwitchInfo: L.rpc.declare({
object: 'luci2.network',
method: 'switch_info',
params: [ 'switch' ],
expect: { 'info': { } }
}),
- _fetch_swstate_cb: function(responses) {
+ callSwitchInfoCallback: function(responses) {
var self = L.NetworkModel;
- var swlist = self._cache.swlist;
- var swstate = self._cache.swstate = { };
+ var swlist = self.rpcCache.swlist;
+ var swstate = self.rpcCache.swstate = { };
for (var i = 0; i < responses.length; i++)
swstate[swlist[i]] = responses[i];
},
- _fetch_cache_cb: function(level)
+ loadCacheCallback: function(level)
{
var self = L.NetworkModel;
var name = '_fetch_cache_cb_' + level;
@@ -1692,18 +1680,18 @@ function LuCI2()
return self[name] || (
self[name] = function(responses)
{
- for (var i = 0; i < self._cache_functions.length; i += 3)
- if (!level || self._cache_functions[i + 1] == level)
- self._cache[self._cache_functions[i]] = responses.shift();
+ for (var i = 0; i < self.rpcCacheFunctions.length; i += 3)
+ if (!level || self.rpcCacheFunctions[i + 1] == level)
+ self.rpcCache[self.rpcCacheFunctions[i]] = responses.shift();
if (!level)
{
L.rpc.batch();
- for (var i = 0; i < self._cache.swlist.length; i++)
- self._fetch_swstate(self._cache.swlist[i]);
+ for (var i = 0; i < self.rpcCache.swlist.length; i++)
+ self.callSwitchInfo(self.rpcCache.swlist[i]);
- return L.rpc.flush().then(self._fetch_swstate_cb);
+ return L.rpc.flush().then(self.callSwitchInfoCallback);
}
return L.deferrable();
@@ -1711,41 +1699,31 @@ function LuCI2()
);
},
- _fetch_cache: function(level)
+ loadCache: function(level)
{
var self = L.NetworkModel;
return L.uci.load(['network', 'wireless']).then(function() {
L.rpc.batch();
- for (var i = 0; i < self._cache_functions.length; i += 3)
- if (!level || self._cache_functions[i + 1] == level)
- self._cache_functions[i + 2]();
+ for (var i = 0; i < self.rpcCacheFunctions.length; i += 3)
+ if (!level || self.rpcCacheFunctions[i + 1] == level)
+ self.rpcCacheFunctions[i + 2]();
- return L.rpc.flush().then(self._fetch_cache_cb(level || 0));
+ return L.rpc.flush().then(self.loadCacheCallback(level || 0));
});
},
- _get: function(pkg, sid, key)
- {
- return L.uci.get(pkg, sid, key);
- },
-
- _set: function(pkg, sid, key, val)
- {
- return L.uci.set(pkg, sid, key, val);
- },
-
- _is_blacklisted: function(dev)
+ isBlacklistedDevice: function(dev)
{
- for (var i = 0; i < this._device_blacklist.length; i++)
- if (dev.match(this._device_blacklist[i]))
+ for (var i = 0; i < this.deviceBlacklist.length; i++)
+ if (dev.match(this.deviceBlacklist[i]))
return true;
return false;
},
- _sort_devices: function(a, b)
+ sortDevicesCallback: function(a, b)
{
if (a.options.kind < b.options.kind)
return -1;
@@ -1760,11 +1738,11 @@ function LuCI2()
return 0;
},
- _get_dev: function(ifname)
+ getDeviceObject: function(ifname)
{
var alias = (ifname.charAt(0) == '@');
- return this._devs[ifname] || (
- this._devs[ifname] = {
+ return this.deviceObjects[ifname] || (
+ this.deviceObjects[ifname] = {
ifname: ifname,
kind: alias ? 'alias' : 'ethernet',
type: alias ? 0 : 1,
@@ -1774,29 +1752,29 @@ function LuCI2()
);
},
- _get_iface: function(name)
+ getInterfaceObject: function(name)
{
- return this._ifaces[name] || (
- this._ifaces[name] = {
+ return this.interfaceObjects[name] || (
+ this.interfaceObjects[name] = {
name: name,
- proto: this._protos.none,
+ proto: this.protocolHandlers.none,
changed: { }
}
);
},
- _parse_devices: function()
+ loadDevicesCallback: function()
{
var self = L.NetworkModel;
var wificount = { };
- for (var ifname in self._cache.devstate)
+ for (var ifname in self.rpcCache.devstate)
{
- if (self._is_blacklisted(ifname))
+ if (self.isBlacklistedDevice(ifname))
continue;
- var dev = self._cache.devstate[ifname];
- var entry = self._get_dev(ifname);
+ var dev = self.rpcCache.devstate[ifname];
+ var entry = self.getDeviceObject(ifname);
entry.up = dev.up;
@@ -1813,14 +1791,14 @@ function LuCI2()
}
}
- for (var i = 0; i < self._cache.devlist.length; i++)
+ for (var i = 0; i < self.rpcCache.devlist.length; i++)
{
- var dev = self._cache.devlist[i];
+ var dev = self.rpcCache.devlist[i];
- if (self._is_blacklisted(dev.device))
+ if (self.isBlacklistedDevice(dev.device))
continue;
- var entry = self._get_dev(dev.device);
+ var entry = self.getDeviceObject(dev.device);
entry.up = dev.is_up;
entry.type = dev.type;
@@ -1854,7 +1832,7 @@ function LuCI2()
if (s['.type'] == 'device' && s.name)
{
- var entry = self._get_dev(s.name);
+ var entry = self.getDeviceObject(s.name);
switch (s.type)
{
@@ -1871,11 +1849,11 @@ function LuCI2()
var ifnames = L.toArray(s.ifname);
for (var j = 0; j < ifnames.length; j++)
- self._get_dev(ifnames[j]);
+ self.getDeviceObject(ifnames[j]);
if (s['.name'] != 'loopback')
{
- var entry = self._get_dev('@%s'.format(s['.name']));
+ var entry = self.getDeviceObject('@%s'.format(s['.name']));
entry.type = 0;
entry.kind = 'alias';
@@ -1884,7 +1862,7 @@ function LuCI2()
}
else if (s['.type'] == 'switch_vlan' && s.device)
{
- var sw = self._cache.swstate[s.device];
+ var sw = self.rpcCache.swstate[s.device];
var vid = parseInt(s.vid || s.vlan);
var ports = L.toArray(s.ports);
@@ -1913,7 +1891,7 @@ function LuCI2()
if (!ifname)
continue;
- var entry = self._get_dev(ifname);
+ var entry = self.getDeviceObject(ifname);
entry.kind = 'vlan';
entry.sid = sid;
@@ -1935,9 +1913,9 @@ function LuCI2()
var id = 'radio%d.network%d'.format(r, n);
var ifname = id;
- if (self._cache.wifistate[s.device])
+ if (self.rpcCache.wifistate[s.device])
{
- var ifcs = self._cache.wifistate[s.device].interfaces;
+ var ifcs = self.rpcCache.wifistate[s.device].interfaces;
for (var ifc in ifcs)
{
if (ifcs[ifc].section == sid)
@@ -1948,7 +1926,7 @@ function LuCI2()
}
}
- var entry = self._get_dev(ifname);
+ var entry = self.getDeviceObject(ifname);
entry.kind = 'wifi';
entry.sid = sid;
@@ -1969,9 +1947,9 @@ function LuCI2()
{
var ifnames = L.toArray(s.ifname);
- for (var ifname in self._devs)
+ for (var ifname in self.deviceObjects)
{
- var dev = self._devs[ifname];
+ var dev = self.deviceObjects[ifname];
if (dev.kind != 'wifi')
continue;
@@ -1981,7 +1959,7 @@ function LuCI2()
ifnames.push(ifname);
}
- entry = self._get_dev('br-%s'.format(s['.name']));
+ entry = self.getDeviceObject('br-%s'.format(s['.name']));
entry.type = 1;
entry.kind = 'bridge';
entry.sid = sid;
@@ -1990,7 +1968,7 @@ function LuCI2()
}
},
- _parse_interfaces: function()
+ loadInterfacesCallback: function()
{
var self = L.NetworkModel;
var net = L.uci.sections('network');
@@ -2002,17 +1980,17 @@ function LuCI2()
if (s['.type'] == 'interface' && !s['.anonymous'] && s.proto)
{
- var entry = self._get_iface(s['.name']);
- var proto = self._protos[s.proto] || self._protos.none;
+ var entry = self.getInterfaceObject(s['.name']);
+ var proto = self.protocolHandlers[s.proto] || self.protocolHandlers.none;
var l3dev = undefined;
var l2dev = undefined;
var ifnames = L.toArray(s.ifname);
- for (var ifname in self._devs)
+ for (var ifname in self.deviceObjects)
{
- var dev = self._devs[ifname];
+ var dev = self.deviceObjects[ifname];
if (dev.kind != 'wifi')
continue;
@@ -2041,11 +2019,11 @@ function LuCI2()
}
}
- for (var i = 0; i < self._cache.ifstate.length; i++)
+ for (var i = 0; i < self.rpcCache.ifstate.length; i++)
{
- var iface = self._cache.ifstate[i];
- var entry = self._get_iface(iface['interface']);
- var proto = self._protos[iface.proto] || self._protos.none;
+ var iface = self.rpcCache.ifstate[i];
+ var entry = self.getInterfaceObject(iface['interface']);
+ var proto = self.protocolHandlers[iface.proto] || self.protocolHandlers.none;
/* this is a virtual interface, either deleted from config but
not applied yet or set up from external tools (6rd) */
@@ -2062,53 +2040,53 @@ function LuCI2()
{
var self = this;
- if (self._cache)
+ if (self.rpcCache)
return L.deferrable();
- self._cache = { };
- self._devs = { };
- self._ifaces = { };
- self._protos = { };
+ self.rpcCache = { };
+ self.deviceObjects = { };
+ self.interfaceObjects = { };
+ self.protocolHandlers = { };
- return self._fetch_cache()
- .then(self._fetch_protocols)
- .then(self._parse_devices)
- .then(self._parse_interfaces);
+ return self.loadCache()
+ .then(self.loadProtocolHandlers)
+ .then(self.loadDevicesCallback)
+ .then(self.loadInterfacesCallback);
},
update: function()
{
- delete this._cache;
+ delete this.rpcCache;
return this.init();
},
refreshInterfaceStatus: function()
{
- return this._fetch_cache(1).then(this._parse_interfaces);
+ return this.loadCache(1).then(this.loadInterfacesCallback);
},
refreshDeviceStatus: function()
{
- return this._fetch_cache(2).then(this._parse_devices);
+ return this.loadCache(2).then(this.loadDevicesCallback);
},
refreshStatus: function()
{
- return this._fetch_cache(1)
- .then(this._fetch_cache(2))
- .then(this._parse_devices)
- .then(this._parse_interfaces);
+ return this.loadCache(1)
+ .then(this.loadCache(2))
+ .then(this.loadDevicesCallback)
+ .then(this.loadInterfacesCallback);
},
getDevices: function()
{
var devs = [ ];
- for (var ifname in this._devs)
+ for (var ifname in this.deviceObjects)
if (ifname != 'lo')
- devs.push(new L.NetworkModel.Device(this._devs[ifname]));
+ devs.push(new L.NetworkModel.Device(this.deviceObjects[ifname]));
- return devs.sort(this._sort_devices);
+ return devs.sort(this.sortDevicesCallback);
},
getDeviceByInterface: function(iface)
@@ -2116,31 +2094,31 @@ function LuCI2()
if (iface instanceof L.NetworkModel.Interface)
iface = iface.name();
- if (this._ifaces[iface])
- return this.getDevice(this._ifaces[iface].l3dev) ||
- this.getDevice(this._ifaces[iface].l2dev);
+ if (this.interfaceObjects[iface])
+ return this.getDevice(this.interfaceObjects[iface].l3dev) ||
+ this.getDevice(this.interfaceObjects[iface].l2dev);
return undefined;
},
getDevice: function(ifname)
{
- if (this._devs[ifname])
- return new L.NetworkModel.Device(this._devs[ifname]);
+ if (this.deviceObjects[ifname])
+ return new L.NetworkModel.Device(this.deviceObjects[ifname]);
return undefined;
},
createDevice: function(name)
{
- return new L.NetworkModel.Device(this._get_dev(name));
+ return new L.NetworkModel.Device(this.getDeviceObject(name));
},
getInterfaces: function()
{
var ifaces = [ ];
- for (var name in this._ifaces)
+ for (var name in this.interfaceObjects)
if (name != 'loopback')
ifaces.push(this.getInterface(name));
@@ -2163,9 +2141,9 @@ function LuCI2()
if (dev instanceof L.NetworkModel.Device)
dev = dev.name();
- for (var name in this._ifaces)
+ for (var name in this.interfaceObjects)
{
- var iface = this._ifaces[name];
+ var iface = this.interfaceObjects[name];
if (iface.l2dev == dev || iface.l3dev == dev)
ifaces.push(this.getInterface(name));
}
@@ -2184,8 +2162,8 @@ function LuCI2()
getInterface: function(iface)
{
- if (this._ifaces[iface])
- return new L.NetworkModel.Interface(this._ifaces[iface]);
+ if (this.interfaceObjects[iface])
+ return new L.NetworkModel.Interface(this.interfaceObjects[iface]);
return undefined;
},
@@ -2194,9 +2172,9 @@ function LuCI2()
{
var rv = [ ];
- for (var proto in this._protos)
+ for (var proto in this.protocolHandlers)
{
- var pr = this._protos[proto];
+ var pr = this.protocolHandlers[proto];
rv.push({
name: proto,
@@ -2216,11 +2194,11 @@ function LuCI2()
});
},
- _find_wan: function(ipaddr)
+ findWANByAddr: function(ipaddr)
{
- for (var i = 0; i < this._cache.ifstate.length; i++)
+ for (var i = 0; i < this.rpcCache.ifstate.length; i++)
{
- var ifstate = this._cache.ifstate[i];
+ var ifstate = this.rpcCache.ifstate[i];
if (!ifstate.route)
continue;
@@ -2239,12 +2217,12 @@ function LuCI2()
findWAN: function()
{
- return this._find_wan('0.0.0.0');
+ return this.findWANByAddr('0.0.0.0');
},
findWAN6: function()
{
- return this._find_wan('::');
+ return this.findWANByAddr('::');
},
resolveAlias: function(ifname)
@@ -2252,7 +2230,7 @@ function LuCI2()
if (ifname instanceof L.NetworkModel.Device)
ifname = ifname.name();
- var dev = this._devs[ifname];
+ var dev = this.deviceObjects[ifname];
var seen = { };
while (dev && dev.kind == 'alias')
@@ -2261,10 +2239,10 @@ function LuCI2()
if (seen[dev.ifname])
return undefined;
- var ifc = this._ifaces[dev.sid];
+ var ifc = this.interfaceObjects[dev.sid];
seen[dev.ifname] = true;
- dev = ifc ? this._devs[ifc.l3dev] : undefined;
+ dev = ifc ? this.deviceObjects[ifc.l3dev] : undefined;
}
return dev ? this.getDevice(dev.ifname) : undefined;
@@ -2272,7 +2250,7 @@ function LuCI2()
};
this.NetworkModel.Device = Class.extend({
- _wifi_modes: {
+ wifiModeStrings: {
ap: L.tr('Master'),
sta: L.tr('Client'),
adhoc: L.tr('Ad-Hoc'),
@@ -2280,9 +2258,9 @@ function LuCI2()
wds: L.tr('Static WDS')
},
- _status: function(key)
+ getStatus: function(key)
{
- var s = L.NetworkModel._cache.devstate[this.options.ifname];
+ var s = L.NetworkModel.rpcCache.devstate[this.options.ifname];
if (s)
return key ? s[key] : s;
@@ -2294,14 +2272,14 @@ function LuCI2()
{
var sid = this.options.sid;
var pkg = (this.options.kind == 'wifi') ? 'wireless' : 'network';
- return L.NetworkModel._get(pkg, sid, key);
+ return L.uci.get(pkg, sid, key);
},
set: function(key, val)
{
var sid = this.options.sid;
var pkg = (this.options.kind == 'wifi') ? 'wireless' : 'network';
- return L.NetworkModel._set(pkg, sid, key, val);
+ return L.uci.set(pkg, sid, key, val);
},
init: function()
@@ -2366,7 +2344,7 @@ function LuCI2()
case 'wifi':
var o = this.options;
return L.trc('(Wifi-Mode) "(SSID)" on (radioX)', '%s "%h" on %s').format(
- o.wmode ? this._wifi_modes[o.wmode] : L.tr('Unknown mode'),
+ o.wmode ? this.wifiModeStrings[o.wmode] : L.tr('Unknown mode'),
o.wssid || '?', o.wdev
);
}
@@ -2389,7 +2367,7 @@ function LuCI2()
isUp: function()
{
- var l = L.NetworkModel._cache.devlist;
+ var l = L.NetworkModel.rpcCache.devlist;
for (var i = 0; i < l.length; i++)
if (l[i].device == this.options.ifname)
@@ -2429,7 +2407,7 @@ function LuCI2()
net.options.l2dev == this.options.ifname)
return true;
- var dev = L.NetworkModel._devs[net.options.l2dev];
+ var dev = L.NetworkModel.deviceObjects[net.options.l2dev];
if (dev && dev.kind == 'bridge' && dev.ports)
return ($.inArray(this.options.ifname, dev.ports) > -1);
}
@@ -2439,7 +2417,7 @@ function LuCI2()
getMTU: function()
{
- var dev = L.NetworkModel._cache.devstate[this.options.ifname];
+ var dev = L.NetworkModel.rpcCache.devstate[this.options.ifname];
if (dev && !isNaN(dev.mtu))
return dev.mtu;
@@ -2451,7 +2429,7 @@ function LuCI2()
if (this.options.type != 1)
return undefined;
- var dev = L.NetworkModel._cache.devstate[this.options.ifname];
+ var dev = L.NetworkModel.rpcCache.devstate[this.options.ifname];
if (dev && dev.macaddr)
return dev.macaddr.toUpperCase();
@@ -2465,7 +2443,7 @@ function LuCI2()
getStatistics: function()
{
- var s = this._status('statistics') || { };
+ var s = this.getStatus('statistics') || { };
return {
rx_bytes: (s.rx_bytes || 0),
tx_bytes: (s.tx_bytes || 0),
@@ -2481,7 +2459,7 @@ function LuCI2()
for (var i = 0; i < 120; i++)
def[i] = 0;
- var h = L.NetworkModel._cache.bwstate[this.options.ifname] || { };
+ var h = L.NetworkModel.rpcCache.bwstate[this.options.ifname] || { };
return {
rx_bytes: (h.rx_bytes || def),
tx_bytes: (h.tx_bytes || def),
@@ -2540,9 +2518,9 @@ function LuCI2()
});
this.NetworkModel.Interface = Class.extend({
- _status: function(key)
+ getStatus: function(key)
{
- var s = L.NetworkModel._cache.ifstate;
+ var s = L.NetworkModel.rpcCache.ifstate;
for (var i = 0; i < s.length; i++)
if (s[i]['interface'] == this.options.name)
@@ -2553,12 +2531,12 @@ function LuCI2()
get: function(key)
{
- return L.NetworkModel._get('network', this.options.name, key);
+ return L.uci.get('network', this.options.name, key);
},
set: function(key, val)
{
- return L.NetworkModel._set('network', this.options.name, key, val);
+ return L.uci.set('network', this.options.name, key, val);
},
name: function()
@@ -2573,7 +2551,7 @@ function LuCI2()
isUp: function()
{
- return (this._status('up') === true);
+ return (this.getStatus('up') === true);
},
isVirtual: function()
@@ -2584,12 +2562,12 @@ function LuCI2()
getProtocol: function()
{
var prname = this.get('proto') || 'none';
- return L.NetworkModel._protos[prname] || L.NetworkModel._protos.none;
+ return L.NetworkModel.protocolHandlers[prname] || L.NetworkModel.protocolHandlers.none;
},
getUptime: function()
{
- var uptime = this._status('uptime');
+ var uptime = this.getStatus('uptime');
return isNaN(uptime) ? 0 : uptime;
},
@@ -2613,7 +2591,7 @@ function LuCI2()
{
var rv = [ ];
var dev = this.options.l2dev ?
- L.NetworkModel._devs[this.options.l2dev] : undefined;
+ L.NetworkModel.deviceObjects[this.options.l2dev] : undefined;
if (dev && dev.kind == 'bridge' && dev.ports && dev.ports.length)
for (var i = 0; i < dev.ports.length; i++)
@@ -2625,7 +2603,7 @@ function LuCI2()
getIPv4Addrs: function(mask)
{
var rv = [ ];
- var addrs = this._status('ipv4-address');
+ var addrs = this.getStatus('ipv4-address');
if (addrs)
for (var i = 0; i < addrs.length; i++)
@@ -2642,7 +2620,7 @@ function LuCI2()
var rv = [ ];
var addrs;
- addrs = this._status('ipv6-address');
+ addrs = this.getStatus('ipv6-address');
if (addrs)
for (var i = 0; i < addrs.length; i++)
@@ -2651,7 +2629,7 @@ function LuCI2()
else
rv.push('%s/%d'.format(addrs[i].address, addrs[i].mask));
- addrs = this._status('ipv6-prefix-assignment');
+ addrs = this.getStatus('ipv6-prefix-assignment');
if (addrs)
for (var i = 0; i < addrs.length; i++)
@@ -2666,7 +2644,7 @@ function LuCI2()
getDNSAddrs: function()
{
var rv = [ ];
- var addrs = this._status('dns-server');
+ var addrs = this.getStatus('dns-server');
if (addrs)
for (var i = 0; i < addrs.length; i++)
@@ -2678,7 +2656,7 @@ function LuCI2()
getIPv4DNS: function()
{
var rv = [ ];
- var dns = this._status('dns-server');
+ var dns = this.getStatus('dns-server');
if (dns)
for (var i = 0; i < dns.length; i++)
@@ -2691,7 +2669,7 @@ function LuCI2()
getIPv6DNS: function()
{
var rv = [ ];
- var dns = this._status('dns-server');
+ var dns = this.getStatus('dns-server');
if (dns)
for (var i = 0; i < dns.length; i++)
@@ -2703,7 +2681,7 @@ function LuCI2()
getIPv4Gateway: function()
{
- var rt = this._status('route');
+ var rt = this.getStatus('route');
if (rt)
for (var i = 0; i < rt.length; i++)
@@ -2715,7 +2693,7 @@ function LuCI2()
getIPv6Gateway: function()
{
- var rt = this._status('route');
+ var rt = this.getStatus('route');
if (rt)
for (var i = 0; i < rt.length; i++)
@@ -2809,7 +2787,7 @@ function LuCI2()
changeProtocol: function(proto)
{
- var pr = L.NetworkModel._protos[proto];
+ var pr = L.NetworkModel.protocolHandlers[proto];
if (!pr)
return;
@@ -3138,28 +3116,28 @@ function LuCI2()
},
- _acls: { },
+ aclCache: { },
- _fetch_acls: L.rpc.declare({
+ callAccess: L.rpc.declare({
object: 'session',
method: 'access',
expect: { '': { } }
}),
- _fetch_acls_cb: function(acls)
+ callAccessCallback: function(acls)
{
- L.session._acls = acls;
+ L.session.aclCache = acls;
},
updateACLs: function()
{
- return L.session._fetch_acls()
- .then(L.session._fetch_acls_cb);
+ return L.session.callAccess()
+ .then(L.session.callAccessCallback);
},
hasACL: function(scope, object, func)
{
- var acls = L.session._acls;
+ var acls = L.session.aclCache;
if (typeof(func) == 'undefined')
return (acls && acls[scope] && acls[scope][object]);
@@ -3586,7 +3564,7 @@ function LuCI2()
}),
- _acl_merge_scope: function(acl_scope, scope)
+ mergeACLScope: function(acl_scope, scope)
{
if ($.isArray(scope))
{
@@ -3608,19 +3586,19 @@ function LuCI2()
}
},
- _acl_merge_permission: function(acl_perm, perm)
+ mergeACLPermission: function(acl_perm, perm)
{
if ($.isPlainObject(perm))
{
for (var scope_name in perm)
{
var acl_scope = acl_perm[scope_name] || (acl_perm[scope_name] = { });
- this._acl_merge_scope(acl_scope, perm[scope_name]);
+ L.ui.mergeACLScope(acl_scope, perm[scope_name]);
}
}
},
- _acl_merge_group: function(acl_group, group)
+ mergeACLGroup: function(acl_group, group)
{
if ($.isPlainObject(group))
{
@@ -3630,42 +3608,48 @@ function LuCI2()
if (group.read)
{
var acl_perm = acl_group.read || (acl_group.read = { });
- this._acl_merge_permission(acl_perm, group.read);
+ L.ui.mergeACLPermission(acl_perm, group.read);
}
if (group.write)
{
var acl_perm = acl_group.write || (acl_group.write = { });
- this._acl_merge_permission(acl_perm, group.write);
+ L.ui.mergeACLPermission(acl_perm, group.write);
}
}
},
- _acl_merge_tree: function(acl_tree, tree)
+ callACLsCallback: function(trees)
{
- if ($.isPlainObject(tree))
+ var acl_tree = { };
+
+ for (var i = 0; i < trees.length; i++)
{
- for (var group_name in tree)
+ if (!$.isPlainObject(trees[i]))
+ continue;
+
+ for (var group_name in trees[i])
{
var acl_group = acl_tree[group_name] || (acl_tree[group_name] = { });
- this._acl_merge_group(acl_group, tree[group_name]);
+ L.ui.mergeACLGroup(acl_group, trees[i][group_name]);
}
}
+
+ return acl_tree;
},
- listAvailableACLs: L.rpc.declare({
+ callACLs: L.rpc.declare({
object: 'luci2.ui',
method: 'acls',
- expect: { acls: [ ] },
- filter: function(trees) {
- var acl_tree = { };
- for (var i = 0; i < trees.length; i++)
- L.ui._acl_merge_tree(acl_tree, trees[i]);
- return acl_tree;
- }
+ expect: { acls: [ ] }
}),
- _render_change_indicator: function()
+ getAvailableACLs: function()
+ {
+ return this.callACLs().then(this.callACLsCallback);
+ },
+
+ renderChangeIndicator: function()
{
return $('<ul />')
.addClass('nav navbar-nav navbar-right')
@@ -3677,21 +3661,28 @@ function LuCI2()
.addClass('label label-info'))));
},
- renderMainMenu: L.rpc.declare({
+ callMenuCallback: function(entries)
+ {
+ L.globals.mainMenu = new L.ui.menu();
+ L.globals.mainMenu.entries(entries);
+
+ $('#mainmenu')
+ .empty()
+ .append(L.globals.mainMenu.render(0, 1))
+ .append(L.ui.renderChangeIndicator());
+ },
+
+ callMenu: L.rpc.declare({
object: 'luci2.ui',
method: 'menu',
- expect: { menu: { } },
- filter: function(entries) {
- L.globals.mainMenu = new L.ui.menu();
- L.globals.mainMenu.entries(entries);
-
- $('#mainmenu')
- .empty()
- .append(L.globals.mainMenu.render(0, 1))
- .append(L.ui._render_change_indicator());
- }
+ expect: { menu: { } }
}),
+ renderMainMenu: function()
+ {
+ return this.callMenu().then(this.callMenuCallback);
+ },
+
renderViewMenu: function()
{
$('#viewmenu')
@@ -4083,7 +4074,7 @@ function LuCI2()
}
},
- _indexcmp: function(a, b)
+ sortNodesCallback: function(a, b)
{
var x = a.index || 0;
var y = b.index || 0;
@@ -4099,7 +4090,7 @@ function LuCI2()
for (var child in (node.childs || { }))
nodes.push(node.childs[child]);
- nodes.sort(this._indexcmp);
+ nodes.sort(this.sortNodesCallback);
for (var i = 0; i < nodes.length; i++)
{
@@ -4117,7 +4108,7 @@ function LuCI2()
return undefined;
},
- _onclick: function(ev)
+ handleClick: function(ev)
{
L.setHash('view', ev.data);
@@ -4125,7 +4116,7 @@ function LuCI2()
this.blur();
},
- _render: function(childs, level, min, max)
+ renderNodes: function(childs, level, min, max)
{
var nodes = [ ];
for (var node in childs)
@@ -4135,7 +4126,7 @@ function LuCI2()
nodes.push(childs[node]);
}
- nodes.sort(this._indexcmp);
+ nodes.sort(this.sortNodesCallback);
var list = $('<ul />');
@@ -4168,11 +4159,11 @@ function LuCI2()
.attr('data-toggle', 'dropdown')
.append('<b class="caret"></b>');
- item.append(this._render(nodes[i].childs, level + 1));
+ item.append(this.renderNodes(nodes[i].childs, level + 1));
}
else
{
- item.find('a').click(nodes[i].view, this._onclick);
+ item.find('a').click(nodes[i].view, this.handleClick);
}
}
@@ -4182,7 +4173,7 @@ function LuCI2()
render: function(min, max)
{
var top = min ? this.getNode(L.globals.defaultNode.view, min) : this._nodes;
- return this._render(top.childs, 0, min, max);
+ return this.renderNodes(top.childs, 0, min, max);
},
getNode: function(path, max)
@@ -4987,14 +4978,15 @@ function LuCI2()
id: function(sid)
{
- return this.section.id('field', sid || '__unknown__', this.name);
+ return this.ownerSection.id('field', sid || '__unknown__', this.name);
},
render: function(sid, condensed)
{
var i = this.instance[sid] = { };
- i.top = $('<div />');
+ i.top = $('<div />')
+ .addClass('luci2-field');
if (!condensed)
{
@@ -5010,9 +5002,10 @@ function LuCI2()
i.error = $('<div />')
.hide()
- .addClass('label label-danger');
+ .addClass('luci2-field-error label label-danger');
i.widget = $('<div />')
+ .addClass('luci2-field-widget')
.append(this.widget(sid))
.append(i.error)
.appendTo(i.top);
@@ -5038,7 +5031,7 @@ function LuCI2()
ucipath: function(sid)
{
return {
- config: (this.options.uci_package || this.map.uci_package),
+ config: (this.options.uci_package || this.ownerMap.uci_package),
section: (this.options.uci_section || sid),
option: (this.options.uci_option || this.name)
};
@@ -5047,7 +5040,7 @@ function LuCI2()
ucivalue: function(sid)
{
var uci = this.ucipath(sid);
- var val = this.map.get(uci.config, uci.section, uci.option);
+ var val = this.ownerMap.get(uci.config, uci.section, uci.option);
if (typeof(val) == 'undefined')
return this.options.initial;
@@ -5132,7 +5125,7 @@ function LuCI2()
if (this.instance[sid].disabled)
{
if (!this.options.keep)
- return this.map.set(uci.config, uci.section, uci.option, undefined);
+ return this.ownerMap.set(uci.config, uci.section, uci.option, undefined);
return false;
}
@@ -5141,16 +5134,56 @@ function LuCI2()
var val = this.formvalue(sid);
if (chg)
- this.map.set(uci.config, uci.section, uci.option, val);
+ this.ownerMap.set(uci.config, uci.section, uci.option, val);
return chg;
},
- _ev_validate: function(ev)
+ findSectionID: function($elem)
+ {
+ return this.ownerSection.findParentSectionIDs($elem)[0];
+ },
+
+ setError: function($elem, msg, msgargs)
{
+ var $field = $elem.parents('.luci2-field:first');
+ var $error = $field.find('.luci2-field-error:first');
+
+ if (typeof(msg) == 'string' && msg.length > 0)
+ {
+ $field.addClass('luci2-form-error');
+ $elem.parent().addClass('has-error');
+
+ $error.text(msg.format.apply(msg, msgargs)).show();
+ $field.trigger('validate');
+
+ return false;
+ }
+ else
+ {
+ $elem.parent().removeClass('has-error');
+
+ var $other_errors = $field.find('.has-error');
+ if ($other_errors.length == 0)
+ {
+ $field.removeClass('luci2-form-error');
+ $error.text('').hide();
+ $field.trigger('validate');
+
+ return true;
+ }
+
+ return false;
+ }
+ },
+
+ handleValidate: function(ev)
+ {
+ var $elem = $(this);
+
var d = ev.data;
var rv = true;
- var val = d.elem.val();
+ var val = $elem.val();
var vstack = d.vstack;
if (vstack && typeof(vstack[0]) == 'function')
@@ -5159,51 +5192,38 @@ function LuCI2()
if ((val.length == 0 && !d.opt))
{
- d.elem.parents('div.form-group, td').first().addClass('luci2-form-error');
- d.elem.parents('div.input-group, div.form-group, td').first().addClass('has-error');
-
- d.inst.error.text(L.tr('Field must not be empty')).show();
- rv = false;
+ rv = d.self.setError($elem, L.tr('Field must not be empty'));
}
else if (val.length > 0 && !vstack[0].apply(val, vstack[1]))
{
- d.elem.parents('div.form-group, td').first().addClass('luci2-form-error');
- d.elem.parents('div.input-group, div.form-group, td').first().addClass('has-error');
-
- d.inst.error.text(validation.message.format.apply(validation.message, vstack[1])).show();
- rv = false;
+ rv = d.self.setError($elem, validation.message, vstack[1]);
}
else
{
- d.elem.parents('div.form-group, td').first().removeClass('luci2-form-error');
- d.elem.parents('div.input-group, div.form-group, td').first().removeClass('has-error');
-
- if (d.multi && d.inst.widget && d.inst.widget.find('input.error, select.error').length > 0)
- rv = false;
- else
- d.inst.error.text('').hide();
+ rv = d.self.setError($elem);
}
}
if (rv)
{
+ var sid = d.self.findSectionID($elem);
+
for (var field in d.self.rdependency)
- d.self.rdependency[field].toggle(d.sid);
+ {
+ d.self.rdependency[field].toggle(sid);
+ d.self.rdependency[field].validate(sid);
+ }
- d.self.section.tabtoggle(d.sid);
+ d.self.ownerSection.tabtoggle(sid);
}
return rv;
},
- validator: function(sid, elem, multi)
+ attachEvents: function(sid, elem)
{
var evdata = {
self: this,
- sid: sid,
- elem: elem,
- multi: multi,
- inst: this.instance[sid],
opt: this.options.optional
};
@@ -5234,20 +5254,21 @@ function LuCI2()
if (elem.prop('tagName') == 'SELECT')
{
- elem.change(evdata, this._ev_validate);
+ elem.change(evdata, this.handleValidate);
}
else if (elem.prop('tagName') == 'INPUT' && elem.attr('type') == 'checkbox')
{
- elem.click(evdata, this._ev_validate);
- elem.blur(evdata, this._ev_validate);
+ elem.click(evdata, this.handleValidate);
+ elem.blur(evdata, this.handleValidate);
}
else
{
- elem.keyup(evdata, this._ev_validate);
- elem.blur(evdata, this._ev_validate);
+ elem.keyup(evdata, this.handleValidate);
+ elem.blur(evdata, this.handleValidate);
}
- elem.attr('cbi-validate', true).on('validate', evdata, this._ev_validate);
+ elem.addClass('luci2-field-validate')
+ .on('validate', evdata, this.handleValidate);
return elem;
},
@@ -5256,7 +5277,7 @@ function LuCI2()
{
var i = this.instance[sid];
- i.widget.find('[cbi-validate]').trigger('validate');
+ i.widget.find('.luci2-field-validate').trigger('validate');
return (i.disabled || i.error.text() == '');
},
@@ -5296,7 +5317,7 @@ function LuCI2()
for (var field in dep)
{
- var f = this.section.fields[field];
+ var f = this.ownerSection.fields[field];
if (f)
f.rdependency[this.name] = this;
else
@@ -5329,7 +5350,7 @@ function LuCI2()
for (var field in d[n])
{
- var val = this.section.fields[field].formvalue(sid);
+ var val = this.ownerSection.fields[field].formvalue(sid);
var cmp = d[n][field];
if (typeof(cmp) == 'boolean')
@@ -5371,6 +5392,7 @@ function LuCI2()
if (i.disabled)
{
i.disabled = false;
+ i.top.removeClass('luci2-field-disabled');
i.top.fadeIn();
}
@@ -5382,6 +5404,7 @@ function LuCI2()
{
i.disabled = true;
i.top.is(':visible') ? i.top.fadeOut() : i.top.hide();
+ i.top.addClass('luci2-field-disabled');
}
return false;
@@ -5403,7 +5426,7 @@ function LuCI2()
return $('<div />')
.addClass('checkbox')
- .append(this.validator(sid, i));
+ .append(this.attachEvents(sid, i));
},
ucivalue: function(sid)
@@ -5433,7 +5456,7 @@ function LuCI2()
if (this.instance[sid].disabled)
{
if (!this.options.keep)
- return this.map.set(uci.config, uci.section, uci.option, undefined);
+ return this.ownerMap.set(uci.config, uci.section, uci.option, undefined);
return false;
}
@@ -5444,9 +5467,9 @@ function LuCI2()
if (chg)
{
if (this.options.optional && val == this.options.initial)
- this.map.set(uci.config, uci.section, uci.option, undefined);
+ this.ownerMap.set(uci.config, uci.section, uci.option, undefined);
else
- this.map.set(uci.config, uci.section, uci.option, val ? this.options.enabled : this.options.disabled);
+ this.ownerMap.set(uci.config, uci.section, uci.option, val ? this.options.enabled : this.options.disabled);
}
return chg;
@@ -5463,7 +5486,7 @@ function LuCI2()
.attr('placeholder', this.options.placeholder)
.val(this.ucivalue(sid));
- return this.validator(sid, i);
+ return this.attachEvents(sid, i);
}
});
@@ -5489,7 +5512,7 @@ function LuCI2()
b = i = t = null;
}));
- this.validator(sid, i);
+ this.attachEvents(sid, i);
return $('<div />')
.addClass('input-group')
@@ -5519,7 +5542,7 @@ function LuCI2()
s.attr('id', this.id(sid)).val(this.ucivalue(sid));
- return this.validator(sid, s);
+ return this.attachEvents(sid, s);
},
value: function(k, v)
@@ -5697,8 +5720,8 @@ function LuCI2()
t.val(this.ucivalue(sid));
t.blur();
- this.validator(sid, t);
- this.validator(sid, s);
+ this.attachEvents(sid, t);
+ this.attachEvents(sid, s);
return d;
},
@@ -5781,8 +5804,8 @@ function LuCI2()
.append(btn))
.appendTo(s.parent);
- evdata.input = this.validator(s.sid, txt, true);
- evdata.select = this.validator(s.sid, sel, true);
+ evdata.input = this.attachEvents(s.sid, txt);
+ evdata.select = this.attachEvents(s.sid, sel);
sel.change(evdata, this._change);
txt.blur(evdata, this._blur);
@@ -5829,7 +5852,7 @@ function LuCI2()
f.val(val);
}
- evdata.input = this.validator(s.sid, f, true);
+ evdata.input = this.attachEvents(s.sid, f);
f = null;
}
@@ -6008,7 +6031,7 @@ function LuCI2()
.attr('type', 'button')
.text(this.label('text'));
- return this.validator(sid, btn);
+ return this.attachEvents(sid, btn);
}
});
@@ -6051,11 +6074,11 @@ function LuCI2()
$('<li />')
.append($('<label />')
.addClass(itype + ' inline')
- .append(this.validator(sid, $('<input />')
+ .append(this.attachEvents(sid, $('<input />')
.attr('name', itype + id)
.attr('type', itype)
.attr('value', iface.name())
- .prop('checked', !!check[iface.name()]), true))
+ .prop('checked', !!check[iface.name()])))
.append(iface.renderBadge()))
.appendTo(ul);
}
@@ -6065,11 +6088,11 @@ function LuCI2()
$('<li />')
.append($('<label />')
.addClass(itype + ' inline text-muted')
- .append(this.validator(sid, $('<input />')
+ .append(this.attachEvents(sid, $('<input />')
.attr('name', itype + id)
.attr('type', itype)
.attr('value', '')
- .prop('checked', $.isEmptyObject(check)), true))
+ .prop('checked', $.isEmptyObject(check))))
.append(L.tr('unspecified')))
.appendTo(ul);
}
@@ -6128,7 +6151,7 @@ function LuCI2()
});
this.cbi.DeviceList = this.cbi.NetworkList.extend({
- _ev_focus: function(ev)
+ handleFocus: function(ev)
{
var self = ev.data.self;
var input = $(this);
@@ -6136,13 +6159,13 @@ function LuCI2()
input.parent().prev().prop('checked', true);
},
- _ev_blur: function(ev)
+ handleBlur: function(ev)
{
ev.which = 10;
- ev.data.self._ev_keydown.call(this, ev);
+ ev.data.self.handleKeydown.call(this, ev);
},
- _ev_keydown: function(ev)
+ handleKeydown: function(ev)
{
if (ev.which != 10 && ev.which != 13)
return;
@@ -6240,9 +6263,9 @@ function LuCI2()
.attr('id', 'custom' + id)
.attr('type', 'text')
.attr('placeholder', L.tr('Custom device …'))
- .on('focus', { self: this, sid: sid }, this._ev_focus)
- .on('blur', { self: this, sid: sid }, this._ev_blur)
- .on('keydown', { self: this, sid: sid }, this._ev_keydown))))
+ .on('focus', { self: this, sid: sid }, this.handleFocus)
+ .on('blur', { self: this, sid: sid }, this.handleBlur)
+ .on('keydown', { self: this, sid: sid }, this.handleKeydown))))
.appendTo(ul);
if (!this.options.multiple)
@@ -6293,9 +6316,9 @@ function LuCI2()
this.cbi.AbstractSection = this.ui.AbstractWidget.extend({
id: function()
{
- var s = [ arguments[0], this.map.uci_package, this.uci_type ];
+ var s = [ arguments[0], this.ownerMap.uci_package, this.uci_type ];
- for (var i = 1; i < arguments.length; i++)
+ for (var i = 1; i < arguments.length && typeof(arguments[i]) == 'string'; i++)
s.push(arguments[i].replace(/\./g, '_'));
return s.join('_');
@@ -6343,8 +6366,8 @@ function LuCI2()
if (!(w instanceof L.cbi.AbstractValue))
throw 'Widget must be an instance of AbstractValue';
- w.section = this;
- w.map = this.map;
+ w.ownerSection = this;
+ w.ownerMap = this.ownerMap;
this.fields[name] = w;
tab.fields.push(w);
@@ -6376,92 +6399,146 @@ function LuCI2()
}
},
- ucipackages: function(pkg)
+ validate: function(parent_sid)
{
- for (var i = 0; i < this.tabs.length; i++)
- for (var j = 0; j < this.tabs[i].fields.length; j++)
- if (this.tabs[i].fields[j].options.uci_package)
- pkg[this.tabs[i].fields[j].options.uci_package] = true;
+ var s = this.getUCISections(parent_sid);
+ var n = 0;
+
+ for (var i = 0; i < s.length; i++)
+ {
+ var $item = $('#' + this.id('sectionitem', s[i]['.name']));
+
+ $item.find('.luci2-field-validate').trigger('validate');
+ n += $item.find('.luci2-field.luci2-form-error').not('.luci2-field-disabled').length;
+ }
+
+ return (n == 0);
},
- formvalue: function()
+ load: function(parent_sid)
{
- var rv = { };
+ var deferreds = [ ];
- this.sections(function(s) {
- var sid = s['.name'];
- var sv = rv[sid] || (rv[sid] = { });
+ var s = this.getUCISections(parent_sid);
+ for (var i = 0; i < s.length; i++)
+ {
+ for (var f in this.fields)
+ {
+ if (typeof(this.fields[f].load) != 'function')
+ continue;
+
+ var rv = this.fields[f].load(s[i]['.name']);
+ if (L.isDeferred(rv))
+ deferreds.push(rv);
+ }
+
+ for (var j = 0; j < this.subsections.length; j++)
+ {
+ var rv = this.subsections[j].load(s[i]['.name']);
+ deferreds.push.apply(deferreds, rv);
+ }
+ }
+
+ return deferreds;
+ },
+
+ save: function(parent_sid)
+ {
+ var deferreds = [ ];
+ var s = this.getUCISections(parent_sid);
- for (var i = 0; i < this.tabs.length; i++)
- for (var j = 0; j < this.tabs[i].fields.length; j++)
+ for (i = 0; i < s.length; i++)
+ {
+ if (!this.options.readonly)
+ {
+ for (var f in this.fields)
{
- var val = this.tabs[i].fields[j].formvalue(sid);
- sv[this.tabs[i].fields[j].name] = val;
+ if (typeof(this.fields[f].save) != 'function')
+ continue;
+
+ var rv = this.fields[f].save(s[i]['.name']);
+ if (L.isDeferred(rv))
+ deferreds.push(rv);
}
- });
+ }
- return rv;
+ for (var j = 0; j < this.subsections.length; j++)
+ {
+ var rv = this.subsections[j].save(s[i]['.name']);
+ deferreds.push.apply(deferreds, rv);
+ }
+ }
+
+ return deferreds;
},
- validate_section: function(sid)
+ teaser: function(sid)
{
- var inst = this.instance[sid];
+ var tf = this.teaser_fields;
- var invals = 0;
- var badge = $('#' + this.id('teaser', sid)).children('span:first');
+ if (!tf)
+ {
+ tf = this.teaser_fields = [ ];
- for (var i = 0; i < this.tabs.length; i++)
+ if ($.isArray(this.options.teasers))
+ {
+ for (var i = 0; i < this.options.teasers.length; i++)
+ {
+ var f = this.options.teasers[i];
+ if (f instanceof L.cbi.AbstractValue)
+ tf.push(f);
+ else if (typeof(f) == 'string' && this.fields[f] instanceof L.cbi.AbstractValue)
+ tf.push(this.fields[f]);
+ }
+ }
+ else
+ {
+ for (var i = 0; tf.length <= 5 && i < this.tabs.length; i++)
+ for (var j = 0; tf.length <= 5 && j < this.tabs[i].fields.length; j++)
+ tf.push(this.tabs[i].fields[j]);
+ }
+ }
+
+ var t = '';
+
+ for (var i = 0; i < tf.length; i++)
{
- var inval = 0;
- var stbadge = $('#' + this.id('nodetab', sid, this.tabs[i].id)).children('span:first');
+ if (tf[i].instance[sid] && tf[i].instance[sid].disabled)
+ continue;
- for (var j = 0; j < this.tabs[i].fields.length; j++)
- if (!this.tabs[i].fields[j].validate(sid))
- inval++;
+ var n = tf[i].options.caption || tf[i].name;
+ var v = tf[i].textvalue(sid);
- if (inval > 0)
- stbadge.show()
- .text(inval)
- .attr('title', L.trp('1 Error', '%d Errors', inval).format(inval));
- else
- stbadge.hide();
+ if (typeof(v) == 'undefined')
+ continue;
- invals += inval;
+ t = t + '%s%s: <strong>%s</strong>'.format(t ? ' | ' : '', n, v);
}
- if (invals > 0)
- badge.show()
- .text(invals)
- .attr('title', L.trp('1 Error', '%d Errors', invals).format(invals));
- else
- badge.hide();
-
- return invals;
+ return t;
},
- validate: function()
+ findAdditionalUCIPackages: function()
{
- var errors = 0;
- var as = this.sections();
+ var packages = [ ];
- for (var i = 0; i < as.length; i++)
- {
- var invals = this.validate_section(as[i]['.name']);
+ for (var i = 0; i < this.tabs.length; i++)
+ for (var j = 0; j < this.tabs[i].fields.length; j++)
+ if (this.tabs[i].fields[j].options.uci_package)
+ packages.push(this.tabs[i].fields[j].options.uci_package);
- if (invals > 0)
- errors += invals;
- }
+ return packages;
+ },
- var badge = $('#' + this.id('sectiontab')).children('span:first');
+ findParentSectionIDs: function($elem)
+ {
+ var rv = [ ];
+ var $parents = $elem.parents('.luci2-section-item');
- if (errors > 0)
- badge.show()
- .text(errors)
- .attr('title', L.trp('1 Error', '%d Errors', errors).format(errors));
- else
- badge.hide();
+ for (var i = 0; i < $parents.length; i++)
+ rv.push($parents[i].getAttribute('data-luci2-sid'));
- return (errors == 0);
+ return rv;
}
});
@@ -6472,11 +6549,14 @@ function LuCI2()
this.options = options;
this.tabs = [ ];
this.fields = { };
- this.active_panel = 0;
+ this.subsections = [ ];
+ this.active_panel = { };
this.active_tab = { };
+
+ this.instance = { };
},
- filter: function(section)
+ filter: function(section, parent_sid)
{
return true;
},
@@ -6486,40 +6566,52 @@ function LuCI2()
return 0;
},
- sections: function(cb)
+ subsection: function(widget, uci_type, options)
+ {
+ var w = widget ? new widget(uci_type, options) : null;
+
+ if (!(w instanceof L.cbi.AbstractSection))
+ throw 'Widget must be an instance of AbstractSection';
+
+ w.ownerSection = this;
+ w.ownerMap = this.ownerMap;
+ w.index = this.subsections.length;
+
+ this.subsections.push(w);
+ return w;
+ },
+
+ getUCISections: function(parent_sid)
{
- var s1 = L.uci.sections(this.map.uci_package);
+ var s1 = L.uci.sections(this.ownerMap.uci_package);
var s2 = [ ];
for (var i = 0; i < s1.length; i++)
if (s1[i]['.type'] == this.uci_type)
- if (this.filter(s1[i]))
+ if (this.filter(s1[i], parent_sid))
s2.push(s1[i]);
s2.sort(this.sort);
- if (typeof(cb) == 'function')
- for (var i = 0; i < s2.length; i++)
- cb.call(this, s2[i]);
-
return s2;
},
- add: function(name)
+ add: function(name, parent_sid)
{
- return this.map.add(this.map.uci_package, this.uci_type, name);
+ return this.ownerMap.add(this.ownerMap.uci_package, this.uci_type, name);
},
- remove: function(sid)
+ remove: function(sid, parent_sid)
{
- return this.map.remove(this.map.uci_package, sid);
+ return this.ownerMap.remove(this.ownerMap.uci_package, sid);
},
- _ev_add: function(ev)
+ handleAdd: function(ev)
{
var addb = $(this);
var name = undefined;
var self = ev.data.self;
+ var sid = self.findParentSectionIDs(addb)[0];
if (addb.prev().prop('nodeName') == 'INPUT')
name = addb.prev().val();
@@ -6529,39 +6621,45 @@ function LuCI2()
L.ui.saveScrollTop();
- self.active_panel = -1;
- self.map.save();
+ self.setPanelIndex(sid, -1);
+ self.ownerMap.save();
- ev.data.sid = self.add(name);
+ ev.data.sid = self.add(name, sid);
ev.data.type = self.uci_type;
ev.data.name = name;
self.trigger('add', ev);
- self.map.redraw();
+ self.ownerMap.redraw();
L.ui.restoreScrollTop();
},
- _ev_remove: function(ev)
+ handleRemove: function(ev)
{
var self = ev.data.self;
- var sid = ev.data.sid;
+ var sids = self.findParentSectionIDs($(this));
- L.ui.saveScrollTop();
+ if (sids.length)
+ {
+ L.ui.saveScrollTop();
- self.trigger('remove', ev);
+ ev.sid = sids[0];
+ ev.parent_sid = sids[1];
- self.map.save();
- self.remove(sid);
- self.map.redraw();
+ self.trigger('remove', ev);
- L.ui.restoreScrollTop();
+ self.ownerMap.save();
+ self.remove(ev.sid, ev.parent_sid);
+ self.ownerMap.redraw();
+
+ L.ui.restoreScrollTop();
+ }
ev.stopPropagation();
},
- _ev_sid: function(ev)
+ handleSID: function(ev)
{
var self = ev.data.self;
var text = $(this);
@@ -6577,7 +6675,7 @@ function LuCI2()
return false;
}
- if (L.uci.get(self.map.uci_package, name))
+ if (L.uci.get(self.ownerMap.uci_package, name))
{
errt.text(L.tr('Name already used')).show();
text.addClass('error');
@@ -6591,117 +6689,117 @@ function LuCI2()
return true;
},
- _ev_tab: function(ev)
+ handleTab: function(ev)
{
var self = ev.data.self;
- var sid = ev.data.sid;
+ var $tab = $(this);
+ var sid = self.findParentSectionIDs($tab)[0];
+
+ self.active_tab[sid] = $tab.parent().index();
+ },
+
+ handleTabValidate: function(ev)
+ {
+ var $pane = $(ev.delegateTarget);
+ var $badge = $pane.parent()
+ .children('.nav-tabs')
+ .children('li')
+ .eq($pane.index() - 1) // item #1 is the <ul>
+ .find('.badge:first');
+
+ var err_count = $pane.find('.luci2-field.luci2-form-error').not('.luci2-field-disabled').length;
+ if (err_count > 0)
+ $badge
+ .text(err_count)
+ .attr('title', L.trp('1 Error', '%d Errors', err_count).format(err_count))
+ .show();
+ else
+ $badge.hide();
+ },
+
+ handlePanelValidate: function(ev)
+ {
+ var $elem = $(this);
+ var $badge = $elem
+ .prevAll('.luci2-section-header:first')
+ .children('.luci2-section-teaser')
+ .find('.badge:first');
- self.validate();
- self.active_tab[sid] = parseInt(ev.target.getAttribute('data-luci2-tab-index'));
+ var err_count = $elem.find('.luci2-field.luci2-form-error').not('.luci2-field-disabled').length;
+ if (err_count > 0)
+ $badge
+ .text(err_count)
+ .attr('title', L.trp('1 Error', '%d Errors', err_count).format(err_count))
+ .show();
+ else
+ $badge.hide();
},
- _ev_panel_collapse: function(ev)
+ handlePanelCollapse: function(ev)
{
var self = ev.data.self;
- var this_panel = $(ev.target);
- var this_toggle = this_panel.prevAll('[data-toggle="collapse"]:first');
+ var $items = $(ev.delegateTarget).children('.luci2-section-item');
+
+ var $this_panel = $(ev.target);
+ var $this_teaser = $this_panel.prevAll('.luci2-section-header:first').children('.luci2-section-teaser');
+
+ var $prev_panel = $items.children('.luci2-section-panel.in');
+ var $prev_teaser = $prev_panel.prevAll('.luci2-section-header:first').children('.luci2-section-teaser');
+
+ var sids = self.findParentSectionIDs($prev_panel);
- var prev_toggle = $($(ev.delegateTarget).find('[data-toggle="collapse"]:eq(%d)'.format(self.active_panel)));
- var prev_panel = $(prev_toggle.attr('data-target'));
+ self.setPanelIndex(sids[1], $this_panel.parent().index());
- prev_panel
+ $prev_panel
.removeClass('in')
.addClass('collapse');
- prev_toggle.find('.luci2-section-teaser')
+ $prev_teaser
.show()
.children('span:last')
.empty()
- .append(self.teaser(prev_panel.attr('data-luci2-sid')));
+ .append(self.teaser(sids[0]));
- this_toggle.find('.luci2-section-teaser')
+ $this_teaser
.hide();
- self.active_panel = parseInt(this_panel.attr('data-luci2-panel-index'));
- self.validate();
+ ev.stopPropagation();
},
- _ev_panel_open: function(ev)
+ handleSort: function(ev)
{
- var self = ev.data.self;
- var panel = $($(this).attr('data-target'));
- var index = parseInt(panel.attr('data-luci2-panel-index'));
-
- if (index == self.active_panel)
- ev.stopPropagation();
- },
+ var self = ev.data.self;
- _ev_sort: function(ev)
- {
- var self = ev.data.self;
- var cur_idx = ev.data.index;
- var new_idx = cur_idx + (ev.data.up ? -1 : 1);
- var s = self.sections();
+ var $item = $(this).parents('.luci2-section-item:first');
+ var $next = ev.data.up ? $item.prev() : $item.next();
- if (new_idx >= 0 && new_idx < s.length)
+ if ($item.length && $next.length)
{
- L.uci.swap(self.map.uci_package, s[cur_idx]['.name'], s[new_idx]['.name']);
+ var cur_sid = $item.attr('data-luci2-sid');
+ var new_sid = $next.attr('data-luci2-sid');
+
+ L.uci.swap(self.ownerMap.uci_package, cur_sid, new_sid);
- self.map.save();
- self.map.redraw();
+ self.ownerMap.save();
+ self.ownerMap.redraw();
}
ev.stopPropagation();
},
- teaser: function(sid)
+ getPanelIndex: function(parent_sid)
{
- var tf = this.teaser_fields;
-
- if (!tf)
- {
- tf = this.teaser_fields = [ ];
-
- if ($.isArray(this.options.teasers))
- {
- for (var i = 0; i < this.options.teasers.length; i++)
- {
- var f = this.options.teasers[i];
- if (f instanceof L.cbi.AbstractValue)
- tf.push(f);
- else if (typeof(f) == 'string' && this.fields[f] instanceof L.cbi.AbstractValue)
- tf.push(this.fields[f]);
- }
- }
- else
- {
- for (var i = 0; tf.length <= 5 && i < this.tabs.length; i++)
- for (var j = 0; tf.length <= 5 && j < this.tabs[i].fields.length; j++)
- tf.push(this.tabs[i].fields[j]);
- }
- }
-
- var t = '';
-
- for (var i = 0; i < tf.length; i++)
- {
- if (tf[i].instance[sid] && tf[i].instance[sid].disabled)
- continue;
-
- var n = tf[i].options.caption || tf[i].name;
- var v = tf[i].textvalue(sid);
-
- if (typeof(v) == 'undefined')
- continue;
-
- t = t + '%s%s: <strong>%s</strong>'.format(t ? ' | ' : '', n, v);
- }
+ return (this.active_panel[parent_sid || '__top__'] || 0);
+ },
- return t;
+ setPanelIndex: function(parent_sid, new_index)
+ {
+ if (typeof(new_index) == 'number')
+ this.active_panel[parent_sid || '__top__'] = new_index;
},
- _render_add: function()
+ renderAdd: function()
{
if (!this.options.addremove)
return null;
@@ -6722,15 +6820,15 @@ function LuCI2()
.addClass('cbi-input-text')
.attr('type', 'text')
.attr('placeholder', ttip)
- .blur({ self: this }, this._ev_sid)
- .keyup({ self: this }, this._ev_sid)
+ .blur({ self: this }, this.handleSID)
+ .keyup({ self: this }, this.handleSID)
.appendTo(add);
$('<img />')
.attr('src', L.globals.resource + '/icons/cbi/add.gif')
.attr('title', text)
.addClass('cbi-button')
- .click({ self: this }, this._ev_add)
+ .click({ self: this }, this.handleAdd)
.appendTo(add);
$('<div />')
@@ -6741,14 +6839,14 @@ function LuCI2()
else
{
L.ui.button(text, 'success', ttip)
- .click({ self: this }, this._ev_add)
+ .click({ self: this }, this.handleAdd)
.appendTo(add);
}
return add;
},
- _render_remove: function(sid, index)
+ renderRemove: function(index)
{
if (!this.options.addremove)
return null;
@@ -6762,31 +6860,31 @@ function LuCI2()
text = this.options.remove_caption, ttip = '';
return L.ui.button(text, 'danger', ttip)
- .click({ self: this, sid: sid, index: index }, this._ev_remove);
+ .click({ self: this, index: index }, this.handleRemove);
},
- _render_sort: function(sid, index)
+ renderSort: function(index)
{
if (!this.options.sortable)
return null;
var b1 = L.ui.button('↑', 'info', L.tr('Move up'))
- .click({ self: this, index: index, up: true }, this._ev_sort);
+ .click({ self: this, index: index, up: true }, this.handleSort);
var b2 = L.ui.button('↓', 'info', L.tr('Move down'))
- .click({ self: this, index: index, up: false }, this._ev_sort);
+ .click({ self: this, index: index, up: false }, this.handleSort);
return b1.add(b2);
},
- _render_caption: function()
+ renderCaption: function()
{
return $('<h3 />')
.addClass('panel-title')
.append(this.label('caption') || this.uci_type);
},
- _render_description: function()
+ renderDescription: function()
{
var text = this.label('description');
@@ -6798,9 +6896,9 @@ function LuCI2()
return null;
},
- _render_teaser: function(sid, index)
+ renderTeaser: function(sid, index)
{
- if (this.options.collabsible || this.map.options.collabsible)
+ if (this.options.collabsible || this.ownerMap.options.collabsible)
{
return $('<div />')
.attr('id', this.id('teaser', sid))
@@ -6813,18 +6911,18 @@ function LuCI2()
return null;
},
- _render_head: function(condensed)
+ renderHead: function(condensed)
{
if (condensed)
return null;
return $('<div />')
.addClass('panel-heading')
- .append(this._render_caption())
- .append(this._render_description());
+ .append(this.renderCaption())
+ .append(this.renderDescription());
},
- _render_tab_description: function(sid, index, tab_index)
+ renderTabDescription: function(sid, index, tab_index)
{
var tab = this.tabs[tab_index];
@@ -6838,7 +6936,7 @@ function LuCI2()
return null;
},
- _render_tab_head: function(sid, index, tab_index)
+ renderTabHead: function(sid, index, tab_index)
{
var tab = this.tabs[tab_index];
var cur = this.active_tab[sid] || 0;
@@ -6848,11 +6946,10 @@ function LuCI2()
.attr('id', this.id('nodetab', sid, tab.id))
.attr('href', '#' + this.id('node', sid, tab.id))
.attr('data-toggle', 'tab')
- .attr('data-luci2-tab-index', tab_index)
.text((tab.caption ? tab.caption.format(tab.id) : tab.id) + ' ')
.append($('<span />')
.addClass('badge'))
- .on('shown.bs.tab', { self: this, sid: sid }, this._ev_tab));
+ .on('shown.bs.tab', { self: this, sid: sid }, this.handleTab));
if (cur == tab_index)
tabh.addClass('active');
@@ -6863,7 +6960,7 @@ function LuCI2()
return tabh;
},
- _render_tab_body: function(sid, index, tab_index)
+ renderTabBody: function(sid, index, tab_index)
{
var tab = this.tabs[tab_index];
var cur = this.active_tab[sid] || 0;
@@ -6871,8 +6968,8 @@ function LuCI2()
var tabb = $('<div />')
.addClass('tab-pane')
.attr('id', this.id('node', sid, tab.id))
- .attr('data-luci2-tab-index', tab_index)
- .append(this._render_tab_description(sid, index, tab_index));
+ .append(this.renderTabDescription(sid, index, tab_index))
+ .on('validate', this.handleTabValidate);
if (cur == tab_index)
tabb.addClass('active');
@@ -6883,39 +6980,38 @@ function LuCI2()
return tabb;
},
- _render_section_head: function(sid, index)
+ renderPanelHead: function(sid, index, parent_sid)
{
var head = $('<div />')
.addClass('luci2-section-header')
- .append(this._render_teaser(sid, index))
+ .append(this.renderTeaser(sid, index))
.append($('<div />')
.addClass('btn-group')
- .append(this._render_sort(sid, index))
- .append(this._render_remove(sid, index)));
+ .append(this.renderSort(index))
+ .append(this.renderRemove(index)));
if (this.options.collabsible)
{
head.attr('data-toggle', 'collapse')
- .attr('data-parent', this.id('sectiongroup'))
- .attr('data-target', '#' + this.id('panel', sid))
- .on('click', { self: this }, this._ev_panel_open);
+ .attr('data-parent', this.id('sectiongroup', parent_sid))
+ .attr('data-target', '#' + this.id('panel', sid));
}
return head;
},
- _render_section_body: function(sid, index)
+ renderPanelBody: function(sid, index, parent_sid)
{
var body = $('<div />')
.attr('id', this.id('panel', sid))
- .attr('data-luci2-panel-index', index)
- .attr('data-luci2-sid', sid);
+ .addClass('luci2-section-panel')
+ .on('validate', this.handlePanelValidate);
- if (this.options.collabsible || this.map.options.collabsible)
+ if (this.options.collabsible || this.ownerMap.options.collabsible)
{
body.addClass('panel-collapse collapse');
- if (index == this.active_panel)
+ if (index == this.getPanelIndex(parent_sid))
body.addClass('in');
}
@@ -6928,8 +7024,8 @@ function LuCI2()
for (var j = 0; j < this.tabs.length; j++)
{
- tab_heads.append(this._render_tab_head(sid, index, j));
- tab_bodies.append(this._render_tab_body(sid, index, j));
+ tab_heads.append(this.renderTabHead(sid, index, j));
+ tab_bodies.append(this.renderTabBody(sid, index, j));
}
body.append(tab_bodies);
@@ -6937,25 +7033,29 @@ function LuCI2()
if (this.tabs.length <= 1)
tab_heads.hide();
+ for (var i = 0; i < this.subsections.length; i++)
+ body.append(this.subsections[i].render(false, sid));
+
return body;
},
- _render_body: function(condensed)
+ renderBody: function(condensed, parent_sid)
{
- var s = this.sections();
+ var s = this.getUCISections(parent_sid);
+ var n = this.getPanelIndex(parent_sid);
- if (this.active_panel < 0)
- this.active_panel += s.length;
- else if (this.active_panel >= s.length)
- this.active_panel = s.length - 1;
+ if (n < 0)
+ this.setPanelIndex(parent_sid, n + s.length);
+ else if (n >= s.length)
+ this.setPanelIndex(parent_sid, s.length - 1);
var body = $('<ul />')
- .addClass('list-group');
+ .addClass('luci2-section-group list-group');
if (this.options.collabsible)
{
- body.attr('id', this.id('sectiongroup'))
- .on('show.bs.collapse', { self: this }, this._ev_panel_collapse);
+ body.attr('id', this.id('sectiongroup', parent_sid))
+ .on('show.bs.collapse', { self: this }, this.handlePanelCollapse);
}
if (s.length == 0)
@@ -6971,53 +7071,56 @@ function LuCI2()
var inst = this.instance[sid] = { tabs: [ ] };
body.append($('<li />')
- .addClass('list-group-item')
- .append(this._render_section_head(sid, i))
- .append(this._render_section_body(sid, i)));
+ .addClass('luci2-section-item list-group-item')
+ .attr('id', this.id('sectionitem', sid))
+ .attr('data-luci2-sid', sid)
+ .append(this.renderPanelHead(sid, i, parent_sid))
+ .append(this.renderPanelBody(sid, i, parent_sid)));
}
return body;
},
- render: function(condensed)
+ render: function(condensed, parent_sid)
{
this.instance = { };
var panel = $('<div />')
.addClass('panel panel-default')
- .append(this._render_head(condensed))
- .append(this._render_body(condensed));
+ .append(this.renderHead(condensed))
+ .append(this.renderBody(condensed, parent_sid));
if (this.options.addremove)
panel.append($('<div />')
.addClass('panel-footer')
- .append(this._render_add()));
+ .append(this.renderAdd()));
return panel;
},
- finish: function()
+ finish: function(parent_sid)
{
- var s = this.sections();
+ var s = this.getUCISections(parent_sid);
for (var i = 0; i < s.length; i++)
{
var sid = s[i]['.name'];
- this.validate_section(sid);
-
- if (i != this.active_panel)
+ if (i != this.getPanelIndex(parent_sid))
$('#' + this.id('teaser', sid)).children('span:last')
.append(this.teaser(sid));
else
$('#' + this.id('teaser', sid))
.hide();
+
+ for (var j = 0; j < this.subsections.length; j++)
+ this.subsections[j].finish(sid);
}
}
});
this.cbi.TableSection = this.cbi.TypedSection.extend({
- _render_table_head: function()
+ renderTableHead: function()
{
var thead = $('<thead />')
.append($('<tr />')
@@ -7037,9 +7140,11 @@ function LuCI2()
return thead;
},
- _render_table_row: function(sid, index)
+ renderTableRow: function(sid, index)
{
var row = $('<tr />')
+ .addClass('luci2-section-item')
+ .attr('id', this.id('sectionitem', sid))
.attr('data-luci2-sid', sid);
for (var j = 0; j < this.tabs[0].fields.length; j++)
@@ -7056,16 +7161,16 @@ function LuCI2()
.addClass('text-right')
.append($('<div />')
.addClass('btn-group')
- .append(this._render_sort(sid, index))
- .append(this._render_remove(sid, index))));
+ .append(this.renderSort(index))
+ .append(this.renderRemove(index))));
}
return row;
},
- _render_table_body: function()
+ renderTableBody: function(parent_sid)
{
- var s = this.sections();
+ var s = this.getUCISections(parent_sid);
var tbody = $('<tbody />');
@@ -7088,26 +7193,26 @@ function LuCI2()
var sid = s[i]['.name'];
var inst = this.instance[sid] = { tabs: [ ] };
- tbody.append(this._render_table_row(sid, i));
+ tbody.append(this.renderTableRow(sid, i));
}
return tbody;
},
- _render_body: function(condensed)
+ renderBody: function(condensed, parent_sid)
{
return $('<table />')
.addClass('table table-condensed table-hover')
- .append(this._render_table_head())
- .append(this._render_table_body());
+ .append(this.renderTableHead())
+ .append(this.renderTableBody(parent_sid));
}
});
this.cbi.NamedSection = this.cbi.TypedSection.extend({
- sections: function(cb)
+ getUCISections: function(cb)
{
var sa = [ ];
- var sl = L.uci.sections(this.map.uci_package);
+ var sl = L.uci.sections(this.ownerMap.uci_package);
for (var i = 0; i < sl.length; i++)
if (sl[i]['.name'] == this.uci_type)
@@ -7129,12 +7234,16 @@ function LuCI2()
this.instance = { };
this.instance[this.uci_type] = { tabs: [ ] };
- return this._render_section_body(this.uci_type, 0);
+ return $('<div />')
+ .addClass('luci2-section-item')
+ .attr('id', this.id('sectionitem', this.uci_type))
+ .attr('data-luci2-sid', this.uci_type)
+ .append(this.renderPanelBody(this.uci_type, 0));
}
});
this.cbi.DummySection = this.cbi.TypedSection.extend({
- sections: function(cb)
+ getUCISections: function(cb)
{
if (typeof(cb) == 'function')
cb.apply(this, [ { '.name': this.uci_type } ]);
@@ -7156,25 +7265,14 @@ function LuCI2()
});
},
- _load_cb: function()
+ loadCallback: function()
{
var deferreds = [ L.deferrable(this.options.prepare()) ];
for (var i = 0; i < this.sections.length; i++)
{
- for (var f in this.sections[i].fields)
- {
- if (typeof(this.sections[i].fields[f].load) != 'function')
- continue;
-
- var s = this.sections[i].sections();
- for (var j = 0; j < s.length; j++)
- {
- var rv = this.sections[i].fields[f].load(s[j]['.name']);
- if (L.isDeferred(rv))
- deferreds.push(rv);
- }
- }
+ var rv = this.sections[i].load();
+ deferreds.push.apply(deferreds, rv);
}
return $.when.apply($, deferreds);
@@ -7183,38 +7281,36 @@ function LuCI2()
load: function()
{
var self = this;
- var packages = { };
+ var packages = [ this.uci_package ];
for (var i = 0; i < this.sections.length; i++)
- this.sections[i].ucipackages(packages);
-
- packages[this.uci_package] = true;
+ packages.push.apply(packages, this.sections[i].findAdditionalUCIPackages());
- for (var pkg in packages)
- if (!L.uci.writable(pkg))
+ for (var i = 0; i < packages.length; i++)
+ if (!L.uci.writable(packages[i]))
+ {
this.options.readonly = true;
+ break;
+ }
- return L.uci.load(L.toArray(packages)).then(function() {
- return self._load_cb();
+ return L.uci.load(packages).then(function() {
+ return self.loadCallback();
});
},
- _ev_tab: function(ev)
+ handleTab: function(ev)
{
- var self = ev.data.self;
-
- self.validate();
- self.active_tab = parseInt(ev.target.getAttribute('data-luci2-tab-index'));
+ ev.data.self.active_tab = $(ev.target).parent().index();
},
- _ev_apply: function(ev)
+ handleApply: function(ev)
{
var self = ev.data.self;
self.trigger('apply', ev);
},
- _ev_save: function(ev)
+ handleSave: function(ev)
{
var self = ev.data.self;
@@ -7223,7 +7319,7 @@ function LuCI2()
});
},
- _ev_reset: function(ev)
+ handleReset: function(ev)
{
var self = ev.data.self;
@@ -7231,7 +7327,7 @@ function LuCI2()
self.reset();
},
- _render_tab_head: function(tab_index)
+ renderTabHead: function(tab_index)
{
var section = this.sections[tab_index];
var cur = this.active_tab || 0;
@@ -7241,11 +7337,10 @@ function LuCI2()
.attr('id', section.id('sectiontab'))
.attr('href', '#' + section.id('section'))
.attr('data-toggle', 'tab')
- .attr('data-luci2-tab-index', tab_index)
.text(section.label('caption') + ' ')
.append($('<span />')
.addClass('badge'))
- .on('shown.bs.tab', { self: this }, this._ev_tab));
+ .on('shown.bs.tab', { self: this }, this.handleTab));
if (cur == tab_index)
tabh.addClass('active');
@@ -7253,7 +7348,7 @@ function LuCI2()
return tabh;
},
- _render_tab_body: function(tab_index)
+ renderTabBody: function(tab_index)
{
var section = this.sections[tab_index];
var desc = section.label('description');
@@ -7261,8 +7356,7 @@ function LuCI2()
var tabb = $('<div />')
.addClass('tab-pane')
- .attr('id', section.id('section'))
- .attr('data-luci2-tab-index', tab_index);
+ .attr('id', section.id('section'));
if (cur == tab_index)
tabb.addClass('active');
@@ -7281,7 +7375,7 @@ function LuCI2()
return tabb;
},
- _render_body: function()
+ renderBody: function()
{
var tabs = $('<ul />')
.addClass('nav nav-tabs');
@@ -7291,8 +7385,8 @@ function LuCI2()
for (var i = 0; i < this.sections.length; i++)
{
- tabs.append(this._render_tab_head(i));
- body.append(this._render_tab_body(i));
+ tabs.append(this.renderTabHead(i));
+ body.append(this.renderTabBody(i));
}
if (this.options.tabbed)
@@ -7303,7 +7397,7 @@ function LuCI2()
return body;
},
- _render_footer: function()
+ renderFooter: function()
{
var evdata = {
self: this
@@ -7314,11 +7408,11 @@ function LuCI2()
.append($('<div />')
.addClass('btn-group')
.append(L.ui.button(L.tr('Save & Apply'), 'primary')
- .click(evdata, this._ev_apply))
+ .click(evdata, this.handleApply))
.append(L.ui.button(L.tr('Save'), 'default')
- .click(evdata, this._ev_save))
+ .click(evdata, this.handleSave))
.append(L.ui.button(L.tr('Reset'), 'default')
- .click(evdata, this._ev_reset)));
+ .click(evdata, this.handleReset)));
},
render: function()
@@ -7333,10 +7427,10 @@ function LuCI2()
map.append($('<p />')
.text(this.options.description));
- map.append(this._render_body());
+ map.append(this.renderBody());
if (this.options.pageaction !== false)
- map.append(this._render_footer());
+ map.append(this.renderFooter());
return map;
},
@@ -7363,30 +7457,13 @@ function LuCI2()
if (!(w instanceof L.cbi.AbstractSection))
throw 'Widget must be an instance of AbstractSection';
- w.map = this;
+ w.ownerMap = this;
w.index = this.sections.length;
this.sections.push(w);
return w;
},
- formvalue: function()
- {
- var rv = { };
-
- for (var i = 0; i < this.sections.length; i++)
- {
- var sids = this.sections[i].formvalue();
- for (var sid in sids)
- {
- var s = rv[sid] || (rv[sid] = { });
- $.extend(s, sids[sid]);
- }
- }
-
- return rv;
- },
-
add: function(conf, type, name)
{
return L.uci.add(conf, type, name);
@@ -7431,22 +7508,8 @@ function LuCI2()
for (var i = 0; i < self.sections.length; i++)
{
- if (self.sections[i].options.readonly)
- continue;
-
- for (var f in self.sections[i].fields)
- {
- if (typeof(self.sections[i].fields[f].save) != 'function')
- continue;
-
- var s = self.sections[i].sections();
- for (var j = 0; j < s.length; j++)
- {
- var rv = self.sections[i].fields[f].save(s[j]['.name']);
- if (L.isDeferred(rv))
- deferreds.push(rv);
- }
- }
+ var rv = self.sections[i].save();
+ deferreds.push.apply(deferreds, rv);
}
return $.when.apply($, deferreds).then(function() {
@@ -7481,14 +7544,12 @@ function LuCI2()
revert: function()
{
- var packages = { };
+ var packages = [ this.uci_package ];
for (var i = 0; i < this.sections.length; i++)
- this.sections[i].ucipackages(packages);
-
- packages[this.uci_package] = true;
+ packages.push.apply(packages, this.sections[i].findAdditionalUCIPackages());
- L.uci.unload(L.toArray(packages));
+ L.uci.unload(packages);
},
reset: function()
@@ -7519,14 +7580,14 @@ function LuCI2()
});
this.cbi.Modal = this.cbi.Map.extend({
- _ev_apply: function(ev)
+ handleApply: function(ev)
{
var self = ev.data.self;
self.trigger('apply', ev);
},
- _ev_save: function(ev)
+ handleSave: function(ev)
{
var self = ev.data.self;
@@ -7536,7 +7597,7 @@ function LuCI2()
});
},
- _ev_reset: function(ev)
+ handleReset: function(ev)
{
var self = ev.data.self;
@@ -7545,7 +7606,7 @@ function LuCI2()
self.close();
},
- _render_footer: function()
+ renderFooter: function()
{
var evdata = {
self: this
@@ -7554,11 +7615,11 @@ function LuCI2()
return $('<div />')
.addClass('btn-group')
.append(L.ui.button(L.tr('Save & Apply'), 'primary')
- .click(evdata, this._ev_apply))
+ .click(evdata, this.handleApply))
.append(L.ui.button(L.tr('Save'), 'default')
- .click(evdata, this._ev_save))
+ .click(evdata, this.handleSave))
.append(L.ui.button(L.tr('Cancel'), 'default')
- .click(evdata, this._ev_reset));
+ .click(evdata, this.handleReset));
},
render: function()
@@ -7570,10 +7631,10 @@ function LuCI2()
if (desc)
map.append($('<p />').text(desc));
- map.append(this._render_body());
+ map.append(this.renderBody());
modal.find('.modal-body').append(map);
- modal.find('.modal-footer').append(this._render_footer());
+ modal.find('.modal-footer').append(this.renderFooter());
return modal;
},
diff --git a/luci2/htdocs/luci2/proto/6in4.js b/luci2/htdocs/luci2/proto/6in4.js
index 4e5d24f..bb65184 100644
--- a/luci2/htdocs/luci2/proto/6in4.js
+++ b/luci2/htdocs/luci2/proto/6in4.js
@@ -33,7 +33,7 @@ L.NetworkModel.Protocol.extend({
section.taboption('general', L.cbi.InputValue, 'ip6prefix', {
caption: L.tr('IPv6 routed prefix'),
description: L.tr('This is the prefix routed to you by the tunnel broker for use by clients'),
- datatype: 'ip6addr',
+ datatype: 'cidr6',
optional: true
});
@@ -46,7 +46,7 @@ L.NetworkModel.Protocol.extend({
update.save = function(sid) { };
update.ucivalue = function(sid) {
- var n = parseInt(this.map.get('network', sid, 'tunnelid'));
+ var n = parseInt(this.ownerMap.get('network', sid, 'tunnelid'));
return !isNaN(n);
};
diff --git a/luci2/htdocs/luci2/proto/static.js b/luci2/htdocs/luci2/proto/static.js
index afa2d6c..e9b9580 100644
--- a/luci2/htdocs/luci2/proto/static.js
+++ b/luci2/htdocs/luci2/proto/static.js
@@ -9,8 +9,8 @@ L.NetworkModel.Protocol.extend({
var self = ev.data.self;
var sid = ev.data.sid;
- var i = ($('#' + self.section.id('field', sid, 'ipaddr')).val() || '').split(/\./);
- var m = ($('#' + self.section.id('field', sid, 'netmask') + ' select').val() || '').split(/\./);
+ var i = ($('#' + self.ownerSection.id('field', sid, 'ipaddr')).val() || '').split(/\./);
+ var m = ($('#' + self.ownerSection.id('field', sid, 'netmask') + ' select').val() || '').split(/\./);
var I = 0;
var M = 0;
diff --git a/luci2/htdocs/luci2/view/network.interfaces.js b/luci2/htdocs/luci2/view/network.interfaces.js
index a344327..a821ef5 100644
--- a/luci2/htdocs/luci2/view/network.interfaces.js
+++ b/luci2/htdocs/luci2/view/network.interfaces.js
@@ -274,7 +274,7 @@ L.ui.view.extend({
renderInterfaceForm: function(network)
{
- var m = new L.cbi.Modal('network', {
+ var m = new L.cbi.Map('network', {
tabbed: true,
caption: 'Interface config',
description: 'I can config interface!!!!'
diff --git a/luci2/htdocs/luci2/view/network.switch.js b/luci2/htdocs/luci2/view/network.switch.js
index 39a5b0b..057955e 100644
--- a/luci2/htdocs/luci2/view/network.switch.js
+++ b/luci2/htdocs/luci2/view/network.switch.js
@@ -49,7 +49,7 @@ L.ui.view.extend({
if (val == 'u')
{
var u = false;
- var sections = self.section.sections();
+ var sections = self.ownerSection.getUCISections();
for (var i = 0; i < sections.length; i++)
{
@@ -72,7 +72,7 @@ L.ui.view.extend({
ucivalue: function(sid)
{
- var ports = (this.map.get('network', sid, 'ports') || '').match(/[0-9]+[tu]?/g);
+ var ports = (this.ownerMap.get('network', sid, 'ports') || '').match(/[0-9]+[tu]?/g);
if (ports)
for (var i = 0; i < ports.length; i++)
@@ -187,12 +187,12 @@ L.ui.view.extend({
});
vlans.add = function() {
- var sections = this.sections();
+ var sections = this.getUCISections();
var used_vids = { };
for (var j = 0; j < sections.length; j++)
{
- var v = this.map.get('network', sections[j]['.name'], 'vlan');
+ var v = this.ownerMap.get('network', sections[j]['.name'], 'vlan');
if (v)
used_vids[v] = true;
}
@@ -202,9 +202,9 @@ L.ui.view.extend({
if (used_vids[j.toString()])
continue;
- var sid = this.map.add('network', 'switch_vlan');
- this.map.set('network', sid, 'device', this.options.swname);
- this.map.set('network', sid, 'vlan', j);
+ var sid = this.ownerMap.add('network', 'switch_vlan');
+ this.ownerMap.set('network', sid, 'device', this.options.swname);
+ this.ownerMap.set('network', sid, 'vlan', j);
break;
}
};
@@ -236,7 +236,7 @@ L.ui.view.extend({
var vo = vlans.option(L.cbi.InputValue, vid_opt, {
caption: L.tr('VLAN ID'),
datatype: function(val) {
- var sections = vlans.sections();
+ var sections = vlans.getUCISections();
var used_vids = { };
for (var j = 0; j < sections.length; j++)
@@ -264,16 +264,16 @@ L.ui.view.extend({
});
vo.ucivalue = function(sid) {
- var id = this.map.get('network', sid, vid_opt);
+ var id = this.ownerMap.get('network', sid, vid_opt);
if (isNaN(parseInt(id)))
- id = this.map.get('network', sid, 'vlan');
+ id = this.ownerMap.get('network', sid, 'vlan');
return id;
};
vo.save = function(sid) {
- var old_ports = this.map.get('network', sid, 'ports');
+ var old_ports = this.ownerMap.get('network', sid, 'ports');
var new_ports = '';
for (var j = 0; j < port_opts.length; j++)
@@ -286,13 +286,13 @@ L.ui.view.extend({
}
if (new_ports != old_ports)
- this.map.set('network', sid, 'ports', new_ports);
+ this.ownerMap.set('network', sid, 'ports', new_ports);
if (v4k_opt)
{
- var s = sw.sections();
+ var s = sw.getUCISections();
for (var j = 0; j < s.length; j++)
- this.map.set('network', s[j]['.name'], v4k_opt, '1');
+ this.ownerMap.set('network', s[j]['.name'], v4k_opt, '1');
}
this.callSuper('save', sid);
diff --git a/luci2/htdocs/luci2/view/system.users.js b/luci2/htdocs/luci2/view/system.users.js
index cc495e9..b467a04 100644
--- a/luci2/htdocs/luci2/view/system.users.js
+++ b/luci2/htdocs/luci2/view/system.users.js
@@ -115,8 +115,8 @@ L.ui.view.extend({
.css('cursor', 'pointer')
.click({ level: 2 }, this.setAll)));
- var acl_r = this.aclFromUCI(this.map.get('rpcd', sid, 'read'));
- var acl_w = this.aclFromUCI(this.map.get('rpcd', sid, 'write'));
+ var acl_r = this.aclFromUCI(this.ownerMap.get('rpcd', sid, 'read'));
+ var acl_w = this.aclFromUCI(this.ownerMap.get('rpcd', sid, 'write'));
if (this.choices)
for (var i = 0; i < this.choices.length; i++)
@@ -147,8 +147,8 @@ L.ui.view.extend({
textvalue: function(sid)
{
- var acl_r = this.aclFromUCI(this.map.get('rpcd', sid, 'read'));
- var acl_w = this.aclFromUCI(this.map.get('rpcd', sid, 'write'));
+ var acl_r = this.aclFromUCI(this.ownerMap.get('rpcd', sid, 'read'));
+ var acl_w = this.aclFromUCI(this.ownerMap.get('rpcd', sid, 'write'));
var htmlid = this.id(sid);
var radios = $('#' + htmlid + ' input');
@@ -187,8 +187,8 @@ L.ui.view.extend({
save: function(sid)
{
- var acl_r = this.aclFromUCI(this.map.get('rpcd', sid, 'read'));
- var acl_w = this.aclFromUCI(this.map.get('rpcd', sid, 'write'));
+ var acl_r = this.aclFromUCI(this.ownerMap.get('rpcd', sid, 'read'));
+ var acl_w = this.aclFromUCI(this.ownerMap.get('rpcd', sid, 'write'));
var acl_r_new = [ ];
var acl_w_new = [ ];
@@ -212,16 +212,16 @@ L.ui.view.extend({
}
if (!this.aclEqual(acl_r, acl_r_new))
- this.map.set('rpcd', sid, 'read', this.aclToUCI(acl_r_new));
+ this.ownerMap.set('rpcd', sid, 'read', this.aclToUCI(acl_r_new));
if (!this.aclEqual(acl_w, acl_w_new))
- this.map.set('rpcd', sid, 'write', this.aclToUCI(acl_w_new));
+ this.ownerMap.set('rpcd', sid, 'write', this.aclToUCI(acl_w_new));
}
}),
execute: function() {
var self = this;
- return L.ui.listAvailableACLs().then(function(acls) {
+ return L.ui.getAvailableACLs().then(function(acls) {
var m = new L.cbi.Map('rpcd', {
caption: L.tr('Guest Logins'),
description: L.tr('Manage user accounts and permissions for accessing the LuCI ui.'),
@@ -249,7 +249,7 @@ L.ui.view.extend({
});
shadow.ucivalue = function(sid) {
- var pw = this.map.get('rpcd', sid, 'password');
+ var pw = this.ownerMap.get('rpcd', sid, 'password');
return (pw && pw.indexOf('$p$') == 0);
};
@@ -264,8 +264,8 @@ L.ui.view.extend({
password.toggle = function(sid) {
var id = '#' + this.id(sid);
- var pw = this.map.get('rpcd', sid, 'password');
- var sh = this.section.fields.__shadow.formvalue(sid);
+ var pw = this.ownerMap.get('rpcd', sid, 'password');
+ var sh = this.ownerSection.fields.__shadow.formvalue(sid);
if (!sh && pw && pw.indexOf('$p$') == 0)
$(id).val('');
@@ -274,23 +274,23 @@ L.ui.view.extend({
};
shadow.save = password.save = function(sid) {
- var sh = this.section.fields.__shadow.formvalue(sid);
- var pw = this.section.fields.password.formvalue(sid);
+ var sh = this.ownerSection.fields.__shadow.formvalue(sid);
+ var pw = this.ownerSection.fields.password.formvalue(sid);
if (!sh && !pw)
return;
if (sh)
- pw = '$p$' + this.section.fields.username.formvalue(sid);
+ pw = '$p$' + this.ownerSection.fields.username.formvalue(sid);
if (pw.match(/^\$[0-9p][a-z]?\$/))
{
- if (pw != this.map.get('rpcd', sid, 'password'))
- this.map.set('rpcd', sid, 'password', pw);
+ if (pw != this.ownerMap.get('rpcd', sid, 'password'))
+ this.ownerMap.set('rpcd', sid, 'password', pw);
}
else
{
- var map = this.map;
+ var map = this.ownerMap;
return L.ui.cryptPassword(pw).then(function(crypt) {
map.set('rpcd', sid, 'password', crypt);
});