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