PageRenderTime 128ms CodeModel.GetById 21ms app.highlight 89ms RepoModel.GetById 6ms app.codeStats 0ms

/packages/jQuery.Validation.1.8.0/Content/Scripts/jquery.validate.js

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