PageSourceSearch

https://prajayengineers.com/include/js/jquery.validate.js

js prajayengineers.com collected 2026-10-05 10:44:56 UTC 85,508 bytes, 2,659 lines download raw bytes

vendor: 48,157 bytes, lines 1-1606
1/*!
2 * jQuery Validation Plugin v1.15.0
3 *
4 * http://jqueryvalidation.org/
5 *
6 * Copyright (c) 2016 Jörn Zaefferer
7 * Released under the MIT license
8 */
9(function( factory ) {
10	if ( typeof define === "function" && define.amd ) {
11		define( ["jquery"], factory );
12	} else if (typeof module === "object" && module.exports) {
13		module.exports = factory( require( "jquery" ) );
14	} else {
15		factory( jQuery );
16	}
17}(function( $ ) {
18
19$.extend( $.fn, {
20
21	// http://jqueryvalidation.org/validate/
22	validate: function( options ) {
23
24		// If nothing is selected, return nothing; can't chain anyway
25		if ( !this.length ) {
26			if ( options && options.debug && window.console ) {
27				console.warn( "Nothing selected, can't validate, returning nothing." );
28			}
29			return;
30		}
31
32		// Check if a validator for this form was already created
33		var validator = $.data( this[ 0 ], "validator" );
34		if ( validator ) {
35			return validator;
36		}
37
38		// Add novalidate tag if HTML5.
39		this.attr( "novalidate", "novalidate" );
40
41		validator = new $.validator( options, this[ 0 ] );
42		$.data( this[ 0 ], "validator", validator );
43
44		if ( validator.settings.onsubmit ) {
45
46			this.on( "click.validate", ":submit", function( event ) {
47				if ( validator.settings.submitHandler ) {
48					validator.submitButton = event.target;
49				}
50
51				// Allow suppressing validation by adding a cancel class to the submit button
52				if ( $( this ).hasClass( "cancel" ) ) {
53					validator.cancelSubmit = true;
54				}
55
56				// Allow suppressing validation by adding the html5 formnovalidate attribute to the submit button
57				if ( $( this ).attr( "formnovalidate" ) !== undefined ) {
58					validator.cancelSubmit = true;
59				}
60			} );
61
62			// Validate the form on submit
63			this.on( "submit.validate", function( event ) {
64				if ( validator.settings.debug ) {
65
66					// Prevent form submit to be able to see console output
67					event.preventDefault();
68				}
69				function handle() {
70					var hidden, result;
71					if ( validator.settings.submitHandler ) {
72						if ( validator.submitButton ) {
73
74							// Insert a hidden input as a replacement for the missing submit button
75							hidden = $( "<input type='hidden'/>" )
76								.attr( "name", validator.submitButton.name )
77								.val( $( validator.submitButton ).val() )
78								.appendTo( validator.currentForm );
79						}
80						result = validator.settings.submitHandler.call( validator, validator.currentForm, event );
81						if ( validator.submitButton ) {
82
83							// And clean up afterwards; thanks to no-block-scope, hidden can be referenced
84							hidden.remove();
85						}
86						if ( result !== undefined ) {
87							return result;
88						}
89						return false;
90					}
91					return true;
92				}
93
94				// Prevent submit for invalid forms or custom submit handlers
95				if ( validator.cancelSubmit ) {
96					validator.cancelSubmit = false;
97					return handle();
98				}
99				if ( validator.form() ) {
100					if ( validator.pendingRequest ) {
101						validator.formSubmitted = true;
102						return false;
103					}
104					return handle();
105				} else {
106					validator.focusInvalid();
107					return false;
108				}
109			} );
110		}
111
112		return validator;
113	},
114
115	// http://jqueryvalidation.org/valid/
116	valid: function() {
117		var valid, validator, errorList;
118
119		if ( $( this[ 0 ] ).is( "form" ) ) {
120			valid = this.validate().form();
121		} else {
122			errorList = [];
123			valid = true;
124			validator = $( this[ 0 ].form ).validate();
125			this.each( function() {
126				valid = validator.element( this ) && valid;
127				if ( !valid ) {
128					errorList = errorList.concat( validator.errorList );
129				}
130			} );
131			validator.errorList = errorList;
132		}
133		return valid;
134	},
135
136	// http://jqueryvalidation.org/rules/
137	rules: function( command, argument ) {
138
139		// If nothing is selected, return nothing; can't chain anyway
140		if ( !this.length ) {
141			return;
142		}
143
144		var element = this[ 0 ],
145			settings, staticRules, existingRules, data, param, filtered;
146
147		if ( command ) {
148			settings = $.data( element.form, "validator" ).settings;
149			staticRules = settings.rules;
150			existingRules = $.validator.staticRules( element );
151			switch ( command ) {
152			case "add":
153				$.extend( existingRules, $.validator.normalizeRule( argument ) );
154
155				// Remove messages from rules, but allow them to be set separately
156				delete existingRules.messages;
157				staticRules[ element.name ] = existingRules;
158				if ( argument.messages ) {
159					settings.messages[ element.name ] = $.extend( settings.messages[ element.name ], argument.messages );
160				}
161				break;
162			case "remove":
163				if ( !argument ) {
164					delete staticRules[ element.name ];
165					return existingRules;
166				}
167				filtered = {};
168				$.each( argument.split( /\s/ ), function( index, method ) {
169					filtered[ method ] = existingRules[ method ];
170					delete existingRules[ method ];
171					if ( method === "required" ) {
172						$( element ).removeAttr( "aria-required" );
173					}
174				} );
175				return filtered;
176			}
177		}
178
179		data = $.validator.normalizeRules(
180		$.extend(
181			{},
182			$.validator.classRules( element ),
183			$.validator.attributeRules( element ),
184			$.validator.dataRules( element ),
185			$.validator.staticRules( element )
186		), element );
187
188		// Make sure required is at front
189		if ( data.required ) {
190			param = data.required;
191			delete data.required;
192			data = $.extend( { required: param }, data );
193			$( element ).attr( "aria-required", "true" );
194		}
195
196		// Make sure remote is at back
197		if ( data.remote ) {
198			param = data.remote;
199			delete data.remote;
200			data = $.extend( data, { remote: param } );
201		}
202
203		return data;
204	}
205} );
206
207// Custom selectors
208$.extend( $.expr[ ":" ], {
209
210	// http://jqueryvalidation.org/blank-selector/
211	blank: function( a ) {
212		return !$.trim( "" + $( a ).val() );
213	},
214
215	// http://jqueryvalidation.org/filled-selector/
216	filled: function( a ) {
217		var val = $( a ).val();
218		return val !== null && !!$.trim( "" + val );
219	},
220
221	// http://jqueryvalidation.org/unchecked-selector/
222	unchecked: function( a ) {
223		return !$( a ).prop( "checked" );
224	}
225} );
226
227// Constructor for validator
228$.validator = function( options, form ) {
229	this.settings = $.extend( true, {}, $.validator.defaults, options );
230	this.currentForm = form;
231	this.init();
232};
233
234// http://jqueryvalidation.org/jQuery.validator.format/
235$.validator.format = function( source, params ) {
236	if ( arguments.length === 1 ) {
237		return function() {
238			var args = $.makeArray( arguments );
239			args.unshift( source );
240			return $.validator.format.apply( this, args );
241		};
242	}
243	if ( params === undefined ) {
244		return source;
245	}
246	if ( arguments.length > 2 && params.constructor !== Array  ) {
247		params = $.makeArray( arguments ).slice( 1 );
248	}
249	if ( params.constructor !== Array ) {
250		params = [ params ];
251	}
252	$.each( params, function( i, n ) {
253		source = source.replace( new RegExp( "\\{" + i + "\\}", "g" ), function() {
254			return n;
255		} );
256	} );
257	return source;
258};
259
260$.extend( $.validator, {
261
262	defaults: {
263		messages: {},
264		groups: {},
265		rules: {},
266		errorClass: "error",
267		pendingClass: "pending",
268		validClass: "valid",
269		errorElement: "label",
270		focusCleanup: false,
271		focusInvalid: true,
272		errorContainer: $( [] ),
273		errorLabelContainer: $( [] ),
274		onsubmit: true,
275		ignore: ":hidden",
276		ignoreTitle: false,
277		onfocusin: function( element ) {
278			this.lastActive = element;
279
280			// Hide error label and remove error class on focus if enabled
281			if ( this.settings.focusCleanup ) {
282				if ( this.settings.unhighlight ) {
283					this.settings.unhighlight.call( this, element, this.settings.errorClass, this.settings.validClass );
284				}
285				this.hideThese( this.errorsFor( element ) );
286			}
287		},
288		onfocusout: function( element ) {
289			if ( !this.checkable( element ) && ( element.name in this.submitted || !this.optional( element ) ) ) {
290				this.element( element );
291			}
292		},
293		onkeyup: function( element, event ) {
294
295			// Avoid revalidate the field when pressing one of the following keys
296			// Shift       => 16
297			// Ctrl        => 17
298			// Alt         => 18
299			// Caps lock   => 20
300			// End         => 35
301			// Home        => 36
302			// Left arrow  => 37
303			// Up arrow    => 38
304			// Right arrow => 39
305			// Down arrow  => 40
306			// Insert      => 45
307			// Num lock    => 144
308			// AltGr key   => 225
309			var excludedKeys = [
310				16, 17, 18, 20, 35, 36, 37,
311				38, 39, 40, 45, 144, 225
312			];
313
314			if ( event.which === 9 && this.elementValue( element ) === "" || $.inArray( event.keyCode, excludedKeys ) !== -1 ) {
315				return;
316			} else if ( element.name in this.submitted || element.name in this.invalid ) {
317				this.element( element );
318			}
319		},
320		onclick: function( element ) {
321
322			// Click on selects, radiobuttons and checkboxes
323			if ( element.name in this.submitted ) {
324				this.element( element );
325
326			// Or option elements, check parent select in that case
327			} else if ( element.parentNode.name in this.submitted ) {
328				this.element( element.parentNode );
329			}
330		},
331		highlight: function( element, errorClass, validClass ) {
332			if ( element.type === "radio" ) {
333				this.findByName( element.name ).addClass( errorClass ).removeClass( validClass );
334			} else {
335				$( element ).addClass( errorClass ).removeClass( validClass );
336			}
337		},
338		unhighlight: function( element, errorClass, validClass ) {
339			if ( element.type === "radio" ) {
340				this.findByName( element.name ).removeClass( errorClass ).addClass( validClass );
341			} else {
342				$( element ).removeClass( errorClass ).addClass( validClass );
343			}
344		}
345	},
346
347	// http://jqueryvalidation.org/jQuery.validator.setDefaults/
348	setDefaults: function( settings ) {
349		$.extend( $.validator.defaults, settings );
350	},
351
352	messages: {
353		required: "This field is required.",
354		remote: "Please fix this field.",
355		email: "Please enter a valid email address.",
356		url: "Please enter a valid URL.",
357		date: "Please enter a valid date.",
358		dateISO: "Please enter a valid date ( ISO ).",
359		number: "Please enter a valid number.",
360		digits: "Please enter only digits.",
361		equalTo: "Please enter the same value again.",
362		maxlength: $.validator.format( "Please enter no more than {0} characters." ),
363		minlength: $.validator.format( "Please enter at least {0} characters." ),
364		rangelength: $.validator.format( "Please enter a value between {0} and {1} characters long." ),
365		range: $.validator.format( "Please enter a value between {0} and {1}." ),
366		max: $.validator.format( "Please enter a value less than or equal to {0}." ),
367		min: $.validator.format( "Please enter a value greater than or equal to {0}." ),
368		step: $.validator.format( "Please enter a multiple of {0}." )
369	},
370
371	autoCreateRanges: false,
372
373	prototype: {
374
375		init: function() {
376			this.labelContainer = $( this.settings.errorLabelContainer );
377			this.errorContext = this.labelContainer.length && this.labelContainer || $( this.currentForm );
378			this.containers = $( this.settings.errorContainer ).add( this.settings.errorLabelContainer );
379			this.submitted = {};
380			this.valueCache = {};
381			this.pendingRequest = 0;
382			this.pending = {};
383			this.invalid = {};
384			this.reset();
385
386			var groups = ( this.groups = {} ),
387				rules;
388			$.each( this.settings.groups, function( key, value ) {
389				if ( typeof value === "string" ) {
390					value = value.split( /\s/ );
391				}
392				$.each( value, function( index, name ) {
393					groups[ name ] = key;
394				} );
395			} );
396			rules = this.settings.rules;
397			$.each( rules, function( key, value ) {
398				rules[ key ] = $.validator.normalizeRule( value );
399			} );
400
401			function delegate( event ) {
402				var validator = $.data( this.form, "validator" ),
403					eventType = "on" + event.type.replace( /^validate/, "" ),
404					settings = validator.settings;
405				if ( settings[ eventType ] && !$( this ).is( settings.ignore ) ) {
406					settings[ eventType ].call( validator, this, event );
407				}
408			}
409
410			$( this.currentForm )
411				.on( "focusin.validate focusout.validate keyup.validate",
412					":text, [type='password'], [type='file'], select, textarea, [type='number'], [type='search'], " +
413					"[type='tel'], [type='url'], [type='email'], [type='datetime'], [type='date'], [type='month'], " +
414					"[type='week'], [type='time'], [type='datetime-local'], [type='range'], [type='color'], " +
415					"[type='radio'], [type='checkbox'], [contenteditable]", delegate )
416
417				// Support: Chrome, oldIE
418				// "select" is provided as event.target when clicking a option
419				.on( "click.validate", "select, option, [type='radio'], [type='checkbox']", delegate );
420
421			if ( this.settings.invalidHandler ) {
422				$( this.currentForm ).on( "invalid-form.validate", this.settings.invalidHandler );
423			}
424
425			// Add aria-required to any Static/Data/Class required fields before first validation
426			// Screen readers require this attribute to be present before the initial submission http://www.w3.org/TR/WCAG-TECHS/ARIA2.html
427			$( this.currentForm ).find( "[required], [data-rule-required], .required" ).attr( "aria-required", "true" );
428		},
429
430		// http://jqueryvalidation.org/Validator.form/
431		form: function() {
432			this.checkForm();
433			$.extend( this.submitted, this.errorMap );
434			this.invalid = $.extend( {}, this.errorMap );
435			if ( !this.valid() ) {
436				$( this.currentForm ).triggerHandler( "invalid-form", [ this ] );
437			}
438			this.showErrors();
439			return this.valid();
440		},
441
442		checkForm: function() {
443			this.prepareForm();
444			for ( var i = 0, elements = ( this.currentElements = this.elements() ); elements[ i ]; i++ ) {
445				this.check( elements[ i ] );
446			}
447			return this.valid();
448		},
449
450		// http://jqueryvalidation.org/Validator.element/
451		element: function( element ) {
452			var cleanElement = this.clean( element ),
453				checkElement = this.validationTargetFor( cleanElement ),
454				v = this,
455				result = true,
456				rs, group;
457
458			if ( checkElement === undefined ) {
459				delete this.invalid[ cleanElement.name ];
460			} else {
461				this.prepareElement( checkElement );
462				this.currentElements = $( checkElement );
463
464				// If this element is grouped, then validate all group elements already
465				// containing a value
466				group = this.groups[ checkElement.name ];
467				if ( group ) {
468					$.each( this.groups, function( name, testgroup ) {
469						if ( testgroup === group && name !== checkElement.name ) {
470							cleanElement = v.validationTargetFor( v.clean( v.findByName( name ) ) );
471							if ( cleanElement && cleanElement.name in v.invalid ) {
472								v.currentElements.push( cleanElement );
473								result = result && v.check( cleanElement );
474							}
475						}
476					} );
477				}
478
479				rs = this.check( checkElement ) !== false;
480				result = result && rs;
481				if ( rs ) {
482					this.invalid[ checkElement.name ] = false;
483				} else {
484					this.invalid[ checkElement.name ] = true;
485				}
486
487				if ( !this.numberOfInvalids() ) {
488
489					// Hide error containers on last error
490					this.toHide = this.toHide.add( this.containers );
491				}
492				this.showErrors();
493
494				// Add aria-invalid status for screen readers
495				$( element ).attr( "aria-invalid", !rs );
496			}
497
498			return result;
499		},
500
501		// http://jqueryvalidation.org/Validator.showErrors/
502		showErrors: function( errors ) {
503			if ( errors ) {
504				var validator = this;
505
506				// Add items to error list and map
507				$.extend( this.errorMap, errors );
508				this.errorList = $.map( this.errorMap, function( message, name ) {
509					return {
510						message: message,
511						element: validator.findByName( name )[ 0 ]
512					};
513				} );
514
515				// Remove items from success list
516				this.successList = $.grep( this.successList, function( element ) {
517					return !( element.name in errors );
518				} );
519			}
520			if ( this.settings.showErrors ) {
521				this.settings.showErrors.call( this, this.errorMap, this.errorList );
522			} else {
523				this.defaultShowErrors();
524			}
525		},
526
527		// http://jqueryvalidation.org/Validator.resetForm/
528		resetForm: function() {
529			if ( $.fn.resetForm ) {
530				$( this.currentForm ).resetForm();
531			}
532			this.invalid = {};
533			this.submitted = {};
534			this.prepareForm();
535			this.hideErrors();
536			var elements = this.elements()
537				.removeData( "previousValue" )
538				.removeAttr( "aria-invalid" );
539
540			this.resetElements( elements );
541		},
542
543		resetElements: function( elements ) {
544			var i;
545
546			if ( this.settings.unhighlight ) {
547				for ( i = 0; elements[ i ]; i++ ) {
548					this.settings.unhighlight.call( this, elements[ i ],
549						this.settings.errorClass, "" );
550					this.findByName( elements[ i ].name ).removeClass( this.settings.validClass );
551				}
552			} else {
553				elements
554					.removeClass( this.settings.errorClass )
555					.removeClass( this.settings.validClass );
556			}
557		},
558
559		numberOfInvalids: function() {
560			return this.objectLength( this.invalid );
561		},
562
563		objectLength: function( obj ) {
564			/* jshint unused: false */
565			var count = 0,
566				i;
567			for ( i in obj ) {
568				if ( obj[ i ] ) {
569					count++;
570				}
571			}
572			return count;
573		},
574
575		hideErrors: function() {
576			this.hideThese( this.toHide );
577		},
578
579		hideThese: function( errors ) {
580			errors.not( this.containers ).text( "" );
581			this.addWrapper( errors ).hide();
582		},
583
584		valid: function() {
585			return this.size() === 0;
586		},
587
588		size: function() {
589			return this.errorList.length;
590		},
591
592		focusInvalid: function() {
593			if ( this.settings.focusInvalid ) {
594				try {
595					$( this.findLastActive() || this.errorList.length && this.errorList[ 0 ].element || [] )
596					.filter( ":visible" )
597					.focus()
598
599					// Manually trigger focusin event; without it, focusin handler isn't called, findLastActive won't have anything to find
600					.trigger( "focusin" );
601				} catch ( e ) {
602
603					// Ignore IE throwing errors when focusing hidden elements
604				}
605			}
606		},
607
608		findLastActive: function() {
609			var lastActive = this.lastActive;
610			return lastActive && $.grep( this.errorList, function( n ) {
611				return n.element.name === lastActive.name;
612			} ).length === 1 && lastActive;
613		},
614
615		elements: function() {
616			var validator = this,
617				rulesCache = {};
618
619			// Select all valid inputs inside the form (no submit or reset buttons)
620			return $( this.currentForm )
621			.find( "input, select, textarea, [contenteditable]" )
622			.not( ":submit, :reset, :image, :disabled" )
623			.not( this.settings.ignore )
624			.filter( function() {
625				var name = this.name || $( this ).attr( "name" ); // For contenteditable
626				if ( !name && validator.settings.debug && window.console ) {
627					console.error( "%o has no name assigned", this );
628				}
629
630				// Set form expando on contenteditable
631				if ( this.hasAttribute( "contenteditable" ) ) {
632					this.form = $( this ).closest( "form" )[ 0 ];
633				}
634
635				// Select only the first element for each name, and only those with rules specified
636				if ( name in rulesCache || !validator.objectLength( $( this ).rules() ) ) {
637					return false;
638				}
639
640				rulesCache[ name ] = true;
641				return true;
642			} );
643		},
644
645		clean: function( selector ) {
646			return $( selector )[ 0 ];
647		},
648
649		errors: function() {
650			var errorClass = this.settings.errorClass.split( " " ).join( "." );
651			return $( this.settings.errorElement + "." + errorClass, this.errorContext );
652		},
653
654		resetInternals: function() {
655			this.successList = [];
656			this.errorList = [];
657			this.errorMap = {};
658			this.toShow = $( [] );
659			this.toHide = $( [] );
660		},
661
662		reset: function() {
663			this.resetInternals();
664			this.currentElements = $( [] );
665		},
666
667		prepareForm: function() {
668			this.reset();
669			this.toHide = this.errors().add( this.containers );
670		},
671
672		prepareElement: function( element ) {
673			this.reset();
674			this.toHide = this.errorsFor( element );
675		},
676
677		elementValue: function( element ) {
678			var $element = $( element ),
679				type = element.type,
680				val, idx;
681
682			if ( type === "radio" || type === "checkbox" ) {
683				return this.findByName( element.name ).filter( ":checked" ).val();
684			} else if ( type === "number" && typeof element.validity !== "undefined" ) {
685				return element.validity.badInput ? "NaN" : $element.val();
686			}
687
688			if ( element.hasAttribute( "contenteditable" ) ) {
689				val = $element.text();
690			} else {
691				val = $element.val();
692			}
693
694			if ( type === "file" ) {
695
696				// Modern browser (chrome & safari)
697				if ( val.substr( 0, 12 ) === "C:\\fakepath\\" ) {
698					return val.substr( 12 );
699				}
700
701				// Legacy browsers
702				// Unix-based path
703				idx = val.lastIndexOf( "/" );
704				if ( idx >= 0 ) {
705					return val.substr( idx + 1 );
706				}
707
708				// Windows-based path
709				idx = val.lastIndexOf( "\\" );
710				if ( idx >= 0 ) {
711					return val.substr( idx + 1 );
712				}
713
714				// Just the file name
715				return val;
716			}
717
718			if ( typeof val === "string" ) {
719				return val.replace( /\r/g, "" );
720			}
721			return val;
722		},
723
724		check: function( element ) {
725			element = this.validationTargetFor( this.clean( element ) );
726
727			var rules = $( element ).rules(),
728				rulesCount = $.map( rules, function( n, i ) {
729					return i;
730				} ).length,
731				dependencyMismatch = false,
732				val = this.elementValue( element ),
733				result, method, rule;
734
735			// If a normalizer is defined for this element, then
736			// call it to retreive the changed value instead
737			// of using the real one.
738			// Note that `this` in the normalizer is `element`.
739			if ( typeof rules.normalizer === "function" ) {
740				val = rules.normalizer.call( element, val );
741
742				if ( typeof val !== "string" ) {
743					throw new TypeError( "The normalizer should return a string value." );
744				}
745
746				// Delete the normalizer from rules to avoid treating
747				// it as a pre-defined method.
748				delete rules.normalizer;
749			}
750
751			for ( method in rules ) {
752				rule = { method: method, parameters: rules[ method ] };
753				try {
754					result = $.validator.methods[ method ].call( this, val, element, rule.parameters );
755
756					// If a method indicates that the field is optional and therefore valid,
757					// don't mark it as valid when there are no other rules
758					if ( result === "dependency-mismatch" && rulesCount === 1 ) {
759						dependencyMismatch = true;
760						continue;
761					}
762					dependencyMismatch = false;
763
764					if ( result === "pending" ) {
765						this.toHide = this.toHide.not( this.errorsFor( element ) );
766						return;
767					}
768
769					if ( !result ) {
770						this.formatAndAdd( element, rule );
771						return false;
772					}
773				} catch ( e ) {
774					if ( this.settings.debug && window.console ) {
775						console.log( "Exception occurred when checking element " + element.id + ", check the '" + rule.method + "' method.", e );
776					}
777					if ( e instanceof TypeError ) {
778						e.message += ".  Exception occurred when checking element " + element.id + ", check the '" + rule.method + "' method.";
779					}
780
781					throw e;
782				}
783			}
784			if ( dependencyMismatch ) {
785				return;
786			}
787			if ( this.objectLength( rules ) ) {
788				this.successList.push( element );
789			}
790			return true;
791		},
792
793		// Return the custom message for the given element and validation method
794		// specified in the element's HTML5 data attribute
795		// return the generic message if present and no method specific message is present
796		customDataMessage: function( element, method ) {
797			return $( element ).data( "msg" + method.charAt( 0 ).toUpperCase() +
798				method.substring( 1 ).toLowerCase() ) || $( element ).data( "msg" );
799		},
800
801		// Return the custom message for the given element name and validation method
802		customMessage: function( name, method ) {
803			var m = this.settings.messages[ name ];
804			return m && ( m.constructor === String ? m : m[ method ] );
805		},
806
807		// Return the first defined argument, allowing empty strings
808		findDefined: function() {
809			for ( var i = 0; i < arguments.length; i++ ) {
810				if ( arguments[ i ] !== undefined ) {
811					return arguments[ i ];
812				}
813			}
814			return undefined;
815		},
816
817		defaultMessage: function( element, rule ) {
818			var message = this.findDefined(
819					this.customMessage( element.name, rule.method ),
820					this.customDataMessage( element, rule.method ),
821
822					// 'title' is never undefined, so handle empty string as undefined
823					!this.settings.ignoreTitle && element.title || undefined,
824					$.validator.messages[ rule.method ],
825					"<strong>Warning: No message defined for " + element.name + "</strong>"
826				),
827				theregex = /\$?\{(\d+)\}/g;
828			if ( typeof message === "function" ) {
829				message = message.call( this, rule.parameters, element );
830			} else if ( theregex.test( message ) ) {
831				message = $.validator.format( message.replace( theregex, "{$1}" ), rule.parameters );
832			}
833
834			return message;
835		},
836
837		formatAndAdd: function( element, rule ) {
838			var message = this.defaultMessage( element, rule );
839
840			this.errorList.push( {
841				message: message,
842				element: element,
843				method: rule.method
844			} );
845
846			this.errorMap[ element.name ] = message;
847			this.submitted[ element.name ] = message;
848		},
849
850		addWrapper: function( toToggle ) {
851			if ( this.settings.wrapper ) {
852				toToggle = toToggle.add( toToggle.parent( this.settings.wrapper ) );
853			}
854			return toToggle;
855		},
856
857		defaultShowErrors: function() {
858			var i, elements, error;
859			for ( i = 0; this.errorList[ i ]; i++ ) {
860				error = this.errorList[ i ];
861				if ( this.settings.highlight ) {
862					this.settings.highlight.call( this, error.element, this.settings.errorClass, this.settings.validClass );
863				}
864				this.showLabel( error.element, error.message );
865			}
866			if ( this.errorList.length ) {
867				this.toShow = this.toShow.add( this.containers );
868			}
869			if ( this.settings.success ) {
870				for ( i = 0; this.successList[ i ]; i++ ) {
871					this.showLabel( this.successList[ i ] );
872				}
873			}
874			if ( this.settings.unhighlight ) {
875				for ( i = 0, elements = this.validElements(); elements[ i ]; i++ ) {
876					this.settings.unhighlight.call( this, elements[ i ], this.settings.errorClass, this.settings.validClass );
877				}
878			}
879			this.toHide = this.toHide.not( this.toShow );
880			this.hideErrors();
881			this.addWrapper( this.toShow ).show();
882		},
883
884		validElements: function() {
885			return this.currentElements.not( this.invalidElements() );
886		},
887
888		invalidElements: function() {
889			return $( this.errorList ).map( function() {
890				return this.element;
891			} );
892		},
893
894		showLabel: function( element, message ) {
895			var place, group, errorID, v,
896				error = this.errorsFor( element ),
897				elementID = this.idOrName( element ),
898				describedBy = $( element ).attr( "aria-describedby" );
899
900			if ( error.length ) {
901
902				// Refresh error/success class
903				error.removeClass( this.settings.validClass ).addClass( this.settings.errorClass );
904
905				// Replace message on existing label
906				error.html( message );
907			} else {
908
909				// Create error element
910				error = $( "<" + this.settings.errorElement + ">" )
911					.attr( "id", elementID + "-error" )
912					.addClass( this.settings.errorClass )
913					.html( message || "" );
914
915				// Maintain reference to the element to be placed into the DOM
916				place = error;
917				if ( this.settings.wrapper ) {
918
919					// Make sure the element is visible, even in IE
920					// actually showing the wrapped element is handled elsewhere
921					place = error.hide().show().wrap( "<" + this.settings.wrapper + "/>" ).parent();
922				}
923				if ( this.labelContainer.length ) {
924					this.labelContainer.append( place );
925				} else if ( this.settings.errorPlacement ) {
926					this.settings.errorPlacement( place, $( element ) );
927				} else {
928					place.insertAfter( element );
929				}
930
931				// Link error back to the element
932				if ( error.is( "label" ) ) {
933
934					// If the error is a label, then associate using 'for'
935					error.attr( "for", elementID );
936
937					// If the element is not a child of an associated label, then it's necessary
938					// to explicitly apply aria-describedby
939				} else if ( error.parents( "label[for='" + this.escapeCssMeta( elementID ) + "']" ).length === 0 ) {
940					errorID = error.attr( "id" );
941
942					// Respect existing non-error aria-describedby
943					if ( !describedBy ) {
944						describedBy = errorID;
945					} else if ( !describedBy.match( new RegExp( "\\b" + this.escapeCssMeta( errorID ) + "\\b" ) ) ) {
946
947						// Add to end of list if not already present
948						describedBy += " " + errorID;
949					}
950					$( element ).attr( "aria-describedby", describedBy );
951
952					// If this element is grouped, then assign to all elements in the same group
953					group = this.groups[ element.name ];
954					if ( group ) {
955						v = this;
956						$.each( v.groups, function( name, testgroup ) {
957							if ( testgroup === group ) {
958								$( "[name='" + v.escapeCssMeta( name ) + "']", v.currentForm )
959									.attr( "aria-describedby", error.attr( "id" ) );
960							}
961						} );
962					}
963				}
964			}
965			if ( !message && this.settings.success ) {
966				error.text( "" );
967				if ( typeof this.settings.success === "string" ) {
968					error.addClass( this.settings.success );
969				} else {
970					this.settings.success( error, element );
971				}
972			}
973			this.toShow = this.toShow.add( error );
974		},
975
976		errorsFor: function( element ) {
977			var name = this.escapeCssMeta( this.idOrName( element ) ),
978				describer = $( element ).attr( "aria-describedby" ),
979				selector = "label[for='" + name + "'], label[for='" + name + "'] *";
980
981			// 'aria-describedby' should directly reference the error element
982			if ( describer ) {
983				selector = selector + ", #" + this.escapeCssMeta( describer )
984					.replace( /\s+/g, ", #" );
985			}
986
987			return this
988				.errors()
989				.filter( selector );
990		},
991
992		// See https://api.jquery.com/category/selectors/, for CSS
993		// meta-characters that should be escaped in order to be used with JQuery
994		// as a literal part of a name/id or any selector.
995		escapeCssMeta: function( string ) {
996			return string.replace( /([\\!"#$%&'()*+,./:;<=>?@\[\]^`{|}~])/g, "\\$1" );
997		},
998
999		idOrName: function( element ) {
1000			return this.groups[ element.name ] || ( this.checkable( element ) ? element.name : element.id || element.name );
1001		},
1002
1003		validationTargetFor: function( element ) {
1004
1005			// If radio/checkbox, validate first element in group instead
1006			if ( this.checkable( element ) ) {
1007				element = this.findByName( element.name );
1008			}
1009
1010			// Always apply ignore filter
1011			return $( element ).not( this.settings.ignore )[ 0 ];
1012		},
1013
1014		checkable: function( element ) {
1015			return ( /radio|checkbox/i ).test( element.type );
1016		},
1017
1018		findByName: function( name ) {
1019			return $( this.currentForm ).find( "[name='" + this.escapeCssMeta( name ) + "']" );
1020		},
1021
1022		getLength: function( value, element ) {
1023			switch ( element.nodeName.toLowerCase() ) {
1024			case "select":
1025				return $( "option:selected", element ).length;
1026			case "input":
1027				if ( this.checkable( element ) ) {
1028					return this.findByName( element.name ).filter( ":checked" ).length;
1029				}
1030			}
1031			return value.length;
1032		},
1033
1034		depend: function( param, element ) {
1035			return this.dependTypes[ typeof param ] ? this.dependTypes[ typeof param ]( param, element ) : true;
1036		},
1037
1038		dependTypes: {
1039			"boolean": function( param ) {
1040				return param;
1041			},
1042			"string": function( param, element ) {
1043				return !!$( param, element.form ).length;
1044			},
1045			"function": function( param, element ) {
1046				return param( element );
1047			}
1048		},
1049
1050		optional: function( element ) {
1051			var val = this.elementValue( element );
1052			return !$.validator.methods.required.call( this, val, element ) && "dependency-mismatch";
1053		},
1054
1055		startRequest: function( element ) {
1056			if ( !this.pending[ element.name ] ) {
1057				this.pendingRequest++;
1058				$( element ).addClass( this.settings.pendingClass );
1059				this.pending[ element.name ] = true;
1060			}
1061		},
1062
1063		stopRequest: function( element, valid ) {
1064			this.pendingRequest--;
1065
1066			// Sometimes synchronization fails, make sure pendingRequest is never < 0
1067			if ( this.pendingRequest < 0 ) {
1068				this.pendingRequest = 0;
1069			}
1070			delete this.pending[ element.name ];
1071			$( element ).removeClass( this.settings.pendingClass );
1072			if ( valid && this.pendingRequest === 0 && this.formSubmitted && this.form() ) {
1073				$( this.currentForm ).submit();
1074				this.formSubmitted = false;
1075			} else if ( !valid && this.pendingRequest === 0 && this.formSubmitted ) {
1076				$( this.currentForm ).triggerHandler( "invalid-form", [ this ] );
1077				this.formSubmitted = false;
1078			}
1079		},
1080
1081		previousValue: function( element, method ) {
1082			return $.data( element, "previousValue" ) || $.data( element, "previousValue", {
1083				old: null,
1084				valid: true,
1085				message: this.defaultMessage( element, { method: method } )
1086			} );
1087		},
1088
1089		// Cleans up all forms and elements, removes validator-specific events
1090		destroy: function() {
1091			this.resetForm();
1092
1093			$( this.currentForm )
1094				.off( ".validate" )
1095				.removeData( "validator" )
1096				.find( ".validate-equalTo-blur" )
1097					.off( ".validate-equalTo" )
1098					.removeClass( "validate-equalTo-blur" );
1099		}
1100
1101	},
1102
1103	classRuleSettings: {
1104		required: { required: true },
1105		email: { email: true },
1106		url: { url: true },
1107		date: { date: true },
1108		dateISO: { dateISO: true },
1109		number: { number: true },
1110		digits: { digits: true },
1111		creditcard: { creditcard: true }
1112	},
1113
1114	addClassRules: function( className, rules ) {
1115		if ( className.constructor === String ) {
1116			this.classRuleSettings[ className ] = rules;
1117		} else {
1118			$.extend( this.classRuleSettings, className );
1119		}
1120	},
1121
1122	classRules: function( element ) {
1123		var rules = {},
1124			classes = $( element ).attr( "class" );
1125
1126		if ( classes ) {
1127			$.each( classes.split( " " ), function() {
1128				if ( this in $.validator.classRuleSettings ) {
1129					$.extend( rules, $.validator.classRuleSettings[ this ] );
1130				}
1131			} );
1132		}
1133		return rules;
1134	},
1135
1136	normalizeAttributeRule: function( rules, type, method, value ) {
1137
1138		// Convert the value to a number for number inputs, and for text for backwards compability
1139		// allows type="date" and others to be compared as strings
1140		if ( /min|max|step/.test( method ) && ( type === null || /number|range|text/.test( type ) ) ) {
1141			value = Number( value );
1142
1143			// Support Opera Mini, which returns NaN for undefined minlength
1144			if ( isNaN( value ) ) {
1145				value = undefined;
1146			}
1147		}
1148
1149		if ( value || value === 0 ) {
1150			rules[ method ] = value;
1151		} else if ( type === method && type !== "range" ) {
1152
1153			// Exception: the jquery validate 'range' method
1154			// does not test for the html5 'range' type
1155			rules[ method ] = true;
1156		}
1157	},
1158
1159	attributeRules: function( element ) {
1160		var rules = {},
1161			$element = $( element ),
1162			type = element.getAttribute( "type" ),
1163			method, value;
1164
1165		for ( method in $.validator.methods ) {
1166
1167			// Support for <input required> in both html5 and older browsers
1168			if ( method === "required" ) {
1169				value = element.getAttribute( method );
1170
1171				// Some browsers return an empty string for the required attribute
1172				// and non-HTML5 browsers might have required="" markup
1173				if ( value === "" ) {
1174					value = true;
1175				}
1176
1177				// Force non-HTML5 browsers to return bool
1178				value = !!value;
1179			} else {
1180				value = $element.attr( method );
1181			}
1182
1183			this.normalizeAttributeRule( rules, type, method, value );
1184		}
1185
1186		// 'maxlength' may be returned as -1, 2147483647 ( IE ) and 524288 ( safari ) for text inputs
1187		if ( rules.maxlength && /-1|2147483647|524288/.test( rules.maxlength ) ) {
1188			delete rules.maxlength;
1189		}
1190
1191		return rules;
1192	},
1193
1194	dataRules: function( element ) {
1195		var rules = {},
1196			$element = $( element ),
1197			type = element.getAttribute( "type" ),
1198			method, value;
1199
1200		for ( method in $.validator.methods ) {
1201			value = $element.data( "rule" + method.charAt( 0 ).toUpperCase() + method.substring( 1 ).toLowerCase() );
1202			this.normalizeAttributeRule( rules, type, method, value );
1203		}
1204		return rules;
1205	},
1206
1207	staticRules: function( element ) {
1208		var rules = {},
1209			validator = $.data( element.form, "validator" );
1210
1211		if ( validator.settings.rules ) {
1212			rules = $.validator.normalizeRule( validator.settings.rules[ element.name ] ) || {};
1213		}
1214		return rules;
1215	},
1216
1217	normalizeRules: function( rules, element ) {
1218
1219		// Handle dependency check
1220		$.each( rules, function( prop, val ) {
1221
1222			// Ignore rule when param is explicitly false, eg. required:false
1223			if ( val === false ) {
1224				delete rules[ prop ];
1225				return;
1226			}
1227			if ( val.param || val.depends ) {
1228				var keepRule = true;
1229				switch ( typeof val.depends ) {
1230				case "string":
1231					keepRule = !!$( val.depends, element.form ).length;
1232					break;
1233				case "function":
1234					keepRule = val.depends.call( element, element );
1235					break;
1236				}
1237				if ( keepRule ) {
1238					rules[ prop ] = val.param !== undefined ? val.param : true;
1239				} else {
1240					$.data( element.form, "validator" ).resetElements( $( element ) );
1241					delete rules[ prop ];
1242				}
1243			}
1244		} );
1245
1246		// Evaluate parameters
1247		$.each( rules, function( rule, parameter ) {
1248			rules[ rule ] = $.isFunction( parameter ) && rule !== "normalizer" ? parameter( element ) : parameter;
1249		} );
1250
1251		// Clean number parameters
1252		$.each( [ "minlength", "maxlength" ], function() {
1253			if ( rules[ this ] ) {
1254				rules[ this ] = Number( rules[ this ] );
1255			}
1256		} );
1257		$.each( [ "rangelength", "range" ], function() {
1258			var parts;
1259			if ( rules[ this ] ) {
1260				if ( $.isArray( rules[ this ] ) ) {
1261					rules[ this ] = [ Number( rules[ this ][ 0 ] ), Number( rules[ this ][ 1 ] ) ];
1262				} else if ( typeof rules[ this ] === "string" ) {
1263					parts = rules[ this ].replace( /[\[\]]/g, "" ).split( /[\s,]+/ );
1264					rules[ this ] = [ Number( parts[ 0 ] ), Number( parts[ 1 ] ) ];
1265				}
1266			}
1267		} );
1268
1269		if ( $.validator.autoCreateRanges ) {
1270
1271			// Auto-create ranges
1272			if ( rules.min != null && rules.max != null ) {
1273				rules.range = [ rules.min, rules.max ];
1274				delete rules.min;
1275				delete rules.max;
1276			}
1277			if ( rules.minlength != null && rules.maxlength != null ) {
1278				rules.rangelength = [ rules.minlength, rules.maxlength ];
1279				delete rules.minlength;
1280				delete rules.maxlength;
1281			}
1282		}
1283
1284		return rules;
1285	},
1286
1287	// Converts a simple string to a {string: true} rule, e.g., "required" to {required:true}
1288	normalizeRule: function( data ) {
1289		if ( typeof data === "string" ) {
1290			var transformed = {};
1291			$.each( data.split( /\s/ ), function() {
1292				transformed[ this ] = true;
1293			} );
1294			data = transformed;
1295		}
1296		return data;
1297	},
1298
1299	// http://jqueryvalidation.org/jQuery.validator.addMethod/
1300	addMethod: function( name, method, message ) {
1301		$.validator.methods[ name ] = method;
1302		$.validator.messages[ name ] = message !== undefined ? message : $.validator.messages[ name ];
1303		if ( method.length < 3 ) {
1304			$.validator.addClassRules( name, $.validator.normalizeRule( name ) );
1305		}
1306	},
1307
1308	// http://jqueryvalidation.org/jQuery.validator.methods/
1309	methods: {
1310
1311		// http://jqueryvalidation.org/required-method/
1312		required: function( value, element, param ) {
1313
1314			// Check if dependency is met
1315			if ( !this.depend( param, element ) ) {
1316				return "dependency-mismatch";
1317			}
1318			if ( element.nodeName.toLowerCase() === "select" ) {
1319
1320				// Could be an array for select-multiple or a string, both are fine this way
1321				var val = $( element ).val();
1322				return val && val.length > 0;
1323			}
1324			if ( this.checkable( element ) ) {
1325				return this.getLength( value, element ) > 0;
1326			}
1327			return value.length > 0;
1328		},
1329
1330		// http://jqueryvalidation.org/email-method/
1331		email: function( value, element ) {
1332
1333			// From https://html.spec.whatwg.org/multipage/forms.html#valid-e-mail-address
1334			// Retrieved 2014-01-14
1335			// If you have a problem with this implementation, report a bug against the above spec
1336			// Or use custom methods to implement your own email validation
1337			return this.optional( element ) || /^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/.test( value );
1338		},
1339
1340		// http://jqueryvalidation.org/url-method/
1341		url: function( value, element ) {
1342
1343			// Copyright (c) 2010-2013 Diego Perini, MIT licensed
1344			// https://gist.github.com/dperini/729294
1345			// see also https://mathiasbynens.be/demo/url-regex
1346			// modified to allow protocol-relative URLs
1347			return this.optional( element ) || /^(?:(?:(?:https?|ftp):)?\/\/)(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})).?)(?::\d{2,5})?(?:[/?#]\S*)?$/i.test( value );
1348		},
1349
1350		// http://jqueryvalidation.org/date-method/
1351		date: function( value, element ) {
1352			return this.optional( element ) || !/Invalid|NaN/.test( new Date( value ).toString() );
1353		},
1354
1355		// http://jqueryvalidation.org/dateISO-method/
1356		dateISO: function( value, element ) {
1357			return this.optional( element ) || /^\d{4}[\/\-](0?[1-9]|1[012])[\/\-](0?[1-9]|[12][0-9]|3[01])$/.test( value );
1358		},
1359
1360		// http://jqueryvalidation.org/number-method/
1361		number: function( value, element ) {
1362			return this.optional( element ) || /^(?:-?\d+|-?\d{1,3}(?:,\d{3})+)?(?:\.\d+)?$/.test( value );
1363		},
1364
1365		// http://jqueryvalidation.org/digits-method/
1366		digits: function( value, element ) {
1367			return this.optional( element ) || /^\d+$/.test( value );
1368		},
1369
1370		// http://jqueryvalidation.org/minlength-method/
1371		minlength: function( value, element, param ) {
1372			var length = $.isArray( value ) ? value.length : this.getLength( value, element );
1373			return this.optional( element ) || length >= param;
1374		},
1375
1376		// http://jqueryvalidation.org/maxlength-method/
1377		maxlength: function( value, element, param ) {
1378			var length = $.isArray( value ) ? value.length : this.getLength( value, element );
1379			return this.optional( element ) || length <= param;
1380		},
1381
1382		// http://jqueryvalidation.org/rangelength-method/
1383		rangelength: function( value, element, param ) {
1384			var length = $.isArray( value ) ? value.length : this.getLength( value, element );
1385			return this.optional( element ) || ( length >= param[ 0 ] && length <= param[ 1 ] );
1386		},
1387
1388		// http://jqueryvalidation.org/min-method/
1389		min: function( value, element, param ) {
1390			return this.optional( element ) || value >= param;
1391		},
1392
1393		// http://jqueryvalidation.org/max-method/
1394		max: function( value, element, param ) {
1395			return this.optional( element ) || value <= param;
1396		},
1397
1398		// http://jqueryvalidation.org/range-method/
1399		range: function( value, element, param ) {
1400			return this.optional( element ) || ( value >= param[ 0 ] && value <= param[ 1 ] );
1401		},
1402
1403		// http://jqueryvalidation.org/step-method/
1404		step: function( value, element, param ) {
1405			var type = $( element ).attr( "type" ),
1406				errorMessage = "Step attribute on input type " + type + " is not supported.",
1407				supportedTypes = [ "text", "number", "range" ],
1408				re = new RegExp( "\\b" + type + "\\b" ),
1409				notSupported = type && !re.test( supportedTypes.join() );
1410
1411			// Works only for text, number and range input types
1412			// TODO find a way to support input types date, datetime, datetime-local, month, time and week
1413			if ( notSupported ) {
1414				throw new Error( errorMessage );
1415			}
1416			return this.optional( element ) || ( value % param === 0 );
1417		},
1418
1419		// http://jqueryvalidation.org/equalTo-method/
1420		equalTo: function( value, element, param ) {
1421
1422			// Bind to the blur event of the target in order to revalidate whenever the target field is updated
1423			var target = $( param );
1424			if ( this.settings.onfocusout && target.not( ".validate-equalTo-blur" ).length ) {
1425				target.addClass( "validate-equalTo-blur" ).on( "blur.validate-equalTo", function() {
1426					$( element ).valid();
1427				} );
1428			}
1429			return value === target.val();
1430		},
1431
1432		// http://jqueryvalidation.org/remote-method/
1433		remote: function( value, element, param, method ) {
1434			if ( this.optional( element ) ) {
1435				return "dependency-mismatch";
1436			}
1437
1438			method = typeof method === "string" && method || "remote";
1439
1440			var previous = this.previousValue( element, method ),
1441				validator, data, optionDataString;
1442
1443			if ( !this.settings.messages[ element.name ] ) {
1444				this.settings.messages[ element.name ] = {};
1445			}
1446			previous.originalMessage = previous.originalMessage || this.settings.messages[ element.name ][ method ];
1447			this.settings.messages[ element.name ][ method ] = previous.message;
1448
1449			param = typeof param === "string" && { url: param } || param;
1450			optionDataString = $.param( $.extend( { data: value }, param.data ) );
1451			if ( previous.old === optionDataString ) {
1452				return previous.valid;
1453			}
1454
1455			previous.old = optionDataString;
1456			validator = this;
1457			this.startRequest( element );
1458			data = {};
1459			data[ element.name ] = value;
1460			$.ajax( $.extend( true, {
1461				mode: "abort",
1462				port: "validate" + element.name,
1463				dataType: "json",
1464				data: data,
1465				context: validator.currentForm,
1466				success: function( response ) {
1467					var valid = response === true || response === "true",
1468						errors, message, submitted;
1469
1470					validator.settings.messages[ element.name ][ method ] = previous.originalMessage;
1471					if ( valid ) {
1472						submitted = validator.formSubmitted;
1473						validator.resetInternals();
1474						validator.toHide = validator.errorsFor( element );
1475						validator.formSubmitted = submitted;
1476						validator.successList.push( element );
1477						validator.invalid[ element.name ] = false;
1478						validator.showErrors();
1479					} else {
1480						errors = {};
1481						message = response || validator.defaultMessage( element, { method: method, parameters: value } );
1482						errors[ element.name ] = previous.message = message;
1483						validator.invalid[ element.name ] = true;
1484						validator.showErrors( errors );
1485					}
1486					previous.valid = valid;
1487					validator.stopRequest( element, valid );
1488				}
1489			}, param ) );
1490			return "pending";
1491		}
1492	}
1493
1494} );
1495
1496// Ajax mode: abort
1497// usage: $.ajax({ mode: "abort"[, port: "uniqueport"]});
1498// if mode:"abort" is used, the previous request on that port (port can be undefined) is aborted via XMLHttpRequest.abort()
1499
1500var pendingRequests = {},
1501	ajax;
1502
1503// Use a prefilter if available (1.5+)
1504if ( $.ajaxPrefilter ) {
1505	$.ajaxPrefilter( function( settings, _, xhr ) {
1506		var port = settings.port;
1507		if ( settings.mode === "abort" ) {
1508			if ( pendingRequests[ port ] ) {
1509				pendingRequests[ port ].abort();
1510			}
1511			pendingRequests[ port ] = xhr;
1512		}
1513	} );
1514} else {
1515
1516	// Proxy ajax
1517	ajax = $.ajax;
1518	$.ajax = function( settings ) {
1519		var mode = ( "mode" in settings ? settings : $.ajaxSettings ).mode,
1520			port = ( "port" in settings ? settings : $.ajaxSettings ).port;
1521		if ( mode === "abort" ) {
1522			if ( pendingRequests[ port ] ) {
1523				pendingRequests[ port ].abort();
1524			}
1525			pendingRequests[ port ] = ajax.apply( this, arguments );
1526			return pendingRequests[ port ];
1527		}
1528		return ajax.apply( this, arguments );
1529	};
1530}
1531
1532}));
1533
1534
1535
1536
1537
1538
1539/*!
1540 * jQuery Form Plugin
1541 * version: 3.20 (20-NOV-2012)
1542 * @requires jQuery v1.5 or later
1543 *
1544 * Examples and documentation at: http://malsup.com/jquery/form/
1545 * Project repository: https://github.com/malsup/form
1546 * Dual licensed under the MIT and GPL licenses:
1547 *    http://malsup.github.com/mit-license.txt
1548 *    http://malsup.github.com/gpl-license-v2.txt
1549 */
1550/*global ActiveXObject alert */
1551;(function($) {
1552"use strict";
1553
1554/*
1555    Usage Note:
1556    -----------
1557    Do not use both ajaxSubmit and ajaxForm on the same form.  These
1558    functions are mutually exclusive.  Use ajaxSubmit if you want
1559    to bind your own submit handler to the form.  For example,
1560
1561    $(document).ready(function() {
1562        $('#myForm').on('submit', function(e) {
1563            e.preventDefault(); // <-- important
1564            $(this).ajaxSubmit({
1565                target: '#output'
1566            });
1567        });
1568    });
1569
1570    Use ajaxForm when you want the plugin to manage all the event binding
1571    for you.  For example,
1572
1573    $(document).ready(function() {
1574        $('#myForm').ajaxForm({
1575            target: '#output'
1576        });
1577    });
1578
1579    You can also use ajaxForm with delegation (requires jQuery v1.7+), so the
1580    form does not have to exist when you invoke ajaxForm:
1581
1582    $('#myForm').ajaxForm({
1583        delegation: true,
1584        target: '#output'
1585    });
1586
1587    When using ajaxForm, the ajaxSubmit function will be invoked for you
1588    at the appropriate time.
1589*/
1590
1591/**
1592 * Feature detection
1593 */
1594var feature = {};
1595feature.fileapi = $("<input type='file'/>").get(0).files !== undefined;
1596feature.formdata = window.FormData !== undefined;
1597
1598/**
1599 * ajaxSubmit() provides a mechanism for immediately submitting
1600 * an HTML form using AJAX.
1601 */
1602$.fn.ajaxSubmit = function(options) {
1603    /*jshint scripturl:true */
1604
1605    // fast fail if nothing selected (http://dev.jquery.com/ticket/2752)
1606    if (!this.length) {
1607        log('ajaxSubmit: skipping submit process - no element selected');
1608        return this;
1609    }
1610
1611    var method, action, url, $form = this;
1612
1613    if (typeof options == 'function') {
1614        options = { success: options };
1615    }
1616
1617    method = this.attr('method');
1618    action = this.attr('action');
1619    url = (typeof action === 'string') ? $.trim(action) : '';
1620    url = url || window.location.href || '';
1621    if (url) {
1622        // clean url (don't include hash vaue)
1623        url = (url.match(/^([^#]+)/)||[])[1];
1624    }
1625
1626    options = $.extend(true, {
1627        url:  url,
1628        success: $.ajaxSettings.success,
1629        type: method || 'GET',
1630        iframeSrc: /^https/i.test(window.location.href || '') ? 'javascript:false' : 'about:blank'
1631    }, options);
1632
1633    // hook for manipulating the form data before it is extracted;
1634    // convenient for use with rich editors like tinyMCE or FCKEditor
1635    var veto = {};
1636    this.trigger('form-pre-serialize', [this, options, veto]);
1637    if (veto.veto) {
1638        log('ajaxSubmit: submit vetoed via form-pre-serialize trigger');
1639        return this;
1640    }
1641
1642    // provide opportunity to alter form data before it is serialized
1643    if (options.beforeSerialize && options.beforeSerialize(this, options) === false) {
1644        log('ajaxSubmit: submit aborted via beforeSerialize callback');
1645        return this;
1646    }
1647
1648    var traditional = options.traditional;
1649    if ( traditional === undefined ) {
1650        traditional = $.ajaxSettings.traditional;
1651    }
1652
1653    var elements = [];
1654    var qx, a = this.formToArray(options.semantic, elements);
1655    if (options.data) {
1656        options.extraData = options.data;
1657        qx = $.param(options.data, traditional);
1658    }
1659
1660    // give pre-submit callback an opportunity to abort the submit
1661    if (options.beforeSubmit && options.beforeSubmit(a, this, options) === false) {
1662        log('ajaxSubmit: submit aborted via beforeSubmit callback');
1663        return this;
1664    }
1665
1666    // fire vetoable 'validate' event
1667    this.trigger('form-submit-validate', [a, this, options, veto]);
1668    if (veto.veto) {
1669        log('ajaxSubmit: submit vetoed via form-submit-validate trigger');
1670        return this;
1671    }
1672
1673    var q = $.param(a, traditional);
1674    if (qx) {
1675        q = ( q ? (q + '&' + qx) : qx );
1676    }
1677    if (options.type.toUpperCase() == 'GET') {
1678        options.url += (options.url.indexOf('?') >= 0 ? '&' : '?') + q;
1679        options.data = null;  // data is null for 'get'
1680    }
1681    else {
1682        options.data = q; // data is the query string for 'post'
1683    }
1684
1685    var callbacks = [];
1686    if (options.resetForm) {
1687        callbacks.push(function() { $form.resetForm(); });
1688    }
1689    if (options.clearForm) {
1690        callbacks.push(function() { $form.clearForm(options.includeHidden); });
1691    }
1692
1693    // perform a load on the target only if dataType is not provided
1694    if (!options.dataType && options.target) {
1695        var oldSuccess = options.success || function(){};
1696        callbacks.push(function(data) {
1697            var fn = options.replaceTarget ? 'replaceWith' : 'html';
1698            $(options.target)[fn](data).each(oldSuccess, arguments);
1699        });
1700    }
1701    else if (options.success) {
1702        callbacks.push(options.success);
1703    }
1704
1705    options.success = function(data, status, xhr) { // jQuery 1.4+ passes xhr as 3rd arg
1706        var context = options.context || this ;    // jQuery 1.4+ supports scope context
1707        for (var i=0, max=callbacks.length; i < max; i++) {
1708            callbacks[i].apply(context, [data, status, xhr || $form, $form]);
1709        }
1710    };
1711
1712    // are there files to upload?
1713
1714    // [value] (issue #113), also see comment:
1715    // https://github.com/malsup/form/commit/588306aedba1de01388032d5f42a60159eea9228#commitcomment-2180219
1716    var fileInputs = $('input[type=file]:enabled[value!=""]', this);
1717
1718    var hasFileInputs = fileInputs.length > 0;
1719    var mp = 'multipart/form-data';
1720    var multipart = ($form.attr('enctype') == mp || $form.attr('encoding') == mp);
1721
1722    var fileAPI = feature.fileapi && feature.formdata;
1723    log("fileAPI :" + fileAPI);
1724    var shouldUseFrame = (hasFileInputs || multipart) && !fileAPI;
1725
1726    var jqxhr;
1727
1728    // options.iframe allows user to force iframe mode
1729    // 06-NOV-09: now defaulting to iframe mode if file input is detected
1730    if (options.iframe !== false && (options.iframe || shouldUseFrame)) {
1731        // hack to fix Safari hang (thanks to Tim Molendijk for this)
1732        // see:  http://groups.google.com/group/jquery-dev/browse_thread/thread/36395b7ab510dd5d
1733        if (options.closeKeepAlive) {
1734            $.get(options.closeKeepAlive, function() {
1735                jqxhr = fileUploadIframe(a);
1736            });
1737        }
1738        else {
1739            jqxhr = fileUploadIframe(a);
1740        }
1741    }
1742    else if ((hasFileInputs || multipart) && fileAPI) {
1743        jqxhr = fileUploadXhr(a);
1744    }
1745    else {
1746        jqxhr = $.ajax(options);
1747    }
1748
1749    $form.removeData('jqxhr').data('jqxhr', jqxhr);
1750
1751    // clear element array
1752    for (var k=0; k < elements.length; k++)
1753        elements[k] = null;
1754
1755    // fire 'notify' event
1756    this.trigger('form-submit-notify', [this, options]);
1757    return this;
1758
1759    // utility fn for deep serialization
1760    function deepSerialize(extraData){
1761        var serialized = $.param(extraData).split('&');
1762        var len = serialized.length;
1763        var result = {};
1764        var i, part;
1765        for (i=0; i < len; i++) {
1766            part = serialized[i].split('=');
1767            result[decodeURIComponent(part[0])] = decodeURIComponent(part[1]);
1768        }
1769        return result;
1770    }
1771
1772     // XMLHttpRequest Level 2 file uploads (big hat tip to francois2metz)
1773    function fileUploadXhr(a) {
1774        var formdata = new FormData();
1775
1776        for (var i=0; i < a.length; i++) {
1777            formdata.append(a[i].name, a[i].value);
1778        }
1779
1780        if (options.extraData) {
1781            var serializedData = deepSerialize(options.extraData);
1782            for (var p in serializedData)
1783                if (serializedData.hasOwnProperty(p))
1784                    formdata.append(p, serializedData[p]);
1785        }
1786
1787        options.data = null;
1788
1789        var s = $.extend(true, {}, $.ajaxSettings, options, {
1790            contentType: false,
1791            processData: false,
1792            cache: false,
1793            type: method || 'POST'
1794        });
1795
1796        if (options.uploadProgress) {
1797            // workaround because jqXHR does not expose upload property
1798            s.xhr = function() {
1799                var xhr = jQuery.ajaxSettings.xhr();
1800                if (xhr.upload) {
1801                    xhr.upload.onprogress = function(event) {
1802                        var percent = 0;
1803                        var position = event.loaded || event.position; /*event.position is deprecated*/
1804                        var total = event.total;
1805                        if (event.lengthComputable) {
1806                            percent = Math.ceil(position / total * 100);
1807                        }
1808                        options.uploadProgress(event, position, total, percent);
1809                    };
1810                }
1811                return xhr;
1812            };
1813        }
1814
1815        s.data = null;
1816            var beforeSend = s.beforeSend;
1817            s.beforeSend = function(xhr, o) {
1818                o.data = formdata;
1819                if(beforeSend)
1820                    beforeSend.call(this, xhr, o);
1821        };
1822        return $.ajax(s);
1823    }
1824
1825    // private function for handling file uploads (hat tip to YAHOO!)
1826    function fileUploadIframe(a) {
1827        var form = $form[0], el, i, s, g, id, $io, io, xhr, sub, n, timedOut, timeoutHandle;
1828        var useProp = !!$.fn.prop;
1829        var deferred = $.Deferred();
1830
1831        if ($('[name=submit],[id=submit]', form).length) {
1832            // if there is an input with a name or id of 'submit' then we won't be
1833            // able to invoke the submit fn on the form (at least not x-browser)
1834            alert('Error: Form elements must not have name or id of "submit".');
1835            deferred.reject();
1836            return deferred;
1837        }
1838
1839        if (a) {
1840            // ensure that every serialized input is still enabled
1841            for (i=0; i < elements.length; i++) {
1842                el = $(elements[i]);
1843                if ( useProp )
1844                    el.prop('disabled', false);
1845                else
1846                    el.removeAttr('disabled');
1847            }
1848        }
1849
1850        s = $.extend(true, {}, $.ajaxSettings, options);
1851        s.context = s.context || s;
1852        id = 'jqFormIO' + (new Date().getTime());
1853        if (s.iframeTarget) {
1854            $io = $(s.iframeTarget);
1855            n = $io.attr('name');
1856            if (!n)
1857                 $io.attr('name', id);
1858            else
1859                id = n;
1860        }
1861        else {
1862            $io = $('<iframe name="' + id + '" src="'+ s.iframeSrc +'" />');
1863            $io.css({ position: 'absolute', top: '-1000px', left: '-1000px' });
1864        }
1865        io = $io[0];
1866
1867
1868        xhr = { // mock object
1869            aborted: 0,
1870            responseText: null,
1871            responseXML: null,
1872            status: 0,
1873            statusText: 'n/a',
1874            getAllResponseHeaders: function() {},
1875            getResponseHeader: function() {},
1876            setRequestHeader: function() {},
1877            abort: function(status) {
1878                var e = (status === 'timeout' ? 'timeout' : 'aborted');
1879                log('aborting upload... ' + e);
1880                this.aborted = 1;
1881                // #214
1882                if (io.contentWindow.document.execCommand) {
1883                    try { // #214
1884                        io.contentWindow.document.execCommand('Stop');
1885                    } catch(ignore) {}
1886                }
1887                $io.attr('src', s.iframeSrc); // abort op in progress
1888                xhr.error = e;
1889                if (s.error)
1890                    s.error.call(s.context, xhr, e, status);
1891                if (g)
1892                    $.event.trigger("ajaxError", [xhr, s, e]);
1893                if (s.complete)
1894                    s.complete.call(s.context, xhr, e);
1895            }
1896        };
1897
1898        g = s.global;
1899        // trigger ajax global events so that activity/block indicators work like normal
1900        if (g && 0 === $.active++) {
1901            $.event.trigger("ajaxStart");
1902        }
1903        if (g) {
1904            $.event.trigger("ajaxSend", [xhr, s]);
1905        }
1906
1907        if (s.beforeSend && s.beforeSend.call(s.context, xhr, s) === false) {
1908            if (s.global) {
1909                $.active--;
1910            }
1911            deferred.reject();
1912            return deferred;
1913        }
1914        if (xhr.aborted) {
1915            deferred.reject();
1916            return deferred;
1917        }
1918
1919        // add submitting element to data if we know it
1920        sub = form.clk;
1921        if (sub) {
1922            n = sub.name;
1923            if (n && !sub.disabled) {
1924                s.extraData = s.extraData || {};
1925                s.extraData[n] = sub.value;
1926                if (sub.type == "image") {
1927                    s.extraData[n+'.x'] = form.clk_x;
1928                    s.extraData[n+'.y'] = form.clk_y;
1929                }
1930            }
1931        }
1932
1933        var CLIENT_TIMEOUT_ABORT = 1;
1934        var SERVER_ABORT = 2;
1935
1936        function getDoc(frame) {
1937            var doc = frame.contentWindow ? frame.contentWindow.document : frame.contentDocument ? frame.contentDocument : frame.document;
1938            return doc;
1939        }
1940
1941        // Rails CSRF hack (thanks to Yvan Barthelemy)
1942        var csrf_token = $('meta[name=csrf-token]').attr('content');
1943        var csrf_param = $('meta[name=csrf-param]').attr('content');
1944        if (csrf_param && csrf_token) {
1945            s.extraData = s.extraData || {};
1946            s.extraData[csrf_param] = csrf_token;
1947        }
1948
1949        // take a breath so that pending repaints get some cpu time before the upload starts
1950        function doSubmit() {
1951            // make sure form attrs are set
1952            var t = $form.attr('target'), a = $form.attr('action');
1953
1954            // update form attrs in IE friendly way
1955            form.setAttribute('target',id);
1956            if (!method) {
1957                form.setAttribute('method', 'POST');
1958            }
1959            if (a != s.url) {
1960                form.setAttribute('action', s.url);
1961            }
1962
1963            // ie borks in some cases when setting encoding
1964            if (! s.skipEncodingOverride && (!method || /post/i.test(method))) {
1965                $form.attr({
1966                    encoding: 'multipart/form-data',
1967                    enctype:  'multipart/form-data'
1968                });
1969            }
1970
1971            // support timout
1972            if (s.timeout) {
1973                timeoutHandle = setTimeout(function() { timedOut = true; cb(CLIENT_TIMEOUT_ABORT); }, s.timeout);
1974            }
1975
1976            // look for server aborts
1977            function checkState() {
1978                try {
1979                    var state = getDoc(io).readyState;
1980                    log('state = ' + state);
1981                    if (state && state.toLowerCase() == 'uninitialized')
1982                        setTimeout(checkState,50);
1983                }
1984                catch(e) {
1985                    log('Server abort: ' , e, ' (', e.name, ')');
1986                    cb(SERVER_ABORT);
1987                    if (timeoutHandle)
1988                        clearTimeout(timeoutHandle);
1989                    timeoutHandle = undefined;
1990                }
1991            }
1992
1993            // add "extra" data to form if provided in options
1994            var extraInputs = [];
1995            try {
1996                if (s.extraData) {
1997                    for (var n in s.extraData) {
1998                        if (s.extraData.hasOwnProperty(n)) {
1999                           // if using the $.param format that allows for multiple values with the same name
2000                           if($.isPlainObject(s.extraData[n]) && s.extraData[n].hasOwnProperty('name') && s.extraData[n].hasOwnProperty('value')) {
2001                               extraInputs.push(
2002                               $('<input type="hidden" name="'+s.extraData[n].name+'">').attr('value',s.extraData[n].value)
2003                                   .appendTo(form)[0]);
2004                           } else {
2005                               extraInputs.push(
2006                               $('<input type="hidden" name="'+n+'">').attr('value',s.extraData[n])
2007                                   .appendTo(form)[0]);
2008                           }
2009                        }
2010                    }
2011                }
2012
2013                if (!s.iframeTarget) {
2014                    // add iframe to doc and submit the form
2015                    $io.appendTo('body');
2016                    if (io.attachEvent)
2017                        io.attachEvent('onload', cb);
2018                    else
2019                        io.addEventListener('load', cb, false);
2020                }
2021                setTimeout(checkState,15);
2022                form.submit();
2023            }
2024            finally {
2025                // reset attrs and remove "extra" input elements
2026                form.setAttribute('action',a);
2027                if(t) {
2028                    form.setAttribute('target', t);
2029                } else {
2030                    $form.removeAttr('target');
2031                }
2032                $(extraInputs).remove();
2033            }
2034        }
2035
2036        if (s.forceSync) {
2037            doSubmit();
2038        }
2039        else {
2040            setTimeout(doSubmit, 10); // this lets dom updates render
2041        }
2042
2043        var data, doc, domCheckCount = 50, callbackProcessed;
2044
2045        function cb(e) {
2046            if (xhr.aborted || callbackProcessed) {
2047                return;
2048            }
2049            try {
2050                doc = getDoc(io);
2051            }
2052            catch(ex) {
2053                log('cannot access response document: ', ex);
2054                e = SERVER_ABORT;
2055            }
2056            if (e === CLIENT_TIMEOUT_ABORT && xhr) {
2057                xhr.abort('timeout');
2058                deferred.reject(xhr, 'timeout');
2059                return;
2060            }
2061            else if (e == SERVER_ABORT && xhr) {
2062                xhr.abort('server abort');
2063                deferred.reject(xhr, 'error', 'server abort');
2064                return;
2065            }
2066
2067            if (!doc || doc.location.href == s.iframeSrc) {
2068                // response not received yet
2069                if (!timedOut)
2070                    return;
2071            }
2072            if (io.detachEvent)
2073                io.detachEvent('onload', cb);
2074            else
2075                io.removeEventListener('load', cb, false);
2076
2077            var status = 'success', errMsg;
2078            try {
2079                if (timedOut) {
2080                    throw 'timeout';
2081                }
2082
2083                var isXml = s.dataType == 'xml' || doc.XMLDocument || $.isXMLDoc(doc);
2084                log('isXml='+isXml);
2085                if (!isXml && window.opera && (doc.body === null || !doc.body.innerHTML)) {
2086                    if (--domCheckCount) {
2087                        // in some browsers (Opera) the iframe DOM is not always traversable when
2088                        // the onload callback fires, so we loop a bit to accommodate
2089                        log('requeing onLoad callback, DOM not available');
2090                        setTimeout(cb, 250);
2091                        return;
2092                    }
2093                    // let this fall through because server response could be an empty document
2094                    //log('Could not access iframe DOM after mutiple tries.');
2095                    //throw 'DOMException: not available';
2096                }
2097
2098                //log('response detected');
2099                var docRoot = doc.body ? doc.body : doc.documentElement;
2100                xhr.responseText = docRoot ? docRoot.innerHTML : null;
2101                xhr.responseXML = doc.XMLDocument ? doc.XMLDocument : doc;
2102                if (isXml)
2103                    s.dataType = 'xml';
2104                xhr.getResponseHeader = function(header){
2105                    var headers = {'content-type': s.dataType};
2106                    return headers[header];
2107                };
2108                // support for XHR 'status' & 'statusText' emulation :
2109                if (docRoot) {
2110                    xhr.status = Number( docRoot.getAttribute('status') ) || xhr.status;
2111                    xhr.statusText = docRoot.getAttribute('statusText') || xhr.statusText;
2112                }
2113
2114                var dt = (s.dataType || '').toLowerCase();
2115                var scr = /(json|script|text)/.test(dt);
2116                if (scr || s.textarea) {
2117                    // see if user embedded response in textarea
2118                    var ta = doc.getElementsByTagName('textarea')[0];
2119                    if (ta) {
2120                        xhr.responseText = ta.value;
2121                        // support for XHR 'status' & 'statusText' emulation :
2122                        xhr.status = Number( ta.getAttribute('status') ) || xhr.status;
2123                        xhr.statusText = ta.getAttribute('statusText') || xhr.statusText;
2124                    }
2125                    else if (scr) {
2126                        // account for browsers injecting pre around json response
2127                        var pre = doc.getElementsByTagName('pre')[0];
2128                        var b = doc.getElementsByTagName('body')[0];
2129                        if (pre) {
2130                            xhr.responseText = pre.textContent ? pre.textContent : pre.innerText;
2131                        }
2132                        else if (b) {
2133                            xhr.responseText = b.textContent ? b.textContent : b.innerText;
2134                        }
2135                    }
2136                }
2137                else if (dt == 'xml' && !xhr.responseXML && xhr.responseText) {
2138                    xhr.responseXML = toXml(xhr.responseText);
2139                }
2140
2141                try {
2142                    data = httpData(xhr, dt, s);
2143                }
2144                catch (e) {
2145                    status = 'parsererror';
2146                    xhr.error = errMsg = (e || status);
2147                }
2148            }
2149            catch (e) {
2150                log('error caught: ',e);
2151                status = 'error';
2152                xhr.error = errMsg = (e || status);
2153            }
2154
2155            if (xhr.aborted) {
2156                log('upload aborted');
2157                status = null;
2158            }
2159
2160            if (xhr.status) { // we've set xhr.status
2161                status = (xhr.status >= 200 && xhr.status < 300 || xhr.status === 304) ? 'success' : 'error';
2162            }
2163
2164            // ordering of these callbacks/triggers is odd, but that's how $.ajax does it
2165            if (status === 'success') {
2166                if (s.success)
2167                    s.success.call(s.context, data, 'success', xhr);
2168                deferred.resolve(xhr.responseText, 'success', xhr);
2169                if (g)
2170                    $.event.trigger("ajaxSuccess", [xhr, s]);
2171            }
2172            else if (status) {
2173                if (errMsg === undefined)
2174                    errMsg = xhr.statusText;
2175                if (s.error)
2176                    s.error.call(s.context, xhr, status, errMsg);
2177                deferred.reject(xhr, 'error', errMsg);
2178                if (g)
2179                    $.event.trigger("ajaxError", [xhr, s, errMsg]);
2180            }
2181
2182            if (g)
2183                $.event.trigger("ajaxComplete", [xhr, s]);
2184
2185            if (g && ! --$.active) {
2186                $.event.trigger("ajaxStop");
2187            }
2188
2189            if (s.complete)
2190                s.complete.call(s.context, xhr, status);
2191
2192            callbackProcessed = true;
2193            if (s.timeout)
2194                clearTimeout(timeoutHandle);
2195
2196            // clean up
2197            setTimeout(function() {
2198                if (!s.iframeTarget)
2199                    $io.remove();
2200                xhr.responseXML = null;
2201            }, 100);
2202        }
2203
2204        var toXml = $.parseXML || function(s, doc) { // use parseXML if available (jQuery 1.5+)
2205            if (window.ActiveXObject) {
2206                doc = new ActiveXObject('Microsoft.XMLDOM');
2207                doc.async = 'false';
2208                doc.loadXML(s);
2209            }
2210            else {
2211                doc = (new DOMParser()).parseFromString(s, 'text/xml');
2212            }
2213            return (doc && doc.documentElement && doc.documentElement.nodeName != 'parsererror') ? doc : null;
2214        };
2215        var parseJSON = $.parseJSON || function(s) {
2216            /*jslint evil:true */
2217            return window['eval']('(' + s + ')');
2218        };
2219
2220        var httpData = function( xhr, type, s ) { // mostly lifted from jq1.4.4
2221
2222            var ct = xhr.getResponseHeader('content-type') || '',
2223                xml = type === 'xml' || !type && ct.indexOf('xml') >= 0,
2224                data = xml ? xhr.responseXML : xhr.responseText;
2225
2226            if (xml && data.documentElement.nodeName === 'parsererror') {
2227                if ($.error)
2228                    $.error('parsererror');
2229            }
2230            if (s && s.dataFilter) {
2231                data = s.dataFilter(data, type);
2232            }
2233            if (typeof data === 'string') {
2234                if (type === 'json' || !type && ct.indexOf('json') >= 0) {
2235                    data = parseJSON(data);
2236                } else if (type === "script" || !type && ct.indexOf("javascript") >= 0) {
2237                    $.globalEval(data);
2238                }
2239            }
2240            return data;
2241        };
2242
2243        return deferred;
2244    }
2245};
2246
2247/**
2248 * ajaxForm() provides a mechanism for fully automating form submission.
2249 *
2250 * The advantages of using this method instead of ajaxSubmit() are:
2251 *
2252 * 1: This method will include coordinates for <input type="image" /> elements (if the element
2253 *    is used to submit the form).
2254 * 2. This method will include the submit element's name/value data (for the element that was
2255 *    used to submit the form).
2256 * 3. This method binds the submit() method to the form for you.
2257 *
2258 * The options argument for ajaxForm works exactly as it does for ajaxSubmit.  ajaxForm merely
2259 * passes the options argument along after properly binding events for submit elements and
2260 * the form itself.
2261 */
2262$.fn.ajaxForm = function(options) {
2263    options = options || {};
2264    options.delegation = options.delegation && $.isFunction($.fn.on);
2265
2266    // in jQuery 1.3+ we can fix mistakes with the ready state
2267    if (!options.delegation && this.length === 0) {
2268        var o = { s: this.selector, c: this.context };
2269        if (!$.isReady && o.s) {
2270            log('DOM not ready, queuing ajaxForm');
2271            $(function() {
2272                $(o.s,o.c).ajaxForm(options);
2273            });
2274            return this;
2275        }
2276        // is your DOM ready?  http://docs.jquery.com/Tutorials:Introducing_$(document).ready()
2277        log('terminating; zero elements found by selector' + ($.isReady ? '' : ' (DOM not ready)'));
2278        return this;
2279    }
2280
2281    if ( options.delegation ) {
2282        $(document)
2283            .off('submit.form-plugin', this.selector, doAjaxSubmit)
2284            .off('click.form-plugin', this.selector, captureSubmittingElement)
2285            .on('submit.form-plugin', this.selector, options, doAjaxSubmit)
2286            .on('click.form-plugin', this.selector, options, captureSubmittingElement);
2287        return this;
2288    }
2289
2290    return this.ajaxFormUnbind()
2291        .bind('submit.form-plugin', options, doAjaxSubmit)
2292        .bind('click.form-plugin', options, captureSubmittingElement);
2293};
2294
2295// private event handlers
2296function doAjaxSubmit(e) {
2297    /*jshint validthis:true */
2298    var options = e.data;
2299    if (!e.isDefaultPrevented()) { // if event has been canceled, don't proceed
2300        e.preventDefault();
2301        $(this).ajaxSubmit(options);
2302    }
2303}
2304
2305function captureSubmittingElement(e) {
2306    /*jshint validthis:true */
2307    var target = e.target;
2308    var $el = $(target);
2309    if (!($el.is("[type=submit],[type=image]"))) {
2310        // is this a child element of the submit el?  (ex: a span within a button)
2311        var t = $el.closest('[type=submit]');
2312        if (t.length === 0) {
2313            return;
2314        }
2315        target = t[0];
2316    }
2317    var form = this;
2318    form.clk = target;
2319    if (target.type == 'image') {
2320        if (e.offsetX !== undefined) {
2321            form.clk_x = e.offsetX;
2322            form.clk_y = e.offsetY;
2323        } else if (typeof $.fn.offset == 'function') {
2324            var offset = $el.offset();
2325            form.clk_x = e.pageX - offset.left;
2326            form.clk_y = e.pageY - offset.top;
2327        } else {
2328            form.clk_x = e.pageX - target.offsetLeft;
2329            form.clk_y = e.pageY - target.offsetTop;
2330        }
2331    }
2332    // clear form vars
2333    setTimeout(function() { form.clk = form.clk_x = form.clk_y = null; }, 100);
2334}
2335
2336
2337// ajaxFormUnbind unbinds the event handlers that were bound by ajaxForm
2338$.fn.ajaxFormUnbind = function() {
2339    return this.unbind('submit.form-plugin click.form-plugin');
2340};
2341
2342/**
2343 * formToArray() gathers form element data into an array of objects that can
2344 * be passed to any of the following ajax functions: $.get, $.post, or load.
2345 * Each object in the array has both a 'name' and 'value' property.  An example of
2346 * an array for a simple login form might be:
2347 *
2348 * [ { name: 'username', value: 'jresig' }, { name: 'password', value: 'secret' } ]
2349 *
2350 * It is this array that is passed to pre-submit callback functions provided to the
2351 * ajaxSubmit() and ajaxForm() methods.
2352 */
2353$.fn.formToArray = function(semantic, elements) {
2354    var a = [];
2355    if (this.length === 0) {
2356        return a;
2357    }
2358
2359    var form = this[0];
2360    var els = semantic ? form.getElementsByTagName('*') : form.elements;
2361    if (!els) {
2362        return a;
2363    }
2364
2365    var i,j,n,v,el,max,jmax;
2366    for(i=0, max=els.length; i < max; i++) {
2367        el = els[i];
2368        n = el.name;
2369        if (!n) {
2370            continue;
2371        }
2372
2373        if (semantic && form.clk && el.type == "image") {
2374            // handle image inputs on the fly when semantic == true
2375            if(!el.disabled && form.clk == el) {
2376                a.push({name: n, value: $(el).val(), type: el.type });
2377                a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y});
2378            }
2379            continue;
2380        }
2381
2382        v = $.fieldValue(el, true);
2383        if (v && v.constructor == Array) {
2384            if (elements)
2385                elements.push(el);
2386            for(j=0, jmax=v.length; j < jmax; j++) {
2387                a.push({name: n, value: v[j]});
2388            }
2389        }
2390        else if (feature.fileapi && el.type == 'file' && !el.disabled) {
2391            if (elements)
2392                elements.push(el);
2393            var files = el.files;
2394            if (files.length) {
2395                for (j=0; j < files.length; j++) {
2396                    a.push({name: n, value: files[j], type: el.type});
2397                }
2398            }
2399            else {
2400                // #180
2401                a.push({ name: n, value: '', type: el.type });
2402            }
2403        }
2404        else if (v !== null && typeof v != 'undefined') {
2405            if (elements)
2406                elements.push(el);
2407            a.push({name: n, value: v, type: el.type, required: el.required});
2408        }
2409    }
2410
2411    if (!semantic && form.clk) {
2412        // input type=='image' are not found in elements array! handle it here
2413        var $input = $(form.clk), input = $input[0];
2414        n = input.name;
2415        if (n && !input.disabled && input.type == 'image') {
2416            a.push({name: n, value: $input.val()});
2417            a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y});
2418        }
2419    }
2420    return a;
2421};
2422
2423/**
2424 * Serializes form data into a 'submittable' string. This method will return a string
2425 * in the format: name1=value1&amp;name2=value2
2426 */
2427$.fn.formSerialize = function(semantic) {
2428    //hand off to jQuery.param for proper encoding
2429    return $.param(this.formToArray(semantic));
2430};
2431
2432/**
2433 * Serializes all field elements in the jQuery object into a query string.
2434 * This method will return a string in the format: name1=value1&amp;name2=value2
2435 */
2436$.fn.fieldSerialize = function(successful) {
2437    var a = [];
2438    this.each(function() {
2439        var n = this.name;
2440        if (!n) {
2441            return;
2442        }
2443        var v = $.fieldValue(this, successful);
2444        if (v && v.constructor == Array) {
2445            for (var i=0,max=v.length; i < max; i++) {
2446                a.push({name: n, value: v[i]});
2447            }
2448        }
2449        else if (v !== null && typeof v != 'undefined') {
2450            a.push({name: this.name, value: v});
2451        }
2452    });
2453    //hand off to jQuery.param for proper encoding
2454    return $.param(a);
2455};
2456
2457/**
2458 * Returns the value(s) of the element in the matched set.  For example, consider the following form:
2459 *
2460 *  <form><fieldset>
2461 *      <input name="A" type="text" />
2462 *      <input name="A" type="text" />
2463 *      <input name="B" type="checkbox" value="B1" />
2464 *      <input name="B" type="checkbox" value="B2"/>
2465 *      <input name="C" type="radio" value="C1" />
2466 *      <input name="C" type="radio" value="C2" />
2467 *  </fieldset></form>
2468 *
2469 *  var v = $('input[type=text]').fieldValue();
2470 *  // if no values are entered into the text inputs
2471 *  v == ['','']
2472 *  // if values entered into the text inputs are 'foo' and 'bar'
2473 *  v == ['foo','bar']
2474 *
2475 *  var v = $('input[type=checkbox]').fieldValue();
2476 *  // if neither checkbox is checked
2477 *  v === undefined
2478 *  // if both checkboxes are checked
2479 *  v == ['B1', 'B2']
2480 *
2481 *  var v = $('input[type=radio]').fieldValue();
2482 *  // if neither radio is checked
2483 *  v === undefined
2484 *  // if first radio is checked
2485 *  v == ['C1']
2486 *
2487 * The successful argument controls whether or not the field element must be 'successful'
2488 * (per http://www.w3.org/TR/html4/interact/forms.html#successful-controls).
2489 * The default value of the successful argument is true.  If this value is false the value(s)
2490 * for each element is returned.
2491 *
2492 * Note: This method *always* returns an array.  If no valid value can be determined the
2493 *    array will be empty, otherwise it will contain one or more values.
2494 */
2495$.fn.fieldValue = function(successful) {
2496    for (var val=[], i=0, max=this.length; i < max; i++) {
2497        var el = this[i];
2498        var v = $.fieldValue(el, successful);
2499        if (v === null || typeof v == 'undefined' || (v.constructor == Array && !v.length)) {
2500            continue;
2501        }
2502        if (v.constructor == Array)
2503            $.merge(val, v);
2504        else
2505            val.push(v);
2506    }
2507    return val;
2508};
2509
2510/**
2511 * Returns the value of the field element.
2512 */
2513$.fieldValue = function(el, successful) {
2514    var n = el.name, t = el.type, tag = el.tagName.toLowerCase();
2515    if (successful === undefined) {
2516        successful = true;
2517    }
2518
2519    if (successful && (!n || el.disabled || t == 'reset' || t == 'button' ||
2520        (t == 'checkbox' || t == 'radio') && !el.checked ||
2521        (t == 'submit' || t == 'image') && el.form && el.form.clk != el ||
2522        tag == 'select' && el.selectedIndex == -1)) {
2523            return null;
2524    }
2525
2526    if (tag == 'select') {
2527        var index = el.selectedIndex;
2528        if (index < 0) {
2529            return null;
2530        }
2531        var a = [], ops = el.options;
2532        var one = (t == 'select-one');
2533        var max = (one ? index+1 : ops.length);
2534        for(var i=(one ? index : 0); i < max; i++) {
2535            var op = ops[i];
2536            if (op.selected) {
2537                var v = op.value;
2538                if (!v) { // extra pain for IE...
2539                    v = (op.attributes && op.attributes['value'] && !(op.attributes['value'].specified)) ? op.text : op.value;
2540                }
2541                if (one) {
2542                    return v;
2543                }
2544                a.push(v);
2545            }
2546        }
2547        return a;
2548    }
2549    return $(el).val();
2550};
2551
2552/**
2553 * Clears the form data.  Takes the following actions on the form's input fields:
2554 *  - input text fields will have their 'value' property set to the empty string
2555 *  - select elements will have their 'selectedIndex' property set to -1
2556 *  - checkbox and radio inputs will have their 'checked' property set to false
2557 *  - inputs of type submit, button, reset, and hidden will *not* be effected
2558 *  - button elements will *not* be effected
2559 */
2560$.fn.clearForm = function(includeHidden) {
2561    return this.each(function() {
2562        $('input,select,textarea', this).clearFields(includeHidden);
2563    });
2564};
2565
2566/**
2567 * Clears the selected form elements.
2568 */
2569$.fn.clearFields = $.fn.clearInputs = function(includeHidden) {
2570    var re = /^(?:color|date|datetime|email|month|number|password|range|search|tel|text|time|url|week)$/i; // 'hidden' is not in this list
2571    return this.each(function() {
2572        var t = this.type, tag = this.tagName.toLowerCase();
2573        if (re.test(t) || tag == 'textarea') {
2574            this.value = '';
2575        }
2576        else if (t == 'checkbox' || t == 'radio') {
2577            this.checked = false;
2578        }
2579        else if (tag == 'select') {
2580            this.selectedIndex = -1;
2581        }
2582        else if (includeHidden) {
2583            // includeHidden can be the value true, or it can be a selector string
2584            // indicating a special test; for example:
2585            //  $('#myForm').clearForm('.special:hidden')
2586            // the above would clean hidden inputs that have the class of 'special'
2587            if ( (includeHidden === true && /hidden/.test(t)) ||
2588                 (typeof includeHidden == 'string' && $(this).is(includeHidden)) )
2589                this.value = '';
2590        }
2591    });
2592};
2593
2594/**
2595 * Resets the form data.  Causes all form elements to be reset to their original value.
2596 */
2597$.fn.resetForm = function() {
2598    return this.each(function() {
2599        // guard against an input with the name of 'reset'
2600        // note that IE reports the reset function as an 'object'
2601        if (typeof this.reset == 'function' || (typeof this.reset == 'object' && !this.reset.nodeType)) {
2602            this.reset();
2603        }
2604    });
2605};
2606
2607/**
2608 * Enables or disables any matching elements.
2609 */
2610$.fn.enable = function(b) {
2611    if (b === undefined) {
2612        b = true;
2613    }
2614    return this.each(function() {
2615        this.disabled = !b;
2616    });
2617};
2618
2619/**
2620 * Checks/unchecks any matching checkboxes or radio buttons and
2621 * selects/deselects and matching option elements.
2622 */
2623$.fn.selected = function(select) {
2624    if (select === undefined) {
2625        select = true;
2626    }
2627    return this.each(function() {
2628        var t = this.type;
2629        if (t == 'checkbox' || t == 'radio') {
2630            this.checked = select;
2631        }
2632        else if (this.tagName.toLowerCase() == 'option') {
2633            var $sel = $(this).parent('select');
2634            if (select && $sel[0] && $sel[0].type == 'select-one') {
2635                // deselect all other options
2636                $sel.find('option').selected(false);
2637            }
2638            this.selected = select;
2639        }
2640    });
2641};
2642
2643// expose debug var
2644$.fn.ajaxSubmit.debug = false;
2645
2646// helper fn for console logging
2647function log() {
2648    if (!$.fn.ajaxSubmit.debug)
2649        return;
2650    var msg = '[jquery.form] ' + Array.prototype.join.call(arguments,'');
2651    if (window.console && window.console.log) {
2652        window.console.log(msg);
2653    }
2654    else if (window.opera && window.opera.postError) {
2655        window.opera.postError(msg);
2656    }
2657}
2658
2659})(jQuery);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.