source: Application/ocrent/wwwroot/lib/jquery-validation/dist/jquery.validate.js

Last change on this file was f5f7c24, checked in by 192011 <mk.snicker@…>, 15 months ago

Initial commit

  • Property mode set to 100644
File size: 47.5 KB
RevLine 
[f5f7c24]1/*!
2 * jQuery Validation Plugin v1.17.0
3 *
4 * https://jqueryvalidation.org/
5 *
6 * Copyright (c) 2017 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 // https://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
48 // Track the used submit button to properly handle scripted
49 // submits later.
50 validator.submitButton = event.currentTarget;
51
52 // Allow suppressing validation by adding a cancel class to the submit button
53 if ( $( this ).hasClass( "cancel" ) ) {
54 validator.cancelSubmit = true;
55 }
56
57 // Allow suppressing validation by adding the html5 formnovalidate attribute to the submit button
58 if ( $( this ).attr( "formnovalidate" ) !== undefined ) {
59 validator.cancelSubmit = true;
60 }
61 } );
62
63 // Validate the form on submit
64 this.on( "submit.validate", function( event ) {
65 if ( validator.settings.debug ) {
66
67 // Prevent form submit to be able to see console output
68 event.preventDefault();
69 }
70 function handle() {
71 var hidden, result;
72
73 // Insert a hidden input as a replacement for the missing submit button
74 // The hidden input is inserted in two cases:
75 // - A user defined a `submitHandler`
76 // - There was a pending request due to `remote` method and `stopRequest()`
77 // was called to submit the form in case it's valid
78 if ( validator.submitButton && ( validator.settings.submitHandler || validator.formSubmitted ) ) {
79 hidden = $( "<input type='hidden'/>" )
80 .attr( "name", validator.submitButton.name )
81 .val( $( validator.submitButton ).val() )
82 .appendTo( validator.currentForm );
83 }
84
85 if ( validator.settings.submitHandler ) {
86 result = validator.settings.submitHandler.call( validator, validator.currentForm, event );
87 if ( hidden ) {
88
89 // And clean up afterwards; thanks to no-block-scope, hidden can be referenced
90 hidden.remove();
91 }
92 if ( result !== undefined ) {
93 return result;
94 }
95 return false;
96 }
97 return true;
98 }
99
100 // Prevent submit for invalid forms or custom submit handlers
101 if ( validator.cancelSubmit ) {
102 validator.cancelSubmit = false;
103 return handle();
104 }
105 if ( validator.form() ) {
106 if ( validator.pendingRequest ) {
107 validator.formSubmitted = true;
108 return false;
109 }
110 return handle();
111 } else {
112 validator.focusInvalid();
113 return false;
114 }
115 } );
116 }
117
118 return validator;
119 },
120
121 // https://jqueryvalidation.org/valid/
122 valid: function() {
123 var valid, validator, errorList;
124
125 if ( $( this[ 0 ] ).is( "form" ) ) {
126 valid = this.validate().form();
127 } else {
128 errorList = [];
129 valid = true;
130 validator = $( this[ 0 ].form ).validate();
131 this.each( function() {
132 valid = validator.element( this ) && valid;
133 if ( !valid ) {
134 errorList = errorList.concat( validator.errorList );
135 }
136 } );
137 validator.errorList = errorList;
138 }
139 return valid;
140 },
141
142 // https://jqueryvalidation.org/rules/
143 rules: function( command, argument ) {
144 var element = this[ 0 ],
145 settings, staticRules, existingRules, data, param, filtered;
146
147 // If nothing is selected, return empty object; can't chain anyway
148 if ( element == null ) {
149 return;
150 }
151
152 if ( !element.form && element.hasAttribute( "contenteditable" ) ) {
153 element.form = this.closest( "form" )[ 0 ];
154 element.name = this.attr( "name" );
155 }
156
157 if ( element.form == null ) {
158 return;
159 }
160
161 if ( command ) {
162 settings = $.data( element.form, "validator" ).settings;
163 staticRules = settings.rules;
164 existingRules = $.validator.staticRules( element );
165 switch ( command ) {
166 case "add":
167 $.extend( existingRules, $.validator.normalizeRule( argument ) );
168
169 // Remove messages from rules, but allow them to be set separately
170 delete existingRules.messages;
171 staticRules[ element.name ] = existingRules;
172 if ( argument.messages ) {
173 settings.messages[ element.name ] = $.extend( settings.messages[ element.name ], argument.messages );
174 }
175 break;
176 case "remove":
177 if ( !argument ) {
178 delete staticRules[ element.name ];
179 return existingRules;
180 }
181 filtered = {};
182 $.each( argument.split( /\s/ ), function( index, method ) {
183 filtered[ method ] = existingRules[ method ];
184 delete existingRules[ method ];
185 } );
186 return filtered;
187 }
188 }
189
190 data = $.validator.normalizeRules(
191 $.extend(
192 {},
193 $.validator.classRules( element ),
194 $.validator.attributeRules( element ),
195 $.validator.dataRules( element ),
196 $.validator.staticRules( element )
197 ), element );
198
199 // Make sure required is at front
200 if ( data.required ) {
201 param = data.required;
202 delete data.required;
203 data = $.extend( { required: param }, data );
204 }
205
206 // Make sure remote is at back
207 if ( data.remote ) {
208 param = data.remote;
209 delete data.remote;
210 data = $.extend( data, { remote: param } );
211 }
212
213 return data;
214 }
215} );
216
217// Custom selectors
218$.extend( $.expr.pseudos || $.expr[ ":" ], { // '|| $.expr[ ":" ]' here enables backwards compatibility to jQuery 1.7. Can be removed when dropping jQ 1.7.x support
219
220 // https://jqueryvalidation.org/blank-selector/
221 blank: function( a ) {
222 return !$.trim( "" + $( a ).val() );
223 },
224
225 // https://jqueryvalidation.org/filled-selector/
226 filled: function( a ) {
227 var val = $( a ).val();
228 return val !== null && !!$.trim( "" + val );
229 },
230
231 // https://jqueryvalidation.org/unchecked-selector/
232 unchecked: function( a ) {
233 return !$( a ).prop( "checked" );
234 }
235} );
236
237// Constructor for validator
238$.validator = function( options, form ) {
239 this.settings = $.extend( true, {}, $.validator.defaults, options );
240 this.currentForm = form;
241 this.init();
242};
243
244// https://jqueryvalidation.org/jQuery.validator.format/
245$.validator.format = function( source, params ) {
246 if ( arguments.length === 1 ) {
247 return function() {
248 var args = $.makeArray( arguments );
249 args.unshift( source );
250 return $.validator.format.apply( this, args );
251 };
252 }
253 if ( params === undefined ) {
254 return source;
255 }
256 if ( arguments.length > 2 && params.constructor !== Array ) {
257 params = $.makeArray( arguments ).slice( 1 );
258 }
259 if ( params.constructor !== Array ) {
260 params = [ params ];
261 }
262 $.each( params, function( i, n ) {
263 source = source.replace( new RegExp( "\\{" + i + "\\}", "g" ), function() {
264 return n;
265 } );
266 } );
267 return source;
268};
269
270$.extend( $.validator, {
271
272 defaults: {
273 messages: {},
274 groups: {},
275 rules: {},
276 errorClass: "error",
277 pendingClass: "pending",
278 validClass: "valid",
279 errorElement: "label",
280 focusCleanup: false,
281 focusInvalid: true,
282 errorContainer: $( [] ),
283 errorLabelContainer: $( [] ),
284 onsubmit: true,
285 ignore: ":hidden",
286 ignoreTitle: false,
287 onfocusin: function( element ) {
288 this.lastActive = element;
289
290 // Hide error label and remove error class on focus if enabled
291 if ( this.settings.focusCleanup ) {
292 if ( this.settings.unhighlight ) {
293 this.settings.unhighlight.call( this, element, this.settings.errorClass, this.settings.validClass );
294 }
295 this.hideThese( this.errorsFor( element ) );
296 }
297 },
298 onfocusout: function( element ) {
299 if ( !this.checkable( element ) && ( element.name in this.submitted || !this.optional( element ) ) ) {
300 this.element( element );
301 }
302 },
303 onkeyup: function( element, event ) {
304
305 // Avoid revalidate the field when pressing one of the following keys
306 // Shift => 16
307 // Ctrl => 17
308 // Alt => 18
309 // Caps lock => 20
310 // End => 35
311 // Home => 36
312 // Left arrow => 37
313 // Up arrow => 38
314 // Right arrow => 39
315 // Down arrow => 40
316 // Insert => 45
317 // Num lock => 144
318 // AltGr key => 225
319 var excludedKeys = [
320 16, 17, 18, 20, 35, 36, 37,
321 38, 39, 40, 45, 144, 225
322 ];
323
324 if ( event.which === 9 && this.elementValue( element ) === "" || $.inArray( event.keyCode, excludedKeys ) !== -1 ) {
325 return;
326 } else if ( element.name in this.submitted || element.name in this.invalid ) {
327 this.element( element );
328 }
329 },
330 onclick: function( element ) {
331
332 // Click on selects, radiobuttons and checkboxes
333 if ( element.name in this.submitted ) {
334 this.element( element );
335
336 // Or option elements, check parent select in that case
337 } else if ( element.parentNode.name in this.submitted ) {
338 this.element( element.parentNode );
339 }
340 },
341 highlight: function( element, errorClass, validClass ) {
342 if ( element.type === "radio" ) {
343 this.findByName( element.name ).addClass( errorClass ).removeClass( validClass );
344 } else {
345 $( element ).addClass( errorClass ).removeClass( validClass );
346 }
347 },
348 unhighlight: function( element, errorClass, validClass ) {
349 if ( element.type === "radio" ) {
350 this.findByName( element.name ).removeClass( errorClass ).addClass( validClass );
351 } else {
352 $( element ).removeClass( errorClass ).addClass( validClass );
353 }
354 }
355 },
356
357 // https://jqueryvalidation.org/jQuery.validator.setDefaults/
358 setDefaults: function( settings ) {
359 $.extend( $.validator.defaults, settings );
360 },
361
362 messages: {
363 required: "This field is required.",
364 remote: "Please fix this field.",
365 email: "Please enter a valid email address.",
366 url: "Please enter a valid URL.",
367 date: "Please enter a valid date.",
368 dateISO: "Please enter a valid date (ISO).",
369 number: "Please enter a valid number.",
370 digits: "Please enter only digits.",
371 equalTo: "Please enter the same value again.",
372 maxlength: $.validator.format( "Please enter no more than {0} characters." ),
373 minlength: $.validator.format( "Please enter at least {0} characters." ),
374 rangelength: $.validator.format( "Please enter a value between {0} and {1} characters long." ),
375 range: $.validator.format( "Please enter a value between {0} and {1}." ),
376 max: $.validator.format( "Please enter a value less than or equal to {0}." ),
377 min: $.validator.format( "Please enter a value greater than or equal to {0}." ),
378 step: $.validator.format( "Please enter a multiple of {0}." )
379 },
380
381 autoCreateRanges: false,
382
383 prototype: {
384
385 init: function() {
386 this.labelContainer = $( this.settings.errorLabelContainer );
387 this.errorContext = this.labelContainer.length && this.labelContainer || $( this.currentForm );
388 this.containers = $( this.settings.errorContainer ).add( this.settings.errorLabelContainer );
389 this.submitted = {};
390 this.valueCache = {};
391 this.pendingRequest = 0;
392 this.pending = {};
393 this.invalid = {};
394 this.reset();
395
396 var groups = ( this.groups = {} ),
397 rules;
398 $.each( this.settings.groups, function( key, value ) {
399 if ( typeof value === "string" ) {
400 value = value.split( /\s/ );
401 }
402 $.each( value, function( index, name ) {
403 groups[ name ] = key;
404 } );
405 } );
406 rules = this.settings.rules;
407 $.each( rules, function( key, value ) {
408 rules[ key ] = $.validator.normalizeRule( value );
409 } );
410
411 function delegate( event ) {
412
413 // Set form expando on contenteditable
414 if ( !this.form && this.hasAttribute( "contenteditable" ) ) {
415 this.form = $( this ).closest( "form" )[ 0 ];
416 this.name = $( this ).attr( "name" );
417 }
418
419 var validator = $.data( this.form, "validator" ),
420 eventType = "on" + event.type.replace( /^validate/, "" ),
421 settings = validator.settings;
422 if ( settings[ eventType ] && !$( this ).is( settings.ignore ) ) {
423 settings[ eventType ].call( validator, this, event );
424 }
425 }
426
427 $( this.currentForm )
428 .on( "focusin.validate focusout.validate keyup.validate",
429 ":text, [type='password'], [type='file'], select, textarea, [type='number'], [type='search'], " +
430 "[type='tel'], [type='url'], [type='email'], [type='datetime'], [type='date'], [type='month'], " +
431 "[type='week'], [type='time'], [type='datetime-local'], [type='range'], [type='color'], " +
432 "[type='radio'], [type='checkbox'], [contenteditable], [type='button']", delegate )
433
434 // Support: Chrome, oldIE
435 // "select" is provided as event.target when clicking a option
436 .on( "click.validate", "select, option, [type='radio'], [type='checkbox']", delegate );
437
438 if ( this.settings.invalidHandler ) {
439 $( this.currentForm ).on( "invalid-form.validate", this.settings.invalidHandler );
440 }
441 },
442
443 // https://jqueryvalidation.org/Validator.form/
444 form: function() {
445 this.checkForm();
446 $.extend( this.submitted, this.errorMap );
447 this.invalid = $.extend( {}, this.errorMap );
448 if ( !this.valid() ) {
449 $( this.currentForm ).triggerHandler( "invalid-form", [ this ] );
450 }
451 this.showErrors();
452 return this.valid();
453 },
454
455 checkForm: function() {
456 this.prepareForm();
457 for ( var i = 0, elements = ( this.currentElements = this.elements() ); elements[ i ]; i++ ) {
458 this.check( elements[ i ] );
459 }
460 return this.valid();
461 },
462
463 // https://jqueryvalidation.org/Validator.element/
464 element: function( element ) {
465 var cleanElement = this.clean( element ),
466 checkElement = this.validationTargetFor( cleanElement ),
467 v = this,
468 result = true,
469 rs, group;
470
471 if ( checkElement === undefined ) {
472 delete this.invalid[ cleanElement.name ];
473 } else {
474 this.prepareElement( checkElement );
475 this.currentElements = $( checkElement );
476
477 // If this element is grouped, then validate all group elements already
478 // containing a value
479 group = this.groups[ checkElement.name ];
480 if ( group ) {
481 $.each( this.groups, function( name, testgroup ) {
482 if ( testgroup === group && name !== checkElement.name ) {
483 cleanElement = v.validationTargetFor( v.clean( v.findByName( name ) ) );
484 if ( cleanElement && cleanElement.name in v.invalid ) {
485 v.currentElements.push( cleanElement );
486 result = v.check( cleanElement ) && result;
487 }
488 }
489 } );
490 }
491
492 rs = this.check( checkElement ) !== false;
493 result = result && rs;
494 if ( rs ) {
495 this.invalid[ checkElement.name ] = false;
496 } else {
497 this.invalid[ checkElement.name ] = true;
498 }
499
500 if ( !this.numberOfInvalids() ) {
501
502 // Hide error containers on last error
503 this.toHide = this.toHide.add( this.containers );
504 }
505 this.showErrors();
506
507 // Add aria-invalid status for screen readers
508 $( element ).attr( "aria-invalid", !rs );
509 }
510
511 return result;
512 },
513
514 // https://jqueryvalidation.org/Validator.showErrors/
515 showErrors: function( errors ) {
516 if ( errors ) {
517 var validator = this;
518
519 // Add items to error list and map
520 $.extend( this.errorMap, errors );
521 this.errorList = $.map( this.errorMap, function( message, name ) {
522 return {
523 message: message,
524 element: validator.findByName( name )[ 0 ]
525 };
526 } );
527
528 // Remove items from success list
529 this.successList = $.grep( this.successList, function( element ) {
530 return !( element.name in errors );
531 } );
532 }
533 if ( this.settings.showErrors ) {
534 this.settings.showErrors.call( this, this.errorMap, this.errorList );
535 } else {
536 this.defaultShowErrors();
537 }
538 },
539
540 // https://jqueryvalidation.org/Validator.resetForm/
541 resetForm: function() {
542 if ( $.fn.resetForm ) {
543 $( this.currentForm ).resetForm();
544 }
545 this.invalid = {};
546 this.submitted = {};
547 this.prepareForm();
548 this.hideErrors();
549 var elements = this.elements()
550 .removeData( "previousValue" )
551 .removeAttr( "aria-invalid" );
552
553 this.resetElements( elements );
554 },
555
556 resetElements: function( elements ) {
557 var i;
558
559 if ( this.settings.unhighlight ) {
560 for ( i = 0; elements[ i ]; i++ ) {
561 this.settings.unhighlight.call( this, elements[ i ],
562 this.settings.errorClass, "" );
563 this.findByName( elements[ i ].name ).removeClass( this.settings.validClass );
564 }
565 } else {
566 elements
567 .removeClass( this.settings.errorClass )
568 .removeClass( this.settings.validClass );
569 }
570 },
571
572 numberOfInvalids: function() {
573 return this.objectLength( this.invalid );
574 },
575
576 objectLength: function( obj ) {
577 /* jshint unused: false */
578 var count = 0,
579 i;
580 for ( i in obj ) {
581
582 // This check allows counting elements with empty error
583 // message as invalid elements
584 if ( obj[ i ] !== undefined && obj[ i ] !== null && obj[ i ] !== false ) {
585 count++;
586 }
587 }
588 return count;
589 },
590
591 hideErrors: function() {
592 this.hideThese( this.toHide );
593 },
594
595 hideThese: function( errors ) {
596 errors.not( this.containers ).text( "" );
597 this.addWrapper( errors ).hide();
598 },
599
600 valid: function() {
601 return this.size() === 0;
602 },
603
604 size: function() {
605 return this.errorList.length;
606 },
607
608 focusInvalid: function() {
609 if ( this.settings.focusInvalid ) {
610 try {
611 $( this.findLastActive() || this.errorList.length && this.errorList[ 0 ].element || [] )
612 .filter( ":visible" )
613 .focus()
614
615 // Manually trigger focusin event; without it, focusin handler isn't called, findLastActive won't have anything to find
616 .trigger( "focusin" );
617 } catch ( e ) {
618
619 // Ignore IE throwing errors when focusing hidden elements
620 }
621 }
622 },
623
624 findLastActive: function() {
625 var lastActive = this.lastActive;
626 return lastActive && $.grep( this.errorList, function( n ) {
627 return n.element.name === lastActive.name;
628 } ).length === 1 && lastActive;
629 },
630
631 elements: function() {
632 var validator = this,
633 rulesCache = {};
634
635 // Select all valid inputs inside the form (no submit or reset buttons)
636 return $( this.currentForm )
637 .find( "input, select, textarea, [contenteditable]" )
638 .not( ":submit, :reset, :image, :disabled" )
639 .not( this.settings.ignore )
640 .filter( function() {
641 var name = this.name || $( this ).attr( "name" ); // For contenteditable
642 if ( !name && validator.settings.debug && window.console ) {
643 console.error( "%o has no name assigned", this );
644 }
645
646 // Set form expando on contenteditable
647 if ( this.hasAttribute( "contenteditable" ) ) {
648 this.form = $( this ).closest( "form" )[ 0 ];
649 this.name = name;
650 }
651
652 // Select only the first element for each name, and only those with rules specified
653 if ( name in rulesCache || !validator.objectLength( $( this ).rules() ) ) {
654 return false;
655 }
656
657 rulesCache[ name ] = true;
658 return true;
659 } );
660 },
661
662 clean: function( selector ) {
663 return $( selector )[ 0 ];
664 },
665
666 errors: function() {
667 var errorClass = this.settings.errorClass.split( " " ).join( "." );
668 return $( this.settings.errorElement + "." + errorClass, this.errorContext );
669 },
670
671 resetInternals: function() {
672 this.successList = [];
673 this.errorList = [];
674 this.errorMap = {};
675 this.toShow = $( [] );
676 this.toHide = $( [] );
677 },
678
679 reset: function() {
680 this.resetInternals();
681 this.currentElements = $( [] );
682 },
683
684 prepareForm: function() {
685 this.reset();
686 this.toHide = this.errors().add( this.containers );
687 },
688
689 prepareElement: function( element ) {
690 this.reset();
691 this.toHide = this.errorsFor( element );
692 },
693
694 elementValue: function( element ) {
695 var $element = $( element ),
696 type = element.type,
697 val, idx;
698
699 if ( type === "radio" || type === "checkbox" ) {
700 return this.findByName( element.name ).filter( ":checked" ).val();
701 } else if ( type === "number" && typeof element.validity !== "undefined" ) {
702 return element.validity.badInput ? "NaN" : $element.val();
703 }
704
705 if ( element.hasAttribute( "contenteditable" ) ) {
706 val = $element.text();
707 } else {
708 val = $element.val();
709 }
710
711 if ( type === "file" ) {
712
713 // Modern browser (chrome & safari)
714 if ( val.substr( 0, 12 ) === "C:\\fakepath\\" ) {
715 return val.substr( 12 );
716 }
717
718 // Legacy browsers
719 // Unix-based path
720 idx = val.lastIndexOf( "/" );
721 if ( idx >= 0 ) {
722 return val.substr( idx + 1 );
723 }
724
725 // Windows-based path
726 idx = val.lastIndexOf( "\\" );
727 if ( idx >= 0 ) {
728 return val.substr( idx + 1 );
729 }
730
731 // Just the file name
732 return val;
733 }
734
735 if ( typeof val === "string" ) {
736 return val.replace( /\r/g, "" );
737 }
738 return val;
739 },
740
741 check: function( element ) {
742 element = this.validationTargetFor( this.clean( element ) );
743
744 var rules = $( element ).rules(),
745 rulesCount = $.map( rules, function( n, i ) {
746 return i;
747 } ).length,
748 dependencyMismatch = false,
749 val = this.elementValue( element ),
750 result, method, rule, normalizer;
751
752 // Prioritize the local normalizer defined for this element over the global one
753 // if the former exists, otherwise user the global one in case it exists.
754 if ( typeof rules.normalizer === "function" ) {
755 normalizer = rules.normalizer;
756 } else if ( typeof this.settings.normalizer === "function" ) {
757 normalizer = this.settings.normalizer;
758 }
759
760 // If normalizer is defined, then call it to retreive the changed value instead
761 // of using the real one.
762 // Note that `this` in the normalizer is `element`.
763 if ( normalizer ) {
764 val = normalizer.call( element, val );
765
766 if ( typeof val !== "string" ) {
767 throw new TypeError( "The normalizer should return a string value." );
768 }
769
770 // Delete the normalizer from rules to avoid treating it as a pre-defined method.
771 delete rules.normalizer;
772 }
773
774 for ( method in rules ) {
775 rule = { method: method, parameters: rules[ method ] };
776 try {
777 result = $.validator.methods[ method ].call( this, val, element, rule.parameters );
778
779 // If a method indicates that the field is optional and therefore valid,
780 // don't mark it as valid when there are no other rules
781 if ( result === "dependency-mismatch" && rulesCount === 1 ) {
782 dependencyMismatch = true;
783 continue;
784 }
785 dependencyMismatch = false;
786
787 if ( result === "pending" ) {
788 this.toHide = this.toHide.not( this.errorsFor( element ) );
789 return;
790 }
791
792 if ( !result ) {
793 this.formatAndAdd( element, rule );
794 return false;
795 }
796 } catch ( e ) {
797 if ( this.settings.debug && window.console ) {
798 console.log( "Exception occurred when checking element " + element.id + ", check the '" + rule.method + "' method.", e );
799 }
800 if ( e instanceof TypeError ) {
801 e.message += ". Exception occurred when checking element " + element.id + ", check the '" + rule.method + "' method.";
802 }
803
804 throw e;
805 }
806 }
807 if ( dependencyMismatch ) {
808 return;
809 }
810 if ( this.objectLength( rules ) ) {
811 this.successList.push( element );
812 }
813 return true;
814 },
815
816 // Return the custom message for the given element and validation method
817 // specified in the element's HTML5 data attribute
818 // return the generic message if present and no method specific message is present
819 customDataMessage: function( element, method ) {
820 return $( element ).data( "msg" + method.charAt( 0 ).toUpperCase() +
821 method.substring( 1 ).toLowerCase() ) || $( element ).data( "msg" );
822 },
823
824 // Return the custom message for the given element name and validation method
825 customMessage: function( name, method ) {
826 var m = this.settings.messages[ name ];
827 return m && ( m.constructor === String ? m : m[ method ] );
828 },
829
830 // Return the first defined argument, allowing empty strings
831 findDefined: function() {
832 for ( var i = 0; i < arguments.length; i++ ) {
833 if ( arguments[ i ] !== undefined ) {
834 return arguments[ i ];
835 }
836 }
837 return undefined;
838 },
839
840 // The second parameter 'rule' used to be a string, and extended to an object literal
841 // of the following form:
842 // rule = {
843 // method: "method name",
844 // parameters: "the given method parameters"
845 // }
846 //
847 // The old behavior still supported, kept to maintain backward compatibility with
848 // old code, and will be removed in the next major release.
849 defaultMessage: function( element, rule ) {
850 if ( typeof rule === "string" ) {
851 rule = { method: rule };
852 }
853
854 var message = this.findDefined(
855 this.customMessage( element.name, rule.method ),
856 this.customDataMessage( element, rule.method ),
857
858 // 'title' is never undefined, so handle empty string as undefined
859 !this.settings.ignoreTitle && element.title || undefined,
860 $.validator.messages[ rule.method ],
861 "<strong>Warning: No message defined for " + element.name + "</strong>"
862 ),
863 theregex = /\$?\{(\d+)\}/g;
864 if ( typeof message === "function" ) {
865 message = message.call( this, rule.parameters, element );
866 } else if ( theregex.test( message ) ) {
867 message = $.validator.format( message.replace( theregex, "{$1}" ), rule.parameters );
868 }
869
870 return message;
871 },
872
873 formatAndAdd: function( element, rule ) {
874 var message = this.defaultMessage( element, rule );
875
876 this.errorList.push( {
877 message: message,
878 element: element,
879 method: rule.method
880 } );
881
882 this.errorMap[ element.name ] = message;
883 this.submitted[ element.name ] = message;
884 },
885
886 addWrapper: function( toToggle ) {
887 if ( this.settings.wrapper ) {
888 toToggle = toToggle.add( toToggle.parent( this.settings.wrapper ) );
889 }
890 return toToggle;
891 },
892
893 defaultShowErrors: function() {
894 var i, elements, error;
895 for ( i = 0; this.errorList[ i ]; i++ ) {
896 error = this.errorList[ i ];
897 if ( this.settings.highlight ) {
898 this.settings.highlight.call( this, error.element, this.settings.errorClass, this.settings.validClass );
899 }
900 this.showLabel( error.element, error.message );
901 }
902 if ( this.errorList.length ) {
903 this.toShow = this.toShow.add( this.containers );
904 }
905 if ( this.settings.success ) {
906 for ( i = 0; this.successList[ i ]; i++ ) {
907 this.showLabel( this.successList[ i ] );
908 }
909 }
910 if ( this.settings.unhighlight ) {
911 for ( i = 0, elements = this.validElements(); elements[ i ]; i++ ) {
912 this.settings.unhighlight.call( this, elements[ i ], this.settings.errorClass, this.settings.validClass );
913 }
914 }
915 this.toHide = this.toHide.not( this.toShow );
916 this.hideErrors();
917 this.addWrapper( this.toShow ).show();
918 },
919
920 validElements: function() {
921 return this.currentElements.not( this.invalidElements() );
922 },
923
924 invalidElements: function() {
925 return $( this.errorList ).map( function() {
926 return this.element;
927 } );
928 },
929
930 showLabel: function( element, message ) {
931 var place, group, errorID, v,
932 error = this.errorsFor( element ),
933 elementID = this.idOrName( element ),
934 describedBy = $( element ).attr( "aria-describedby" );
935
936 if ( error.length ) {
937
938 // Refresh error/success class
939 error.removeClass( this.settings.validClass ).addClass( this.settings.errorClass );
940
941 // Replace message on existing label
942 error.html( message );
943 } else {
944
945 // Create error element
946 error = $( "<" + this.settings.errorElement + ">" )
947 .attr( "id", elementID + "-error" )
948 .addClass( this.settings.errorClass )
949 .html( message || "" );
950
951 // Maintain reference to the element to be placed into the DOM
952 place = error;
953 if ( this.settings.wrapper ) {
954
955 // Make sure the element is visible, even in IE
956 // actually showing the wrapped element is handled elsewhere
957 place = error.hide().show().wrap( "<" + this.settings.wrapper + "/>" ).parent();
958 }
959 if ( this.labelContainer.length ) {
960 this.labelContainer.append( place );
961 } else if ( this.settings.errorPlacement ) {
962 this.settings.errorPlacement.call( this, place, $( element ) );
963 } else {
964 place.insertAfter( element );
965 }
966
967 // Link error back to the element
968 if ( error.is( "label" ) ) {
969
970 // If the error is a label, then associate using 'for'
971 error.attr( "for", elementID );
972
973 // If the element is not a child of an associated label, then it's necessary
974 // to explicitly apply aria-describedby
975 } else if ( error.parents( "label[for='" + this.escapeCssMeta( elementID ) + "']" ).length === 0 ) {
976 errorID = error.attr( "id" );
977
978 // Respect existing non-error aria-describedby
979 if ( !describedBy ) {
980 describedBy = errorID;
981 } else if ( !describedBy.match( new RegExp( "\\b" + this.escapeCssMeta( errorID ) + "\\b" ) ) ) {
982
983 // Add to end of list if not already present
984 describedBy += " " + errorID;
985 }
986 $( element ).attr( "aria-describedby", describedBy );
987
988 // If this element is grouped, then assign to all elements in the same group
989 group = this.groups[ element.name ];
990 if ( group ) {
991 v = this;
992 $.each( v.groups, function( name, testgroup ) {
993 if ( testgroup === group ) {
994 $( "[name='" + v.escapeCssMeta( name ) + "']", v.currentForm )
995 .attr( "aria-describedby", error.attr( "id" ) );
996 }
997 } );
998 }
999 }
1000 }
1001 if ( !message && this.settings.success ) {
1002 error.text( "" );
1003 if ( typeof this.settings.success === "string" ) {
1004 error.addClass( this.settings.success );
1005 } else {
1006 this.settings.success( error, element );
1007 }
1008 }
1009 this.toShow = this.toShow.add( error );
1010 },
1011
1012 errorsFor: function( element ) {
1013 var name = this.escapeCssMeta( this.idOrName( element ) ),
1014 describer = $( element ).attr( "aria-describedby" ),
1015 selector = "label[for='" + name + "'], label[for='" + name + "'] *";
1016
1017 // 'aria-describedby' should directly reference the error element
1018 if ( describer ) {
1019 selector = selector + ", #" + this.escapeCssMeta( describer )
1020 .replace( /\s+/g, ", #" );
1021 }
1022
1023 return this
1024 .errors()
1025 .filter( selector );
1026 },
1027
1028 // See https://api.jquery.com/category/selectors/, for CSS
1029 // meta-characters that should be escaped in order to be used with JQuery
1030 // as a literal part of a name/id or any selector.
1031 escapeCssMeta: function( string ) {
1032 return string.replace( /([\\!"#$%&'()*+,./:;<=>?@\[\]^`{|}~])/g, "\\$1" );
1033 },
1034
1035 idOrName: function( element ) {
1036 return this.groups[ element.name ] || ( this.checkable( element ) ? element.name : element.id || element.name );
1037 },
1038
1039 validationTargetFor: function( element ) {
1040
1041 // If radio/checkbox, validate first element in group instead
1042 if ( this.checkable( element ) ) {
1043 element = this.findByName( element.name );
1044 }
1045
1046 // Always apply ignore filter
1047 return $( element ).not( this.settings.ignore )[ 0 ];
1048 },
1049
1050 checkable: function( element ) {
1051 return ( /radio|checkbox/i ).test( element.type );
1052 },
1053
1054 findByName: function( name ) {
1055 return $( this.currentForm ).find( "[name='" + this.escapeCssMeta( name ) + "']" );
1056 },
1057
1058 getLength: function( value, element ) {
1059 switch ( element.nodeName.toLowerCase() ) {
1060 case "select":
1061 return $( "option:selected", element ).length;
1062 case "input":
1063 if ( this.checkable( element ) ) {
1064 return this.findByName( element.name ).filter( ":checked" ).length;
1065 }
1066 }
1067 return value.length;
1068 },
1069
1070 depend: function( param, element ) {
1071 return this.dependTypes[ typeof param ] ? this.dependTypes[ typeof param ]( param, element ) : true;
1072 },
1073
1074 dependTypes: {
1075 "boolean": function( param ) {
1076 return param;
1077 },
1078 "string": function( param, element ) {
1079 return !!$( param, element.form ).length;
1080 },
1081 "function": function( param, element ) {
1082 return param( element );
1083 }
1084 },
1085
1086 optional: function( element ) {
1087 var val = this.elementValue( element );
1088 return !$.validator.methods.required.call( this, val, element ) && "dependency-mismatch";
1089 },
1090
1091 startRequest: function( element ) {
1092 if ( !this.pending[ element.name ] ) {
1093 this.pendingRequest++;
1094 $( element ).addClass( this.settings.pendingClass );
1095 this.pending[ element.name ] = true;
1096 }
1097 },
1098
1099 stopRequest: function( element, valid ) {
1100 this.pendingRequest--;
1101
1102 // Sometimes synchronization fails, make sure pendingRequest is never < 0
1103 if ( this.pendingRequest < 0 ) {
1104 this.pendingRequest = 0;
1105 }
1106 delete this.pending[ element.name ];
1107 $( element ).removeClass( this.settings.pendingClass );
1108 if ( valid && this.pendingRequest === 0 && this.formSubmitted && this.form() ) {
1109 $( this.currentForm ).submit();
1110
1111 // Remove the hidden input that was used as a replacement for the
1112 // missing submit button. The hidden input is added by `handle()`
1113 // to ensure that the value of the used submit button is passed on
1114 // for scripted submits triggered by this method
1115 if ( this.submitButton ) {
1116 $( "input:hidden[name='" + this.submitButton.name + "']", this.currentForm ).remove();
1117 }
1118
1119 this.formSubmitted = false;
1120 } else if ( !valid && this.pendingRequest === 0 && this.formSubmitted ) {
1121 $( this.currentForm ).triggerHandler( "invalid-form", [ this ] );
1122 this.formSubmitted = false;
1123 }
1124 },
1125
1126 previousValue: function( element, method ) {
1127 method = typeof method === "string" && method || "remote";
1128
1129 return $.data( element, "previousValue" ) || $.data( element, "previousValue", {
1130 old: null,
1131 valid: true,
1132 message: this.defaultMessage( element, { method: method } )
1133 } );
1134 },
1135
1136 // Cleans up all forms and elements, removes validator-specific events
1137 destroy: function() {
1138 this.resetForm();
1139
1140 $( this.currentForm )
1141 .off( ".validate" )
1142 .removeData( "validator" )
1143 .find( ".validate-equalTo-blur" )
1144 .off( ".validate-equalTo" )
1145 .removeClass( "validate-equalTo-blur" );
1146 }
1147
1148 },
1149
1150 classRuleSettings: {
1151 required: { required: true },
1152 email: { email: true },
1153 url: { url: true },
1154 date: { date: true },
1155 dateISO: { dateISO: true },
1156 number: { number: true },
1157 digits: { digits: true },
1158 creditcard: { creditcard: true }
1159 },
1160
1161 addClassRules: function( className, rules ) {
1162 if ( className.constructor === String ) {
1163 this.classRuleSettings[ className ] = rules;
1164 } else {
1165 $.extend( this.classRuleSettings, className );
1166 }
1167 },
1168
1169 classRules: function( element ) {
1170 var rules = {},
1171 classes = $( element ).attr( "class" );
1172
1173 if ( classes ) {
1174 $.each( classes.split( " " ), function() {
1175 if ( this in $.validator.classRuleSettings ) {
1176 $.extend( rules, $.validator.classRuleSettings[ this ] );
1177 }
1178 } );
1179 }
1180 return rules;
1181 },
1182
1183 normalizeAttributeRule: function( rules, type, method, value ) {
1184
1185 // Convert the value to a number for number inputs, and for text for backwards compability
1186 // allows type="date" and others to be compared as strings
1187 if ( /min|max|step/.test( method ) && ( type === null || /number|range|text/.test( type ) ) ) {
1188 value = Number( value );
1189
1190 // Support Opera Mini, which returns NaN for undefined minlength
1191 if ( isNaN( value ) ) {
1192 value = undefined;
1193 }
1194 }
1195
1196 if ( value || value === 0 ) {
1197 rules[ method ] = value;
1198 } else if ( type === method && type !== "range" ) {
1199
1200 // Exception: the jquery validate 'range' method
1201 // does not test for the html5 'range' type
1202 rules[ method ] = true;
1203 }
1204 },
1205
1206 attributeRules: function( element ) {
1207 var rules = {},
1208 $element = $( element ),
1209 type = element.getAttribute( "type" ),
1210 method, value;
1211
1212 for ( method in $.validator.methods ) {
1213
1214 // Support for <input required> in both html5 and older browsers
1215 if ( method === "required" ) {
1216 value = element.getAttribute( method );
1217
1218 // Some browsers return an empty string for the required attribute
1219 // and non-HTML5 browsers might have required="" markup
1220 if ( value === "" ) {
1221 value = true;
1222 }
1223
1224 // Force non-HTML5 browsers to return bool
1225 value = !!value;
1226 } else {
1227 value = $element.attr( method );
1228 }
1229
1230 this.normalizeAttributeRule( rules, type, method, value );
1231 }
1232
1233 // 'maxlength' may be returned as -1, 2147483647 ( IE ) and 524288 ( safari ) for text inputs
1234 if ( rules.maxlength && /-1|2147483647|524288/.test( rules.maxlength ) ) {
1235 delete rules.maxlength;
1236 }
1237
1238 return rules;
1239 },
1240
1241 dataRules: function( element ) {
1242 var rules = {},
1243 $element = $( element ),
1244 type = element.getAttribute( "type" ),
1245 method, value;
1246
1247 for ( method in $.validator.methods ) {
1248 value = $element.data( "rule" + method.charAt( 0 ).toUpperCase() + method.substring( 1 ).toLowerCase() );
1249 this.normalizeAttributeRule( rules, type, method, value );
1250 }
1251 return rules;
1252 },
1253
1254 staticRules: function( element ) {
1255 var rules = {},
1256 validator = $.data( element.form, "validator" );
1257
1258 if ( validator.settings.rules ) {
1259 rules = $.validator.normalizeRule( validator.settings.rules[ element.name ] ) || {};
1260 }
1261 return rules;
1262 },
1263
1264 normalizeRules: function( rules, element ) {
1265
1266 // Handle dependency check
1267 $.each( rules, function( prop, val ) {
1268
1269 // Ignore rule when param is explicitly false, eg. required:false
1270 if ( val === false ) {
1271 delete rules[ prop ];
1272 return;
1273 }
1274 if ( val.param || val.depends ) {
1275 var keepRule = true;
1276 switch ( typeof val.depends ) {
1277 case "string":
1278 keepRule = !!$( val.depends, element.form ).length;
1279 break;
1280 case "function":
1281 keepRule = val.depends.call( element, element );
1282 break;
1283 }
1284 if ( keepRule ) {
1285 rules[ prop ] = val.param !== undefined ? val.param : true;
1286 } else {
1287 $.data( element.form, "validator" ).resetElements( $( element ) );
1288 delete rules[ prop ];
1289 }
1290 }
1291 } );
1292
1293 // Evaluate parameters
1294 $.each( rules, function( rule, parameter ) {
1295 rules[ rule ] = $.isFunction( parameter ) && rule !== "normalizer" ? parameter( element ) : parameter;
1296 } );
1297
1298 // Clean number parameters
1299 $.each( [ "minlength", "maxlength" ], function() {
1300 if ( rules[ this ] ) {
1301 rules[ this ] = Number( rules[ this ] );
1302 }
1303 } );
1304 $.each( [ "rangelength", "range" ], function() {
1305 var parts;
1306 if ( rules[ this ] ) {
1307 if ( $.isArray( rules[ this ] ) ) {
1308 rules[ this ] = [ Number( rules[ this ][ 0 ] ), Number( rules[ this ][ 1 ] ) ];
1309 } else if ( typeof rules[ this ] === "string" ) {
1310 parts = rules[ this ].replace( /[\[\]]/g, "" ).split( /[\s,]+/ );
1311 rules[ this ] = [ Number( parts[ 0 ] ), Number( parts[ 1 ] ) ];
1312 }
1313 }
1314 } );
1315
1316 if ( $.validator.autoCreateRanges ) {
1317
1318 // Auto-create ranges
1319 if ( rules.min != null && rules.max != null ) {
1320 rules.range = [ rules.min, rules.max ];
1321 delete rules.min;
1322 delete rules.max;
1323 }
1324 if ( rules.minlength != null && rules.maxlength != null ) {
1325 rules.rangelength = [ rules.minlength, rules.maxlength ];
1326 delete rules.minlength;
1327 delete rules.maxlength;
1328 }
1329 }
1330
1331 return rules;
1332 },
1333
1334 // Converts a simple string to a {string: true} rule, e.g., "required" to {required:true}
1335 normalizeRule: function( data ) {
1336 if ( typeof data === "string" ) {
1337 var transformed = {};
1338 $.each( data.split( /\s/ ), function() {
1339 transformed[ this ] = true;
1340 } );
1341 data = transformed;
1342 }
1343 return data;
1344 },
1345
1346 // https://jqueryvalidation.org/jQuery.validator.addMethod/
1347 addMethod: function( name, method, message ) {
1348 $.validator.methods[ name ] = method;
1349 $.validator.messages[ name ] = message !== undefined ? message : $.validator.messages[ name ];
1350 if ( method.length < 3 ) {
1351 $.validator.addClassRules( name, $.validator.normalizeRule( name ) );
1352 }
1353 },
1354
1355 // https://jqueryvalidation.org/jQuery.validator.methods/
1356 methods: {
1357
1358 // https://jqueryvalidation.org/required-method/
1359 required: function( value, element, param ) {
1360
1361 // Check if dependency is met
1362 if ( !this.depend( param, element ) ) {
1363 return "dependency-mismatch";
1364 }
1365 if ( element.nodeName.toLowerCase() === "select" ) {
1366
1367 // Could be an array for select-multiple or a string, both are fine this way
1368 var val = $( element ).val();
1369 return val && val.length > 0;
1370 }
1371 if ( this.checkable( element ) ) {
1372 return this.getLength( value, element ) > 0;
1373 }
1374 return value.length > 0;
1375 },
1376
1377 // https://jqueryvalidation.org/email-method/
1378 email: function( value, element ) {
1379
1380 // From https://html.spec.whatwg.org/multipage/forms.html#valid-e-mail-address
1381 // Retrieved 2014-01-14
1382 // If you have a problem with this implementation, report a bug against the above spec
1383 // Or use custom methods to implement your own email validation
1384 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 );
1385 },
1386
1387 // https://jqueryvalidation.org/url-method/
1388 url: function( value, element ) {
1389
1390 // Copyright (c) 2010-2013 Diego Perini, MIT licensed
1391 // https://gist.github.com/dperini/729294
1392 // see also https://mathiasbynens.be/demo/url-regex
1393 // modified to allow protocol-relative URLs
1394 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 );
1395 },
1396
1397 // https://jqueryvalidation.org/date-method/
1398 date: function( value, element ) {
1399 return this.optional( element ) || !/Invalid|NaN/.test( new Date( value ).toString() );
1400 },
1401
1402 // https://jqueryvalidation.org/dateISO-method/
1403 dateISO: function( value, element ) {
1404 return this.optional( element ) || /^\d{4}[\/\-](0?[1-9]|1[012])[\/\-](0?[1-9]|[12][0-9]|3[01])$/.test( value );
1405 },
1406
1407 // https://jqueryvalidation.org/number-method/
1408 number: function( value, element ) {
1409 return this.optional( element ) || /^(?:-?\d+|-?\d{1,3}(?:,\d{3})+)?(?:\.\d+)?$/.test( value );
1410 },
1411
1412 // https://jqueryvalidation.org/digits-method/
1413 digits: function( value, element ) {
1414 return this.optional( element ) || /^\d+$/.test( value );
1415 },
1416
1417 // https://jqueryvalidation.org/minlength-method/
1418 minlength: function( value, element, param ) {
1419 var length = $.isArray( value ) ? value.length : this.getLength( value, element );
1420 return this.optional( element ) || length >= param;
1421 },
1422
1423 // https://jqueryvalidation.org/maxlength-method/
1424 maxlength: function( value, element, param ) {
1425 var length = $.isArray( value ) ? value.length : this.getLength( value, element );
1426 return this.optional( element ) || length <= param;
1427 },
1428
1429 // https://jqueryvalidation.org/rangelength-method/
1430 rangelength: function( value, element, param ) {
1431 var length = $.isArray( value ) ? value.length : this.getLength( value, element );
1432 return this.optional( element ) || ( length >= param[ 0 ] && length <= param[ 1 ] );
1433 },
1434
1435 // https://jqueryvalidation.org/min-method/
1436 min: function( value, element, param ) {
1437 return this.optional( element ) || value >= param;
1438 },
1439
1440 // https://jqueryvalidation.org/max-method/
1441 max: function( value, element, param ) {
1442 return this.optional( element ) || value <= param;
1443 },
1444
1445 // https://jqueryvalidation.org/range-method/
1446 range: function( value, element, param ) {
1447 return this.optional( element ) || ( value >= param[ 0 ] && value <= param[ 1 ] );
1448 },
1449
1450 // https://jqueryvalidation.org/step-method/
1451 step: function( value, element, param ) {
1452 var type = $( element ).attr( "type" ),
1453 errorMessage = "Step attribute on input type " + type + " is not supported.",
1454 supportedTypes = [ "text", "number", "range" ],
1455 re = new RegExp( "\\b" + type + "\\b" ),
1456 notSupported = type && !re.test( supportedTypes.join() ),
1457 decimalPlaces = function( num ) {
1458 var match = ( "" + num ).match( /(?:\.(\d+))?$/ );
1459 if ( !match ) {
1460 return 0;
1461 }
1462
1463 // Number of digits right of decimal point.
1464 return match[ 1 ] ? match[ 1 ].length : 0;
1465 },
1466 toInt = function( num ) {
1467 return Math.round( num * Math.pow( 10, decimals ) );
1468 },
1469 valid = true,
1470 decimals;
1471
1472 // Works only for text, number and range input types
1473 // TODO find a way to support input types date, datetime, datetime-local, month, time and week
1474 if ( notSupported ) {
1475 throw new Error( errorMessage );
1476 }
1477
1478 decimals = decimalPlaces( param );
1479
1480 // Value can't have too many decimals
1481 if ( decimalPlaces( value ) > decimals || toInt( value ) % toInt( param ) !== 0 ) {
1482 valid = false;
1483 }
1484
1485 return this.optional( element ) || valid;
1486 },
1487
1488 // https://jqueryvalidation.org/equalTo-method/
1489 equalTo: function( value, element, param ) {
1490
1491 // Bind to the blur event of the target in order to revalidate whenever the target field is updated
1492 var target = $( param );
1493 if ( this.settings.onfocusout && target.not( ".validate-equalTo-blur" ).length ) {
1494 target.addClass( "validate-equalTo-blur" ).on( "blur.validate-equalTo", function() {
1495 $( element ).valid();
1496 } );
1497 }
1498 return value === target.val();
1499 },
1500
1501 // https://jqueryvalidation.org/remote-method/
1502 remote: function( value, element, param, method ) {
1503 if ( this.optional( element ) ) {
1504 return "dependency-mismatch";
1505 }
1506
1507 method = typeof method === "string" && method || "remote";
1508
1509 var previous = this.previousValue( element, method ),
1510 validator, data, optionDataString;
1511
1512 if ( !this.settings.messages[ element.name ] ) {
1513 this.settings.messages[ element.name ] = {};
1514 }
1515 previous.originalMessage = previous.originalMessage || this.settings.messages[ element.name ][ method ];
1516 this.settings.messages[ element.name ][ method ] = previous.message;
1517
1518 param = typeof param === "string" && { url: param } || param;
1519 optionDataString = $.param( $.extend( { data: value }, param.data ) );
1520 if ( previous.old === optionDataString ) {
1521 return previous.valid;
1522 }
1523
1524 previous.old = optionDataString;
1525 validator = this;
1526 this.startRequest( element );
1527 data = {};
1528 data[ element.name ] = value;
1529 $.ajax( $.extend( true, {
1530 mode: "abort",
1531 port: "validate" + element.name,
1532 dataType: "json",
1533 data: data,
1534 context: validator.currentForm,
1535 success: function( response ) {
1536 var valid = response === true || response === "true",
1537 errors, message, submitted;
1538
1539 validator.settings.messages[ element.name ][ method ] = previous.originalMessage;
1540 if ( valid ) {
1541 submitted = validator.formSubmitted;
1542 validator.resetInternals();
1543 validator.toHide = validator.errorsFor( element );
1544 validator.formSubmitted = submitted;
1545 validator.successList.push( element );
1546 validator.invalid[ element.name ] = false;
1547 validator.showErrors();
1548 } else {
1549 errors = {};
1550 message = response || validator.defaultMessage( element, { method: method, parameters: value } );
1551 errors[ element.name ] = previous.message = message;
1552 validator.invalid[ element.name ] = true;
1553 validator.showErrors( errors );
1554 }
1555 previous.valid = valid;
1556 validator.stopRequest( element, valid );
1557 }
1558 }, param ) );
1559 return "pending";
1560 }
1561 }
1562
1563} );
1564
1565// Ajax mode: abort
1566// usage: $.ajax({ mode: "abort"[, port: "uniqueport"]});
1567// if mode:"abort" is used, the previous request on that port (port can be undefined) is aborted via XMLHttpRequest.abort()
1568
1569var pendingRequests = {},
1570 ajax;
1571
1572// Use a prefilter if available (1.5+)
1573if ( $.ajaxPrefilter ) {
1574 $.ajaxPrefilter( function( settings, _, xhr ) {
1575 var port = settings.port;
1576 if ( settings.mode === "abort" ) {
1577 if ( pendingRequests[ port ] ) {
1578 pendingRequests[ port ].abort();
1579 }
1580 pendingRequests[ port ] = xhr;
1581 }
1582 } );
1583} else {
1584
1585 // Proxy ajax
1586 ajax = $.ajax;
1587 $.ajax = function( settings ) {
1588 var mode = ( "mode" in settings ? settings : $.ajaxSettings ).mode,
1589 port = ( "port" in settings ? settings : $.ajaxSettings ).port;
1590 if ( mode === "abort" ) {
1591 if ( pendingRequests[ port ] ) {
1592 pendingRequests[ port ].abort();
1593 }
1594 pendingRequests[ port ] = ajax.apply( this, arguments );
1595 return pendingRequests[ port ];
1596 }
1597 return ajax.apply( this, arguments );
1598 };
1599}
1600return $;
1601}));
Note: See TracBrowser for help on using the repository browser.