jquery-validation-rails 1.10.0 → 1.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,1174 +1,1155 @@
1
- /**
2
- * jQuery Validation Plugin 1.10.0
3
- *
4
- * http://bassistance.de/jquery-plugins/jquery-plugin-validation/
5
- * http://docs.jquery.com/Plugins/Validation
6
- *
7
- * Copyright (c) 2012 Jörn Zaefferer
8
- *
9
- * Dual licensed under the MIT and GPL licenses:
10
- * http://www.opensource.org/licenses/mit-license.php
11
- * http://www.gnu.org/licenses/gpl.html
12
- */
1
+ /*! jQuery Validation Plugin - v1.11.0 - 2/4/2013
2
+ * https://github.com/jzaefferer/jquery-validation
3
+ * Copyright (c) 2013 Jörn Zaefferer; Licensed MIT */
13
4
 
14
5
  (function($) {
15
6
 
16
7
  $.extend($.fn, {
17
- // http://docs.jquery.com/Plugins/Validation/validate
18
- validate: function( options ) {
19
-
20
- // if nothing is selected, return nothing; can't chain anyway
21
- if (!this.length) {
22
- if (options && options.debug && window.console) {
23
- console.warn( "nothing selected, can't validate, returning nothing" );
24
- }
25
- return;
26
- }
27
-
28
- // check if a validator for this form was already created
29
- var validator = $.data(this[0], 'validator');
30
- if ( validator ) {
31
- return validator;
32
- }
33
-
34
- // Add novalidate tag if HTML5.
35
- this.attr('novalidate', 'novalidate');
36
-
37
- validator = new $.validator( options, this[0] );
38
- $.data(this[0], 'validator', validator);
39
-
40
- if ( validator.settings.onsubmit ) {
41
-
42
- this.validateDelegate( ":submit", "click", function(ev) {
43
- if ( validator.settings.submitHandler ) {
44
- validator.submitButton = ev.target;
45
- }
46
- // allow suppressing validation by adding a cancel class to the submit button
47
- if ( $(ev.target).hasClass('cancel') ) {
48
- validator.cancelSubmit = true;
49
- }
50
- });
51
-
52
- // validate the form on submit
53
- this.submit( function( event ) {
54
- if ( validator.settings.debug ) {
55
- // prevent form submit to be able to see console output
56
- event.preventDefault();
57
- }
58
- function handle() {
59
- var hidden;
60
- if ( validator.settings.submitHandler ) {
61
- if (validator.submitButton) {
62
- // insert a hidden input as a replacement for the missing submit button
63
- hidden = $("<input type='hidden'/>").attr("name", validator.submitButton.name).val(validator.submitButton.value).appendTo(validator.currentForm);
64
- }
65
- validator.settings.submitHandler.call( validator, validator.currentForm, event );
66
- if (validator.submitButton) {
67
- // and clean up afterwards; thanks to no-block-scope, hidden can be referenced
68
- hidden.remove();
69
- }
70
- return false;
71
- }
72
- return true;
73
- }
74
-
75
- // prevent submit for invalid forms or custom submit handlers
76
- if ( validator.cancelSubmit ) {
77
- validator.cancelSubmit = false;
78
- return handle();
79
- }
80
- if ( validator.form() ) {
81
- if ( validator.pendingRequest ) {
82
- validator.formSubmitted = true;
83
- return false;
84
- }
85
- return handle();
86
- } else {
87
- validator.focusInvalid();
88
- return false;
89
- }
90
- });
91
- }
92
-
93
- return validator;
94
- },
95
- // http://docs.jquery.com/Plugins/Validation/valid
96
- valid: function() {
97
- if ( $(this[0]).is('form')) {
98
- return this.validate().form();
99
- } else {
100
- var valid = true;
101
- var validator = $(this[0].form).validate();
102
- this.each(function() {
103
- valid &= validator.element(this);
104
- });
105
- return valid;
106
- }
107
- },
108
- // attributes: space seperated list of attributes to retrieve and remove
109
- removeAttrs: function(attributes) {
110
- var result = {},
111
- $element = this;
112
- $.each(attributes.split(/\s/), function(index, value) {
113
- result[value] = $element.attr(value);
114
- $element.removeAttr(value);
115
- });
116
- return result;
117
- },
118
- // http://docs.jquery.com/Plugins/Validation/rules
119
- rules: function(command, argument) {
120
- var element = this[0];
121
-
122
- if (command) {
123
- var settings = $.data(element.form, 'validator').settings;
124
- var staticRules = settings.rules;
125
- var existingRules = $.validator.staticRules(element);
126
- switch(command) {
127
- case "add":
128
- $.extend(existingRules, $.validator.normalizeRule(argument));
129
- staticRules[element.name] = existingRules;
130
- if (argument.messages) {
131
- settings.messages[element.name] = $.extend( settings.messages[element.name], argument.messages );
132
- }
133
- break;
134
- case "remove":
135
- if (!argument) {
136
- delete staticRules[element.name];
137
- return existingRules;
138
- }
139
- var filtered = {};
140
- $.each(argument.split(/\s/), function(index, method) {
141
- filtered[method] = existingRules[method];
142
- delete existingRules[method];
143
- });
144
- return filtered;
145
- }
146
- }
147
-
148
- var data = $.validator.normalizeRules(
149
- $.extend(
150
- {},
151
- $.validator.metadataRules(element),
152
- $.validator.classRules(element),
153
- $.validator.attributeRules(element),
154
- $.validator.staticRules(element)
155
- ), element);
156
-
157
- // make sure required is at front
158
- if (data.required) {
159
- var param = data.required;
160
- delete data.required;
161
- data = $.extend({required: param}, data);
162
- }
163
-
164
- return data;
165
- }
8
+ // http://docs.jquery.com/Plugins/Validation/validate
9
+ validate: function( options ) {
10
+
11
+ // if nothing is selected, return nothing; can't chain anyway
12
+ if ( !this.length ) {
13
+ if ( options && options.debug && window.console ) {
14
+ console.warn( "Nothing selected, can't validate, returning nothing." );
15
+ }
16
+ return;
17
+ }
18
+
19
+ // check if a validator for this form was already created
20
+ var validator = $.data( this[0], "validator" );
21
+ if ( validator ) {
22
+ return validator;
23
+ }
24
+
25
+ // Add novalidate tag if HTML5.
26
+ this.attr( "novalidate", "novalidate" );
27
+
28
+ validator = new $.validator( options, this[0] );
29
+ $.data( this[0], "validator", validator );
30
+
31
+ if ( validator.settings.onsubmit ) {
32
+
33
+ this.validateDelegate( ":submit", "click", function( event ) {
34
+ if ( validator.settings.submitHandler ) {
35
+ validator.submitButton = event.target;
36
+ }
37
+ // allow suppressing validation by adding a cancel class to the submit button
38
+ if ( $(event.target).hasClass("cancel") ) {
39
+ validator.cancelSubmit = true;
40
+ }
41
+ });
42
+
43
+ // validate the form on submit
44
+ this.submit( function( event ) {
45
+ if ( validator.settings.debug ) {
46
+ // prevent form submit to be able to see console output
47
+ event.preventDefault();
48
+ }
49
+ function handle() {
50
+ var hidden;
51
+ if ( validator.settings.submitHandler ) {
52
+ if ( validator.submitButton ) {
53
+ // insert a hidden input as a replacement for the missing submit button
54
+ hidden = $("<input type='hidden'/>").attr("name", validator.submitButton.name).val(validator.submitButton.value).appendTo(validator.currentForm);
55
+ }
56
+ validator.settings.submitHandler.call( validator, validator.currentForm, event );
57
+ if ( validator.submitButton ) {
58
+ // and clean up afterwards; thanks to no-block-scope, hidden can be referenced
59
+ hidden.remove();
60
+ }
61
+ return false;
62
+ }
63
+ return true;
64
+ }
65
+
66
+ // prevent submit for invalid forms or custom submit handlers
67
+ if ( validator.cancelSubmit ) {
68
+ validator.cancelSubmit = false;
69
+ return handle();
70
+ }
71
+ if ( validator.form() ) {
72
+ if ( validator.pendingRequest ) {
73
+ validator.formSubmitted = true;
74
+ return false;
75
+ }
76
+ return handle();
77
+ } else {
78
+ validator.focusInvalid();
79
+ return false;
80
+ }
81
+ });
82
+ }
83
+
84
+ return validator;
85
+ },
86
+ // http://docs.jquery.com/Plugins/Validation/valid
87
+ valid: function() {
88
+ if ( $(this[0]).is("form")) {
89
+ return this.validate().form();
90
+ } else {
91
+ var valid = true;
92
+ var validator = $(this[0].form).validate();
93
+ this.each(function() {
94
+ valid &= validator.element(this);
95
+ });
96
+ return valid;
97
+ }
98
+ },
99
+ // attributes: space seperated list of attributes to retrieve and remove
100
+ removeAttrs: function( attributes ) {
101
+ var result = {},
102
+ $element = this;
103
+ $.each(attributes.split(/\s/), function( index, value ) {
104
+ result[value] = $element.attr(value);
105
+ $element.removeAttr(value);
106
+ });
107
+ return result;
108
+ },
109
+ // http://docs.jquery.com/Plugins/Validation/rules
110
+ rules: function( command, argument ) {
111
+ var element = this[0];
112
+
113
+ if ( command ) {
114
+ var settings = $.data(element.form, "validator").settings;
115
+ var staticRules = settings.rules;
116
+ var existingRules = $.validator.staticRules(element);
117
+ switch(command) {
118
+ case "add":
119
+ $.extend(existingRules, $.validator.normalizeRule(argument));
120
+ staticRules[element.name] = existingRules;
121
+ if ( argument.messages ) {
122
+ settings.messages[element.name] = $.extend( settings.messages[element.name], argument.messages );
123
+ }
124
+ break;
125
+ case "remove":
126
+ if ( !argument ) {
127
+ delete staticRules[element.name];
128
+ return existingRules;
129
+ }
130
+ var filtered = {};
131
+ $.each(argument.split(/\s/), function( index, method ) {
132
+ filtered[method] = existingRules[method];
133
+ delete existingRules[method];
134
+ });
135
+ return filtered;
136
+ }
137
+ }
138
+
139
+ var data = $.validator.normalizeRules(
140
+ $.extend(
141
+ {},
142
+ $.validator.classRules(element),
143
+ $.validator.attributeRules(element),
144
+ $.validator.dataRules(element),
145
+ $.validator.staticRules(element)
146
+ ), element);
147
+
148
+ // make sure required is at front
149
+ if ( data.required ) {
150
+ var param = data.required;
151
+ delete data.required;
152
+ data = $.extend({required: param}, data);
153
+ }
154
+
155
+ return data;
156
+ }
166
157
  });
167
158
 
168
159
  // Custom selectors
169
160
  $.extend($.expr[":"], {
170
- // http://docs.jquery.com/Plugins/Validation/blank
171
- blank: function(a) {return !$.trim("" + a.value);},
172
- // http://docs.jquery.com/Plugins/Validation/filled
173
- filled: function(a) {return !!$.trim("" + a.value);},
174
- // http://docs.jquery.com/Plugins/Validation/unchecked
175
- unchecked: function(a) {return !a.checked;}
161
+ // http://docs.jquery.com/Plugins/Validation/blank
162
+ blank: function( a ) { return !$.trim("" + a.value); },
163
+ // http://docs.jquery.com/Plugins/Validation/filled
164
+ filled: function( a ) { return !!$.trim("" + a.value); },
165
+ // http://docs.jquery.com/Plugins/Validation/unchecked
166
+ unchecked: function( a ) { return !a.checked; }
176
167
  });
177
168
 
178
169
  // constructor for validator
179
170
  $.validator = function( options, form ) {
180
- this.settings = $.extend( true, {}, $.validator.defaults, options );
181
- this.currentForm = form;
182
- this.init();
171
+ this.settings = $.extend( true, {}, $.validator.defaults, options );
172
+ this.currentForm = form;
173
+ this.init();
183
174
  };
184
175
 
185
- $.validator.format = function(source, params) {
186
- if ( arguments.length === 1 ) {
187
- return function() {
188
- var args = $.makeArray(arguments);
189
- args.unshift(source);
190
- return $.validator.format.apply( this, args );
191
- };
192
- }
193
- if ( arguments.length > 2 && params.constructor !== Array ) {
194
- params = $.makeArray(arguments).slice(1);
195
- }
196
- if ( params.constructor !== Array ) {
197
- params = [ params ];
198
- }
199
- $.each(params, function(i, n) {
200
- source = source.replace(new RegExp("\\{" + i + "\\}", "g"), n);
201
- });
202
- return source;
176
+ $.validator.format = function( source, params ) {
177
+ if ( arguments.length === 1 ) {
178
+ return function() {
179
+ var args = $.makeArray(arguments);
180
+ args.unshift(source);
181
+ return $.validator.format.apply( this, args );
182
+ };
183
+ }
184
+ if ( arguments.length > 2 && params.constructor !== Array ) {
185
+ params = $.makeArray(arguments).slice(1);
186
+ }
187
+ if ( params.constructor !== Array ) {
188
+ params = [ params ];
189
+ }
190
+ $.each(params, function( i, n ) {
191
+ source = source.replace( new RegExp("\\{" + i + "\\}", "g"), function() {
192
+ return n;
193
+ });
194
+ });
195
+ return source;
203
196
  };
204
197
 
205
198
  $.extend($.validator, {
206
199
 
207
- defaults: {
208
- messages: {},
209
- groups: {},
210
- rules: {},
211
- errorClass: "error",
212
- validClass: "valid",
213
- errorElement: "label",
214
- focusInvalid: true,
215
- errorContainer: $( [] ),
216
- errorLabelContainer: $( [] ),
217
- onsubmit: true,
218
- ignore: ":hidden",
219
- ignoreTitle: false,
220
- onfocusin: function(element, event) {
221
- this.lastActive = element;
222
-
223
- // hide error label and remove error class on focus if enabled
224
- if ( this.settings.focusCleanup && !this.blockFocusCleanup ) {
225
- if ( this.settings.unhighlight ) {
226
- this.settings.unhighlight.call( this, element, this.settings.errorClass, this.settings.validClass );
227
- }
228
- this.addWrapper(this.errorsFor(element)).hide();
229
- }
230
- },
231
- onfocusout: function(element, event) {
232
- if ( !this.checkable(element) && (element.name in this.submitted || !this.optional(element)) ) {
233
- this.element(element);
234
- }
235
- },
236
- onkeyup: function(element, event) {
237
- if ( event.which === 9 && this.elementValue(element) === '' ) {
238
- return;
239
- } else if ( element.name in this.submitted || element === this.lastActive ) {
240
- this.element(element);
241
- }
242
- },
243
- onclick: function(element, event) {
244
- // click on selects, radiobuttons and checkboxes
245
- if ( element.name in this.submitted ) {
246
- this.element(element);
247
- }
248
- // or option elements, check parent select in that case
249
- else if (element.parentNode.name in this.submitted) {
250
- this.element(element.parentNode);
251
- }
252
- },
253
- highlight: function(element, errorClass, validClass) {
254
- if (element.type === 'radio') {
255
- this.findByName(element.name).addClass(errorClass).removeClass(validClass);
256
- } else {
257
- $(element).addClass(errorClass).removeClass(validClass);
258
- }
259
- },
260
- unhighlight: function(element, errorClass, validClass) {
261
- if (element.type === 'radio') {
262
- this.findByName(element.name).removeClass(errorClass).addClass(validClass);
263
- } else {
264
- $(element).removeClass(errorClass).addClass(validClass);
265
- }
266
- }
267
- },
268
-
269
- // http://docs.jquery.com/Plugins/Validation/Validator/setDefaults
270
- setDefaults: function(settings) {
271
- $.extend( $.validator.defaults, settings );
272
- },
273
-
274
- messages: {
275
- required: "This field is required.",
276
- remote: "Please fix this field.",
277
- email: "Please enter a valid email address.",
278
- url: "Please enter a valid URL.",
279
- date: "Please enter a valid date.",
280
- dateISO: "Please enter a valid date (ISO).",
281
- number: "Please enter a valid number.",
282
- digits: "Please enter only digits.",
283
- creditcard: "Please enter a valid credit card number.",
284
- equalTo: "Please enter the same value again.",
285
- maxlength: $.validator.format("Please enter no more than {0} characters."),
286
- minlength: $.validator.format("Please enter at least {0} characters."),
287
- rangelength: $.validator.format("Please enter a value between {0} and {1} characters long."),
288
- range: $.validator.format("Please enter a value between {0} and {1}."),
289
- max: $.validator.format("Please enter a value less than or equal to {0}."),
290
- min: $.validator.format("Please enter a value greater than or equal to {0}.")
291
- },
292
-
293
- autoCreateRanges: false,
294
-
295
- prototype: {
296
-
297
- init: function() {
298
- this.labelContainer = $(this.settings.errorLabelContainer);
299
- this.errorContext = this.labelContainer.length && this.labelContainer || $(this.currentForm);
300
- this.containers = $(this.settings.errorContainer).add( this.settings.errorLabelContainer );
301
- this.submitted = {};
302
- this.valueCache = {};
303
- this.pendingRequest = 0;
304
- this.pending = {};
305
- this.invalid = {};
306
- this.reset();
307
-
308
- var groups = (this.groups = {});
309
- $.each(this.settings.groups, function(key, value) {
310
- $.each(value.split(/\s/), function(index, name) {
311
- groups[name] = key;
312
- });
313
- });
314
- var rules = this.settings.rules;
315
- $.each(rules, function(key, value) {
316
- rules[key] = $.validator.normalizeRule(value);
317
- });
318
-
319
- function delegate(event) {
320
- var validator = $.data(this[0].form, "validator"),
321
- eventType = "on" + event.type.replace(/^validate/, "");
322
- if (validator.settings[eventType]) {
323
- validator.settings[eventType].call(validator, this[0], event);
324
- }
325
- }
326
- $(this.currentForm)
327
- .validateDelegate(":text, [type='password'], [type='file'], select, textarea, " +
328
- "[type='number'], [type='search'] ,[type='tel'], [type='url'], " +
329
- "[type='email'], [type='datetime'], [type='date'], [type='month'], " +
330
- "[type='week'], [type='time'], [type='datetime-local'], " +
331
- "[type='range'], [type='color'] ",
332
- "focusin focusout keyup", delegate)
333
- .validateDelegate("[type='radio'], [type='checkbox'], select, option", "click", delegate);
334
-
335
- if (this.settings.invalidHandler) {
336
- $(this.currentForm).bind("invalid-form.validate", this.settings.invalidHandler);
337
- }
338
- },
339
-
340
- // http://docs.jquery.com/Plugins/Validation/Validator/form
341
- form: function() {
342
- this.checkForm();
343
- $.extend(this.submitted, this.errorMap);
344
- this.invalid = $.extend({}, this.errorMap);
345
- if (!this.valid()) {
346
- $(this.currentForm).triggerHandler("invalid-form", [this]);
347
- }
348
- this.showErrors();
349
- return this.valid();
350
- },
351
-
352
- checkForm: function() {
353
- this.prepareForm();
354
- for ( var i = 0, elements = (this.currentElements = this.elements()); elements[i]; i++ ) {
355
- this.check( elements[i] );
356
- }
357
- return this.valid();
358
- },
359
-
360
- // http://docs.jquery.com/Plugins/Validation/Validator/element
361
- element: function( element ) {
362
- element = this.validationTargetFor( this.clean( element ) );
363
- this.lastElement = element;
364
- this.prepareElement( element );
365
- this.currentElements = $(element);
366
- var result = this.check( element ) !== false;
367
- if (result) {
368
- delete this.invalid[element.name];
369
- } else {
370
- this.invalid[element.name] = true;
371
- }
372
- if ( !this.numberOfInvalids() ) {
373
- // Hide error containers on last error
374
- this.toHide = this.toHide.add( this.containers );
375
- }
376
- this.showErrors();
377
- return result;
378
- },
379
-
380
- // http://docs.jquery.com/Plugins/Validation/Validator/showErrors
381
- showErrors: function(errors) {
382
- if(errors) {
383
- // add items to error list and map
384
- $.extend( this.errorMap, errors );
385
- this.errorList = [];
386
- for ( var name in errors ) {
387
- this.errorList.push({
388
- message: errors[name],
389
- element: this.findByName(name)[0]
390
- });
391
- }
392
- // remove items from success list
393
- this.successList = $.grep( this.successList, function(element) {
394
- return !(element.name in errors);
395
- });
396
- }
397
- if (this.settings.showErrors) {
398
- this.settings.showErrors.call( this, this.errorMap, this.errorList );
399
- } else {
400
- this.defaultShowErrors();
401
- }
402
- },
403
-
404
- // http://docs.jquery.com/Plugins/Validation/Validator/resetForm
405
- resetForm: function() {
406
- if ( $.fn.resetForm ) {
407
- $( this.currentForm ).resetForm();
408
- }
409
- this.submitted = {};
410
- this.lastElement = null;
411
- this.prepareForm();
412
- this.hideErrors();
413
- this.elements().removeClass( this.settings.errorClass ).removeData( "previousValue" );
414
- },
415
-
416
- numberOfInvalids: function() {
417
- return this.objectLength(this.invalid);
418
- },
419
-
420
- objectLength: function( obj ) {
421
- var count = 0;
422
- for ( var i in obj ) {
423
- count++;
424
- }
425
- return count;
426
- },
427
-
428
- hideErrors: function() {
429
- this.addWrapper( this.toHide ).hide();
430
- },
431
-
432
- valid: function() {
433
- return this.size() === 0;
434
- },
435
-
436
- size: function() {
437
- return this.errorList.length;
438
- },
439
-
440
- focusInvalid: function() {
441
- if( this.settings.focusInvalid ) {
442
- try {
443
- $(this.findLastActive() || this.errorList.length && this.errorList[0].element || [])
444
- .filter(":visible")
445
- .focus()
446
- // manually trigger focusin event; without it, focusin handler isn't called, findLastActive won't have anything to find
447
- .trigger("focusin");
448
- } catch(e) {
449
- // ignore IE throwing errors when focusing hidden elements
450
- }
451
- }
452
- },
453
-
454
- findLastActive: function() {
455
- var lastActive = this.lastActive;
456
- return lastActive && $.grep(this.errorList, function(n) {
457
- return n.element.name === lastActive.name;
458
- }).length === 1 && lastActive;
459
- },
460
-
461
- elements: function() {
462
- var validator = this,
463
- rulesCache = {};
464
-
465
- // select all valid inputs inside the form (no submit or reset buttons)
466
- return $(this.currentForm)
467
- .find("input, select, textarea")
468
- .not(":submit, :reset, :image, [disabled]")
469
- .not( this.settings.ignore )
470
- .filter(function() {
471
- if ( !this.name && validator.settings.debug && window.console ) {
472
- console.error( "%o has no name assigned", this);
473
- }
474
-
475
- // select only the first element for each name, and only those with rules specified
476
- if ( this.name in rulesCache || !validator.objectLength($(this).rules()) ) {
477
- return false;
478
- }
479
-
480
- rulesCache[this.name] = true;
481
- return true;
482
- });
483
- },
484
-
485
- clean: function( selector ) {
486
- return $( selector )[0];
487
- },
488
-
489
- errors: function() {
490
- var errorClass = this.settings.errorClass.replace(' ', '.');
491
- return $( this.settings.errorElement + "." + errorClass, this.errorContext );
492
- },
493
-
494
- reset: function() {
495
- this.successList = [];
496
- this.errorList = [];
497
- this.errorMap = {};
498
- this.toShow = $([]);
499
- this.toHide = $([]);
500
- this.currentElements = $([]);
501
- },
502
-
503
- prepareForm: function() {
504
- this.reset();
505
- this.toHide = this.errors().add( this.containers );
506
- },
507
-
508
- prepareElement: function( element ) {
509
- this.reset();
510
- this.toHide = this.errorsFor(element);
511
- },
512
-
513
- elementValue: function( element ) {
514
- var type = $(element).attr('type'),
515
- val = $(element).val();
516
-
517
- if ( type === 'radio' || type === 'checkbox' ) {
518
- return $('input[name="' + $(element).attr('name') + '"]:checked').val();
519
- }
520
-
521
- if ( typeof val === 'string' ) {
522
- return val.replace(/\r/g, "");
523
- }
524
- return val;
525
- },
526
-
527
- check: function( element ) {
528
- element = this.validationTargetFor( this.clean( element ) );
529
-
530
- var rules = $(element).rules();
531
- var dependencyMismatch = false;
532
- var val = this.elementValue(element);
533
- var result;
534
-
535
- for (var method in rules ) {
536
- var rule = { method: method, parameters: rules[method] };
537
- try {
538
-
539
- result = $.validator.methods[method].call( this, val, element, rule.parameters );
540
-
541
- // if a method indicates that the field is optional and therefore valid,
542
- // don't mark it as valid when there are no other rules
543
- if ( result === "dependency-mismatch" ) {
544
- dependencyMismatch = true;
545
- continue;
546
- }
547
- dependencyMismatch = false;
548
-
549
- if ( result === "pending" ) {
550
- this.toHide = this.toHide.not( this.errorsFor(element) );
551
- return;
552
- }
553
-
554
- if( !result ) {
555
- this.formatAndAdd( element, rule );
556
- return false;
557
- }
558
- } catch(e) {
559
- if ( this.settings.debug && window.console ) {
560
- console.log("exception occured when checking element " + element.id + ", check the '" + rule.method + "' method", e);
561
- }
562
- throw e;
563
- }
564
- }
565
- if (dependencyMismatch) {
566
- return;
567
- }
568
- if ( this.objectLength(rules) ) {
569
- this.successList.push(element);
570
- }
571
- return true;
572
- },
573
-
574
- // return the custom message for the given element and validation method
575
- // specified in the element's "messages" metadata
576
- customMetaMessage: function(element, method) {
577
- if (!$.metadata) {
578
- return;
579
- }
580
- var meta = this.settings.meta ? $(element).metadata()[this.settings.meta] : $(element).metadata();
581
- return meta && meta.messages && meta.messages[method];
582
- },
583
-
584
- // return the custom message for the given element and validation method
585
- // specified in the element's HTML5 data attribute
586
- customDataMessage: function(element, method) {
587
- return $(element).data('msg-' + method.toLowerCase()) || (element.attributes && $(element).attr('data-msg-' + method.toLowerCase()));
588
- },
589
-
590
- // return the custom message for the given element name and validation method
591
- customMessage: function( name, method ) {
592
- var m = this.settings.messages[name];
593
- return m && (m.constructor === String ? m : m[method]);
594
- },
595
-
596
- // return the first defined argument, allowing empty strings
597
- findDefined: function() {
598
- for(var i = 0; i < arguments.length; i++) {
599
- if (arguments[i] !== undefined) {
600
- return arguments[i];
601
- }
602
- }
603
- return undefined;
604
- },
605
-
606
- defaultMessage: function( element, method) {
607
- return this.findDefined(
608
- this.customMessage( element.name, method ),
609
- this.customDataMessage( element, method ),
610
- this.customMetaMessage( element, method ),
611
- // title is never undefined, so handle empty string as undefined
612
- !this.settings.ignoreTitle && element.title || undefined,
613
- $.validator.messages[method],
614
- "<strong>Warning: No message defined for " + element.name + "</strong>"
615
- );
616
- },
617
-
618
- formatAndAdd: function( element, rule ) {
619
- var message = this.defaultMessage( element, rule.method ),
620
- theregex = /\$?\{(\d+)\}/g;
621
- if ( typeof message === "function" ) {
622
- message = message.call(this, rule.parameters, element);
623
- } else if (theregex.test(message)) {
624
- message = $.validator.format(message.replace(theregex, '{$1}'), rule.parameters);
625
- }
626
- this.errorList.push({
627
- message: message,
628
- element: element
629
- });
630
-
631
- this.errorMap[element.name] = message;
632
- this.submitted[element.name] = message;
633
- },
634
-
635
- addWrapper: function(toToggle) {
636
- if ( this.settings.wrapper ) {
637
- toToggle = toToggle.add( toToggle.parent( this.settings.wrapper ) );
638
- }
639
- return toToggle;
640
- },
641
-
642
- defaultShowErrors: function() {
643
- var i, elements;
644
- for ( i = 0; this.errorList[i]; i++ ) {
645
- var error = this.errorList[i];
646
- if ( this.settings.highlight ) {
647
- this.settings.highlight.call( this, error.element, this.settings.errorClass, this.settings.validClass );
648
- }
649
- this.showLabel( error.element, error.message );
650
- }
651
- if( this.errorList.length ) {
652
- this.toShow = this.toShow.add( this.containers );
653
- }
654
- if (this.settings.success) {
655
- for ( i = 0; this.successList[i]; i++ ) {
656
- this.showLabel( this.successList[i] );
657
- }
658
- }
659
- if (this.settings.unhighlight) {
660
- for ( i = 0, elements = this.validElements(); elements[i]; i++ ) {
661
- this.settings.unhighlight.call( this, elements[i], this.settings.errorClass, this.settings.validClass );
662
- }
663
- }
664
- this.toHide = this.toHide.not( this.toShow );
665
- this.hideErrors();
666
- this.addWrapper( this.toShow ).show();
667
- },
668
-
669
- validElements: function() {
670
- return this.currentElements.not(this.invalidElements());
671
- },
672
-
673
- invalidElements: function() {
674
- return $(this.errorList).map(function() {
675
- return this.element;
676
- });
677
- },
678
-
679
- showLabel: function(element, message) {
680
- var label = this.errorsFor( element );
681
- if ( label.length ) {
682
- // refresh error/success class
683
- label.removeClass( this.settings.validClass ).addClass( this.settings.errorClass );
684
-
685
- // check if we have a generated label, replace the message then
686
- if ( label.attr("generated") ) {
687
- label.html(message);
688
- }
689
- } else {
690
- // create label
691
- label = $("<" + this.settings.errorElement + "/>")
692
- .attr({"for": this.idOrName(element), generated: true})
693
- .addClass(this.settings.errorClass)
694
- .html(message || "");
695
- if ( this.settings.wrapper ) {
696
- // make sure the element is visible, even in IE
697
- // actually showing the wrapped element is handled elsewhere
698
- label = label.hide().show().wrap("<" + this.settings.wrapper + "/>").parent();
699
- }
700
- if ( !this.labelContainer.append(label).length ) {
701
- if ( this.settings.errorPlacement ) {
702
- this.settings.errorPlacement(label, $(element) );
703
- } else {
704
- label.insertAfter(element);
705
- }
706
- }
707
- }
708
- if ( !message && this.settings.success ) {
709
- label.text("");
710
- if ( typeof this.settings.success === "string" ) {
711
- label.addClass( this.settings.success );
712
- } else {
713
- this.settings.success( label, element );
714
- }
715
- }
716
- this.toShow = this.toShow.add(label);
717
- },
718
-
719
- errorsFor: function(element) {
720
- var name = this.idOrName(element);
721
- return this.errors().filter(function() {
722
- return $(this).attr('for') === name;
723
- });
724
- },
725
-
726
- idOrName: function(element) {
727
- return this.groups[element.name] || (this.checkable(element) ? element.name : element.id || element.name);
728
- },
729
-
730
- validationTargetFor: function(element) {
731
- // if radio/checkbox, validate first element in group instead
732
- if (this.checkable(element)) {
733
- element = this.findByName( element.name ).not(this.settings.ignore)[0];
734
- }
735
- return element;
736
- },
737
-
738
- checkable: function( element ) {
739
- return (/radio|checkbox/i).test(element.type);
740
- },
741
-
742
- findByName: function( name ) {
743
- return $(this.currentForm).find('[name="' + name + '"]');
744
- },
745
-
746
- getLength: function(value, element) {
747
- switch( element.nodeName.toLowerCase() ) {
748
- case 'select':
749
- return $("option:selected", element).length;
750
- case 'input':
751
- if( this.checkable( element) ) {
752
- return this.findByName(element.name).filter(':checked').length;
753
- }
754
- }
755
- return value.length;
756
- },
757
-
758
- depend: function(param, element) {
759
- return this.dependTypes[typeof param] ? this.dependTypes[typeof param](param, element) : true;
760
- },
761
-
762
- dependTypes: {
763
- "boolean": function(param, element) {
764
- return param;
765
- },
766
- "string": function(param, element) {
767
- return !!$(param, element.form).length;
768
- },
769
- "function": function(param, element) {
770
- return param(element);
771
- }
772
- },
773
-
774
- optional: function(element) {
775
- var val = this.elementValue(element);
776
- return !$.validator.methods.required.call(this, val, element) && "dependency-mismatch";
777
- },
778
-
779
- startRequest: function(element) {
780
- if (!this.pending[element.name]) {
781
- this.pendingRequest++;
782
- this.pending[element.name] = true;
783
- }
784
- },
785
-
786
- stopRequest: function(element, valid) {
787
- this.pendingRequest--;
788
- // sometimes synchronization fails, make sure pendingRequest is never < 0
789
- if (this.pendingRequest < 0) {
790
- this.pendingRequest = 0;
791
- }
792
- delete this.pending[element.name];
793
- if ( valid && this.pendingRequest === 0 && this.formSubmitted && this.form() ) {
794
- $(this.currentForm).submit();
795
- this.formSubmitted = false;
796
- } else if (!valid && this.pendingRequest === 0 && this.formSubmitted) {
797
- $(this.currentForm).triggerHandler("invalid-form", [this]);
798
- this.formSubmitted = false;
799
- }
800
- },
801
-
802
- previousValue: function(element) {
803
- return $.data(element, "previousValue") || $.data(element, "previousValue", {
804
- old: null,
805
- valid: true,
806
- message: this.defaultMessage( element, "remote" )
807
- });
808
- }
809
-
810
- },
811
-
812
- classRuleSettings: {
813
- required: {required: true},
814
- email: {email: true},
815
- url: {url: true},
816
- date: {date: true},
817
- dateISO: {dateISO: true},
818
- number: {number: true},
819
- digits: {digits: true},
820
- creditcard: {creditcard: true}
821
- },
822
-
823
- addClassRules: function(className, rules) {
824
- if ( className.constructor === String ) {
825
- this.classRuleSettings[className] = rules;
826
- } else {
827
- $.extend(this.classRuleSettings, className);
828
- }
829
- },
830
-
831
- classRules: function(element) {
832
- var rules = {};
833
- var classes = $(element).attr('class');
834
- if ( classes ) {
835
- $.each(classes.split(' '), function() {
836
- if (this in $.validator.classRuleSettings) {
837
- $.extend(rules, $.validator.classRuleSettings[this]);
838
- }
839
- });
840
- }
841
- return rules;
842
- },
843
-
844
- attributeRules: function(element) {
845
- var rules = {};
846
- var $element = $(element);
847
-
848
- for (var method in $.validator.methods) {
849
- var value;
850
-
851
- // support for <input required> in both html5 and older browsers
852
- if (method === 'required') {
853
- value = $element.get(0).getAttribute(method);
854
- // Some browsers return an empty string for the required attribute
855
- // and non-HTML5 browsers might have required="" markup
856
- if (value === "") {
857
- value = true;
858
- }
859
- // force non-HTML5 browsers to return bool
860
- value = !!value;
861
- } else {
862
- value = $element.attr(method);
863
- }
864
-
865
- if (value) {
866
- rules[method] = value;
867
- } else if ($element[0].getAttribute("type") === method) {
868
- rules[method] = true;
869
- }
870
- }
871
-
872
- // maxlength may be returned as -1, 2147483647 (IE) and 524288 (safari) for text inputs
873
- if (rules.maxlength && /-1|2147483647|524288/.test(rules.maxlength)) {
874
- delete rules.maxlength;
875
- }
876
-
877
- return rules;
878
- },
879
-
880
- metadataRules: function(element) {
881
- if (!$.metadata) {
882
- return {};
883
- }
884
-
885
- var meta = $.data(element.form, 'validator').settings.meta;
886
- return meta ?
887
- $(element).metadata()[meta] :
888
- $(element).metadata();
889
- },
890
-
891
- staticRules: function(element) {
892
- var rules = {};
893
- var validator = $.data(element.form, 'validator');
894
- if (validator.settings.rules) {
895
- rules = $.validator.normalizeRule(validator.settings.rules[element.name]) || {};
896
- }
897
- return rules;
898
- },
899
-
900
- normalizeRules: function(rules, element) {
901
- // handle dependency check
902
- $.each(rules, function(prop, val) {
903
- // ignore rule when param is explicitly false, eg. required:false
904
- if (val === false) {
905
- delete rules[prop];
906
- return;
907
- }
908
- if (val.param || val.depends) {
909
- var keepRule = true;
910
- switch (typeof val.depends) {
911
- case "string":
912
- keepRule = !!$(val.depends, element.form).length;
913
- break;
914
- case "function":
915
- keepRule = val.depends.call(element, element);
916
- break;
917
- }
918
- if (keepRule) {
919
- rules[prop] = val.param !== undefined ? val.param : true;
920
- } else {
921
- delete rules[prop];
922
- }
923
- }
924
- });
925
-
926
- // evaluate parameters
927
- $.each(rules, function(rule, parameter) {
928
- rules[rule] = $.isFunction(parameter) ? parameter(element) : parameter;
929
- });
930
-
931
- // clean number parameters
932
- $.each(['minlength', 'maxlength', 'min', 'max'], function() {
933
- if (rules[this]) {
934
- rules[this] = Number(rules[this]);
935
- }
936
- });
937
- $.each(['rangelength', 'range'], function() {
938
- if (rules[this]) {
939
- rules[this] = [Number(rules[this][0]), Number(rules[this][1])];
940
- }
941
- });
942
-
943
- if ($.validator.autoCreateRanges) {
944
- // auto-create ranges
945
- if (rules.min && rules.max) {
946
- rules.range = [rules.min, rules.max];
947
- delete rules.min;
948
- delete rules.max;
949
- }
950
- if (rules.minlength && rules.maxlength) {
951
- rules.rangelength = [rules.minlength, rules.maxlength];
952
- delete rules.minlength;
953
- delete rules.maxlength;
954
- }
955
- }
956
-
957
- // To support custom messages in metadata ignore rule methods titled "messages"
958
- if (rules.messages) {
959
- delete rules.messages;
960
- }
961
-
962
- return rules;
963
- },
964
-
965
- // Converts a simple string to a {string: true} rule, e.g., "required" to {required:true}
966
- normalizeRule: function(data) {
967
- if( typeof data === "string" ) {
968
- var transformed = {};
969
- $.each(data.split(/\s/), function() {
970
- transformed[this] = true;
971
- });
972
- data = transformed;
973
- }
974
- return data;
975
- },
976
-
977
- // http://docs.jquery.com/Plugins/Validation/Validator/addMethod
978
- addMethod: function(name, method, message) {
979
- $.validator.methods[name] = method;
980
- $.validator.messages[name] = message !== undefined ? message : $.validator.messages[name];
981
- if (method.length < 3) {
982
- $.validator.addClassRules(name, $.validator.normalizeRule(name));
983
- }
984
- },
985
-
986
- methods: {
987
-
988
- // http://docs.jquery.com/Plugins/Validation/Methods/required
989
- required: function(value, element, param) {
990
- // check if dependency is met
991
- if ( !this.depend(param, element) ) {
992
- return "dependency-mismatch";
993
- }
994
- if ( element.nodeName.toLowerCase() === "select" ) {
995
- // could be an array for select-multiple or a string, both are fine this way
996
- var val = $(element).val();
997
- return val && val.length > 0;
998
- }
999
- if ( this.checkable(element) ) {
1000
- return this.getLength(value, element) > 0;
1001
- }
1002
- return $.trim(value).length > 0;
1003
- },
1004
-
1005
- // http://docs.jquery.com/Plugins/Validation/Methods/remote
1006
- remote: function(value, element, param) {
1007
- if ( this.optional(element) ) {
1008
- return "dependency-mismatch";
1009
- }
1010
-
1011
- var previous = this.previousValue(element);
1012
- if (!this.settings.messages[element.name] ) {
1013
- this.settings.messages[element.name] = {};
1014
- }
1015
- previous.originalMessage = this.settings.messages[element.name].remote;
1016
- this.settings.messages[element.name].remote = previous.message;
1017
-
1018
- param = typeof param === "string" && {url:param} || param;
1019
-
1020
- if ( this.pending[element.name] ) {
1021
- return "pending";
1022
- }
1023
- if ( previous.old === value ) {
1024
- return previous.valid;
1025
- }
1026
-
1027
- previous.old = value;
1028
- var validator = this;
1029
- this.startRequest(element);
1030
- var data = {};
1031
- data[element.name] = value;
1032
- $.ajax($.extend(true, {
1033
- url: param,
1034
- mode: "abort",
1035
- port: "validate" + element.name,
1036
- dataType: "json",
1037
- data: data,
1038
- success: function(response) {
1039
- validator.settings.messages[element.name].remote = previous.originalMessage;
1040
- var valid = response === true || response === "true";
1041
- if ( valid ) {
1042
- var submitted = validator.formSubmitted;
1043
- validator.prepareElement(element);
1044
- validator.formSubmitted = submitted;
1045
- validator.successList.push(element);
1046
- delete validator.invalid[element.name];
1047
- validator.showErrors();
1048
- } else {
1049
- var errors = {};
1050
- var message = response || validator.defaultMessage( element, "remote" );
1051
- errors[element.name] = previous.message = $.isFunction(message) ? message(value) : message;
1052
- validator.invalid[element.name] = true;
1053
- validator.showErrors(errors);
1054
- }
1055
- previous.valid = valid;
1056
- validator.stopRequest(element, valid);
1057
- }
1058
- }, param));
1059
- return "pending";
1060
- },
1061
-
1062
- // http://docs.jquery.com/Plugins/Validation/Methods/minlength
1063
- minlength: function(value, element, param) {
1064
- var length = $.isArray( value ) ? value.length : this.getLength($.trim(value), element);
1065
- return this.optional(element) || length >= param;
1066
- },
1067
-
1068
- // http://docs.jquery.com/Plugins/Validation/Methods/maxlength
1069
- maxlength: function(value, element, param) {
1070
- var length = $.isArray( value ) ? value.length : this.getLength($.trim(value), element);
1071
- return this.optional(element) || length <= param;
1072
- },
1073
-
1074
- // http://docs.jquery.com/Plugins/Validation/Methods/rangelength
1075
- rangelength: function(value, element, param) {
1076
- var length = $.isArray( value ) ? value.length : this.getLength($.trim(value), element);
1077
- return this.optional(element) || ( length >= param[0] && length <= param[1] );
1078
- },
1079
-
1080
- // http://docs.jquery.com/Plugins/Validation/Methods/min
1081
- min: function( value, element, param ) {
1082
- return this.optional(element) || value >= param;
1083
- },
1084
-
1085
- // http://docs.jquery.com/Plugins/Validation/Methods/max
1086
- max: function( value, element, param ) {
1087
- return this.optional(element) || value <= param;
1088
- },
1089
-
1090
- // http://docs.jquery.com/Plugins/Validation/Methods/range
1091
- range: function( value, element, param ) {
1092
- return this.optional(element) || ( value >= param[0] && value <= param[1] );
1093
- },
1094
-
1095
- // http://docs.jquery.com/Plugins/Validation/Methods/email
1096
- email: function(value, element) {
1097
- // contributed by Scott Gonzalez: http://projects.scottsplayground.com/email_address_validation/
1098
- return this.optional(element) || /^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([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])))$/i.test(value);
1099
- },
1100
-
1101
- // http://docs.jquery.com/Plugins/Validation/Methods/url
1102
- url: function(value, element) {
1103
- // contributed by Scott Gonzalez: http://projects.scottsplayground.com/iri/
1104
- return this.optional(element) || /^(https?|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);
1105
- },
1106
-
1107
- // http://docs.jquery.com/Plugins/Validation/Methods/date
1108
- date: function(value, element) {
1109
- return this.optional(element) || !/Invalid|NaN/.test(new Date(value));
1110
- },
1111
-
1112
- // http://docs.jquery.com/Plugins/Validation/Methods/dateISO
1113
- dateISO: function(value, element) {
1114
- return this.optional(element) || /^\d{4}[\/\-]\d{1,2}[\/\-]\d{1,2}$/.test(value);
1115
- },
1116
-
1117
- // http://docs.jquery.com/Plugins/Validation/Methods/number
1118
- number: function(value, element) {
1119
- return this.optional(element) || /^-?(?:\d+|\d{1,3}(?:,\d{3})+)?(?:\.\d+)?$/.test(value);
1120
- },
1121
-
1122
- // http://docs.jquery.com/Plugins/Validation/Methods/digits
1123
- digits: function(value, element) {
1124
- return this.optional(element) || /^\d+$/.test(value);
1125
- },
1126
-
1127
- // http://docs.jquery.com/Plugins/Validation/Methods/creditcard
1128
- // based on http://en.wikipedia.org/wiki/Luhn
1129
- creditcard: function(value, element) {
1130
- if ( this.optional(element) ) {
1131
- return "dependency-mismatch";
1132
- }
1133
- // accept only spaces, digits and dashes
1134
- if (/[^0-9 \-]+/.test(value)) {
1135
- return false;
1136
- }
1137
- var nCheck = 0,
1138
- nDigit = 0,
1139
- bEven = false;
1140
-
1141
- value = value.replace(/\D/g, "");
1142
-
1143
- for (var n = value.length - 1; n >= 0; n--) {
1144
- var cDigit = value.charAt(n);
1145
- nDigit = parseInt(cDigit, 10);
1146
- if (bEven) {
1147
- if ((nDigit *= 2) > 9) {
1148
- nDigit -= 9;
1149
- }
1150
- }
1151
- nCheck += nDigit;
1152
- bEven = !bEven;
1153
- }
1154
-
1155
- return (nCheck % 10) === 0;
1156
- },
1157
-
1158
- // http://docs.jquery.com/Plugins/Validation/Methods/equalTo
1159
- equalTo: function(value, element, param) {
1160
- // bind to the blur event of the target in order to revalidate whenever the target field is updated
1161
- // TODO find a way to bind the event just once, avoiding the unbind-rebind overhead
1162
- var target = $(param);
1163
- if (this.settings.onfocusout) {
1164
- target.unbind(".validate-equalTo").bind("blur.validate-equalTo", function() {
1165
- $(element).valid();
1166
- });
1167
- }
1168
- return value === target.val();
1169
- }
1170
-
1171
- }
200
+ defaults: {
201
+ messages: {},
202
+ groups: {},
203
+ rules: {},
204
+ errorClass: "error",
205
+ validClass: "valid",
206
+ errorElement: "label",
207
+ focusInvalid: true,
208
+ errorContainer: $([]),
209
+ errorLabelContainer: $([]),
210
+ onsubmit: true,
211
+ ignore: ":hidden",
212
+ ignoreTitle: false,
213
+ onfocusin: function( element, event ) {
214
+ this.lastActive = element;
215
+
216
+ // hide error label and remove error class on focus if enabled
217
+ if ( this.settings.focusCleanup && !this.blockFocusCleanup ) {
218
+ if ( this.settings.unhighlight ) {
219
+ this.settings.unhighlight.call( this, element, this.settings.errorClass, this.settings.validClass );
220
+ }
221
+ this.addWrapper(this.errorsFor(element)).hide();
222
+ }
223
+ },
224
+ onfocusout: function( element, event ) {
225
+ if ( !this.checkable(element) && (element.name in this.submitted || !this.optional(element)) ) {
226
+ this.element(element);
227
+ }
228
+ },
229
+ onkeyup: function( element, event ) {
230
+ if ( event.which === 9 && this.elementValue(element) === "" ) {
231
+ return;
232
+ } else if ( element.name in this.submitted || element === this.lastElement ) {
233
+ this.element(element);
234
+ }
235
+ },
236
+ onclick: function( element, event ) {
237
+ // click on selects, radiobuttons and checkboxes
238
+ if ( element.name in this.submitted ) {
239
+ this.element(element);
240
+ }
241
+ // or option elements, check parent select in that case
242
+ else if ( element.parentNode.name in this.submitted ) {
243
+ this.element(element.parentNode);
244
+ }
245
+ },
246
+ highlight: function( element, errorClass, validClass ) {
247
+ if ( element.type === "radio" ) {
248
+ this.findByName(element.name).addClass(errorClass).removeClass(validClass);
249
+ } else {
250
+ $(element).addClass(errorClass).removeClass(validClass);
251
+ }
252
+ },
253
+ unhighlight: function( element, errorClass, validClass ) {
254
+ if ( element.type === "radio" ) {
255
+ this.findByName(element.name).removeClass(errorClass).addClass(validClass);
256
+ } else {
257
+ $(element).removeClass(errorClass).addClass(validClass);
258
+ }
259
+ }
260
+ },
261
+
262
+ // http://docs.jquery.com/Plugins/Validation/Validator/setDefaults
263
+ setDefaults: function( settings ) {
264
+ $.extend( $.validator.defaults, settings );
265
+ },
266
+
267
+ messages: {
268
+ required: "This field is required.",
269
+ remote: "Please fix this field.",
270
+ email: "Please enter a valid email address.",
271
+ url: "Please enter a valid URL.",
272
+ date: "Please enter a valid date.",
273
+ dateISO: "Please enter a valid date (ISO).",
274
+ number: "Please enter a valid number.",
275
+ digits: "Please enter only digits.",
276
+ creditcard: "Please enter a valid credit card number.",
277
+ equalTo: "Please enter the same value again.",
278
+ maxlength: $.validator.format("Please enter no more than {0} characters."),
279
+ minlength: $.validator.format("Please enter at least {0} characters."),
280
+ rangelength: $.validator.format("Please enter a value between {0} and {1} characters long."),
281
+ range: $.validator.format("Please enter a value between {0} and {1}."),
282
+ max: $.validator.format("Please enter a value less than or equal to {0}."),
283
+ min: $.validator.format("Please enter a value greater than or equal to {0}.")
284
+ },
285
+
286
+ autoCreateRanges: false,
287
+
288
+ prototype: {
289
+
290
+ init: function() {
291
+ this.labelContainer = $(this.settings.errorLabelContainer);
292
+ this.errorContext = this.labelContainer.length && this.labelContainer || $(this.currentForm);
293
+ this.containers = $(this.settings.errorContainer).add( this.settings.errorLabelContainer );
294
+ this.submitted = {};
295
+ this.valueCache = {};
296
+ this.pendingRequest = 0;
297
+ this.pending = {};
298
+ this.invalid = {};
299
+ this.reset();
300
+
301
+ var groups = (this.groups = {});
302
+ $.each(this.settings.groups, function( key, value ) {
303
+ if ( typeof value === "string" ) {
304
+ value = value.split(/\s/);
305
+ }
306
+ $.each(value, function( index, name ) {
307
+ groups[name] = key;
308
+ });
309
+ });
310
+ var rules = this.settings.rules;
311
+ $.each(rules, function( key, value ) {
312
+ rules[key] = $.validator.normalizeRule(value);
313
+ });
314
+
315
+ function delegate(event) {
316
+ var validator = $.data(this[0].form, "validator"),
317
+ eventType = "on" + event.type.replace(/^validate/, "");
318
+ if ( validator.settings[eventType] ) {
319
+ validator.settings[eventType].call(validator, this[0], event);
320
+ }
321
+ }
322
+ $(this.currentForm)
323
+ .validateDelegate(":text, [type='password'], [type='file'], select, textarea, " +
324
+ "[type='number'], [type='search'] ,[type='tel'], [type='url'], " +
325
+ "[type='email'], [type='datetime'], [type='date'], [type='month'], " +
326
+ "[type='week'], [type='time'], [type='datetime-local'], " +
327
+ "[type='range'], [type='color'] ",
328
+ "focusin focusout keyup", delegate)
329
+ .validateDelegate("[type='radio'], [type='checkbox'], select, option", "click", delegate);
330
+
331
+ if ( this.settings.invalidHandler ) {
332
+ $(this.currentForm).bind("invalid-form.validate", this.settings.invalidHandler);
333
+ }
334
+ },
335
+
336
+ // http://docs.jquery.com/Plugins/Validation/Validator/form
337
+ form: function() {
338
+ this.checkForm();
339
+ $.extend(this.submitted, this.errorMap);
340
+ this.invalid = $.extend({}, this.errorMap);
341
+ if ( !this.valid() ) {
342
+ $(this.currentForm).triggerHandler("invalid-form", [this]);
343
+ }
344
+ this.showErrors();
345
+ return this.valid();
346
+ },
347
+
348
+ checkForm: function() {
349
+ this.prepareForm();
350
+ for ( var i = 0, elements = (this.currentElements = this.elements()); elements[i]; i++ ) {
351
+ this.check( elements[i] );
352
+ }
353
+ return this.valid();
354
+ },
355
+
356
+ // http://docs.jquery.com/Plugins/Validation/Validator/element
357
+ element: function( element ) {
358
+ element = this.validationTargetFor( this.clean( element ) );
359
+ this.lastElement = element;
360
+ this.prepareElement( element );
361
+ this.currentElements = $(element);
362
+ var result = this.check( element ) !== false;
363
+ if ( result ) {
364
+ delete this.invalid[element.name];
365
+ } else {
366
+ this.invalid[element.name] = true;
367
+ }
368
+ if ( !this.numberOfInvalids() ) {
369
+ // Hide error containers on last error
370
+ this.toHide = this.toHide.add( this.containers );
371
+ }
372
+ this.showErrors();
373
+ return result;
374
+ },
375
+
376
+ // http://docs.jquery.com/Plugins/Validation/Validator/showErrors
377
+ showErrors: function( errors ) {
378
+ if ( errors ) {
379
+ // add items to error list and map
380
+ $.extend( this.errorMap, errors );
381
+ this.errorList = [];
382
+ for ( var name in errors ) {
383
+ this.errorList.push({
384
+ message: errors[name],
385
+ element: this.findByName(name)[0]
386
+ });
387
+ }
388
+ // remove items from success list
389
+ this.successList = $.grep( this.successList, function( element ) {
390
+ return !(element.name in errors);
391
+ });
392
+ }
393
+ if ( this.settings.showErrors ) {
394
+ this.settings.showErrors.call( this, this.errorMap, this.errorList );
395
+ } else {
396
+ this.defaultShowErrors();
397
+ }
398
+ },
399
+
400
+ // http://docs.jquery.com/Plugins/Validation/Validator/resetForm
401
+ resetForm: function() {
402
+ if ( $.fn.resetForm ) {
403
+ $(this.currentForm).resetForm();
404
+ }
405
+ this.submitted = {};
406
+ this.lastElement = null;
407
+ this.prepareForm();
408
+ this.hideErrors();
409
+ this.elements().removeClass( this.settings.errorClass ).removeData( "previousValue" );
410
+ },
411
+
412
+ numberOfInvalids: function() {
413
+ return this.objectLength(this.invalid);
414
+ },
415
+
416
+ objectLength: function( obj ) {
417
+ var count = 0;
418
+ for ( var i in obj ) {
419
+ count++;
420
+ }
421
+ return count;
422
+ },
423
+
424
+ hideErrors: function() {
425
+ this.addWrapper( this.toHide ).hide();
426
+ },
427
+
428
+ valid: function() {
429
+ return this.size() === 0;
430
+ },
431
+
432
+ size: function() {
433
+ return this.errorList.length;
434
+ },
435
+
436
+ focusInvalid: function() {
437
+ if ( this.settings.focusInvalid ) {
438
+ try {
439
+ $(this.findLastActive() || this.errorList.length && this.errorList[0].element || [])
440
+ .filter(":visible")
441
+ .focus()
442
+ // manually trigger focusin event; without it, focusin handler isn't called, findLastActive won't have anything to find
443
+ .trigger("focusin");
444
+ } catch(e) {
445
+ // ignore IE throwing errors when focusing hidden elements
446
+ }
447
+ }
448
+ },
449
+
450
+ findLastActive: function() {
451
+ var lastActive = this.lastActive;
452
+ return lastActive && $.grep(this.errorList, function( n ) {
453
+ return n.element.name === lastActive.name;
454
+ }).length === 1 && lastActive;
455
+ },
456
+
457
+ elements: function() {
458
+ var validator = this,
459
+ rulesCache = {};
460
+
461
+ // select all valid inputs inside the form (no submit or reset buttons)
462
+ return $(this.currentForm)
463
+ .find("input, select, textarea")
464
+ .not(":submit, :reset, :image, [disabled]")
465
+ .not( this.settings.ignore )
466
+ .filter(function() {
467
+ if ( !this.name && validator.settings.debug && window.console ) {
468
+ console.error( "%o has no name assigned", this);
469
+ }
470
+
471
+ // select only the first element for each name, and only those with rules specified
472
+ if ( this.name in rulesCache || !validator.objectLength($(this).rules()) ) {
473
+ return false;
474
+ }
475
+
476
+ rulesCache[this.name] = true;
477
+ return true;
478
+ });
479
+ },
480
+
481
+ clean: function( selector ) {
482
+ return $(selector)[0];
483
+ },
484
+
485
+ errors: function() {
486
+ var errorClass = this.settings.errorClass.replace(" ", ".");
487
+ return $(this.settings.errorElement + "." + errorClass, this.errorContext);
488
+ },
489
+
490
+ reset: function() {
491
+ this.successList = [];
492
+ this.errorList = [];
493
+ this.errorMap = {};
494
+ this.toShow = $([]);
495
+ this.toHide = $([]);
496
+ this.currentElements = $([]);
497
+ },
498
+
499
+ prepareForm: function() {
500
+ this.reset();
501
+ this.toHide = this.errors().add( this.containers );
502
+ },
503
+
504
+ prepareElement: function( element ) {
505
+ this.reset();
506
+ this.toHide = this.errorsFor(element);
507
+ },
508
+
509
+ elementValue: function( element ) {
510
+ var type = $(element).attr("type"),
511
+ val = $(element).val();
512
+
513
+ if ( type === "radio" || type === "checkbox" ) {
514
+ return $("input[name='" + $(element).attr("name") + "']:checked").val();
515
+ }
516
+
517
+ if ( typeof val === "string" ) {
518
+ return val.replace(/\r/g, "");
519
+ }
520
+ return val;
521
+ },
522
+
523
+ check: function( element ) {
524
+ element = this.validationTargetFor( this.clean( element ) );
525
+
526
+ var rules = $(element).rules();
527
+ var dependencyMismatch = false;
528
+ var val = this.elementValue(element);
529
+ var result;
530
+
531
+ for (var method in rules ) {
532
+ var rule = { method: method, parameters: rules[method] };
533
+ try {
534
+
535
+ result = $.validator.methods[method].call( this, val, element, rule.parameters );
536
+
537
+ // if a method indicates that the field is optional and therefore valid,
538
+ // don't mark it as valid when there are no other rules
539
+ if ( result === "dependency-mismatch" ) {
540
+ dependencyMismatch = true;
541
+ continue;
542
+ }
543
+ dependencyMismatch = false;
544
+
545
+ if ( result === "pending" ) {
546
+ this.toHide = this.toHide.not( this.errorsFor(element) );
547
+ return;
548
+ }
549
+
550
+ if ( !result ) {
551
+ this.formatAndAdd( element, rule );
552
+ return false;
553
+ }
554
+ } catch(e) {
555
+ if ( this.settings.debug && window.console ) {
556
+ console.log( "Exception occured when checking element " + element.id + ", check the '" + rule.method + "' method.", e );
557
+ }
558
+ throw e;
559
+ }
560
+ }
561
+ if ( dependencyMismatch ) {
562
+ return;
563
+ }
564
+ if ( this.objectLength(rules) ) {
565
+ this.successList.push(element);
566
+ }
567
+ return true;
568
+ },
569
+
570
+ // return the custom message for the given element and validation method
571
+ // specified in the element's HTML5 data attribute
572
+ customDataMessage: function( element, method ) {
573
+ return $(element).data("msg-" + method.toLowerCase()) || (element.attributes && $(element).attr("data-msg-" + method.toLowerCase()));
574
+ },
575
+
576
+ // return the custom message for the given element name and validation method
577
+ customMessage: function( name, method ) {
578
+ var m = this.settings.messages[name];
579
+ return m && (m.constructor === String ? m : m[method]);
580
+ },
581
+
582
+ // return the first defined argument, allowing empty strings
583
+ findDefined: function() {
584
+ for(var i = 0; i < arguments.length; i++) {
585
+ if ( arguments[i] !== undefined ) {
586
+ return arguments[i];
587
+ }
588
+ }
589
+ return undefined;
590
+ },
591
+
592
+ defaultMessage: function( element, method ) {
593
+ return this.findDefined(
594
+ this.customMessage( element.name, method ),
595
+ this.customDataMessage( element, method ),
596
+ // title is never undefined, so handle empty string as undefined
597
+ !this.settings.ignoreTitle && element.title || undefined,
598
+ $.validator.messages[method],
599
+ "<strong>Warning: No message defined for " + element.name + "</strong>"
600
+ );
601
+ },
602
+
603
+ formatAndAdd: function( element, rule ) {
604
+ var message = this.defaultMessage( element, rule.method ),
605
+ theregex = /\$?\{(\d+)\}/g;
606
+ if ( typeof message === "function" ) {
607
+ message = message.call(this, rule.parameters, element);
608
+ } else if (theregex.test(message)) {
609
+ message = $.validator.format(message.replace(theregex, "{$1}"), rule.parameters);
610
+ }
611
+ this.errorList.push({
612
+ message: message,
613
+ element: element
614
+ });
615
+
616
+ this.errorMap[element.name] = message;
617
+ this.submitted[element.name] = message;
618
+ },
619
+
620
+ addWrapper: function( toToggle ) {
621
+ if ( this.settings.wrapper ) {
622
+ toToggle = toToggle.add( toToggle.parent( this.settings.wrapper ) );
623
+ }
624
+ return toToggle;
625
+ },
626
+
627
+ defaultShowErrors: function() {
628
+ var i, elements;
629
+ for ( i = 0; this.errorList[i]; i++ ) {
630
+ var error = this.errorList[i];
631
+ if ( this.settings.highlight ) {
632
+ this.settings.highlight.call( this, error.element, this.settings.errorClass, this.settings.validClass );
633
+ }
634
+ this.showLabel( error.element, error.message );
635
+ }
636
+ if ( this.errorList.length ) {
637
+ this.toShow = this.toShow.add( this.containers );
638
+ }
639
+ if ( this.settings.success ) {
640
+ for ( i = 0; this.successList[i]; i++ ) {
641
+ this.showLabel( this.successList[i] );
642
+ }
643
+ }
644
+ if ( this.settings.unhighlight ) {
645
+ for ( i = 0, elements = this.validElements(); elements[i]; i++ ) {
646
+ this.settings.unhighlight.call( this, elements[i], this.settings.errorClass, this.settings.validClass );
647
+ }
648
+ }
649
+ this.toHide = this.toHide.not( this.toShow );
650
+ this.hideErrors();
651
+ this.addWrapper( this.toShow ).show();
652
+ },
653
+
654
+ validElements: function() {
655
+ return this.currentElements.not(this.invalidElements());
656
+ },
657
+
658
+ invalidElements: function() {
659
+ return $(this.errorList).map(function() {
660
+ return this.element;
661
+ });
662
+ },
663
+
664
+ showLabel: function( element, message ) {
665
+ var label = this.errorsFor( element );
666
+ if ( label.length ) {
667
+ // refresh error/success class
668
+ label.removeClass( this.settings.validClass ).addClass( this.settings.errorClass );
669
+ // replace message on existing label
670
+ label.html(message);
671
+ } else {
672
+ // create label
673
+ label = $("<" + this.settings.errorElement + ">")
674
+ .attr("for", this.idOrName(element))
675
+ .addClass(this.settings.errorClass)
676
+ .html(message || "");
677
+ if ( this.settings.wrapper ) {
678
+ // make sure the element is visible, even in IE
679
+ // actually showing the wrapped element is handled elsewhere
680
+ label = label.hide().show().wrap("<" + this.settings.wrapper + "/>").parent();
681
+ }
682
+ if ( !this.labelContainer.append(label).length ) {
683
+ if ( this.settings.errorPlacement ) {
684
+ this.settings.errorPlacement(label, $(element) );
685
+ } else {
686
+ label.insertAfter(element);
687
+ }
688
+ }
689
+ }
690
+ if ( !message && this.settings.success ) {
691
+ label.text("");
692
+ if ( typeof this.settings.success === "string" ) {
693
+ label.addClass( this.settings.success );
694
+ } else {
695
+ this.settings.success( label, element );
696
+ }
697
+ }
698
+ this.toShow = this.toShow.add(label);
699
+ },
700
+
701
+ errorsFor: function( element ) {
702
+ var name = this.idOrName(element);
703
+ return this.errors().filter(function() {
704
+ return $(this).attr("for") === name;
705
+ });
706
+ },
707
+
708
+ idOrName: function( element ) {
709
+ return this.groups[element.name] || (this.checkable(element) ? element.name : element.id || element.name);
710
+ },
711
+
712
+ validationTargetFor: function( element ) {
713
+ // if radio/checkbox, validate first element in group instead
714
+ if ( this.checkable(element) ) {
715
+ element = this.findByName( element.name ).not(this.settings.ignore)[0];
716
+ }
717
+ return element;
718
+ },
719
+
720
+ checkable: function( element ) {
721
+ return (/radio|checkbox/i).test(element.type);
722
+ },
723
+
724
+ findByName: function( name ) {
725
+ return $(this.currentForm).find("[name='" + name + "']");
726
+ },
727
+
728
+ getLength: function( value, element ) {
729
+ switch( element.nodeName.toLowerCase() ) {
730
+ case "select":
731
+ return $("option:selected", element).length;
732
+ case "input":
733
+ if ( this.checkable( element) ) {
734
+ return this.findByName(element.name).filter(":checked").length;
735
+ }
736
+ }
737
+ return value.length;
738
+ },
739
+
740
+ depend: function( param, element ) {
741
+ return this.dependTypes[typeof param] ? this.dependTypes[typeof param](param, element) : true;
742
+ },
743
+
744
+ dependTypes: {
745
+ "boolean": function( param, element ) {
746
+ return param;
747
+ },
748
+ "string": function( param, element ) {
749
+ return !!$(param, element.form).length;
750
+ },
751
+ "function": function( param, element ) {
752
+ return param(element);
753
+ }
754
+ },
755
+
756
+ optional: function( element ) {
757
+ var val = this.elementValue(element);
758
+ return !$.validator.methods.required.call(this, val, element) && "dependency-mismatch";
759
+ },
760
+
761
+ startRequest: function( element ) {
762
+ if ( !this.pending[element.name] ) {
763
+ this.pendingRequest++;
764
+ this.pending[element.name] = true;
765
+ }
766
+ },
767
+
768
+ stopRequest: function( element, valid ) {
769
+ this.pendingRequest--;
770
+ // sometimes synchronization fails, make sure pendingRequest is never < 0
771
+ if ( this.pendingRequest < 0 ) {
772
+ this.pendingRequest = 0;
773
+ }
774
+ delete this.pending[element.name];
775
+ if ( valid && this.pendingRequest === 0 && this.formSubmitted && this.form() ) {
776
+ $(this.currentForm).submit();
777
+ this.formSubmitted = false;
778
+ } else if (!valid && this.pendingRequest === 0 && this.formSubmitted) {
779
+ $(this.currentForm).triggerHandler("invalid-form", [this]);
780
+ this.formSubmitted = false;
781
+ }
782
+ },
783
+
784
+ previousValue: function( element ) {
785
+ return $.data(element, "previousValue") || $.data(element, "previousValue", {
786
+ old: null,
787
+ valid: true,
788
+ message: this.defaultMessage( element, "remote" )
789
+ });
790
+ }
791
+
792
+ },
793
+
794
+ classRuleSettings: {
795
+ required: {required: true},
796
+ email: {email: true},
797
+ url: {url: true},
798
+ date: {date: true},
799
+ dateISO: {dateISO: true},
800
+ number: {number: true},
801
+ digits: {digits: true},
802
+ creditcard: {creditcard: true}
803
+ },
804
+
805
+ addClassRules: function( className, rules ) {
806
+ if ( className.constructor === String ) {
807
+ this.classRuleSettings[className] = rules;
808
+ } else {
809
+ $.extend(this.classRuleSettings, className);
810
+ }
811
+ },
812
+
813
+ classRules: function( element ) {
814
+ var rules = {};
815
+ var classes = $(element).attr("class");
816
+ if ( classes ) {
817
+ $.each(classes.split(" "), function() {
818
+ if ( this in $.validator.classRuleSettings ) {
819
+ $.extend(rules, $.validator.classRuleSettings[this]);
820
+ }
821
+ });
822
+ }
823
+ return rules;
824
+ },
825
+
826
+ attributeRules: function( element ) {
827
+ var rules = {};
828
+ var $element = $(element);
829
+
830
+ for (var method in $.validator.methods) {
831
+ var value;
832
+
833
+ // support for <input required> in both html5 and older browsers
834
+ if ( method === "required" ) {
835
+ value = $element.get(0).getAttribute(method);
836
+ // Some browsers return an empty string for the required attribute
837
+ // and non-HTML5 browsers might have required="" markup
838
+ if ( value === "" ) {
839
+ value = true;
840
+ }
841
+ // force non-HTML5 browsers to return bool
842
+ value = !!value;
843
+ } else {
844
+ value = $element.attr(method);
845
+ }
846
+
847
+ if ( value ) {
848
+ rules[method] = value;
849
+ } else if ( $element[0].getAttribute("type") === method ) {
850
+ rules[method] = true;
851
+ }
852
+ }
853
+
854
+ // maxlength may be returned as -1, 2147483647 (IE) and 524288 (safari) for text inputs
855
+ if ( rules.maxlength && /-1|2147483647|524288/.test(rules.maxlength) ) {
856
+ delete rules.maxlength;
857
+ }
858
+
859
+ return rules;
860
+ },
861
+
862
+ dataRules: function( element ) {
863
+ var method, value,
864
+ rules = {}, $element = $(element);
865
+ for (method in $.validator.methods) {
866
+ value = $element.data("rule-" + method.toLowerCase());
867
+ if ( value !== undefined ) {
868
+ rules[method] = value;
869
+ }
870
+ }
871
+ return rules;
872
+ },
873
+
874
+ staticRules: function( element ) {
875
+ var rules = {};
876
+ var validator = $.data(element.form, "validator");
877
+ if ( validator.settings.rules ) {
878
+ rules = $.validator.normalizeRule(validator.settings.rules[element.name]) || {};
879
+ }
880
+ return rules;
881
+ },
882
+
883
+ normalizeRules: function( rules, element ) {
884
+ // handle dependency check
885
+ $.each(rules, function( prop, val ) {
886
+ // ignore rule when param is explicitly false, eg. required:false
887
+ if ( val === false ) {
888
+ delete rules[prop];
889
+ return;
890
+ }
891
+ if ( val.param || val.depends ) {
892
+ var keepRule = true;
893
+ switch (typeof val.depends) {
894
+ case "string":
895
+ keepRule = !!$(val.depends, element.form).length;
896
+ break;
897
+ case "function":
898
+ keepRule = val.depends.call(element, element);
899
+ break;
900
+ }
901
+ if ( keepRule ) {
902
+ rules[prop] = val.param !== undefined ? val.param : true;
903
+ } else {
904
+ delete rules[prop];
905
+ }
906
+ }
907
+ });
908
+
909
+ // evaluate parameters
910
+ $.each(rules, function( rule, parameter ) {
911
+ rules[rule] = $.isFunction(parameter) ? parameter(element) : parameter;
912
+ });
913
+
914
+ // clean number parameters
915
+ $.each(['minlength', 'maxlength'], function() {
916
+ if ( rules[this] ) {
917
+ rules[this] = Number(rules[this]);
918
+ }
919
+ });
920
+ $.each(['rangelength'], function() {
921
+ var parts;
922
+ if ( rules[this] ) {
923
+ if ( $.isArray(rules[this]) ) {
924
+ rules[this] = [Number(rules[this][0]), Number(rules[this][1])];
925
+ } else if ( typeof rules[this] === "string" ) {
926
+ parts = rules[this].split(/[\s,]+/);
927
+ rules[this] = [Number(parts[0]), Number(parts[1])];
928
+ }
929
+ }
930
+ });
931
+
932
+ if ( $.validator.autoCreateRanges ) {
933
+ // auto-create ranges
934
+ if ( rules.min && rules.max ) {
935
+ rules.range = [rules.min, rules.max];
936
+ delete rules.min;
937
+ delete rules.max;
938
+ }
939
+ if ( rules.minlength && rules.maxlength ) {
940
+ rules.rangelength = [rules.minlength, rules.maxlength];
941
+ delete rules.minlength;
942
+ delete rules.maxlength;
943
+ }
944
+ }
945
+
946
+ return rules;
947
+ },
948
+
949
+ // Converts a simple string to a {string: true} rule, e.g., "required" to {required:true}
950
+ normalizeRule: function( data ) {
951
+ if ( typeof data === "string" ) {
952
+ var transformed = {};
953
+ $.each(data.split(/\s/), function() {
954
+ transformed[this] = true;
955
+ });
956
+ data = transformed;
957
+ }
958
+ return data;
959
+ },
960
+
961
+ // http://docs.jquery.com/Plugins/Validation/Validator/addMethod
962
+ addMethod: function( name, method, message ) {
963
+ $.validator.methods[name] = method;
964
+ $.validator.messages[name] = message !== undefined ? message : $.validator.messages[name];
965
+ if ( method.length < 3 ) {
966
+ $.validator.addClassRules(name, $.validator.normalizeRule(name));
967
+ }
968
+ },
969
+
970
+ methods: {
971
+
972
+ // http://docs.jquery.com/Plugins/Validation/Methods/required
973
+ required: function( value, element, param ) {
974
+ // check if dependency is met
975
+ if ( !this.depend(param, element) ) {
976
+ return "dependency-mismatch";
977
+ }
978
+ if ( element.nodeName.toLowerCase() === "select" ) {
979
+ // could be an array for select-multiple or a string, both are fine this way
980
+ var val = $(element).val();
981
+ return val && val.length > 0;
982
+ }
983
+ if ( this.checkable(element) ) {
984
+ return this.getLength(value, element) > 0;
985
+ }
986
+ return $.trim(value).length > 0;
987
+ },
988
+
989
+ // http://docs.jquery.com/Plugins/Validation/Methods/remote
990
+ remote: function( value, element, param ) {
991
+ if ( this.optional(element) ) {
992
+ return "dependency-mismatch";
993
+ }
994
+
995
+ var previous = this.previousValue(element);
996
+ if (!this.settings.messages[element.name] ) {
997
+ this.settings.messages[element.name] = {};
998
+ }
999
+ previous.originalMessage = this.settings.messages[element.name].remote;
1000
+ this.settings.messages[element.name].remote = previous.message;
1001
+
1002
+ param = typeof param === "string" && {url:param} || param;
1003
+
1004
+ if ( previous.old === value ) {
1005
+ return previous.valid;
1006
+ }
1007
+
1008
+ previous.old = value;
1009
+ var validator = this;
1010
+ this.startRequest(element);
1011
+ var data = {};
1012
+ data[element.name] = value;
1013
+ $.ajax($.extend(true, {
1014
+ url: param,
1015
+ mode: "abort",
1016
+ port: "validate" + element.name,
1017
+ dataType: "json",
1018
+ data: data,
1019
+ success: function( response ) {
1020
+ validator.settings.messages[element.name].remote = previous.originalMessage;
1021
+ var valid = response === true || response === "true";
1022
+ if ( valid ) {
1023
+ var submitted = validator.formSubmitted;
1024
+ validator.prepareElement(element);
1025
+ validator.formSubmitted = submitted;
1026
+ validator.successList.push(element);
1027
+ delete validator.invalid[element.name];
1028
+ validator.showErrors();
1029
+ } else {
1030
+ var errors = {};
1031
+ var message = response || validator.defaultMessage( element, "remote" );
1032
+ errors[element.name] = previous.message = $.isFunction(message) ? message(value) : message;
1033
+ validator.invalid[element.name] = true;
1034
+ validator.showErrors(errors);
1035
+ }
1036
+ previous.valid = valid;
1037
+ validator.stopRequest(element, valid);
1038
+ }
1039
+ }, param));
1040
+ return "pending";
1041
+ },
1042
+
1043
+ // http://docs.jquery.com/Plugins/Validation/Methods/minlength
1044
+ minlength: function( value, element, param ) {
1045
+ var length = $.isArray( value ) ? value.length : this.getLength($.trim(value), element);
1046
+ return this.optional(element) || length >= param;
1047
+ },
1048
+
1049
+ // http://docs.jquery.com/Plugins/Validation/Methods/maxlength
1050
+ maxlength: function( value, element, param ) {
1051
+ var length = $.isArray( value ) ? value.length : this.getLength($.trim(value), element);
1052
+ return this.optional(element) || length <= param;
1053
+ },
1054
+
1055
+ // http://docs.jquery.com/Plugins/Validation/Methods/rangelength
1056
+ rangelength: function( value, element, param ) {
1057
+ var length = $.isArray( value ) ? value.length : this.getLength($.trim(value), element);
1058
+ return this.optional(element) || ( length >= param[0] && length <= param[1] );
1059
+ },
1060
+
1061
+ // http://docs.jquery.com/Plugins/Validation/Methods/min
1062
+ min: function( value, element, param ) {
1063
+ return this.optional(element) || value >= param;
1064
+ },
1065
+
1066
+ // http://docs.jquery.com/Plugins/Validation/Methods/max
1067
+ max: function( value, element, param ) {
1068
+ return this.optional(element) || value <= param;
1069
+ },
1070
+
1071
+ // http://docs.jquery.com/Plugins/Validation/Methods/range
1072
+ range: function( value, element, param ) {
1073
+ return this.optional(element) || ( value >= param[0] && value <= param[1] );
1074
+ },
1075
+
1076
+ // http://docs.jquery.com/Plugins/Validation/Methods/email
1077
+ email: function( value, element ) {
1078
+ // contributed by Scott Gonzalez: http://projects.scottsplayground.com/email_address_validation/
1079
+ return this.optional(element) || /^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([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])))$/i.test(value);
1080
+ },
1081
+
1082
+ // http://docs.jquery.com/Plugins/Validation/Methods/url
1083
+ url: function( value, element ) {
1084
+ // contributed by Scott Gonzalez: http://projects.scottsplayground.com/iri/
1085
+ 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);
1086
+ },
1087
+
1088
+ // http://docs.jquery.com/Plugins/Validation/Methods/date
1089
+ date: function( value, element ) {
1090
+ return this.optional(element) || !/Invalid|NaN/.test(new Date(value).toString());
1091
+ },
1092
+
1093
+ // http://docs.jquery.com/Plugins/Validation/Methods/dateISO
1094
+ dateISO: function( value, element ) {
1095
+ return this.optional(element) || /^\d{4}[\/\-]\d{1,2}[\/\-]\d{1,2}$/.test(value);
1096
+ },
1097
+
1098
+ // http://docs.jquery.com/Plugins/Validation/Methods/number
1099
+ number: function( value, element ) {
1100
+ return this.optional(element) || /^-?(?:\d+|\d{1,3}(?:,\d{3})+)?(?:\.\d+)?$/.test(value);
1101
+ },
1102
+
1103
+ // http://docs.jquery.com/Plugins/Validation/Methods/digits
1104
+ digits: function( value, element ) {
1105
+ return this.optional(element) || /^\d+$/.test(value);
1106
+ },
1107
+
1108
+ // http://docs.jquery.com/Plugins/Validation/Methods/creditcard
1109
+ // based on http://en.wikipedia.org/wiki/Luhn
1110
+ creditcard: function( value, element ) {
1111
+ if ( this.optional(element) ) {
1112
+ return "dependency-mismatch";
1113
+ }
1114
+ // accept only spaces, digits and dashes
1115
+ if ( /[^0-9 \-]+/.test(value) ) {
1116
+ return false;
1117
+ }
1118
+ var nCheck = 0,
1119
+ nDigit = 0,
1120
+ bEven = false;
1121
+
1122
+ value = value.replace(/\D/g, "");
1123
+
1124
+ for (var n = value.length - 1; n >= 0; n--) {
1125
+ var cDigit = value.charAt(n);
1126
+ nDigit = parseInt(cDigit, 10);
1127
+ if ( bEven ) {
1128
+ if ( (nDigit *= 2) > 9 ) {
1129
+ nDigit -= 9;
1130
+ }
1131
+ }
1132
+ nCheck += nDigit;
1133
+ bEven = !bEven;
1134
+ }
1135
+
1136
+ return (nCheck % 10) === 0;
1137
+ },
1138
+
1139
+ // http://docs.jquery.com/Plugins/Validation/Methods/equalTo
1140
+ equalTo: function( value, element, param ) {
1141
+ // bind to the blur event of the target in order to revalidate whenever the target field is updated
1142
+ // TODO find a way to bind the event just once, avoiding the unbind-rebind overhead
1143
+ var target = $(param);
1144
+ if ( this.settings.onfocusout ) {
1145
+ target.unbind(".validate-equalTo").bind("blur.validate-equalTo", function() {
1146
+ $(element).valid();
1147
+ });
1148
+ }
1149
+ return value === target.val();
1150
+ }
1151
+
1152
+ }
1172
1153
 
1173
1154
  });
1174
1155
 
@@ -1181,77 +1162,46 @@ $.format = $.validator.format;
1181
1162
  // usage: $.ajax({ mode: "abort"[, port: "uniqueport"]});
1182
1163
  // if mode:"abort" is used, the previous request on that port (port can be undefined) is aborted via XMLHttpRequest.abort()
1183
1164
  (function($) {
1184
- var pendingRequests = {};
1185
- // Use a prefilter if available (1.5+)
1186
- if ( $.ajaxPrefilter ) {
1187
- $.ajaxPrefilter(function(settings, _, xhr) {
1188
- var port = settings.port;
1189
- if (settings.mode === "abort") {
1190
- if ( pendingRequests[port] ) {
1191
- pendingRequests[port].abort();
1192
- }
1193
- pendingRequests[port] = xhr;
1194
- }
1195
- });
1196
- } else {
1197
- // Proxy ajax
1198
- var ajax = $.ajax;
1199
- $.ajax = function(settings) {
1200
- var mode = ( "mode" in settings ? settings : $.ajaxSettings ).mode,
1201
- port = ( "port" in settings ? settings : $.ajaxSettings ).port;
1202
- if (mode === "abort") {
1203
- if ( pendingRequests[port] ) {
1204
- pendingRequests[port].abort();
1205
- }
1206
- return (pendingRequests[port] = ajax.apply(this, arguments));
1207
- }
1208
- return ajax.apply(this, arguments);
1209
- };
1210
- }
1165
+ var pendingRequests = {};
1166
+ // Use a prefilter if available (1.5+)
1167
+ if ( $.ajaxPrefilter ) {
1168
+ $.ajaxPrefilter(function( settings, _, xhr ) {
1169
+ var port = settings.port;
1170
+ if ( settings.mode === "abort" ) {
1171
+ if ( pendingRequests[port] ) {
1172
+ pendingRequests[port].abort();
1173
+ }
1174
+ pendingRequests[port] = xhr;
1175
+ }
1176
+ });
1177
+ } else {
1178
+ // Proxy ajax
1179
+ var ajax = $.ajax;
1180
+ $.ajax = function( settings ) {
1181
+ var mode = ( "mode" in settings ? settings : $.ajaxSettings ).mode,
1182
+ port = ( "port" in settings ? settings : $.ajaxSettings ).port;
1183
+ if ( mode === "abort" ) {
1184
+ if ( pendingRequests[port] ) {
1185
+ pendingRequests[port].abort();
1186
+ }
1187
+ return (pendingRequests[port] = ajax.apply(this, arguments));
1188
+ }
1189
+ return ajax.apply(this, arguments);
1190
+ };
1191
+ }
1211
1192
  }(jQuery));
1212
1193
 
1213
- // provides cross-browser focusin and focusout events
1214
- // IE has native support, in other browsers, use event caputuring (neither bubbles)
1215
-
1216
1194
  // provides delegate(type: String, delegate: Selector, handler: Callback) plugin for easier event delegation
1217
1195
  // handler is only called when $(event.target).is(delegate), in the scope of the jquery-object for event.target
1218
1196
  (function($) {
1219
- // only implement if not provided by jQuery core (since 1.4)
1220
- // TODO verify if jQuery 1.4's implementation is compatible with older jQuery special-event APIs
1221
- if (!jQuery.event.special.focusin && !jQuery.event.special.focusout && document.addEventListener) {
1222
- $.each({
1223
- focus: 'focusin',
1224
- blur: 'focusout'
1225
- }, function( original, fix ){
1226
- $.event.special[fix] = {
1227
- setup:function() {
1228
- this.addEventListener( original, handler, true );
1229
- },
1230
- teardown:function() {
1231
- this.removeEventListener( original, handler, true );
1232
- },
1233
- handler: function(e) {
1234
- var args = arguments;
1235
- args[0] = $.event.fix(e);
1236
- args[0].type = fix;
1237
- return $.event.handle.apply(this, args);
1238
- }
1239
- };
1240
- function handler(e) {
1241
- e = $.event.fix(e);
1242
- e.type = fix;
1243
- return $.event.handle.call(this, e);
1244
- }
1245
- });
1246
- }
1247
- $.extend($.fn, {
1248
- validateDelegate: function(delegate, type, handler) {
1249
- return this.bind(type, function(event) {
1250
- var target = $(event.target);
1251
- if (target.is(delegate)) {
1252
- return handler.apply(target, arguments);
1253
- }
1254
- });
1255
- }
1256
- });
1197
+ $.extend($.fn, {
1198
+ validateDelegate: function( delegate, type, handler ) {
1199
+ return this.bind(type, function( event ) {
1200
+ var target = $(event.target);
1201
+ if ( target.is(delegate) ) {
1202
+ return handler.apply(target, arguments);
1203
+ }
1204
+ });
1205
+ }
1206
+ });
1257
1207
  }(jQuery));