PluginProbe ʕ •ᴥ•ʔ
Everest Forms – Contact Form, Payment Form, Quiz, Survey & Custom Form Builder with AI / 1.6.3
Everest Forms – Contact Form, Payment Form, Quiz, Survey & Custom Form Builder with AI v1.6.3
3.5.2 3.5.1 3.5.0 3.4.8 3.4.7 3.4.6 1.1.0 1.1.1 1.1.2 1.1.3 1.1.4 1.1.5 1.1.5.1 1.1.6 1.1.7 1.1.8 1.1.9 1.2.0 1.2.1 1.2.2 1.2.3 1.2.4 1.3.0 1.3.1 1.3.2 1.3.3 1.3.4 1.4.0 1.4.1 1.4.2 1.4.3 1.4.4 1.4.5 1.4.6 1.4.7 1.4.8 1.4.9 1.5.0 1.5.1 1.5.10 1.5.2 1.5.3 1.5.4 1.5.5 1.5.6 1.5.7 1.5.8 1.5.9 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 1.6.5 1.6.6 1.6.6.1 1.6.7 1.7.0 1.7.0.1 1.7.0.2 1.7.0.3 1.7.1 1.7.2 1.7.2.1 1.7.2.2 1.7.3 1.7.4 1.7.5 1.7.5.1 1.7.5.2 1.7.6 1.7.7 1.7.7.1 1.7.7.2 1.7.8 1.7.9 1.8.0 1.8.0.1 1.8.1 1.8.2 1.8.2.1 1.8.2.2 1.8.2.3 1.8.3 1.8.4 1.8.5 1.8.6 1.8.7 1.8.8 1.8.9 1.9.0 1.9.0.1 1.9.1 1.9.2 1.9.3 1.9.4 1.9.4.1 1.9.5 1.9.6 1.9.7 1.9.8 1.9.9 2.0.0 2.0.0.1 2.0.1 2.0.2 2.0.3 2.0.3.1 2.0.4 2.0.4.1 2.0.5 2.0.6 2.0.7 2.0.8 2.0.8.1 2.0.9 3.0.0 3.0.0.1 3.0.1 3.0.2 3.0.3 3.0.3.1 3.0.4 3.0.4.1 3.0.4.2 3.0.5 3.0.5.1 3.0.5.2 3.0.6 3.0.6.1 3.0.7.1 3.0.8 3.0.8.1 3.0.9 3.0.9.1 3.0.9.2 3.0.9.3 3.0.9.4 3.0.9.5 3.1.0 3.1.1 3.1.2 3.2.0 3.2.1 3.2.2 3.2.3 3.2.4 3.2.5 3.2.6 3.3.0 3.4.0 3.4.1 3.4.2 3.4.2.1 3.4.3 3.4.4 3.4.5 trunk 1.0 1.0.1 1.0.2 1.0.3
everest-forms / assets / js / jquery-validate / jquery.validate.js
everest-forms / assets / js / jquery-validate Last commit date
jquery.validate.js 6 years ago jquery.validate.min.js 8 years ago
jquery.validate.js
1601 lines
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
1569 var pendingRequests = {},
1570 ajax;
1571
1572 // Use a prefilter if available (1.5+)
1573 if ( $.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 }
1600 return $;
1601 }));