jquery-validation-rails 1.16.0 → 1.19.0

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