PageSourceSearch

https://rosenbergfamilylaw.com/SpryAssets/SpryValidationTextarea.js

js rosenbergfamilylaw.com collected 2026-10-08 02:25:40 UTC 36,290 bytes, 1,127 lines download raw bytes

1/* SpryValidationTextarea.js - Revision: Spry Preview Release 1.4 */
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
30var Spry;
31if (!Spry) Spry = {};
32if (!Spry.Widget) Spry.Widget = {};
33
34Spry.Widget.BrowserSniff = function() {
35	var b = navigator.appName.toString();
36	var up = navigator.platform.toString();
37	var ua = navigator.userAgent.toString();
38
39	this.mozilla = this.ie = this.opera = r = false;
40	var re_opera = /Opera.([0-9\.]*)/i;
41	var re_msie = /MSIE.([0-9\.]*)/i;
42	var re_gecko = /gecko/i;
43	var re_safari = /safari\/([\d\.]*)/i;
44	
45	if (ua.match(re_opera)) {
46		r = ua.match(re_opera);
47		this.opera = true;
48		this.version = parseFloat(r[1]);
49	} else if (ua.match(re_msie)) {
50		r = ua.match(re_msie);
51		this.ie = true;
52		this.version = parseFloat(r[1]);
53	} else if (ua.match(re_safari)) {
54		this.safari = true;
55		this.version = 1.4;
56	} else if (ua.match(re_gecko)) {
57		var re_gecko_version = /rv:\s*([0-9\.]+)/i;
58		r = ua.match(re_gecko_version);
59		this.mozilla = true;
60		this.version = parseFloat(r[1]);
61	}
62	this.windows = this.mac = this.linux = false;
63
64	this.Platform = ua.match(/windows/i) ? "windows" :
65					(ua.match(/linux/i) ? "linux" :
66					(ua.match(/mac/i) ? "mac" :
67					ua.match(/unix/i)? "unix" : "unknown"));
68	this[this.Platform] = true;
69	this.v = this.version;
70
71	if (this.safari && this.mac && this.mozilla) {
72		this.mozilla = false;
73	}
74};
75
76Spry.is = new Spry.Widget.BrowserSniff();
77
78
79Spry.Widget.ValidationTextarea = function(element, options){
80	
81	options = options || {};
82	this.flags = {locked: false};
83	this.options = {};
84	this.element = element;
85	this.init(element);
86
87	if (!this.isBrowserSupported()){
88		return;	
89	}
90
91	options.useCharacterMasking = Spry.Widget.Utils.firstValid(options.useCharacterMasking, true);
92	options.hint = Spry.Widget.Utils.firstValid(options.hint, '');
93	options.isRequired = Spry.Widget.Utils.firstValid(options.isRequired, true);
94
95	Spry.Widget.Utils.setOptions(this, options);
96	Spry.Widget.Utils.setOptions(this.options, options);
97
98	//make sure we validate at least on submit
99	var validateOn = ['submit'].concat(Spry.Widget.Utils.firstValid(this.options.validateOn, []));
100	validateOn = validateOn.join(",");
101	this.validateOn = 0;
102	this.validateOn = this.validateOn | (validateOn.indexOf('submit') != -1 ? Spry.Widget.ValidationTextarea.ONSUBMIT : 0);
103	this.validateOn = this.validateOn | (validateOn.indexOf('blur') != -1 ? Spry.Widget.ValidationTextarea.ONBLUR : 0);
104	this.validateOn = this.validateOn | (validateOn.indexOf('change') != -1 ? Spry.Widget.ValidationTextarea.ONCHANGE : 0);
105
106	if (Spry.Widget.ValidationTextarea.onloadDidFire){
107		this.attachBehaviors();
108	}else{
109		Spry.Widget.ValidationTextarea.loadQueue.push(this);
110	}
111};
112
113Spry.Widget.ValidationTextarea.ONCHANGE = 1;
114Spry.Widget.ValidationTextarea.ONBLUR = 2;
115Spry.Widget.ValidationTextarea.ONSUBMIT = 4;
116
117Spry.Widget.ValidationTextarea.INITIAL = 'Initial';
118Spry.Widget.ValidationTextarea.REQUIRED = 'Required';
119Spry.Widget.ValidationTextarea.INVALID = 'Invalid Format';
120Spry.Widget.ValidationTextarea.MINIMUM = 'Minimum Number of Chars Not Met';
121Spry.Widget.ValidationTextarea.MAXIMUM = 'Maximum Number of Chars Exceeded';
122Spry.Widget.ValidationTextarea.VALID = 'Valid';
123
124Spry.Widget.ValidationTextarea.prototype.init = function(element)
125{
126	this.element = this.getElement(element);
127	this.event_handlers = [];
128
129	this.requiredClass = "textareaRequiredState";
130	this.invalidCharsMaxClass = "textareaMaxCharsState";
131	this.invalidCharsMinClass = "textareaMinCharsState";
132	this.validClass = "textareaValidState";
133	this.focusClass = "textareaFocusState";
134	this.textareaFlashClass = "textareaFlashState";
135
136	this.isMaxInvalid = false;
137	this.isMinInvalid = false;
138	this.isRequireInvalid = false;
139	
140	this.safariClicked = false;
141	this.state = Spry.Widget.ValidationTextarea.INITIAL;
142};
143
144Spry.Widget.ValidationTextarea.prototype.destroy = function() {
145	for (var i=0; i<this.event_handlers.length; i++) {
146		Spry.Widget.Utils.removeEventListener(this.event_handlers[i][0], this.event_handlers[i][1], this.event_handlers[i][2], false);
147	}
148	try { delete this.element; } catch(err) {}
149	try { delete this.input; } catch(err) {}
150	try { delete this.counterEl; } catch(err) {}
151	try { delete this.form; } catch(err) {}
152	try { delete this.event_handlers; } catch(err) {}
153	try { this.cursorPosition.destroy(); } catch(err) {}
154	try { delete this.cursorPosition; } catch(err) {}
155	try { this.initialCursor.destroy(); } catch(err) {}
156	try { delete this.initialCursor; } catch(err) {}
157
158	var q = Spry.Widget.Form.onSubmitWidgetQueue;
159	var qlen = q.length;
160	for (var i = 0; i < qlen; i++) {
161		if (q[i] == this) {
162			q.splice(i, 1);
163			break;
164		}
165	}
166};
167
168Spry.Widget.ValidationTextarea.prototype.isDisabled = function() {
169	return this.input && (this.input.disabled || this.input.readOnly) || !this.input;
170};
171
172Spry.Widget.ValidationTextarea.prototype.getElement = function(ele)
173{
174	if (ele && typeof ele == "string")
175		return document.getElementById(ele);
176	return ele;
177};
178
179
180Spry.Widget.ValidationTextarea.addLoadListener = function(handler){
181	if (typeof window.addEventListener != 'undefined'){
182		window.addEventListener('load', handler, false);
183	}else if (typeof document.addEventListener != 'undefined'){
184		document.addEventListener('load', handler, false);
185	}else if (typeof window.attachEvent != 'undefined'){
186		window.attachEvent('onload', handler);
187	}
188};
189
190Spry.Widget.ValidationTextarea.processLoadQueue = function(handler){
191	Spry.Widget.ValidationTextarea.onloadDidFire = true;
192	var q = Spry.Widget.ValidationTextarea.loadQueue;
193	var qlen = q.length;
194	for (var i = 0; i < qlen; i++){
195		q[i].attachBehaviors();
196	}
197};
198
199Spry.Widget.ValidationTextarea.onloadDidFire = false;
200Spry.Widget.ValidationTextarea.loadQueue = [];
201Spry.Widget.ValidationTextarea.addLoadListener(Spry.Widget.ValidationTextarea.processLoadQueue);
202Spry.Widget.ValidationTextarea.addLoadListener(function(){
203	Spry.Widget.Utils.addEventListener(window, "unload", Spry.Widget.Form.destroyAll, false);
204});
205
206Spry.Widget.ValidationTextarea.prototype.isBrowserSupported = function()
207{
208	return Spry.is.ie && Spry.is.v >= 5 && Spry.is.windows
209		||
210	Spry.is.mozilla && Spry.is.v >= 1.4
211		||
212	Spry.is.safari
213		||
214	Spry.is.opera && Spry.is.v >= 9;
215};
216
217/* 
218 * register our input to different event notifiers 
219 *
220 */
221Spry.Widget.ValidationTextarea.prototype.attachBehaviors = function()
222{
223	if (this.element){
224		if (this.element.nodeName == "TEXTAREA") {
225			this.input = this.element;
226		} else {
227			this.input = Spry.Widget.Utils.getFirstChildWithNodeNameAtAnyLevel(this.element, "TEXTAREA");
228		}
229	}
230	if (this.options && this.options.counterType && (this.options.counterType == 'chars_count' || this.options.counterType == 'chars_remaining')){
231			this.counterEl = document.getElementById(this.options.counterId);
232			this.counterChar();
233	}
234
235	if (this.input) {
236		this.input.setAttribute("AutoComplete", "off");
237		this.putHint();
238		this.cursorPosition = new Spry.Widget.SelectionDescriptor(this.input);
239
240		var self = this;
241		this.event_handlers = [];
242
243		//attach the pattern related event handlers (to stop invalid keys) 
244		if (this.useCharacterMasking) {
245			if (Spry.is.ie){
246				this.event_handlers.push([this.input, "propertychange", function(e) { return self.onKeyEvent(e || event); }]);
247				this.event_handlers.push([this.input, "drop", function(e) { return self.onDrop (e || event); }]);
248				this.event_handlers.push([this.input, "keypress", function(e) { return self.onKeyPress(e || event); }]);
249			} else{
250				this.event_handlers.push([this.input, "keydown", function(e) { return self.onKeyDown(e); }]);
251				this.event_handlers.push([this.input, "keypress", function(e) { return self.safariKeyPress(e); }]);
252				this.event_handlers.push([this.input, "keyup", function(e) { return self.safariValidate(e); }]);
253				if (Spry.is.safari){
254					this.event_handlers.push([this.input, "mouseup", function(e) { return self.safariMouseUp(e); }]);
255					this.event_handlers.push([this.input, "mousedown", function(e) { return self.safariMouseDown(e); }]);
256				} else {
257					//Firefox bug: 355219
258					//this.event_handlers.push([this.input, "input", function(e) { self.onKeyEvent(e); return true;}]);
259					this.event_handlers.push([this.input, "dragdrop", function(e) { return self.onKeyEvent(e); }]);
260					this.event_handlers.push([this.input, "dragenter", function(e) { self.removeHint(); return self.onKeyDown(e); }]);
261					this.event_handlers.push([this.input, "dragexit", function(e) { return self.putHint(); }]);
262				}
263			}
264			// we need to save an initial state in case of invalid input
265			this.event_handlers.push([this.input, "keydown", function(e) {return self.onKeyDown(e || event); }]);
266		}
267
268		this.event_handlers.push([this.input, "focus", function(e) { return self.onFocus(e || event); }]);
269		this.event_handlers.push([this.input, "mousedown", function(e) { return self.onMouseDown(e || event); }]);
270		this.event_handlers.push([this.input, "blur", function(e) { return self.onBlur(e || event); }]);
271
272		if (this.validateOn & Spry.Widget.ValidationTextarea.ONCHANGE){
273				if (Spry.is.ie){
274						this.event_handlers.push([this.input, "propertychange", function(e) { return self.onChange(e || event); }]);
275						this.event_handlers.push([this.input, "drop", function(e) { return self.onChange(e || event); }]);
276				} else{
277						this.event_handlers.push([this.input, "keydown", function(e) { return self.onKeyDown(e); }]);
278						this.event_handlers.push([this.input, "keypress", function(e) { return self.safariChangeKeyPress(e); }]);
279						this.event_handlers.push([this.input, "keyup", function(e) { return self.safariChangeValidate(e); }]);
280						if (Spry.is.safari){
281							this.event_handlers.push([this.input, "mouseup", function(e) { return self.safariChangeMouseUp(e); }]);
282							this.event_handlers.push([this.input, "mousedown", function(e) { return self.safariMouseDown(e); }]);
283						} else {
284							// Firefox bug: 355219
285							//this.event_handlers.push([this.input, "input", function(e) { return self.onChange(e); }]);
286							this.event_handlers.push([this.input, "dragdrop", function(e) {return self.onChange(e); }]);
287							this.event_handlers.push([this.input, "dragenter", function(e) { self.removeHint(); return self.onKeyDown(e); }]);
288							this.event_handlers.push([this.input, "dragexit", function(e) { return self.putHint(); }]);
289						}
290				}
291		}
292		// The counter should be called directly when no enforcement or change restrictions exists
293		if (! (this.validateOn & Spry.Widget.ValidationTextarea.ONCHANGE) && !this.useCharacterMasking){
294				if (Spry.is.ie){
295						this.event_handlers.push([this.input, "propertychange", function(e) { return self.counterChar(); }]);
296						this.event_handlers.push([this.input, "drop", function(e) { return self.counterChar(); }]);
297				} else{
298						this.event_handlers.push([this.input, "keypress", function(e) { return self.counterChar(); }]);
299						this.event_handlers.push([this.input, "keyup", function(e) { return self.counterChar(); }]);
300						if (Spry.is.safari){
301							this.event_handlers.push([this.input, "mouseup", function(e) { return self.counterChar(); }]);
302						} else {
303							// Firefox bug: 355219
304							//this.event_handlers.push([this.input, "input", function(e) { return self.onChange(e); }]);
305							this.event_handlers.push([this.input, "dragdrop", function(e) {return self.counterChar(); }]);
306						}
307				}
308		}
309
310		for (var i=0; i<this.event_handlers.length; i++) {
311			Spry.Widget.Utils.addEventListener(this.event_handlers[i][0], this.event_handlers[i][1], this.event_handlers[i][2], false);
312		}
313
314		this.form = Spry.Widget.Utils.getFirstParentWithNodeName(this.input, "FORM");
315		if (this.form) {
316			if (!this.form.attachedSubmitHandler && !this.form.onsubmit) {
317				this.form.onsubmit = function(e) { e = e || event; return Spry.Widget.Form.onSubmit(e, e.srcElement || e.currentTarget) };
318				this.form.attachedSubmitHandler = true;                 
319			}
320			if (!this.form.attachedResetHandler) {
321				Spry.Widget.Utils.addEventListener(this.form, "reset", function(e) { e = e || event; return Spry.Widget.Form.onReset(e, e.srcElement || e.currentTarget) }, false);
322				this.form.attachedResetHandler = true;                 
323			}
324			// add the currrent widget to the "onSubmit" check queue;
325			Spry.Widget.Form.onSubmitWidgetQueue.push(this);
326		}
327	}
328	this.saveState();
329};
330
331Spry.Widget.ValidationTextarea.prototype.onTyping = function(e){
332	if (this.input.disabled == true || this.input.readOnly == true){
333			return;	
334	}
335
336	if (!this.initialCursor){
337		this.initialCursor = this.cursorPosition;	
338	}
339	// on IE a stack overflow appears
340	if (this.flags.locked){
341			return true;
342	}
343
344	var val = this.input.value;
345
346	var ret = true;
347	
348	if (this.flags.hintOn){
349		return true;
350	}
351 	if (e && this.input && this.options && this.options.maxChars > 0 && ret){
352		if ( val.length > this.options.maxChars  && 
353							((!Spry.Widget.Utils.isSpecialKey(e) && this.cursorPosition.start == this.cursorPosition.end) ||
354				 			 (Spry.Widget.Utils.isSpecialKey(e) && val != this.initialValue) ||
355				 				this.cursorPosition.start != this.cursorPosition.end)
356			 ){
357					// cut the extra chars and display error
358					this.flags.locked = true;
359					var initial = this.initialValue;
360					var start = this.initialCursor.start;
361					var end = this.initialCursor.end;
362					if (initial.length && this.initialCursor.end < initial.length) {
363							// we try to behave more like maxlength textfield
364							var tmp = end - start + this.options.maxChars - initial.length;
365							var newValue = initial.substring(0, start) + val.substring(start, start+tmp) + initial.substring(end, initial.length < this.options.maxChars ? initial.length:this.options.maxChars);
366							end = start + tmp;
367					}else{
368							var newValue = val.substring(0, this.options.maxChars);
369							end = start = this.options.maxChars;
370					}
371					if (Spry.is.ie) {
372						this.input.innerText = newValue;
373					} else {
374						this.input.value = newValue;
375					}
376					this.redTextFlash();
377					this.cursorPosition.moveTo(end, end);
378					this.flags.locked = false;
379					ret = false;
380			} else{
381					this.setState(Spry.Widget.ValidationTextarea.VALID);
382					this.isMaxInvalid = false;
383			}
384	}
385	this.counterChar();
386	return ret;
387};
388
389Spry.Widget.ValidationTextarea.prototype.validateMinRequired = function(val){
390	var oldInvalid = false;
391	if (typeof this.notFireMinYet == 'undefined'){
392		this.notFireMinYet = false;
393	}else{
394		oldInvalid = true;
395		this.notFireMinYet = true;
396	}
397	if (this.onBlurOn){
398		this.notFireMinYet = true;
399	}else if (!this.onKeyEventOn){
400		this.notFireMinYet = true;
401	}
402
403	if (this.input && this.options && this.options.isRequired){
404			if (val.length > 0 && this.isRequireInvalid && (!this.hint || (this.hint && !this.flags.hintOn) || (this.hint && val != this.hint))){
405						this.switchClassName(this.validClass);
406						this.setState(Spry.Widget.ValidationTextarea.VALID);
407						this.isRequireInvalid = false;
408			}else if ((val.length == 0 || !(!this.hint || (this.hint && !this.flags.hintOn) || (this.hint && val != this.hint))) && (!this.isRequireInvalid || oldInvalid)){
409						if (this.notFireMinYet || Spry.is.ie){
410							this.switchClassName(this.requiredClass);
411							this.setState(Spry.Widget.ValidationTextarea.REQUIRED);
412						}
413						this.isRequireInvalid = true;
414						this.isMinInvalid = false;
415			}
416	}
417	if (this.input && this.options && this.options.minChars > 0 && !this.isRequireInvalid){
418			if (val.length >= this.options.minChars && (!this.hint || (this.hint && !this.flags.hintOn) || (this.hint && val != this.hint)) && this.isMinInvalid){
419						this.switchClassName(this.validClass);
420						this.setState(Spry.Widget.ValidationTextarea.VALID);
421						this.isMinInvalid = false;
422			}else if ( (val.length < this.options.minChars || (this.hint && val == this.hint && this.flags.hintOn)) && !this.isMinInvalid){
423						this.switchClassName(this.invalidCharsMinClass);
424						this.setState(Spry.Widget.ValidationTextarea.MINIMUM);
425						this.isMinInvalid = true;
426			}
427	}
428};
429Spry.Widget.ValidationTextarea.prototype.counterChar = function(){
430	if (!this.counterEl || !this.options || !this.options.counterType || (this.options.counterType != 'chars_remaining' && this.options.counterType != 'chars_count')){
431		return;	
432	}
433
434	if (this.options.counterType == 'chars_remaining') {
435		if (this.options.maxChars > 0){
436			if (this.flags.hintOn){
437				this.setCounterElementValue(this.options.maxChars);
438			} else {
439				if (this.options.maxChars > this.input.value.length){
440					this.setCounterElementValue(this.options.maxChars - this.input.value.length);
441				}else{
442					this.setCounterElementValue(0);
443				}
444			}
445		}
446	} else {
447		if (this.flags.hintOn){
448			this.setCounterElementValue(0);
449		} else {
450			if (this.useCharacterMasking && typeof this.options.maxChars != 'undefined' && this.options.maxChars < this.input.value.length){
451				this.setCounterElementValue(this.options.maxChars);
452			} else {
453				this.setCounterElementValue(this.input.value.length);
454			}
455		}
456	}
457};
458
459Spry.Widget.ValidationTextarea.prototype.setCounterElementValue = function(val){
460		if ( this.counterEl.nodeName.toLowerCase() != 'input' && 
461			this.counterEl.nodeName.toLowerCase() != 'textarea' &&
462			this.counterEl.nodeName.toLowerCase() != 'select' &&
463			this.counterEl.nodeName.toLowerCase() != 'img'){
464			this.counterEl.innerHTML = val;
465		}
466};
467Spry.Widget.ValidationTextarea.prototype.reset = function() {
468	this.removeHint();
469	this.removeClassName(this.requiredClass);
470	this.removeClassName(this.invalidCharsMinClass);
471	this.removeClassName(this.invalidCharsMaxClass);
472	this.removeClassName(this.validClass);
473	this.setState(Spry.Widget.ValidationTextarea.INITIAL);
474	var self = this;
475	setTimeout(function() {self.putHint();self.counterChar();}, 10);
476};
477
478Spry.Widget.ValidationTextarea.prototype.validate = function(){
479	if (this.input.disabled == true || this.input.readOnly == true){
480			return true;	
481	}
482
483	var val = this.input.value;
484	this.validateMinRequired(val);
485
486	var ret = !this.isMinInvalid && !this.isRequireInvalid;
487
488	if (ret && this.options.maxChars > 0 && !this.useCharacterMasking){
489			if (val.length <= this.options.maxChars || (this.hint && this.hint == val && this.flags.hintOn))	{
490					this.switchClassName(this.validClass);
491					this.setState(Spry.Widget.ValidationTextarea.VALID);
492				  this.isMaxInvalid = false;
493			}else{
494					this.switchClassName(this.invalidCharsMaxClass);
495					this.setState(Spry.Widget.ValidationTextarea.MAXIMUM);
496					this.isMaxInvalid = true;	
497			}
498	}
499	ret = ret && !this.isMaxInvalid;
500	if (ret) {
501		this.switchClassName(this.validClass);
502	}
503	this.counterChar();	
504	return ret;
505};
506
507Spry.Widget.ValidationTextarea.prototype.setState = function(newstate){
508	this.state = newstate;
509};
510
511Spry.Widget.ValidationTextarea.prototype.getState = function(){
512	return this.state;
513};
514
515Spry.Widget.ValidationTextarea.prototype.removeHint = function()
516{
517	if (this.flags.hintOn) {
518		this.flags.locked = true;
519		this.input.value = "";
520		this.flags.locked = false;
521		this.flags.hintOn = false;
522	}
523};
524
525Spry.Widget.ValidationTextarea.prototype.putHint = function()
526{
527	if(this.hint && this.input.value == "") {
528		this.flags.hintOn = true;
529		this.input.value = this.hint;
530	}
531};
532
533Spry.Widget.ValidationTextarea.prototype.redTextFlash = function()
534{
535	var self = this;
536	this.addClassName(this.textareaFlashClass);
537	setTimeout(function() {
538		self.removeClassName(self.textareaFlashClass)
539	}, 200);
540};
541
542
543Spry.Widget.ValidationTextarea.prototype.onKeyPress = function(e)
544{
545	//ENTER has length 2 on IE Windows, so will exceed maxLength on proximity
546	if (Spry.is.ie && Spry.is.windows && e.keyCode == 13) {
547		if ( (this.initialCursor.length + this.options.maxChars - this.input.value.length) < 2) {
548			Spry.Widget.Utils.stopEvent(e);
549			return false;
550		}
551	}
552};
553
554Spry.Widget.ValidationTextarea.prototype.onKeyDown = function(e)
555{ 
556	this.saveState();
557	this.keyCode = e.keyCode;
558	return true;
559};
560
561/*
562 * hadle for the max chars restrictions
563 * if key pressed or the input text is invalid it returns false
564 * 
565 */
566Spry.Widget.ValidationTextarea.prototype.onKeyEvent = function(e){
567	// on IE we look only for this input value changes
568	if (e.type == 'propertychange' && e.propertyName != 'value'){
569			return true;
570	}
571
572	var allow = this.onTyping(e);
573
574	if (!allow){
575		Spry.Widget.Utils.stopEvent(e);
576	}
577	//return allow;
578};
579
580/*
581 * handle for the min or required value
582 * if the input text is invalid it returns false
583 * 
584 */
585Spry.Widget.ValidationTextarea.prototype.onChange = function(e){
586	if (Spry.is.ie && e && e.type == 'propertychange' && e.propertyName != 'value') {
587		return true;
588	}
589
590	if (this.flags.drop) {
591		//delay this if it's a drop operation
592		var self = this;
593		setTimeout(function() {
594			self.flags.drop = false;
595			self.onChange(null);
596		}, 0);
597		return true;
598	}
599	if (this.flags.hintOn) {
600		return true;
601	}
602	this.onKeyEventOn = true;
603	var answer = this.validate();
604	this.onKeyEventOn = false;
605	return answer;
606};
607
608Spry.Widget.ValidationTextarea.prototype.onMouseDown = function(e)
609{
610	if (this.flags.active) {
611		//mousedown fires before focus
612		//avoid double saveState on first focus by mousedown by checking if the control has focus
613		//do nothing if it's not focused because saveState will be called onfocus
614		this.saveState();
615	}
616};
617
618Spry.Widget.ValidationTextarea.prototype.onDrop = function(e)
619{
620	//mark that a drop operation is in progress to avoid race conditions with event handlers for other events
621	//especially onchange and onfocus
622	this.flags.drop = true;
623	this.removeHint();
624
625	if (Spry.is.ie) {
626		var rng = document.body.createTextRange();
627		rng.moveToPoint(e.x, e.y);
628		rng.select();
629	}
630
631	this.saveState();
632	this.flags.active = true;
633	this.addClassName(this.focusClass);
634};
635
636Spry.Widget.ValidationTextarea.prototype.onFocus = function(e)
637{
638	if (this.flags.drop) {
639		return;
640	}
641	this.removeHint();
642	this.saveState();
643	this.flags.active = true;
644	this.addClassName(this.focusClass);
645};
646
647Spry.Widget.ValidationTextarea.prototype.onBlur = function(e){
648	this.removeClassName(this.focusClass);
649
650	if (this.validateOn & Spry.Widget.ValidationTextarea.ONBLUR) {
651		this.onBlurOn = true;
652		this.validate();
653		this.onBlurOn = false;
654	}
655
656	this.flags.active = false;
657	var self = this;
658	setTimeout(function() {self.putHint();}, 10);
659};
660
661Spry.Widget.ValidationTextarea.prototype.safariMouseDown = function(e){
662	this.safariClicked = true;
663};
664Spry.Widget.ValidationTextarea.prototype.safariChangeMouseUp = function(e){
665		if (!this.safariClicked){
666			this.onKeyDown(e); 
667			return this.safariChangeValidate(e, false);
668		}else{
669			this.safariClicked = false;
670			return true;
671		}
672};
673
674Spry.Widget.ValidationTextarea.prototype.safariMouseUp = function(e){
675		if (!this.safariClicked){
676			this.onKeyDown(e);
677			return this.safariValidate(e, false);
678		}else{
679			this.safariClicked = false;
680			return true;
681		}
682};
683
684Spry.Widget.ValidationTextarea.prototype.safariKeyPress = function(e){
685	this.safariFlag = new Date();
686	return this.safariValidate(e, true);
687};
688
689Spry.Widget.ValidationTextarea.prototype.safariValidate = function(e, recall)
690{
691	if (e.keyCode && Spry.Widget.Utils.isSpecialKey(e) && e.keyCode != 8 && e.keyCode != 46){
692		return true;
693	}
694	var answer = this.onTyping(e);
695
696	// the answer to this is not yet final - we schedule another closing check
697	if (new Date() - this.safariFlag < 1000 && recall){
698		var self = this;
699		setTimeout(function(){self.safariValidate(e, false);}, 1000);
700	}
701	return answer;
702};
703
704Spry.Widget.ValidationTextarea.prototype.safariChangeKeyPress = function(e){
705	this.safariChangeFlag = new Date();
706	return this.safariChangeValidate(e, true);
707};
708
709Spry.Widget.ValidationTextarea.prototype.safariChangeValidate = function(e, recall){
710	
711	if(e.keyCode && Spry.Widget.Utils.isSpecialKey(e) && e.keyCode != 8 && e.keyCode != 46){
712		return true;	
713	}
714	var answer = this.onChange(e);
715
716	// the answer to this is not yet final - we schedule another closing check
717	if (new Date() - this.safariChangeFlag < 1000 && recall){
718		var self = this;
719		setTimeout(function(){ self.safariChangeValidate(e, false);}, 1000 - new Date() + this.safariChangeFlag);
720	}
721	return answer;
722};
723
724/*
725 * save an initial state of the input to restore if the value is invalid
726 * 
727 */
728Spry.Widget.ValidationTextarea.prototype.saveState = function(e){
729	
730	// we don't need this initial value that is already invalid
731	if (this.options.maxChars > 0 && this.input.value.length > this.options.maxChars){
732		return;
733	}
734	this.cursorPosition.update();
735	if (!this.flags.hintOn){
736		this.initialValue = this.input.value;
737	}else{
738		this.initialValue = '';
739	}
740	this.initialCursor = this.cursorPosition; 
741	return true;
742};
743
744Spry.Widget.ValidationTextarea.prototype.checkClassName = function(ele, className){
745	if (!ele || !className){
746		return false;
747	}
748	if (typeof ele == 'string' ) {
749		ele = document.getElementById(ele);
750		if (!ele){
751			return false;	
752		}
753	}
754	if (!ele.className){
755		ele.className = ' ';
756	}
757	return ele;
758};
759
760Spry.Widget.ValidationTextarea.prototype.switchClassName = function (className){
761	var classes = [this.invalidCharsMaxClass, this.validClass, this.requiredClass, this.invalidCharsMinClass];
762	var self = this;
763	for (var k in classes){
764		if (classes[k] != className){
765				this.removeClassName(classes[k]);			
766		}
767	}
768
769	this.addClassName(className);
770};
771
772Spry.Widget.ValidationTextarea.prototype.addClassName = function(clssName){
773	var ele = this.checkClassName(this.element, clssName);
774	if (!ele || ele.className.search(new RegExp("\\b" + clssName + "\\b")) != -1){
775	  return;
776	}
777	this.element.className += ' ' + clssName;
778};
779
780Spry.Widget.ValidationTextarea.prototype.removeClassName = function(className){
781	var ele = this.checkClassName(this.element, className);
782	if (!ele){
783	  return;	
784	}
785	ele.className = ele.className.replace(new RegExp("\\s*\\b" + className + "\\b", "g"), '');
786}; 
787
788/**
789 * SelectionDescriptor is a wrapper for input type text selection methods and properties 
790 * as implemented by various  browsers
791 */
792Spry.Widget.SelectionDescriptor = function (element)
793{
794	this.element = element;
795	this.update();
796};
797
798Spry.Widget.SelectionDescriptor.prototype.update = function()
799{
800	if (Spry.is.ie && Spry.is.windows) {
801		if (this.element.nodeName == "TEXTAREA") {
802		var range = this.element.ownerDocument.selection.createRange();
803		if (range.parentElement() == this.element){
804			var range_all = this.element.ownerDocument.body.createTextRange();
805			range_all.moveToElementText(this.element);
806			for (var sel_start = 0; range_all.compareEndPoints('StartToStart', range) < 0; sel_start ++){
807			 	range_all.moveStart('character', 1);
808			}
809			this.start = sel_start;
810			// create a selection of the whole this.element
811			range_all = this.element.ownerDocument.body.createTextRange();
812			range_all.moveToElementText(this.element);
813			for (var sel_end = 0; range_all.compareEndPoints('StartToEnd', range) < 0; sel_end++){
814				range_all.moveStart('character', 1);
815			}
816			this.end = sel_end;
817			this.length = this.end - this.start;
818			// get selected and surrounding text
819			this.text = range.text;
820		 }
821		} else if (this.element.nodeName == "INPUT"){
822			this.range = this.element.ownerDocument.selection.createRange();
823			this.length = this.range.text.length;
824			var clone = this.range.duplicate();
825			this.start = -clone.moveStart("character", -10000);
826			clone = this.range.duplicate();
827			clone.collapse(false);
828			this.end = -clone.moveStart("character", -10000);
829			this.text = this.range.text;
830		}
831	} else {
832		var tmp = this.element;
833		var selectionStart = 0;
834		var selectionEnd = 0;
835
836		try { selectionStart = tmp.selectionStart; } catch(err) {}
837		try { selectionEnd = tmp.selectionEnd; } catch(err) {}
838
839		if (Spry.is.safari) {
840			if (selectionStart == 2147483647) {
841				selectionStart = 0;
842			}
843			if (selectionEnd == 2147483647) {
844				selectionEnd = 0;
845			}
846		}
847		this.start = selectionStart;
848		this.end = selectionEnd;
849		this.length = selectionEnd - selectionStart;
850		this.text = this.element.value.substring(selectionStart, selectionEnd);
851	}
852};
853
854Spry.Widget.SelectionDescriptor.prototype.destroy = function() {
855	try { delete this.range} catch(err) {}
856	try { delete this.element} catch(err) {}
857};
858
859Spry.Widget.SelectionDescriptor.prototype.moveTo = function(start, end)
860{
861	if (Spry.is.ie && Spry.is.windows) {
862		if (this.element.nodeName == "TEXTAREA") {
863			var ta_range = this.element.createTextRange();
864			this.range = this.element.createTextRange();
865			this.range.move("character", start);
866			this.range.moveEnd("character", end - start);
867			
868			var c1 = this.range.compareEndPoints("StartToStart", ta_range);
869			if (c1 < 0) {
870				this.range.setEndPoint("StartToStart", ta_range);
871			}
872
873			var c2 = this.range.compareEndPoints("EndToEnd", ta_range);
874			if (c2 > 0) {
875				this.range.setEndPoint("EndToEnd", ta_range);
876			}
877		} else if (this.element.nodeName == "INPUT"){
878			this.range = this.element.ownerDocument.selection.createRange();
879			this.range.move("character", -10000);
880			this.start = this.range.moveStart("character", start);
881			this.end = this.start + this.range.moveEnd("character", end - start);
882		}
883		this.range.select();
884	} else {
885		this.start = start;
886		try { this.element.selectionStart = start; } catch(err) {}
887		this.end = end;
888		try { this.element.selectionEnd = end; } catch(err) {}
889	}
890	this.ignore = true;
891	this.update();
892};
893
894//////////////////////////////////////////////////////////////////////
895//
896// Spry.Widget.Form - common for all widgets
897//
898//////////////////////////////////////////////////////////////////////
899
900if (!Spry.Widget.Form) Spry.Widget.Form = {};
901if (!Spry.Widget.Form.onSubmitWidgetQueue) Spry.Widget.Form.onSubmitWidgetQueue = [];
902
903if (!Spry.Widget.Form.validate) {
904	Spry.Widget.Form.validate = function(vform) {
905		var isValid = true;
906		var isElementValid = true;
907		var q = Spry.Widget.Form.onSubmitWidgetQueue;
908		var qlen = q.length;
909		for (var i = 0; i < qlen; i++) {
910			if (!q[i].isDisabled() && q[i].form == vform) {
911				isElementValid = q[i].validate();
912				isValid = isElementValid && isValid;
913			}
914		}
915		return isValid;
916	}
917};
918
919if (!Spry.Widget.Form.onSubmit) {
920	Spry.Widget.Form.onSubmit = function(e, form)
921	{
922		if (Spry.Widget.Form.validate(form) == false) {
923			return false;
924		}
925		return true;
926	};
927};
928
929if (!Spry.Widget.Form.onReset) {
930	Spry.Widget.Form.onReset = function(e, vform)
931	{
932		var q = Spry.Widget.Form.onSubmitWidgetQueue;
933		var qlen = q.length;
934		for (var i = 0; i < qlen; i++) {
935			if (!q[i].isDisabled() && q[i].form == vform && typeof(q[i].reset) == 'function') {
936				q[i].reset();
937			}
938		}
939		return true;
940	};
941};
942
943if (!Spry.Widget.Form.destroy) {
944	Spry.Widget.Form.destroy = function(form)
945	{
946		var q = Spry.Widget.Form.onSubmitWidgetQueue;
947		for (var i = 0; i < Spry.Widget.Form.onSubmitWidgetQueue.length; i++) {
948			if (q[i].form == form && typeof(q[i].destroy) == 'function') {
949				q[i].destroy();
950				i--;
951			}
952		}
953	}
954};
955
956if (!Spry.Widget.Form.destroyAll) {
957	Spry.Widget.Form.destroyAll = function()
958	{
959		var q = Spry.Widget.Form.onSubmitWidgetQueue;
960		for (var i = 0; i < Spry.Widget.Form.onSubmitWidgetQueue.length; i++) {
961			if (typeof(q[i].destroy) == 'function') {
962				q[i].destroy();
963				i--;
964			}
965		}
966	}
967};
968
969//////////////////////////////////////////////////////////////////////
970//
971// Spry.Widget.Utils
972//
973//////////////////////////////////////////////////////////////////////
974
975if (!Spry.Widget.Utils)	Spry.Widget.Utils = {};
976
977Spry.Widget.Utils.setOptions = function(obj, optionsObj, ignoreUndefinedProps)
978{
979	if (!optionsObj)
980		return;
981	for (var optionName in optionsObj)
982	{
983		if (ignoreUndefinedProps && optionsObj[optionName] == undefined)
984			continue;
985		obj[optionName] = optionsObj[optionName];
986	}
987};
988
989Spry.Widget.Utils.firstValid = function() {
990	var ret = null;
991	for(var i=0; i<Spry.Widget.Utils.firstValid.arguments.length; i++) {
992		if (typeof(Spry.Widget.Utils.firstValid.arguments[i]) != 'undefined') {
993			ret = Spry.Widget.Utils.firstValid.arguments[i];
994			break;
995		}
996	}
997	return ret;
998};
999
1000Spry.Widget.Utils.specialSafariNavKeys = ",63232,63233,63234,63235,63272,63273,63275,63276,63277,63289,";
1001
1002Spry.Widget.Utils.specialCharacters = ",8,9,16,17,18,20,27,33,34,35,36,37,38,39,40,45,46,91,92,93,144,192,63232,";
1003Spry.Widget.Utils.specialCharacters += Spry.Widget.Utils.specialSafariNavKeys;
1004
1005Spry.Widget.Utils.isSpecialKey = function (ev) {
1006	return Spry.Widget.Utils.specialCharacters.indexOf("," + ev.keyCode + ",") != -1;
1007};
1008
1009Spry.Widget.Utils.getFirstChildWithNodeNameAtAnyLevel = function(node, nodeName) {
1010	var elements  = node.getElementsByTagName(nodeName);
1011	if (elements) {
1012		return elements[0];
1013	}
1014	return null;
1015};
1016
1017Spry.Widget.Utils.getFirstParentWithNodeName = function(node, nodeName)
1018{
1019	while (node.parentNode
1020			&& node.parentNode.nodeName.toLowerCase() != nodeName.toLowerCase()
1021			&& node.parentNode.nodeName != 'BODY') {
1022		node = node.parentNode;
1023	}
1024
1025	if (node.parentNode && node.parentNode.nodeName.toLowerCase() == nodeName.toLowerCase()) {
1026		return node.parentNode;
1027	} else {
1028		return null;
1029	}
1030};
1031
1032Spry.Widget.Utils.destroyWidgets = function (container)
1033{
1034	if (typeof container == 'string') {
1035		container = document.getElementById(container);
1036	}
1037
1038	var q = Spry.Widget.Form.onSubmitWidgetQueue;
1039	for (var i = 0; i < Spry.Widget.Form.onSubmitWidgetQueue.length; i++) {
1040		if (typeof(q[i].destroy) == 'function' && Spry.Widget.Utils.contains(container, q[i].element)) {
1041			q[i].destroy();
1042			i--;
1043		}
1044	}
1045};
1046
1047Spry.Widget.Utils.contains = function (who, what)
1048{
1049	if (typeof who.contains == 'object') {
1050		return what && who && (who == what || who.contains(what));
1051	} else {
1052		var el = what;
1053		while(el) {
1054			if (el == who) {
1055				return true;
1056			}
1057			el = el.parentNode;
1058		}
1059		return false;
1060	}
1061};
1062
1063Spry.Widget.Utils.addEventListener = function(element, eventType, handler, capture)
1064{
1065	try
1066	{
1067		if (element.addEventListener)
1068			element.addEventListener(eventType, handler, capture);
1069		else if (element.attachEvent)
1070			element.attachEvent("on" + eventType, handler, capture);
1071	}
1072	catch (e) {}
1073};
1074
1075Spry.Widget.Utils.removeEventListener = function(element, eventType, handler, capture)
1076{
1077	try
1078	{
1079		if (element.removeEventListener)
1080			element.removeEventListener(eventType, handler, capture);
1081		else if (element.detachEvent)
1082			element.detachEvent("on" + eventType, handler, capture);
1083	}
1084	catch (e) {}
1085};
1086
1087Spry.Widget.Utils.stopEvent = function(ev)
1088{
1089	try
1090	{
1091		this.stopPropagation(ev);
1092		this.preventDefault(ev);
1093	}
1094	catch (e) {}
1095};
1096
1097/**
1098 * Stops event propagation
1099 * @param {Event} ev the event
1100 */
1101Spry.Widget.Utils.stopPropagation = function(ev)
1102{
1103	if (ev.stopPropagation)
1104	{
1105		ev.stopPropagation();
1106	}
1107	else
1108	{
1109		ev.cancelBubble = true;
1110	}
1111};
1112
1113/**
1114 * Prevents the default behavior of the event
1115 * @param {Event} ev the event
1116 */
1117Spry.Widget.Utils.preventDefault = function(ev)
1118{
1119	if (ev.preventDefault)
1120	{
1121		ev.preventDefault();
1122	}
1123	else
1124	{
1125		ev.returnValue = false;
1126	}
1127};

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.