]> Dogcows Code - chaz/p5-CGI-Ex/blobdiff - lib/CGI/Ex/validate.js
CGI::Ex 2.22
[chaz/p5-CGI-Ex] / lib / CGI / Ex / validate.js
index 40b4c04d6d7f92d615df5c69fe65c9e5e7c9849e..72cca57da30c5634834bb5c5f64cf90731a366e3 100644 (file)
-/**----------------------------------------------------------------***
-*  Copyright 2007 - Paul Seamons                                     *
-*  Distributed under the Perl Artistic License without warranty      *
-*  Based upon CGI/Ex/Validate.pm v1.14 from Perl                     *
-*  For instructions on usage, see perldoc of CGI::Ex::Validate       *
-***----------------------------------------------------------------**/
-// $Revision: 1.42 $
-
-function Validate () {
- this.error             = vob_error;
- this.validate          = vob_validate;
- this.check_conditional = vob_check_conditional;
- this.filter_types      = vob_filter_types;
- this.add_error         = vob_add_error;
- this.validate_buddy    = vob_validate_buddy;
- this.check_type        = vob_check_type;
- this.get_form_value    = vob_get_form_value;
-}
+// Copyright 2007 - Paul Seamons - $Revision: 1.62 $
+// Distributed under the Perl Artistic License without warranty
+// See perldoc CGI::Ex::Validate for usage
+
+var v_did_inline  = {};
 
 function ValidateError (errors, extra) {
  this.errors = errors;
  this.extra  = extra;
-
  this.as_string = eob_as_string;
  this.as_array  = eob_as_array;
  this.as_hash   = eob_as_hash;
- this.get_error_text = eob_get_error_text;
- this.first_field    = eob_first_field;
+ this.first_field = eob_first_field;
 }
 
-///----------------------------------------------------------------///
+//
 
-function vob_error (err) {
- alert (err);
-}
-
-function vob_validate (form, val_hash) {
- if (typeof(val_hash) == 'string') {
-   if (! document.yaml_load)
-     return this.error("Cannot parse yaml string - document.yaml_load is not loaded");
-   val_hash = document.yaml_load(val_hash);
- }
+function v_error (err) { alert (err); return 1 }
 
- var ERRORS = new Array ();
- var EXTRA  = new Array ();
- //  var USED_GROUPS = new Array();
-
- // distinguishing between associative and index based arrays is harder than in perl
- if (! val_hash.length) val_hash = new Array(val_hash);
- for (var i = 0; i < val_hash.length; i ++) {
-   var group_val = val_hash[i];
-   if (typeof(group_val) != 'object' || group_val.length) return this.error("Validation groups must be a hash");
-   var title       = group_val['group title'];
-   var validate_if = group_val['group validate_if'];
-
-   if (validate_if && ! this.check_conditional(form, validate_if)) continue;
-   //    USED_GROUPS.push(group_val);
-
-   /// if the validation items were not passed as an arrayref
-   /// look for a group order and then fail back to the keys of the group
-   var fields = group_val['group fields'];
-   var order  = new Array();
-   for (var key in group_val) {
-     if (key == 'extend') continue; // Protoype Array() fix
-     order[order.length] = key;
-   }
-   order = order.sort();
-   if (fields) {
-     if (typeof(fields) != 'object' || ! fields.length)
-       return this.error("'group fields' must be a non-empty array");
-   } else {
-     fields = new Array();
-     var _order = (group_val['group order']) ? group_val['group order'] : order;
-     if (typeof(_order) != 'object' || ! _order.length)
-       return this.error("'group order' must be a non-empty array");
-     for (var j = 0; j < _order.length; j ++) {
-       var field = _order[j];
-       if (field.match('^(group|general)\\s')) continue;
-       var field_val = group_val[field];
-       if (! field_val) {
-         if (field == 'OR') field_val = 'OR';
-         else return this.error('No element found in group for '+field);
-       }
-       if (typeof(field_val) == 'object' && ! field_val['field']) field_val['field'] = field;
-       fields[fields.length] = field_val;
-     }
-   }
+function v_clean_val_hash (val_hash) {
+ if (typeof(val_hash) != 'object') return {error: v_error("Validation must be an associative array (hash)")};
 
-   /// check which fields have been used
-   var found = new Array();
-   for (var j = 0; j < fields.length; j ++) {
-     var field_val = fields[j];
-     var field = field_val['field'];
-     if (! field) return this.error("Missing field key in validation");
-     // if (found[field]) return this.error('Duplicate order found for '+field+' in group order or fields');
-     found[field] = 1;
-   }
+ var order  = [];
+ 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;
+  }
+  order.push(key);
+ }
+ order = order.sort();
 
-   /// add any remaining fields from the order
-   for (var j = 0; j < order.length; j ++) {
-     var field = order[j];
-     if (found[field] || field.match('^(group|general)\\s')) continue;
-     var field_val = group_val[field];
-     if (typeof(field_val) != 'object' || field_val.length) return this.error('Found a non-hash value on field '+field);
-     if (! field_val['field']) field_val['field'] = field;
-     fields[fields.length] = field_val;
-   }
+ 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);
 
-   /// now lets do the validation
-   var is_found  = 1;
-   var errors = new Array();
-   var hold_error;
-
-   for (var j = 0; j < fields.length; j ++) {
-     var ref = fields[j];
-     if (typeof(ref) != 'object' && ref == 'OR') {
-       if (is_found) j ++;
-       is_found = 1;
-       continue;
-     }
-     is_found = 1;
-     if (! ref['field']) return this.error("Missing field key during normal validation");
-     var err = this.validate_buddy(form, ref['field'], ref);
-
-     /// test the error - if errors occur allow for OR - if OR fails use errors from first fail
-     if (err.length) {
-       if (j <= fields.length && typeof(fields[j + 1] != 'object') && fields[j + 1] == 'OR') {
-         hold_error = err;
-       } else {
-         if (hold_error) err = hold_error;
-         for (var k = 0; k < err.length; k ++) errors[errors.length] = err[k];
-         hold_error = '';
-       }
-     } else {
-       hold_error = '';
-     }
-   }
+ var fields = val_hash['group fields'];
+ if (fields) {
+  if (typeof(fields) != 'object' || ! fields.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)};
+   }
+   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;
+ }
+
+ for (var i = 0; i < order.length; i++) {
+  var field = order[i];
+  if (found[field] || field.match(/^group\s/)) 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 (! 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};
+}
 
-   /// add on errors as requested
-   if (errors.length) {
-     if (title) ERRORS[ERRORS.length] = title;
-     for (var j = 0; j < errors.length; j ++) ERRORS[ERRORS.length] = errors[j];
-   }
+function v_clean_field_val (field_val) {
+ 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 (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*$/)) {
+   if (typeof(v) == 'string') field_val[k] = v.split(/\s*\|\|\s*/);
+  } 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;
+    var m = v[j].match(/^\s*(!\s*|)m([^\s\w])(.*)\2([eigsmx]*)\s*$/);
+    if (! m) return {error:v_error("Not sure how to parse that match ("+v[j]+")")};
+    var not = m[1];
+    var pat = m[3];
+    var opt = m[4];
+    if (opt.indexOf('e') != -1) return {error:v_error("The e option cannot be used on field "+field_val.field+", test "+k)};
+    opt = opt.replace(/[sg]/g,'');
+    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);
+  }
+ }
+}
 
-   /// add on general options, and group options if errors in group occurred
-   var m;
-   for (var j = 0; j < order.length; j ++) {
-     var field = order[j];
-     if (! (m = field.match('^(general|group)\\s+(\\w+)$'))) continue;
-     if (m[1] == 'group' && (errors.length == 0 || m[2].match('^(field|order|title)$'))) continue;
-       EXTRA[m[2]] = group_val[field];
+function v_validate (form, val_hash) {
+ var clean  = v_clean_val_hash(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 is_found  = 1;
+ var errors = [];
+ var hold_error;
+
+ for (var j = 0; j < fields.length; j++) {
+  var ref = fields[j];
+  if (typeof(ref) != 'object' && ref == 'OR') {
+   if (is_found) j++;
+   is_found = 1;
+   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);
+
+  if (err.length) {
+   if (j <= fields.length && typeof(fields[j + 1] != 'object') && fields[j + 1] == 'OR') {
+    hold_error = err;
+   } else {
+    if (hold_error) err = hold_error;
+    for (var k = 0; k < err.length; k++) errors.push(err[k]);
+    hold_error = '';
    }
+  } else {
+   hold_error = '';
+  }
  }
 
- /// store any extra items from self
- for (var key in this) {
-   if (key == 'extend') continue; // Protoype Array() fix
-   if (! key.match('_error$')
-       && ! key.match('^(raise_error|as_hash_\\w+|as_array_\\w+|as_string_\\w+)$')) continue;
-   EXTRA[key] = this[key];
+ if (errors.length) {
+  if (title) ERRORS.push(title);
+  for (var j = 0; j < errors.length; j++) ERRORS.push(errors[j]);
  }
 
- /// allow for checking for unused keys
- // if (EXTRA['no_extra_fields'])
- // won't do anything about this for now - let the server handle it
+ 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];
+ }
 
- /// return what they want
  if (ERRORS.length) return new ValidateError(ERRORS, EXTRA);
  return;
 }
 
-
-/// allow for optional validation on groups and on individual items
-function vob_check_conditional (form, ifs, N_level, ifs_match) {
-
+function v_check_conditional (form, ifs, N_level, ifs_match) {
  if (! N_level) N_level = 0;
- N_level ++;
-
- /// can pass a single hash - or an array ref of hashes
- if (! ifs) {
-   return this.error("Need reference passed to check_conditional");
- } else if (typeof(ifs) != 'object') {
-   ifs = new Array(ifs);
- } else if (! ifs.length) { // turn hash into array of hash
-   ifs = new Array(ifs);
- }
+ N_level++;
+
+ if (! ifs) return v_error("Need reference passed to check_conditional");
+ if (typeof(ifs) != 'object' || ! ifs.length) ifs = [ifs];
 
- /// run the if options here
- /// multiple items can be passed - all are required unless OR is used to separate
  var is_found = 1;
  var m;
- 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 = new Array();
-       if (m = field.match('^(\\s*!\\s*)')) {
-         field = field.substring(m[1].length);
-         ref['max_in_set'] = '0 of ' + field;
-       } else {
-         ref['required'] = 1;
-       }
-       ref['field'] = field;
-     }
-   }
-   if (! is_found) break;
-
-   /// get the field - allow for custom variables based upon a match
-   var field = ref['field'];
-   if (! field) return this.error("Missing field key during validate_if");
-   field = field.replace(new RegExp('\\$(\\d+)','g'), function (all, N) {
-     if (typeof(ifs_match) != 'object'
-         || typeof(ifs_match[N]) == 'undefined') return ''
-     return ifs_match[N];
-   });
-
-   var err = this.validate_buddy(form, field, ref, N_level);
-   if (err.length) is_found = 0;
+ 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 (! 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;
 }
 
-function vob_filter_types (type, types) {
- var values = new Array();
+function v_filter_types (type, types) {
+ var values = [];
  var regexp = new RegExp('^'+type+'_?\\d*$');
  for (var i = 0; i < types.length; i++)
-   if (types[i].match(regexp)) values[values.length] = types[i];
+  if (types[i].match(regexp)) values.push(types[i]);
  return values;
 }
 
-function vob_add_error (errors,field,type,field_val,ifs_match,form) {
- errors[errors.length] = new Array(field, type, field_val, ifs_match);
- if (field_val['clear_on_error']) {
-   var el = form[field];
-   if (el) {
-     var type = el.type;
-     if (type && (type == 'hidden' || type == 'password' || type == 'text' || type == 'textarea' || type == 'submit'))
-       el.value = '';
-   }
+function v_add_error (errors,field,type,field_val,ifs_match,form) {
+ errors.push([field, type, field_val, ifs_match]);
+ if (field_val.clear_on_error) {
+  var el = form[field];
+  if (el && el.type && el.type.match(/(hidden|password|text|textarea|submit)/)) el.value = '';
  }
+ return errors;
 }
 
-/// this is where the main checking goes on
-function vob_validate_buddy (form, field, field_val, N_level, ifs_match) {
- if (! N_level) N_level = 0;
- if (++ N_level > 10) return this.error("Max dependency level reached " + N_level);
- if (! form.elements) return;
-
- var errors = new Array();
- var types  = new Array();
- for (var key in field_val) {
-   if (key == 'extend') continue; // Protoype Array() fix
-   types[types.length] = key;
- }
- types = types.sort();
+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);
+ return o.sort();
+}
 
- /// allow for not running some tests in the cgi
- if (this.filter_types('exclude_js', types).length) return errors;
+function v_validate_buddy (form, field, field_val, N_level, 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;
+ var types = field_val.order || v_field_order(field_val);
 
- /// allow for field names that contain regular expressions
  var m;
- if (m = field.match('^(!\\s*|)m([^\\s\\w])(.*)\\2([eigsmx]*)$')) {
-   var not = m[1];
-   var pat = m[3];
-   var opt = m[4];
-   if (opt.indexOf('e') != -1) return this.error("The e option cannot be used on field "+field);
-   opt = opt.replace(new RegExp('[sg]','g'),'');
-   var reg = new RegExp(pat, opt);
-
-   var keys = new Array();
-   for (var i = 0; i < form.elements.length; i ++) {
-     var _field = form.elements[i].name;
-     if (! _field) continue;
-     if ( (not && ! (m = _field.match(reg))) || (m = _field.match(reg))) {
-       var err = this.validate_buddy(form, _field, field_val, N_level, m);
-       for (var j = 0; j < err.length; j ++) errors[errors.length] = err[j];
-     }
-   }
-   return errors;
- }
+ if (m = field.match(/^(!\s*|)m([^\s\w])(.*)\2([eigsmx]*)$/)) {
+  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 }
+  opt = opt.replace(/[sg]/g,'');
+  var reg = new RegExp(pat, opt);
+
+  for (var i = 0; i < form.elements.length; i++) {
+   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);
+    for (var j = 0; j < err.length; j++) errors.push(err[j]);
+   }
+  }
+  return errors;
+ }
+
+ var _value   = v_get_form_value(form[field]);
+ var modified = 0;
 
- var _value = this.get_form_value(form[field]);
- var values;
- if (typeof(_value) == 'object') {
-   values = _value;
- } else {
-   values = new Array();
-   values[values.length] = _value;
+ if (typeof(field_val['default']) != 'undefined'
+     && (typeof(_value) == 'undefined'
+         || (typeof(_value) == 'object' && _value.length == 0)
+         || ! _value.length)) {
+  _value = field_val['default'];
+  modified = 1;
  }
- var n_values = (typeof(_value) == 'undefined') ? 0 : values.length;
 
- /// allow for default value
- var tests = this.filter_types('default', types);
- if (n_values == 0 || (n_values == 1 && values[0].length == 0)) {
-   for (var i = 0; i < tests.length; i ++) {
-     var el = form[field];
-     if (! el) continue;
-     var type = el.type;
-     if (type && (type == 'hidden' || type == 'password' || type == 'text' || type == 'textarea' || type == 'submit'))
-       el.value = values[0] = '' + field_val[tests[i]];
-   }
- }
+ var values   = (typeof(_value) == 'object') ? _value : [_value];
+ var n_values = (typeof(_value) == 'undefined') ? 0 : values.length;
 
- /// allow for a few form modifiers
- var modified = 0;
- for (var i = 0; i < values.length; i ++) {
-   if (typeof(values[i]) == 'undefined') continue;
-   if (! this.filter_types('do_not_trim',types).length)
-     values[i] = values[i].replace('^\\s+','').replace(new RegExp('\\s+$',''),'');
-   if (this.filter_types('trim_control_chars',types).length)
-     values[i] = values[i].replace(new RegExp('\t', 'g'),' ').replace(new RegExp('[\\x00-\\x1F]+','g'),'');
-   if (this.filter_types('to_upper_case',types).length) {
-     values[i] = values[i].toUpperCase();
-   } else if (this.filter_types('to_lower_case',types).length) {
-     values[i] = values[i].toLowerCase();
-   }
- }
- var tests = this.filter_types('replace', types);
- for (var i = 0; i < tests.length; i ++) {
-   var ref = field_val[tests[i]];
-   ref = (typeof(ref) == 'object') ? ref : ref.split(new RegExp('\\s*\\|\\|\\s*'));
-   for (var j = 0; j < ref.length; j ++) {
-     if (! (m = ref[j].match('^\\s*s([^\\s\\w])(.+)\\1(.*)\\1([eigmx]*)$')))
-       return this.error("Not sure how to parse that replace "+ref[j]);
-     var pat  = m[2];
-     var swap = m[3];
-     var opt  = m[4];
-     if (opt.indexOf('e') != -1)
-       return this.error("The e option cannot be used on field "+field+", replace "+tests[i]);
-     var regexp = new RegExp(pat, opt);
-     for (var k = 0; k < values.length; k ++) {
-       if (values[k].match(regexp)) modified = 1;
-       values[k] = values[k].replace(regexp,swap);
-     }
-   }
+ 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.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();
+
+  var tests = v_filter_types('replace', types);
+  for (var k = 0; k < tests.length; k++) {
+   var ref = field_val[tests[k]];
+   ref = (typeof(ref) == 'object') ? ref : ref.split(/\s*\|\|\s*/);
+   for (var j = 0; j < ref.length; j++) {
+    if (! (m = ref[j].match(/^\s*s([^\s\w])(.+)\1(.*)\1([eigmx]*)$/)))
+     return v_error("Not sure how to parse that replace "+ref[j]);
+    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 }
+    var regexp = new RegExp(pat, opt);
+    values[i] = values[i].replace(regexp, swap);
+   }
+  }
+
+  if (orig != values[i]) modified = 1;
  }
  if (modified && n_values == 1) {
-   var el = form[field];
-   var type = el.type;
-   if (! type) return '';
-   if (type == 'hidden' || type == 'password' || type == 'text' || type == 'textarea' || type == 'submit')
-     el.value = values[0];
+  var el = form[field];
+  if (el && el.type && el.type.match(/(hidden|password|text|textarea|submit)/)) el.value = values[0];
  }
 
- /// only continue if a validate_if is not present or passes test
  var needs_val = 0;
  var n_vif = 0;
- var tests = this.filter_types('validate_if', types);
- for (var i = 0; i < tests.length; i ++) {
-   n_vif ++;
-   var ifs = field_val[tests[i]];
-   var ret = this.check_conditional(form, ifs, N_level, ifs_match);
-   if (ret) needs_val ++;
+ 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);
+  if (ret) needs_val++;
  }
  if (! needs_val && n_vif) return errors;
 
- /// check for simple existence
- /// optionally check only if another condition is met
  var is_required = '';
- var tests = this.filter_types('required', types);
- for (var i = 0; i < tests.length; i ++) {
-   if (! field_val[tests[i]] || field_val[tests[i]] == 0) continue;
+ 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 (! 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;
    is_required = tests[i];
    break;
+  }
  }
- if (! is_required) {
-   var tests = this.filter_types('required_if', types);
-   for (var i = 0; i < tests.length; i ++) {
-     var ifs = field_val[tests[i]];
-     if (! this.check_conditional(form, ifs, N_level, ifs_match)) continue;
-     is_required = tests[i];
-     break;
+ if (is_required) {
+  var found;
+  for (var i = 0; i < values.length; i++) {
+   if (values[i].length) {
+    found = 1;
+    break;
    }
- }
- if (is_required && (typeof(_value) == 'undefined'
-                     || ((typeof(_value) == 'object' && _value.length == 0)
-                         || ! _value.length))) {
-   this.add_error(errors, field, is_required, field_val, ifs_match, form);
-   return errors;
+  }
+  if (! found) return v_add_error(errors, field, is_required, field_val, ifs_match, form);
  }
 
- /// min values check
- var tests = this.filter_types('min_values', types);
- for (var i = 0; i < tests.length; i ++) {
-   var n = field_val[tests[i]];
-   if (n_values < n) {
-     this.add_error(errors, field, tests[i], field_val, ifs_match, form);
-     return errors;
-   }
- }
+ if (field_val.min_values && n_values < field_val.min_values)
+  return v_add_error(errors, field, 'min_values', field_val, ifs_match, form);
 
- /// max values check
- var tests = this.filter_types('max_values', types);
- if (! tests.length) {
-   tests[tests.length] = 'max_values';
-   field_val['max_values'] = 1;
- }
- for (var i = 0; i < tests.length; i ++) {
-   var n = field_val[tests[i]];
-   if (n_values > n) {
-     this.add_error(errors, field, tests[i], field_val, ifs_match, form);
-     return errors;
-   }
- }
+ if (typeof(field_val.max_values) == 'undefined') field_val.max_values = 1;
+ if (field_val.max_values && n_values > field_val.max_values)
+  return v_add_error(errors, field, 'max_values', field_val, ifs_match, form);
 
- /// min_in_set and max_in_set check
  for (var h = 0; h < 2 ; h++) {
-   var minmax = (h == 0) ? 'min' : 'max';
-   var tests = this.filter_types(minmax+'_in_set', types);
-   for (var i = 0; i < tests.length; i ++) {
-     if (! (m = field_val[tests[i]].match('^\\s*(\\d+)(?:\\s*[oO][fF])?\\s+(.+)\\s*$')))
-       return this.error("Invalid in_set check "+field_val[tests[i]]);
-     var n       = m[1];
-     var _fields = m[2].split(new RegExp('[\\s,]+'));
-     for (var k = 0; k < _fields.length; k ++) {
-       var _value = this.get_form_value(form[_fields[k]]);
-       var _values;
-       if (typeof(_value) == 'undefined') continue;
-       if (typeof(_value) == 'object') {
-         _values = _value;
-       } else {
-         _values = new Array();
-         _values[_values.length] = _value;
-       }
-       for (var l = 0; l < _values.length; l ++) {
-         var _value = _values[l];
-         if (typeof(_value) != 'undefined' && _value.length) n --;
-       }
-     }
-     if (   (minmax == 'min' && n > 0)
-         || (minmax == 'max' && n < 0)) {
-       this.add_error(errors, field, tests[i], field_val, ifs_match, form);
-       return errors;
-     }
-   }
- }
-
- // the remaining tests operate on each value of a field
- for (var n = 0; n < values.length; n ++) {
+  var minmax = (h == 0) ? 'min' : 'max';
+  var tests = v_filter_types(minmax+'_in_set', types);
+  for (var i = 0; i < tests.length; i++) {
+   var a = field_val[tests[i]];
+   var n = a[0];
+   for (var k = 1; k < a.length; k++) {
+    var _value = v_get_form_value(form[a[k]]);
+    var _values;
+    if (typeof(_value) == 'undefined') continue;
+    _values = (typeof(_value) == 'object') ? _value : [_value];
+    for (var l = 0; l < _values.length; l++) {
+     var _value = _values[l];
+     if (typeof(_value) != 'undefined' && _value.length) n--;
+    }
+   }
+   if (   (minmax == 'min' && n > 0)
+     || (minmax == 'max' && n < 0)) {
+    v_add_error(errors, field, tests[i], field_val, ifs_match, form);
+    return errors;
+   }
+  }
+ }
+
+ 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];
 
-   /// allow for enum types
-   var tests = this.filter_types('enum', types);
-   for (var i = 0; i < tests.length; i ++) {
-     var hold  = field_val[tests[i]];
-     var _enum = (typeof(hold) == 'object') ? hold : hold.split(new RegExp('\\s*\\|\\|\\s*'));
-     var is_found = 0;
-     for (var j = 0; j < _enum.length; j ++) {
-       if (value != _enum[j]) continue;
-       is_found = 1;
-       break;
-     }
-     if (! is_found) this.add_error(errors, field, tests[i], field_val, ifs_match, form);
-   }
-
-   /// field equality test
-   var tests = this.filter_types('equals', types);
-   for (var i = 0; i < tests.length; i ++) {
-     var field2  = field_val[tests[i]];
-     var not = field2.match('^!\\s*');
-     if (not) field2 = field2.substring(not[0].length);
-     var success = 0;
-     if (m = field2.match('^(["\'])(.*)\\1$')) {
-       if (value == m[2]) success = 1;
+   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 (type.match(/^equals\d*$/)) {
+    var not = _fv.match(/^!\s*/);
+    if (not) _fv = _fv.substring(not[0].length);
+    var success = 0;
+    if (m = _fv.match(/^([\"\'])(.*)\1$/)) {
+     if (value == m[2]) success = 1;
+    } else {
+     var value2 = v_get_form_value(form[_fv]);
+     if (typeof(value2) == 'undefined') value2 = '';
+     if (value == value2) success = 1;
+    }
+    if (not && success || ! not && ! success)
+     v_add_error(errors, field, type, field_val, ifs_match, form);
+   }
+
+   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*$/)) {
+    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;
+     if (   (  not &&   value.match(_fv[j]))
+         || (! not && ! value.match(_fv[j]))) v_add_error(errors, field, type, field_val, ifs_match, form);
+    }
+   }
+
+   if (type.match(/^compare\d*$/)) {
+    for (var j = 0; j < _fv.length; j++) {
+     var comp = _fv[j];
+     if (! comp) continue;
+     var hold = false;
+     var copy = value;
+     if (m = comp.match(/^\s*(>|<|[><!=]=)\s*([\d\.\-]+)\s*$/)) {
+      if (! copy) copy = 0;
+      copy *= 1;
+      if      (m[1] == '>' ) hold = (copy >  m[2])
+      else if (m[1] == '<' ) hold = (copy <  m[2])
+      else if (m[1] == '>=') hold = (copy >= m[2])
+      else if (m[1] == '<=') hold = (copy <= m[2])
+      else if (m[1] == '!=') hold = (copy != m[2])
+      else if (m[1] == '==') hold = (copy == m[2])
+     } else if (m = comp.match(/^\s*(eq|ne|gt|ge|lt|le)\s+(.+?)\s*$/)) {
+      if (     m[2].match(/^\"/)) m[2] = m[2].replace(/^"(.*)"$/,'$1');
+      else if (m[2].match(/^\'/)) m[2] = m[2].replace(/^'(.*)'$/,'$1');
+      if      (m[1] == 'gt') hold = (copy >  m[2])
+      else if (m[1] == 'lt') hold = (copy <  m[2])
+      else if (m[1] == 'ge') hold = (copy >= m[2])
+      else if (m[1] == 'le') hold = (copy <= m[2])
+      else if (m[1] == 'ne') hold = (copy != m[2])
+      else if (m[1] == 'eq') hold = (copy == m[2])
      } else {
-       var value2 = this.get_form_value(form[field2]);
-       if (typeof(value2) == 'undefined') value2 = '';
-       if (value == value2) success = 1;
-     }
-     if (not && success || ! not && ! success)
-       this.add_error(errors, field, tests[i], field_val, ifs_match, form);
-   }
-
-   /// length min check
-   var tests = this.filter_types('min_len', types);
-   for (var i = 0; i < tests.length; i ++) {
-     var n = field_val[tests[i]];
-     if (value.length < n) this.add_error(errors, field, tests[i], field_val, ifs_match, form);
-   }
-
-   /// length max check
-   var tests = this.filter_types('max_len', types);
-   for (var i = 0; i < tests.length; i ++) {
-     var n = field_val[tests[i]];
-     if (value.length > n) this.add_error(errors, field, tests[i], field_val, ifs_match, form);
-   }
-
-   /// now do match types
-   var tests = this.filter_types('match', types);
-   for (var i = 0; i < tests.length; i ++) {
-     var ref = field_val[tests[i]];
-     ref = (typeof(ref) == 'object') ? ref
-       : (typeof(ref) == 'function') ? new Array(ref)
-       : ref.split(new RegExp('\\s*\\|\\|\\s*'));
-     for (var j = 0; j < ref.length; j ++) {
-       if (typeof(ref[j]) == 'function') {
-         if (! value.match(ref[j])) this.add_error(errors, field, tests[i], field_val, ifs_match, form);
-       } else {
-         if (! (m = ref[j].match('^\\s*(!\\s*|)m([^\\s\\w])(.*)\\2([eigsmx]*)\\s*$')))
-           return this.error("Not sure how to parse that match ("+ref[j]+")");
-         var not = m[1];
-         var pat = m[3];
-         var opt = m[4];
-         if (opt.indexOf('e') != -1)
-           return this.error("The e option cannot be used on field "+field+", test "+tests[i]);
-         opt = opt.replace(new RegExp('[sg]','g'),'');
-         var regexp = new RegExp(pat, opt);
-         if (   (  not &&   value.match(regexp))
-             || (! not && ! value.match(regexp))) {
-           this.add_error(errors, field, tests[i], field_val, ifs_match, form);
-         }
-       }
+      v_error("Not sure how to compare \""+comp+"\"");
+      return errors;
      }
+     if (! hold) v_add_error(errors, field, type, field_val, ifs_match, form);
+    }
    }
 
-   /// allow for comparison checks
-   var tests = this.filter_types('compare', types);
-   for (var i = 0; i < tests.length; i ++) {
-     var ref = field_val[tests[i]];
-     ref = (typeof(ref) == 'object') ? ref : ref.split(new RegExp('\\s*\\|\\|\\s*'));
-     for (var j = 0; j < ref.length; j ++) {
-       var comp = ref[j];
-       if (! comp) continue;
-       var hold = false;
-       var copy = value;
-       if (m = comp.match('^\\s*(>|<|[><!=]=)\\s*([\\d\.\-]+)\\s*$')) {
-         if (! copy) copy = 0;
-         copy *= 1;
-         if      (m[1] == '>' ) hold = (copy >  m[2])
-         else if (m[1] == '<' ) hold = (copy <  m[2])
-         else if (m[1] == '>=') hold = (copy >= m[2])
-         else if (m[1] == '<=') hold = (copy <= m[2])
-         else if (m[1] == '!=') hold = (copy != m[2])
-         else if (m[1] == '==') hold = (copy == m[2])
-       } else if (m = comp.match('^\\s*(eq|ne|gt|ge|lt|le)\\s+(.+?)\\s*$')) {
-         m[2] = m[2].replace('^(["\'])(.*)\\1$','$1');
-         if      (m[1] == 'gt') hold = (copy >  m[2])
-         else if (m[1] == 'lt') hold = (copy <  m[2])
-         else if (m[1] == 'ge') hold = (copy >= m[2])
-         else if (m[1] == 'le') hold = (copy <= m[2])
-         else if (m[1] == 'ne') hold = (copy != m[2])
-         else if (m[1] == 'eq') hold = (copy == m[2])
-       } else {
-         return this.error("Not sure how to compare \""+comp+"\"");
-       }
-       if (! hold) this.add_error(errors, field, tests[i], 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);
+  }
 
-   /// do specific type checks
-   var tests = this.filter_types('type',types);
-   for (var i = 0; i < tests.length; i ++)
-     if (! this.check_type(value, field_val[tests[i]], field, form))
-       this.add_error(errors, field, tests[i], field_val, ifs_match, form);
-
-   /// do custom_js type checks
-   // this will allow for a custom piece of javascript
-   // 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
-   var tests = this.filter_types('custom_js',types);
-   for (var i = 0; i < tests.length; i ++)
-     if (! eval(field_val[tests[i]]))
-       this.add_error(errors, field, tests[i], field_val, ifs_match, form);
+  // 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*$/)) {
+   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);
+  }
  }
 
- /// all done - time to return
  return errors;
 }
 
-/// used to validate specific types
-function vob_check_type (value, type, field, form) {
+function v_check_type (value, type, field, form) {
  var m;
+ type = type.toUpperCase();
 
- /// do valid email address for our system
  if (type == 'EMAIL') {
-   if (! value) return 0;
-   if (! (m = value.match('^(.+)\@(.+?)$'))) return 0;
-   if (m[1].length > 60)  return 0;
-   if (m[2].length > 100) return 0;
-   if (! this.check_type(m[2],'DOMAIN') && ! this.check_type(m[2],'IP')) return 0;
-   if (! this.check_type(m[1],'LOCAL_PART')) return 0;
-
- /// the "username" portion of an email address
+  if (! value) return 0;
+  if (! (m = value.match(/^(.+)@(.+?)$/))) return 0;
+  if (m[1].length > 60)  return 0;
+  if (m[2].length > 100) return 0;
+  if (! v_check_type(m[2],'DOMAIN') && ! v_check_type(m[2],'IP')) return 0;
+  if (! v_check_type(m[1],'LOCAL_PART')) return 0;
+
  } else if (type == 'LOCAL_PART') {
-   if (typeof(value) == 'undefined' || ! value.length) return 0;
-   if (value.match('[^a-z0-9.\\-!&+]'))   return 0;
-   if (value.match('^[.\\-]'))            return 0;
-   if (value.match('[.\\-&]$'))           return 0;
-   if (value.match('(\\.-|-\\.|\\.\\.)')) return 0;
+  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;
 
- /// standard IP address
  } else if (type == 'IP') {
-   if (! value) return 0;
-   var dig = value.split(new RegExp('\\.'));
-   if (dig.length != 4) return 0;
-   for (var i = 0; i < 4; i ++)
-     if (typeof(dig[i]) == 'undefined' || dig[i].match('\\D') || dig[i] > 255) return 0;
+  if (! value) return 0;
+  var dig = value.split(/\./);
+  if (dig.length != 4) return 0;
+  for (var i = 0; i < 4; i++)
+   if (typeof(dig[i]) == 'undefined' || dig[i].match(/\D/) || dig[i] > 255) return 0;
 
- /// domain name - including tld and subdomains (which are all domains)
  } else if (type == 'DOMAIN') {
-   if (! value) return 0;
-   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;
-
- /// validate a url
+  if (! value) return 0;
+  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;
+
  } else if (type == 'URL') {
-   if (! value) return 0;
-   if (! (m = value.match(new RegExp('^https?://([^/]+)','i'),''))) return 0;
-   value = value.substring(m[0].length);
-   if (! this.check_type(m[1],'DOMAIN') && ! this.check_type(m[1],'IP')) return 0;
-   if (value && ! this.check_type(value,'URI')) return 0;
+  if (! value) return 0;
+  if (! (m = value.match(/^https?:\/\/([^\/]+)/i))) return 0;
+  value = value.substring(m[0].length);
+  var dom = m[1].replace(/:\d+$/).replace(/\.$/);
+  if (! v_check_type(dom,'DOMAIN') && ! v_check_type(m[1],'IP')) return 0;
+  if (value && ! v_check_type(value,'URI')) return 0;
 
- /// validate a uri - the path portion of a request
  } else if (type == 'URI') {
-   if (! value) return 0;
-   if (value.match('\\s')) return 0;
+  if (! value) return 0;
+  if (value.match(/\s/)) return 0;
 
  } else if (type == 'CC') {
-   if (! value) return 0;
-   if (value.match('[^\\d\\- ]') || value.length > 16 || value.length < 13) return;
-   /// simple mod10 check
-   value = value.replace(new RegExp('[\\- ]','g'), '');
-   var sum = 0;
-   var swc = 0;
-
-   for (var i = value.length - 1; i >= 0; i --) {
-     if (++ swc > 2) swc = 1;
-     var y = value.charAt(i) * swc;
-     if (y > 9) y -= 9;
-     sum += y;
-   }
-   if (sum % 10) return 0;
-
+  if (! value) return 0;
+  if (value.match(/[^\d\- ]/)) return 0;
+  value = value.replace(/[\- ]/g, '');
+  if (value.length > 16 || value.length < 13) return 0;
+  // mod10
+  var sum = 0;
+  var swc = 0;
+  for (var i = value.length - 1; i >= 0; i--) {
+   if (++swc > 2) swc = 1;
+   var y = value.charAt(i) * swc;
+   if (y > 9) y -= 9;
+   sum += y;
+  }
+  if (sum % 10) return 0;
  }
 
  return 1;
 }
 
-// little routine that will get the values from the form
-// it will return multiple values as an array
-function vob_get_form_value (el) {
+function v_get_form_value (el) {
  if (! el) return '';
  if (el.disabled) return '';
  var type = el.type ? el.type.toLowerCase() : '';
  if (el.length && type != 'select-one') {
-   var a = new Array();
-   for (var j=0;j<el.length;j++) {
-     if (type.indexOf('multiple') != -1) {
-       if (el[j].selected) a[a.length] = el[j].value;
-     } else {
-       if (el[j].checked)  a[a.length] = vob_get_form_value(el[j]);
-     }
+  var a = [];
+  for (var j=0;j<el.length;j++) {
+   if (type.indexOf('multiple') != -1) {
+    if (el[j].selected) a.push(el[j].value);
+   } else {
+    if (el[j].checked)  a.push(v_get_form_value(el[j]));
    }
-   if (a.length == 0) return '';
-   if (a.length == 1) return a[0];
-   return a;
+  }
+  if (a.length == 0) return '';
+  if (a.length == 1) return a[0];
+  return a;
  }
  if (! type) return '';
- if (type == 'hidden' || type == 'password' || type == 'text' || type == 'textarea' || type == 'submit')
-   return el.value;
+ if (type.match(/(hidden|password|text|textarea|submit)/)) return el.value;
  if (type.indexOf('select') != -1) {
-   if (! el.length) return '';
-   return el[el.selectedIndex].value;
- }
- if (type == 'checkbox' || type == 'radio') {
-   return el.checked ? el.value : '';
- }
- if (type == 'file') {
-   return el.value; // hope this works
+  if (! el.length) return '';
+  return el[el.selectedIndex].value;
  }
+ if (type == 'checkbox' || type == 'radio') return el.checked ? el.value : '';
+ if (type == 'file') return el.value;
+
  alert('Unknown form type for '+el.name+': '+type);
  return '';
 }
 
-///----------------------------------------------------------------///
-
-function eob_get_val (key, extra2, extra1, _default) {
- if (typeof(extra2[key]) != 'undefined') return extra2[key];
- if (typeof(extra1[key]) != 'undefined') return extra1[key];
- return _default;
-}
-
-function eob_as_string (extra2) {
- var extra1 = this.extra;
- if (! extra2) extra2 = new Array();
-
- var joiner = eob_get_val('as_string_join',   extra2, extra1, '\n');
- var header = eob_get_val('as_string_header', extra2, extra1, '');
- var footer = eob_get_val('as_string_footer', extra2, extra1, '');
-
- return header + this.as_array(extra2).join(joiner) + footer;
-}
-
-/// return an array of applicable errors
-function eob_as_array (extra2) {
- var errors = this.errors;
- var extra1 = this.extra;
- if (! extra2) extra2 = new Array();
-
- var title = eob_get_val('as_array_title', extra2, extra1, 'Please correct the following items:');
-
- /// if there are heading items then we may end up needing a prefix
- var has_headings;
- if (title) has_headings = 1;
- else {
-   for (var i = 0; i < errors.length; i ++) {
-     if (typeof(errors[i]) != 'string') continue;
-     has_headings = 1;
-     break;
-   }
- }
-
- var prefix = eob_get_val('as_array_prefix', extra2, extra1, has_headings ? '  ' : '');
-
- /// get the array ready
- var arr = new Array();
- if (title && title.length) arr[arr.length] = title;
- /// add the errors
- var found = new Array();
- for (var i = 0; i < errors.length; i ++) {
-   if (typeof(errors[i]) == 'string') {
-     arr[arr.length] = errors[i];
-     found = new Array();
-   } else {
-     var text = this.get_error_text(errors[i]);
-     if (found[text]) continue;
-     found[text] = 1;
-     arr[arr.length] = prefix + text;
-   }
- }
-
- return arr;
-}
-
-/// return a hash of applicable errors
-function eob_as_hash (extra2) {
- var errors = this.errors;
- var extra1 = this.extra;
- if (! extra2) extra2 = new Array();
- var suffix = eob_get_val('as_hash_suffix', extra2, extra1, '_error');
- var joiner = eob_get_val('as_hash_join',   extra2, extra1, '<br />');
-
- /// now add to the hash
- var found = new Array();
- var ret   = new Array();
- for (var i = 0; i < errors.length; i ++) {
-   if (typeof(errors[i]) == 'string') continue;
-   if (! errors[i].length) continue;
-
-   var field     = errors[i][0];
-   var type      = errors[i][1];
-   var field_val = errors[i][2];
-   var ifs_match = errors[i][3];
-
-   if (! field) return alert("Missing field name");
-   if (field_val['delegate_error']) {
-     field = field_val['delegate_error'];
-     field = field.replace(new RegExp('\\$(\\d+)','g'), function (all, N) {
-       if (typeof(ifs_match) != 'object'
-           || typeof(ifs_match[N]) == 'undefined') return ''
-       return ifs_match[N];
-     });
-   }
-
-   var text = this.get_error_text(errors[i]);
-   if (! found[field]) found[field] = new Array();
-   if (found[field][text]) continue;
-   found[field][text] = 1;
-
-   field += suffix;
-   if (! ret[field]) ret[field] = new Array();
-   ret[field].push(text);
- }
-
- /// allow for elements returned as
- if (joiner) {
-   var header = eob_get_val('as_hash_header', extra2, extra1, '');
-   var footer = eob_get_val('as_hash_footer', extra2, extra1, '');
-   for (var key in ret) {
-     if (key == 'extend') continue; // Protoype Array() fix
-     ret[key] = header + ret[key].join(joiner) + footer;
-   }
+function v_find_val () {
+ var key = arguments[0];
+ for (var i = 1; i < arguments.length; i++) {
+  if (typeof(arguments[i]) == 'string') return arguments[i];
+  if (typeof(arguments[i]) == 'undefined') continue;
+  if (typeof(arguments[i][key]) != 'undefined') return arguments[i][key];
  }
-
- return ret;
+ return '';
 }
 
-/// return a user friendly error message
-function eob_get_error_text (err) {
- var extra     = this.extra;
+function v_get_error_text (err, extra1, extra2) {
  var field     = err[0];
  var type      = err[1];
  var field_val = err[2];
  var ifs_match = err[3];
  var m;
 
- var dig = (m = type.match('(_?\\d+)$')) ? m[1] : '';
+ var dig = (m = type.match(/(_?\d+)$/)) ? m[1] : '';
  var type_lc = type.toLowerCase();
+ var v = field_val[type + dig];
 
- /// allow for delegated field names - only used for defaults
- if (field_val['delegate_error']) {
-   field = field_val['delegate_error'];
-   field = field.replace(new RegExp('\\$(\\d+)','g'), function (all, N) {
-     if (typeof(ifs_match) != 'object'
-         || typeof(ifs_match[N]) == 'undefined') return ''
-     return ifs_match[N];
-   });
- }
-
- /// the the name of this thing
- var name = (field_val['name']) ? field_val['name'] : "The field " +field;
- name = name.replace(new RegExp('\\$(\\d+)','g'), function (all, N) {
+ if (field_val.delegate_error) {
+  field = field_val.delegate_error;
+  field = field.replace(/\$(\d+)/g, function (all, N) {
    if (typeof(ifs_match) != 'object'
-       || typeof(ifs_match[N]) == 'undefined') return ''
+     || typeof(ifs_match[N]) == 'undefined') return ''
    return ifs_match[N];
+  });
+ }
+
+ var name = field_val.name || "The field " +field;
+ name = name.replace(/\$(\d+)/g, function (all, N) {
+  if (typeof(ifs_match) != 'object'
+    || typeof(ifs_match[N]) == 'undefined') return ''
+  return ifs_match[N];
  });
 
+ var msg = v_find_val(type + '_error', extra1, extra2);
+ if (! msg) {
+   if (dig.length) msg = field_val[type + dig + '_error'];
+   if (! msg)      msg = field_val[type +       '_error'];
+ }
+ if (msg) {
+  msg = msg.replace(/\$(\d+)/g, function (all, N) {
+   if (typeof(ifs_match) != 'object' || typeof(ifs_match[N]) == 'undefined') return '';
+   return ifs_match[N];
+  });
+  msg = msg.replace(/\$field/g, field);
+  msg = msg.replace(/\$name/g, name);
+  if (v && typeof(v) == 'string') msg = msg.replace(/\$value/g, v);
+  return msg;
+ }
+
+ if (type == 'equals') {
+  var field2 = field_val["equals" + dig];
+  var name2  = field_val["equals" +dig+ "_name"];
+  if (! name2) name2 = "the field " +field2;
+  name2 = name2.replace(/\$(\d+)/g, function (all, N) {
+   return (typeof(ifs_match) != 'object' || typeof(ifs_match[N]) == 'undefined') ? '' : ifs_match[N];
+  });
+  return name + " did not equal " + name2 +".";
+ }
+ if (type == 'min_in_set') return "Not enough fields were chosen from the set ("+v[0]+' of '+v.join(", ").replace(/^\d+,\s*/,'')+")";
+ if (type == 'max_in_set') return "Too many fields were chosen from the set ("  +v[0]+' of '+v.join(", ").replace(/^\d+,\s*/,'')+")";
+
+ return name + (
+  (type == 'required' || type == 'required_if') ? " is required."
+  : type == 'match'      ? " contains invalid characters."
+  : type == 'compare'    ? " did not fit comparison."
+  : type == 'custom_js'  ? " did not match custom_js"+dig+" check."
+  : type == 'enum'       ? " is not in the given list."
+  : type == 'min_values' ? " had less than "+v+" value"+(v == 1 ? '' : 's')+"."
+  : type == 'max_values' ? " had more than "+v+" value"+(v == 1 ? '' : 's')+"."
+  : 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+"."
+  : alert("Missing error on field "+field+" for type "+type+dig));
+}
 
- /// type can look like "required" or "required2" or "required100023"
- /// allow for fallback from required100023_error through required_error
- var possible_keys = new Array(type + '_error');
- if (dig.length) possible_keys.unshift(type + dig + '_error');
+//
 
- /// look in the passed hash or self first
- for (var i = 0; i < possible_keys.length; i ++) {
-   var key = possible_keys[i];
-   var ret = field_val[key];
-   if (! ret) {
-     if (extra[key]) ret = extra[key];
-     else continue;
-   }
-   ret = ret.replace(new RegExp('\\$(\\d+)','g'), function (all, N) {
-     if (typeof(ifs_match) != 'object'
-         || typeof(ifs_match[N]) == 'undefined') return ''
-     return ifs_match[N];
-   });
-   ret = ret.replace(new RegExp('\\$field','g'), field);
-   ret = ret.replace(new RegExp('\\$name' ,'g'), name);
-   if (field_val[type + dig] && typeof(field_val[type + dig]) == 'string')
-     ret = ret.replace(new RegExp('\\$value' ,'g'), field_val[type + dig]);
-   return ret;
- }
+function eob_as_string (extra) {
+ var joiner = v_find_val('as_string_join',   extra, this.extra, '\n');
+ var header = v_find_val('as_string_header', extra, this.extra, '');
+ var footer = v_find_val('as_string_footer', extra, this.extra, '');
+ return header + this.as_array(extra).join(joiner) + footer;
+}
 
- /// set default messages
- if (type == 'required' || type == 'required_if') {
-   return name + " is required.";
-
- } else if (type == 'min_values') {
-   var n = field_val["min_values" + dig];
-   var values = (n == 1) ? 'value' : 'values';
-   return name + " had less than "+n+" "+values+".";
-
- } else if (type == 'max_values') {
-   var n = field_val["max_values" + dig];
-   var values = (n == 1) ? 'value' : 'values';
-   return name + " had more than "+n+" "+values+".";
-
- } else if (type == 'min_in_set') {
-   var set = field_val["min_in_set" + dig];
-   return "Not enough fields were chosen from the set ("+set+")";
-   return "Too many fields were chosen from the set ("+set+")";
-
- } else if (type == 'max_in_set') {
-   var set = field_val["max_in_set" + dig];
-   return "Too many fields were chosen from the set ("+set+")";
-
- } else if (type == 'enum') {
-   return name + " is not in the given list.";
-
- } else if (type == 'equals') {
-   var field2 = field_val["equals" + dig];
-   var name2  = field_val["equals" +dig+ "_name"];
-   if (! name2) name2 = "the field " +field2;
-   name2 = name2.replace(new RegExp('\\$(\\d+)','g'), function (all, N) {
-     if (typeof(ifs_match) != 'object'
-         || typeof(ifs_match[N]) == 'undefined') return ''
-     return ifs_match[N];
-   });
-   return name + " did not equal " + name2 +".";
+function eob_as_array (extra) {
+ var errors = this.errors;
+ var title  = v_find_val('as_array_title', extra, this.extra, 'Please correct the following items:');
+
+ var has_headings;
+ if (title) has_headings = 1;
+ else for (var i = 0; i < errors.length; i++) if (typeof(errors[i]) == 'string') has_headings = 1;
 
- } else if (type == 'min_len') {
-   var n = field_val["min_len"+dig];
-   var chars = (n == 1) ? 'character' : 'characters';
-   return name + " was less than "+n+" "+chars+".";
+ var prefix = v_find_val('as_array_prefix', extra, this.extra, (has_headings ? '  ' : ''));
 
- } else if (type == 'max_len') {
-   var n = field_val["max_len"+dig];
-   var chars = (n == 1) ? 'character' : 'characters';
-   return name + " was more than "+n+" "+chars+".";
+ var arr = [];
+ if (title && title.length) arr.push(title);
 
- } else if (type == 'match') {
-   return name + " contains invalid characters.";
+ var found = {};
+ for (var i = 0; i < errors.length; i++) {
+  if (typeof(errors[i]) == 'string') {
+   arr.push(errors[i]);
+   found = {};
+  } else {
+   var text = v_get_error_text(errors[i], extra, this.extra);
+   if (found[text]) continue;
+   found[text] = 1;
+   arr.push(prefix + text);
+  }
+ }
 
- } else if (type == 'compare') {
-   return name + " did not fit comparison.";
+ return arr;
+}
 
- } else if (type == 'type') {
-   var _type = field_val["type"+dig];
-   return name + " did not match type "+_type+".";
+function eob_as_hash (extra) {
+ var errors = this.errors;
+ var suffix = v_find_val('as_hash_suffix', extra, this.extra, '_error');
+ var joiner = v_find_val('as_hash_join',   extra, this.extra, '<br/>');
+
+ var found = {};
+ var ret   = {};
+ for (var i = 0; i < errors.length; i++) {
+  if (typeof(errors[i]) == 'string') continue;
+  if (! errors[i].length) continue;
+
+  var field     = errors[i][0];
+  var type      = errors[i][1];
+  var field_val = errors[i][2];
+  var ifs_match = errors[i][3];
+
+  if (! field) return alert("Missing field name");
+  if (field_val['delegate_error']) {
+   field = field_val['delegate_error'];
+   field = field.replace(/\$(\d+)/g, function (all, N) {
+    if (typeof(ifs_match) != 'object'
+        || typeof(ifs_match[N]) == 'undefined') return ''
+    return ifs_match[N];
+   });
+  }
 
- } else if (type == 'custom_js') {
-   return name + " did not match custom_js"+dig+" check.";
+  var text = v_get_error_text(errors[i], extra, this.extra);
+  if (! found[field]) found[field] = {};
+  if (found[field][text]) continue;
+  found[field][text] = 1;
 
+  field += suffix;
+  if (! ret[field]) ret[field] = [];
+  ret[field].push(text);
  }
 
- return alert("Missing error on field "+field+" for type "+type+dig);
+ if (joiner) {
+  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()
+   ret[key] = header + ret[key].join(joiner) + footer;
+  }
+ }
+
+ return ret;
 }
 
 function eob_first_field () {
  for (var i = 0; i < this.errors.length; i++) {
-   if (typeof(this.errors[i]) != 'object') continue;
-   if (! this.errors[i][0]) continue;
-   return this.errors[i][0];
+  if (typeof(this.errors[i]) != 'object') continue;
+  if (! this.errors[i][0]) continue;
+  return this.errors[i][0];
  }
  return;
 }
 
-///----------------------------------------------------------------///
+//
 
 document.validate = function (form, val_hash) {
- // undo previous inline
- if (document.did_inline) {
-   for (var key in document.did_inline) {
-     if (key == 'extend') continue; // Protoype Array() fix
-     var el = document.getElementById(key);
-     if (el) el.innerHTML = '';
-   }
-   document.did_inline = undefined;
- }
-
- // do the validate
  val_hash = document.load_val_hash(form, val_hash);
  if (typeof(val_hash) == 'undefined') return true;
- if (! document.val_obj) document.val_obj = new Validate();
- var err_obj = document.val_obj.validate(form, val_hash);
 
- // return success
+ for (var key in v_did_inline) {
+  if (key == 'extend') continue; // Protoype Array()
+  v_inline_error_clear(key, val_hash, form);
+ }
+
+ var err_obj = v_validate(form, val_hash);
  if (! err_obj) return true;
 
- // focus
  var field = err_obj.first_field();
- if (field && form[field] && form[field].focus) form[field].focus();
-
- // inline
- if (! err_obj.extra.no_inline) {
-   var d = document.did_inline = new Array();
-   var hash = err_obj.as_hash();
-   for (var key in hash) {
-     if (key == 'extend') continue; // Protoype Array() fix
-     var el = document.getElementById(key);
-     if (el) el.innerHTML = hash[key];
-     d[key] = 1;
-   }
- }
-
- // alert
- if (! err_obj.extra.no_confirm) {
-   return confirm(err_obj.as_string()) ? false : true;
- } else if (! err_obj.extra.no_alert) {
-   alert(err_obj.as_string());
-   return false;
- } else if (! err_obj.extra.no_inline) {
-   return false;
+ if (field && form[field]) {
+   if (form[field].focus) form[field].focus();
+   else if (form[field].length && form[field][0].focus) form[field][0].focus();
+ }
+
+ 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()
+   v_inline_error_set(key, hash[key], val_hash, form);
+  }
+ }
+
+ 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());
+  return false;
+ } else if (! val_hash['group no_inline']) {
+  return false;
  } else {
-   return true;
+  return true;
  }
 }
 
 document.load_val_hash = function (form, val_hash) {
- // check the form we are using
  if (! form) return alert('Missing form or form name');
  if (typeof(form) == 'string') {
-   if (! document[form]) return alert('No form by name '+form);
-   form = document[form];
+  if (! document[form]) return alert('No form by name '+form);
+  form = document[form];
  }
 
- // if we already have validation - use it
  if (form.val_hash) return form.val_hash;
 
- // load in the validation and save it for future use
  if (typeof(val_hash) != 'object') {
-   // get the hash from a javascript function
-   if (typeof(val_hash) == 'function') {
-     val_hash = val_hash(formname);
-   } else if (typeof(val_hash) == 'undefined') {
-     var el;
-     // get hash from a global js variable
-     if (typeof(document.validation) != 'undefined') {
-       val_hash = document.validation;
-     // get hash from a element by if of validation
-     } else if (el = document.getElementById('validation')) {
-       val_hash = el.innerHTML;
-       val_hash = val_hash.replace(new RegExp('&lt;', 'ig'),'<');
-       val_hash = val_hash.replace(new RegExp('&gt;', 'ig'),'>');
-       val_hash = val_hash.replace(new RegExp('&amp;','ig'),'&');
-     // read hash from <input name=foo validation="">
-     } else {
-       var order = new Array();
-       var str   = '';
-       var yaml  = form.getAttribute('validation');
-       if (yaml) {
-         if (m = yaml.match('^( +)')) yaml = yaml.replace(new RegExp('^'+m[1], 'g'), ''); //unindent
-         yaml = yaml.replace(new RegExp('\\s*$',''),'\n'); // add trailing
-         str += yaml;
-       }
-       var m;
-       for (var i = 0; i < form.elements.length; i ++) {
-         var name = form.elements[i].name;
-         var yaml = form.elements[i].getAttribute('validation');
-         if (! name || ! yaml) continue;
-         yaml = yaml.replace(new RegExp('\\s*$',''),'\n'); // add trailing
-         yaml = yaml.replace(new RegExp('^(.)','mg'),' $1');    // indent all
-         yaml = yaml.replace(new RegExp('^( *[^\\s&*\\[\\{])',''),'\n$1'); // add newline
-         str += name +':' + yaml;
-         order[order.length] = name;
-       }
-       if (str) val_hash = str + "group order: [" + order.join(', ') + "]\n";
-     }
-   }
-   if (typeof(val_hash) == 'string') {
-     if (! document.yaml_load) return;
-     document.hide_yaml_errors = (! document.show_yaml_errors);
-     if (location.search && location.search.indexOf('show_yaml_errors') != -1)
-       document.hide_yaml_errors = 0;
-     val_hash = document.yaml_load(val_hash);
-     if (document.yaml_error_occured) return;
-   }
+  if (typeof(val_hash) == 'function') {
+   val_hash = val_hash(formname);
+  } else if (typeof(val_hash) == 'undefined') {
+   var el;
+   if (typeof(document.validation) != 'undefined') {
+    val_hash = document.validation;
+   } else if (el = document.getElementById('validation')) {
+    val_hash = el.innerHTML.replace(/&lt;/ig,'<').replace(/&gt;/ig,'>').replace(/&amp;/ig,'&');
+   } else {
+    var order = [];
+    var str   = '';
+    var yaml  = form.getAttribute('validation');
+    if (yaml) {
+     if (m = yaml.match(/^( +)/)) yaml = yaml.replace(new RegExp('^'+m[1], 'g'), '');
+     yaml = yaml.replace(/\s*$/,'\n');
+     str += yaml;
+    }
+    var m;
+    for (var i = 0; i < form.elements.length; i++) {
+     var name = form.elements[i].name;
+     var yaml = form.elements[i].getAttribute('validation');
+     if (! name || ! yaml) continue;
+     yaml = yaml.replace(/\s*$/,'\n').replace(/^(.)/mg,' $1').replace(/^( *[^\s&*\[\{])/,'\n$1');
+     str += name +':' + yaml;
+     order.push(name);
+    }
+    if (str) val_hash = str + "group order: [" + order.join(', ') + "]\n";
+   }
+  }
+  if (typeof(val_hash) == 'string') {
+   if (! document.yaml_load) return;
+   document.hide_yaml_errors = (! document.show_yaml_errors);
+   if (location.search && location.search.indexOf('show_yaml_errors') != -1)
+    document.hide_yaml_errors = 0;
+   val_hash = document.yaml_load(val_hash);
+   if (document.yaml_error_occured) return;
+   val_hash = val_hash[0];
+  }
  }
 
- // attach to the form
  form.val_hash = val_hash;
  return form.val_hash;
 }
 
-
 document.check_form = function (form, val_hash) {
- // check the form we are using
  if (! form) return alert('Missing form or form name');
  if (typeof(form) == 'string') {
-   if (! document[form]) return alert('No form by name '+form);
-   form = document[form];
+  if (! document[form]) return alert('No form by name '+form);
+  form = document[form];
  }
 
- // void call - allow for getting it at run time rather than later
- document.load_val_hash(form, val_hash);
+ val_hash = document.load_val_hash(form, val_hash);
+ if (! val_hash) return;
+
+ var types = val_hash['group onevent'] || {submit:1};
+ if (typeof(types) == 'string') types = types.split(/\s*,\s*/);
+ if (typeof(types.length) != 'undefined') {
+  var t = {};
+  for (var i = 0; i < types.length; i++) t[types[i]] = 1;
+  types = t;
+ }
+ val_hash['group onevent'] = types;
+
+ if (types.change || types.blur) {
+  var clean = v_clean_val_hash(val_hash);
+  if (clean.error) return clean.error;
+  var h = {};
+  _add = function (k, v) { if (! h[k]) h[k] = []; h[k].push(v) };
+  for (var i = 0; i < clean.fields.length; i++) {
+   _add(clean.fields[i].field, clean.fields[i]);
+   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()
+   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);
+  }
+ }
+
+ if (types.submit) {
+  var orig_submit = form.onsubmit || function () { return true };
+  form.onsubmit = function (e) { return document.validate(this) && orig_submit(e, this) };
+ }
+}
 
- // attach handler
- var orig_submit = form.onsubmit || function () { return true };
- form.onsubmit = function (e) { return document.validate(this) && orig_submit(e, this) };
+function v_el_attach (el, fvs, form, val_hash) {
+ if (! el.type) {
+  if (el.length) for (var i = 0; i < el.length; i++) v_el_attach(el[i], fvs, form, val_hash);
+  return;
+ }
+ var types = val_hash['group onevent'];
+ var func = function () {
+  var e = [];
+  var f = {};
+  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;
+  }
+  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()
+   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;
+ }
 }
 
-// the end //
+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 el = document.getElementById(key + v_find_val('as_hash_suffix', val_hash, '_error'));
+   if (el) el.innerHTML = '';
+}
+
+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;
+   var el = document.getElementById(key + v_find_val('as_hash_suffix', val_hash, '_error'));
+   if (el) el.innerHTML = val;
+}
This page took 0.051303 seconds and 4 git commands to generate.