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