source: main/trunk/model-sites-dev/cambridge-museum/collect/waikato-independent/pre-import/EditableDatabaseTable/WebContent/scripts/jquery.validate-1.7.js@ 34511

Last change on this file since 34511 was 34511, checked in by davidb, 4 years ago

Evolution of code away from Company model to one that uses RecordHashmap to represent the rows coming out of the JDBC database

File size: 42.3 KB
Line 
1// Sourced from:
2// https://github.com/fossology/fossology
3
4/*
5 * jQuery validation plug-in 1.7
6 *
7 * http://bassistance.de/jquery-plugins/jquery-plugin-validation/
8 * http://docs.jquery.com/Plugins/Validation
9 *
10 * Copyright (c) 2006 - 2008 Jörn Zaefferer
11 *
12 * $Id: jquery.validate.js 6403 2009-06-17 14:27:16Z joern.zaefferer $
13 *
14 * Dual licensed under the MIT and GPL licenses:
15 * http://www.opensource.org/licenses/mit-license.php
16 * http://www.gnu.org/licenses/gpl.html
17 */
18
19(function($) {
20
21 $.extend($.fn, {
22 // http://docs.jquery.com/Plugins/Validation/validate
23 validate: function( options ) {
24
25 // if nothing is selected, return nothing; can't chain anyway
26 if (!this.length) {
27 options && options.debug && window.console && console.warn( "nothing selected, can't validate, returning nothing" );
28 return;
29 }
30
31 // check if a validator for this form was already created
32 var validator = $.data(this[0], 'validator');
33 if ( validator ) {
34 return validator;
35 }
36
37 validator = new $.validator( options, this[0] );
38 $.data(this[0], 'validator', validator);
39
40 if ( validator.settings.onsubmit ) {
41
42 // allow suppresing validation by adding a cancel class to the submit button
43 this.find("input, button").filter(".cancel").click(function() {
44 validator.cancelSubmit = true;
45 });
46
47 // when a submitHandler is used, capture the submitting button
48 if (validator.settings.submitHandler) {
49 this.find("input, button").filter(":submit").click(function() {
50 validator.submitButton = this;
51 });
52 }
53
54 // validate the form on submit
55 this.submit( function( event ) {
56 if ( validator.settings.debug ) {
57 // prevent form submit to be able to see console output
58 event.preventDefault();
59 }
60
61 function handle() {
62 if ( validator.settings.submitHandler ) {
63 if (validator.submitButton) {
64 // insert a hidden input as a replacement for the missing submit button
65 var hidden = $("<input type='hidden'/>").attr("name", validator.submitButton.name).val(validator.submitButton.value).appendTo(validator.currentForm);
66 }
67 validator.settings.submitHandler.call( validator, validator.currentForm );
68 if (validator.submitButton) {
69 // and clean up afterwards; thanks to no-block-scope, hidden can be referenced
70 hidden.remove();
71 }
72 return false;
73 }
74 return true;
75 }
76
77 // prevent submit for invalid forms or custom submit handlers
78 if ( validator.cancelSubmit ) {
79 validator.cancelSubmit = false;
80 return handle();
81 }
82 if ( validator.form() ) {
83 if ( validator.pendingRequest ) {
84 validator.formSubmitted = true;
85 return false;
86 }
87 return handle();
88 } else {
89 validator.focusInvalid();
90 return false;
91 }
92 });
93 }
94
95 return validator;
96 },
97 // http://docs.jquery.com/Plugins/Validation/valid
98 valid: function() {
99 if ( $(this[0]).is('form')) {
100 return this.validate().form();
101 } else {
102 var valid = true;
103 var validator = $(this[0].form).validate();
104 this.each(function() {
105 valid &= validator.element(this);
106 });
107 return valid;
108 }
109 },
110 // attributes: space seperated list of attributes to retrieve and remove
111 removeAttrs: function(attributes) {
112 var result = {},
113 $element = this;
114 $.each(attributes.split(/\s/), function(index, value) {
115 result[value] = $element.attr(value);
116 $element.removeAttr(value);
117 });
118 return result;
119 },
120 // http://docs.jquery.com/Plugins/Validation/rules
121 rules: function(command, argument) {
122 var element = this[0];
123
124 if (command) {
125 var settings = $.data(element.form, 'validator').settings;
126 var staticRules = settings.rules;
127 var existingRules = $.validator.staticRules(element);
128 switch(command) {
129 case "add":
130 $.extend(existingRules, $.validator.normalizeRule(argument));
131 staticRules[element.name] = existingRules;
132 if (argument.messages) {
133 settings.messages[element.name] = $.extend( settings.messages[element.name], argument.messages );
134 }
135 break;
136 case "remove":
137 if (!argument) {
138 delete staticRules[element.name];
139 return existingRules;
140 }
141 var filtered = {};
142 $.each(argument.split(/\s/), function(index, method) {
143 filtered[method] = existingRules[method];
144 delete existingRules[method];
145 });
146 return filtered;
147 }
148 }
149
150 var data = $.validator.normalizeRules(
151 $.extend(
152 {},
153 $.validator.metadataRules(element),
154 $.validator.classRules(element),
155 $.validator.attributeRules(element),
156 $.validator.staticRules(element)
157 ), element);
158
159 // make sure required is at front
160 if (data.required) {
161 var param = data.required;
162 delete data.required;
163 data = $.extend({required: param}, data);
164 }
165
166 return data;
167 }
168 });
169
170 // Custom selectors
171 $.extend($.expr[":"], {
172 // http://docs.jquery.com/Plugins/Validation/blank
173 blank: function(a) {return !$.trim("" + a.value);},
174 // http://docs.jquery.com/Plugins/Validation/filled
175 filled: function(a) {return !!$.trim("" + a.value);},
176 // http://docs.jquery.com/Plugins/Validation/unchecked
177 unchecked: function(a) {return !a.checked;}
178 });
179
180 // constructor for validator
181 $.validator = function( options, form ) {
182 this.settings = $.extend( true, {}, $.validator.defaults, options );
183 this.currentForm = form;
184 this.init();
185 };
186
187 $.validator.format = function(source, params) {
188 if ( arguments.length == 1 ) {
189 return function() {
190 var args = $.makeArray(arguments);
191 args.unshift(source);
192 return $.validator.format.apply( this, args );
193 };
194 }
195 if ( arguments.length > 2 && params.constructor != Array ) {
196 params = $.makeArray(arguments).slice(1);
197 }
198 if ( params.constructor != Array ) {
199 params = [ params ];
200 }
201 $.each(params, function(i, n) {
202 source = source.replace(new RegExp("\\{" + i + "\\}", "g"), n);
203 });
204 return source;
205 };
206
207 $.extend($.validator, {
208
209 defaults: {
210 messages: {},
211 groups: {},
212 rules: {},
213 errorClass: "error",
214 validClass: "valid",
215 errorElement: "label",
216 focusInvalid: true,
217 errorContainer: $( [] ),
218 errorLabelContainer: $( [] ),
219 onsubmit: true,
220 ignore: [],
221 ignoreTitle: false,
222 onfocusin: function(element) {
223 this.lastActive = element;
224
225 // hide error label and remove error class on focus if enabled
226 if ( this.settings.focusCleanup && !this.blockFocusCleanup ) {
227 this.settings.unhighlight && this.settings.unhighlight.call( this, element, this.settings.errorClass, this.settings.validClass );
228 this.errorsFor(element).hide();
229 }
230 },
231 onfocusout: function(element) {
232 if ( !this.checkable(element) && (element.name in this.submitted || !this.optional(element)) ) {
233 this.element(element);
234 }
235 },
236 onkeyup: function(element) {
237 if ( element.name in this.submitted || element == this.lastElement ) {
238 this.element(element);
239 }
240 },
241 onclick: function(element) {
242 // click on selects, radiobuttons and checkboxes
243 if ( element.name in this.submitted ) {
244 this.element(element);
245 }
246 // or option elements, check parent select in that case
247 else if (element.parentNode.name in this.submitted) {
248 this.element(element.parentNode);
249 }
250 },
251 highlight: function( element, errorClass, validClass ) {
252 $(element).addClass(errorClass).removeClass(validClass);
253 },
254 unhighlight: function( element, errorClass, validClass ) {
255 $(element).removeClass(errorClass).addClass(validClass);
256 }
257 },
258
259 // http://docs.jquery.com/Plugins/Validation/Validator/setDefaults
260 setDefaults: function(settings) {
261 $.extend( $.validator.defaults, settings );
262 },
263
264 messages: {
265 required: "This field is required.",
266 remote: "Please fix this field.",
267 email: "Please enter a valid email address.",
268 url: "Please enter a valid URL.",
269 date: "Please enter a valid date.",
270 dateISO: "Please enter a valid date (ISO).",
271 number: "Please enter a valid number.",
272 digits: "Please enter only digits.",
273 creditcard: "Please enter a valid credit card number.",
274 equalTo: "Please enter the same value again.",
275 accept: "Please enter a value with a valid extension.",
276 maxlength: $.validator.format("Please enter no more than {0} characters."),
277 minlength: $.validator.format("Please enter at least {0} characters."),
278 rangelength: $.validator.format("Please enter a value between {0} and {1} characters long."),
279 range: $.validator.format("Please enter a value between {0} and {1}."),
280 max: $.validator.format("Please enter a value less than or equal to {0}."),
281 min: $.validator.format("Please enter a value greater than or equal to {0}.")
282 },
283
284 autoCreateRanges: false,
285
286 prototype: {
287
288 init: function() {
289 this.labelContainer = $(this.settings.errorLabelContainer);
290 this.errorContext = this.labelContainer.length && this.labelContainer || $(this.currentForm);
291 this.containers = $(this.settings.errorContainer).add( this.settings.errorLabelContainer );
292 this.submitted = {};
293 this.valueCache = {};
294 this.pendingRequest = 0;
295 this.pending = {};
296 this.invalid = {};
297 this.reset();
298
299 var groups = (this.groups = {});
300 $.each(this.settings.groups, function(key, value) {
301 $.each(value.split(/\s/), function(index, name) {
302 groups[name] = key;
303 });
304 });
305 var rules = this.settings.rules;
306 $.each(rules, function(key, value) {
307 rules[key] = $.validator.normalizeRule(value);
308 });
309
310 function delegate(event) {
311 var validator = $.data(this[0].form, "validator"),
312 eventType = "on" + event.type.replace(/^validate/, "");
313 validator.settings[eventType] && validator.settings[eventType].call(validator, this[0] );
314 }
315 $(this.currentForm)
316 .validateDelegate(":text, :password, :file, select, textarea", "focusin focusout keyup", delegate)
317 .validateDelegate(":radio, :checkbox, select, option", "click", delegate);
318
319 if (this.settings.invalidHandler) {
320 $(this.currentForm).bind("invalid-form.validate", this.settings.invalidHandler);
321 }
322 },
323
324 // http://docs.jquery.com/Plugins/Validation/Validator/form
325 form: function() {
326 this.checkForm();
327 $.extend(this.submitted, this.errorMap);
328 this.invalid = $.extend({}, this.errorMap);
329 if (!this.valid()) {
330 $(this.currentForm).triggerHandler("invalid-form", [this]);
331 }
332 this.showErrors();
333 return this.valid();
334 },
335
336 checkForm: function() {
337 this.prepareForm();
338 for ( var i = 0, elements = (this.currentElements = this.elements()); elements[i]; i++ ) {
339 this.check( elements[i] );
340 }
341 return this.valid();
342 },
343
344 // http://docs.jquery.com/Plugins/Validation/Validator/element
345 element: function( element ) {
346 element = this.clean( element );
347 this.lastElement = element;
348 this.prepareElement( element );
349 this.currentElements = $(element);
350 var result = this.check( element );
351 if ( result ) {
352 delete this.invalid[element.name];
353 } else {
354 this.invalid[element.name] = true;
355 }
356 if ( !this.numberOfInvalids() ) {
357 // Hide error containers on last error
358 this.toHide = this.toHide.add( this.containers );
359 }
360 this.showErrors();
361 return result;
362 },
363
364 // http://docs.jquery.com/Plugins/Validation/Validator/showErrors
365 showErrors: function(errors) {
366 if(errors) {
367 // add items to error list and map
368 $.extend( this.errorMap, errors );
369 this.errorList = [];
370 for ( var name in errors ) {
371 this.errorList.push({
372 message: errors[name],
373 element: this.findByName(name)[0]
374 });
375 }
376 // remove items from success list
377 this.successList = $.grep( this.successList, function(element) {
378 return !(element.name in errors);
379 });
380 }
381 this.settings.showErrors
382 ? this.settings.showErrors.call( this, this.errorMap, this.errorList )
383 : this.defaultShowErrors();
384 },
385
386 // http://docs.jquery.com/Plugins/Validation/Validator/resetForm
387 resetForm: function() {
388 if ( $.fn.resetForm ) {
389 $( this.currentForm ).resetForm();
390 }
391 this.submitted = {};
392 this.prepareForm();
393 this.hideErrors();
394 this.elements().removeClass( this.settings.errorClass );
395 },
396
397 numberOfInvalids: function() {
398 return this.objectLength(this.invalid);
399 },
400
401 objectLength: function( obj ) {
402 var count = 0;
403 for ( var i in obj ) {
404 count++;
405 }
406 return count;
407 },
408
409 hideErrors: function() {
410 this.addWrapper( this.toHide ).hide();
411 },
412
413 valid: function() {
414 return this.size() == 0;
415 },
416
417 size: function() {
418 return this.errorList.length;
419 },
420
421 focusInvalid: function() {
422 if( this.settings.focusInvalid ) {
423 try {
424 $(this.findLastActive() || this.errorList.length && this.errorList[0].element || [])
425 .filter(":visible")
426 .focus()
427 // manually trigger focusin event; without it, focusin handler isn't called, findLastActive won't have anything to find
428 .trigger("focusin");
429 } catch(e) {
430 // ignore IE throwing errors when focusing hidden elements
431 }
432 }
433 },
434
435 findLastActive: function() {
436 var lastActive = this.lastActive;
437 return lastActive && $.grep(this.errorList, function(n) {
438 return n.element.name == lastActive.name;
439 }).length == 1 && lastActive;
440 },
441
442 elements: function() {
443 var validator = this,
444 rulesCache = {};
445
446 // select all valid inputs inside the form (no submit or reset buttons)
447 // workaround $Query([]).add until http://dev.jquery.com/ticket/2114 is solved
448 return $([]).add(this.currentForm.elements)
449 .filter(":input")
450 .not(":submit, :reset, :image, [disabled]")
451 .not( this.settings.ignore )
452 .filter(function() {
453 !this.name && validator.settings.debug && window.console && console.error( "%o has no name assigned", this);
454
455 // select only the first element for each name, and only those with rules specified
456 if ( this.name in rulesCache || !validator.objectLength($(this).rules()) ) {
457 return false;
458 }
459
460 rulesCache[this.name] = true;
461 return true;
462 });
463 },
464
465 clean: function( selector ) {
466 return $( selector )[0];
467 },
468
469 errors: function() {
470 return $( this.settings.errorElement + "." + this.settings.errorClass, this.errorContext );
471 },
472
473 reset: function() {
474 this.successList = [];
475 this.errorList = [];
476 this.errorMap = {};
477 this.toShow = $([]);
478 this.toHide = $([]);
479 this.currentElements = $([]);
480 },
481
482 prepareForm: function() {
483 this.reset();
484 this.toHide = this.errors().add( this.containers );
485 },
486
487 prepareElement: function( element ) {
488 this.reset();
489 this.toHide = this.errorsFor(element);
490 },
491
492 check: function( element ) {
493 element = this.clean( element );
494
495 // if radio/checkbox, validate first element in group instead
496 if (this.checkable(element)) {
497 element = this.findByName( element.name )[0];
498 }
499
500 var rules = $(element).rules();
501 var dependencyMismatch = false;
502 for( method in rules ) {
503 var rule = { method: method, parameters: rules[method] };
504 try {
505 var result = $.validator.methods[method].call( this, element.value.replace(/\r/g, ""), element, rule.parameters );
506
507 // if a method indicates that the field is optional and therefore valid,
508 // don't mark it as valid when there are no other rules
509 if ( result == "dependency-mismatch" ) {
510 dependencyMismatch = true;
511 continue;
512 }
513 dependencyMismatch = false;
514
515 if ( result == "pending" ) {
516 this.toHide = this.toHide.not( this.errorsFor(element) );
517 return;
518 }
519
520 if( !result ) {
521 this.formatAndAdd( element, rule );
522 return false;
523 }
524 } catch(e) {
525 this.settings.debug && window.console && console.log("exception occured when checking element " + element.id
526 + ", check the '" + rule.method + "' method", e);
527 throw e;
528 }
529 }
530 if (dependencyMismatch) {
531 return;
532 }
533 if ( this.objectLength(rules) ) {
534 this.successList.push(element);
535 }
536 return true;
537 },
538
539 // return the custom message for the given element and validation method
540 // specified in the element's "messages" metadata
541 customMetaMessage: function(element, method) {
542 if (!$.metadata) {
543 return;
544 }
545
546 var meta = this.settings.meta
547 ? $(element).metadata()[this.settings.meta]
548 : $(element).metadata();
549
550 return meta && meta.messages && meta.messages[method];
551 },
552
553 // return the custom message for the given element name and validation method
554 customMessage: function( name, method ) {
555 var m = this.settings.messages[name];
556 return m && (m.constructor == String
557 ? m
558 : m[method]);
559 },
560
561 // return the first defined argument, allowing empty strings
562 findDefined: function() {
563 for(var i = 0; i < arguments.length; i++) {
564 if (arguments[i] !== undefined) {
565 return arguments[i];
566 }
567 }
568 return undefined;
569 },
570
571 defaultMessage: function( element, method) {
572 return this.findDefined(
573 this.customMessage( element.name, method ),
574 this.customMetaMessage( element, method ),
575 // title is never undefined, so handle empty string as undefined
576 !this.settings.ignoreTitle && element.title || undefined,
577 $.validator.messages[method],
578 "<strong>Warning: No message defined for " + element.name + "</strong>"
579 );
580 },
581
582 formatAndAdd: function( element, rule ) {
583 var message = this.defaultMessage( element, rule.method ),
584 theregex = /\$?\{(\d+)\}/g;
585 if ( typeof message == "function" ) {
586 message = message.call(this, rule.parameters, element);
587 } else if (theregex.test(message)) {
588 message = jQuery.format(message.replace(theregex, '{$1}'), rule.parameters);
589 }
590 this.errorList.push({
591 message: message,
592 element: element
593 });
594
595 this.errorMap[element.name] = message;
596 this.submitted[element.name] = message;
597 },
598
599 addWrapper: function(toToggle) {
600 if ( this.settings.wrapper ) {
601 toToggle = toToggle.add( toToggle.parent( this.settings.wrapper ) );
602 }
603 return toToggle;
604 },
605
606 defaultShowErrors: function() {
607 for ( var i = 0; this.errorList[i]; i++ ) {
608 var error = this.errorList[i];
609 this.settings.highlight && this.settings.highlight.call( this, error.element, this.settings.errorClass, this.settings.validClass );
610 this.showLabel( error.element, error.message );
611 }
612 if( this.errorList.length ) {
613 this.toShow = this.toShow.add( this.containers );
614 }
615 if (this.settings.success) {
616 for ( var i = 0; this.successList[i]; i++ ) {
617 this.showLabel( this.successList[i] );
618 }
619 }
620 if (this.settings.unhighlight) {
621 for ( var i = 0, elements = this.validElements(); elements[i]; i++ ) {
622 this.settings.unhighlight.call( this, elements[i], this.settings.errorClass, this.settings.validClass );
623 }
624 }
625 this.toHide = this.toHide.not( this.toShow );
626 this.hideErrors();
627 this.addWrapper( this.toShow ).show();
628 },
629
630 validElements: function() {
631 return this.currentElements.not(this.invalidElements());
632 },
633
634 invalidElements: function() {
635 return $(this.errorList).map(function() {
636 return this.element;
637 });
638 },
639
640 showLabel: function(element, message) {
641 var label = this.errorsFor( element );
642 if ( label.length ) {
643 // refresh error/success class
644 label.removeClass().addClass( this.settings.errorClass );
645
646 // check if we have a generated label, replace the message then
647 label.attr("generated") && label.html(message);
648 } else {
649 // create label
650 label = $("<" + this.settings.errorElement + "/>")
651 .attr({"for": this.idOrName(element), generated: true})
652 .addClass(this.settings.errorClass)
653 .html(message || "");
654 if ( this.settings.wrapper ) {
655 // make sure the element is visible, even in IE
656 // actually showing the wrapped element is handled elsewhere
657 label = label.hide().show().wrap("<" + this.settings.wrapper + "/>").parent();
658 }
659 if ( !this.labelContainer.append(label).length ) {
660 this.settings.errorPlacement
661 ? this.settings.errorPlacement(label, $(element) )
662 : label.insertAfter(element);
663 }
664 }
665 if ( !message && this.settings.success ) {
666 label.text("");
667 typeof this.settings.success == "string"
668 ? label.addClass( this.settings.success )
669 : this.settings.success( label );
670 }
671 this.toShow = this.toShow.add(label);
672 },
673
674 errorsFor: function(element) {
675 var name = this.idOrName(element);
676 return this.errors().filter(function() {
677 return $(this).attr('for') == name;
678 });
679 },
680
681 idOrName: function(element) {
682 return this.groups[element.name] || (this.checkable(element) ? element.name : element.id || element.name);
683 },
684
685 checkable: function( element ) {
686 return /radio|checkbox/i.test(element.type);
687 },
688
689 findByName: function( name ) {
690 // select by name and filter by form for performance over form.find("[name=...]")
691 var form = this.currentForm;
692 return $(document.getElementsByName(name)).map(function(index, element) {
693 return element.form == form && element.name == name && element || null;
694 });
695 },
696
697 getLength: function(value, element) {
698 switch( element.nodeName.toLowerCase() ) {
699 case 'select':
700 return $("option:selected", element).length;
701 case 'input':
702 if( this.checkable( element) ) {
703 return this.findByName(element.name).filter(':checked').length;
704 }
705 }
706 return value.length;
707 },
708
709 depend: function(param, element) {
710 return this.dependTypes[typeof param]
711 ? this.dependTypes[typeof param](param, element)
712 : true;
713 },
714
715 dependTypes: {
716 "boolean": function(param, element) {
717 return param;
718 },
719 "string": function(param, element) {
720 return !!$(param, element.form).length;
721 },
722 "function": function(param, element) {
723 return param(element);
724 }
725 },
726
727 optional: function(element) {
728 return !$.validator.methods.required.call(this, $.trim(element.value), element) && "dependency-mismatch";
729 },
730
731 startRequest: function(element) {
732 if (!this.pending[element.name]) {
733 this.pendingRequest++;
734 this.pending[element.name] = true;
735 }
736 },
737
738 stopRequest: function(element, valid) {
739 this.pendingRequest--;
740 // sometimes synchronization fails, make sure pendingRequest is never < 0
741 if (this.pendingRequest < 0) {
742 this.pendingRequest = 0;
743 }
744 delete this.pending[element.name];
745 if ( valid && this.pendingRequest == 0 && this.formSubmitted && this.form() ) {
746 $(this.currentForm).submit();
747 this.formSubmitted = false;
748 } else if (!valid && this.pendingRequest == 0 && this.formSubmitted) {
749 $(this.currentForm).triggerHandler("invalid-form", [this]);
750 this.formSubmitted = false;
751 }
752 },
753
754 previousValue: function(element) {
755 return $.data(element, "previousValue") || $.data(element, "previousValue", {
756 old: null,
757 valid: true,
758 message: this.defaultMessage( element, "remote" )
759 });
760 }
761
762 },
763
764 classRuleSettings: {
765 required: {required: true},
766 email: {email: true},
767 url: {url: true},
768 date: {date: true},
769 dateISO: {dateISO: true},
770 dateDE: {dateDE: true},
771 number: {number: true},
772 numberDE: {numberDE: true},
773 digits: {digits: true},
774 creditcard: {creditcard: true}
775 },
776
777 addClassRules: function(className, rules) {
778 className.constructor == String ?
779 this.classRuleSettings[className] = rules :
780 $.extend(this.classRuleSettings, className);
781 },
782
783 classRules: function(element) {
784 var rules = {};
785 var classes = $(element).attr('class');
786 classes && $.each(classes.split(' '), function() {
787 if (this in $.validator.classRuleSettings) {
788 $.extend(rules, $.validator.classRuleSettings[this]);
789 }
790 });
791 return rules;
792 },
793
794 attributeRules: function(element) {
795 var rules = {};
796 var $element = $(element);
797
798 for (method in $.validator.methods) {
799 var value = $element.attr(method);
800 if (value) {
801 rules[method] = value;
802 }
803 }
804
805 // maxlength may be returned as -1, 2147483647 (IE) and 524288 (safari) for text inputs
806 if (rules.maxlength && /-1|2147483647|524288/.test(rules.maxlength)) {
807 delete rules.maxlength;
808 }
809
810 return rules;
811 },
812
813 metadataRules: function(element) {
814 if (!$.metadata) return {};
815
816 var meta = $.data(element.form, 'validator').settings.meta;
817 return meta ?
818 $(element).metadata()[meta] :
819 $(element).metadata();
820 },
821
822 staticRules: function(element) {
823 var rules = {};
824 var validator = $.data(element.form, 'validator');
825 if (validator.settings.rules) {
826 rules = $.validator.normalizeRule(validator.settings.rules[element.name]) || {};
827 }
828 return rules;
829 },
830
831 normalizeRules: function(rules, element) {
832 // handle dependency check
833 $.each(rules, function(prop, val) {
834 // ignore rule when param is explicitly false, eg. required:false
835 if (val === false) {
836 delete rules[prop];
837 return;
838 }
839 if (val.param || val.depends) {
840 var keepRule = true;
841 switch (typeof val.depends) {
842 case "string":
843 keepRule = !!$(val.depends, element.form).length;
844 break;
845 case "function":
846 keepRule = val.depends.call(element, element);
847 break;
848 }
849 if (keepRule) {
850 rules[prop] = val.param !== undefined ? val.param : true;
851 } else {
852 delete rules[prop];
853 }
854 }
855 });
856
857 // evaluate parameters
858 $.each(rules, function(rule, parameter) {
859 rules[rule] = $.isFunction(parameter) ? parameter(element) : parameter;
860 });
861
862 // clean number parameters
863 $.each(['minlength', 'maxlength', 'min', 'max'], function() {
864 if (rules[this]) {
865 rules[this] = Number(rules[this]);
866 }
867 });
868 $.each(['rangelength', 'range'], function() {
869 if (rules[this]) {
870 rules[this] = [Number(rules[this][0]), Number(rules[this][1])];
871 }
872 });
873
874 if ($.validator.autoCreateRanges) {
875 // auto-create ranges
876 if (rules.min && rules.max) {
877 rules.range = [rules.min, rules.max];
878 delete rules.min;
879 delete rules.max;
880 }
881 if (rules.minlength && rules.maxlength) {
882 rules.rangelength = [rules.minlength, rules.maxlength];
883 delete rules.minlength;
884 delete rules.maxlength;
885 }
886 }
887
888 // To support custom messages in metadata ignore rule methods titled "messages"
889 if (rules.messages) {
890 delete rules.messages;
891 }
892
893 return rules;
894 },
895
896 // Converts a simple string to a {string: true} rule, e.g., "required" to {required:true}
897 normalizeRule: function(data) {
898 if( typeof data == "string" ) {
899 var transformed = {};
900 $.each(data.split(/\s/), function() {
901 transformed[this] = true;
902 });
903 data = transformed;
904 }
905 return data;
906 },
907
908 // http://docs.jquery.com/Plugins/Validation/Validator/addMethod
909 addMethod: function(name, method, message) {
910 $.validator.methods[name] = method;
911 $.validator.messages[name] = message != undefined ? message : $.validator.messages[name];
912 if (method.length < 3) {
913 $.validator.addClassRules(name, $.validator.normalizeRule(name));
914 }
915 },
916
917 methods: {
918
919 // http://docs.jquery.com/Plugins/Validation/Methods/required
920 required: function(value, element, param) {
921 // check if dependency is met
922 if ( !this.depend(param, element) ) {
923 return "dependency-mismatch";
924 }
925 switch( element.nodeName.toLowerCase() ) {
926 case 'select':
927 // could be an array for select-multiple or a string, both are fine this way
928 var val = $(element).val();
929 return val && val.length > 0;
930 case 'input':
931 if ( this.checkable(element) ) {
932 return this.getLength(value, element) > 0;
933 }
934 default:
935 return $.trim(value).length > 0;
936 }
937 },
938
939 // http://docs.jquery.com/Plugins/Validation/Methods/remote
940 remote: function(value, element, param) {
941 if ( this.optional(element) ) {
942 return "dependency-mismatch";
943 }
944
945 var previous = this.previousValue(element);
946 if (!this.settings.messages[element.name] ) {
947 this.settings.messages[element.name] = {};
948 }
949 previous.originalMessage = this.settings.messages[element.name].remote;
950 this.settings.messages[element.name].remote = previous.message;
951
952 param = typeof param == "string" && {url:param} || param;
953
954 if ( previous.old !== value ) {
955 previous.old = value;
956 var validator = this;
957 this.startRequest(element);
958 var data = {};
959 data[element.name] = value;
960 $.ajax($.extend(true, {
961 url: param,
962 mode: "abort",
963 port: "validate" + element.name,
964 dataType: "json",
965 data: data,
966 success: function(response) {
967 validator.settings.messages[element.name].remote = previous.originalMessage;
968 var valid = response === true;
969 if ( valid ) {
970 var submitted = validator.formSubmitted;
971 validator.prepareElement(element);
972 validator.formSubmitted = submitted;
973 validator.successList.push(element);
974 validator.showErrors();
975 } else {
976 var errors = {};
977 var message = (previous.message = response || validator.defaultMessage( element, "remote" ));
978 errors[element.name] = $.isFunction(message) ? message(value) : message;
979 validator.showErrors(errors);
980 }
981 previous.valid = valid;
982 validator.stopRequest(element, valid);
983 }
984 }, param));
985 return "pending";
986 } else if( this.pending[element.name] ) {
987 return "pending";
988 }
989 return previous.valid;
990 },
991
992 // http://docs.jquery.com/Plugins/Validation/Methods/minlength
993 minlength: function(value, element, param) {
994 return this.optional(element) || this.getLength($.trim(value), element) >= param;
995 },
996
997 // http://docs.jquery.com/Plugins/Validation/Methods/maxlength
998 maxlength: function(value, element, param) {
999 return this.optional(element) || this.getLength($.trim(value), element) <= param;
1000 },
1001
1002 // http://docs.jquery.com/Plugins/Validation/Methods/rangelength
1003 rangelength: function(value, element, param) {
1004 var length = this.getLength($.trim(value), element);
1005 return this.optional(element) || ( length >= param[0] && length <= param[1] );
1006 },
1007
1008 // http://docs.jquery.com/Plugins/Validation/Methods/min
1009 min: function( value, element, param ) {
1010 return this.optional(element) || value >= param;
1011 },
1012
1013 // http://docs.jquery.com/Plugins/Validation/Methods/max
1014 max: function( value, element, param ) {
1015 return this.optional(element) || value <= param;
1016 },
1017
1018 // http://docs.jquery.com/Plugins/Validation/Methods/range
1019 range: function( value, element, param ) {
1020 return this.optional(element) || ( value >= param[0] && value <= param[1] );
1021 },
1022
1023 // http://docs.jquery.com/Plugins/Validation/Methods/email
1024 email: function(value, element) {
1025 // contributed by Scott Gonzalez: http://projects.scottsplayground.com/email_address_validation/
1026 return this.optional(element) || /^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?$/i.test(value);
1027 },
1028
1029 // http://docs.jquery.com/Plugins/Validation/Methods/url
1030 url: function(value, element) {
1031 // contributed by Scott Gonzalez: http://projects.scottsplayground.com/iri/
1032 return this.optional(element) || /^(https?|ftp):\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(\#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i.test(value);
1033 },
1034
1035 // http://docs.jquery.com/Plugins/Validation/Methods/date
1036 date: function(value, element) {
1037 return this.optional(element) || !/Invalid|NaN/.test(new Date(value));
1038 },
1039
1040 // http://docs.jquery.com/Plugins/Validation/Methods/dateISO
1041 dateISO: function(value, element) {
1042 return this.optional(element) || /^\d{4}[\/-]\d{1,2}[\/-]\d{1,2}$/.test(value);
1043 },
1044
1045 // http://docs.jquery.com/Plugins/Validation/Methods/number
1046 number: function(value, element) {
1047 return this.optional(element) || /^-?(?:\d+|\d{1,3}(?:,\d{3})+)(?:\.\d+)?$/.test(value);
1048 },
1049
1050 // http://docs.jquery.com/Plugins/Validation/Methods/digits
1051 digits: function(value, element) {
1052 return this.optional(element) || /^\d+$/.test(value);
1053 },
1054
1055 // http://docs.jquery.com/Plugins/Validation/Methods/creditcard
1056 // based on http://en.wikipedia.org/wiki/Luhn
1057 creditcard: function(value, element) {
1058 if ( this.optional(element) ) {
1059 return "dependency-mismatch";
1060 }
1061 // accept only digits and dashes
1062 if (/[^0-9-]+/.test(value)) {
1063 return false;
1064 }
1065 var nCheck = 0,
1066 nDigit = 0,
1067 bEven = false;
1068
1069 value = value.replace(/\D/g, "");
1070
1071 for (var n = value.length - 1; n >= 0; n--) {
1072 var cDigit = value.charAt(n);
1073 var nDigit = parseInt(cDigit, 10);
1074 if (bEven) {
1075 if ((nDigit *= 2) > 9) {
1076 nDigit -= 9;
1077 }
1078 }
1079 nCheck += nDigit;
1080 bEven = !bEven;
1081 }
1082
1083 return (nCheck % 10) == 0;
1084 },
1085
1086 // http://docs.jquery.com/Plugins/Validation/Methods/accept
1087 accept: function(value, element, param) {
1088 param = typeof param == "string" ? param.replace(/,/g, '|') : "png|jpe?g|gif";
1089 return this.optional(element) || value.match(new RegExp(".(" + param + ")$", "i"));
1090 },
1091
1092 // http://docs.jquery.com/Plugins/Validation/Methods/equalTo
1093 equalTo: function(value, element, param) {
1094 // bind to the blur event of the target in order to revalidate whenever the target field is updated
1095 // TODO find a way to bind the event just once, avoiding the unbind-rebind overhead
1096 var target = $(param).unbind(".validate-equalTo").bind("blur.validate-equalTo", function() {
1097 $(element).valid();
1098 });
1099 return value == target.val();
1100 }
1101
1102 }
1103
1104 });
1105
1106 // deprecated, use $.validator.format instead
1107 $.format = $.validator.format;
1108
1109})(jQuery);
1110
1111// ajax mode: abort
1112// usage: $.ajax({ mode: "abort"[, port: "uniqueport"]});
1113// if mode:"abort" is used, the previous request on that port (port can be undefined) is aborted via XMLHttpRequest.abort()
1114;(function($) {
1115 var ajax = $.ajax;
1116 var pendingRequests = {};
1117 $.ajax = function(settings) {
1118 // create settings for compatibility with ajaxSetup
1119 settings = $.extend(settings, $.extend({}, $.ajaxSettings, settings));
1120 var port = settings.port;
1121 if (settings.mode == "abort") {
1122 if ( pendingRequests[port] ) {
1123 pendingRequests[port].abort();
1124 }
1125 return (pendingRequests[port] = ajax.apply(this, arguments));
1126 }
1127 return ajax.apply(this, arguments);
1128 };
1129})(jQuery);
1130
1131// provides cross-browser focusin and focusout events
1132// IE has native support, in other browsers, use event caputuring (neither bubbles)
1133
1134// provides delegate(type: String, delegate: Selector, handler: Callback) plugin for easier event delegation
1135// handler is only called when $(event.target).is(delegate), in the scope of the jquery-object for event.target
1136;(function($) {
1137 // only implement if not provided by jQuery core (since 1.4)
1138 // TODO verify if jQuery 1.4's implementation is compatible with older jQuery special-event APIs
1139 if (!jQuery.event.special.focusin && !jQuery.event.special.focusout && document.addEventListener) {
1140 $.each({
1141 focus: 'focusin',
1142 blur: 'focusout'
1143 }, function( original, fix ){
1144 $.event.special[fix] = {
1145 setup:function() {
1146 this.addEventListener( original, handler, true );
1147 },
1148 teardown:function() {
1149 this.removeEventListener( original, handler, true );
1150 },
1151 handler: function(e) {
1152 arguments[0] = $.event.fix(e);
1153 arguments[0].type = fix;
1154 return $.event.handle.apply(this, arguments);
1155 }
1156 };
1157 function handler(e) {
1158 e = $.event.fix(e);
1159 e.type = fix;
1160 return $.event.handle.call(this, e);
1161 }
1162 });
1163 };
1164 $.extend($.fn, {
1165 validateDelegate: function(delegate, type, handler) {
1166 return this.bind(type, function(event) {
1167 var target = $(event.target);
1168 if (target.is(delegate)) {
1169 return handler.apply(target, arguments);
1170 }
1171 });
1172 }
1173 });
1174})(jQuery);
Note: See TracBrowser for help on using the repository browser.