libs/web: remove debug code from cbi.js
[project/luci.git] / libs / web / htdocs / luci-static / resources / cbi.js
index 4af6e58..3959b69 100644 (file)
@@ -70,34 +70,27 @@ var cbi_validators = {
                                        addr = addr.substr(0, off) + ':0:0';
                                }
 
-                               if( addr.indexOf('::') < 0 )
+                               if( addr.indexOf('::') >= 0 )
                                {
-                                       return (addr.match(/^(?:[a-fA-F0-9]{1,4}:){7}[a-fA-F0-9]{1,4}$/) != null);
-                               }
+                                       var colons = 0;
+                                       var fill = '0';
 
-                               var fields = 0;
+                                       for( var i = 1; i < (addr.length-1); i++ )
+                                               if( addr.charAt(i) == ':' )
+                                                       colons++;
 
-                               for( var i = 0, last = 0, comp = false; i <= addr.length; i++ )
-                               {
-                                       if( (addr.charAt(i) == ':') || (i == addr.length) )
-                                       {
-                                               if( (i == last) && !comp )
-                                               {
-                                                       comp = true;
-                                               }
-                                               else
-                                               {
-                                                       var f = addr.substring(last, i);
-                                                       if( !(f && f.match(/^[a-fA-F0-9]{1,4}$/)) )
-                                                               return false;
-                                               }
-
-                                               fields++;
-                                               last = i + 1;
-                                       }                               
+                                       if( colons > 7 )
+                                               return false;
+
+                                       for( var i = 0; i < (7 - colons); i++ )
+                                               fill += ':0';
+
+                                       if (addr.match(/^(.*?)::(.*?)$/))
+                                               addr = (RegExp.$1 ? RegExp.$1 + ':' : '') + fill +
+                                                      (RegExp.$2 ? ':' + RegExp.$2 : '');
                                }
 
-                               return (fields == 8);
+                               return (addr.match(/^(?:[a-fA-F0-9]{1,4}:){7}[a-fA-F0-9]{1,4}$/) != null);
                        }
                }
 
@@ -161,6 +154,22 @@ var cbi_validators = {
                        return (v.length == 5) || (v.length == 13);
        },
 
+       'uciname': function(v)
+       {
+               return (v.match(/^[a-zA-Z0-9_]+$/) != null);
+       },
+
+       'range': function(v, args)
+       {
+               var min = parseInt(args[0]);
+               var max = parseInt(args[1]);
+               var val = parseInt(v);
+
+               if (!isNaN(min) && !isNaN(max) && !isNaN(val))
+                       return ((val >= min) && (val <= max));
+
+               return false;
+       }
 };
 
 
@@ -264,7 +273,7 @@ function cbi_d_update() {
                }
        }
 
-       if (entry.parent) {
+       if (entry && entry.parent) {
                cbi_t_update();
        }
 
@@ -274,22 +283,19 @@ function cbi_d_update() {
 }
 
 function cbi_bind(obj, type, callback, mode) {
-       if (typeof mode == "undefined") {
-               mode = false;
-       }
        if (!obj.addEventListener) {
-               ieCallback = function(){
-                       var e = window.event;
-                       if (!e.target && e.srcElement) {
-                               e.target = e.srcElement;
-                       };
-                       e.target['_eCB' + type + callback] = callback;
-                       e.target['_eCB' + type + callback](e);
-                       e.target['_eCB' + type + callback] = null;
-               };
-               obj.attachEvent('on' + type, ieCallback);
+               obj.attachEvent('on' + type,
+                       function(){
+                               var e = window.event;
+
+                               if (!e.target && e.srcElement)
+                                       e.target = e.srcElement;
+
+                               return !!callback(e);
+                       }
+               );
        } else {
-               obj.addEventListener(type, callback, mode);
+               obj.addEventListener(type, callback, !!mode);
        }
        return obj;
 }
@@ -302,17 +308,21 @@ function cbi_combobox(id, values, def, man) {
 
        var obj = document.getElementById(id)
        var sel = document.createElement("select");
-       sel.id = selid;
-       sel.className = 'cbi-input-select';
-       if (obj.className && obj.className.match(/cbi-input-invalid/)) {
-               sel.className += ' cbi-input-invalid';
-       }
+               sel.id = selid;
+               sel.className = 'cbi-input-select';
+
        if (obj.nextSibling) {
                obj.parentNode.insertBefore(sel, obj.nextSibling);
        } else {
                obj.parentNode.appendChild(sel);
        }
 
+       var dt = obj.getAttribute('cbi_datatype');
+       var op = obj.getAttribute('cbi_optional');
+
+       if (dt)
+               cbi_validate_field(sel, op == 'true', dt);
+
        if (!values[obj.value]) {
                if (obj.value == "") {
                        var optdef = document.createElement("option");
@@ -354,8 +364,6 @@ function cbi_combobox(id, values, def, man) {
                        obj.focus();
                } else {
                        obj.value = sel.options[sel.selectedIndex].value;
-                       sel.className = (!obj.validate || obj.validate())
-                               ? 'cbi-input-select' : 'cbi-input-select cbi-input-invalid';
                }
 
                try {
@@ -384,6 +392,152 @@ function cbi_filebrowser(id, url, defpath) {
        browser.focus();
 }
 
+function cbi_dynlist_init(name)
+{
+       function cbi_dynlist_renumber(e)
+       {
+               var count = 1;
+               var childs = e.parentNode.childNodes;
+
+               for( var i = 0; i < childs.length; i++ )
+                       if( childs[i].name == name )
+                               childs[i].id = name + '.' + (count++);
+
+               e.focus();
+       }
+
+       function cbi_dynlist_keypress(ev)
+       {
+               ev = ev ? ev : window.event;
+
+               var se = ev.target ? ev.target : ev.srcElement;
+
+               if (se.nodeType == 3)
+                       se = se.parentNode;
+
+               switch (ev.keyCode)
+               {
+                       /* backspace, delete */
+                       case 8:
+                       case 46:
+                               if (se.value.length == 0)
+                               {
+                                       if (ev.preventDefault)
+                                               ev.preventDefault();
+
+                                       return false;
+                               }
+
+                               return true;
+
+                       /* enter, arrow up, arrow down */
+                       case 13:
+                       case 38:
+                       case 40:
+                               if (ev.preventDefault)
+                                       ev.preventDefault();
+
+                               return false;
+               }
+
+               return true;
+       }
+
+       function cbi_dynlist_keydown(ev)
+       {
+               ev = ev ? ev : window.event;
+
+               var se = ev.target ? ev.target : ev.srcElement;
+
+               if (se.nodeType == 3)
+                       se = se.parentNode;
+
+               var prev = se.previousSibling;
+               while (prev && prev.name != name)
+                       prev = prev.previousSibling;
+
+               var next = se.nextSibling;
+               while (next && next.name != name)
+                       next = next.nextSibling;
+
+               switch (ev.keyCode)
+               {
+                       /* backspace, delete */
+                       case 8:
+                       case 46:
+                               var jump = (ev.keyCode == 8)
+                                       ? (prev || next) : (next || prev);
+
+                               if (se.value.length == 0 && jump)
+                               {
+                                       se.parentNode.removeChild(se.nextSibling);
+                                       se.parentNode.removeChild(se);
+
+                                       cbi_dynlist_renumber(jump);
+
+                                       if (ev.preventDefault)
+                                               ev.preventDefault();
+
+                                       return false;
+                               }
+
+                               break;
+
+                       /* enter */
+                       case 13:
+                               var n = document.createElement('input');
+                                       n.name       = se.name;
+                                       n.type       = se.type;
+
+                               cbi_bind(n, 'keydown',  cbi_dynlist_keydown);
+                               cbi_bind(n, 'keypress', cbi_dynlist_keypress);
+
+                               if (next)
+                               {
+                                       se.parentNode.insertBefore(n, next);
+                                       se.parentNode.insertBefore(document.createElement('br'), next);
+                               }
+                               else
+                               {
+                                       se.parentNode.appendChild(n);
+                                       se.parentNode.appendChild(document.createElement('br'));
+                               }
+
+                               var dt = se.getAttribute('cbi_datatype');
+                               var op = se.getAttribute('cbi_optional') == 'true';
+
+                               if (dt)
+                                       cbi_validate_field(n, op, dt);
+
+                               cbi_dynlist_renumber(n);
+                               break;
+
+                       /* arrow up */
+                       case 38:
+                               if (prev)
+                                       prev.focus();
+
+                               break;
+
+                       /* arrow down */
+                       case 40:
+                               if (next)
+                                       next.focus();
+
+                               break;
+               }
+
+               return true;
+       }
+
+       var inputs = document.getElementsByName(name);
+       for( var i = 0; i < inputs.length; i++ )
+       {
+               cbi_bind(inputs[i], 'keydown',  cbi_dynlist_keydown);
+               cbi_bind(inputs[i], 'keypress', cbi_dynlist_keypress);
+       }
+}
+
 //Hijacks the CBI form to send via XHR (requires Prototype)
 function cbi_hijack_forms(layer, win, fail, load) {
        var forms = layer.getElementsByTagName('form');
@@ -437,6 +591,8 @@ function cbi_t_switch(section, tab) {
 }
 
 function cbi_t_update() {
+       var hl_tabs = [ ];
+
        for( var sid in cbi_t )
                for( var tid in cbi_t[sid] )
                        if( cbi_c[cbi_t[sid][tid].cid] == 0 ) {
@@ -446,14 +602,24 @@ function cbi_t_update() {
                                cbi_t[sid][tid].tab.style.display = '';
 
                                var t = cbi_t[sid][tid].tab;
-                               window.setTimeout(function() { t.className = t.className.replace(/ cbi-tab-highlighted/g, '') }, 750);
-                               cbi_t[sid][tid].tab.className += ' cbi-tab-highlighted';
+                               t.className += ' cbi-tab-highlighted';
+                               hl_tabs.push(t);
                        }
+
+       if( hl_tabs.length > 0 )
+               window.setTimeout(function() {
+                       for( var i = 0; i < hl_tabs.length; i++ )
+                               hl_tabs[i].className = hl_tabs[i].className.replace(/ cbi-tab-highlighted/g, '');
+               }, 750);
 }
 
 
 function cbi_validate_form(form, errmsg)
 {
+       /* if triggered by a section removal or addition, don't validate */
+       if( form.cbi_state == 'add-section' || form.cbi_state == 'del-section' )
+               return true;
+
        if( form.cbi_validators )
        {
                for( var i = 0; i < form.cbi_validators.length; i++ )
@@ -481,12 +647,20 @@ function cbi_validate_reset(form)
 
 function cbi_validate_field(cbid, optional, type)
 {
-       var field = document.getElementById(cbid);
+       var field = (typeof cbid == "string") ? document.getElementById(cbid) : cbid;
+       var vargs;
+
+       if( type.match(/^(\w+)\(([^\(\)]+)\)/) )
+       {
+               type  = RegExp.$1;
+               vargs = RegExp.$2.split(/\s*,\s*/);
+       }
+
        var vldcb = cbi_validators[type];
 
        if( field && vldcb )
        {
-               var validator = function(reset)
+               var validator = function()
                {
                        // is not detached
                        if( field.form )
@@ -494,8 +668,10 @@ function cbi_validate_field(cbid, optional, type)
                                field.className = field.className.replace(/ cbi-input-invalid/g, '');
 
                                // validate value
-                               var value = (field.options) ? field.options[field.options.selectedIndex].value : field.value;
-                               if( !(((value.length == 0) && optional) || vldcb(value)) )
+                               var value = (field.options && field.options.selectedIndex > -1)
+                                       ? field.options[field.options.selectedIndex].value : field.value;
+
+                               if( !(((value.length == 0) && optional) || vldcb(value, vargs)) )
                                {
                                        // invalid
                                        field.className += ' cbi-input-invalid';
@@ -510,9 +686,224 @@ function cbi_validate_field(cbid, optional, type)
                        field.form.cbi_validators = [ ];
 
                field.form.cbi_validators.push(validator);
-               field.onblur = field.onkeyup = field.validate = validator;
+
+               cbi_bind(field, "blur",  validator);
+               cbi_bind(field, "keyup", validator);
+
+               if (field.nodeName == 'SELECT')
+               {
+                       cbi_bind(field, "change", validator);
+                       cbi_bind(field, "click",  validator);
+               }
+
+               field.setAttribute("cbi_validate", validator);
+               field.setAttribute("cbi_datatype", type);
+               field.setAttribute("cbi_optional", (!!optional).toString());
 
                validator();
+
+               var fcbox = document.getElementById('cbi.combobox.' + field.id);
+               if (fcbox)
+                       cbi_validate_field(fcbox, optional, type);
        }
 }
 
+if( ! String.serialize )
+       String.serialize = function(o)
+       {
+               switch(typeof(o))
+               {
+                       case 'object':
+                               // null
+                               if( o == null )
+                               {
+                                       return 'null';
+                               }
+
+                               // array
+                               else if( o.length )
+                               {
+                                       var i, s = '';
+
+                                       for( var i = 0; i < o.length; i++ )
+                                               s += (s ? ', ' : '') + String.serialize(o[i]);
+
+                                       return '[ ' + s + ' ]';
+                               }
+
+                               // object
+                               else
+                               {
+                                       var k, s = '';
+
+                                       for( k in o )
+                                               s += (s ? ', ' : '') + k + ': ' + String.serialize(o[k]);
+
+                                       return '{ ' + s + ' }';
+                               }
+
+                               break;
+
+                       case 'string':
+                               // complex string
+                               if( o.match(/[^a-zA-Z0-9_,.: -]/) )
+                                       return 'decodeURIComponent("' + encodeURIComponent(o) + '")';
+
+                               // simple string
+                               else
+                                       return '"' + o + '"';
+
+                               break;
+
+                       default:
+                               return o.toString();
+               }
+       }
+
+
+if( ! String.format )
+       String.format = function()
+       {
+               if (!arguments || arguments.length < 1 || !RegExp)
+                       return;
+
+               var html_esc = [/&/g, '&#38;', /"/g, '&#34;', /'/g, '&#39;', /</g, '&#60;', />/g, '&#62;'];
+               var quot_esc = [/"/g, '&#34;', /'/g, '&#39;'];
+
+               function esc(s, r) {
+                       for( var i = 0; i < r.length; i += 2 )
+                               s = s.replace(r[i], r[i+1]);
+                       return s;
+               }
+
+               var str = arguments[0];
+               var out = '';
+               var re = /^(([^%]*)%('.|0|\x20)?(-)?(\d+)?(\.\d+)?(%|b|c|d|u|f|o|s|x|X|q|h|j|t))/;
+               var a = b = [], numSubstitutions = 0, numMatches = 0;
+
+               while( a = re.exec(str) )
+               {
+                       var m = a[1];
+                       var leftpart = a[2], pPad = a[3], pJustify = a[4], pMinLength = a[5];
+                       var pPrecision = a[6], pType = a[7];
+
+                       numMatches++;
+
+                       if (pType == '%')
+                       {
+                               subst = '%';
+                       }
+                       else
+                       {
+                               if (numSubstitutions++ < arguments.length)
+                               {
+                                       var param = arguments[numSubstitutions];
+
+                                       var pad = '';
+                                       if (pPad && pPad.substr(0,1) == "'")
+                                               pad = leftpart.substr(1,1);
+                                       else if (pPad)
+                                               pad = pPad;
+
+                                       var justifyRight = true;
+                                       if (pJustify && pJustify === "-")
+                                               justifyRight = false;
+
+                                       var minLength = -1;
+                                       if (pMinLength)
+                                               minLength = parseInt(pMinLength);
+
+                                       var precision = -1;
+                                       if (pPrecision && pType == 'f')
+                                               precision = parseInt(pPrecision.substring(1));
+
+                                       var subst = param;
+
+                                       switch(pType)
+                                       {
+                                               case 'b':
+                                                       subst = (parseInt(param) || 0).toString(2);
+                                                       break;
+
+                                               case 'c':
+                                                       subst = String.fromCharCode(parseInt(param) || 0);
+                                                       break;
+
+                                               case 'd':
+                                                       subst = (parseInt(param) || 0);
+                                                       break;
+
+                                               case 'u':
+                                                       subst = Math.abs(parseInt(param) || 0);
+                                                       break;
+
+                                               case 'f':
+                                                       subst = (precision > -1)
+                                                               ? ((parseFloat(param) || 0.0)).toFixed(precision)
+                                                               : (parseFloat(param) || 0.0);
+                                                       break;
+
+                                               case 'o':
+                                                       subst = (parseInt(param) || 0).toString(8);
+                                                       break;
+
+                                               case 's':
+                                                       subst = param;
+                                                       break;
+
+                                               case 'x':
+                                                       subst = ('' + (parseInt(param) || 0).toString(16)).toLowerCase();
+                                                       break;
+
+                                               case 'X':
+                                                       subst = ('' + (parseInt(param) || 0).toString(16)).toUpperCase();
+                                                       break;
+
+                                               case 'h':
+                                                       subst = esc(param, html_esc);
+                                                       break;
+
+                                               case 'q':
+                                                       subst = esc(param, quot_esc);
+                                                       break;
+
+                                               case 'j':
+                                                       subst = String.serialize(param);
+                                                       break;
+
+                                               case 't':
+                                                       var td = 0;
+                                                       var th = 0;
+                                                       var tm = 0;
+                                                       var ts = (param || 0);
+
+                                                       if (ts > 60) {
+                                                               tm = Math.floor(ts / 60);
+                                                               ts = (ts % 60);
+                                                       }
+
+                                                       if (tm > 60) {
+                                                               th = Math.floor(tm / 60);
+                                                               tm = (tm % 60);
+                                                       }
+
+                                                       if (th > 24) {
+                                                               td = Math.floor(th / 24);
+                                                               th = (th % 24);
+                                                       }
+
+                                                       subst = (td > 0)
+                                                               ? String.format('%dd %dh %dm %ds', td, th, tm, ts)
+                                                               : String.format('%dh %dm %ds', th, tm, ts);
+
+                                                       break;
+                                       }
+                               }
+                       }
+
+                       out += leftpart + subst;
+                       str = str.substr(m.length);
+               }
+
+               return out + str;
+       }