]> Dogcows Code - chaz/p5-CGI-Ex/blobdiff - lib/CGI/Ex/validate.js
CGI::Ex 2.37
[chaz/p5-CGI-Ex] / lib / CGI / Ex / validate.js
index 72cca57da30c5634834bb5c5f64cf90731a366e3..a3c0db05c4557f052f4c5a163444cd1f9a868466 100644 (file)
@@ -1,8 +1,9 @@
-// Copyright 2007 - Paul Seamons - $Revision: 1.62 $
+// Copyright 2003-2012 - Paul Seamons - ver 2.37
 // Distributed under the Perl Artistic License without warranty
 // See perldoc CGI::Ex::Validate for usage
 
 var v_did_inline  = {};
+var v_event;
 
 function ValidateError (errors, extra) {
  this.errors = errors;
@@ -17,88 +18,95 @@ function ValidateError (errors, extra) {
 
 function v_error (err) { alert (err); return 1 }
 
-function v_clean_val_hash (val_hash) {
+function v_get_ordered_fields (val_hash) {
  if (typeof(val_hash) != 'object') return {error: v_error("Validation must be an associative array (hash)")};
 
- var order  = [];
+ var ARGS = {};
+ var field_keys = [];
+ var m;
  for (var key in val_hash) {
-  if (key == 'extend') continue; // Protoype Array()
-  if (key.match(/^general\s/)) {
-    var new_key = key.replace(/^general\s+/, 'group ');
-    val_hash[new_key] = val_hash[key];
-    delete(val_hash[key]);
-    key = new_key;
+  if (!val_hash.hasOwnProperty(key)) continue;
+  if (m = key.match(/^(general|group)\s+(\w+)/)) {
+    ARGS[m[2]] = val_hash[key];
+    continue;
   }
-  order.push(key);
+  field_keys.push(key);
  }
- order = order.sort();
+ field_keys = field_keys.sort();
+
+ var f = ARGS.set_hook;   if (f && typeof(f) == 'string') eval("ARGS.set_hook = "+f);
+ f = ARGS.clear_hook;     if (f && typeof(f) == 'string') eval("ARGS.clear_hook = "+f);
+ f = ARGS.set_all_hook;   if (f && typeof(f) == 'string') eval("ARGS.set_all_hook = "+f);
+ f = ARGS.clear_all_hook; if (f && typeof(f) == 'string') eval("ARGS.clear_all_hook = "+f);
 
- var f = val_hash['group set_hook'];
if (f && typeof(f) == 'string') val_hash['group set_hook'] = eval(f);
f = val_hash['group clear_hook'];
- if (f && typeof(f) == 'string') val_hash['group clear_hook'] = eval(f);
+ if (f = ARGS.validate_if) {
  if (typeof(f) == 'string' || ! f.length) f = [f];
  var deps = v_clean_cond(f);
+ }
 
- var fields = val_hash['group fields'];
- if (fields) {
-  if (typeof(fields) != 'object' || ! fields.length)
+ var fields = [];
+ var ref;
+ if (ref = ARGS.fields || ARGS['order']) {
+  if (typeof(ref) != 'object' || ! ref.length)
    return {error:v_error("'group fields' must be a non-empty array")};
} else {
-  fields = [];
-  var _order = (val_hash['group order']) ? val_hash['group order'] : order;
-  if (typeof(_order) != 'object' || ! _order.length)
-   return {error:v_error("'group order' must be a non-empty array")};
-  for (var i = 0; i < _order.length; i++) {
-   var field = _order[i];
-   if (field.match(/^group\s/)) continue;
-   var field_val = val_hash[field];
-   if (! field_val) {
-    if (field == 'OR') field_val = 'OR';
-    else return {error:v_error('No element found in group for '+field)};
 for (var i = 0; i < ref.length; i++) {
+   var field = ref[i];
+   if (typeof(field) == 'object') {
+    if (! field.field) return {error:v_error("Missing field key in validation")};
+    fields.push(field);
+   } else if (field == 'OR') {
+    fields.push('OR');
+   } else {
+    var field_val = val_hash[field];
+    if (! field_val) return {error:v_error('No element found in group for '+field)};
+    if (typeof(field_val) == 'object' && ! field_val['field']) field_val['field'] = field;
+    fields.push(field_val);
    }
-   if (typeof(field_val) == 'object' && ! field_val['field']) field_val['field'] = field;
-   fields.push(field_val);
   }
  }
 
  var found = {};
  for (var i = 0; i < fields.length; i++) {
   var field_val = fields[i];
-  var field = field_val.field;
-  if (! field) return {error:v_error("Missing field key in validation")};
-  found[field] = 1;
+  if (typeof(field_val) != 'object') continue;
+  found[field_val.field] = 1;
  }
 
- for (var i = 0; i < order.length; i++) {
-  var field = order[i];
-  if (found[field] || field.match(/^group\s/)) continue;
+ for (var i = 0; i < field_keys.length; i++) {
+  var field = field_keys[i];
+  if (found[field]) continue;
   var field_val = val_hash[field];
-  if (typeof(field_val) != 'object' || field_val.length) {debug(val_hash);alert(field);return {error:v_error('Found a non-hash value on field '+field)};}
+  if (typeof(field_val) != 'object' || field_val.length) return {error:v_error('Found a non-hash value on field '+field)};
   if (! field_val.field) field_val.field = field;
   fields.push(field_val);
  }
 
  for (var i = 0; i < fields.length; i++) v_clean_field_val(fields[i]);
 
- return {'fields':fields, 'order':order};
+ val_hash['group was_checked'] = {};
+ val_hash['group was_valid'] = {};
+ val_hash['group had_error'] = {};
+
+ return {'fields':fields, 'args':ARGS};
 }
 
-function v_clean_field_val (field_val) {
+function v_clean_field_val (field_val, N_level) {
  if (! field_val.order) field_val.order = v_field_order(field_val);
  if (! field_val.deps) field_val.deps = {};
  for (var i = 0; i < field_val.order.length; i++) {
   var k = field_val.order[i];
   var v = field_val[k];
   if (typeof(v) == 'undefined') return {error:v_error('No matching validation found on field '+field+' for type '+k)};
-  if (k.match(/^(min|max)_in_set(\d*)$/)) {
+  if (k.match(/^(min|max)_in_set_?(\d*)$/)) {
    if (typeof(v) == 'string') {
     if (! (m = v.match(/^\s*(\d+)(?:\s*[oO][fF])?\s+(.+)\s*$/))) return {error:v_error("Invalid "+k+" check "+v)};
     field_val[k] = m[2].split(/[\s,]+/);
     field_val[k].unshift(m[1]);
    }
    for (var j = 1; j < field_val[k].length; j++) if (field_val[k][j] != field_val.field) field_val.deps[field_val[k][j]] = 1;
-  } else if (k.match(/^(enum|compare)\d*$/)) {
+  } else if (k.match(/^(enum|compare)_?\d*$/)) {
    if (typeof(v) == 'string') field_val[k] = v.split(/\s*\|\|\s*/);
-  } else if (k.match(/^match\d*$/)) {
+  } else if (k.match(/^match_?\d*$/)) {
    if (typeof(v) == 'string') v = field_val[k] = v.split(/\s*\|\|\s*/);
    for (var j = 0; j < v.length; j++) {
     if (typeof(v[j]) != 'string' || v[j] == '!') continue;
@@ -112,28 +120,57 @@ function v_clean_field_val (field_val) {
     v[j] = new RegExp(pat, opt);
     if (not) v.splice(j, 0, '!');
    }
-  } else if (k.match(/^custom_js\d*$/)) {
-   if (typeof(v) == 'string' && v.match(/^\s*function\s*/)) field_val[k] = eval(v);
+  } else if (k.match(/^custom_js_?\d*$/)) {
+   if (typeof(v) == 'string' && v.match(/^\s*function\s*\(/)) eval("field_val[k] = "+v);
+  } else if (k.match(/^(validate|required)_if_?\d*$/)) {
+    if (typeof(v) == 'string' || ! v.length) v = field_val[k] = [v];
+    var deps = v_clean_cond(v, N_level);
+    for (var k in deps) field_val.deps[k] = 2;
+  }
+ }
+}
+
+function v_clean_cond (ifs, N_level, ifs_match) {
+ if (typeof(ifs) != 'object') { v_error("Need reference v_clean_cond "+typeof(ifs)); return [] }
+ if (! N_level) N_level = 0;
+ if (++N_level > 10) { v_error("Max dependency level reached " + N_level); return [] }
+
+ var deps = {};
+ var m;
+ for (var i = 0; i < ifs.length; i++) {
+  if (typeof(ifs[i]) == 'string') {
+   if (ifs[i].match(/^\s*function\s*\(/)) eval("ifs[i] = "+ifs[i]);
+   else if (m = ifs[i].match(/^(.+?)\s+was_valid$/)) ifs[i] = {field: m[1], was_valid:1}
+   else if (m = ifs[i].match(/^(.+?)\s+had_error$/)) ifs[i] = {field: m[1], had_error:1}
+   else if (m = ifs[i].match(/^(.+?)\s+was_checked$/)) ifs[i] = {field: m[1], was_checked:1}
+   else if (m = ifs[i].match(/^(\s*!\s*)(.+)\s*$/)) ifs[i] = {field: m[2], max_in_set: [0, m[2]]};
+   else if (ifs[i] != 'OR') ifs[i] = {field: ifs[i], required: 1};
   }
+  if (typeof(ifs[i]) != 'object') continue;
+  if (! ifs[i].field) { v_error("Missing field key during validate_if"); return [] }
+  deps[ifs[i].field] = 2;
+  v_clean_field_val(ifs[i], N_level);
+  for (var k in ifs[i].deps) deps[k] = 2;
  }
+ return deps;
 }
 
 function v_validate (form, val_hash) {
- var clean  = v_clean_val_hash(val_hash);
+ var clean  = v_get_ordered_fields(val_hash);
  if (clean.error) return;
- var order  = clean.order;
  var fields = clean.fields;
 
  var ERRORS = [];
  var EXTRA  = [];
  var title       = val_hash['group title'];
- var validate_if = val_hash['group validate_if'];
- if (validate_if && ! v_check_conditional(form, validate_if)) return;
+ var v_if = val_hash['group validate_if'];
+ if (v_if && ! v_check_conditional(form, v_if, val_hash)) return;
 
  var is_found  = 1;
  var errors = [];
  var hold_error;
 
+ var chk = {};
  for (var j = 0; j < fields.length; j++) {
   var ref = fields[j];
   if (typeof(ref) != 'object' && ref == 'OR') {
@@ -142,10 +179,17 @@ function v_validate (form, val_hash) {
    continue;
   }
   is_found = 1;
-  if (! ref.field) return v_error("Missing field key during normal validation");
-  var err = v_validate_buddy(form, ref.field, ref);
-
+  var f = ref.field;
+  if (! chk[f]) {
+   chk[f] = 1;
+   val_hash['group was_checked'][f] = 1;
+   val_hash['group was_valid'][f]   = 1;
+   val_hash['group had_error'][f]   = 0;
+  }
+  var err = v_validate_buddy(form, f, ref, val_hash);
   if (err.length) {
+   val_hash['group had_error'][f] = 1;
+   val_hash['group was_valid'][f] = 0;
    if (j <= fields.length && typeof(fields[j + 1] != 'object') && fields[j + 1] == 'OR') {
     hold_error = err;
    } else {
@@ -163,59 +207,37 @@ function v_validate (form, val_hash) {
   for (var j = 0; j < errors.length; j++) ERRORS.push(errors[j]);
  }
 
- var m;
- for (var j = 0; j < order.length; j++) {
-  var field = order[j];
-  if (! (m = field.match(/^group\s+(\w+)$/))) continue;
-  if (errors.length == 0 || m[1].match(/^(field|order|title|validate_if)$/)) continue;
-   EXTRA[m[1]] = val_hash[field];
+ for (var field in clean.args) {
+  if (errors.length == 0 || field.match(/^(field|order|title|validate_if)$/)) continue;
+  EXTRA[field] = clean.args[field];
  }
 
  if (ERRORS.length) return new ValidateError(ERRORS, EXTRA);
  return;
 }
 
-function v_check_conditional (form, ifs, N_level, ifs_match) {
- if (! N_level) N_level = 0;
- N_level++;
-
- if (! ifs) return v_error("Need reference passed to check_conditional");
- if (typeof(ifs) != 'object' || ! ifs.length) ifs = [ifs];
-
- var is_found = 1;
- var m;
+function v_check_conditional (form, ifs, val_hash, ifs_match) {
+ var is_ok = 1;
  for (var i = 0; i < ifs.length; i++) {
-  var ref = ifs[i];
-  if (typeof(ref) != 'object') {
-   if (ref == 'OR') {
-    if (is_found) i++;
-    is_found = 1;
-    continue;
-   } else {
-    var field = ref;
-    ref = {};
-    if (m = field.match(/^(\s*!\s*)/)) {
-     field = field.substring(m[1].length);
-     ref.max_in_set = [0, field];
-    } else {
-     ref.required = 1;
-    }
-    ref.field = field;
-   }
+  if (typeof(ifs[i]) == 'function') {
+   if (! is_ok) break;
+   if (! ifs[i]({'form':form})) is_ok = 0;
+  } else if (typeof(ifs[i]) == 'string') {
+   if (ifs[i] != 'OR') { v_error("Found non-OR string"); return }
+   if (is_ok) i++;
+   is_ok = 1;
+   continue;
+  } else {
+   if (! is_ok) break;
+   var field = ifs[i].field;
+   field = field.replace(/\$(\d+)/g, function (all, N) {
+    return (typeof(ifs_match) != 'object' || typeof(ifs_match[N]) == 'undefined') ? '' : ifs_match[N];
+   });
+   var err = v_validate_buddy(form, field, ifs[i], val_hash);
+   if (err.length) is_ok = 0;
   }
-  if (! is_found) break;
-
-  var field = ref.field;
-  if (! field) return v_error("Missing field key during validate_if");
-  field = field.replace(/\$(\d+)/g, function (all, N) {
-   return (typeof(ifs_match) != 'object' || typeof(ifs_match[N]) == 'undefined') ? '' : ifs_match[N];
-  });
-
-  v_clean_field_val(ref);
-  var err = v_validate_buddy(form, field, ref, N_level);
-  if (err.length) is_found = 0;
  }
- return is_found;
+ return is_ok;
 }
 
 function v_filter_types (type, types) {
@@ -226,8 +248,8 @@ function v_filter_types (type, types) {
  return values;
 }
 
-function v_add_error (errors,field,type,field_val,ifs_match,form) {
- errors.push([field, type, field_val, ifs_match]);
+function v_add_error (errors,field,type,field_val,ifs_match,form,custom_err) {
+ errors.push([field, type, field_val, ifs_match, custom_err]);
  if (field_val.clear_on_error) {
   var el = form[field];
   if (el && el.type && el.type.match(/(hidden|password|text|textarea|submit)/)) el.value = '';
@@ -237,15 +259,14 @@ function v_add_error (errors,field,type,field_val,ifs_match,form) {
 
 function v_field_order (field_val) {
  var o = [];
- for (var k in field_val) if (! k.match(/^(extend|field|name)$/) && ! k.match(/_error$/)) o.push(k);
+ for (var k in field_val)
+   if (field_val.hasOwnProperty(k) && ! k.match(/^(field|name|required|was_valid|was_checked|had_error)$/) && ! k.match(/_error$/)) o.push(k);
  return o.sort();
 }
 
-function v_validate_buddy (form, field, field_val, N_level, ifs_match) {
+function v_validate_buddy (form, field, field_val, val_hash, ifs_match) {
  var errors = [];
- if (! N_level) N_level = 0;
- if (++N_level > 10) { v_error("Max dependency level reached " + N_level); return errors }
- if (! form.elements || field_val.exclude_js) return errors;
+ if (! form.elements || field_val.exclude_js) return [];
  var types = field_val.order || v_field_order(field_val);
 
  var m;
@@ -253,7 +274,7 @@ function v_validate_buddy (form, field, field_val, N_level, ifs_match) {
   var not = m[1];
   var pat = m[3];
   var opt = m[4];
-  if (opt.indexOf('e') != -1) { v_error("The e option cannot be used on field "+field); return errors }
+  if (opt.indexOf('e') != -1) { v_error("The e option cannot be used on field "+field); return [] }
   opt = opt.replace(/[sg]/g,'');
   var reg = new RegExp(pat, opt);
 
@@ -261,13 +282,17 @@ function v_validate_buddy (form, field, field_val, N_level, ifs_match) {
    var _field = form.elements[i].name;
    if (! _field) continue;
    if ( (not && ! (m = _field.match(reg))) || (m = _field.match(reg))) {
-    var err = v_validate_buddy(form, _field, field_val, N_level, m);
+    var err = v_validate_buddy(form, _field, field_val, val_hash, m);
     for (var j = 0; j < err.length; j++) errors.push(err[j]);
    }
   }
   return errors;
  }
 
+ if (field_val.was_valid   && ! val_hash['group was_valid'][field])   return v_add_error(errors, field, 'was_valid',   field_val, ifs_match, form);
+ if (field_val.had_error   && ! val_hash['group had_error'][field])   return v_add_error(errors, field, 'had_error',   field_val, ifs_match, form);
+ if (field_val.was_checked && ! val_hash['group was_checked'][field]) return v_add_error(errors, field, 'was_checked', field_val, ifs_match, form);
+
  var _value   = v_get_form_value(form[field]);
  var modified = 0;
 
@@ -285,7 +310,10 @@ function v_validate_buddy (form, field, field_val, N_level, ifs_match) {
  for (var i = 0; i < values.length; i++) {
   if (typeof(values[i]) == 'undefined') continue;
   var orig = values[i];
-  if (! field_val.do_not_trim)      values[i] = values[i].replace(/^\s+/,'').replace(/\s+$/,'');
+  if (! field_val.do_not_trim) {
+    values[i] = values[i].replace(/^\s+/,'');
+    if (v_event != 'change') values[i] = values[i].replace(/\s+$/,'');
+  }
   if (field_val.trim_control_chars) values[i] = values[i].replace(/\t/g,' ').replace(/[\x00-\x1F]/g,'');
   if (field_val.to_upper_case) values[i] = values[i].toUpperCase();
   if (field_val.to_lower_case) values[i] = values[i].toLowerCase();
@@ -300,7 +328,7 @@ function v_validate_buddy (form, field, field_val, N_level, ifs_match) {
     var pat  = m[2];
     var swap = m[3];
     var opt  = m[4];
-    if (opt.indexOf('e') != -1) { v_error("The e option cannot be used on field "+field+", replace "+tests[i]); return errors }
+    if (opt.indexOf('e') != -1) { v_error("The e option cannot be used on field "+field+", replace "+tests[i]); return [] }
     var regexp = new RegExp(pat, opt);
     values[i] = values[i].replace(regexp, swap);
    }
@@ -308,34 +336,32 @@ function v_validate_buddy (form, field, field_val, N_level, ifs_match) {
 
   if (orig != values[i]) modified = 1;
  }
- if (modified && n_values == 1) {
+ if (modified) {
   var el = form[field];
-  if (el && el.type && el.type.match(/(hidden|password|text|textarea|submit)/)) el.value = values[0];
+  if (el) v_set_form_value(el, values);
  }
 
+
  var needs_val = 0;
- var n_vif = 0;
  var tests = v_filter_types('validate_if', types);
  for (var i = 0; i < tests.length; i++) {
-  n_vif++;
   var ifs = field_val[tests[i]];
-  var ret = v_check_conditional(form, ifs, N_level, ifs_match);
+  var ret = v_check_conditional(form, ifs, val_hash, ifs_match);
   if (ret) needs_val++;
  }
- if (! needs_val && n_vif) return errors;
-
- var is_required = '';
- var tests = v_filter_types('required', types);
- for (var i = 0; i < tests.length; i++) {
-  if (! field_val[tests[i]] || field_val[tests[i]] == 0) continue;
-  is_required = tests[i];
-  break;
+ if (tests.length && ! needs_val) {
+  if (field_val.vif_disable && val_hash['group was_valid'][field]) v_set_disable(form[field], true);
+  val_hash['group was_valid'][field] = 0;
+  return [];
  }
+ if (field_val.vif_disable) v_set_disable(form[field], false);
+
+ var is_required = field_val['required'] ? 'required' : '';
  if (! is_required) {
   var tests = v_filter_types('required_if', types);
   for (var i = 0; i < tests.length; i++) {
    var ifs = field_val[tests[i]];
-   if (! v_check_conditional(form, ifs, N_level, ifs_match)) continue;
+   if (! v_check_conditional(form, ifs, val_hash, ifs_match)) continue;
    is_required = tests[i];
    break;
   }
@@ -382,19 +408,29 @@ function v_validate_buddy (form, field, field_val, N_level, ifs_match) {
   }
  }
 
- for (var i = 0; i < types.length; i++) {
-  var type = types[i];
-  var _fv  = field_val[type];
-  for (var n = 0; n < values.length; n++) {
-   var value = values[n];
+ for (var n = 0; n < values.length; n++) {
+  var value = values[n];
 
-   if (type.match(/^enum\d*$/)) {
-    var is_found = 0;
-    for (var j = 0; j < _fv.length; j++) if (value == _fv[j]) { is_found = 1; break }
-    if (! is_found) v_add_error(errors, field, type, field_val, ifs_match, form);
+  if (typeof field_val['enum'] != 'undefined') {
+   var is_found = 0;
+   for (var j = 0; j < field_val['enum'].length; j++) if (value == field_val['enum'][j]) { is_found = 1; break }
+   if (! is_found) {
+    v_add_error(errors, field, 'enum', field_val, ifs_match, form);
+    continue;
    }
+  }
 
-   if (type.match(/^equals\d*$/)) {
+  if (typeof field_val['type'] != 'undefined')
+   if (! v_check_type(value, field_val['type'], field, form)) {
+    v_add_error(errors, field, 'type', field_val, ifs_match, form);
+    continue;
+   }
+
+  for (var i = 0; i < types.length; i++) {
+   var type = types[i];
+   var _fv  = field_val[type];
+
+   if (type.match(/^equals_?\d*$/)) {
     var not = _fv.match(/^!\s*/);
     if (not) _fv = _fv.substring(not[0].length);
     var success = 0;
@@ -405,14 +441,16 @@ function v_validate_buddy (form, field, field_val, N_level, ifs_match) {
      if (typeof(value2) == 'undefined') value2 = '';
      if (value == value2) success = 1;
     }
-    if (not && success || ! not && ! success)
+    if (not && success || ! not && ! success) {
      v_add_error(errors, field, type, field_val, ifs_match, form);
+     break;
+    }
    }
 
    if (type == 'min_len' && value.length < _fv) v_add_error(errors, field, 'min_len', field_val, ifs_match, form);
    if (type == 'max_len' && value.length > _fv) v_add_error(errors, field, 'max_len', field_val, ifs_match, form);
 
-   if (type.match(/^match\d*$/)) {
+   if (type.match(/^match_?\d*$/)) {
     for (var j = 0; j < _fv.length; j++) {
      if (typeof(_fv[j]) == 'string') continue;
      var not = (j > 0 && typeof(_fv[j-1]) == 'string' && _fv[j-1] == '!') ? 1 : 0;
@@ -421,7 +459,7 @@ function v_validate_buddy (form, field, field_val, N_level, ifs_match) {
     }
    }
 
-   if (type.match(/^compare\d*$/)) {
+   if (type.match(/^compare_?\d*$/)) {
     for (var j = 0; j < _fv.length; j++) {
      var comp = _fv[j];
      if (! comp) continue;
@@ -452,19 +490,20 @@ function v_validate_buddy (form, field, field_val, N_level, ifs_match) {
      if (! hold) v_add_error(errors, field, type, field_val, ifs_match, form);
     }
    }
-
-   if (type.match(/^type\d*$/))
-    if (! v_check_type(value, _fv, field, form))
-     v_add_error(errors, field, type, field_val, ifs_match, form);
   }
+ }
 
+ for (var i = 0; i < types.length; i++) {
+  var type = types[i];
+  var _fv  = field_val[type];
   // the js is evaluated and should return 1 for success
   // or 0 for failure - the variables field, value, and field_val (the hash) are available
-  if (type.match(/^custom_js\d*$/)) {
+  if (type.match(/^custom_js_?\d*$/)) {
    var value = values.length == 1 ? values[0] : values;
-   if (typeof(_fv) == 'function'
-       ? ! _fv({'value':value, 'field_val':field_val, 'form':form, 'key':field_val.field})
-       : ! eval(_fv)) v_add_error(errors, field, type, field_val, ifs_match, form);
+   var err;
+   var ok;
+   try { ok = (typeof _fv == 'function') ? _fv({'value':value, 'field_val':field_val, 'form':form, 'key':field_val.field, 'errors':errors, 'event':v_event}) : eval(_fv) } catch (e) { err = e }
+   if (!ok) v_add_error(errors, field, type, field_val, ifs_match, form, err);
   }
  }
 
@@ -486,10 +525,8 @@ function v_check_type (value, type, field, form) {
  } else if (type == 'LOCAL_PART') {
   if (typeof(value) == 'undefined' || ! value.length) return 0;
   if (typeof(v_local_part) != 'undefined') return (value.match(v_local_part) ? 1 : 0);
-  if (value.match(/[^a-z0-9.\-!&+]/)) return 0;
-  if (value.match(/^[.\-]/))          return 0;
-  if (value.match(/[.\-&]$/))         return 0;
-  if (value.match(/(\.-|-\.|\.\.)/))  return 0;
+  // ignoring all valid quoted string local parts
+  if (value.match(/[^\w.~!\#\$%\^&*\-=+?]/)) return 0;
 
  } else if (type == 'IP') {
   if (! value) return 0;
@@ -503,12 +540,8 @@ function v_check_type (value, type, field, form) {
   if (! value.match(/^[a-z0-9.-]{4,255}$/)) return 0;
   if (value.match(/^[.\-]/))             return 0;
   if (value.match(/(\.-|-\.|\.\.)/))  return 0;
-  if (! (m = value.match(/\.([a-z]+)$/))) return 0;
-  value = value.substring(0,value.lastIndexOf('.'));
-  if (m[1] == 'name') {
-   if (! value.match(/^[a-z0-9][a-z0-9\-]{0,62}\.[a-z0-9][a-z0-9\-]{0,62}$/)) return 0;
-  } else
-   if (! value.match(/^([a-z0-9][a-z0-9\-]{0,62}\.)*[a-z0-9][a-z0-9\-]{0,62}$/)) return 0;
+  if (! (m = value.match(/^(.+\.)([a-z]{2,10})$/))) return 0;
+  if (! m[1].match(/^([a-z0-9\-]{1,63}\.)+$/)) return 0;
 
  } else if (type == 'URL') {
   if (! value) return 0;
@@ -522,6 +555,15 @@ function v_check_type (value, type, field, form) {
   if (! value) return 0;
   if (value.match(/\s/)) return 0;
 
+ } else if (type == 'INT') {
+  if (!value.match(/^-?(?:0|[1-9]\d*)$/)) return 0;
+  if ((value < 0) ? value < -Math.pow(2,31) : value > Math.pow(2,31)-1) return 0;
+ } else if (type == 'UINT') {
+  if (!value.match(/^(?:0|[1-9]\d*)$/)) return 0;
+  if (value > Math.pow(2,32)-1) return 0;
+ } else if (type == 'NUM') {
+  if (!value.match(/^-?(?:0|[1-9]\d*(?:\.\d+)?|0?\.\d+)$/)) return 0;
+
  } else if (type == 'CC') {
   if (! value) return 0;
   if (value.match(/[^\d\- ]/)) return 0;
@@ -542,10 +584,46 @@ function v_check_type (value, type, field, form) {
  return 1;
 }
 
-function v_get_form_value (el) {
- if (! el) return '';
- if (el.disabled) return '';
+function v_set_form_value (el, values, form) {
+ if (typeof(el) == 'string') el = form[el];
+ if (typeof(values) != 'object') values = [values];
+ if (! el) return;
+ var type = (el.type && ! (''+el).match(/HTMLCollection/)) ? el.type.toLowerCase() : '';
+ if (el.length && type != 'select-one') {
+  for (var i = 0; i < el.length; i++) {
+   if (! el[i] || ! el[i].type) continue;
+   v_set_form_value(el[i], (el[i].type.match(/^(checkbox|radio)$/) ? values : i < values.length ? [values[i]] : ['']));
+  }
+  return;
+ }
+ if (! type) return;
+ if (type.match(/(hidden|password|text|textarea|submit)/)) return el.value = values[0];
+ if (type.indexOf('select') != -1) {
+   if (el.length) for (var i = 0; i < el.length; i++) el[i].selected = (el[i].value == values[0]) ? true : false;
+   return;
+ }
+ if (type == 'checkbox' || type == 'radio') {
+  var f; for (var i = 0; i < values.length; i++) if (values[i] == el.value) f = 1;
+  return el.checked = f ? true : false;
+ }
+ if (type == 'file') return;
+
+ alert('Unknown form type for '+el.name+': '+type);
+ return;
+}
+
+function v_set_disable (el, disable) {
+ if (! el) return
  var type = el.type ? el.type.toLowerCase() : '';
+ if (el.length && type != 'select-one') {
+  for (var j=0;j<el.length;j++) el[i].disabled = disable;
+ } else el.disabled = disable;
+}
+
+function v_get_form_value (el, form) {
+ if (typeof(el) == 'string') el = form[el];
+ if (! el) return '';
+ var type = (el.type && ! (''+el).match(/HTMLCollection/)) ? el.type.toLowerCase() : '';
  if (el.length && type != 'select-one') {
   var a = [];
   for (var j=0;j<el.length;j++) {
@@ -563,6 +641,7 @@ function v_get_form_value (el) {
  if (type.match(/(hidden|password|text|textarea|submit)/)) return el.value;
  if (type.indexOf('select') != -1) {
   if (! el.length) return '';
+  if (el.selectedIndex == -1) return '';
   return el[el.selectedIndex].value;
  }
  if (type == 'checkbox' || type == 'radio') return el.checked ? el.value : '';
@@ -587,9 +666,11 @@ function v_get_error_text (err, extra1, extra2) {
  var type      = err[1];
  var field_val = err[2];
  var ifs_match = err[3];
- var m;
+ if (err.length == 5 && typeof err[4] != 'undefined' && err[4].length) return err[4]; // custom error from throw in custom_js
 
- var dig = (m = type.match(/(_?\d+)$/)) ? m[1] : '';
+ var m;
+ var dig = '';
+ if (m = type.match(/^(.+?)(_?\d+)$/)) { type = m[1] ; dig = m[2] }
  var type_lc = type.toLowerCase();
  var v = field_val[type + dig];
 
@@ -602,7 +683,11 @@ function v_get_error_text (err, extra1, extra2) {
   });
  }
 
- var name = field_val.name || "The field " +field;
+ var name = field_val.name;
+ if (! name && (field.match(/\W/) || (field.match(/\d/) && field.match(/\D/)))) {
+  name = "The field " +field;
+ }
+ if (! name) name = field.replace(/_/g, ' ').replace(/\b(\w)/g, function(all,str){return str.toUpperCase()});
  name = name.replace(/\$(\d+)/g, function (all, N) {
   if (typeof(ifs_match) != 'object'
     || typeof(ifs_match[N]) == 'undefined') return ''
@@ -613,6 +698,7 @@ function v_get_error_text (err, extra1, extra2) {
  if (! msg) {
    if (dig.length) msg = field_val[type + dig + '_error'];
    if (! msg)      msg = field_val[type +       '_error'];
+   if (! msg)      msg = field_val['error'];
  }
  if (msg) {
   msg = msg.replace(/\$(\d+)/g, function (all, N) {
@@ -648,6 +734,9 @@ function v_get_error_text (err, extra1, extra2) {
   : type == 'min_len'    ? " was less than "+v+" character"+(v == 1 ? '' : 's')+"."
   : type == 'max_len'    ? " was more than "+v+" character"+(v == 1 ? '' : 's')+"."
   : type == 'type'       ? " did not match type "+v+"."
+  : type == 'had_error'  ? " had no error (but should have had)."
+  : type == 'was_valid'  ? " was not valid."
+  : type == 'was_checked'? " was not checked."
   : alert("Missing error on field "+field+" for type "+type+dig));
 }
 
@@ -729,7 +818,7 @@ function eob_as_hash (extra) {
   var header = v_find_val('as_hash_header', extra, this.extra, '');
   var footer = v_find_val('as_hash_footer', extra, this.extra, '');
   for (var key in ret) {
-   if (key == 'extend') continue; // Protoype Array()
+   if (!ret.hasOwnProperty(key)) continue;
    ret[key] = header + ret[key].join(joiner) + footer;
   }
  }
@@ -752,13 +841,22 @@ document.validate = function (form, val_hash) {
  val_hash = document.load_val_hash(form, val_hash);
  if (typeof(val_hash) == 'undefined') return true;
 
- for (var key in v_did_inline) {
-  if (key == 'extend') continue; // Protoype Array()
-  v_inline_error_clear(key, val_hash, form);
+ if (v_event != 'load') {
+  for (var key in v_did_inline) {
+   if (!v_did_inline.hasOwnProperty(key)) continue;
+   v_inline_error_clear(key, val_hash, form);
+  }
  }
 
  var err_obj = v_validate(form, val_hash);
- if (! err_obj) return true;
+ if (! err_obj) {
+   var f = val_hash['group clear_all_hook'] || document.validate_clear_all_hook;
+   if (f) f();
+   return true;
+ }
+
+ var f = val_hash['group set_all_hook'] || document.validate_set_all_hook;
+ if (f) f(err_obj, val_hash, form);
 
  var field = err_obj.first_field();
  if (field && form[field]) {
@@ -769,12 +867,14 @@ document.validate = function (form, val_hash) {
  if (! val_hash['group no_inline']) {
   var hash = err_obj.as_hash({as_hash_suffix:""});
   for (var key in hash) {
-   if (key == 'extend') continue; // Protoype Array()
+   if (!hash.hasOwnProperty(key)) continue;
    v_inline_error_set(key, hash[key], val_hash, form);
   }
  }
 
- if (! val_hash['group no_confirm']) {
+ if (v_event == 'load') {
+   return false;
+ } else if (! val_hash['group no_confirm']) {
   return confirm(err_obj.as_string()) ? false : true;
  } else if (! val_hash['group no_alert']) {
   alert(err_obj.as_string());
@@ -860,7 +960,7 @@ document.check_form = function (form, val_hash) {
  val_hash['group onevent'] = types;
 
  if (types.change || types.blur) {
-  var clean = v_clean_val_hash(val_hash);
+  var clean = v_get_ordered_fields(val_hash);
   if (clean.error) return clean.error;
   var h = {};
   _add = function (k, v) { if (! h[k]) h[k] = []; h[k].push(v) };
@@ -869,57 +969,75 @@ document.check_form = function (form, val_hash) {
    for (var j in clean.fields[i].deps) if (j != clean.fields[i].field) _add(j, clean.fields[i]);
   }
   for (var k in h) {
-   if (k == 'extend') continue; // Protoype Array()
+   if (!h.hasOwnProperty(k)) continue;
    var el = form[k];
    if (! el) return v_error("No form element by the name "+k);
-   v_el_attach(el, h[k], form, val_hash);
+   var _change = !types.change ? 0 : typeof(types.change) == 'object' ? types.change[k] : 1;
+   var _blur   = !types.blur   ? 0 : typeof(types.blur)   == 'object' ? types.blur[k]   : 1;
+   v_el_attach(el, h[k], form, val_hash, _change, _blur);
   }
  }
 
  if (types.submit) {
   var orig_submit = form.onsubmit || function () { return true };
-  form.onsubmit = function (e) { return document.validate(this) && orig_submit(e, this) };
+  form.onsubmit = function (e) { v_event = 'submit'; return document.validate(this) && orig_submit(e, this) };
  }
+
+ if (types.load) { v_event = 'load'; document.validate(form) }
 }
 
-function v_el_attach (el, fvs, form, val_hash) {
+function v_el_attach (el, fvs, form, val_hash, _change, _blur) {
+ if (!_change && !_blur) return;
  if (! el.type) {
-  if (el.length) for (var i = 0; i < el.length; i++) v_el_attach(el[i], fvs, form, val_hash);
+  if (el.length) for (var i = 0; i < el.length; i++) v_el_attach(el[i], fvs, form, val_hash, _change, _blur);
   return;
  }
  var types = val_hash['group onevent'];
  var func = function () {
+  v_event = 'change';
   var e = [];
   var f = {};
+  var chk = {};
   for (var i = 0; i < fvs.length; i++) {
    var field_val = fvs[i];
-   var _e = v_validate_buddy(form, field_val.field, field_val);
-   for (var j = 0; j < _e.length; j++) e.push(_e[j]);
-   f[field_val.delegate_error || field_val.field] = 1;
-  }
-  if (! e.length) {
-    for (var k in f) v_inline_error_clear(k, val_hash, form);
-    return;
+   var k = field_val.field;
+   if (! chk[k]) {
+    chk[k] = 1;
+    val_hash['group was_checked'][k] = 1;
+    val_hash['group was_valid'][k]   = 1;
+    val_hash['group had_error'][k]   = 0;
+   }
+   var _e = v_validate_buddy(form, k, field_val, val_hash);
+   if (_e.length) {
+    val_hash['group had_error'][k] = 1;
+    val_hash['group was_valid'][k] = 0;
+    for (var j = 0; j < _e.length; j++) e.push(_e[j]);
+   }
+   f[field_val.delegate_error || field_val.field] = _e.length ? 0 : 1;
   }
+  for (var k in f) if (f[k]) v_inline_error_clear(k, val_hash, form);
+  if (! e.length) return;
   e = new ValidateError(e, {});
   e = e.as_hash({as_hash_suffix:"", first_only:(val_hash['group first_only']?1:0)});
   for (var k in e) {
-   if (k == 'extend') continue; // Protoype Array()
+   if (!e.hasOwnProperty(k)) continue;
    v_inline_error_set(k, e[k], val_hash, form);
   }
  };
- if (types.blur) el.onblur = func;
- if (types.change) {
-  if (el.type.match(/(password|text|textarea)/)) el.onkeyup = func;
-  else if (el.type.match(/(checkbox|radio)/)) el.onclick = func;
-  else if (el.type.match(/(select)/)) el.onchange = func;
+ if (_blur) el.onblur = func;
+ if (_change && ! (''+el).match(/HTMLCollection/)) { // find better way on opera
+  var type = el.type ? el.type.toLowerCase() : '';
+  if (type.match(/(password|text|textarea)/)) el.onkeyup = func;
+  else if (type.match(/(checkbox|radio)/)) el.onclick = func;
+  else if (type.match(/(select)/)) el.onchange = func;
  }
 }
 
 function v_inline_error_clear (key, val_hash, form) {
    delete(v_did_inline[key]);
    var f = val_hash['group clear_hook'] || document.validate_clear_hook;
-   if (typeof(f) == 'function') if (f(key, val_hash, form)) return 1;
+   var g = val_hash['group was_valid'] || {};
+   if (typeof(f) == 'function') if (f({'key':key, 'val_hash':val_hash, 'form':form, was_valid:g[key], 'event':v_event})) return 1;
    var el = document.getElementById(key + v_find_val('as_hash_suffix', val_hash, '_error'));
    if (el) el.innerHTML = '';
 }
@@ -927,7 +1045,7 @@ function v_inline_error_clear (key, val_hash, form) {
 function v_inline_error_set (key, val, val_hash, form) {
    v_did_inline[key] = 1;
    var f = val_hash['group set_hook'] || document.validate_set_hook;
-   if (typeof(f) == 'function') if(f(key, val, val_hash, form)) return 1;
+   if (typeof(f) == 'function') if (f({'key':key, 'value':val, 'val_hash':val_hash, 'form':form, 'event':v_event})) return 1;
    var el = document.getElementById(key + v_find_val('as_hash_suffix', val_hash, '_error'));
    if (el) el.innerHTML = val;
 }
This page took 0.040116 seconds and 4 git commands to generate.