4af6e58d9b5a234268db37bf62f82bd6e1313aff
2 LuCI - Lua Configuration Interface
4 Copyright 2008 Steven Barth <steven@midlink.org>
5 Copyright 2008-2010 Jo-Philipp Wich <xm@subsignal.org>
7 Licensed under the Apache License, Version 2.0 (the "License");
8 you may not use this file except in compliance with the License.
9 You may obtain a copy of the License at
11 http://www.apache.org/licenses/LICENSE-2.0
18 var cbi_validators
= {
20 'integer': function(v
)
22 return (v
.match(/^-?[0-9]+$/) != null);
25 'uinteger': function(v
)
27 return (cbi_validators
.integer(v
) && (v
>= 0));
32 return cbi_validators
.ip4addr(v
) || cbi_validators
.ip6addr(v
);
35 'ip4addr': function(v
)
37 if( v
.match(/^(\d+)\.(\d+)\.(\d+)\.(\d+)(\/(\d+))?$/) )
39 return (RegExp
.$1 >= 0) && (RegExp
.$1 <= 255) &&
40 (RegExp
.$2 >= 0) && (RegExp
.$2 <= 255) &&
41 (RegExp
.$3 >= 0) && (RegExp
.$3 <= 255) &&
42 (RegExp
.$4 >= 0) && (RegExp
.$4 <= 255) &&
43 (!RegExp
.$5 || ((RegExp
.$6 >= 0) && (RegExp
.$6 <= 32)))
50 'ip6addr': function(v
)
52 if( v
.match(/^([a-fA-F0-9:.]+)(\/(\d+))?$/) )
54 if( !RegExp
.$2 || ((RegExp
.$3 >= 0) && (RegExp
.$3 <= 128)) )
63 if( addr
.indexOf('.') > 0 )
65 var off
= addr
.lastIndexOf(':');
67 if( !(off
&& cbi_validators
.ip4addr(addr
.substr(off
+1))) )
70 addr
= addr
.substr(0, off
) + ':0:0';
73 if( addr
.indexOf('::') < 0 )
75 return (addr
.match(/^(?:[a-fA-F0-9]{1,4}:){7}[a-fA-F0-9]{1,4}$/) != null);
80 for( var i
= 0, last
= 0, comp
= false; i
<= addr
.length
; i
++ )
82 if( (addr
.charAt(i
) == ':') || (i
== addr
.length
) )
84 if( (i
== last
) && !comp
)
90 var f
= addr
.substring(last
, i
);
91 if( !(f
&& f
.match(/^[a-fA-F0-9]{1,4}$/)) )
100 return (fields
== 8);
109 return cbi_validators
.integer(v
) && (v
>= 0) && (v
<= 65535);
112 'portrange': function(v
)
114 if( v
.match(/^(\d+)-(\d+)$/) )
119 return cbi_validators
.port(p1
) &&
120 cbi_validators
.port(p2
) &&
121 (parseInt(p1
) <= parseInt(p2
))
126 return cbi_validators
.port(v
);
130 'macaddr': function(v
)
132 return (v
.match(/^([a-fA-F0-9]{2}:){5}[a-fA-F0-9]{2}$/) != null);
137 return cbi_validators
.hostname(v
) || cbi_validators
.ipaddr(v
);
140 'hostname': function(v
)
142 return (v
.match(/^[a-zA-Z_][a-zA-Z0-9_\-.]*$/) != null);
145 'wpakey': function(v
)
148 return (v
.match(/^[a-fA-F0-9]{64}$/) != null);
150 return (v
.length
>= 8) && (v
.length
<= 63);
153 'wepkey': function(v
)
155 if( v
.substr(0,2) == 's:' )
158 if( (v
.length
== 10) || (v
.length
== 26) )
159 return (v
.match(/^[a-fA-F0-9]{10,26}$/) != null);
161 return (v
.length
== 5) || (v
.length
== 13);
167 function cbi_d_add(field
, dep
, next
) {
168 var obj
= document
.getElementById(field
);
171 for (var i
=0; i
<cbi_d
.length
; i
++) {
172 if (cbi_d
[i
].id
== field
) {
181 "parent": obj
.parentNode
.id
,
185 cbi_d
.unshift(entry
);
191 function cbi_d_checkvalue(target
, ref
) {
192 var t
= document
.getElementById(target
);
196 var tl
= document
.getElementsByName(target
);
198 if( tl
.length
> 0 && tl
[0].type
== 'radio' )
199 for( var i
= 0; i
< tl
.length
; i
++ )
200 if( tl
[i
].checked
) {
205 value
= value
? value
: "";
206 } else if (!t
.value
) {
211 if (t
.type
== "checkbox") {
212 value
= t
.checked
? value
: "";
216 return (value
== ref
)
219 function cbi_d_check(deps
) {
222 for (var i
=0; i
<deps
.length
; i
++) {
225 for (var j
in deps
[i
]) {
226 if (j
== "!reverse") {
228 } else if (j
== "!default") {
232 istat
= (istat
&& cbi_d_checkvalue(j
, deps
[i
][j
]))
242 function cbi_d_update() {
244 for (var i
=0; i
<cbi_d
.length
; i
++) {
245 var entry
= cbi_d
[i
];
246 var next
= document
.getElementById(entry
.next
)
247 var node
= document
.getElementById(entry
.id
)
248 var parent
= document
.getElementById(entry
.parent
)
250 if (node
&& node
.parentNode
&& !cbi_d_check(entry
.deps
)) {
251 node
.parentNode
.removeChild(node
);
254 cbi_c
[entry
.parent
]--;
255 } else if ((!node
|| !node
.parentNode
) && cbi_d_check(entry
.deps
)) {
257 parent
.appendChild(entry
.node
);
259 next
.parentNode
.insertBefore(entry
.node
, next
);
263 cbi_c
[entry
.parent
]++;
276 function cbi_bind(obj
, type
, callback
, mode
) {
277 if (typeof mode
== "undefined") {
280 if (!obj
.addEventListener
) {
281 ieCallback = function(){
282 var e
= window
.event
;
283 if (!e
.target
&& e
.srcElement
) {
284 e
.target
= e
.srcElement
;
286 e
.target
['_eCB' + type
+ callback
] = callback
;
287 e
.target
['_eCB' + type
+ callback
](e
);
288 e
.target
['_eCB' + type
+ callback
] = null;
290 obj
.attachEvent('on' + type
, ieCallback
);
292 obj
.addEventListener(type
, callback
, mode
);
297 function cbi_combobox(id
, values
, def
, man
) {
298 var selid
= "cbi.combobox." + id
;
299 if (document
.getElementById(selid
)) {
303 var obj
= document
.getElementById(id
)
304 var sel
= document
.createElement("select");
306 sel
.className
= 'cbi-input-select';
307 if (obj
.className
&& obj
.className
.match(/cbi-input-invalid/)) {
308 sel
.className
+= ' cbi-input-invalid';
310 if (obj
.nextSibling
) {
311 obj
.parentNode
.insertBefore(sel
, obj
.nextSibling
);
313 obj
.parentNode
.appendChild(sel
);
316 if (!values
[obj
.value
]) {
317 if (obj
.value
== "") {
318 var optdef
= document
.createElement("option");
320 optdef
.appendChild(document
.createTextNode(def
));
321 sel
.appendChild(optdef
);
323 var opt
= document
.createElement("option");
324 opt
.value
= obj
.value
;
325 opt
.selected
= "selected";
326 opt
.appendChild(document
.createTextNode(obj
.value
));
327 sel
.appendChild(opt
);
331 for (var i
in values
) {
332 var opt
= document
.createElement("option");
335 if (obj
.value
== i
) {
336 opt
.selected
= "selected";
339 opt
.appendChild(document
.createTextNode(values
[i
]));
340 sel
.appendChild(opt
);
343 var optman
= document
.createElement("option");
345 optman
.appendChild(document
.createTextNode(man
));
346 sel
.appendChild(optman
);
348 obj
.style
.display
= "none";
350 cbi_bind(sel
, "change", function() {
351 if (sel
.selectedIndex
== sel
.options
.length
- 1) {
352 obj
.style
.display
= "inline";
353 sel
.parentNode
.removeChild(sel
);
356 obj
.value
= sel
.options
[sel
.selectedIndex
].value
;
357 sel
.className
= (!obj
.validate
|| obj
.validate())
358 ? 'cbi-input-select' : 'cbi-input-select cbi-input-invalid';
369 function cbi_combobox_init(id
, values
, def
, man
) {
370 var obj
= document
.getElementById(id
);
371 cbi_bind(obj
, "blur", function() {
372 cbi_combobox(id
, values
, def
, man
)
374 cbi_combobox(id
, values
, def
, man
);
377 function cbi_filebrowser(id
, url
, defpath
) {
378 var field
= document
.getElementById(id
);
379 var browser
= window
.open(
380 url
+ ( field
.value
|| defpath
|| '' ) + '?field=' + id
,
381 "luci_filebrowser", "width=300,height=400,left=100,top=200,scrollbars=yes"
387 //Hijacks the CBI form to send via XHR (requires Prototype)
388 function cbi_hijack_forms(layer
, win
, fail
, load
) {
389 var forms
= layer
.getElementsByTagName('form');
390 for (var i
=0; i
<forms
.length
; i
++) {
391 $(forms
[i
]).observe('submit', function(event
) {
392 // Prevent the form from also submitting the regular way
396 event
.element().request({
409 function cbi_t_add(section
, tab
) {
410 var t
= document
.getElementById('tab.' + section
+ '.' + tab
);
411 var c
= document
.getElementById('container.' + section
+ '.' + tab
);
414 cbi_t
[section
] = (cbi_t
[section
] || [ ]);
415 cbi_t
[section
][tab
] = { 'tab': t
, 'container': c
, 'cid': c
.id
};
419 function cbi_t_switch(section
, tab
) {
420 if( cbi_t
[section
] && cbi_t
[section
][tab
] ) {
421 var o
= cbi_t
[section
][tab
];
422 var h
= document
.getElementById('tab.' + section
);
423 for( var tid
in cbi_t
[section
] ) {
424 var o2
= cbi_t
[section
][tid
];
425 if( o
.tab
.id
!= o2
.tab
.id
) {
426 o2
.tab
.className
= o2
.tab
.className
.replace(/(^| )cbi-tab( |$)/, " cbi-tab-disabled ");
427 o2
.container
.style
.display
= 'none';
431 o2
.tab
.className
= o2
.tab
.className
.replace(/(^| )cbi-tab-disabled( |$)/, " cbi-tab ");
432 o2
.container
.style
.display
= 'block';
439 function cbi_t_update() {
440 for( var sid
in cbi_t
)
441 for( var tid
in cbi_t
[sid
] )
442 if( cbi_c
[cbi_t
[sid
][tid
].cid
] == 0 ) {
443 cbi_t
[sid
][tid
].tab
.style
.display
= 'none';
445 else if( cbi_t
[sid
][tid
].tab
&& cbi_t
[sid
][tid
].tab
.style
.display
== 'none' ) {
446 cbi_t
[sid
][tid
].tab
.style
.display
= '';
448 var t
= cbi_t
[sid
][tid
].tab
;
449 window
.setTimeout(function() { t
.className
= t
.className
.replace(/ cbi
-tab
-highlighted
/g
, '') }, 750);
450 cbi_t
[sid
][tid
].tab
.className
+= ' cbi-tab-highlighted';
455 function cbi_validate_form(form
, errmsg
)
457 if( form
.cbi_validators
)
459 for( var i
= 0; i
< form
.cbi_validators
.length
; i
++ )
461 var validator
= form
.cbi_validators
[i
];
462 if( !validator() && errmsg
)
473 function cbi_validate_reset(form
)
476 function() { cbi_validate_form(form
, null) }, 100
482 function cbi_validate_field(cbid
, optional
, type
)
484 var field
= document
.getElementById(cbid
);
485 var vldcb
= cbi_validators
[type
];
489 var validator = function(reset
)
494 field
.className
= field
.className
.replace(/ cbi
-input
-invalid
/g
, '');
497 var value
= (field
.options
) ? field
.options
[field
.options
.selectedIndex
].value
: field
.value
;
498 if( !(((value
.length
== 0) && optional
) || vldcb(value
)) )
501 field
.className
+= ' cbi-input-invalid';
509 if( ! field
.form
.cbi_validators
)
510 field
.form
.cbi_validators
= [ ];
512 field
.form
.cbi_validators
.push(validator
);
513 field
.onblur
= field
.onkeyup
= field
.validate
= validator
;