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