X-Git-Url: https://git.archive.openwrt.org/?a=blobdiff_plain;f=libs%2Fweb%2Fhtdocs%2Fluci-static%2Fresources%2Fcbi.js;h=ac4eaa9b231c8cb08644c8185c4e1aaf371bbfc1;hb=80e1900b03b2a5315c791f9240f9d7641ae67562;hp=a00254c76e148f492c519c675210fe8f82acde96;hpb=1a3533cb8693ef81e9ce9e638e4fb24fa67b67fd;p=project%2Fluci.git diff --git a/libs/web/htdocs/luci-static/resources/cbi.js b/libs/web/htdocs/luci-static/resources/cbi.js index a00254c76..ac4eaa9b2 100644 --- a/libs/web/htdocs/luci-static/resources/cbi.js +++ b/libs/web/htdocs/luci-static/resources/cbi.js @@ -27,6 +27,16 @@ var cbi_validators = { return (cbi_validators.integer(v) && (v >= 0)); }, + 'float': function(v) + { + return !isNaN(parseFloat(v)); + }, + + 'ufloat': function(v) + { + return (cbi_validators['float'](v) && (v >= 0)); + }, + 'ipaddr': function(v) { return cbi_validators.ip4addr(v) || cbi_validators.ip6addr(v); @@ -70,34 +80,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 +164,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; + } }; @@ -274,22 +293,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 +318,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 +374,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 +402,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 +601,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 +612,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 +657,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 +678,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,12 +696,72 @@ 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); } } +function cbi_row_swap(elem, up, store) +{ + var tr = elem.parentNode; + while (tr && tr.nodeName != 'tr') + tr = tr.parentNode; + + var table = tr.parentNode; + while (table && table.nodeName != 'table') + table = table.parentNode; + + var s = up ? 3 : 2; + var e = up ? table.rows.length : table.rows.length - 1; + + for (var idx = s; idx < e; idx++) + { + if (table.rows[idx] == tr) + { + if (up) + tr.parentNode.insertBefore(table.rows[idx], table.rows[idx-1]); + else + tr.parentNode.insertBefore(table.rows[idx+1], table.rows[idx]); + + break; + } + } + + var ids = [ ]; + for (idx = 2; idx < table.rows.length; idx++) + { + table.rows[idx].className = table.rows[idx].className.replace( + /cbi-rowstyle-[12]/, 'cbi-rowstyle-' + (1 + (idx % 2)) + ); + + if (table.rows[idx].id && table.rows[idx].id.match(/-(cfg[0-9a-f]+)$/) ) + ids.push(RegExp.$1); + } + + var input = document.getElementById(store); + if (input) + input.value = ids.join(' '); + + return false; +} + if( ! String.serialize ) String.serialize = function(o) { @@ -586,7 +832,7 @@ if( ! String.format ) var str = arguments[0]; var out = ''; - var re = /^(([^%]*)%('.|0|\x20)?(-)?(\d+)?(\.\d+)?(%|b|c|d|u|f|o|s|x|X|q|h|j))/; + 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) ) @@ -647,7 +893,7 @@ if( ! String.format ) case 'f': subst = (precision > -1) - ? Math.round((parseFloat(param) || 0.0) * Math.pow(10, precision)) / Math.pow(10, precision) + ? ((parseFloat(param) || 0.0)).toFixed(precision) : (parseFloat(param) || 0.0); break; @@ -678,6 +924,33 @@ if( ! String.format ) 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; } } }