From e28f8f6a5a654a86dc6840f8bb1b16b888e24430 Mon Sep 17 00:00:00 2001 From: Jo-Philipp Wich Date: Mon, 5 Jan 2015 19:17:55 +0100 Subject: [PATCH] luci2: split into submodules Signed-off-by: Jo-Philipp Wich --- luci2/htdocs/luci2.html | 2 +- luci2/htdocs/luci2/cbi.js | 3200 ++++++++++++++++++ luci2/htdocs/luci2/firewall.js | 50 + luci2/htdocs/luci2/luci2.js | 7036 +--------------------------------------- luci2/htdocs/luci2/network.js | 1447 +++++++++ luci2/htdocs/luci2/rpc.js | 188 ++ luci2/htdocs/luci2/session.js | 78 + luci2/htdocs/luci2/system.js | 82 + luci2/htdocs/luci2/uci.js | 532 +++ luci2/htdocs/luci2/ui.js | 1324 ++++++++ luci2/htdocs/luci2/wireless.js | 156 + 11 files changed, 7067 insertions(+), 7028 deletions(-) create mode 100644 luci2/htdocs/luci2/cbi.js create mode 100644 luci2/htdocs/luci2/firewall.js create mode 100644 luci2/htdocs/luci2/network.js create mode 100644 luci2/htdocs/luci2/rpc.js create mode 100644 luci2/htdocs/luci2/session.js create mode 100644 luci2/htdocs/luci2/system.js create mode 100644 luci2/htdocs/luci2/uci.js create mode 100644 luci2/htdocs/luci2/ui.js create mode 100644 luci2/htdocs/luci2/wireless.js diff --git a/luci2/htdocs/luci2.html b/luci2/htdocs/luci2.html index de5e037..47c74c7 100644 --- a/luci2/htdocs/luci2.html +++ b/luci2/htdocs/luci2.html @@ -24,7 +24,7 @@ var L = new LuCI2(); L.ui.login().then(function() { - L.ui.init(); + L.ui.load(); }); }); diff --git a/luci2/htdocs/luci2/cbi.js b/luci2/htdocs/luci2/cbi.js new file mode 100644 index 0000000..cfc677d --- /dev/null +++ b/luci2/htdocs/luci2/cbi.js @@ -0,0 +1,3200 @@ +(function() { + var type = function(f, l) + { + f.message = l; + return f; + }; + + var cbi_class = { + validation: { + i18n: function(msg) + { + L.cbi.validation.message = L.tr(msg); + }, + + compile: function(code) + { + var pos = 0; + var esc = false; + var depth = 0; + var types = L.cbi.validation.types; + var stack = [ ]; + + code += ','; + + for (var i = 0; i < code.length; i++) + { + if (esc) + { + esc = false; + continue; + } + + switch (code.charCodeAt(i)) + { + case 92: + esc = true; + break; + + case 40: + case 44: + if (depth <= 0) + { + if (pos < i) + { + var label = code.substring(pos, i); + label = label.replace(/\\(.)/g, '$1'); + label = label.replace(/^[ \t]+/g, ''); + label = label.replace(/[ \t]+$/g, ''); + + if (label && !isNaN(label)) + { + stack.push(parseFloat(label)); + } + else if (label.match(/^(['"]).*\1$/)) + { + stack.push(label.replace(/^(['"])(.*)\1$/, '$2')); + } + else if (typeof types[label] == 'function') + { + stack.push(types[label]); + stack.push([ ]); + } + else + { + throw "Syntax error, unhandled token '"+label+"'"; + } + } + pos = i+1; + } + depth += (code.charCodeAt(i) == 40); + break; + + case 41: + if (--depth <= 0) + { + if (typeof stack[stack.length-2] != 'function') + throw "Syntax error, argument list follows non-function"; + + stack[stack.length-1] = + L.cbi.validation.compile(code.substring(pos, i)); + + pos = i+1; + } + break; + } + } + + return stack; + } + } + }; + + var validation = cbi_class.validation; + + validation.types = { + 'integer': function() + { + if (this.match(/^-?[0-9]+$/) != null) + return true; + + validation.i18n('Must be a valid integer'); + return false; + }, + + 'uinteger': function() + { + if (validation.types['integer'].apply(this) && (this >= 0)) + return true; + + validation.i18n('Must be a positive integer'); + return false; + }, + + 'float': function() + { + if (!isNaN(parseFloat(this))) + return true; + + validation.i18n('Must be a valid number'); + return false; + }, + + 'ufloat': function() + { + if (validation.types['float'].apply(this) && (this >= 0)) + return true; + + validation.i18n('Must be a positive number'); + return false; + }, + + 'ipaddr': function() + { + if (L.parseIPv4(this) || L.parseIPv6(this)) + return true; + + validation.i18n('Must be a valid IP address'); + return false; + }, + + 'ip4addr': function() + { + if (L.parseIPv4(this)) + return true; + + validation.i18n('Must be a valid IPv4 address'); + return false; + }, + + 'ip6addr': function() + { + if (L.parseIPv6(this)) + return true; + + validation.i18n('Must be a valid IPv6 address'); + return false; + }, + + 'netmask4': function() + { + if (L.isNetmask(L.parseIPv4(this))) + return true; + + validation.i18n('Must be a valid IPv4 netmask'); + return false; + }, + + 'netmask6': function() + { + if (L.isNetmask(L.parseIPv6(this))) + return true; + + validation.i18n('Must be a valid IPv6 netmask6'); + return false; + }, + + 'cidr4': function() + { + if (this.match(/^([0-9.]+)\/(\d{1,2})$/)) + if (RegExp.$2 <= 32 && L.parseIPv4(RegExp.$1)) + return true; + + validation.i18n('Must be a valid IPv4 prefix'); + return false; + }, + + 'cidr6': function() + { + if (this.match(/^([a-fA-F0-9:.]+)\/(\d{1,3})$/)) + if (RegExp.$2 <= 128 && L.parseIPv6(RegExp.$1)) + return true; + + validation.i18n('Must be a valid IPv6 prefix'); + return false; + }, + + 'ipmask4': function() + { + if (this.match(/^([0-9.]+)\/([0-9.]+)$/)) + { + var addr = RegExp.$1, mask = RegExp.$2; + if (L.parseIPv4(addr) && L.isNetmask(L.parseIPv4(mask))) + return true; + } + + validation.i18n('Must be a valid IPv4 address/netmask pair'); + return false; + }, + + 'ipmask6': function() + { + if (this.match(/^([a-fA-F0-9:.]+)\/([a-fA-F0-9:.]+)$/)) + { + var addr = RegExp.$1, mask = RegExp.$2; + if (L.parseIPv6(addr) && L.isNetmask(L.parseIPv6(mask))) + return true; + } + + validation.i18n('Must be a valid IPv6 address/netmask pair'); + return false; + }, + + 'port': function() + { + if (validation.types['integer'].apply(this) && + (this >= 0) && (this <= 65535)) + return true; + + validation.i18n('Must be a valid port number'); + return false; + }, + + 'portrange': function() + { + if (this.match(/^(\d+)-(\d+)$/)) + { + var p1 = RegExp.$1; + var p2 = RegExp.$2; + + if (validation.types['port'].apply(p1) && + validation.types['port'].apply(p2) && + (parseInt(p1) <= parseInt(p2))) + return true; + } + else if (validation.types['port'].apply(this)) + { + return true; + } + + validation.i18n('Must be a valid port range'); + return false; + }, + + 'macaddr': function() + { + if (this.match(/^([a-fA-F0-9]{2}:){5}[a-fA-F0-9]{2}$/) != null) + return true; + + validation.i18n('Must be a valid MAC address'); + return false; + }, + + 'host': function() + { + if (validation.types['hostname'].apply(this) || + validation.types['ipaddr'].apply(this)) + return true; + + validation.i18n('Must be a valid hostname or IP address'); + return false; + }, + + 'hostname': function() + { + if ((this.length <= 253) && + ((this.match(/^[a-zA-Z0-9]+$/) != null || + (this.match(/^[a-zA-Z0-9_][a-zA-Z0-9_\-.]*[a-zA-Z0-9]$/) && + this.match(/[^0-9.]/))))) + return true; + + validation.i18n('Must be a valid host name'); + return false; + }, + + 'network': function() + { + if (validation.types['uciname'].apply(this) || + validation.types['host'].apply(this)) + return true; + + validation.i18n('Must be a valid network name'); + return false; + }, + + 'wpakey': function() + { + var v = this; + + if ((v.length == 64) + ? (v.match(/^[a-fA-F0-9]{64}$/) != null) + : ((v.length >= 8) && (v.length <= 63))) + return true; + + validation.i18n('Must be a valid WPA key'); + return false; + }, + + 'wepkey': function() + { + var v = this; + + if (v.substr(0,2) == 's:') + v = v.substr(2); + + if (((v.length == 10) || (v.length == 26)) + ? (v.match(/^[a-fA-F0-9]{10,26}$/) != null) + : ((v.length == 5) || (v.length == 13))) + return true; + + validation.i18n('Must be a valid WEP key'); + return false; + }, + + 'uciname': function() + { + if (this.match(/^[a-zA-Z0-9_]+$/) != null) + return true; + + validation.i18n('Must be a valid UCI identifier'); + return false; + }, + + 'range': function(min, max) + { + var val = parseFloat(this); + + if (validation.types['integer'].apply(this) && + !isNaN(min) && !isNaN(max) && ((val >= min) && (val <= max))) + return true; + + validation.i18n('Must be a number between %d and %d'); + return false; + }, + + 'min': function(min) + { + var val = parseFloat(this); + + if (validation.types['integer'].apply(this) && + !isNaN(min) && !isNaN(val) && (val >= min)) + return true; + + validation.i18n('Must be a number greater or equal to %d'); + return false; + }, + + 'max': function(max) + { + var val = parseFloat(this); + + if (validation.types['integer'].apply(this) && + !isNaN(max) && !isNaN(val) && (val <= max)) + return true; + + validation.i18n('Must be a number lower or equal to %d'); + return false; + }, + + 'rangelength': function(min, max) + { + var val = '' + this; + + if (!isNaN(min) && !isNaN(max) && + (val.length >= min) && (val.length <= max)) + return true; + + if (min != max) + validation.i18n('Must be between %d and %d characters'); + else + validation.i18n('Must be %d characters'); + return false; + }, + + 'minlength': function(min) + { + var val = '' + this; + + if (!isNaN(min) && (val.length >= min)) + return true; + + validation.i18n('Must be at least %d characters'); + return false; + }, + + 'maxlength': function(max) + { + var val = '' + this; + + if (!isNaN(max) && (val.length <= max)) + return true; + + validation.i18n('Must be at most %d characters'); + return false; + }, + + 'or': function() + { + var msgs = [ ]; + + for (var i = 0; i < arguments.length; i += 2) + { + delete validation.message; + + if (typeof(arguments[i]) != 'function') + { + if (arguments[i] == this) + return true; + i--; + } + else if (arguments[i].apply(this, arguments[i+1])) + { + return true; + } + + if (validation.message) + msgs.push(validation.message.format.apply(validation.message, arguments[i+1])); + } + + validation.message = msgs.join( L.tr(' - or - ')); + return false; + }, + + 'and': function() + { + var msgs = [ ]; + + for (var i = 0; i < arguments.length; i += 2) + { + delete validation.message; + + if (typeof arguments[i] != 'function') + { + if (arguments[i] != this) + return false; + i--; + } + else if (!arguments[i].apply(this, arguments[i+1])) + { + return false; + } + + if (validation.message) + msgs.push(validation.message.format.apply(validation.message, arguments[i+1])); + } + + validation.message = msgs.join(', '); + return true; + }, + + 'neg': function() + { + return validation.types['or'].apply( + this.replace(/^[ \t]*![ \t]*/, ''), arguments); + }, + + 'list': function(subvalidator, subargs) + { + if (typeof subvalidator != 'function') + return false; + + var tokens = this.match(/[^ \t]+/g); + for (var i = 0; i < tokens.length; i++) + if (!subvalidator.apply(tokens[i], subargs)) + return false; + + return true; + }, + + 'phonedigit': function() + { + if (this.match(/^[0-9\*#!\.]+$/) != null) + return true; + + validation.i18n('Must be a valid phone number digit'); + return false; + }, + + 'string': function() + { + return true; + } + }; + + cbi_class.AbstractValue = L.ui.AbstractWidget.extend({ + init: function(name, options) + { + this.name = name; + this.instance = { }; + this.dependencies = [ ]; + this.rdependency = { }; + + this.options = L.defaults(options, { + placeholder: '', + datatype: 'string', + optional: false, + keep: true + }); + }, + + id: function(sid) + { + return this.ownerSection.id('field', sid || '__unknown__', this.name); + }, + + render: function(sid, condensed) + { + var i = this.instance[sid] = { }; + + i.top = $('
') + .addClass('luci2-field'); + + if (!condensed) + { + i.top.addClass('form-group'); + + if (typeof(this.options.caption) == 'string') + $('