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