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