/**----------------------------------------------------------------***
* 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.41 $
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;
}
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;
}
///----------------------------------------------------------------///
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);
}
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;
}
}
/// 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;
}
/// 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;
}
/// 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 = '';
}
}
/// 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];
}
/// 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];
}
}
/// 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];
}
/// allow for checking for unused keys
// if (EXTRA['no_extra_fields'])
// won't do anything about this for now - let the server handle it
/// 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) {
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);
}
/// 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;
}
return is_found;
}
function vob_filter_types (type, types) {
var values = new Array();
var regexp = new RegExp('^'+type+'_?\\d*$');
for (var i = 0; i < types.length; i++)
if (types[i].match(regexp)) values[values.length] = types[i];
return values;
}
function vob_add_error (errors,field,type,field_val,ifs_match) {
errors[errors.length] = new Array(field, type, field_val, ifs_match);
}
/// 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();
/// allow for not running some tests in the cgi
if (this.filter_types('exclude_js', types).length) return errors;
/// 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;
}
var _value = this.get_form_value(form[field]);
var values;
if (typeof(_value) == 'object') {
values = _value;
} else {
values = new Array();
values[values.length] = _value;
}
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]];
}
}
/// 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);
}
}
}
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];
}
/// 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 ++;
}
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;
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 && (typeof(_value) == 'undefined'
|| ((typeof(_value) == 'object' && _value.length == 0)
|| ! _value.length))) {
this.add_error(errors, field, is_required, field_val, ifs_match);
return errors;
}
/// 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);
return errors;
}
}
/// 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);
return errors;
}
}
/// 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);
return errors;
}
}
}
// the remaining tests operate on each value of a field
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);
}
/// 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;
} 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);
}
/// 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);
}
/// 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);
}
/// 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);
} 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);
}
}
}
}
/// 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*(>|<|[>' ) 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);
}
}
/// 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);
/// 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);
}
/// all done - time to return
return errors;
}
/// used to validate specific types
function vob_check_type (value, type, field, form) {
var m;
/// 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
} 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;
/// 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;
/// 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
} 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;
/// validate a uri - the path portion of a request
} else if (type == 'URI') {
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;
}
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) {
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');
/// 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;
}
}
return ret;
}
/// return a user friendly error message
function eob_get_error_text (err) {
var extra = this.extra;
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 type_lc = type.toLowerCase();
/// 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 (typeof(ifs_match) != 'object'
|| typeof(ifs_match[N]) == 'undefined') return ''
return ifs_match[N];
});
/// 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;
}
/// 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 +".";
} 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+".";
} 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+".";
} else if (type == 'match') {
return name + " contains invalid characters.";
} else if (type == 'compare') {
return name + " did not fit comparison.";
} else if (type == 'type') {
var _type = field_val["type"+dig];
return name + " did not match type "+_type+".";
} else if (type == 'custom_js') {
return name + " did not match custom_js"+dig+" check.";
}
return alert("Missing error on field "+field+" for type "+type+dig);
}
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];
}
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
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;
} else {
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 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('<', 'ig'),'<');
val_hash = val_hash.replace(new RegExp('>', 'ig'),'>');
val_hash = val_hash.replace(new RegExp('&','ig'),'&');
// read hash from
} 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;
}
}
// 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];
}
// void call - allow for getting it at run time rather than later
document.load_val_hash(form, val_hash);
// attach handler
var orig_submit = form.onsubmit || function () { return true };
form.onsubmit = function (e) { return document.validate(this) && orig_submit(e, this) };
}
// the end //