jquery-validation-rails 1.15.0.0 → 1.16.0

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