From 7add1278c5fcbc24bb5773fbb70fb0cf7407b863 Mon Sep 17 00:00:00 2001 From: Jo-Philipp Wich Date: Fri, 30 May 2014 18:48:58 +0200 Subject: [PATCH] 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 --- luci2/htdocs/luci2/luci2.js | 1397 +++++++++-------- luci2/htdocs/luci2/proto/6in4.js | 4 +- luci2/htdocs/luci2/proto/static.js | 4 +- luci2/htdocs/luci2/view/network.interfaces.js | 2 +- luci2/htdocs/luci2/view/network.switch.js | 28 +- luci2/htdocs/luci2/view/system.users.js | 36 +- 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 + Copyright 2013-2014 Jo-Philipp Wich 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 $('
    ') .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 = $('
      '); @@ -4168,11 +4159,11 @@ function LuCI2() .attr('data-toggle', 'dropdown') .append(''); - 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 = $('
      '); + i.top = $('
      ') + .addClass('luci2-field'); if (!condensed) { @@ -5010,9 +5002,10 @@ function LuCI2() i.error = $('
      ') .hide() - .addClass('label label-danger'); + .addClass('luci2-field-error label label-danger'); i.widget = $('
      ') + .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 $('
      ') .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 $('
      ') .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() $('
    • ') .append($('
    • ') .append($('