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