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