PageSourceSearch

http://lintao.gov.cn/jis/ui/widgets/validity/validity.js

js lintao.gov.cn collected 2026-10-02 17:05:15 UTC 37,140 bytes, 1,202 lines download raw bytes

1/*
2 * 
3 * Dual licensed under MIT and GPL
4 *
5 * Date: 2013-02-10 (Sunday, 10 February 2013)
6 */
7(function($, undefined) {
8
9	// Default settings:
10	// /////////////////////////////////////////////////////////////////////////////
11
12	var defaults = {
13		// The default output mode is tooltip because it requires no
14		// dependencies:
15		outputMode : "tooltip",
16
17		// The this property is set to true, validity will scroll the browser
18		// viewport so that the first error is visible when validation fails:
19		scrollTo : false,
20
21		// If this setting is true, modal errors will disappear when they are
22		// clicked on:
23		modalErrorsClickable : true,
24
25		// If a field name cannot be otherwise inferred, this will be used:
26		defaultFieldName : "This field",
27
28		// jQuery selector to filter down to validation-supported elements:
29		elementSupport : ":text, :password, textarea, select, :radio, :checkbox, input[type='hidden'], input[type='tel'], input[type='email']",
30
31		// Function to stringify argments for use when generating error
32		// messages. Primarily, it just generates pretty date strings:
33		argToString : function(val) {
34			return val.getDate ? [ val.getMonth() + 1, val.getDate(), val.getFullYear() ].join("/") : val + "";
35		},
36
37		debugPrivates : false
38	},
39
40	__private;
41
42	// Static functions and properties:
43	// /////////////////////////////////////////////////////////////////////////////
44
45	$.validity = {
46
47		// Clone the defaults. They can be overridden with the setup function:
48		settings : $.extend(defaults, {}),
49
50		// Built-in library of format-checking tools for use with the match
51		// validator as well as the nonHtml validator:
52		patterns : {
53			intege1 : /^[1-9]\d*$/, // 正整数
54			intege2 : /^-[1-9]\d*$/, // 负整数
55			num : /^([+-]?)\d*\.?\d+$/, // 数字
56			num1 : /^[0-9]\d*$/, // 正数(正整数 + 0)
57			num2 : /^-[0-9]\d*$/, // 负数(负整数 + 0)
58			decmal : /^([+-]?)\d*\.\d+$/, // 浮点数
59			decmal1 : /^[1-9]\d*.\d*|0.\d*[1-9]\d*$/,// 正浮点数
60			decmal2 : /^-([1-9]\d*.\d*|0.\d*[1-9]\d*)$/,// 负浮点数
61			decmal3 : /^-?([1-9]\d*.\d*|0.\d*[1-9]\d*|0?.0+|0)$/,// 浮点数
62			decmal4 : /^([0-9]\d*\.\d+|0)$/,// 非负浮点数(正浮点数 + 0)
63			decmal5 : /^(-([1-9]\d*.\d*|0.\d*[1-9]\d*))|0?.0+|0$/,// 非正浮点数(负浮点数 + 0)
64
65			email : /^\w+((-\w+)|(\.\w+))*\@[A-Za-z0-9]+((\.|-)[A-Za-z0-9]+)*\.[A-Za-z0-9]+$/, // 邮件
66			color : /^[a-fA-F0-9]{6}$/, // 颜色
67			chinese : /^[\u4E00-\u9FA5\uF900-\uFA2D]+$/, // 仅中文
68			ascii : /^[\x00-\xFF]+$/, // 仅ACSII字符
69			zipcode : /^\d{6}$/, // 邮编
70			mobile : /^[1][0-9]{10}$/, // 手机
71			ip4 : /^(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])$/, // ip地址
72			picture : /(.*)\.(jpg|bmp|gif|ico|pcx|jpeg|tif|png|raw|tga)$/, // 图片
73			rar : /(.*)\.(rar|zip|7zip|tgz)$/, // 压缩文件
74			zip : /(.*)\.(zip)$/,
75			qq : /^[1-9]*[1-9][0-9]*$/, // QQ号码
76			tel : /(\d{3}-|\d{4}-)?(\d{8}|\d{7})/, // 国内电话
77			username : /^\w+$/, // 用来用户注册。匹配由数字、26个英文字母或者下划线组成的字符串
78			username1 : /^(?!_)(?!.*?_$)[a-zA-Z0-9_\u4e00-\u9fa5]+$/,// 用来用户注册。匹配字母、数字、下划线、中文组成,不能以下划线开头和结尾
79			username2 : /^(?!_)(?!.*?_$)[a-zA-Z0-9_\u4e00-\u9fa5,]+$/,// 用来用户注册。匹配字母、数字、下划线、中文、英文逗号组成,不能以下划线开头和结尾
80			username3 : /^[a-zA-Z]{1}(?!.*?_$)[a-zA-Z0-9_\u4e00-\u9fa5]+$/,// 用来用户注册。匹配字母、数字、下划线、中文组成,只能以字母开头
81			username4 : /^[a-zA-Z]{1}(?!.*?_$)[a-zA-Z0-9_]+$/,// 用来用户注册。匹配字母、数字、下划线组成,只能以英文字母开头不能以下划线结尾
82			username5 : /^(?!_)(?!.*?_$)[a-zA-Z0-9_()()\u4e00-\u9fa5]+$/,// 用来用户注册。匹配字母、数字、下划线、中文、括号组成,不能以下划线开头和结尾
83			letter : /^[A-Za-z]+$/, // 字母
84			letter_u : /^[A-Z]+$/, // 大写字母
85			letter_l : /^[a-z]+$/, // 小写字母
86			codeid : /^[a-zA-Z0-9]+$/, // 机构标识。大小写字母及数字
87			idcard : /^[1-9]([0-9]{14}|([0-9]{16}([X]|\d)))$/, // 身份证
88			date : /^((0?\d)|(1[012]))[\/-]([012]?\d|30|31)[\/-]\d{1,4}$/,
89			url : /^(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,
90			nonHtml : /^[^<>]*$/
91		},
92
93		// Built-in set of default error messages (for use when a message isn't
94		// specified):
95		messages : {
96
97			require : "#{field} is required.",
98
99			// Format validators:
100			match : "#{field} is in an invalid format.",
101			integer : "#{field} must be a positive, whole number.",
102			date : "#{field} must be formatted as a date. (mm/dd/yyyy)",
103			email : "#{field} must be formatted as an email.",
104			usd : "#{field} must be formatted as a US Dollar amount.",
105			url : "#{field} must be formatted as a URL.",
106			number : "#{field} must be formatted as a number.",
107			zip : "#{field} must be formatted as a zipcode ##### or #####-####.",
108			phone : "#{field} must be formatted as a phone number ###-###-####.",
109			guid : "#{field} must be formatted as a guid like {3F2504E0-4F89-11D3-9A0C-0305E82C3301}.",
110			time24 : "#{field} must be formatted as a 24 hour time: 23:00.",
111			time12 : "#{field} must be formatted as a 12 hour time: 12:00 AM/PM",
112
113			// Value range messages:
114			lessThan : "#{field} must be less than #{max}.",
115			lessThanOrEqualTo : "#{field} must be less than or equal to #{max}.",
116			greaterThan : "#{field} must be greater than #{min}.",
117			greaterThanOrEqualTo : "#{field} must be greater than or equal to #{min}.",
118			range : "#{field} must be between #{min} and #{max}.",
119
120			// Value length messages:
121			tooLong : "#{field} cannot be longer than #{max} characters.",
122			tooShort : "#{field} cannot be shorter than #{min} characters.",
123
124			// Composition validators:
125			nonHtml : "#{field} cannot contain HTML characters.",
126			alphabet : "#{field} contains disallowed characters.",
127
128			minCharClass : "#{field} cannot have more than #{min} #{charClass} characters.",
129			maxCharClass : "#{field} cannot have less than #{min} #{charClass} characters.",
130
131			// Aggregate validator messages:
132			equal : "Values don't match.",
133			distinct : "A value was repeated.",
134			sum : "Values don't add to #{sum}.",
135			sumMax : "The sum of the values must be less than #{max}.",
136			sumMin : "The sum of the values must be greater than #{min}.",
137
138			// Radio validator messages:
139			radioChecked : "The selected value is not valid.",
140
141			generic : "Invalid."
142		},
143
144		// Abstract output:
145		out : {
146			start : function() {
147				this.defer("start");
148			},
149			end : function(results) {
150				this.defer("end", results);
151			},
152			raise : function($obj, msg) {
153				this.defer("raise", $obj, msg);
154			},
155			raiseAggregate : function($obj, msg) {
156				this.defer("raiseAggregate", $obj, msg);
157			},
158			defer : function(name) {
159				var v = $.validity, o = v.outputs[v.settings.outputMode];
160
161				o[name].apply(o, Array.prototype.slice.call(arguments, 1));
162			}
163		},
164
165		// Character classes can be used to determine the quantity of a given type
166		// of character in a string:
167		charClasses : {
168			alphabetical : /\w/g,
169			numeric : /\d/g,
170			alphanumeric : /[A-Za-z0-9]/g,
171			symbol : /[^A-Za-z0-9]/g
172		},
173
174		// Object to contain the output modes. The three built-in output modes are
175		// installed later on in this script.
176		outputs : {},
177
178		// By default, private members are not exposed.
179		__private : undefined,
180
181		// Override the default settings with user-specified ones.
182		setup : function(options) {
183			this.settings = $.extend(this.settings, options);
184
185			if (this.settings.debugPrivates) {
186				this.__private = __private;
187			} else {
188				this.__private = undefined;
189			}
190		},
191
192		// Object to store information about ongoing validation. When validation
193		// starts, this will be set to a report object. When validators fail, they
194		// will inform this object. When validation is completed, this object will
195		// contain the information of whether it succeeded:
196		report : null,
197
198		// Determine whether validity is in the middle of validation:
199		isValidating : function() {
200			return !!this.report;
201		},
202
203		// Function to prepare validity to start validating:
204		start : function() {
205
206			// The output mode should be notified that validation is starting. This
207			// usually means that the output mode will erase errors from the
208			// document in whatever way the mode needs to:
209			this.out.start();
210
211			// Initialize the report object:
212			this.report = {
213				errors : 0,
214				valid : true
215			};
216		},
217
218		// Function called when validation is over to examine the results and
219		// clean-up:
220		end : function() {
221
222			// Null coalescence: fix for Issue 5:
223			var results = this.report || {
224				errors : 0,
225				valid : true
226			};
227
228			this.report = null;
229
230			// Notify the current output mode that validation is over:
231			this.out.end(results);
232
233			return results;
234		},
235
236		// Remove validiation errors:
237		clear : function() {
238			this.start();
239			this.end();
240		}
241	};
242
243	// jQuery instance methods:
244	// /////////////////////////////////////////////////////////////////////////////
245
246	$.fn.extend({
247
248		// The validity function is how validation can be bound to forms. The user
249		// may pass in a validation function or, as a shortcut, pass in a string of
250		// a CSS selector that grabs all the inputs to require:
251		/**
252		 * 
253		 */
254		validity : function(arg, setting) {
255
256			return this.each(
257
258			function() {
259				var op = {
260					auto : true,
261					type : 'ajax',
262					resultType : 'json',
263					contentType : 'application/x-www-form-urlencoded',
264					beforeSubmit : function(result) {
265					},
266					success : function() {
267					},
268					error : function() {
269					}
270				};
271				op = $.extend(op, setting);
272				// Only operate on forms:
273				if (this.tagName.toLowerCase() == "form") {
274					var form = $(this);
275					var f = null;
276
277					// If the user entered a string to select the inputs to
278					// require, then make the validation logic ad hoc:
279					if (typeof (arg) == "string") {
280						f = function() {
281							$(arg).require();
282						};
283					}
284
285					// If the user entered a validation function then just call
286					// that at the appropriate time:
287					else if ($.isFunction(arg)) {
288						f = arg;
289					}
290
291					if (arg) {
292						if (op.auto == true && op.type == 'iframe') {
293							$('body').append('<iframe frameborder="0" id="hiddenSubmit" name="hiddenSubmit" style="width: 0;height: 0"></iframe>');
294							$(this).attr('target', 'hiddenSubmit');
295						}
296						$(this).bind("submit", function() {
297							$.validity.start();
298							f();
299							var result = $.validity.end().valid;
300							var before = op.beforeSubmit(result);
301							if(before == false){
302								return false;
303							}
304							
305							if (result == true && op.auto == true) {
306								var submitBtn = $(form.find('[type=submit],.submit'));
307								var data = form.serialize();
308								submitBtn.attr('disabled', true).removeClass('btn-primary').addClass('disabled');
309								if(op.type == 'ajax'){
310									var url = form.attr('action');
311									$.ajax({
312										type : "post",
313										url : url,
314										data : data,
315										dataType : op.resultType,
316										contentType : op.contentType,
317										success : function(obj) {
318											submitBtn.attr('disabled', false).removeClass('disabled').addClass('btn-primary');
319											op.success(obj);
320										},
321										error : function(a, b, msg) {
322											submitBtn.attr('disabled', false).removeClass('disabled').addClass('btn-primary');
323											alert('操作失败');
324											op.error();
325										}
326									});
327									result = false;
328								}
329							}
330							return result;
331						});
332					}
333				}
334			});
335		},
336
337		// Validators:
338		// /////////////////////////////////////////////////////////////////////////
339
340		// Common validators:
341		// /////////////////////////////////////////////////////////////////////////
342
343		// Validate whether the field has a value.
344		require : function(msg) {
345			return validate(this, function(obj) {
346				return !!$.trim($(obj).val()).length;
347			}, msg || $.validity.messages.require);
348		},
349
350		// Validate whether the field matches a regex.
351		match : function(rule, msg) {
352
353			// If a default message is to be used:
354			if (!msg) {
355				// First grab the generic one:
356				msg = $.validity.messages.match;
357
358				// If there's a more specific one, use that.
359				if (typeof (rule) === "string" && $.validity.messages[rule]) {
360					msg = $.validity.messages[rule];
361				}
362			}
363
364			// If the rule is named, rather than specified:
365			if (typeof (rule) == "string") {
366				rule = $.validity.patterns[rule];
367			}
368
369			return validate(this,
370
371			// Some of the named rules can be functions, such as 'date'. If the
372			// discovered rule is a function use it as such. Otherwise, assume
373			// it's a RegExp.
374			$.isFunction(rule) ?
375
376			function(obj) {
377				return !obj.value.length || rule(obj.value);
378			} :
379
380			function(obj) {
381				// Fix for regexes where the global flag is set. Make sure
382				// to test from the start of the string.
383				if (rule.global) {
384					rule.lastIndex = 0;
385				}
386
387				return !obj.value.length || rule.test(obj.value);
388			},
389
390			msg);
391		},
392
393		range : function(min, max, msg) {
394			return validate(this,
395
396			min.getTime && max.getTime ?
397
398			// If both arguments are dates then use them that way.
399			function(obj) {
400				var d = new Date(obj.value);
401				return d >= new Date(min) && d <= new Date(max);
402			} :
403
404			min.substring && max.substring && Big ?
405
406			// If both arguments are strings then parse them using the
407			// Arbitrary-Precision library.
408			function(obj) {
409				var n = new Big(obj.value);
410				return (n.greaterThanOrEqualTo(new Big(min)) && n.lessThanOrEqualTo(new Big(max)));
411			} :
412
413			// Otherwise treat them like floats.
414			function(obj) {
415				var f = parseFloat(obj.value);
416				return f >= min && f <= max;
417			},
418
419			msg || format($.validity.messages.range, {
420				min : $.validity.settings.argToString(min),
421				max : $.validity.settings.argToString(max)
422			}));
423		},
424
425		greaterThan : function(min, msg) {
426			return validate(this,
427
428			min.getTime ? function(obj) {
429				return new Date(obj.value) > min;
430			} :
431
432			min.substring && Big ?
433
434			function(obj) {
435				return new Big(obj.value).greaterThan(new Big(min));
436			} :
437
438			function(obj) {
439				return parseFloat(obj.value) > min;
440			},
441
442			msg || format($.validity.messages.greaterThan, {
443				min : $.validity.settings.argToString(min)
444			}));
445		},
446
447		greaterThanOrEqualTo : function(min, msg) {
448			return validate(this,
449
450			min.getTime ? function(obj) {
451				return new Date(obj.value) >= min;
452			} :
453
454			min.substring && Big ?
455
456			function(obj) {
457				return new Big(obj.value).greaterThanOrEqualTo(new Big(min));
458			} :
459
460			function(obj) {
461				return parseFloat(obj.value) >= min;
462			},
463
464			msg || format($.validity.messages.greaterThanOrEqualTo, {
465				min : $.validity.settings.argToString(min)
466			}));
467		},
468
469		lessThan : function(max, msg) {
470			return validate(this,
471
472			max.getTime ? function(obj) {
473				return new Date(obj.value) < max;
474			} :
475
476			max.substring && Big ?
477
478			function(obj) {
479				return new Big(obj.value).lessThan(new Big(max));
480			} :
481
482			function(obj) {
483				return parseFloat(obj.value) < max;
484			},
485
486			msg || format($.validity.messages.lessThan, {
487				max : $.validity.settings.argToString(max)
488			}));
489		},
490
491		lessThanOrEqualTo : function(max, msg) {
492			return validate(this,
493
494			max.getTime ? function(obj) {
495				return new Date(obj.value) <= max;
496			} :
497
498			max.substring && Big ?
499
500			function(obj) {
501				return new Big(obj.value).lessThanOrEqualTo(new Big(max));
502			} :
503
504			function(obj) {
505				return parseFloat(obj.value) <= max;
506			},
507
508			msg || format($.validity.messages.lessThanOrEqualTo, {
509				max : $.validity.settings.argToString(max)
510			}));
511		},
512
513		maxLength : function(max, msg) {
514			return validate(this, function(obj) {
515				return obj.value.length <= max;
516			}, msg || format($.validity.messages.tooLong, {
517				max : max
518			}));
519		},
520
521		minLength : function(min, msg) {
522			return validate(this, function(obj) {
523				return obj.value.length >= min;
524			}, msg || format($.validity.messages.tooShort, {
525				min : min
526			}));
527		},
528
529		alphabet : function(alpha, msg) {
530			var chars = [];
531
532			return validate(this, function(obj) {
533
534				// For each character in the string, ensure that it's in the
535				// alphabet definition:
536				for ( var idx = 0; idx < obj.value.length; ++idx) {
537					if (alpha.indexOf(obj.value.charAt(idx)) == -1) {
538						chars.push(obj.value.charAt(idx));
539						return false;
540					}
541				}
542
543				return true;
544			}, msg || format($.validity.messages.alphabet, {
545				chars : chars.join(", ")
546			}));
547		},
548
549		minCharClass : function(charClass, min, msg) {
550			if (typeof (charClass) == "string") {
551				charClass = charClass.toLowerCase();
552
553				if ($.validity.charClasses[charClass]) {
554					charClass = $.validity.charClasses[charClass];
555				}
556			}
557
558			return validate(this, function(obj) {
559				return (obj.value.match(charClass) || []).length >= min;
560			}, msg || format($.validity.messages.minCharClass, {
561				min : min,
562				charClass : charClass
563			}));
564		},
565
566		maxCharClass : function(charClass, max, msg) {
567			if (typeof (charClass) == "string") {
568				charClass = charClass.toLowerCase();
569
570				if ($.validity.charClasses[charClass]) {
571					charClass = $.validity.charClasses[charClass];
572				}
573			}
574
575			return validate(this, function(obj) {
576				return (obj.value.match(charClass) || []).length <= max;
577			}, msg || format($.validity.messages.maxCharClass, {
578				max : max,
579				charClass : charClass
580			}));
581		},
582
583		// Validate that the input does not contain potentially dangerous strings.
584		nonHtml : function(msg) {
585			return validate(this,
586
587			function(obj) {
588				return $.validity.patterns.nonHtml.test(obj.value);
589			},
590
591			msg || $.validity.messages.nonHtml);
592		},
593
594		// Aggregate validators:
595		// /////////////////////////////////////////////////////////////////////////
596
597		// Validate that all matched elements bear the same values. Accepts a
598		// function to transform the values for testing.
599		equal : function(arg0, arg1) {
600			var
601			// If a reduced set is attached, use it. Also, remove unsupported
602			// elements.
603			$reduction = (this.reduction || this).filter($.validity.settings.elementSupport),
604
605			transform = function(val) {
606				return val;
607			},
608
609			msg = $.validity.messages.equal;
610
611			if ($reduction.length) {
612
613				// Figure out what arguments were specified.
614				if ($.isFunction(arg0)) {
615					transform = arg0;
616
617					if (typeof (arg1) == "string") {
618						msg = arg1;
619					}
620				}
621
622				else if (typeof (arg0) == "string") {
623					msg = arg0;
624				}
625
626				var map = $.map($reduction, function(obj) {
627					return transform(obj.value);
628				}),
629
630				// Get the first value.
631				first = map[0], valid = true;
632
633				// If any value is not equal to the first value, then they aren't
634				// all equal, and it's not valid.
635				for ( var i in map) {
636					if (map[i] != first) {
637						valid = false;
638					}
639				}
640
641				if (!valid) {
642					raiseAggregateError($reduction, msg);
643
644					// The set reduces to zero valid elements.
645					this.reduction = $([]);
646				}
647			}
648
649			return this;
650		},
651
652		// Validate that all matched elements bear distinct values. Accepts an
653		// optional function to transform the values for testing.
654		distinct : function(arg0, arg1) {
655			var
656			// If a reduced set is attached, use it.
657			// Also, remove unsupported elements.
658			$reduction = (this.reduction || this).filter($.validity.settings.elementSupport),
659
660			transform = function(val) {
661				return val;
662			},
663
664			msg = $.validity.messages.distinct,
665
666			// An empty array to store already-examined values
667			subMap = [],
668
669			// An array with repeated values
670			repeatedVal = [],
671
672			valid = true;
673
674			if ($reduction.length) {
675
676				// Figure out what arguments were specified.
677				if ($.isFunction(arg0)) {
678					transform = arg0;
679
680					if (typeof (arg1) == "string") {
681						msg = arg1;
682					}
683				}
684
685				else if (typeof (arg0) == "string") {
686					msg = arg0;
687				}
688
689				// Map all the matched values into an array.
690				var map = $.map($reduction, function(obj) {
691					return transform(obj.value);
692				});
693
694				// For each transformed value:
695				for ( var i1 = 0; i1 < map.length; ++i1) {
696					// Unless it's an empty string:
697					if (map[i1].length) {
698						// For each value we've already looked at:
699						for ( var i2 = 0; i2 < subMap.length; ++i2) {
700							// If we've already seen the transformed value:
701							if (subMap[i2] == map[i1]) {
702								valid = false;
703								// Collect repeated values
704								repeatedVal.push(map[i1]);
705							}
706						}
707
708						// We looked at the value.
709						subMap.push(map[i1]);
710					}
711				}
712
713				if (!valid) {
714					// Remove duplicates of duplicates
715					repeatedVal = $.unique(repeatedVal);
716
717					// For all repeated values found...
718					for ( var i = 0, repeatedLength = repeatedVal.length; i < repeatedLength; ++i) {
719
720						// raise the error - aggregate will use last repeated value
721						raiseAggregateError($reduction.filter("[value=\'" + repeatedVal[i] + "\']"), msg);
722					}
723
724					// The set reduces to zero valid elements.
725					this.reduction = $([]);
726				}
727			}
728
729			return this;
730		},
731
732		// Validate that the numeric sum of all values is equal to a given value.
733		sum : function(sum, msg) {
734			// If a reduced set is attached, use it. Also, remove unsupported
735			// elements.
736			var $reduction = (this.reduction || this).filter($.validity.settings.elementSupport);
737
738			if ($reduction.length && sum != numericSum($reduction)) {
739				raiseAggregateError($reduction, msg || format($.validity.messages.sum, {
740					sum : sum
741				}));
742
743				// The set reduces to zero valid elements.
744				this.reduction = $([]);
745			}
746
747			return this;
748		},
749
750		// Validates an inclusive upper-bound on the numeric sum of the values of
751		// all matched elements.
752		sumMax : function(max, msg) {
753			// If a reduced set is attached, use it. Also, remove unsupported
754			// elements.
755			var $reduction = (this.reduction || this).filter($.validity.settings.elementSupport);
756
757			if ($reduction.length && max < numericSum($reduction)) {
758				raiseAggregateError($reduction, msg || format($.validity.messages.sumMax, {
759					max : max
760				}));
761
762				// The set reduces to zero valid elements.
763				this.reduction = $([]);
764			}
765
766			return this;
767		},
768
769		// Validates an inclusive lower-bound on the numeric sum of the values of
770		// all matched elements.
771		sumMin : function(min, msg) {
772			// If a reduced set is attached, use it. Also, remove unsupported
773			// elements.
774			var $reduction = (this.reduction || this).filter($.validity.settings.elementSupport);
775
776			if ($reduction.length && min > numericSum($reduction)) {
777				raiseAggregateError($reduction, msg || format($.validity.messages.sumMin, {
778					min : min
779				}));
780
781				// The set reduces to zero valid elements.
782				this.reduction = $([]);
783			}
784
785			return this;
786		},
787
788		// Radio group validators:
789		// /////////////////////////////////////////////////////////////////////////
790
791		radioChecked : function(val, msg) {
792			// If a reduced set is attached, use it. Also, remove unsupported
793			// elements.
794			var $reduction = (this.reduction || this).filter($.validity.settings.elementSupport);
795
796			if ($reduction.is(":radio") && $reduction.find(":checked").val() != val) {
797				raiseAggregateError($reduction, msg || $.validity.messages.radioChecked);
798			}
799		},
800
801		radioNotChecked : function(val, msg) {
802			// If a reduced set is attached, use it. Also, remove unsupported
803			// elements.
804			var $reduction = (this.reduction || this).filter($.validity.settings.elementSupport);
805
806			if ($reduction.is(":radio") && $reduction.filter(":checked").val() == val) {
807				raiseAggregateError($reduction, msg || $.validity.messages.radioChecked);
808			}
809		},
810
811		// Checkbox validators:
812		// /////////////////////////////////////////////////////////////////////////
813
814		checkboxChecked : function(msg) {
815			// If a reduced set is attached, use it. Also, remove unsupported
816			// elements.
817			var $reduction = (this.reduction || this).filter($.validity.settings.elementSupport);
818
819			if ($reduction.is(":checkbox") && !$reduction.is(":checked")) {
820				raiseAggregateError($reduction, msg || $.validity.messages.radioChecked);
821			}
822		},
823
824		// Specialized validators:
825		// /////////////////////////////////////////////////////////////////////////
826
827		// If expression is a function, it will be called on each matched element.
828		// Otherwise, it is treated as a boolean, and the determines the validity
829		// of elements in an aggregate fashion.
830		assert : function(expression, msg) {
831
832			// If a reduced set is attached, use it. Do not reduce to supp
832orted
833			// elements.
834			var $reduction = this.reduction || this;
835
836			if ($reduction.length) {
837
838				// In the case that 'expression' is a function, use it as a
839				// regimen on each matched element individually:
840				if ($.isFunction(expression)) {
841					return validate(this, expression, msg || $.validity.messages.generic);
842				}
843
844				// Otherwise map it to a boolean and consider this as an aggregate
845				// validation:
846				else if (!expression) {
847
848					raiseAggregateError($reduction, msg || $.validity.messages.generic);
849
850					// The set reduces to zero valid elements.
851					this.reduction = $([]);
852				}
853			}
854
855			return this;
856		},
857
858		fail : function(msg) {
859			return this.assert(false, msg);
860		}
861	});
862
863	// Private utilities:
864	// /////////////////////////////////////////////////////////////////////////////
865
866	// Do non-aggregate validation. Subject each element in $obj to the regimen.
867	// Raise the specified error on failures. This function is the heart of
868	// validity:
869	function validate($obj, regimen, message) {
870
871		var
872		// If a reduced set is attached, use it Also, remove any unsupported
873		// elements.
874		$reduction = ($obj.reduction || $obj).filter($.validity.settings.elementSupport),
875
876		// Array to store only elements that pass the regimen.
877		elements = [];
878
879		// For each in the reduction.
880		$reduction.each(function() {
881			// If the element passes the regimen, include it in the reduction.
882			if (regimen(this)) {
883				elements.push(this);
884			}
885
886			// Else give the element an error message.
887			else {
888				raiseError(this, format(message, {
889					field : infer(this)
890				}));
891			}
892		});
893
894		// Attach a (potentially) reduced set of only elements that passed.
895		$obj.reduction = $(elements);
896
897		// Return the full set with attached reduction.
898		return $obj;
899	}
900
901	// Inform the report object that there was a failure.
902	function addToReport() {
903		if ($.validity.isValidating()) {
904			$.validity.report.errors++;
905			$.validity.report.valid = false;
906		}
907	}
908
909	// Inform the report of a failure and display an error according to the idiom
910	// of the current output mode.
911	function raiseError(obj, msg) {
912		addToReport();
913
914		$.validity.out.raise($(obj), msg);
915	}
916
917	// Inform the report of a failure and display an aggregate error according to
918	// the idiom of the current output mode.
919	function raiseAggregateError($obj, msg) {
920		addToReport();
921
922		$.validity.out.raiseAggregate($obj, msg);
923	}
924
925	// Yield the sum of the values of all fields matched in obj that can be parsed.
926	function numericSum(obj) {
927		var accumulator = 0;
928		obj.each(function() {
929			var n = parseFloat(this.value);
930
931			accumulator += isNaN(n) ? 0 : n;
932		});
933		return accumulator;
934	}
935
936	// Using the associative array supplied as the 'obj' argument, replace tokens
937	// of the format #{<key>} in the 'str' argument with that key's value.
938	function format(str, obj) {
939		for ( var p in obj) {
940			if (obj.hasOwnProperty(p)) {
941				str = str.replace(new RegExp("#\\{" + p + "\\}", "g"), obj[p]);
942			}
943		}
944		return capitalize(str);
945	}
946
947	// Infer the field name of the passed DOM element. If a title is specified, its
948	// value is returned. Otherwise, attempt to parse a field name out of the id
949	// attribute. If that doesn't work, return the default field name in the
950	// configuration.
951	function infer(field) {
952		var $f = $(field), id = $f.prop("id"), ret = $.validity.settings.defaultFieldName;
953
954		// Check for title.
955		if ($f.prop("title").length) {
956			ret = $f.prop("title");
957		}
958
959		// Check for UpperCamelCase.
960		else if (/^([A-Z0-9][a-z]*)+$/.test(id)) {
961			ret = id.replace(/([A-Z0-9])[a-z]*/g, " $&");
962		}
963
964		// Check for lowercase_separated_by_underscores
965		else if (/^[a-z0-9]+(_[a-z0-9]+)*$/.test(id)) {
966			var arr = id.split("_");
967
968			for ( var i = 0; i < arr.length; ++i) {
969				arr[i] = capitalize(arr[i]);
970			}
971
972			ret = arr.join(" ");
973		}
974
975		return $.trim(ret);
976	}
977
978	// Capitalize the first character of the string argument.
979	function capitalize(sz) {
980		return sz.substring ? sz.substring(0, 1).toUpperCase() + sz.substring(1, sz.length) : sz;
981	}
982
983	__private = {
984		validate : validate,
985		addToReport : addToReport,
986		raiseError : raiseError,
987		raiseAggregateError : raiseAggregateError,
988		numericSum : numericSum,
989		format : format,
990		infer : infer,
991		capitalize : capitalize
992	};
993
994})(jQuery);
995// Output modes:
996// //////////////////////////////////////////////////////////////
997
998// Each output mode gets its own closure,
999// distinct from the validity closure.
1000
1001// Install the tooltip output.
1002(function($) {
1003	$.validity.outputs.tooltip = {
1004		tooltipClass : "validity-tooltip",
1005
1006		start : function() {
1007			$("." + $.validity.outputs.tooltip.tooltipClass).remove();
1008		},
1009
1010		end : function(results) {
1011			// If not valid and scrollTo is enabled, scroll the page to the first error.
1012			if (!results.valid && $.validity.settings.scrollTo) {
1013				$(document).scrollTop($("." + $.validity.outputs.tooltip.tooltipClass).offset().top);
1014			}
1015		},
1016
1017		raise : function($obj, msg) {
1018			var pos = $obj.offset();
1019			pos.left += $obj.width() + 18;
1020			pos.top += 8;
1021
1022			$("<div class=\"validity-tooltip\">" + msg + "<div class=\"validity-tooltip-outer\">" + "<div class=\"validity-tooltip-inner\"></div>" + "</div>" + "</div>").click(function() {
1023				$obj.focus();
1024				$(this).fadeOut();
1025			}).css(pos).hide().appendTo("body").fadeIn();
1026		},
1027
1028		raiseAggregate : function($obj, msg) {
1029			// Just raise the error on the last input.
1030			if ($obj.length) {
1031				this.raise($obj.filter(":last"), msg);
1032			}
1033		}
1034	};
1035})(jQuery);
1036
1037// Install the label output.
1038(function($) {
1039	function getIdentifier($obj) {
1040		return $obj.attr('id').length ? $obj.attr('id') : $obj.attr('name');
1041	}
1042
1043	$.validity.outputs.label = {
1044		cssClass : "error",
1045
1046		start : function() {
1047			// Remove all the existing error labels.
1048			$("." + $.validity.outputs.label.cssClass).remove();
1049		},
1050
1051		end : function(results) {
1052			// If not valid and scrollTo is enabled, scroll the page to the first error.
1053			if (!results.valid && $.validity.settings.scrollTo) {
1054				location.hash = $("." + $.validity.outputs.label.cssClass + ":eq(0)").attr('for');
1055			}
1056		},
1057
1058		raise : function($obj, msg) {
1059			var labelSelector = "." + $.validity.outputs.label.cssClass + "[for='" + getIdentifier($obj) + "']";
1060
1061			// If an error label already exists for the bad input just update its text:
1062			if ($(labelSelector).length) {
1063				$(labelSelector).text(msg);
1064			}
1065
1066			// Otherwize create a new one and stick it after the input:
1067			else {
1068				$("<label/>").attr("for", getIdentifier($obj)).addClass($.validity.outputs.label.cssClass).text(msg)
1069
1070				// In the case that the element does not have an id
1071				// then the for attribute in the label will not cause
1072				// clicking the label to focus the element. This line
1073				// will make that happen.
1074				.click(function() {
1075					if ($obj.length) {
1076						$obj[0].select();
1077					}
1078				})
1079
1080				.insertAfter($obj);
1081			}
1082		},
1083
1084		raiseAggregate : function($obj, msg) {
1085			// Just raise the error on the last input.
1086			if ($obj.length) {
1087				this.raise($($obj.get($obj.length - 1)), msg);
1088			}
1089		}
1090	};
1091})(jQuery);
1092
1093// Install the modal output.
1094(function($) {
1095	var
1096	// Class to apply to modal errors.
1097	errorClass = "validity-modal-msg",
1098
1099	// The selector for the element where modal errors will me injected semantically.
1100	container = "body";
1101
1102	$.validity.outputs.modal = {
1103		start : function() {
1104			// Remove all the existing errors.
1105			$("." + errorClass).remove();
1106		},
1107
1108		end : function(results) {
1109			// If not valid and scrollTo is enabled, scroll the page to the first error.
1110			if (!results.valid && $.validity.settings.scrollTo) {
1111				location.hash = $("." + errorClass + ":eq(0)").attr('id');
1112			}
1113		},
1114
1115		raise : function($obj, msg) {
1116			if ($obj.length) {
1117				var off = $obj.offset(), obj = $obj.get(0),
1118
1119				// Design a style object based off of the input's location.
1120				errorStyle = {
1121					left : parseInt(off.left + $obj.width() + 4, 10) + "px",
1122					top : parseInt(off.top - 10, 10) + "px"
1123				};
1124
1125				// Create one and position it next to the input.
1126				$("<div/>").addClass(errorClass).css(errorStyle).text(msg).click($.validity.settings.modalErrorsClickable ? function() {
1127					$(this).remove();
1128				} : null).appendTo(container);
1129			}
1130		},
1131
1132		raiseAggregate : function($obj, msg) {
1133			// Just raise the error on the last input.
1134			if ($obj.length) {
1135				this.raise($($obj.get($obj.length - 1)), msg);
1136			}
1137		}
1138	};
1139})(jQuery);
1140
1141// Install the summary output
1142(function($) {
1143	var
1144	// Container contains the summary. This is the element that is shown or hidden.
1145	container = ".validity-summary-container",
1146
1147	// Erroneous refers to an input with an invalid value,
1148	// not the error message itself.
1149	erroneous = "validity-erroneous",
1150
1151	// Selector for erroneous inputs.
1152	errors = "." + erroneous,
1153
1154	// The wrapper for entries in the summary.
1155	wrapper = "<li/>",
1156
1157	// Buffer to contain all the error messages that build up during validation.
1158	// When validation ends, it'll be flushed into the summary.
1159	// This way, the summary doesn't flicker empty then fill up.
1160	buffer = [];
1161
1162	$.validity.outputs.summary = {
1163		start : function() {
1164			$(errors).removeClass(erroneous);
1165			buffer = [];
1166		},
1167
1168		end : function(results) {
1169			// Hide the container and empty its summary.
1170			$(container).hide().find("ul").html('');
1171
1172			// If there are any errors at all:
1173			// (Otherwise the container shouldn't be shown):
1174			if (buffer.length) {
1175				// Use integer based iteration for solution to Issue 7.
1176				for ( var i = 0; i < buffer.length; ++i) {
1177					$(wrapper).text(buffer[i]).appendTo(container + " ul");
1178				}
1179
1180				$(container).show();
1181
1182				// If scrollTo is enabled, scroll the page to the first error.
1183				if ($.validity.settings.scrollTo) {
1184					location.hash = $(errors + ":eq(0)").attr("id");
1185				}
1186			}
1187		},
1188
1189		raise : function($obj, msg) {
1190			buffer.push(msg);
1191			$obj.addClass(erroneous);
1192		},
1193
1194		raiseAggregate : function($obj, msg) {
1195			this.raise($obj, msg);
1196		},
1197
1198		container : function() {
1199			document.write("<div class=\"validity-summary-container\">" + "The form didn't submit for the following reason(s):" + "<ul></ul>" + "</div>");
1200		}
1201	};
1202})(jQuery);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.