Free cookie consent management tool by TermsFeed Policy Generator

source: branches/WebApplication/MVC2/HLWebOKBQueryPlugin/Scripts/jquery.validate.js @ 9232

Last change on this file since 9232 was 5756, checked in by cfleisch, 14 years ago

Test Query Plugin added #1439

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