luci-base: cbi: fix reverse field order after dependency change
[project/luci.git] / modules / luci-base / htdocs / luci-static / resources / cbi.js
index 02c54ad..8bf94a6 100644 (file)
@@ -13,7 +13,6 @@
 
 var cbi_d = [];
 var cbi_t = [];
-var cbi_c = [];
 
 var cbi_validators = {
 
@@ -139,10 +138,11 @@ var cbi_validators = {
                return (this.match(/^([a-fA-F0-9]{2}:){5}[a-fA-F0-9]{2}$/) != null);
        },
 
-       'host': function()
+       'host': function(ipv4only)
        {
                return cbi_validators.hostname.apply(this) ||
-                       cbi_validators.ipaddr.apply(this);
+                       ((ipv4only != 1) && cbi_validators.ipaddr.apply(this)) ||
+                       ((ipv4only == 1) && cb_validators.ip4addr.apply(this));
        },
 
        'hostname': function()
@@ -161,6 +161,49 @@ var cbi_validators = {
                        cbi_validators.host.apply(this);
        },
 
+       'hostport': function(ipv4only)
+       {
+               var hp = this.split(/:/);
+
+               if (hp.length == 2)
+                       return (cbi_validators.host.apply(hp[0], ipv4only) &&
+                               cbi_validators.port.apply(hp[1]));
+
+               return false;
+       },
+
+       'ip4addrport': function()
+       {
+               var hp = this.split(/:/);
+
+               if (hp.length == 2)
+                       return (cbi_validators.ipaddr.apply(hp[0]) &&
+                               cbi_validators.port.apply(hp[1]));
+               return false;
+       },
+
+       'ipaddrport': function(bracket)
+       {
+               if (this.match(/^([^\[\]:]+):([^:]+)$/)) {
+                       var addr = RegExp.$1
+                       var port = RegExp.$2
+                       return (cbi_validators.ip4addr.apply(addr) &&
+                               cbi_validators.port.apply(port));
+                } else if ((bracket == 1) && (this.match(/^\[(.+)\]:([^:]+)$/))) {
+                       var addr = RegExp.$1
+                       var port = RegExp.$2
+                       return (cbi_validators.ip6addr.apply(addr) &&
+                               cbi_validators.port.apply(port));
+                } else if ((bracket != 1) && (this.match(/^([^\[\]]+):([^:]+)$/))) {
+                       var addr = RegExp.$1
+                       var port = RegExp.$2
+                       return (cbi_validators.ip6addr.apply(addr) &&
+                               cbi_validators.port.apply(port));
+               } else {
+                       return false;
+               }
+       },
+
        'wpakey': function()
        {
                var v = this;
@@ -300,16 +343,57 @@ var cbi_validators = {
        'phonedigit': function()
        {
                return (this.match(/^[0-9\*#!\.]+$/) != null);
+       },
+       'timehhmmss': function()
+       {
+               return (this.match(/^[0-6][0-9]:[0-6][0-9]:[0-6][0-9]$/) != null);
+       },
+       'dateyyyymmdd': function()
+       {
+               if (this == null) {
+                       return false;
+               }
+               if (this.match(/^(\d\d\d\d)-(\d\d)-(\d\d)/)) {
+                       var year = RegExp.$1;
+                       var month = RegExp.$2;
+                       var day = RegExp.$2
+
+                       var days_in_month = [ 31, 28, 31, 30, 31, 30, 31, 31, 30 , 31, 30, 31 ];
+                       function is_leap_year(year) {
+                               return ((year % 4) == 0) && ((year % 100) != 0) || ((year % 400) == 0);
+                       }
+                       function get_days_in_month(month, year) {
+                               if ((month == 2) && is_leap_year(year)) {
+                                       return 29;
+                               } else {
+                                       return days_in_month[month];
+                               }
+                       }
+                       /* Firewall rules in the past don't make sense */
+                       if (year < 2015) {
+                               return false;
+                       }
+                       if ((month <= 0) || (month > 12)) {
+                               return false;
+                       }
+                       if ((day <= 0) || (day > get_days_in_month(month, year))) {
+                               return false;
+                       }
+                       return true;
+
+               } else {
+                       return false;
+               }
        }
 };
 
 
-function cbi_d_add(field, dep, next) {
-       var obj = document.getElementById(field);
+function cbi_d_add(field, dep, index) {
+       var obj = (typeof(field) === 'string') ? document.getElementById(field) : field;
        if (obj) {
                var entry
                for (var i=0; i<cbi_d.length; i++) {
-                       if (cbi_d[i].id == field) {
+                       if (cbi_d[i].id == obj.id) {
                                entry = cbi_d[i];
                                break;
                        }
@@ -317,10 +401,10 @@ function cbi_d_add(field, dep, next) {
                if (!entry) {
                        entry = {
                                "node": obj,
-                               "id": field,
+                               "id": obj.id,
                                "parent": obj.parentNode.id,
-                               "next": next,
-                               "deps": []
+                               "deps": [],
+                               "index": index
                        };
                        cbi_d.unshift(entry);
                }
@@ -383,24 +467,28 @@ function cbi_d_update() {
        var state = false;
        for (var i=0; i<cbi_d.length; i++) {
                var entry = cbi_d[i];
-               var next  = document.getElementById(entry.next)
-               var node  = document.getElementById(entry.id)
-               var parent = document.getElementById(entry.parent)
+               var node  = document.getElementById(entry.id);
+               var parent = document.getElementById(entry.parent);
 
                if (node && node.parentNode && !cbi_d_check(entry.deps)) {
                        node.parentNode.removeChild(node);
                        state = true;
-                       if( entry.parent )
-                               cbi_c[entry.parent]--;
                } else if ((!node || !node.parentNode) && cbi_d_check(entry.deps)) {
+                       var next = undefined;
+
+                       for (next = parent.firstChild; next; next = next.nextSibling) {
+                               if (next.getAttribute && parseInt(next.getAttribute('data-index'), 10) > entry.index) {
+                                       break;
+                               }
+                       }
+
                        if (!next) {
                                parent.appendChild(entry.node);
                        } else {
-                               next.parentNode.insertBefore(entry.node, next);
+                               parent.insertBefore(entry.node, next);
                        }
+
                        state = true;
-                       if( entry.parent )
-                               cbi_c[entry.parent]++;
                }
        }
 
@@ -414,6 +502,22 @@ function cbi_d_update() {
        }
 }
 
+function cbi_init() {
+       var nodes = document.querySelectorAll('[data-depends]');
+
+       for (var i = 0, node; (node = nodes[i]) !== undefined; i++) {
+               var index = parseInt(node.getAttribute('data-index'), 10);
+               var depends = JSON.parse(node.getAttribute('data-depends'));
+               if (!isNaN(index) && depends.length > 0) {
+                       for (var alt = 0; alt < depends.length; alt++) {
+                               cbi_d_add(node, depends[alt], index);
+                       }
+               }
+       }
+
+       cbi_d_update();
+}
+
 function cbi_bind(obj, type, callback, mode) {
        if (!obj.addEventListener) {
                obj.attachEvent('on' + type,
@@ -791,27 +895,6 @@ function cbi_dynlist_init(name, respath, datatype, optional, url, defpath, choic
        cbi_dynlist_redraw(NaN, -1, -1);
 }
 
-//Hijacks the CBI form to send via XHR (requires Prototype)
-function cbi_hijack_forms(layer, win, fail, load) {
-       var forms = layer.getElementsByTagName('form');
-       for (var i=0; i<forms.length; i++) {
-               $(forms[i]).observe('submit', function(event) {
-                       // Prevent the form from also submitting the regular way
-                       event.stop();
-
-                       // Submit via XHR
-                       event.element().request({
-                               onSuccess: win,
-                               onFailure: fail
-                       });
-
-                       if (load) {
-                               load();
-                       }
-               });
-       }
-}
-
 
 function cbi_t_add(section, tab) {
        var t = document.getElementById('tab.' + section + '.' + tab);
@@ -850,22 +933,24 @@ function cbi_t_update() {
        for( var sid in cbi_t )
                for( var tid in cbi_t[sid] )
                {
-                       if( cbi_c[cbi_t[sid][tid].cid] == 0 ) {
-                               cbi_t[sid][tid].tab.style.display = 'none';
-                       }
-                       else if( cbi_t[sid][tid].tab && cbi_t[sid][tid].tab.style.display == 'none' ) {
-                               cbi_t[sid][tid].tab.style.display = '';
+                       var t = cbi_t[sid][tid].tab;
+                       var c = cbi_t[sid][tid].container;
+                       var n = c.getElementsByTagName('div');
 
-                               var t = cbi_t[sid][tid].tab;
+                       if (n.length === 0) {
+                               t.style.display = 'none';
+                       }
+                       else if (t.style.display == 'none') {
+                               t.style.display = '';
                                t.className += ' cbi-tab-highlighted';
                                hl_tabs.push(t);
                        }
 
-                       cbi_tag_last(cbi_t[sid][tid].container);
+                       cbi_tag_last(c);
                        updated = true;
                }
 
-       if( hl_tabs.length > 0 )
+       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, '');