jquery-validation-rails 1.16.0 → 1.19.0

Sign up to get free protection for your applications and to get access to all the features.
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
  }));