var cbi_d = [];
var cbi_t = [];
+var cbi_strings = { path: {}, label: {} };
+
+function Int(x) {
+ return (/^-?\d+$/.test(x) ? +x : NaN);
+}
+
+function Dec(x) {
+ return (/^-?\d+(?:\.\d+)?$/.test(x) ? +x : NaN);
+}
var cbi_validators = {
'integer': function()
{
- return (this.match(/^-?[0-9]+$/) != null);
+ return !!Int(this);
},
'uinteger': function()
{
- return (cbi_validators.integer.apply(this) && (this >= 0));
+ return (Int(this) >= 0);
},
'float': function()
{
- return !isNaN(parseFloat(this));
+ return !!Dec(this);
},
'ufloat': function()
{
- return (cbi_validators['float'].apply(this) && (this >= 0));
+ return (Dec(this) >= 0);
},
'ipaddr': function()
'port': function()
{
- return cbi_validators.integer.apply(this) &&
- (this >= 0) && (this <= 65535);
+ var p = Int(this);
+ return (p >= 0 && p <= 65535);
},
'portrange': function()
{
if (this.match(/^(\d+)-(\d+)$/))
{
- var p1 = RegExp.$1;
- var p2 = RegExp.$2;
-
- return cbi_validators.port.apply(p1) &&
- cbi_validators.port.apply(p2) &&
- (parseInt(p1) <= parseInt(p2))
- ;
- }
- else
- {
- return cbi_validators.port.apply(this);
+ var p1 = +RegExp.$1;
+ var p2 = +RegExp.$2;
+ return (p1 <= p2 && p2 <= 65535);
}
+
+ return cbi_validators.port.apply(this);
},
'macaddr': function()
'range': function(min, max)
{
- var val = parseFloat(this);
- if (!isNaN(min) && !isNaN(max) && !isNaN(val))
- return ((val >= min) && (val <= max));
-
- return false;
+ var val = Dec(this);
+ return (val >= +min && val <= +max);
},
'min': function(min)
{
- var val = parseFloat(this);
- if (!isNaN(min) && !isNaN(val))
- return (val >= min);
-
- return false;
+ return (Dec(this) >= +min);
},
'max': function(max)
{
- var val = parseFloat(this);
- if (!isNaN(max) && !isNaN(val))
- return (val <= max);
-
- return false;
+ return (Dec(this) <= +max);
},
'rangelength': function(min, max)
{
var val = '' + this;
- if (!isNaN(min) && !isNaN(max))
- return ((val.length >= min) && (val.length <= max));
-
- return false;
+ return ((val.length >= +min) && (val.length <= +max));
},
'minlength': function(min)
{
- var val = '' + this;
- if (!isNaN(min))
- return (val.length >= min);
-
- return false;
+ return ((''+this).length >= +min);
},
'maxlength': function(max)
{
- var val = '' + this;
- if (!isNaN(max))
- return (val.length <= max);
-
- return false;
+ return ((''+this).length <= +max);
},
'or': function()
}
function cbi_init() {
- var nodes = document.querySelectorAll('[data-depends]');
+ var nodes;
+
+ nodes = document.querySelectorAll('[data-strings]');
+
+ for (var i = 0, node; (node = nodes[i]) !== undefined; i++) {
+ var str = JSON.parse(node.getAttribute('data-strings'));
+ for (var key in str) {
+ for (var key2 in str[key]) {
+ var dst = cbi_strings[key] || (cbi_strings[key] = { });
+ dst[key2] = str[key][key2];
+ }
+ }
+ }
+
+ nodes = document.querySelectorAll('[data-depends]');
for (var i = 0, node; (node = nodes[i]) !== undefined; i++) {
var index = parseInt(node.getAttribute('data-index'), 10);
}
}
+ nodes = document.querySelectorAll('[data-type]');
+
+ for (var i = 0, node; (node = nodes[i]) !== undefined; i++) {
+ cbi_validate_field(node, node.getAttribute('data-optional') === 'true',
+ node.getAttribute('data-type'));
+ }
+
+ nodes = document.querySelectorAll('[data-choices]');
+
+ for (var i = 0, node; (node = nodes[i]) !== undefined; i++) {
+ var choices = JSON.parse(node.getAttribute('data-choices'));
+ var options = {};
+
+ for (var j = 0; j < choices[0].length; j++)
+ options[choices[0][j]] = choices[1][j];
+
+ var def = (node.getAttribute('data-optional') === 'true')
+ ? node.placeholder || '' : null;
+
+ cbi_combobox_init(node, options, def,
+ node.getAttribute('data-manual'));
+ }
+
+ nodes = document.querySelectorAll('[data-dynlist]');
+
+ for (var i = 0, node; (node = nodes[i]) !== undefined; i++) {
+ var choices = JSON.parse(node.getAttribute('data-dynlist'));
+ var options = {};
+
+ for (var j = 0; j < choices[0].length; j++)
+ options[choices[0][j]] = choices[1][j];
+
+ cbi_dynlist_init(node, choices[2], choices[3], options);
+ }
+
cbi_d_update();
}
if (obj.value == "") {
var optdef = document.createElement("option");
optdef.value = "";
- optdef.appendChild(document.createTextNode(def));
+ optdef.appendChild(document.createTextNode(typeof(def) === 'string' ? def : cbi_strings.label.choose));
sel.appendChild(optdef);
} else {
var opt = document.createElement("option");
var optman = document.createElement("option");
optman.value = "";
- optman.appendChild(document.createTextNode(man));
+ optman.appendChild(document.createTextNode(typeof(man) === 'string' ? man : cbi_strings.label.custom));
sel.appendChild(optman);
obj.style.display = "none";
}
function cbi_combobox_init(id, values, def, man) {
- var obj = document.getElementById(id);
+ var obj = (typeof(id) === 'string') ? document.getElementById(id) : id;
cbi_bind(obj, "blur", function() {
- cbi_combobox(id, values, def, man, true);
+ cbi_combobox(obj.id, values, def, man, true);
});
- cbi_combobox(id, values, def, man, false);
+ cbi_combobox(obj.id, values, def, man, false);
}
-function cbi_filebrowser(id, url, defpath) {
+function cbi_filebrowser(id, defpath) {
var field = document.getElementById(id);
var browser = window.open(
- url + ( field.value || defpath || '' ) + '?field=' + id,
+ cbi_strings.path.browser + ( field.value || defpath || '' ) + '?field=' + id,
"luci_filebrowser", "width=300,height=400,left=100,top=200,scrollbars=yes"
);
browser.focus();
}
-function cbi_browser_init(id, respath, url, defpath)
+function cbi_browser_init(id, defpath)
{
function cbi_browser_btnclick(e) {
- cbi_filebrowser(id, url, defpath);
+ cbi_filebrowser(id, defpath);
return false;
}
var btn = document.createElement('img');
btn.className = 'cbi-image-button';
- btn.src = respath + '/cbi/folder.gif';
+ btn.src = cbi_strings.path.resource + '/cbi/folder.gif';
field.parentNode.insertBefore(btn, field.nextSibling);
cbi_bind(btn, 'click', cbi_browser_btnclick);
}
-function cbi_dynlist_init(name, respath, datatype, optional, url, defpath, choices)
+function cbi_dynlist_init(parent, datatype, optional, choices)
{
- var input0 = document.getElementsByName(name)[0];
- var prefix = input0.name;
- var parent = input0.parentNode;
- var holder = input0.placeholder;
+ var prefix = parent.getAttribute('data-prefix');
+ var holder = parent.getAttribute('data-placeholder');
var values;
while (parent.firstChild)
{
var n = parent.firstChild;
- var i = parseInt(n.index);
+ var i = +n.index;
if (i != del)
{
}
var b = document.createElement('img');
- b.src = respath + ((i+1) < values.length ? '/cbi/remove.gif' : '/cbi/add.gif');
+ b.src = cbi_strings.path.resource + ((i+1) < values.length ? '/cbi/remove.gif' : '/cbi/add.gif');
b.className = 'cbi-image-button';
parent.appendChild(t);
parent.appendChild(b);
if (datatype == 'file')
{
- cbi_browser_init(t.id, respath, url, defpath);
+ cbi_browser_init(t.id, parent.getAttribute('data-browser-path'));
}
parent.appendChild(document.createElement('br'));
if (choices)
{
- cbi_combobox_init(t.id, choices[0], '', choices[1]);
+ cbi_combobox_init(t.id, choices, '', cbi_strings.label.custom);
b.index = i;
cbi_bind(b, 'keydown', cbi_dynlist_keydown);
se = se.parentNode;
var prev = se.previousSibling;
- while (prev && prev.name != name)
+ while (prev && prev.name != prefix)
prev = prev.previousSibling;
var next = se.nextSibling;
- while (next && next.name != name)
+ while (next && next.name != prefix)
next = next.nextSibling;
/* advance one further in combobox case */
- if (next && next.nextSibling.name == name)
+ if (next && next.nextSibling.name == prefix)
next = next.nextSibling;
switch (ev.keyCode)
var se = ev.target ? ev.target : ev.srcElement;
var input = se.previousSibling;
- while (input && input.name != name) {
+ while (input && input.name != prefix) {
input = input.previousSibling;
}
input.value = '';
cbi_dynlist_keydown({
- target: input,
+ target: se,
keyCode: 8
});
}
else
{
cbi_dynlist_keydown({
- target: input,
+ target: se,
keyCode: 13
});
}
var minLength = -1;
if (pMinLength)
- minLength = parseInt(pMinLength);
+ minLength = +pMinLength;
var precision = -1;
if (pPrecision && pType == 'f')
- precision = parseInt(pPrecision.substring(1));
+ precision = +pPrecision.substring(1);
var subst = param;
switch(pType)
{
case 'b':
- subst = (parseInt(param) || 0).toString(2);
+ subst = (+param || 0).toString(2);
break;
case 'c':
- subst = String.fromCharCode(parseInt(param) || 0);
+ subst = String.fromCharCode(+param || 0);
break;
case 'd':
- subst = (parseInt(param) || 0);
+ subst = (+param || 0);
break;
case 'u':
- subst = Math.abs(parseInt(param) || 0);
+ subst = Math.abs(+param || 0);
break;
case 'f':
subst = (precision > -1)
- ? ((parseFloat(param) || 0.0)).toFixed(precision)
- : (parseFloat(param) || 0.0);
+ ? ((+param || 0.0)).toFixed(precision)
+ : (+param || 0.0);
break;
case 'o':
- subst = (parseInt(param) || 0).toString(8);
+ subst = (+param || 0).toString(8);
break;
case 's':
break;
case 'x':
- subst = ('' + (parseInt(param) || 0).toString(16)).toLowerCase();
+ subst = ('' + (+param || 0).toString(16)).toLowerCase();
break;
case 'X':
- subst = ('' + (parseInt(param) || 0).toString(16)).toUpperCase();
+ subst = ('' + (+param || 0).toString(16)).toUpperCase();
break;
case 'h':
break;
case 'm':
- var mf = pMinLength ? parseInt(pMinLength) : 1000;
- var pr = pPrecision ? Math.floor(10*parseFloat('0'+pPrecision)) : 2;
+ var mf = pMinLength ? +pMinLength : 1000;
+ var pr = pPrecision ? ~~(10 * +('0' + pPrecision)) : 2;
var i = 0;
- var val = parseFloat(param || 0);
+ var val = (+param || 0);
var units = [ '', 'K', 'M', 'G', 'T', 'P', 'E' ];
for (i = 0; (i < units.length) && (val > mf); i++)