]> Dogcows Code - chaz/p5-CGI-Ex/blob - lib/CGI/Ex/validate.js
CGI::Ex 2.37
[chaz/p5-CGI-Ex] / lib / CGI / Ex / validate.js
1 // Copyright 2003-2012 - Paul Seamons - ver 2.37
2 // Distributed under the Perl Artistic License without warranty
3 // See perldoc CGI::Ex::Validate for usage
4
5 var v_did_inline = {};
6 var v_event;
7
8 function ValidateError (errors, extra) {
9 this.errors = errors;
10 this.extra = extra;
11 this.as_string = eob_as_string;
12 this.as_array = eob_as_array;
13 this.as_hash = eob_as_hash;
14 this.first_field = eob_first_field;
15 }
16
17 //
18
19 function v_error (err) { alert (err); return 1 }
20
21 function v_get_ordered_fields (val_hash) {
22 if (typeof(val_hash) != 'object') return {error: v_error("Validation must be an associative array (hash)")};
23
24 var ARGS = {};
25 var field_keys = [];
26 var m;
27 for (var key in val_hash) {
28 if (!val_hash.hasOwnProperty(key)) continue;
29 if (m = key.match(/^(general|group)\s+(\w+)/)) {
30 ARGS[m[2]] = val_hash[key];
31 continue;
32 }
33 field_keys.push(key);
34 }
35 field_keys = field_keys.sort();
36
37 var f = ARGS.set_hook; if (f && typeof(f) == 'string') eval("ARGS.set_hook = "+f);
38 f = ARGS.clear_hook; if (f && typeof(f) == 'string') eval("ARGS.clear_hook = "+f);
39 f = ARGS.set_all_hook; if (f && typeof(f) == 'string') eval("ARGS.set_all_hook = "+f);
40 f = ARGS.clear_all_hook; if (f && typeof(f) == 'string') eval("ARGS.clear_all_hook = "+f);
41
42 if (f = ARGS.validate_if) {
43 if (typeof(f) == 'string' || ! f.length) f = [f];
44 var deps = v_clean_cond(f);
45 }
46
47 var fields = [];
48 var ref;
49 if (ref = ARGS.fields || ARGS['order']) {
50 if (typeof(ref) != 'object' || ! ref.length)
51 return {error:v_error("'group fields' must be a non-empty array")};
52 for (var i = 0; i < ref.length; i++) {
53 var field = ref[i];
54 if (typeof(field) == 'object') {
55 if (! field.field) return {error:v_error("Missing field key in validation")};
56 fields.push(field);
57 } else if (field == 'OR') {
58 fields.push('OR');
59 } else {
60 var field_val = val_hash[field];
61 if (! field_val) return {error:v_error('No element found in group for '+field)};
62 if (typeof(field_val) == 'object' && ! field_val['field']) field_val['field'] = field;
63 fields.push(field_val);
64 }
65 }
66 }
67
68 var found = {};
69 for (var i = 0; i < fields.length; i++) {
70 var field_val = fields[i];
71 if (typeof(field_val) != 'object') continue;
72 found[field_val.field] = 1;
73 }
74
75 for (var i = 0; i < field_keys.length; i++) {
76 var field = field_keys[i];
77 if (found[field]) continue;
78 var field_val = val_hash[field];
79 if (typeof(field_val) != 'object' || field_val.length) return {error:v_error('Found a non-hash value on field '+field)};
80 if (! field_val.field) field_val.field = field;
81 fields.push(field_val);
82 }
83
84 for (var i = 0; i < fields.length; i++) v_clean_field_val(fields[i]);
85
86 val_hash['group was_checked'] = {};
87 val_hash['group was_valid'] = {};
88 val_hash['group had_error'] = {};
89
90 return {'fields':fields, 'args':ARGS};
91 }
92
93 function v_clean_field_val (field_val, N_level) {
94 if (! field_val.order) field_val.order = v_field_order(field_val);
95 if (! field_val.deps) field_val.deps = {};
96 for (var i = 0; i < field_val.order.length; i++) {
97 var k = field_val.order[i];
98 var v = field_val[k];
99 if (typeof(v) == 'undefined') return {error:v_error('No matching validation found on field '+field+' for type '+k)};
100 if (k.match(/^(min|max)_in_set_?(\d*)$/)) {
101 if (typeof(v) == 'string') {
102 if (! (m = v.match(/^\s*(\d+)(?:\s*[oO][fF])?\s+(.+)\s*$/))) return {error:v_error("Invalid "+k+" check "+v)};
103 field_val[k] = m[2].split(/[\s,]+/);
104 field_val[k].unshift(m[1]);
105 }
106 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;
107 } else if (k.match(/^(enum|compare)_?\d*$/)) {
108 if (typeof(v) == 'string') field_val[k] = v.split(/\s*\|\|\s*/);
109 } else if (k.match(/^match_?\d*$/)) {
110 if (typeof(v) == 'string') v = field_val[k] = v.split(/\s*\|\|\s*/);
111 for (var j = 0; j < v.length; j++) {
112 if (typeof(v[j]) != 'string' || v[j] == '!') continue;
113 var m = v[j].match(/^\s*(!\s*|)m([^\s\w])(.*)\2([eigsmx]*)\s*$/);
114 if (! m) return {error:v_error("Not sure how to parse that match ("+v[j]+")")};
115 var not = m[1];
116 var pat = m[3];
117 var opt = m[4];
118 if (opt.indexOf('e') != -1) return {error:v_error("The e option cannot be used on field "+field_val.field+", test "+k)};
119 opt = opt.replace(/[sg]/g,'');
120 v[j] = new RegExp(pat, opt);
121 if (not) v.splice(j, 0, '!');
122 }
123 } else if (k.match(/^custom_js_?\d*$/)) {
124 if (typeof(v) == 'string' && v.match(/^\s*function\s*\(/)) eval("field_val[k] = "+v);
125 } else if (k.match(/^(validate|required)_if_?\d*$/)) {
126 if (typeof(v) == 'string' || ! v.length) v = field_val[k] = [v];
127 var deps = v_clean_cond(v, N_level);
128 for (var k in deps) field_val.deps[k] = 2;
129 }
130 }
131 }
132
133 function v_clean_cond (ifs, N_level, ifs_match) {
134 if (typeof(ifs) != 'object') { v_error("Need reference v_clean_cond "+typeof(ifs)); return [] }
135 if (! N_level) N_level = 0;
136 if (++N_level > 10) { v_error("Max dependency level reached " + N_level); return [] }
137
138 var deps = {};
139 var m;
140 for (var i = 0; i < ifs.length; i++) {
141 if (typeof(ifs[i]) == 'string') {
142 if (ifs[i].match(/^\s*function\s*\(/)) eval("ifs[i] = "+ifs[i]);
143 else if (m = ifs[i].match(/^(.+?)\s+was_valid$/)) ifs[i] = {field: m[1], was_valid:1}
144 else if (m = ifs[i].match(/^(.+?)\s+had_error$/)) ifs[i] = {field: m[1], had_error:1}
145 else if (m = ifs[i].match(/^(.+?)\s+was_checked$/)) ifs[i] = {field: m[1], was_checked:1}
146 else if (m = ifs[i].match(/^(\s*!\s*)(.+)\s*$/)) ifs[i] = {field: m[2], max_in_set: [0, m[2]]};
147 else if (ifs[i] != 'OR') ifs[i] = {field: ifs[i], required: 1};
148 }
149 if (typeof(ifs[i]) != 'object') continue;
150 if (! ifs[i].field) { v_error("Missing field key during validate_if"); return [] }
151 deps[ifs[i].field] = 2;
152 v_clean_field_val(ifs[i], N_level);
153 for (var k in ifs[i].deps) deps[k] = 2;
154 }
155 return deps;
156 }
157
158 function v_validate (form, val_hash) {
159 var clean = v_get_ordered_fields(val_hash);
160 if (clean.error) return;
161 var fields = clean.fields;
162
163 var ERRORS = [];
164 var EXTRA = [];
165 var title = val_hash['group title'];
166 var v_if = val_hash['group validate_if'];
167 if (v_if && ! v_check_conditional(form, v_if, val_hash)) return;
168
169 var is_found = 1;
170 var errors = [];
171 var hold_error;
172
173 var chk = {};
174 for (var j = 0; j < fields.length; j++) {
175 var ref = fields[j];
176 if (typeof(ref) != 'object' && ref == 'OR') {
177 if (is_found) j++;
178 is_found = 1;
179 continue;
180 }
181 is_found = 1;
182 var f = ref.field;
183 if (! chk[f]) {
184 chk[f] = 1;
185 val_hash['group was_checked'][f] = 1;
186 val_hash['group was_valid'][f] = 1;
187 val_hash['group had_error'][f] = 0;
188 }
189 var err = v_validate_buddy(form, f, ref, val_hash);
190 if (err.length) {
191 val_hash['group had_error'][f] = 1;
192 val_hash['group was_valid'][f] = 0;
193 if (j <= fields.length && typeof(fields[j + 1] != 'object') && fields[j + 1] == 'OR') {
194 hold_error = err;
195 } else {
196 if (hold_error) err = hold_error;
197 for (var k = 0; k < err.length; k++) errors.push(err[k]);
198 hold_error = '';
199 }
200 } else {
201 hold_error = '';
202 }
203 }
204
205 if (errors.length) {
206 if (title) ERRORS.push(title);
207 for (var j = 0; j < errors.length; j++) ERRORS.push(errors[j]);
208 }
209
210 for (var field in clean.args) {
211 if (errors.length == 0 || field.match(/^(field|order|title|validate_if)$/)) continue;
212 EXTRA[field] = clean.args[field];
213 }
214
215 if (ERRORS.length) return new ValidateError(ERRORS, EXTRA);
216 return;
217 }
218
219 function v_check_conditional (form, ifs, val_hash, ifs_match) {
220 var is_ok = 1;
221 for (var i = 0; i < ifs.length; i++) {
222 if (typeof(ifs[i]) == 'function') {
223 if (! is_ok) break;
224 if (! ifs[i]({'form':form})) is_ok = 0;
225 } else if (typeof(ifs[i]) == 'string') {
226 if (ifs[i] != 'OR') { v_error("Found non-OR string"); return }
227 if (is_ok) i++;
228 is_ok = 1;
229 continue;
230 } else {
231 if (! is_ok) break;
232 var field = ifs[i].field;
233 field = field.replace(/\$(\d+)/g, function (all, N) {
234 return (typeof(ifs_match) != 'object' || typeof(ifs_match[N]) == 'undefined') ? '' : ifs_match[N];
235 });
236 var err = v_validate_buddy(form, field, ifs[i], val_hash);
237 if (err.length) is_ok = 0;
238 }
239 }
240 return is_ok;
241 }
242
243 function v_filter_types (type, types) {
244 var values = [];
245 var regexp = new RegExp('^'+type+'_?\\d*$');
246 for (var i = 0; i < types.length; i++)
247 if (types[i].match(regexp)) values.push(types[i]);
248 return values;
249 }
250
251 function v_add_error (errors,field,type,field_val,ifs_match,form,custom_err) {
252 errors.push([field, type, field_val, ifs_match, custom_err]);
253 if (field_val.clear_on_error) {
254 var el = form[field];
255 if (el && el.type && el.type.match(/(hidden|password|text|textarea|submit)/)) el.value = '';
256 }
257 return errors;
258 }
259
260 function v_field_order (field_val) {
261 var o = [];
262 for (var k in field_val)
263 if (field_val.hasOwnProperty(k) && ! k.match(/^(field|name|required|was_valid|was_checked|had_error)$/) && ! k.match(/_error$/)) o.push(k);
264 return o.sort();
265 }
266
267 function v_validate_buddy (form, field, field_val, val_hash, ifs_match) {
268 var errors = [];
269 if (! form.elements || field_val.exclude_js) return [];
270 var types = field_val.order || v_field_order(field_val);
271
272 var m;
273 if (m = field.match(/^(!\s*|)m([^\s\w])(.*)\2([eigsmx]*)$/)) {
274 var not = m[1];
275 var pat = m[3];
276 var opt = m[4];
277 if (opt.indexOf('e') != -1) { v_error("The e option cannot be used on field "+field); return [] }
278 opt = opt.replace(/[sg]/g,'');
279 var reg = new RegExp(pat, opt);
280
281 for (var i = 0; i < form.elements.length; i++) {
282 var _field = form.elements[i].name;
283 if (! _field) continue;
284 if ( (not && ! (m = _field.match(reg))) || (m = _field.match(reg))) {
285 var err = v_validate_buddy(form, _field, field_val, val_hash, m);
286 for (var j = 0; j < err.length; j++) errors.push(err[j]);
287 }
288 }
289 return errors;
290 }
291
292 if (field_val.was_valid && ! val_hash['group was_valid'][field]) return v_add_error(errors, field, 'was_valid', field_val, ifs_match, form);
293 if (field_val.had_error && ! val_hash['group had_error'][field]) return v_add_error(errors, field, 'had_error', field_val, ifs_match, form);
294 if (field_val.was_checked && ! val_hash['group was_checked'][field]) return v_add_error(errors, field, 'was_checked', field_val, ifs_match, form);
295
296 var _value = v_get_form_value(form[field]);
297 var modified = 0;
298
299 if (typeof(field_val['default']) != 'undefined'
300 && (typeof(_value) == 'undefined'
301 || (typeof(_value) == 'object' && _value.length == 0)
302 || ! _value.length)) {
303 _value = field_val['default'];
304 modified = 1;
305 }
306
307 var values = (typeof(_value) == 'object') ? _value : [_value];
308 var n_values = (typeof(_value) == 'undefined') ? 0 : values.length;
309
310 for (var i = 0; i < values.length; i++) {
311 if (typeof(values[i]) == 'undefined') continue;
312 var orig = values[i];
313 if (! field_val.do_not_trim) {
314 values[i] = values[i].replace(/^\s+/,'');
315 if (v_event != 'change') values[i] = values[i].replace(/\s+$/,'');
316 }
317 if (field_val.trim_control_chars) values[i] = values[i].replace(/\t/g,' ').replace(/[\x00-\x1F]/g,'');
318 if (field_val.to_upper_case) values[i] = values[i].toUpperCase();
319 if (field_val.to_lower_case) values[i] = values[i].toLowerCase();
320
321 var tests = v_filter_types('replace', types);
322 for (var k = 0; k < tests.length; k++) {
323 var ref = field_val[tests[k]];
324 ref = (typeof(ref) == 'object') ? ref : ref.split(/\s*\|\|\s*/);
325 for (var j = 0; j < ref.length; j++) {
326 if (! (m = ref[j].match(/^\s*s([^\s\w])(.+)\1(.*)\1([eigmx]*)$/)))
327 return v_error("Not sure how to parse that replace "+ref[j]);
328 var pat = m[2];
329 var swap = m[3];
330 var opt = m[4];
331 if (opt.indexOf('e') != -1) { v_error("The e option cannot be used on field "+field+", replace "+tests[i]); return [] }
332 var regexp = new RegExp(pat, opt);
333 values[i] = values[i].replace(regexp, swap);
334 }
335 }
336
337 if (orig != values[i]) modified = 1;
338 }
339 if (modified) {
340 var el = form[field];
341 if (el) v_set_form_value(el, values);
342 }
343
344
345 var needs_val = 0;
346 var tests = v_filter_types('validate_if', types);
347 for (var i = 0; i < tests.length; i++) {
348 var ifs = field_val[tests[i]];
349 var ret = v_check_conditional(form, ifs, val_hash, ifs_match);
350 if (ret) needs_val++;
351 }
352 if (tests.length && ! needs_val) {
353 if (field_val.vif_disable && val_hash['group was_valid'][field]) v_set_disable(form[field], true);
354 val_hash['group was_valid'][field] = 0;
355 return [];
356 }
357 if (field_val.vif_disable) v_set_disable(form[field], false);
358
359 var is_required = field_val['required'] ? 'required' : '';
360 if (! is_required) {
361 var tests = v_filter_types('required_if', types);
362 for (var i = 0; i < tests.length; i++) {
363 var ifs = field_val[tests[i]];
364 if (! v_check_conditional(form, ifs, val_hash, ifs_match)) continue;
365 is_required = tests[i];
366 break;
367 }
368 }
369 if (is_required) {
370 var found;
371 for (var i = 0; i < values.length; i++) {
372 if (values[i].length) {
373 found = 1;
374 break;
375 }
376 }
377 if (! found) return v_add_error(errors, field, is_required, field_val, ifs_match, form);
378 }
379
380 if (field_val.min_values && n_values < field_val.min_values)
381 return v_add_error(errors, field, 'min_values', field_val, ifs_match, form);
382
383 if (typeof(field_val.max_values) == 'undefined') field_val.max_values = 1;
384 if (field_val.max_values && n_values > field_val.max_values)
385 return v_add_error(errors, field, 'max_values', field_val, ifs_match, form);
386
387 for (var h = 0; h < 2 ; h++) {
388 var minmax = (h == 0) ? 'min' : 'max';
389 var tests = v_filter_types(minmax+'_in_set', types);
390 for (var i = 0; i < tests.length; i++) {
391 var a = field_val[tests[i]];
392 var n = a[0];
393 for (var k = 1; k < a.length; k++) {
394 var _value = v_get_form_value(form[a[k]]);
395 var _values;
396 if (typeof(_value) == 'undefined') continue;
397 _values = (typeof(_value) == 'object') ? _value : [_value];
398 for (var l = 0; l < _values.length; l++) {
399 var _value = _values[l];
400 if (typeof(_value) != 'undefined' && _value.length) n--;
401 }
402 }
403 if ( (minmax == 'min' && n > 0)
404 || (minmax == 'max' && n < 0)) {
405 v_add_error(errors, field, tests[i], field_val, ifs_match, form);
406 return errors;
407 }
408 }
409 }
410
411 for (var n = 0; n < values.length; n++) {
412 var value = values[n];
413
414 if (typeof field_val['enum'] != 'undefined') {
415 var is_found = 0;
416 for (var j = 0; j < field_val['enum'].length; j++) if (value == field_val['enum'][j]) { is_found = 1; break }
417 if (! is_found) {
418 v_add_error(errors, field, 'enum', field_val, ifs_match, form);
419 continue;
420 }
421 }
422
423 if (typeof field_val['type'] != 'undefined')
424 if (! v_check_type(value, field_val['type'], field, form)) {
425 v_add_error(errors, field, 'type', field_val, ifs_match, form);
426 continue;
427 }
428
429 for (var i = 0; i < types.length; i++) {
430 var type = types[i];
431 var _fv = field_val[type];
432
433 if (type.match(/^equals_?\d*$/)) {
434 var not = _fv.match(/^!\s*/);
435 if (not) _fv = _fv.substring(not[0].length);
436 var success = 0;
437 if (m = _fv.match(/^([\"\'])(.*)\1$/)) {
438 if (value == m[2]) success = 1;
439 } else {
440 var value2 = v_get_form_value(form[_fv]);
441 if (typeof(value2) == 'undefined') value2 = '';
442 if (value == value2) success = 1;
443 }
444 if (not && success || ! not && ! success) {
445 v_add_error(errors, field, type, field_val, ifs_match, form);
446 break;
447 }
448 }
449
450 if (type == 'min_len' && value.length < _fv) v_add_error(errors, field, 'min_len', field_val, ifs_match, form);
451 if (type == 'max_len' && value.length > _fv) v_add_error(errors, field, 'max_len', field_val, ifs_match, form);
452
453 if (type.match(/^match_?\d*$/)) {
454 for (var j = 0; j < _fv.length; j++) {
455 if (typeof(_fv[j]) == 'string') continue;
456 var not = (j > 0 && typeof(_fv[j-1]) == 'string' && _fv[j-1] == '!') ? 1 : 0;
457 if ( ( not && value.match(_fv[j]))
458 || (! not && ! value.match(_fv[j]))) v_add_error(errors, field, type, field_val, ifs_match, form);
459 }
460 }
461
462 if (type.match(/^compare_?\d*$/)) {
463 for (var j = 0; j < _fv.length; j++) {
464 var comp = _fv[j];
465 if (! comp) continue;
466 var hold = false;
467 var copy = value;
468 if (m = comp.match(/^\s*(>|<|[><!=]=)\s*([\d\.\-]+)\s*$/)) {
469 if (! copy) copy = 0;
470 copy *= 1;
471 if (m[1] == '>' ) hold = (copy > m[2])
472 else if (m[1] == '<' ) hold = (copy < m[2])
473 else if (m[1] == '>=') hold = (copy >= m[2])
474 else if (m[1] == '<=') hold = (copy <= m[2])
475 else if (m[1] == '!=') hold = (copy != m[2])
476 else if (m[1] == '==') hold = (copy == m[2])
477 } else if (m = comp.match(/^\s*(eq|ne|gt|ge|lt|le)\s+(.+?)\s*$/)) {
478 if ( m[2].match(/^\"/)) m[2] = m[2].replace(/^"(.*)"$/,'$1');
479 else if (m[2].match(/^\'/)) m[2] = m[2].replace(/^'(.*)'$/,'$1');
480 if (m[1] == 'gt') hold = (copy > m[2])
481 else if (m[1] == 'lt') hold = (copy < m[2])
482 else if (m[1] == 'ge') hold = (copy >= m[2])
483 else if (m[1] == 'le') hold = (copy <= m[2])
484 else if (m[1] == 'ne') hold = (copy != m[2])
485 else if (m[1] == 'eq') hold = (copy == m[2])
486 } else {
487 v_error("Not sure how to compare \""+comp+"\"");
488 return errors;
489 }
490 if (! hold) v_add_error(errors, field, type, field_val, ifs_match, form);
491 }
492 }
493 }
494 }
495
496 for (var i = 0; i < types.length; i++) {
497 var type = types[i];
498 var _fv = field_val[type];
499 // the js is evaluated and should return 1 for success
500 // or 0 for failure - the variables field, value, and field_val (the hash) are available
501 if (type.match(/^custom_js_?\d*$/)) {
502 var value = values.length == 1 ? values[0] : values;
503 var err;
504 var ok;
505 try { ok = (typeof _fv == 'function') ? _fv({'value':value, 'field_val':field_val, 'form':form, 'key':field_val.field, 'errors':errors, 'event':v_event}) : eval(_fv) } catch (e) { err = e }
506 if (!ok) v_add_error(errors, field, type, field_val, ifs_match, form, err);
507 }
508 }
509
510 return errors;
511 }
512
513 function v_check_type (value, type, field, form) {
514 var m;
515 type = type.toUpperCase();
516
517 if (type == 'EMAIL') {
518 if (! value) return 0;
519 if (! (m = value.match(/^(.+)@(.+?)$/))) return 0;
520 if (m[1].length > 60) return 0;
521 if (m[2].length > 100) return 0;
522 if (! v_check_type(m[2],'DOMAIN') && ! v_check_type(m[2],'IP')) return 0;
523 if (! v_check_type(m[1],'LOCAL_PART')) return 0;
524
525 } else if (type == 'LOCAL_PART') {
526 if (typeof(value) == 'undefined' || ! value.length) return 0;
527 if (typeof(v_local_part) != 'undefined') return (value.match(v_local_part) ? 1 : 0);
528 // ignoring all valid quoted string local parts
529 if (value.match(/[^\w.~!\#\$%\^&*\-=+?]/)) return 0;
530
531 } else if (type == 'IP') {
532 if (! value) return 0;
533 var dig = value.split(/\./);
534 if (dig.length != 4) return 0;
535 for (var i = 0; i < 4; i++)
536 if (typeof(dig[i]) == 'undefined' || dig[i].match(/\D/) || dig[i] > 255) return 0;
537
538 } else if (type == 'DOMAIN') {
539 if (! value) return 0;
540 if (! value.match(/^[a-z0-9.-]{4,255}$/)) return 0;
541 if (value.match(/^[.\-]/)) return 0;
542 if (value.match(/(\.-|-\.|\.\.)/)) return 0;
543 if (! (m = value.match(/^(.+\.)([a-z]{2,10})$/))) return 0;
544 if (! m[1].match(/^([a-z0-9\-]{1,63}\.)+$/)) return 0;
545
546 } else if (type == 'URL') {
547 if (! value) return 0;
548 if (! (m = value.match(/^https?:\/\/([^\/]+)/i))) return 0;
549 value = value.substring(m[0].length);
550 var dom = m[1].replace(/:\d+$/).replace(/\.$/);
551 if (! v_check_type(dom,'DOMAIN') && ! v_check_type(m[1],'IP')) return 0;
552 if (value && ! v_check_type(value,'URI')) return 0;
553
554 } else if (type == 'URI') {
555 if (! value) return 0;
556 if (value.match(/\s/)) return 0;
557
558 } else if (type == 'INT') {
559 if (!value.match(/^-?(?:0|[1-9]\d*)$/)) return 0;
560 if ((value < 0) ? value < -Math.pow(2,31) : value > Math.pow(2,31)-1) return 0;
561 } else if (type == 'UINT') {
562 if (!value.match(/^(?:0|[1-9]\d*)$/)) return 0;
563 if (value > Math.pow(2,32)-1) return 0;
564 } else if (type == 'NUM') {
565 if (!value.match(/^-?(?:0|[1-9]\d*(?:\.\d+)?|0?\.\d+)$/)) return 0;
566
567 } else if (type == 'CC') {
568 if (! value) return 0;
569 if (value.match(/[^\d\- ]/)) return 0;
570 value = value.replace(/[\- ]/g, '');
571 if (value.length > 16 || value.length < 13) return 0;
572 // mod10
573 var sum = 0;
574 var swc = 0;
575 for (var i = value.length - 1; i >= 0; i--) {
576 if (++swc > 2) swc = 1;
577 var y = value.charAt(i) * swc;
578 if (y > 9) y -= 9;
579 sum += y;
580 }
581 if (sum % 10) return 0;
582 }
583
584 return 1;
585 }
586
587 function v_set_form_value (el, values, form) {
588 if (typeof(el) == 'string') el = form[el];
589 if (typeof(values) != 'object') values = [values];
590 if (! el) return;
591 var type = (el.type && ! (''+el).match(/HTMLCollection/)) ? el.type.toLowerCase() : '';
592 if (el.length && type != 'select-one') {
593 for (var i = 0; i < el.length; i++) {
594 if (! el[i] || ! el[i].type) continue;
595 v_set_form_value(el[i], (el[i].type.match(/^(checkbox|radio)$/) ? values : i < values.length ? [values[i]] : ['']));
596 }
597 return;
598 }
599 if (! type) return;
600 if (type.match(/(hidden|password|text|textarea|submit)/)) return el.value = values[0];
601 if (type.indexOf('select') != -1) {
602 if (el.length) for (var i = 0; i < el.length; i++) el[i].selected = (el[i].value == values[0]) ? true : false;
603 return;
604 }
605 if (type == 'checkbox' || type == 'radio') {
606 var f; for (var i = 0; i < values.length; i++) if (values[i] == el.value) f = 1;
607 return el.checked = f ? true : false;
608 }
609 if (type == 'file') return;
610
611 alert('Unknown form type for '+el.name+': '+type);
612 return;
613 }
614
615 function v_set_disable (el, disable) {
616 if (! el) return
617 var type = el.type ? el.type.toLowerCase() : '';
618 if (el.length && type != 'select-one') {
619 for (var j=0;j<el.length;j++) el[i].disabled = disable;
620 } else el.disabled = disable;
621 }
622
623 function v_get_form_value (el, form) {
624 if (typeof(el) == 'string') el = form[el];
625 if (! el) return '';
626 var type = (el.type && ! (''+el).match(/HTMLCollection/)) ? el.type.toLowerCase() : '';
627 if (el.length && type != 'select-one') {
628 var a = [];
629 for (var j=0;j<el.length;j++) {
630 if (type.indexOf('multiple') != -1) {
631 if (el[j].selected) a.push(el[j].value);
632 } else {
633 if (el[j].checked) a.push(v_get_form_value(el[j]));
634 }
635 }
636 if (a.length == 0) return '';
637 if (a.length == 1) return a[0];
638 return a;
639 }
640 if (! type) return '';
641 if (type.match(/(hidden|password|text|textarea|submit)/)) return el.value;
642 if (type.indexOf('select') != -1) {
643 if (! el.length) return '';
644 if (el.selectedIndex == -1) return '';
645 return el[el.selectedIndex].value;
646 }
647 if (type == 'checkbox' || type == 'radio') return el.checked ? el.value : '';
648 if (type == 'file') return el.value;
649
650 alert('Unknown form type for '+el.name+': '+type);
651 return '';
652 }
653
654 function v_find_val () {
655 var key = arguments[0];
656 for (var i = 1; i < arguments.length; i++) {
657 if (typeof(arguments[i]) == 'string') return arguments[i];
658 if (typeof(arguments[i]) == 'undefined') continue;
659 if (typeof(arguments[i][key]) != 'undefined') return arguments[i][key];
660 }
661 return '';
662 }
663
664 function v_get_error_text (err, extra1, extra2) {
665 var field = err[0];
666 var type = err[1];
667 var field_val = err[2];
668 var ifs_match = err[3];
669 if (err.length == 5 && typeof err[4] != 'undefined' && err[4].length) return err[4]; // custom error from throw in custom_js
670
671 var m;
672 var dig = '';
673 if (m = type.match(/^(.+?)(_?\d+)$/)) { type = m[1] ; dig = m[2] }
674 var type_lc = type.toLowerCase();
675 var v = field_val[type + dig];
676
677 if (field_val.delegate_error) {
678 field = field_val.delegate_error;
679 field = field.replace(/\$(\d+)/g, function (all, N) {
680 if (typeof(ifs_match) != 'object'
681 || typeof(ifs_match[N]) == 'undefined') return ''
682 return ifs_match[N];
683 });
684 }
685
686 var name = field_val.name;
687 if (! name && (field.match(/\W/) || (field.match(/\d/) && field.match(/\D/)))) {
688 name = "The field " +field;
689 }
690 if (! name) name = field.replace(/_/g, ' ').replace(/\b(\w)/g, function(all,str){return str.toUpperCase()});
691 name = name.replace(/\$(\d+)/g, function (all, N) {
692 if (typeof(ifs_match) != 'object'
693 || typeof(ifs_match[N]) == 'undefined') return ''
694 return ifs_match[N];
695 });
696
697 var msg = v_find_val(type + '_error', extra1, extra2);
698 if (! msg) {
699 if (dig.length) msg = field_val[type + dig + '_error'];
700 if (! msg) msg = field_val[type + '_error'];
701 if (! msg) msg = field_val['error'];
702 }
703 if (msg) {
704 msg = msg.replace(/\$(\d+)/g, function (all, N) {
705 if (typeof(ifs_match) != 'object' || typeof(ifs_match[N]) == 'undefined') return '';
706 return ifs_match[N];
707 });
708 msg = msg.replace(/\$field/g, field);
709 msg = msg.replace(/\$name/g, name);
710 if (v && typeof(v) == 'string') msg = msg.replace(/\$value/g, v);
711 return msg;
712 }
713
714 if (type == 'equals') {
715 var field2 = field_val["equals" + dig];
716 var name2 = field_val["equals" +dig+ "_name"];
717 if (! name2) name2 = "the field " +field2;
718 name2 = name2.replace(/\$(\d+)/g, function (all, N) {
719 return (typeof(ifs_match) != 'object' || typeof(ifs_match[N]) == 'undefined') ? '' : ifs_match[N];
720 });
721 return name + " did not equal " + name2 +".";
722 }
723 if (type == 'min_in_set') return "Not enough fields were chosen from the set ("+v[0]+' of '+v.join(", ").replace(/^\d+,\s*/,'')+")";
724 if (type == 'max_in_set') return "Too many fields were chosen from the set (" +v[0]+' of '+v.join(", ").replace(/^\d+,\s*/,'')+")";
725
726 return name + (
727 (type == 'required' || type == 'required_if') ? " is required."
728 : type == 'match' ? " contains invalid characters."
729 : type == 'compare' ? " did not fit comparison."
730 : type == 'custom_js' ? " did not match custom_js"+dig+" check."
731 : type == 'enum' ? " is not in the given list."
732 : type == 'min_values' ? " had less than "+v+" value"+(v == 1 ? '' : 's')+"."
733 : type == 'max_values' ? " had more than "+v+" value"+(v == 1 ? '' : 's')+"."
734 : type == 'min_len' ? " was less than "+v+" character"+(v == 1 ? '' : 's')+"."
735 : type == 'max_len' ? " was more than "+v+" character"+(v == 1 ? '' : 's')+"."
736 : type == 'type' ? " did not match type "+v+"."
737 : type == 'had_error' ? " had no error (but should have had)."
738 : type == 'was_valid' ? " was not valid."
739 : type == 'was_checked'? " was not checked."
740 : alert("Missing error on field "+field+" for type "+type+dig));
741 }
742
743 //
744
745 function eob_as_string (extra) {
746 var joiner = v_find_val('as_string_join', extra, this.extra, '\n');
747 var header = v_find_val('as_string_header', extra, this.extra, '');
748 var footer = v_find_val('as_string_footer', extra, this.extra, '');
749 return header + this.as_array(extra).join(joiner) + footer;
750 }
751
752 function eob_as_array (extra) {
753 var errors = this.errors;
754 var title = v_find_val('as_array_title', extra, this.extra, 'Please correct the following items:');
755
756 var has_headings;
757 if (title) has_headings = 1;
758 else for (var i = 0; i < errors.length; i++) if (typeof(errors[i]) == 'string') has_headings = 1;
759
760 var prefix = v_find_val('as_array_prefix', extra, this.extra, (has_headings ? ' ' : ''));
761
762 var arr = [];
763 if (title && title.length) arr.push(title);
764
765 var found = {};
766 for (var i = 0; i < errors.length; i++) {
767 if (typeof(errors[i]) == 'string') {
768 arr.push(errors[i]);
769 found = {};
770 } else {
771 var text = v_get_error_text(errors[i], extra, this.extra);
772 if (found[text]) continue;
773 found[text] = 1;
774 arr.push(prefix + text);
775 }
776 }
777
778 return arr;
779 }
780
781 function eob_as_hash (extra) {
782 var errors = this.errors;
783 var suffix = v_find_val('as_hash_suffix', extra, this.extra, '_error');
784 var joiner = v_find_val('as_hash_join', extra, this.extra, '<br/>');
785
786 var found = {};
787 var ret = {};
788 for (var i = 0; i < errors.length; i++) {
789 if (typeof(errors[i]) == 'string') continue;
790 if (! errors[i].length) continue;
791
792 var field = errors[i][0];
793 var type = errors[i][1];
794 var field_val = errors[i][2];
795 var ifs_match = errors[i][3];
796
797 if (! field) return alert("Missing field name");
798 if (field_val['delegate_error']) {
799 field = field_val['delegate_error'];
800 field = field.replace(/\$(\d+)/g, function (all, N) {
801 if (typeof(ifs_match) != 'object'
802 || typeof(ifs_match[N]) == 'undefined') return ''
803 return ifs_match[N];
804 });
805 }
806
807 var text = v_get_error_text(errors[i], extra, this.extra);
808 if (! found[field]) found[field] = {};
809 if (found[field][text]) continue;
810 found[field][text] = 1;
811
812 field += suffix;
813 if (! ret[field]) ret[field] = [];
814 ret[field].push(text);
815 }
816
817 if (joiner) {
818 var header = v_find_val('as_hash_header', extra, this.extra, '');
819 var footer = v_find_val('as_hash_footer', extra, this.extra, '');
820 for (var key in ret) {
821 if (!ret.hasOwnProperty(key)) continue;
822 ret[key] = header + ret[key].join(joiner) + footer;
823 }
824 }
825
826 return ret;
827 }
828
829 function eob_first_field () {
830 for (var i = 0; i < this.errors.length; i++) {
831 if (typeof(this.errors[i]) != 'object') continue;
832 if (! this.errors[i][0]) continue;
833 return this.errors[i][0];
834 }
835 return;
836 }
837
838 //
839
840 document.validate = function (form, val_hash) {
841 val_hash = document.load_val_hash(form, val_hash);
842 if (typeof(val_hash) == 'undefined') return true;
843
844 if (v_event != 'load') {
845 for (var key in v_did_inline) {
846 if (!v_did_inline.hasOwnProperty(key)) continue;
847 v_inline_error_clear(key, val_hash, form);
848 }
849 }
850
851 var err_obj = v_validate(form, val_hash);
852 if (! err_obj) {
853 var f = val_hash['group clear_all_hook'] || document.validate_clear_all_hook;
854 if (f) f();
855 return true;
856 }
857
858 var f = val_hash['group set_all_hook'] || document.validate_set_all_hook;
859 if (f) f(err_obj, val_hash, form);
860
861 var field = err_obj.first_field();
862 if (field && form[field]) {
863 if (form[field].focus) form[field].focus();
864 else if (form[field].length && form[field][0].focus) form[field][0].focus();
865 }
866
867 if (! val_hash['group no_inline']) {
868 var hash = err_obj.as_hash({as_hash_suffix:""});
869 for (var key in hash) {
870 if (!hash.hasOwnProperty(key)) continue;
871 v_inline_error_set(key, hash[key], val_hash, form);
872 }
873 }
874
875 if (v_event == 'load') {
876 return false;
877 } else if (! val_hash['group no_confirm']) {
878 return confirm(err_obj.as_string()) ? false : true;
879 } else if (! val_hash['group no_alert']) {
880 alert(err_obj.as_string());
881 return false;
882 } else if (! val_hash['group no_inline']) {
883 return false;
884 } else {
885 return true;
886 }
887 }
888
889 document.load_val_hash = function (form, val_hash) {
890 if (! form) return alert('Missing form or form name');
891 if (typeof(form) == 'string') {
892 if (! document[form]) return alert('No form by name '+form);
893 form = document[form];
894 }
895
896 if (form.val_hash) return form.val_hash;
897
898 if (typeof(val_hash) != 'object') {
899 if (typeof(val_hash) == 'function') {
900 val_hash = val_hash(formname);
901 } else if (typeof(val_hash) == 'undefined') {
902 var el;
903 if (typeof(document.validation) != 'undefined') {
904 val_hash = document.validation;
905 } else if (el = document.getElementById('validation')) {
906 val_hash = el.innerHTML.replace(/&lt;/ig,'<').replace(/&gt;/ig,'>').replace(/&amp;/ig,'&');
907 } else {
908 var order = [];
909 var str = '';
910 var yaml = form.getAttribute('validation');
911 if (yaml) {
912 if (m = yaml.match(/^( +)/)) yaml = yaml.replace(new RegExp('^'+m[1], 'g'), '');
913 yaml = yaml.replace(/\s*$/,'\n');
914 str += yaml;
915 }
916 var m;
917 for (var i = 0; i < form.elements.length; i++) {
918 var name = form.elements[i].name;
919 var yaml = form.elements[i].getAttribute('validation');
920 if (! name || ! yaml) continue;
921 yaml = yaml.replace(/\s*$/,'\n').replace(/^(.)/mg,' $1').replace(/^( *[^\s&*\[\{])/,'\n$1');
922 str += name +':' + yaml;
923 order.push(name);
924 }
925 if (str) val_hash = str + "group order: [" + order.join(', ') + "]\n";
926 }
927 }
928 if (typeof(val_hash) == 'string') {
929 if (! document.yaml_load) return;
930 document.hide_yaml_errors = (! document.show_yaml_errors);
931 if (location.search && location.search.indexOf('show_yaml_errors') != -1)
932 document.hide_yaml_errors = 0;
933 val_hash = document.yaml_load(val_hash);
934 if (document.yaml_error_occured) return;
935 val_hash = val_hash[0];
936 }
937 }
938
939 form.val_hash = val_hash;
940 return form.val_hash;
941 }
942
943 document.check_form = function (form, val_hash) {
944 if (! form) return alert('Missing form or form name');
945 if (typeof(form) == 'string') {
946 if (! document[form]) return alert('No form by name '+form);
947 form = document[form];
948 }
949
950 val_hash = document.load_val_hash(form, val_hash);
951 if (! val_hash) return;
952
953 var types = val_hash['group onevent'] || {submit:1};
954 if (typeof(types) == 'string') types = types.split(/\s*,\s*/);
955 if (typeof(types.length) != 'undefined') {
956 var t = {};
957 for (var i = 0; i < types.length; i++) t[types[i]] = 1;
958 types = t;
959 }
960 val_hash['group onevent'] = types;
961
962 if (types.change || types.blur) {
963 var clean = v_get_ordered_fields(val_hash);
964 if (clean.error) return clean.error;
965 var h = {};
966 _add = function (k, v) { if (! h[k]) h[k] = []; h[k].push(v) };
967 for (var i = 0; i < clean.fields.length; i++) {
968 _add(clean.fields[i].field, clean.fields[i]);
969 for (var j in clean.fields[i].deps) if (j != clean.fields[i].field) _add(j, clean.fields[i]);
970 }
971 for (var k in h) {
972 if (!h.hasOwnProperty(k)) continue;
973 var el = form[k];
974 if (! el) return v_error("No form element by the name "+k);
975 var _change = !types.change ? 0 : typeof(types.change) == 'object' ? types.change[k] : 1;
976 var _blur = !types.blur ? 0 : typeof(types.blur) == 'object' ? types.blur[k] : 1;
977 v_el_attach(el, h[k], form, val_hash, _change, _blur);
978 }
979 }
980
981 if (types.submit) {
982 var orig_submit = form.onsubmit || function () { return true };
983 form.onsubmit = function (e) { v_event = 'submit'; return document.validate(this) && orig_submit(e, this) };
984 }
985
986 if (types.load) { v_event = 'load'; document.validate(form) }
987 }
988
989 function v_el_attach (el, fvs, form, val_hash, _change, _blur) {
990 if (!_change && !_blur) return;
991 if (! el.type) {
992 if (el.length) for (var i = 0; i < el.length; i++) v_el_attach(el[i], fvs, form, val_hash, _change, _blur);
993 return;
994 }
995 var types = val_hash['group onevent'];
996 var func = function () {
997 v_event = 'change';
998 var e = [];
999 var f = {};
1000 var chk = {};
1001 for (var i = 0; i < fvs.length; i++) {
1002 var field_val = fvs[i];
1003 var k = field_val.field;
1004 if (! chk[k]) {
1005 chk[k] = 1;
1006 val_hash['group was_checked'][k] = 1;
1007 val_hash['group was_valid'][k] = 1;
1008 val_hash['group had_error'][k] = 0;
1009 }
1010 var _e = v_validate_buddy(form, k, field_val, val_hash);
1011 if (_e.length) {
1012 val_hash['group had_error'][k] = 1;
1013 val_hash['group was_valid'][k] = 0;
1014 for (var j = 0; j < _e.length; j++) e.push(_e[j]);
1015 }
1016 f[field_val.delegate_error || field_val.field] = _e.length ? 0 : 1;
1017 }
1018 for (var k in f) if (f[k]) v_inline_error_clear(k, val_hash, form);
1019 if (! e.length) return;
1020 e = new ValidateError(e, {});
1021 e = e.as_hash({as_hash_suffix:"", first_only:(val_hash['group first_only']?1:0)});
1022 for (var k in e) {
1023 if (!e.hasOwnProperty(k)) continue;
1024 v_inline_error_set(k, e[k], val_hash, form);
1025 }
1026 };
1027 if (_blur) el.onblur = func;
1028 if (_change && ! (''+el).match(/HTMLCollection/)) { // find better way on opera
1029 var type = el.type ? el.type.toLowerCase() : '';
1030 if (type.match(/(password|text|textarea)/)) el.onkeyup = func;
1031 else if (type.match(/(checkbox|radio)/)) el.onclick = func;
1032 else if (type.match(/(select)/)) el.onchange = func;
1033 }
1034 }
1035
1036 function v_inline_error_clear (key, val_hash, form) {
1037 delete(v_did_inline[key]);
1038 var f = val_hash['group clear_hook'] || document.validate_clear_hook;
1039 var g = val_hash['group was_valid'] || {};
1040 if (typeof(f) == 'function') if (f({'key':key, 'val_hash':val_hash, 'form':form, was_valid:g[key], 'event':v_event})) return 1;
1041 var el = document.getElementById(key + v_find_val('as_hash_suffix', val_hash, '_error'));
1042 if (el) el.innerHTML = '';
1043 }
1044
1045 function v_inline_error_set (key, val, val_hash, form) {
1046 v_did_inline[key] = 1;
1047 var f = val_hash['group set_hook'] || document.validate_set_hook;
1048 if (typeof(f) == 'function') if (f({'key':key, 'value':val, 'val_hash':val_hash, 'form':form, 'event':v_event})) return 1;
1049 var el = document.getElementById(key + v_find_val('as_hash_suffix', val_hash, '_error'));
1050 if (el) el.innerHTML = val;
1051 }
This page took 0.103715 seconds and 4 git commands to generate.