PluginProbe
RSVP and Event Management / 1.2.0
RSVP and Event Management v1.2.0
trunk 0.5.0 0.6.0 0.7.0 0.8.0 0.9.0 0.9.5 1.0.0 1.1.0 1.2.0 1.2.1 1.3.0 1.3.1 1.3.2 1.5.0 1.6.0 1.6.1 1.6.2 1.6.5 1.7.0 1.7.2 1.7.3 1.7.4 1.7.5 1.7.6 All 136 releases
rsvp / jquery-validate / jquery.validate.js

jquery.validate.js in RSVP and Event Management 1.2.0, at jquery-validate/jquery.validate.js

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