(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') $('