PageSourceSearch

https://satei-meijin.com/user_data/SpryAssets/SpryValidationTextField.js

js satei-meijin.com collected 2026-10-05 10:43:30 UTC 76,337 bytes, 2,379 lines download raw bytes

1// SpryValidationTextField.js - version 0.38 - Spry Pre-Release 1.6.1
2//
3// Copyright (c) 2006. Adobe Systems Incorporated.
4// All rights reserved.
5//
6// Redistribution and use in source and binary forms, with or without
7// modification, are permitted provided that the following conditions are met:
8//
9//   * Redistributions of source code must retain the above copyright notice,
10//     this list of conditions and the following disclaimer.
11//   * Redistributions in binary form must reproduce the above copyright notice,
12//     this list of conditions and the following disclaimer in the documentation
13//     and/or other materials provided with the distribution.
14//   * Neither the name of Adobe Systems Incorporated nor the names of its
15//     contributors may be used to endorse or promote products derived from this
16//     software without specific prior written permission.
17//
18// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28// POSSIBILITY OF SUCH DAMAGE.
29
30/* 更新履歴
31---------------------------------------------------*/
32// 14/09/24 1087行目:Firefoxで未変換の文字が確定されるバグを回避
33//
34
35(function() { // BeginSpryComponent
36
37if (typeof Spry == "undefined") window.Spry = {}; if (!Spry.Widget) Spry.Widget = {};
38
39Spry.Widget.BrowserSniff = function()
40{
41	var b = navigator.appName.toString();
42	var up = navigator.platform.toString();
43	var ua = navigator.userAgent.toString();
44
45	this.mozilla = this.ie = this.opera = this.safari = false;
46	var re_opera = /Opera.([0-9\.]*)/i;
47	var re_msie = /MSIE.([0-9\.]*)/i;
48	var re_gecko = /gecko/i;
49	var re_safari = /(applewebkit|safari)\/([\d\.]*)/i;
50	var r = false;
51
52	if ( (r = ua.match(re_opera))) {
53		this.opera = true;
54		this.version = parseFloat(r[1]);
55	} else if ( (r = ua.match(re_msie))) {
56		this.ie = true;
57		this.version = parseFloat(r[1]);
58	} else if ( (r = ua.match(re_safari))) {
59		this.safari = true;
60		this.version = parseFloat(r[2]);
61	} else if (ua.match(re_gecko)) {
62		var re_gecko_version = /rv:\s*([0-9\.]+)/i;
63		r = ua.match(re_gecko_version);
64		this.mozilla = true;
65		this.version = parseFloat(r[1]);
66	}
67	this.windows = this.mac = this.linux = false;
68
69	this.Platform = ua.match(/windows/i) ? "windows" :
70					(ua.match(/linux/i) ? "linux" :
71					(ua.match(/mac/i) ? "mac" :
72					ua.match(/unix/i)? "unix" : "unknown"));
73	this[this.Platform] = true;
74	this.v = this.version;
75
76	if (this.safari && this.mac && this.mozilla) {
77		this.mozilla = false;
78	}
79};
80
81Spry.is = new Spry.Widget.BrowserSniff();
82
83Spry.Widget.ValidationTextField = function(element, type, options)
84{
85	type = Spry.Widget.Utils.firstValid(type, "none");
86	if (typeof type != 'string') {
87		this.showError('The second parameter in the constructor should be the validation type, the options are the third parameter.');
88		return;
89	}
90	if (typeof Spry.Widget.ValidationTextField.ValidationDescriptors[type] == 'undefined') {
91		this.showError('Unknown validation type received as the second parameter.');
92		return;
93	}
94	options = Spry.Widget.Utils.firstValid(options, {});
95	this.type = type;
96	if (!this.isBrowserSupported()) {
97		//disable character masking and pattern behaviors for low level browsers
98		options.useCharacterMasking = false;
99	}
100	this.init(element, options);
101
102	//make sure we validate at least on submit
103	var validateOn = ['submit'].concat(Spry.Widget.Utils.firstValid(this.options.validateOn, []));
104	validateOn = validateOn.join(",");
105
106	this.validateOn = 0;
107	this.validateOn = this.validateOn | (validateOn.indexOf('submit') != -1 ? Spry.Widget.ValidationTextField.ONSUBMIT : 0);
108	this.validateOn = this.validateOn | (validateOn.indexOf('blur') != -1 ? Spry.Widget.ValidationTextField.ONBLUR : 0);
109	this.validateOn = this.validateOn | (validateOn.indexOf('change') != -1 ? Spry.Widget.ValidationTextField.ONCHANGE : 0);
110
111	if (Spry.Widget.ValidationTextField.onloadDidFire)
112		this.attachBehaviors();
113	else
114		Spry.Widget.ValidationTextField.loadQueue.push(this);
115};
116
117Spry.Widget.ValidationTextField.ONCHANGE = 1;
118Spry.Widget.ValidationTextField.ONBLUR = 2;
119Spry.Widget.ValidationTextField.ONSUBMIT = 4;
120
121Spry.Widget.ValidationTextField.ERROR_REQUIRED = 1;
122Spry.Widget.ValidationTextField.ERROR_FORMAT = 2;
123Spry.Widget.ValidationTextField.ERROR_RANGE_MIN = 4;
124Spry.Widget.ValidationTextField.ERROR_RANGE_MAX = 8;
125Spry.Widget.ValidationTextField.ERROR_CHARS_MIN = 16;
126Spry.Widget.ValidationTextField.ERROR_CHARS_MAX = 32;
127
128/* validation parameters:
129 *  - characterMasking : prevent typing of characters not matching an regular expression
130 *  - regExpFilter : additional regular expression to disalow typing of characters 
131 *		(like the "-" sign in the middle of the value); use for partial matching of the currently typed value;
132 * 		the typed value must match regExpFilter at any moment
133 *  - pattern : enforce character on each position inside a pattern (AX0?)
134 *  - validation : function performing logic validation; return false if failed and the typedValue value on success
135 *  - minValue, maxValue : range validation; check if typedValue inside the specified range
136 *  - minChars, maxChars : value length validation; at least/at most number of characters
137 * */
138Spry.Widget.ValidationTextField.ValidationDescriptors = {
139	'none': {
140	},
141	'custom': {
142	},
143	'integer': {
144		characterMasking: /[\-\+\d]/,
145		regExpFilter: /^[\-\+]?\d*$/,
146		validation: function(value, options) {
147			if (value == '' || value == '-' || value == '+') {
148				return false;
149			}
150			var regExp = /^[\-\+]?\d*$/;
151			if (!regExp.test(value)) {
152				return false;
153			}
154			options = options || {allowNegative:false};
155			var ret = parseInt(value, 10);
156			if (!isNaN(ret)) {
157				var allowNegative = true;
158				if (typeof options.allowNegative != 'undefined' && options.allowNegative == false) {
159					allowNegative = false;
160				}
161				if (!allowNegative && value < 0) {
162					ret = false;
163				}
164			} else {
165				ret = false;
166			}
167			return ret;
168		}
169	},
170	'real': {
171		characterMasking: /[\d\.,\-\+e]/i,
172		regExpFilter: /^[\-\+]?\d(?:|\.,\d{0,2})|(?:|e{0,1}[\-\+]?\d{0,})$/i,
173		validation: function (value, options) {
174			var regExp = /^[\+\-]?[0-9]+([\.,][0-9]+)?([eE]{0,1}[\-\+]?[0-9]+)?$/;
175			if (!regExp.test(value)) {
176				return false;
177			}
178			var ret = parseFloat(value);
179			if (isNaN(ret)) {
180				ret = false;
181			}
182			return ret;
183		}
184	},
185	'currency': {
186		formats: {
187			'dot_comma': {
188				characterMasking: /[\d\.\,\-\+\$]/,
189				regExpFilter: /^[\-\+]?(?:[\d\.]*)+(|\,\d{0,2})$/,
190				validation: function(value, options) {
191					var ret = false;
192					//2 or no digits after the comma
193					if (/^(\-|\+)?\d{1,3}(?:\.\d{3})*(?:\,\d{2}|)$/.test(value) || /^(\-|\+)?\d+(?:\,\d{2}|)$/.test(value)) {
194						value = value.toString().replace(/\./gi, '').replace(/\,/, '.');
195						ret = parseFloat(value);
196					}
197					return ret;
198				}
199			},
200			'comma_dot': {
201				characterMasking: /[\d\.\,\-\+\$]/,
202				regExpFilter: /^[\-\+]?(?:[\d\,]*)+(|\.\d{0,2})$/,
203				validation: function(value, options) {
204					var ret = false;
205					//2 or no digits after the comma
206					if (/^(\-|\+)?\d{1,3}(?:\,\d{3})*(?:\.\d{2}|)$/.test(value) || /^(\-|\+)?\d+(?:\.\d{2}|)$/.test(value)) {
207						value = value.toString().replace(/\,/gi, '');
208						ret = parseFloat(value);
209					}
210					return ret;
211				}
212			}
213		}
214	},
215	'email': {
216		characterMasking: /[^\s]/,
217		validation: function(value, options) {
218			var rx = /^[\w\.-]+@[\w\.-]+\.\w+$/i;
219			return rx.test(value);
220		}
221	},
222	'date': {
223		validation: function(value, options) {
224			var formatRegExp = /^([mdy]+)[\.\-\/\\\s]+([mdy]+)[\.\-\/\\\s]+([mdy]+)$/i;
225			var valueRegExp = this.dateValidationPattern;
226			var formatGroups = options.format.match(formatRegExp);
227			var valueGroups = value.match(valueRegExp);
228			if (formatGroups !== null && valueGroups !== null) {
229				var dayIndex = -1;
230				var monthIndex = -1;
231				var yearIndex = -1;
232				for (var i=1; i<formatGroups.length; i++) {
233					switch (formatGroups[i].toLowerCase()) {
234						case "dd":
235							dayIndex = i;
236							break;
237						case "mm":
238							monthIndex = i;
239							break;
240						case "yy":
241						case "yyyy":
242							yearIndex = i;
243							break;
244					}
245				}
246				if (dayIndex != -1 && monthIndex != -1 && yearIndex != -1) {
247					var maxDay = -1;
248					var theDay = parseInt(valueGroups[dayIndex], 10);
249					var theMonth = parseInt(valueGroups[monthIndex], 10);
250					var theYear = parseInt(valueGroups[yearIndex], 10);
251
252					// Check month value to be between 1..12
253					if (theMonth < 1 || theMonth > 12) {
254						return false;
255					}
256					
257					// Calculate the maxDay according to the current month
258					switch (theMonth) {
259						case 1:	// January
260						case 3: // March
261						case 5: // May
262						case 7: // July
263						case 8: // August
264						case 10: // October
265						case 12: // December
266							maxDay = 31;
267							break;
268						case 4:	// April
269						case 6: // June
270						case 9: // September
271						case 11: // November
272							maxDay = 30;
273							break;
274						case 2: // February
275							if ((parseInt(theYear/4, 10) * 4 == theYear) && (theYear % 100 != 0 || theYear % 400 == 0)) {
276								maxDay = 29;
277							} else {
278								maxDay = 28;
279							}
280							break;
281					}
282
283					// Check day value to be between 1..maxDay
284					if (theDay < 1 || theDay > maxDay) {
285						return false;
286					}
287					
288					// If successfull we'll return the date object
289					return (new Date(theYear, theMonth - 1, theDay));   //JavaScript requires a month between 0 and 11
290				}
291			} else {
292				return false;
293			}
294		}
295	},
296	'time': {
297		validation: function(value, options) {
298			//	HH:MM:SS T
299			var formatRegExp = /([hmst]+)/gi;
300			var valueRegExp = /(\d+|AM?|PM?)/gi;
301			var formatGroups = options.format.match(formatRegExp);
302			var valueGroups = value.match(valueRegExp);
303			//mast match and have same length
304			if (formatGroups !== null && valueGroups !== null) {
305				if (formatGroups.length != valueGroups.length) {
306					return false;
307				}
308
309				var hourIndex = -1;
310				var minuteIndex = -1;
311				var secondIndex = -1;
312				//T is AM or PM
313				var tIndex = -1;
314				var theHour = 0, theMinute = 0, theSecond = 0, theT = 'AM';
315				for (var i=0; i<formatGroups.length; i++) {
316					switch (formatGroups[i].toLowerCase()) {
317						case "hh":
318							hourIndex = i;
319							break;
320						case "mm":
321							minuteIndex = i;
322							break;
323						case "ss":
324							secondIndex = i;
325							break;
326						case "t":
327						case "tt":
328							tIndex = i;
329							break;
330					}
331				}
332				if (hourIndex != -1) {
333					var theHour = parseInt(valueGroups[hourIndex], 10);
334					if (isNaN(theHour) || theHour > (formatGroups[hourIndex] == 'HH' ? 23 : 12 )) {
335						return false;
336					}
337				}
338				if (minuteIndex != -1) {
339					var theMinute = parseInt(valueGroups[minuteIndex], 10);
340					if (isNaN(theMinute) || theMinute > 59) {
341						return false;
342					}
343				}
344				if (secondIndex != -1) {
345					var theSecond = parseInt(valueGroups[secondIndex], 10);
346					if (isNaN(theSecond) || theSecond > 59) {
347						return false;
348					}
349				}
350				if (tIndex != -1) {
351					var theT = valueGroups[tIndex].toUpperCase();
352					if (
353						formatGroups[tIndex].toUpperCase() == 'TT' && !/^a|pm$/i.test(theT) || 
354						formatGroups[tIndex].toUpperCase() == 'T' && !/^a|p$/i.test(theT)
355					) {
356						return false;
357					}
358				}
359				var date = new Date(2000, 0, 1, theHour + (theT.charAt(0) == 'P'?12:0), theMinute, theSecond);
360				return date;
361			} else {
362				return false;
363			}
364		}
365	},
366	'credit_card': {
367		characterMasking: /\d/,
368		validation: function(value, options) {
369			var regExp = null;
370			options.format = options.format || 'ALL';
371			switch (options.format.toUpperCase()) {
372				case 'ALL': regExp = /^[3-6]{1}[0-9]{12,18}$/; break;
373				case 'VISA': regExp = /^4(?:[0-9]{12}|[0-9]{15})$/; break;
374				case 'MASTERCARD': regExp = /^5[1-5]{1}[0-9]{14}$/; break;
375				case 'AMEX': regExp = /^3(4|7){1}[0-9]{13}$/; break;
376				case 'DISCOVER': regExp = /^6011[0-9]{12}$/; break;
377				case 'DINERSCLUB': regExp = /^3(?:(0[0-5]{1}[0-9]{11})|(6[0-9]{12})|(8[0-9]{12}))$/; break;
378			}
379			if (!regExp.test(value)) {
380				return false;
381			}
382			var digits = [];
383			var j = 1, digit = '';
384			for (var i = value.length - 1; i >= 0; i--) {
385				if ((j%2) == 0) {
386					digit = parseInt(value.charAt(i), 10) * 2;
387					digits[digits.length] = digit.toString().charAt(0);
388					if (digit.toString().length == 2) {
389						digits[digits.length] = digit.toString().charAt(1);
390					}
391				} else {
392					digit = value.charAt(i);
393					digits[digits.length] = digit;
394				}
395				j++;
396			}
397			var sum = 0;
398			for(i=0; i < digits.length; i++ ) {
399				sum += parseInt(digits[i], 10);
400			}
401			if ((sum%10) == 0) {
402				return true;
403			}
404			return false;
405		}
406	},
407	'zip_code': {
408		formats: {
409			'zip_us9': {
410				pattern:'00000-0000'
411			},
412			'zip_us5': {
413				pattern:'00000'
414			},
415			'zip_uk': {
416				characterMasking: /[\dA-Z\s]/,
417				validation: function(value, options) {
418					//check one of the following masks
419					// AN NAA, ANA NAA, ANN NAA, AAN NAA, AANA NAA, AANN NAA
420					return /^[A-Z]{1,2}\d[\dA-Z]?\s?\d[A-Z]{2}$/.test(value);
421				}
422			},
423			'zip_canada': {
424				characterMasking: /[\dA-Z\s]/,
425				pattern: 'A0A 0A0'
426			},
427			'zip_custom': {}
428		}
429	},
430	'phone_number': {
431		formats: {
432			//US phone number; 10 digits
433			'phone_us': {
434				pattern:'(000) 000-0000'
435			},
436			'phone_custom': {}
437		}
438	},
439	'social_security_number': {
440		pattern:'000-00-0000'
441	},
442	'ip': {
443		characterMaskingFormats: {
444			'ipv4': /[\d\.]/i,
445			'ipv6_ipv4': /[\d\.\:A-F\/]/i,
446			'ipv6': /[\d\.\:A-F\/]/i
447		},
448		validation: function (value, options) {
449			return Spry.Widget.ValidationTextField.validateIP(value, options.format);
450		}
451	},
452
453	'url': {
454		characterMasking: /[^\s]/,
455		validation: function(value, options) {
456			//fix for ?ID=223429 and ?ID=223387
457			/* the following regexp matches components of an URI as specified in http://tools.ietf.org/html/rfc3986#page-51 page 51, Appendix B.
458				scheme    = $2
459				authority = $4
460				path      = $5
461				query     = $7
462				fragment  = $9
463			*/
464			var URI_spliter = /^(([^:\/?#]+):)?(\/\/([^\/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?/;
465			var parts = value.match(URI_spliter);
466			if (parts && parts[4]) {
467				//encode each component of the domain name using Punycode encoding scheme: http://tools.ietf.org/html/rfc3492
468				var host  = parts[4].split(".");
469				var punyencoded = '';
470				for (var i=0; i<host.length; i++) {
471					punyencoded = Spry.Widget.Utils.punycode_encode(host[i], 64);
472					if (!punyencoded) {
473						return false;
474					} else {
475						if (punyencoded != (host[i] + "-")) {
476							host[i] = 'xn--' + punyencoded;
477						}
478					}
479				}
480				host = host .join(".");
481				//the encoded domain name is replaced into the original URL to be validated again later as URL
482				value = value.replace(URI_spliter, "$1//" + host + "$5$6$8");
483			}
484
485			//fix for ?ID=223358 and ?ID=223594
486			//the following validates an URL using ABNF rules as defined in http://tools.ietf.org/html/rfc3986 , Appendix A., page 49
487			//except host which is extracted by match[1] and validated separately
488			/*
489			 * userinfo=	(?:(?:[a-z0-9\-\._~\!\$\&\'\(\)\*\+\,\;\=:]|%[0-9a-f]{2,2})*\@)?
490			 * host=			(?:((?:(?:[a-z0-9][a-z0-9\-]*[a-z0-9]|[a-z0-9])\.)*(?:[a-z][a-z0-9\-]*[a-z0-9]|[a-z])|(?:\[[^\]]*\]))
491			 * pathname=	(?:\/(?:[a-z0-9\-\._~\!\$\&\'\(\)\*\+\,\;\=\:\@]|%[0-9a-f]{2,2})*)*
492			 * query=			(?:\?(?:[a-z0-9\-\._~\!\$\&\'\(\)\*\+\,\;\=\:\@\/\?]|%[0-9a-f]{2,2})*)?
493			 * anchor=		(?:\#(?:[a-z0-9\-\._~\!\$\&\'\(\)\*\+\,\;\=\:\@\/\?]|%[0-9a-f]{2,2})*)?
494			 */
495			var regExp = /^(?:https?|ftp)\:\/\/(?:(?:[a-z0-9\-\._~\!\$\&\'\(\)\*\+\,\;\=:]|%[0-9a-f]{2,2})*\@)?(?:((?:(?:[a-z0-9][a-z0-9\-]*[a-z0-9]|[a-z0-9])\.)*(?:[a-z][a-z0-9\-]*[a-z0-9]|[a-z])|(?:\[[^\]]*\]))(?:\:[0-9]*)?)(?:\/(?:[a-z0-9\-\._~\!\$\&\'\(\)\*\+\,\;\=\:\@]|%[0-9a-f]{2,2})*)*(?:\?(?:[a-z0-9\-\._~\!\$\&\'\(\)\*\+\,\;\=\:\@\/\?]|%[0-9a-f]{2,2})*)?(?:\#(?:[a-z0-9\-\._~\!\$\&\'\(\)\*\+\,\;\=\:\@\/\?]|%[0-9a-f]{2,2})*)?$/i;
496
497			var valid = value.match(regExp);
498			if (valid) {
499				//extract the  address from URL
500				var address = valid[1];
501
502				if (address) {
503					if (address == '[]') {
504						return false;
505					}
506					if (address.charAt(0) == '[' ) {
507						//IPv6 address or IPv4 enclosed in square brackets
508						address = address.replace(/^\[|\]$/gi, '');
509						return Spry.Widget.ValidationTextField.validateIP(address, 'ipv6_ipv4');
510					} else {
511						if (/[^0-9\.]/.test(address)) {
512							return true;
513						} else {
514							//check if hostname is all digits and dots and then check for IPv4
515							return Spry.Widget.ValidationTextField.validateIP(address, 'ipv4');
516						}
517					}
518				} else {
519					return true;
520				}
521			} else {
522				return false;
523			}
524		}
525	}
526};
527
528/*
5292.2.1. Preferred
530x:x:x:x:x:x:x:x, where the 'x's are the hexadecimal values of the eight 16-bit pieces of the address.
531Examples:
532	FEDC:BA98:7654:3210:FEDC:BA98:7654:3210
533	1080:0:0:0:8:800:200C:417A
534Note that it is not necessary to write the leading zeros in an
535individual field, but there must be at least one numeral in every
536field (except for the case described in 2.2.2.).
537
5382.2.2. Compressed
539The use of "::" indicates multiple groups of 16-bits of zeros.
540The "::" can only appear once in an address.  The "::" can also be
541used to compress the leading and/or trailing zeros in an address.
542	1080:0:0:0:8:800:200C:417A --> 1080::8:800:200C:417A
543	FF01:0:0:0:0:0:0:101 --> FF01::101
544	0:0:0:0:0:0:0:1 --> ::1
545	0:0:0:0:0:0:0:0 --> ::
546
5472.5.4 IPv6 Addresses with Embedded IPv4 Addresses
548	IPv4-compatible IPv6 address (tunnel IPv6 packets over IPv4 routing infrastructures)
549	::0:129.144.52.38
550	IPv4-mapped IPv6 address (represent the addresses of IPv4-only nodes as IPv6 addresses)
551	::ffff:129.144.52.38
552
553The text representation of IPv6 addresses and prefixes in Augmented BNF (Backus-Naur Form) [ABNF] for reference purposes.
554[ABNF http://tools.ietf.org/html/rfc2234]
555      IPv6address = hexpart [ ":" IPv4address ]
556      IPv4address = 1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT
557
558      IPv6prefix  = hexpart "/" 1*2DIGIT
559
560      hexpart = hexseq | hexseq "::" [ hexseq ] | "::" [ hexseq ]
561      hexseq  = hex4 *( ":" hex4)
562      hex4    = 1*4HEXDIG
563*/
564Spry.Widget.ValidationTextField.validateIP = function (value, format)
565{
566	var validIPv6Addresses = [
567		//preferred
568		/^(?:[a-f0-9]{1,4}:){7}[a-f0-9]{1,4}(?:\/\d{1,3})?$/i,
569
570		//various compressed
571		/^[a-f0-9]{0,4}::(?:\/\d{1,3})?$/i,
572		/^:(?::[a-f0-9]{1,4}){1,6}(?:\/\d{1,3})?$/i,
573		/^(?:[a-f0-9]{1,4}:){1,6}:(?:\/\d{1,3})?$/i,
574		/^(?:[a-f0-9]{1,4}:)(?::[a-f0-9]{1,4}){1,6}(?:\/\d{1,3})?$/i,
575		/^(?:[a-f0-9]{1,4}:){2}(?::[a-f0-9]{1,4}){1,5}(?:\/\d{1,3})?$/i,
576		/^(?:[a-f0-9]{1,4}:){3}(?::[a-f0-9]{1,4}){1,4}(?:\/\d{1,3})?$/i,
577		/^(?:[a-f0-9]{1,4}:){4}(?::[a-f0-9]{1,4}){1,3}(?:\/\d{1,3})?$/i,
578		/^(?:[a-f0-9]{1,4}:){5}(?::[a-f0-9]{1,4}){1,2}(?:\/\d{1,3})?$/i,
579		/^(?:[a-f0-9]{1,4}:){6}(?::[a-f0-9]{1,4})(?:\/\d{1,3})?$/i,
580
581
582		//IPv6 mixes with IPv4
583		/^(?:[a-f0-9]{1,4}:){6}(?:\d{1,3}\.){3}\d{1,3}(?:\/\d{1,3})?$/i,
584		/^:(?::[a-f0-9]{1,4}){0,4}:(?:\d{1,3}\.){3}\d{1,3}(?:\/\d{1,3})?$/i,
585		/^(?:[a-f0-9]{1,4}:){1,5}:(?:\d{1,3}\.){3}\d{1,3}(?:\/\d{1,3})?$/i,
586		/^(?:[a-f0-9]{1,4}:)(?::[a-f0-9]{1,4}){1,4}:(?:\d{1,3}\.){3}\d{1,3}(?:\/\d{1,3})?$/i,
587		/^(?:[a-f0-9]{1,4}:){2}(?::[a-f0-9]{1,4}){1,3}:(?:\d{1,3}\.){3}\d{1,3}(?:\/\d{1,3})?$/i,	
588		/^(?:[a-f0-9]{1,4}:){3}(?::[a-f0-9]{1,4}){1,2}:(?:\d{1,3}\.){3}\d{1,3}(?:\/\d{1,3})?$/i,
589		/^(?:[a-f0-9]{1,4}:){4}(?::[a-f0-9]{1,4}):(?:\d{1,3}\.){3}\d{1,3}(?:\/\d{1,3})?$/i
590	];
591	var validIPv4Addresses = [
592		//IPv4
593		/^(\d{1,3}\.){3}\d{1,3}$/i
594	];
595	var validAddresses = [];
596	if (format == 'ipv6' || format == 'ipv6_ipv4') {
597		validAddresses = validAddresses.concat(validIPv6Addresses);
598	}
599	if (format == 'ipv4' || format == 'ipv6_ipv4') {
600		validAddresses = validAddresses.concat(validIPv4Addresses);
601	}
602
603	var ret = false;
604	for (var i=0; i<validAddresses.length; i++) {
605		if (validAddresses[i].test(value)) {
606			ret = true;
607			break;
608		}
609	}
610
611	if (ret && value.indexOf(".") != -1) {
612		//if address contains IPv4 fragment, it must be valid; all 4 groups must be less than 256
613		var ipv4 = value.match(/:?(?:\d{1,3}\.){3}\d{1,3}/i);
614		if(!ipv4) {
615			return false;
616		}
617		ipv4 = ipv4[0].replace(/^:/, '');
618		var pieces = ipv4.split('.');
619		if (pieces.length != 4) {
620			return false;
621		}
622		var regExp = /^[\-\+]?\d*$/;
623		for (var i=0; i< pieces.length; i++) {
624			if (pieces[i] == '') {
625				return false;
626			}
627			var piece = parseInt(pieces[i], 10);
628			if (isNaN(piece) || piece > 255 || !regExp.test(pieces[i]) || pieces[i].length>3 || /^0{2,3}$/.test(pieces[i])) {
629				return false;
630			}
631		}
632	}
633	if (ret && value.indexOf("/") != -1) {
634		// if prefix-length is specified must be in [1-128]
635		var prefLen = value.match(/\/\d{1,3}$/);
636		if (!prefLen) return false;
637		var prefLenVal = parseInt(prefLen[0].replace(/^\//,''), 10);
638		if (isNaN(prefLenVal) || prefLenVal > 128 || prefLenVal < 1) {
639			return false;
640		}
641	}
642	return ret;
643};
644
645Spry.Widget.ValidationTextField.onloadDidFire = false;
646Spry.Widget.ValidationTextField.loadQueue = [];
647
648Spry.Widget.ValidationTextField.prototype.isBrowserSupported = function()
649{
650	return Spry.is.ie && Spry.is.v >= 5 && Spry.is.windows
651		||
652	Spry.is.mozilla && Spry.is.v >= 1.4
653		||
654	Spry.is.safari
655		||
656	Spry.is.opera && Spry.is.v >= 9;
657};
658
659Spry.Widget.ValidationTextField.prototype.init = function(element, options)
660{
661	this.element = this.getElement(element);
662	this.errors = 0;
663	this.flags = {locked: false, restoreSelection: true};
664	this.options = {};
665	this.event_handlers = [];
666
667	this.validClass = "textfieldValidState";
668	this.focusClass = "textfieldFocusState";
669	this.requiredClass = "textfieldRequiredState";
670	this.hintClass = "textfieldHintState";
671	this.invalidFormatClass = "textfieldInvalidFormatState";
672	this.invalidRangeMinClass = "textfieldMinValueState";
673	this.invalidRangeMaxClass = "textfieldMaxValueState";
674	this.invalidCharsMinClass = "textfieldMinCharsState";
675	this.invalidCharsMaxClass = "textfieldMaxCharsState";
676	this.textfieldFlashTextClass = "textfieldFlashText";
677	if (Spry.is.safari) {
678		this.flags.lastKeyPressedTimeStamp = 0;
679	}
680
681	switch (this.type) {
682		case 'phone_number':options.format = Spry.Widget.Utils.firstValid(options.format, 'phone_us');break;
683		case 'currency':options.format = Spry.Widget.Utils.firstValid(options.format, 'comma_dot');break;
684		case 'zip_code':options.format = Spry.Widget.Utils.firstValid(options.format, 'zip_us5');break;
685		case 'date':
686			options.format = Spry.Widget.Utils.firstValid(options.format, 'mm/dd/yy');
687			break;
688		case 'time':
689			options.format = Spry.Widget.Utils.firstValid(options.format, 'HH:mm');
690			options.pattern = options.format.replace(/[hms]/gi, "0").replace(/TT/gi, 'AM').replace(/T/gi, 'A');
691			break;
692		case 'ip':
693			options.format = Spry.Widget.Utils.firstValid(options.format, 'ipv4');
694			options.characterMasking = Spry.Widget.ValidationTextField.ValidationDescriptors[this.type].characterMaskingFormats[options.format]; 
695			break;
696	}
697
698	//retrieve the validation type descriptor to be used with this instance (base on type and format)
699	//widgets may have different validations depending on format (like zip_code with formats)
700	var validationDescriptor = {};
701	if (options.format && Spry.Widget.ValidationTextField.ValidationDescriptors[this.type].formats) {
702		if (Spry.Widget.ValidationTextField.ValidationDescriptors[this.type].formats[options.format]) {
703			Spry.Widget.Utils.setOptions(validationDescriptor, Spry.Widget.ValidationTextField.ValidationDescriptors[this.type].formats[options.format]);
704		}
705	} else {
706		Spry.Widget.Utils.setOptions(validationDescriptor, Spry.Widget.ValidationTextField.ValidationDescriptors[this.type]);
707	}
708
709	//set default values for some parameters which were not aspecified
710	options.useCharacterMasking = Spry.Widget.Utils.firstValid(options.useCharacterMasking, false);
711	options.hint = Spry.Widget.Utils.firstValid(options.hint, '');
712	options.isRequired = Spry.Widget.Utils.firstValid(options.isRequired, true);
713	options.additionalError = Spry.Widget.Utils.firstValid(options.additionalError, false);
714	if (options.additionalError)
715		options.additionalError = this.getElement(options.additionalError);
716
717	//set widget validation parameters
718	//get values from validation type descriptor
719	//use the user specified values, if defined
720	options.characterMasking = Spry.Widget.Utils.firstValid(options.characterMasking, validationDescriptor.characterMasking);
721	options.regExpFilter = Spry.Widget.Utils.firstValid(options.regExpFilter, validationDescriptor.regExpFilter);
722	options.pattern = Spry.Widget.Utils.firstValid(options.pattern, validationDescriptor.pattern);
723	options.validation = Spry.Widget.Utils.firstValid(options.validation, validationDescriptor.validation);
724	if (typeof options.validation == 'string') {
725		options.validation = eval(options.validation);
726	}
727
728	options.minValue = Spry.Widget.Utils.firstValid(options.minValue, validationDescriptor.minValue);
729	options.maxValue = Spry.Widget.Utils.firstValid(options.maxValue, validationDescriptor.maxValue);
730
731	options.minChars = Spry.Widget.Utils.firstValid(options.minChars, validationDescriptor.minChars);
732	options.maxChars = Spry.Widget.Utils.firstValid(options.maxChars, validationDescriptor.maxChars);
733
734	Spry.Widget.Utils.setOptions(this, options);
735	Spry.Widget.Utils.setOptions(this.options, options);
736};
737
738Spry.Widget.ValidationTextField.prototype.destroy = function() {
739	if (this.event_handlers)
740		for (var i=0; i<this.event_handlers.length; i++) {
741			Spry.Widget.Utils.removeEventListener(this.event_handlers[i][0], this.event_handlers[i][1], this.event_handlers[i][2], false);
742		}
743	try { delete this.element; } catch(err) {}
744	try { delete this.input; } catch(err) {}
745	try { delete this.form; } catch(err) {}
746	try { delete this.event_handlers; } catch(err) {}
747	try { this.selection.destroy(); } catch(err) {}
748	try { delete this.selection; } catch(err) {}
749
750	var q = Spry.Widget.Form.onSubmitWidgetQueue;
751	var qlen = q.length;
752	for (var i = 0; i < qlen; i++) {
753		if (q[i] == this) {
754			q.splice(i, 1);
755			break;
756		}
757	}
758};
759
760Spry.Widget.ValidationTextField.prototype.attachBehaviors = function()
761{
762	if (this.element) {
763		if (this.element.nodeName == "INPUT") {
764			this.input = this.element;
765		} else {
766			this.input = Spry.Widget.Utils.getFirstChildWithNodeNameAtAnyLevel(this.element, "INPUT");
767		}
768	}
769
770	if (this.input) {
771		if (this.maxChars) {
772			this.input.removeAttribute("maxLength");
773		}
774		this.putHint();
775		this.compilePattern();
776		if (this.type == 'date') {
777			this.compileDatePattern();
778		}
779		this.input.setAttribute("AutoComplete", "off");
780		this.selection = new Spry.Widget.SelectionDescriptor(this.input);
781		this.oldValue = this.input.value;
782
783		var self = this;
784		this.event_handlers = [];
785
786		this.event_handlers.push([this.input, "keydown", function(e) { if (self.isDisabled()) return true; return self.onKeyDown(e || event); }]);
787		this.event_handlers.push([this.input, "keypress", function(e) { if (self.isDisabled()) return true; return self.onKeyPress(e || event); }]);
788		if (Spry.is.opera) {
789			this.event_handlers.push([this.input, "keyup", function(e) { if (self.isDisabled()) return true; return self.onKeyUp(e || event); }]);
790		}
791
792		this.event_handlers.push([this.input, "focus", function(e) { if (self.isDisabled()) return true; return self.onFocus(e || event); }]);
793		this.event_handlers.push([this.input, "blur", function(e) { if (self.isDisabled()) return true; return self.onBlur(e || event); }]);
794
795		this.event_handlers.push([this.input, "mousedown", function(e) { if (self.isDisabled()) return true; return self.onMouseDown(e || event); }]);
796
797		var changeEvent = 
798			Spry.is.mozilla || Spry.is.opera || Spry.is.safari?"input":
799			Spry.is.ie?"propertychange":
800			"change";
801		this.event_handlers.push([this.input, changeEvent, function(e) { if (self.isDisabled()) return true; return self.onChange(e || event); }]);
802
803		if (Spry.is.mozilla || Spry.is.safari) {
804			//oninput event on mozilla does not fire ondragdrop
805			this.event_handlers.push([this.input, "dragdrop", function(e) { if (self.isDisabled()) return true; self.removeHint();return self.onChange(e || event); }]);
806		} else if (Spry.is.ie){
807			//ondrop&onpropertychange crash on IE 
808			this.event_handlers.push([this.input, "drop", function(e) { if (self.isDisabled()) return true; return self.onDrop(e || event); }]);
809		}
810
811		for (var i=0; i<this.event_handlers.length; i++) {
812			Spry.Widget.Utils.addEventListener(this.event_handlers[i][0], this.event_handlers[i][1], this.event_handlers[i][2], false);
813		}
814
815		// submit
816		this.form = Spry.Widget.Utils.getFirstParentWithNodeName(this.input, "FORM");
817		if (this.form) {
818			// if no "onSubmit" handler has been attached to the current form, attach one
819			if (!this.form.attachedSubmitHandler && !this.form.onsubmit) {
820				this.form.onsubmit = function(e) { e = e || event; return Spry.Widget.Form.onSubmit(e, e.srcElement || e.currentTarget) };
821				this.form.attachedSubmitHandler = true;                 
822			}
823			if (!this.form.attachedResetHandler) {
824				Spry.Widget.Utils.addEventListener(this.form, "reset", function(e) { e = e || event; return Spry.Widget.Form.onReset(e, e.srcElement || e.currentTarget) }, false);
825				this.form.attachedResetHandler = true;                 
826			}
827			// add the currrent widget to the "onSubmit" check queue;
828			Spry.Widget.Form.onSubmitWidgetQueue.push(this);
829		}
830	}	
831};
832
833Spry.Widget.ValidationTextField.prototype.isDisabled = function() {
834	return this.input && (this.input.disabled || this.input.readOnly) || !this.input;
835};
836
837Spry.Widget.ValidationTextField.prototype.getElement = function(ele)
838{
839	if (ele && typeof ele == "string")
840		return document.getElementById(ele);
841	return ele;
842};
843
844Spry.Widget.ValidationTextField.addLoadListener = function(handler)
845{
846	if (typeof window.addEventListener != 'undefined')
847		window.addEventListener('load', handler, false);
848	else if (typeof document.addEventListener != 'undefined')
849		document.addEventListener('load', handler, false);
850	else if (typeof window.attachEvent != 'undefined')
851		window.attachEvent('onload', handler);
852};
853
854Spry.Widget.ValidationTextField.processLoadQueue = function(handler)
855{
856	Spry.Widget.ValidationTextField.onloadDidFire = true;
857	var q = Spry.Widget.ValidationTextField.loadQueue;
858	var qlen = q.length;
859	for (var i = 0; i < qlen; i++)
860		q[i].attachBehaviors();
861};
862
863Spry.Widget.ValidationTextField.addLoadListener(Spry.Widget.ValidationTextField.processLoadQueue);
864Spry.Widget.ValidationTextField.addLoadListener(function(){
865	Spry.Widget.Utils.addEventListener(window, "unload", Spry.Widget.Form.destroyAll, false);
866});
867
868Spry.Widget.ValidationTextField.prototype.setValue = function(newValue) {
869	this.flags.locked = true;
870	this.input.value = newValue;
871	this.flags.locked = false;
872	this.oldValue = newValue;
873	if (!Spry.is.ie) {
874		this.onChange();
875	}
876};
877
878/**
879 * save the state of the input (selection and value) so we can revert to it
880 * should call this just before modifying the input value
881 */
882Spry.Widget.ValidationTextField.prototype.saveState = function()
883{
884	this.oldValue = this.input.value;
885	this.selection.update();
886};
887
888Spry.Widget.ValidationTextField.prototype.revertState = function(revertValue)
889{
890	if (revertValue != this.input.value) {
891		this.input.readOnly = true;
892		this.input.value = revertValue;
893		this.input.readOnly = false;
894		if (Spry.is.safari && this.flags.active) {
895			this.input.focus();
896		}
897	}
898  if (this.flags.restoreSelection) {
899	this.selection.moveTo(this.selection.start, this.selection.end);
900  }
901
902	this.redTextFlash();
903};
904
905Spry.Widget.ValidationTextField.prototype.removeHint = function()
906{
907	if (this.flags.hintOn) {
908		this.input.value = "";
909		this.flags.hintOn = false;
910		this.removeClassName(this.element, this.hintClass);
911		this.removeClassName(this.additionalError, this.hintClass);
912	}
913};
914
915Spry.Widget.ValidationTextField.prototype.putHint = function()
916{
917	if(this.hint && this.input && this.input.type == "text" && this.input.value == "") {
918		this.flags.hintOn = true;
919		this.input.value = this.hint;
920		this.addClassName(this.element, this.hintClass);
921		this.addClassName(this.additionalError, this.hintClass);
922	}
923};
924
925Spry.Widget.ValidationTextField.prototype.redTextFlash = function()
926{
927	var self = this;
928	this.addClassName(this.element, this.textfieldFlashTextClass);
929	setTimeout(function() {
930		self.removeClassName(self.element, self.textfieldFlashTextClass)
931	}, 100);
932};
933
934Spry.Widget.ValidationTextField.prototype.doValidations = function(testValue, revertValue)
935{
936	if (this.isDisabled()) return false;
937
938	if (this.flags.locked) {
939		return false;
940	}
941
942	if (testValue.length == 0 && !this.isRequired) {
943		this.errors = 0;
944		return false;
945	}
946	this.flags.locked = true;
947
948	var mustRevert = false;
949	var continueValidations = true;
950	if (!this.options.isRequired && testValue.length == 0) {
951		continueValidations = false;
952	}
953
954	var errors = 0;
955	var fixedValue = testValue;
956
957	//characterMasking - test if all characters are valid with the characterMasking (keyboard filter)
958	if (this.useCharacterMasking && this.characterMasking) {
959		for(var i=0; i<testValue.length; i++) {
960			if (!this.characterMasking.test(testValue.charAt(i))) {
961				errors = errors | Spry.Widget.ValidationTextField.ERROR_FORMAT;
962				fixedValue = revertValue;
963				mustRevert = true;
964				break;
965			}
966		}
967	}
968
969	//regExpFilter - character mask positioning (additional mask to restrict some characters only in some position)
970	if (!mustRevert && this.useCharacterMasking && this.regExpFilter) {
971		if (!this.regExpFilter.test(fixedValue)) {
972			errors = errors | Spry.Widget.ValidationTextField.ERROR_FORMAT;
973			mustRevert = true;
974		}
975	}
976
977	//pattern - testValue matches the pattern so far
978	if (!mustRevert && this.pattern) {
979		var currentRegExp = this.patternToRegExp(testValue.length);
980		if (!currentRegExp.test(testValue)) {
981			errors = errors | Spry.Widget.ValidationTextField.ERROR_FORMAT;
982			mustRevert = true;
983		} else if (this.patternLength != testValue.length) {
984			//testValue matches pattern so far, but it's not ok if it does not have the proper length
985			//do not revert, but should show the error
986			errors = errors | Spry.Widget.ValidationTextField.ERROR_FORMAT;
987		}
988	}
989
990	if (fixedValue == '') {
991		errors = errors | Spry.Widget.ValidationTextField.ERROR_REQUIRED;
992	}
993
994	if (!mustRevert && this.pattern && this.useCharacterMasking) {
995		var n = this.getAutoComplete(testValue.length);
996		if (n) {
997			fixedValue += n;
998		}
999	}
1000
1001	if(!mustRevert && this.minChars !== null  && continueValidations) {
1002		if (testValue.length < this.minChars) {
1003			errors = errors | Spry.Widget.ValidationTextField.ERROR_CHARS_MIN;
1004			continueValidations = false;
1005		}
1006	}
1007
1008	if(!mustRevert && this.maxChars !== null && continueValidations) {
1009		if (testValue.length > this.maxChars) {
1010			errors = errors | Spry.Widget.ValidationTextField.ERROR_CHARS_MAX;
1011			continueValidations = false;
1012		}
1013	}
1014
1015	//validation - testValue passes widget validation function
1016	if (!mustRevert && this.validation && continueValidations) {
1017		var value = this.validation(fixedValue, this.options);
1018		if (false === value) {
1019			errors = errors | Spry.Widget.ValidationTextField.ERROR_FORMAT;
1020			continueValidations = false;
1021		} else {
1022			this.typedValue = value;
1023		}
1024	}
1025
1026	if(!mustRevert && this.validation && this.minValue !== null && continueValidations) {
1027		var minValue = this.validation(this.minValue.toString(), this.options);
1028		if (minValue !== false) {
1029			if (this.typedValue < minValue) {
1030				errors = errors | Spry.Widget.ValidationTextField.ERROR_RANGE_MIN;
1031				continueValidations = false;
1032			}
1033		}
1034	}
1035
1036	if(!mustRevert && this.validation && this.maxValue !== null && continueValidations) {
1037		var maxValue = this.validation(this.maxValue.toString(), this.options);
1038		if (maxValue !== false) {
1039			if( this.typedValue > maxValue) {
1040				errors = errors | Spry.Widget.ValidationTextField.ERROR_RANGE_MAX;
1041				continueValidations = false;
1042			}
1043		}
1044	}
1045
1046	//an invalid value was tested; must make sure it does not get inside the input
1047	if (this.useCharacterMasking && mustRevert) {
1048		this.revertState(revertValue);
1049	}
1050
1051	this.errors = errors;
1052	this.fixedValue = fixedValue;
1053
1054	this.flags.locked = false;
1055
1056	return mustRevert;
1057};
1058
1059Spry.Widget.ValidationTextField.prototype.onChange = function(e)
1060{
1061	if (Spry.is.opera && this.flags.operaRevertOnKeyUp) {
1062		return true;
1063	}
1064	if (Spry.is.ie && e && e.propertyName != 'value') {
1065		return true;
1066	}
1067	if (this.flags.drop) {
1068		//delay this if it's a drop operation
1069		var self = this;
1070		setTimeout(function() {
1071			self.flags.drop = false;
1072			self.onChange(null);
1073		}, 0);
1074		return;
1075	}
1076
1077	if (this.flags.hintOn) {
1078		return true;
1079	}
1080
1081	if (this.keyCode == 8 || this.keyCode == 46 ) {
1082		var mustRevert = this.doValidations(this.input.value, this.input.value);
1083		this.oldValue = this.input.value;
1084		if ((mustRevert || this.errors) && this.validateOn & Spry.Widget.ValidationTextField.ONCHANGE) {
1085			var self = this;
1086			setTimeout(function() {self.validate();}, 0);
1087			return true;
1088		}
1089	}
1090	
1091	var mustRevert = this.doValidations(this.input.value, this.oldValue);
1092	/* Firefoxの場合は無効に(未変換の文字が確定されるバグのため、removeClassのバグ?) */
1093	//if ((!mustRevert || this.errors) && this.validateOn & Spry.Widget.ValidationTextField.ONCHANGE) {
1094	if (!Spry.is.mozilla && (!mustRevert || this.errors) && this.validateOn & Spry.Widget.ValidationTextField.ONCHANGE) {
1095		var self = this;
1096		setTimeout(function() {self.validate();}, 0);
1097	}
1098	return true;
1099};
1100
1101Spry.Widget.ValidationTextField.prototype.onKeyUp = function(e) {
1102	if (this.flags.operaRevertOnKeyUp) {
1103		this.setValue(this.oldValue);
1104		Spry.Widget.Utils.stopEvent(e);
1105		this.selection.moveTo(this.selection.start, this.selection.start);
1106		this.flags.operaRevertOnKeyUp = false;
1107		return false;
1108	}
1109	if (this.flags.operaPasteOperation) {
1110		window.clearInterval(this.flags.operaPasteOperation);
1111		this.flags.operaPasteOperation = null;
1112	}
1113};
1114
1115Spry.Widget.ValidationTextField.prototype.operaPasteMonitor = function() {
1116	if (this.input.value != this.oldValue) {
1117		var mustRevert = this.doValidations(this.input.value, this.input.value);
1118		if (mustRevert) {
1119			this.setValue(this.oldValue);
1120			this.selection.moveTo(this.selection.start, this.selection.start);
1121		} else {
1122			this.onChange();
1123		}
1124	}
1125};
1126
1127
1128Spry.Widget.ValidationTextField.prototype.compileDatePattern = function () 
1129{
1130	var dateValidationPatternString = "";
1131	var groupPatterns = [];
1132	var fullGroupPatterns = [];
1133	var autocompleteCharacters = [];
1134	
1135	
1136	var formatRegExp = /^([mdy]+)([\.\-\/\\\s]+)([mdy]+)([\.\-\/\\\s]+)([mdy]+)$/i;
1137	var formatGroups = this.options.format.match(formatRegExp);
1138	if (formatGroups !== null) {
1139		for (var i=1; i<formatGroups.length; i++) {
1140			switch (formatGroups[i].toLowerCase()) {
1141				case "dd":
1142					groupPatterns[i-1] = "\\d{1,2}";
1143					fullGroupPatterns[i-1] = "\\d\\d";
1144					dateValidationPatternString += "(" + groupPatterns[i-1] + ")";
1145					autocompleteCharacters[i-1] = null;
1146					break;
1147				case "mm":
1148					groupPatterns[i-1] = "\\d{1,2}";
1149					fullGroupPatterns[i-1] = "\\d\\d";
1150					dateValidationPatternString += "(" + groupPatterns[i-1] + ")";
1151					autocompleteCharacters[i-1] = null;
1152					break;
1153				case "yy":
1154					groupPatterns[i-1] = "\\d{1,2}";
1155					fullGroupPatterns[i-1] = "\\d\\d";
1156					dateValidationPatternString += "(\\d\\d)";
1157					autocompleteCharacters[i-1] = null;
1158					break;
1159				case "yyyy":
1160					groupPatterns[i-1] = "\\d{1,4}";
1161					fullGroupPatterns[i-1] = "\\d\\d\\d\\d";
1162					dateValidationPatternString += "(\\d\\d\\d\\d)";
1163					autocompleteCharacters[i-1] = null;
1164					break;
1165				default:
1166					groupPatterns[i-1] = fullGroupPatterns[i-1] = Spry.Widget.ValidationTextField.regExpFromChars(formatGroups[i]);
1167					dateValidationPatternString += "["+ groupPatterns[i-1] + "]";
1168					autocompleteCharacters[i-1] = formatGroups[i];
1169			}
1170		}
1171	}
1172	this.dateValidationPattern = new RegExp("^" + dateValidationPatternString + "$" , "");
1173	this.dateAutocompleteCharacters = autocompleteCharacters;
1174	this.dateGroupPatterns = groupPatterns;
1175	this.dateFullGroupPatterns = fullGroupPatterns;
1176	this.lastDateGroup = formatGroups.length-2;
1177};
1178
1179Spry.Widget.ValidationTextField.prototype.getRegExpForGroup = function (group) 
1180{
1181	var ret = '^';
1182	for (var j = 0; j <= group; j++) ret += this.dateGroupPatterns[j];
1183	ret += '$';
1184	return new RegExp(ret, "");	
1185};
1186
1187Spry.Widget.ValidationTextField.prototype.getRegExpForFullGroup = function (group) 
1188{
1189	var ret = '^';
1190	for (var j = 0; j < group; j++) ret += this.dateGroupPatterns[j];
1191	ret += this.dateFullGroupPatterns[group];
1192	return new RegExp(ret, "");	
1193};
1194
1195Spry.Widget.ValidationTextField.prototype.getDateGroup = function(value, pos) 
1196{
1197	if (pos == 0) return 0;
1198	var test_value = value.substring(0, pos);
1199	for (var i=0; i <= this.lastDateGroup; i++) 
1200		if (this.getRegExpForGroup(i).test(test_value)) return i;
1201	return -1;
1202};
1203
1204
1205Spry.Widget.ValidationTextField.prototype.isDateGroupFull = function(value, group) 
1206{
1207	return this.getRegExpForFullGroup(group).test(value);
1208};
1209
1210Spry.Widget.ValidationTextField.prototype.isValueValid = function(value, pos, group) 
1211{
1212	var test_value = value.substring(0, pos);
1213	return this.getRegExpForGroup(group).test(test_value);
1214};
1215
1216
1217Spry.Widget.ValidationTextField.prototype.isPositionAtEndOfGroup = function (value, pos, group)
1218{
1219	var test_value = value.substring(0, pos);
1220	return this.getRegExpForFullGroup(group).test(test_value);
1221};
1222
1223Spry.Widget.ValidationTextField.prototype.nextDateDelimiterExists = function (value, pos, group)
1224{
1225	var autocomplete = this.dateAutocompleteCharacters[group+1];
1226	if (value.length < pos  + autocomplete.length) 
1227		return false;
1228	else 
1229	{
1230		var test_value = value.substring(pos, pos+autocomplete.length);
1231		if (test_value == autocomplete) 
1232			return true;
1233	}
1234	return false;
1235};
1236
1237
1238
1239Spry.Widget.ValidationTextField.prototype.onKeyPress = function(e)
1240{
1241	if (this.flags.skp) {
1242		this.flags.skp = false;
1243		Spry.Widget.Utils.stopEvent(e);
1244		return false;
1245	}
1246
1247	if (e.ctrlKey || e.metaKey || !this.useCharacterMasking) {
1248		return true;
1249	}
1250/*
1251	if (Spry.is.safari) {
1252		if ( (e.timeStamp - this.flags.lastKeyPressedTimeStamp)<10 ) {
1253			return true;
1254		}
1255		this.flags.lastKeyPressedTimeStamp = e.timeStamp;
1256	}
1257*/
1258	if (Spry.is.opera && this.flags.operaRevertOnKeyUp) {
1259		Spry.Widget.Utils.stopEvent(e);
1260		return false;
1261	}
1262
1263	if (this.keyCode == 8 || this.keyCode == 46) {
1264		var mr = this.doValidations(this.input.value, this.input.value);
1265		if (mr) {
1266			return true;
1267		}
1268	}
1269
1270	var pressed = Spry.Widget.Utils.getCharacterFromEvent(e);
1271
1272	if (pressed && this.characterMasking) {
1273		if (!this.characterMasking.test(pressed)) {
1274			Spry.Widget.Utils.stopEvent(e);
1275			this.redTextFlash();
1276			return false;
1277		}
1278	}
1279
1280	if(pressed && this.pattern) {
1281		var currentPatternChar = this.patternCharacters[this.selection.start];
1282		if (/[ax]/i.test(currentPatternChar)) {
1283			//convert the entered character to the pattern character case
1284			if (currentPatternChar.toLowerCase() == currentPatternChar) {
1285				pressed = pressed.toLowerCase();
1286			} else {
1287				pressed = pressed.toUpperCase();
1288			}
1289		}
1290
1291		var autocomplete = this.getAutoComplete(this.selection.start);
1292		if (this.selection.start == this.oldValue.length) {
1293			if (this.oldValue.length < this.patternLength) {
1294				if (autocomplete) {
1295					Spry.Widget.Utils.stopEvent(e);
1296					var futureValue = this.oldValue.substring(0, this.selection.start) + autocomplete + pressed;
1297					var mustRevert = this.doValidations(futureValue, this.oldValue);
1298					if (!mustRevert) {
1299						this.setValue(this.fixedValue);
1300						this.selection.moveTo(this.fixedValue.length, this.fixedValue.length);
1301					} else {
1302						this.setValue(this.oldValue.substring(0, this.selection.start) + autocomplete);
1303						this.selection.moveTo(this.selection.start + autocomplete.length, this.selection.start + autocomplete.length);
1304					}
1305					return false;
1306				}
1307			} else {
1308				Spry.Widget.Utils.stopEvent(e);
1309				this.setValue(this.input.value);
1310				return false;
1311			}
1312		} else if (autocomplete) {
1313			Spry.Widget.Utils.stopEvent(e);
1314			this.selection.moveTo(this.selection.start + autocomplete.length, this.selection.start + autocomplete.length);
1315			return false;
1316		}
1317
1318		Spry.Widget.Utils.stopEvent(e);
1319
1320		var futureValue = this.oldValue.substring(0, this.selection.start) + pressed + this.oldValue.substring(this.selection.start + 1);
1321		var mustRevert = this.doValidations(futureValue, this.oldValue);
1322
1323		if (!mustRevert) {
1324			autocomplete = this.getAutoComplete(this.selection.start + 1);
1325			this.setValue(this.fixedValue);
1326			this.selection.moveTo(this.selection.start + 1 + autocomplete.length, this.selection.start + 1 + autocomplete.length);
1327		} else {
1328			this.selection.moveTo(this.selection.start, this.selection.start);
1329		}
1330
1331		return false;
1332	}
1333	
1334	
1335	if (pressed && this.type == 'date' && this.useCharacterMasking) 
1336	{
1337		var group = this.getDateGroup(this.oldValue, this.selection.start);
1338		if (group != -1) {
1339			Spry.Widget.Utils.stopEvent(e);
1340			if ( (group % 2) !=0 ) 
1341				group ++;
1342			
1343			if (this.isDateGroupFull(this.oldValue, group)) 
1344			{
1345				if(this.isPositionAtEndOfGroup(this.oldValue, this.selection.start, group))
1346				{
1347					if(group == this.lastDateGroup) 
1348					{
1349						this.redTextFlash(); return false;
1350					}
1351					else 
1352					{
1353						// add or jump over autocomplete delimiter
1354						var autocomplete = this.dateAutocompleteCharacters[group+1];
1355						
1356						if (this.nextDateDelimiterExists(this.oldValue, this.selection.start, group))
1357						{
1358							var autocomplete = this.dateAutocompleteCharacters[group+1];
1359							
1360							this.selection.moveTo(this.selection.start + autocomplete.length, this.selection.start + autocomplete.length);
1361							if (pressed == autocomplete) 
1362								return false;
1363							
1364							if (this.isDateGroupFull(this.oldValue, group+2)) 
1365								// need to overwrite first char in the next digit group
1366								futureValue = this.oldValue.substring(0, this.selection.start) + pressed + this.oldValue.substring(this.selection.start + 1);
1367							else
1368								futureValue = this.oldValue.substring(0, this.selection.start) + pressed + this.oldValue.substring(this.selection.start);
1369								
1370							if (!this.isValueValid(futureValue, this.selection.start + 1, group +2 )) 
1371							{
1372								this.redTextFlash(); return false;						
1373							}
1374							else
1375							{
1376								this.setValue (futureValue);
1377								this.selection.moveTo(this.selection.start + 1, this.selection.start + 1);									
1378							}
1379							return false;					
1380						}
1381						else 
1382						{
1383							var autocomplete = this.dateAutocompleteCharacters[group+1];
1384							
1385							var insertedValue = autocomplete + pressed;
1386							futureValue = this.oldValue.substring(0, this.selection.start) + insertedValue + this.oldValue.substring(this.selection.start);
1387							if (!this.isValueValid(futureValue, this.selection.start + insertedValue.length, group +2 )) 
1388							{
1389								// block this type
1390								insertedValue = autocomplete;
1391								futureValue = this.oldValue.substring(0, this.selection.start) + insertedValue + this.oldValue.substring(this.selection.start);
1392								this.setValue (futureValue);
1393								this.selection.moveTo(this.selection.start + insertedValue.length, this.selection.start + insertedValue.length);									
1394								this.redTextFlash(); return false;
1395							}
1396							else 
1397							{
1398								this.setValue (futureValue);
1399								this.selection.moveTo(this.selection.start + insertedValue.length, this.selection.start + insertedValue.length);									
1400								return false;
1401							}
1402						}
1403						
1404					}
1405				}
1406				else
1407				{
1408					// it's not the end of the full digits group
1409					
1410					// overwrite
1411					var movePosition = 1;
1412					futureValue = this.oldValue.substring(0, this.selection.start) + pressed + this.oldValue.substring(this.selection.start + 1);
1413					if (!this.isValueValid(futureValue, this.selection.start + 1, group)) 
1414					{
1415						this.redTextFlash(); return false;
1416					}
1417					else 
1418					{
1419						if(this.isPositionAtEndOfGroup(futureValue, this.selection.start+1, group)) 
1420						{
1421							if (group != this.lastDateGroup)
1422							{
1423								if (this.nextDateDelimiterExists(futureValue, this.selection.start + 1, group))
1424								{
1425									var autocomplete = this.dateAutocompleteCharacters[group+1];
1426									movePosition = 1 + autocomplete.length;
1427								}
1428								else
1429								{
1430									var autocomplete = this.dateAutocompleteCharacters[group+1];
1431									futureValue = this.oldValue.substring(0, this.selection.start) + pressed + autocomplete + this.oldValue.substring(this.selection.start + 1);
1432									movePosition = 1 + autocomplete.length;
1433								}
1434							}
1435						}
1436						this.setValue (futureValue);
1437						this.selection.moveTo(this.selection.start + movePosition, this.selection.start + movePosition);									
1438						return false;							
1439					}			
1440				}
1441			}
1442			else
1443			{
1444				// date group is not full
1445				// insert
1446				futureValue = this.oldValue.substring(0, this.selection.start) + pressed + this.oldValue.substring(this.selection.start);
1447				var movePosition = 1;
1448				if (!this.isValueValid(futureValue, this.selection.start + 1, group) && !this.isValueValid(futureValue, this.selection.start + 1, group+1)) 
1449				{
1450					this.redTextFlash(); return false;
1451				}
1452				else 
1453				{
1454					var autocomplete = this.dateAutocompleteCharacters[group+1];
1455					if (pressed == autocomplete) 
1456					{
1457						if (this.nextDateDelimiterExists(this.oldValue, this.selection.start, group))
1458						{
1459							futureValue = this.oldValue;
1460							movePosition = 1;
1461						}
1462					}
1463					else
1464					{
1465						if(this.isPositionAtEndOfGroup(futureValue, this.selection.start+1, group)) 
1466						{
1467							if (group != this.lastDateGroup)
1468							{
1469								if (this.nextDateDelimiterExists(futureValue, this.selection.start + 1, group))
1470								{
1471									var autocomplete = this.dateAutocompleteCharacters[group+1];
1472									movePosition = 1 + autocomplete.length;
1473								}
1474								else
1475								{
1476									var autocomplete = this.dateAutocompleteCharacters[group+1];
1477									futureValue = this.oldValue.substring(0, this.selection.start) + pressed + autocomplete + this.oldValue.substring(this.selection.start + 1);
1478									movePosition = 1 + autocomplete.length;
1479								}
1480							}
1481						}
1482					}
1483					this.setValue (futureValue);
1484					this.selection.moveTo(this.selection.start + movePosition, this.selection.start + movePosition);									
1485					return false;						
1486				}	
1487			}
1488		}
1489		return false;
1490	}
1491	
1492};
1493
1494Spry.Widget.ValidationTextField.prototype.onKeyDown = function(e)
1495{
1496	this.saveState();
1497	this.keyCode = e.keyCode;
1498
1499	if (Spry.is.opera) {
1500		if (this.flags.operaPasteOperation) {
1501			window.clearInterval(this.flags.operaPasteOperation);
1502			this.flags.operaPasteOperation = null;
1503		}
1504		if (e.ctrlKey) {
1505			var pressed = Spry.Widget.Utils.getCharacterFromEvent(e);
1506			if (pressed && 'vx'.indexOf(pressed.toLowerCase()) != -1) {
1507				var self = this;
1508				this.flags.operaPasteOperation = window.setInterval(function() { self.operaPasteMonitor();}, 1);
1509				return true;
1510			}
1511		}
1512	}
1513
1514	if (this.keyCode != 8 && this.keyCode != 46 && Spry.Widget.Utils.isSpecialKey(e)) {
1515		return true;
1516	}
1517	if (this.keyCode == 8 || this.keyCode == 46 ) {
1518		var mr = this.doValidations(this.input.value, this.input.value);
1519		if (mr) {
1520			return true;
1521		}
1522	}
1523
1524	//DELETE
1525	if (this.useCharacterMasking && this.pattern && this.keyCode == 46) {
1526		if (e.ctrlKey) {
1527			//delete from selection until end
1528			this.setValue(this.input.value.substring(0, this.selection.start));
1529		} else if (this.selection.end == this.input.value.length || this.selection.start == this.input.value.length-1){
1530			//allow key if selection is at end (will delete selection)
1531			return true;
1532		} else {
1533			this.flags.operaRevertOnKeyUp = true;
1534		}
1535		if (Spry.is.mozilla && Spry.is.mac) {
1536			this.flags.skp = true;
1537		}
1538		Spry.Widget.Utils.stopEvent(e);
1539		return false;
1540	}
1541
1542	//BACKSPACE
1543	if (this.useCharacterMasking && this.pattern && !e.ctrlKey && this.keyCode == 8) {
1544		if (this.selection.start == this.input.value.length) {
1545			//delete with BACKSPACE from the end of the input value only
1546			var n = this.getAutoComplete(this.selection.start, -1);
1547			this.setValue(this.input.value.substring(0, this.input.value.length - (Spry.is.opera?0:1) - n.length));
1548			if (Spry.is.opera) {
1549				//cant stop the event on Opera, we'll just preserve the selection so delete will act on it
1550				this.selection.start = this.selection.start - 1 - n.length;
1551				this.selection.end = this.selection.end - 1 - n.length;
1552			}
1553		} else if (this.selection.end == this.input.value.length){
1554			//allow BACKSPACE if selection is at end (will delete selection)
1555			return true;
1556		} else {
1557			this.flags.operaRevertOnKeyUp = true;
1558		}
1559		if (Spry.is.mozilla && Spry.is.mac) {
1560			this.flags.skp = true;
1561		} 
1562		Spry.Widget.Utils.stopEvent(e);
1563		return false;
1564	}
1565
1566	return true;
1567};
1568
1569Spry.Widget.ValidationTextField.prototype.onMouseDown = function(e)
1570{
1571	if (this.flags.active) {
1572		//mousedown fires before focus
1573		//avoid double saveState on first focus by mousedown by checking if the control has focus
1574		//do nothing if it's not focused because saveState will be called onfocus
1575		this.saveState();
1576	}
1577};
1578
1579Spry.Widget.ValidationTextField.prototype.onDrop = function(e)
1580{
1581	//mark that a drop operation is in progress to avoid race conditions with event handlers for other events
1582	//especially onchange and onfocus
1583	this.flags.drop = true;
1584	this.removeHint();
1585	this.saveState();
1586	this.flags.active = true;
1587	this.addClassName(this.element, this.focusClass);
1588	this.addClassName(this.additionalError, this.focusClass);
1589};
1590
1591Spry.Widget.ValidationTextField.prototype.onFocus = function(e)
1592{
1593	if (this.flags.drop) {
1594		return;
1595	}
1596	this.removeHint();
1597
1598	if (this.pattern && this.useCharacterMasking) {
1599		var autocomplete = this.getAutoComplete(this.selection.start);
1600		this.setValue(this.input.value + autocomplete);
1601		this.selection.moveTo(this.input.value.length, this.input.value.length);
1602	}
1603	
1604	this.saveState();
1605	this.flags.active = true;
1606	this.addClassName(this.element, this.focusClass);
1607	this.addClassName(this.additionalError, this.focusClass);
1608};
1609	
1610Spry.Widget.ValidationTextField.prototype.onBlur = function(e)
1611{
1612	this.flags.active = false;
1613	this.removeClassName(this.element, this.focusClass);
1614	this.removeClassName(this.additionalError, this.focusClass);
1615	this.flags.restoreSelection = false;
1616	var mustRevert = this.doValidations(this.input.value, this.input.value);
1617	this.flags.restoreSelection = true;
1618
1619	if (this.validateOn & Spry.Widget.ValidationTextField.ONBLUR) {
1620		this.validate();
1621	}
1622	var self = this;
1623	setTimeout(function() {self.putHint();}, 10);
1624	return true;
1625};
1626
1627Spry.Widget.ValidationTextField.prototype.compilePattern = function() {
1628	if (!this.pattern) {
1629		return;
1630	}
1631	var compiled = [];
1632	var regexps = [];
1633	var patternCharacters = [];
1634	var idx = 0;
1635	var c = '', p = '';
1636	for (var i=0; i<this.pattern.length; i++) {
1637		c = this.pattern.charAt(i);
1638		if (p == '\\') {
1639			if (/[0ABXY\?]/i.test(c)) {
1640				regexps[idx - 1] = c;
1641			} else {
1642				regexps[idx - 1] = Spry.Widget.ValidationTextField.regExpFromChars(c);
1643			}
1644			compiled[idx - 1] = c;
1645			patternCharacters[idx - 1] = null;
1646			p = '';
1647			continue;
1648		}
1649		regexps[idx] = Spry.Widget.ValidationTextField.regExpFromChars(c);
1650		if (/[0ABXY\?]/i.test(c)) {
1651			compiled[idx] = null;
1652			patternCharacters[idx] = c;
1653		} else if (c == '\\') {
1654			compiled[idx] = c;
1655			patternCharacters[idx] = '\\';
1656		} else {
1657			compiled[idx] = c;
1658			patternCharacters[idx] = null;
1659		}
1660		idx++;
1661		p = c;
1662	}
1663
1664	this.autoCompleteCharacters = compiled;
1665	this.compiledPattern = regexps;
1666	this.patternCharacters = patternCharacters;
1667	this.patternLength = compiled.length;
1668};
1669
1670Spry.Widget.ValidationTextField.prototype.getAutoComplete = function(from, direction) {
1671	if (direction == -1) {
1672		var n = '', m = '';
1673		while(from && (n = this.getAutoComplete(--from) )) {
1674			m = n;
1675		}
1676		return m;
1677	}
1678	var ret = '', c = '';
1679	for (var i=from; i<this.autoCompleteCharacters.length; i++) {
1680		c = this.autoCompleteCharacters[i];
1681		if (c) {
1682			ret += c;
1683		} else {
1684			break;
1685		}
1686	}
1687	return ret;
1688};
1689
1690Spry.Widget.ValidationTextField.regExpFromChars = function (string) {
1691	//string contains pattern characters
1692	var ret = '', character = '';
1693	for (var i = 0; i<string.length; i++) {
1694		character = string.charAt(i);
1695		switch (character) {
1696			case '0': ret += '\\d';break;
1697			case 'A': ret += '[A-Z]';break;
1698//			case 'A': ret += '[\u0041-\u005A\u0061-\u007A\u0100-\u017E\u0180-\u0233\u0391-\u03CE\u0410-\u044F\u05D0-\u05EA\u0621-\u063A\u0641-\u064A\u0661-\u06D3\u06F1-\u06FE]';break;
1699			case 'a': ret += '[a-z]';break;
1700//			case 'a': ret += '[\u0080-\u00FF]';break;
1701			case 'B': case 'b': ret += '[a-zA-Z]';break;
1702			case 'x': ret += '[0-9a-z]';break;
1703			case 'X': ret += '[0-9A-Z]';break;
1704			case 'Y': case 'y': ret += '[0-9a-zA-Z]';break;
1705			case '?': ret += '.';break;
1706			case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8':case '9':
1707				ret += character;
1708				break;
1709			case 'c': case 'C': case 'e': case 'E': case 'f': case 'F':case 'r':case 'd': case 'D':case 'n':case 's':case 'S':case 'w':case 'W':case 't':case 'v':
1710				ret += character;
1711				break;
1712			default: ret += '\\' + character;
1713		}
1714	}
1715	return ret;
1716};
1717
1718Spry.Widget.ValidationTextField.prototype.patternToRegExp = function(len) {
1719	var ret = '^';
1720	var end = Math.min(this.compiledPattern.length, len);
1721	for (var i=0; i < end; i++) {
1722		ret += this.compiledPattern[i];
1723	}
1724	ret += '$';
1725	ret = new RegExp(ret, "");
1726	return ret;
1727};
1728
1729Spry.Widget.ValidationTextField.prototype.resetClasses = function() {
1730	var classes = [this.requiredClass, this.invalidFormatClass, this.invalidRangeMinClass, this.invalidRangeMaxClass, this.invalidCharsMinClass, this.invalidCharsMaxClass, this.validClass];
1731	for (var i=0; i < classes.length; i++)
1732	{
1733		this.removeClassName(this.element, classes[i]);
1734		this.removeClassName(this.additionalError, classes[i]);
1735	}
1736};
1737
1738Spry.Widget.ValidationTextField.prototype.reset = function() {
1739	this.removeHint();
1740	this.oldValue = this.input.defaultValue;
1741	
1742	this.resetClasses();
1743	if (Spry.is.ie) {
1744		//this will fire the onpropertychange event right after the className changed on the container element
1745		//IE6 will not fire the first onpropertychange on an input type text after a onreset handler if inside that handler the className of one of the elements inside the form has been changed
1746		//to reproduce: change the className of one of the elements inside the form from within the onreset handler; then the onpropertychange does not fire the first time
1747		this.input.forceFireFirstOnPropertyChange = true;
1748		this.input.removeAttribute("forceFireFirstOnPropertyChange");
1749	}
1750	var self = this;
1751	setTimeout(function() {self.putHint();}, 10);
1752};
1753
1754/* エラー回避用に追加 */
1755Spry.Widget.ValidationTextField.prototype.hasClassName = function(ele, className)
1756{
1757	if (!ele || !className || !ele.className || ele.className.search(new RegExp("\\b" + className + "\\b")) == -1)
1758		return false;
1759	return true;
1760};
1761
1762Spry.Widget.ValidationTextField.prototype.validate = function() {
1763
1764	this.resetClasses();
1765	
1766	//エラー無効にチェックされている場合は実行しない(リセットの後ろに記述)
1767	if(document.getElementById("conf_error_check") != null){if(document.getElementById("conf_error_check").checked == true){return true;}}
1768	
1769	//チェックを無効にする「SpryInvalidClass」が設定されている場合
1770	if(this.hasClassName(this.element,'SpryInvalidClass')){return true;}
1771	
1772	//possible states: required, format, rangeMin, rangeMax, charsMin, charsMax
1773	if (this.validateOn & Spry.Widget.ValidationTextField.ONSUBMIT) {
1774
1775		this.removeHint();
1776		this.doValidations(this.input.value, this.input.value);
1777
1778		if(!this.flags.active) {
1779			var self = this;
1780			setTimeout(function() {self.putHint();}, 10);
1781		}
1782	}
1783
1784	if (this.isRequired && this.errors & Spry.Widget.ValidationTextField.ERROR_REQUIRED) {
1785		this.addClassName(this.element, this.requiredClass);
1786		this.addClassName(this.additionalError, this.requiredClass);
1787		return false;
1788	}
1789
1790	if (this.errors & Spry.Widget.ValidationTextField.ERROR_FORMAT) {
1791		this.addClassName(this.element, this.invalidFormatClass);
1792		this.addClassName(this.additionalError, this.invalidFormatClass);
1793		return false;
1794	}
1795
1796	if (this.errors & Spry.Widget.ValidationTextField.ERROR_RANGE_MIN) {
1797		this.addClassName(this.element, this.invalidRangeMinClass);
1798		this.addClassName(this.additionalError, this.invalidRangeMinClass);
1799		return false;
1800	}
1801
1802	if (this.errors & Spry.Widget.ValidationTextField.ERROR_RANGE_MAX) {
1803		this.addClassName(this.element, this.invalidRangeMaxClass);
1804		this.addClassName(this.additionalError, this.invalidRangeMaxClass);
1805		return false;
1806	}
1807
1808	if (this.errors & Spry.Widget.ValidationTextField.ERROR_CHARS_MIN) {
1809		this.addClassName(this.element, this.invalidCharsMinClass);
1810		this.addClassName(this.additionalError, this.invalidCharsMinClass);
1811		return false;
1812	}
1813
1814	if (this.errors & Spry.Widget.ValidationTextField.ERROR_CHARS_MAX) {
1815		this.addClassName(this.element, this.invalidCharsMaxClass);
1816		this.addClassName(this.additionalError, this.invalidCharsMaxClass);
1817		return false;
1818	}
1819
1820	this.addClassName(this.element, this.validClass);
1821	this.addClassName(this.additionalError, this.validClass);
1822	return true;
1823};
1824
1825Spry.Widget.ValidationTextField.prototype.addClassName = function(ele, className)
1826{
1827	if (!ele || !className || (ele.className && ele.className.search(new RegExp("\\b" + className + "\\b")) != -1))
1828		return;
1829	ele.className += (ele.className ? " " : "") + className;
1830};
1831
1832Spry.Widget.ValidationTextField.prototype.removeClassName = function(ele, className)
1833{
1834	if (!ele || !className || (ele.className && ele.className.search(new RegExp("\\b" + className + "\\b")) == -1))
1835		return;
1836	ele.className = ele.className.replace(new RegExp("\\s*\\b" + className + "\\b", "g"), "");
1837};
1838Spry.Widget.ValidationTextField.prototype.showError = function(msg)
1839{
1840	alert('Spry.Widget.TextField ERR: ' + msg);
1841};
1842/**
1843 * SelectionDescriptor is a wrapper for input type text selection methods and properties 
1844 * as implemented by various  browsers
1845 */
1846Spry.Widget.SelectionDescriptor = function (element)
1847{
1848	this.element = element;
1849	this.update();
1850};
1851
1852Spry.Widget.SelectionDescriptor.prototype.update = function()
1853{
1854	if (Spry.is.ie && Spry.is.windows) {
1855		var sel = this.element.ownerDocument.selection;
1856		if (this.element.nodeName == "TEXTAREA") {
1857			if (sel.type != 'None') {
1858				try{var range = sel.createRange();}catch(err){return;}
1859				if (range.parentElement() == this.element){
1860					var range_all = this.element.ownerDocument.body.createTextRange();
1861					range_all.moveToElementText(this.element);
1862					for (var sel_start = 0; range_all.compareEndPoints('StartToStart', range) < 0; sel_start ++){
1863						range_all.moveStart('character', 1);
1864					}
1865					this.start = sel_start;
1866					// create a selection of the whole this.element
1867					range_all = this.element.ownerDocument.body.createTextRange();
1868					range_all.moveToElementText(this.element);
1869					for (var sel_end = 0; range_all.compareEndPoints('StartToEnd', range) < 0; sel_end++){
1870						range_all.moveStart('character', 1);
1871					}
1872					this.end = sel_end;
1873					this.length = this.end - this.start;
1874					// get selected and surrounding text
1875					this.text = range.text;
1876		 		}
1877			}        
1878		} else if (this.element.nodeName == "INPUT"){
1879			try{this.range = sel.createRange();}catch(err){return;}
1880			this.length = this.range.text.length;
1881			var clone = this.range.duplicate();
1882			this.start = -clone.moveStart("character", -10000);
1883			clone = this.range.duplicate();
1884			clone.collapse(false);
1885			this.end = -clone.moveStart("character", -10000);
1886			this.text = this.range.text;
1887		}
1888	} else {
1889		var tmp = this.element;
1890		var selectionStart = 0;
1891		var selectionEnd = 0;
1892        
1893		try { selectionStart = tmp.selectionStart;} catch(err) {}
1894		try { selectionEnd = tmp.selectionEnd;} catch(err) {}
1895
1896		if (Spry.is.safari) {
1897			if (selectionStart == 2147483647) {
1898				selectionStart = 0;
1899			}
1900			if (selectionEnd == 2147483647) {
1901				selectionEnd = 0;
1902			}
1903		}
1904		this.start = selectionStart;
1905		this.end = selectionEnd;
1906		this.length = selectionEnd - selectionStart;
1907		this.text = this.element.value.substring(selectionStart, selectionEnd);
1908	}
1909};
1910
1911Spry.Widget.SelectionDescriptor.prototype.destroy = function() {
1912	try { delete this.range} catch(err) {}
1913	try { delete this.element} catch(err) {}
1914};
1915
1916Spry.Widget.SelectionDescriptor.prototype.move = function(amount)
1917{
1918	if (Spry.is.ie && Spry.is.windows) {
1919		this.range.move("character", amount);
1920		this.range.select();
1921	} else {
1922		try { this.element.selectionStart++;}catch(err) {}
1923	}
1924	this.update();
1925};
1926
1927Spry.Widget.SelectionDescriptor.prototype.moveTo = function(start, end)
1928{
1929	if (Spry.is.ie && Spry.is.windows) {
1930		if (this.element.nodeName == "TEXTAREA") {
1931			var ta_range = this.element.createTextRange();
1932			this.range = this.element.createTextRange();
1933			this.range.move("character", start);
1934			this.range.moveEnd("character", end - start);
1935			
1936			var c1 = this.range.compareEndPoints("StartToStart", ta_range);
1937			if (c1 < 0) {
1938				this.range.setEndPoint("StartToStart", ta_range);
1939			}
1940
1941			var c2 = this.range.compareEndPoints("EndToEnd", ta_range);
1942			if (c2 > 0) {
1943				this.range.setEndPoint("EndToEnd", ta_range);
1944			}
1945		} else if (this.element.nodeName == "INPUT"){
1946			this.range = this.element.ownerDocument.selection.createRange();
1947			this.range.move("character", -10000);
1948			this.start = this.range.moveStart("character", start);
1949			this.end = this.start + this.range.moveEnd("character", end - start);
1950		}
1951		this.range.select();
1952	} else {
1953		this.start = start;
1954		try { this.element.selectionStart = start;} catch(err) {}
1955		this.end = end;
1956		try { this.element.selectionEnd = end;} catch(err) {}
1957	}
1958	this.ignore = true;
1959	this.update();
1960};
1961
1962Spry.Widget.SelectionDescriptor.prototype.moveEnd = function(amount)
1963{
1964	if (Spry.is.ie && Spry.is.windows) {
1965		this.range.moveEnd("character", amount);
1966		this.range.select();
1967	} else {
1968		try { this.element.selectionEnd++;} catch(err) {}
1969	}
1970	this.update();
1971};
1972
1973Spry.Widget.SelectionDescriptor.prototype.collapse = function(begin)
1974{
1975	if (Spry.is.ie && Spry.is.windows) {
1976		this.range = this.element.ownerDocument.selection.createRange();
1977		this.range.collapse(begin);
1978		this.range.select();
1979	} else {
1980		if (begin) {
1981			try { this.element.selectionEnd = this.element.selectionStart;} catch(err) {}
1982		} else {
1983			try { this.element.selectionStart = this.element.selectionEnd;} catch(err) {}
1984		}
1985	}
1986
1987	this.update();
1988};
1989
1990//////////////////////////////////////////////////////////////////////
1991//
1992// Spry.Widget.Form - common for all widgets
1993//
1994//////////////////////////////////////////////////////////////////////
1995
1996if (!Spry.Widget.Form) Spry.Widget.Form = {};
1997if (!Spry.Widget.Form.onSubmitWidgetQueue) Spry.Widget.Form.onSubmitWidgetQueue = [];
1998
1999if (!Spry.Widget.Form.validate) {
2000	Spry.Widget.Form.validate = function(vform) {
2001		var isValid = true;
2002		var isElementValid = true;
2003		var q = Spry.Widget.Form.onSubmitWidgetQueue;
2004		var qlen = q.length;
2005		for (var i = 0; i < qlen; i++) {
2006			if (!q[i].isDisabled() && q[i].form == vform) {
2007				isElementValid = q[i].validate();
2008				isValid = isElementValid && isValid;
2009			}
2010		}
2011		return isValid;
2012	}
2013};
2014
2015if (!Spry.Widget.Form.onSubmit) {
2016	Spry.Widget.Form.onSubmit = function(e, form)
2017	{
2018		if (Spry.Widget.Form.validate(form) == false) {
2019			return false;
2020		}
2021		return true;
2022	};
2023};
2024
2025if (!Spry.Widget.Form.onReset) {
2026	Spry.Widget.Form.onReset = function(e, vform)
2027	{
2028		var q = Spry.Widget.Form.onSubmitWidgetQueue;
2029		var qlen = q.length;
2030		for (var i = 0; i < qlen; i++) {
2031			if (!q[i].isDisabled() && q[i].form == vform && typeof(q[i].reset) == 'function') {
2032				q[i].reset();
2033			}
2034		}
2035		return true;
2036	};
2037};
2038
2039if (!Spry.Widget.Form.destroy) {
2040	Spry.Widget.Form.destroy = function(form)
2041	{
2042		var q = Spry.Widget.Form.onSubmitWidgetQueue;
2043		for (var i = 0; i < Spry.Widget.Form.onSubmitWidgetQueue.length; i++) {
2044			if (q[i].form == form && typeof(q[i].destroy) == 'function') {
2045				q[i].destroy();
2046				i--;
2047			}
2048		}
2049	}
2050};
2051
2052if (!Spry.Widget.Form.destroyAll) {
2053	Spry.Widget.Form.destroyAll = function()
2054	{
2055		var q = Spry.Widget.Form.onSubmitWidgetQueue;
2056		for (var i = 0; i < Spry.Widget.Form.onSubmitWidgetQueue.length; i++) {
2057			if (typeof(q[i].destroy) == 'function') {
2058				q[i].destroy();
2059				i--;
2060			}
2061		}
2062	}
2063};
2064
2065//////////////////////////////////////////////////////////////////////
2066//
2067// Spry.Widget.Utils
2068//
2069//////////////////////////////////////////////////////////////////////
2070
2071if (!Spry.Widget.Utils)	Spry.Widget.Utils = {};
2072
2073Spry.Widget.Utils.punycode_constants = {
2074	base : 36, tmin : 1, tmax : 26, skew : 38, damp : 700,
2075  initial_bias : 72, initial_n : 0x80, delimiter : 0x2D,
2076  maxint : 2<<26-1
2077};
2078
2079Spry.Widget.Utils.punycode_encode_digit = function (d) {
2080  return String.fromCharCode(d + 22 + 75 * (d < 26));
2081};
2082
2083Spry.Widget.Utils.punycode_adapt = function (delta, numpoints, firsttime) {
2084	delta = firsttime ? delta / this.punycode_constants.damp : delta >> 1;
2085	delta += delta / numpoints;
2086	
2087	for (var k = 0; delta > ((this.punycode_constants.base - this.punycode_constants.tmin) * this.punycode_constants.tmax) / 2; k += this.punycode_constants.base) {
2088		delta /= this.punycode_constants.base - this.punycode_constants.tmin;
2089	}
2090	return k + (this.punycode_constants.base - this.punycode_constants.tmin + 1) * delta / (delta + this.punycode_constants.skew);
2091};
2092
2093/**
2094 * returns a 	Punicode representation of a UTF-8 string
2095 * adapted from http://tools.ietf.org/html/rfc3492
2096 */
2097Spry.Widget.Utils.punycode_encode = function (input, max_out) {
2098	var inputc = input.split("");
2099	input = [];
2100	for(var i=0; i<inputc.length; i++) {
2101		input.push(inputc[i].charCodeAt(0));
2102	}
2103	var output = '';
2104
2105  var h, b, j, m, q, k, t;
2106	var input_len = input.length;
2107  var n = this.punycode_constants.initial_n;
2108  var delta = 0;
2109  var bias = this.punycode_constants.initial_bias;
2110  var out = 0;
2111
2112  for (j = 0; j < input_len; j++) {
2113		if (input[j] < 128) {
2114			if (max_out - out < 2) {
2115				return false;
2116			}
2117			output += String.fromCharCode(input[j]);
2118			out++;
2119		}
2120	}
2121
2122	h = b = out;
2123	if (b > 0) {
2124		output += String.fromCharCode(this.punycode_constants.delimiter);
2125		out++;
2126	}
2127
2128  while (h < input_len)	{
2129		for (m = this.punycode_constants.maxint, j = 0; j < input_len; j++) {
2130			if (input[j] >= n && input[j] < m) {
2131				m = input[j];
2132			}
2133		}
2134		if (m - n > (this.punycode_constants.maxint - delta) / (h + 1)) {
2135			return false;
2136		}
2137		
2138		delta += (m - n) * (h + 1);
2139		n = m;
2140
2141		for (j = 0; j < input_len; j++) {
2142			if (input[j] < n ) {
2143				if (++delta == 0) {
2144					return false;
2145				}
2146			}
2147
2148			if (input[j] == n) {
2149				for (q = delta, k = this.punycode_constants.base; true; k += this.punycode_constants.base) {
2150					if (out >= max_out) {
2151						return false;
2152					}
2153
2154					t = k <= bias ? this.punycode_constants.tmin : k >= bias + this.punycode_constants.tmax ? this.punycode_constants.tmax : k - bias;
2155					if (q < t) {
2156						break;
2157					}
2158
2159					output += this.punycode_encode_digit(t + (q - t) % (this.punycode_constants.base - t));
2160					out++;
2161					q = (q - t) / (this.punycode_constants.base - t);
2162				}
2163
2164				output += this.punycode_encode_digit(q);
2165				out++;
2166				bias = this.punycode_adapt(delta, h + 1, h == b);
2167				delta = 0;
2168				h++;
2169			}
2170		}
2171		delta++, n++;
2172	}
2173
2174  return output;
2175};
2176
2177Spry.Widget.Utils.setOptions = function(obj, optionsObj, ignoreUndefinedProps)
2178{
2179	if (!optionsObj)
2180		return;
2181	for (var optionName in optionsObj)
2182	{
2183		if (ignoreUndefinedProps && optionsObj[optionName] == undefined)
2184			continue;
2185		obj[optionName] = optionsObj[optionName];
2186	}
2187};
2188
2189Spry.Widget.Utils.firstValid = function() {
2190	var ret = null;
2191	for(var i=0; i<Spry.Widget.Utils.firstValid.arguments.length; i++) {
2192		if (typeof(Spry.Widget.Utils.firstValid.arguments[i]) != 'undefined') {
2193			ret = Spry.Widget.Utils.firstValid.arguments[i];
2194			break;
2195		}
2196	}
2197	return ret;
2198};
2199
2200
2201Spry.Widget.Utils.specialCharacters = ",8,9,16,17,18,20,27,33,34,35,36,37,38,40,45,144,192,63232,";
2202Spry.Widget.Utils.specialSafariNavKeys = "63232,63233,63234,63235,63272,63273,63275,63276,63277,63289,";
2203Spry.Widget.Utils.specialNotSafariCharacters = "39,46,91,92,93,";
2204
2205Spry.Widget.Utils.specialCharacters += Spry.Widget.Utils.specialSafariNavKeys;
2206
2207if (!Spry.is.safari) {
2208	Spry.Widget.Utils.specialCharacters += Spry.Widget.Utils.specialNotSafariCharacters;
2209}
2210
2211Spry.Widget.Utils.isSpecialKey = function (ev) {
2212	return Spry.Widget.Utils.specialCharacters.indexOf("," + ev.keyCode + ",") != -1;
2213};
2214
2215Spry.Widget.Utils.getCharacterFromEvent = function(e){
2216	var keyDown = e.type == "keydown";
2217
2218	var code = null;
2219	var character = null;
2220	if(Spry.is.mozilla && !keyDown){
2221		if(e.charCode){
2222			character = String.fromCharCode(e.charCode);
2223		} else {
2224			code = e.keyCode;
2225		}
2226	} else {
2227		code = e.keyCode || e.which;
2228		if (code != 13) {
2229			character = String.fromCharCode(code);
2230		}
2231	}
2232
2233	if (Spry.is.safari) {
2234		if (keyDown) {
2235			code = e.keyCode || e.which;
2236			character = String.fromCharCode(code);
2237		} else {
2238			code = e.keyCode || e.which;
2239			if (Spry.Widget.Utils.specialCharacters.indexOf("," + code + ",") != -1) {
2240				character = null;
2241			} else {
2242				character = String.fromCharCode(code);
2243			}
2244		}
2245	}
2246
2247	if(Spry.is.opera) {
2248		if (Spry.Widget.Utils.specialCharacters.indexOf("," + code + ",") != -1) {
2249			character = null;
2250		} else {
2251			character = String.fromCharCode(code);
2252		}
2253	}
2254
2255	return character;
2256};
2257
2258Spry.Widget.Utils.getFirstChildWithNodeNameAtAnyLevel = function(node, nodeName)
2259{
2260	var elements  = node.getElementsByTagName(nodeName);
2261	if (elements) {
2262		return elements[0];
2263	}
2264	return null;
2265};
2266
2267Spry.Widget.Utils.getFirstParentWithNodeName = function(node, nodeName)
2268{
2269	while (node.parentNode
2270			&& node.parentNode.nodeName.toLowerCase() != nodeName.toLowerCase()
2271			&& node.parentNode.nodeName != 'BODY') {
2272		node = node.parentNode;
2273	}
2274
2275	if (node.parentNode && node.parentNode.nodeName.toLowerCase() == nodeName.toLowerCase()) {
2276		return node.parentNode;
2277	} else {
2278		return null;
2279	}
2280};
2281
2282Spry.Widget.Utils.destroyWidgets = function (container)
2283{
2284	if (typeof container == 'string') {
2285		container = document.getElementById(container);
2286	}
2287
2288	var q = Spry.Widget.Form.onSubmitWidgetQueue;
2289	for (var i = 0; i < Spry.Widget.Form.onSubmitWidgetQueue.length; i++) {
2290		if (typeof(q[i].destroy) == 'function' && Spry.Widget.Utils.contains(container, q[i].element)) {
2291			q[i].destroy();
2292			i--;
2293		}
2294	}
2295};
2296
2297Spry.Widget.Utils.contains = function (who, what)
2298{
2299	if (typeof who.contains == 'object') {
2300		return what && who && (who == what || who.contains(what));
2301	} else {
2302		var el = what;
2303		while(el) {
2304			if (el == who) {
2305				return true;
2306			}
2307			el = el.parentNode;
2308		}
2309		return false;
2310	}
2311};
2312
2313Spry.Widget.Utils.addEventListener = function(element, eventType, handler, capture)
2314{
2315	try
2316	{
2317		if (element.addEventListener)
2318			element.addEventListener(eventType, handler, capture);
2319		else if (element.attachEvent)
2320			element.attachEvent("on" + eventType, handler, capture);
2321	}
2322	catch (e) {}
2323};
2324
2325Spry.Widget.Utils.removeEventListener = function(element, eventType, handler, capture)
2326{
2327	try
2328	{
2329		if (element.removeEventListener)
2330			element.removeEventListener(eventType, handler, capture);
2331		else if (element.detachEvent)
2332			element.detachEvent("on" + eventType, handler, capture);
2333	}
2334	catch (e) {}
2335};
2336
2337Spry.Widget.Utils.stopEvent = function(ev)
2338{
2339	try
2340	{
2341		this.stopPropagation(ev);
2342		this.preventDefault(ev);
2343	}
2344	catch (e) {}
2345};
2346
2347/**
2348 * Stops event propagation
2349 * @param {Event} ev the event
2350 */
2351Spry.Widget.Utils.stopPropagation = function(ev)
2352{
2353	if (ev.stopPropagation)
2354	{
2355		ev.stopPropagation();
2356	}
2357	else
2358	{
2359		ev.cancelBubble = true;
2360	}
2361};
2362
2363/**
2364 * Prevents the default behavior of the event
2365 * @param {Event} ev the event
2366 */
2367Spry.Widget.Utils.preventDefault = function(ev)
2368{
2369	if (ev.preventDefault)
2370	{
2371		ev.preventDefault();
2372	}
2373	else
2374	{
2375		ev.returnValue = false;
2376	}
2377};
2378
2379})(); // EndSpryComponent

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.