6056 |
efrain |
1 |
/*!
|
|
|
2 |
* jQuery Validation Plugin v1.15.0
|
|
|
3 |
*
|
|
|
4 |
* http://jqueryvalidation.org/
|
|
|
5 |
*
|
|
|
6 |
* Copyright (c) 2016 Jörn Zaefferer
|
|
|
7 |
* Released under the MIT license
|
|
|
8 |
*/
|
|
|
9 |
(function( factory ) {
|
|
|
10 |
if ( typeof define === "function" && define.amd ) {
|
|
|
11 |
define( ["jquery"], factory );
|
|
|
12 |
} else if (typeof module === "object" && module.exports) {
|
|
|
13 |
module.exports = factory( require( "jquery" ) );
|
|
|
14 |
} else {
|
|
|
15 |
factory( jQuery );
|
|
|
16 |
}
|
|
|
17 |
}(function( $ ) {
|
|
|
18 |
|
|
|
19 |
$.extend( $.fn, {
|
|
|
20 |
|
|
|
21 |
// http://jqueryvalidation.org/validate/
|
|
|
22 |
validate: function( options ) {
|
|
|
23 |
|
|
|
24 |
// If nothing is selected, return nothing; can't chain anyway
|
|
|
25 |
if ( !this.length ) {
|
|
|
26 |
if ( options && options.debug && window.console ) {
|
|
|
27 |
console.warn( "Nothing selected, can't validate, returning nothing." );
|
|
|
28 |
}
|
|
|
29 |
return;
|
|
|
30 |
}
|
|
|
31 |
|
|
|
32 |
// Check if a validator for this form was already created
|
|
|
33 |
var validator = $.data( this[ 0 ], "validator" );
|
|
|
34 |
if ( validator ) {
|
|
|
35 |
return validator;
|
|
|
36 |
}
|
|
|
37 |
|
|
|
38 |
// Add novalidate tag if HTML5.
|
|
|
39 |
this.attr( "novalidate", "novalidate" );
|
|
|
40 |
|
|
|
41 |
validator = new $.validator( options, this[ 0 ] );
|
|
|
42 |
$.data( this[ 0 ], "validator", validator );
|
|
|
43 |
|
|
|
44 |
if ( validator.settings.onsubmit ) {
|
|
|
45 |
|
|
|
46 |
this.on( "click.validate", ":submit", function( event ) {
|
|
|
47 |
if ( validator.settings.submitHandler ) {
|
|
|
48 |
validator.submitButton = event.target;
|
|
|
49 |
}
|
|
|
50 |
|
|
|
51 |
// Allow suppressing validation by adding a cancel class to the submit button
|
|
|
52 |
if ( $( this ).hasClass( "cancel" ) ) {
|
|
|
53 |
validator.cancelSubmit = true;
|
|
|
54 |
}
|
|
|
55 |
|
|
|
56 |
// Allow suppressing validation by adding the html5 formnovalidate attribute to the submit button
|
|
|
57 |
if ( $( this ).attr( "formnovalidate" ) !== undefined ) {
|
|
|
58 |
validator.cancelSubmit = true;
|
|
|
59 |
}
|
|
|
60 |
} );
|
|
|
61 |
|
|
|
62 |
// Validate the form on submit
|
|
|
63 |
this.on( "submit.validate", function( event ) {
|
|
|
64 |
if ( validator.settings.debug ) {
|
|
|
65 |
|
|
|
66 |
// Prevent form submit to be able to see console output
|
|
|
67 |
event.preventDefault();
|
|
|
68 |
}
|
|
|
69 |
function handle() {
|
|
|
70 |
var hidden, result;
|
|
|
71 |
if ( validator.settings.submitHandler ) {
|
|
|
72 |
if ( validator.submitButton ) {
|
|
|
73 |
|
|
|
74 |
// Insert a hidden input as a replacement for the missing submit button
|
|
|
75 |
hidden = $( "<input type='hidden'/>" )
|
|
|
76 |
.attr( "name", validator.submitButton.name )
|
|
|
77 |
.val( $( validator.submitButton ).val() )
|
|
|
78 |
.appendTo( validator.currentForm );
|
|
|
79 |
}
|
|
|
80 |
result = validator.settings.submitHandler.call( validator, validator.currentForm, event );
|
|
|
81 |
if ( validator.submitButton ) {
|
|
|
82 |
|
|
|
83 |
// And clean up afterwards; thanks to no-block-scope, hidden can be referenced
|
|
|
84 |
hidden.remove();
|
|
|
85 |
}
|
|
|
86 |
if ( result !== undefined ) {
|
|
|
87 |
return result;
|
|
|
88 |
}
|
|
|
89 |
return false;
|
|
|
90 |
}
|
|
|
91 |
return true;
|
|
|
92 |
}
|
|
|
93 |
|
|
|
94 |
// Prevent submit for invalid forms or custom submit handlers
|
|
|
95 |
if ( validator.cancelSubmit ) {
|
|
|
96 |
validator.cancelSubmit = false;
|
|
|
97 |
return handle();
|
|
|
98 |
}
|
|
|
99 |
if ( validator.form() ) {
|
|
|
100 |
if ( validator.pendingRequest ) {
|
|
|
101 |
validator.formSubmitted = true;
|
|
|
102 |
return false;
|
|
|
103 |
}
|
|
|
104 |
return handle();
|
|
|
105 |
} else {
|
|
|
106 |
validator.focusInvalid();
|
|
|
107 |
return false;
|
|
|
108 |
}
|
|
|
109 |
} );
|
|
|
110 |
}
|
|
|
111 |
|
|
|
112 |
return validator;
|
|
|
113 |
},
|
|
|
114 |
|
|
|
115 |
// http://jqueryvalidation.org/valid/
|
|
|
116 |
valid: function() {
|
|
|
117 |
var valid, validator, errorList;
|
|
|
118 |
|
|
|
119 |
if ( $( this[ 0 ] ).is( "form" ) ) {
|
|
|
120 |
valid = this.validate().form();
|
|
|
121 |
} else {
|
|
|
122 |
errorList = [];
|
|
|
123 |
valid = true;
|
|
|
124 |
validator = $( this[ 0 ].form ).validate();
|
|
|
125 |
this.each( function() {
|
|
|
126 |
valid = validator.element( this ) && valid;
|
|
|
127 |
if ( !valid ) {
|
|
|
128 |
errorList = errorList.concat( validator.errorList );
|
|
|
129 |
}
|
|
|
130 |
} );
|
|
|
131 |
validator.errorList = errorList;
|
|
|
132 |
}
|
|
|
133 |
return valid;
|
|
|
134 |
},
|
|
|
135 |
|
|
|
136 |
// http://jqueryvalidation.org/rules/
|
|
|
137 |
rules: function( command, argument ) {
|
|
|
138 |
|
|
|
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 |
} );
|
|
|
206 |
|
|
|
207 |
// Custom selectors
|
|
|
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 |
};
|
|
|
233 |
|
|
|
234 |
// http://jqueryvalidation.org/jQuery.validator.format/
|
|
|
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
|
|
|
1497 |
// usage: $.ajax({ mode: "abort"[, port: "uniqueport"]});
|
|
|
1498 |
// if mode:"abort" is used, the previous request on that port (port can be undefined) is aborted via XMLHttpRequest.abort()
|
|
|
1499 |
|
|
|
1500 |
var pendingRequests = {},
|
|
|
1501 |
ajax;
|
|
|
1502 |
|
|
|
1503 |
// Use a prefilter if available (1.5+)
|
|
|
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 |
}
|
|
|
1531 |
|
|
|
1532 |
}));
|