jquery-validation-rails 1.13.1 → 1.15.0.0

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