1// SpryValidationTextarea.js - version 0.15 - Spry Pre-Release 1.6 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 = 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 var val = this.input.value; 490 this.validateMinRequired(val); 491 492 var ret = !this.isMinInvalid && !this.isRequireInvalid; 493 494 if (ret && this.options.maxChars > 0 && !this.useCharacterMasking){ 495 if (val.length <= this.options.maxChars || (this.hint && this.hint == val && this.flags.hintOn)) { 496 this.switchClassName(this.validClass); 497 this.setState(Spry.Widget.ValidationTextarea.VALID); 498 this.isMaxInvalid = false; 499 }else{ 500 this.switchClassName(this.invalidCharsMaxClass); 501 this.setState(Spry.Widget.ValidationTextarea.MAXIMUM); 502 this.isMaxInvalid = true; 503 } 504 } 505 ret = ret && !this.isMaxInvalid; 506 if (ret) { 507 this.switchClassName(this.validClass); 508 } 509 this.counterChar(); 510 return ret; 511}; 512 513Spry.Widget.ValidationTextarea.prototype.setState = function(newstate){ 514 this.state = newstate; 515}; 516 517Spry.Widget.ValidationTextarea.prototype.getState = function(){ 518 return this.state; 519}; 520 521Spry.Widget.ValidationTextarea.prototype.removeHint = function() 522{ 523 if (this.flags.hintOn) 524 { 525 this.flags.locked = true; 526 this.input.value = ""; 527 this.flags.locked = false; 528 this.flags.hintOn = false; 529 this.removeClassName(this.hintClass); 530 } 531}; 532 533Spry.Widget.ValidationTextarea.prototype.putHint = function() 534{ 535 if(this.hint && this.input.value == "") { 536 this.flags.hintOn = true; 537 this.input.value = this.hint; 538 this.addClassName(this.hintClass); 539 } 540}; 541 542Spry.Widget.ValidationTextarea.prototype.redTextFlash = function() 543{ 544 var self = this; 545 this.addClassName(this.textareaFlashClass); 546 setTimeout(function() { 547 self.removeClassName(self.textareaFlashClass) 548 }, 200); 549}; 550 551 552Spry.Widget.ValidationTextarea.prototype.onKeyPress = function(e) 553{ 554 //ENTER has length 2 on IE Windows, so will exceed maxLength on proximity 555 if (Spry.is.ie && Spry.is.windows && e.keyCode == 13) { 556 if ( (this.initialCursor.length + this.options.maxChars - this.input.value.length) < 2) { 557 Spry.Widget.Utils.stopEvent(e); 558 return false; 559 } 560 } 561}; 562 563Spry.Widget.ValidationTextarea.prototype.onKeyDown = function(e) 564{ 565 this.saveState(); 566 this.keyCode = e.keyCode; 567 return true; 568}; 569 570/* 571 * hadle for the max chars restrictions 572 * if key pressed or the input text is invalid it returns false 573 * 574 */ 575Spry.Widget.ValidationTextarea.prototype.onKeyEvent = function(e){ 576 // on IE we look only for this input value changes 577 if (e.type == 'propertychange' && e.propertyName != 'value'){ 578 return true; 579 } 580 581 var allow = this.onTyping(e); 582 583 if (!allow){ 584 Spry.Widget.Utils.stopEvent(e); 585 } 586 //return allow; 587}; 588 589/* 590 * handle for the min or required value 591 * if the input text is invalid it returns false 592 * 593 */ 594Spry.Widget.ValidationTextarea.prototype.onChange = function(e){ 595 if (Spry.is.ie && e && e.type == 'propertychange' && e.propertyName != 'value') { 596 return true; 597 } 598 599 if (this.flags.drop) { 600 //delay this if it's a drop operation 601 var self = this; 602 setTimeout(function() { 603 self.flags.drop = false; 604 self.onChange(null); 605 }, 0); 606 return true; 607 } 608 if (this.flags.hintOn) { 609 return true; 610 } 611 this.onKeyEventOn = true; 612 var answer = this.validate(); 613 this.onKeyEventOn = false; 614 return answer; 615}; 616 617Spry.Widget.ValidationTextarea.prototype.onMouseDown = function(e) 618{ 619 if (this.flags.active) { 620 //mousedown fires before focus 621 //avoid double saveState on first focus by mousedown by checking if the control has focus 622 //do nothing if it's not focused because saveState will be called onfocus 623 this.saveState(); 624 } 625}; 626 627Spry.Widget.ValidationTextarea.prototype.onDrop = function(e) 628{ 629 //mark that a drop operation is in progress to avoid race conditions with event handlers for other events 630 //especially onchange and onfocus 631 this.flags.drop = true; 632 this.removeHint(); 633 634 if (Spry.is.ie) { 635 var rng = document.body.createTextRange(); 636 rng.moveToPoint(e.x, e.y); 637 rng.select(); 638 } 639 640 this.saveState(); 641 this.flags.active = true; 642 this.addClassName(this.focusClass); 643}; 644 645Spry.Widget.ValidationTextarea.prototype.onFocus = function(e) 646{ 647 if (this.flags.drop) { 648 return; 649 } 650 this.removeHint(); 651 this.saveState(); 652 this.flags.active = true; 653 this.addClassName(this.focusClass); 654}; 655 656Spry.Widget.ValidationTextarea.prototype.onBlur = function(e){
657 this.removeClassName(this.focusClass); 658 659 if (this.validateOn & Spry.Widget.ValidationTextarea.ONBLUR) { 660 this.onBlurOn = true; 661 this.validate(); 662 this.onBlurOn = false; 663 } 664 665 this.flags.active = false; 666 var self = this; 667 setTimeout(function() {self.putHint();}, 10); 668}; 669 670Spry.Widget.ValidationTextarea.prototype.safariMouseDown = function(e){ 671 this.safariClicked = true; 672}; 673Spry.Widget.ValidationTextarea.prototype.safariChangeMouseUp = function(e){ 674 if (!this.safariClicked){ 675 this.onKeyDown(e); 676 return this.safariChangeValidate(e, false); 677 }else{ 678 this.safariClicked = false; 679 return true; 680 } 681}; 682 683Spry.Widget.ValidationTextarea.prototype.safariMouseUp = function(e){ 684 if (!this.safariClicked){ 685 this.onKeyDown(e); 686 return this.safariValidate(e, false); 687 }else{ 688 this.safariClicked = false; 689 return true; 690 } 691}; 692 693Spry.Widget.ValidationTextarea.prototype.safariKeyPress = function(e){ 694 this.safariFlag = new Date(); 695 return this.safariValidate(e, true); 696}; 697 698Spry.Widget.ValidationTextarea.prototype.safariValidate = function(e, recall) 699{ 700 if (e.keyCode && Spry.Widget.Utils.isSpecialKey(e) && e.keyCode != 8 && e.keyCode != 46){ 701 return true; 702 } 703 var answer = this.onTyping(e); 704 705 // the answer to this is not yet final - we schedule another closing check 706 if (new Date() - this.safariFlag < 1000 && recall){ 707 var self = this; 708 setTimeout(function(){self.safariValidate(e, false);}, 1000); 709 } 710 return answer; 711}; 712 713Spry.Widget.ValidationTextarea.prototype.safariChangeKeyPress = function(e){ 714 this.safariChangeFlag = new Date(); 715 return this.safariChangeValidate(e, true); 716}; 717 718Spry.Widget.ValidationTextarea.prototype.safariChangeValidate = function(e, recall){ 719 720 if(e.keyCode && Spry.Widget.Utils.isSpecialKey(e) && e.keyCode != 8 && e.keyCode != 46){ 721 return true; 722 } 723 var answer = this.onChange(e); 724 725 // the answer to this is not yet final - we schedule another closing check 726 if (new Date() - this.safariChangeFlag < 1000 && recall){ 727 var self = this; 728 setTimeout(function(){ self.safariChangeValidate(e, false);}, 1000 - new Date() + this.safariChangeFlag); 729 } 730 return answer; 731}; 732 733/* 734 * save an initial state of the input to restore if the value is invalid 735 * 736 */ 737Spry.Widget.ValidationTextarea.prototype.saveState = function(e){ 738
739 // we don't need this initial value that is already invalid 740 if (this.options.maxChars > 0 && this.input.value.length > this.options.maxChars){ 741 return; 742 } 743 this.cursorPosition.update(); 744 if (!this.flags.hintOn){ 745 this.initialValue = this.input.value; 746 }else{ 747 this.initialValue = ''; 748 } 749 this.initialCursor = this.cursorPosition; 750 return true; 751}; 752 753Spry.Widget.ValidationTextarea.prototype.checkClassName = function(ele, className){ 754 if (!ele || !className){ 755 return false; 756 } 757 if (typeof ele == 'string' ) { 758 ele = document.getElementById(ele); 759 if (!ele){ 760 return false; 761 } 762 } 763 if (!ele.className){ 764 ele.className = ' '; 765 } 766 return ele; 767}; 768 769Spry.Widget.ValidationTextarea.prototype.switchClassName = function (className){ 770 var classes = [this.invalidCharsMaxClass, this.validClass, this.requiredClass, this.invalidCharsMinClass]; 771 772 for (var k = 0; k < classes.length; k++){ 773 if (classes[k] != className){ 774 this.removeClassName(classes[k]); 775 } 776 } 777 778 this.addClassName(className); 779}; 780 781Spry.Widget.ValidationTextarea.prototype.addClassName = function(clssName){ 782 var ele = this.checkClassName(this.element, clssName); 783 var add = this.checkClassName(this.additionalError, clssName); 784 785 if (!ele || ele.className.search(new RegExp("\\b" + clssName + "\\b")) != -1){ 786 return; 787 } 788 this.element.className += ' ' + clssName; 789 if (add) 790 add.className += ' ' + clssName; 791}; 792 793Spry.Widget.ValidationTextarea.prototype.removeClassName = function(className){ 794 var ele = this.checkClassName(this.element, className); 795 var add = this.checkClassName(this.additionalError, className); 796 if (!ele){ 797 return; 798 } 799 ele.className = ele.className.replace(new RegExp("\\s*\\b" + className + "\\b", "g"), ''); 800 if (add){ 801 add.className = add.className.replace(new RegExp("\\s*\\b" + className + "\\b", "g"), ''); 802 } 803}; 804 805/** 806 * SelectionDescriptor is a wrapper for input type text selection methods and properties 807 * as implemented by various browsers 808 */ 809Spry.Widget.SelectionDescriptor = function (element) 810{ 811 this.element = element; 812 this.update(); 813}; 814 815Spry.Widget.SelectionDescriptor.prototype.update = function() 816{ 817 if (Spry.is.ie && Spry.is.windows) { 818 var sel = this.element.ownerDocument.selection; 819 if (this.element.nodeName == "TEXTAREA") { 820 if (sel.type != 'None') { 821 try{var range = sel.createRange();}catch(err){return;} 822 if (range.parentElement() == this.element){ 823 var range_all = this.element.ownerDocument.body.createTextRange(); 824 range_all.moveToElementText(this.element); 825 for (var sel_start = 0; range_all.compareEndPoints('StartToStart', range) < 0; sel_start ++){ 826 range_all.moveStart('character', 1); 827 } 828 this.start = sel_start; 829 // create a selection of the whole this.element 830 range_all = this.element.ownerDocument.body.createTextRange(); 831 range_all.moveToElementText(this.element); 832 for (var sel_end = 0; range_all.compareEndPoints('StartToEnd', range) < 0; sel_end++){ 833 range_all.moveStart('character', 1); 834 } 835 this.end = sel_end; 836 this.length = this.end - this.start; 837 // get selected and surrounding text 838 this.text = range.text; 839 } 840 } 841 } else if (this.element.nodeName == "INPUT"){ 842 try{this.range = sel.createRange();}catch(err){return;} 843 this.length = this.range.text.length; 844 var clone = this.range.duplicate(); 845 this.start = -clone.moveStart("character", -10000); 846 clone = this.range.duplicate(); 847 clone.collapse(false); 848 this.end = -clone.moveStart("character", -10000); 849 this.text = this.range.text; 850 } 851 } else { 852 var tmp = this.element; 853 var selectionStart = 0; 854 var selectionEnd = 0; 855 856 try { selectionStart = tmp.selectionStart;} catch(err) {} 857 try { selectionEnd = tmp.selectionEnd;} catch(err) {} 858 859 if (Spry.is.safari) { 860 if (selectionStart == 2147483647) { 861 selectionStart = 0; 862 } 863 if (selectionEnd == 2147483647) { 864 selectionEnd = 0; 865 } 866 } 867 this.start = selectionStart; 868 this.end = selectionEnd; 869 this.length = selectionEnd - selectionStart; 870 this.text = this.element.value.substring(selectionStart, selectionEnd); 871 } 872}; 873Spry.Widget.SelectionDescriptor.prototype.destroy = function() { 874 try { delete this.range} catch(err) {} 875 try { delete this.element} catch(err) {} 876}; 877 878Spry.Widget.SelectionDescriptor.prototype.moveTo = function(start, end) 879{ 880 if (Spry.is.ie && Spry.is.windows) { 881 if (this.element.nodeName == "TEXTAREA") { 882 var ta_range = this.element.createTextRange(); 883 this.range = this.element.createTextRange(); 884 this.range.move("character", start); 885 this.range.moveEnd("character", end - start); 886 887 var c1 = this.range.compareEndPoints("StartToStart", ta_range); 888 if (c1 < 0) { 889 this.range.setEndPoint("StartToStart", ta_range); 890 } 891 892 var c2 = this.range.compareEndPoints("EndToEnd", ta_range); 893 if (c2 > 0) { 894 this.range.setEndPoint("EndToEnd", ta_range); 895 } 896 } else if (this.element.nodeName == "INPUT"){ 897 this.range = this.element.ownerDocument.selection.createRange(); 898 this.range.move("character", -10000); 899 this.start = this.range.moveStart("character", start); 900 this.end = this.start + this.range.moveEnd("character", end - start); 901 } 902 this.range.select(); 903 } else { 904 this.start = start; 905 try { this.element.selectionStart = start; } catch(err) {} 906 this.end = end; 907 try { this.element.selectionEnd = end; } catch(err) {} 908 } 909 this.ignore = true; 910 this.update(); 911}; 912
913////////////////////////////////////////////////////////////////////// 914// 915// Spry.Widget.Form - common for all widgets 916// 917////////////////////////////////////////////////////////////////////// 918 919if (!Spry.Widget.Form) Spry.Widget.Form = {}; 920if (!Spry.Widget.Form.onSubmitWidgetQueue) Spry.Widget.Form.onSubmitWidgetQueue = []; 921 922if (!Spry.Widget.Form.validate) { 923 Spry.Widget.Form.validate = function(vform) { 924 var isValid = true; 925 var isElementValid = true; 926 var q = Spry.Widget.Form.onSubmitWidgetQueue; 927 var qlen = q.length; 928 for (var i = 0; i < qlen; i++) { 929 if (!q[i].isDisabled() && q[i].form == vform) { 930 isElementValid = q[i].validate(); 931 isValid = isElementValid && isValid; 932 } 933 } 934 return isValid; 935 } 936}; 937 938if (!Spry.Widget.Form.onSubmit) { 939 Spry.Widget.Form.onSubmit = function(e, form) 940 { 941 if (Spry.Widget.Form.validate(form) == false) { 942 return false; 943 } 944 return true; 945 }; 946}; 947 948if (!Spry.Widget.Form.onReset) { 949 Spry.Widget.Form.onReset = function(e, vform) 950 { 951 var q = Spry.Widget.Form.onSubmitWidgetQueue; 952 var qlen = q.length; 953 for (var i = 0; i < qlen; i++) { 954 if (!q[i].isDisabled() && q[i].form == vform && typeof(q[i].reset) == 'function') { 955 q[i].reset(); 956 } 957 } 958 return true; 959 }; 960}; 961 962if (!Spry.Widget.Form.destroy) { 963 Spry.Widget.Form.destroy = function(form) 964 { 965 var q = Spry.Widget.Form.onSubmitWidgetQueue; 966 for (var i = 0; i < Spry.Widget.Form.onSubmitWidgetQueue.length; i++) { 967 if (q[i].form == form && typeof(q[i].destroy) == 'function') { 968 q[i].destroy(); 969 i--; 970 } 971 } 972 } 973}; 974 975if (!Spry.Widget.Form.destroyAll) { 976 Spry.Widget.Form.destroyAll = function() 977 { 978 var q = Spry.Widget.Form.onSubmitWidgetQueue; 979 for (var i = 0; i < Spry.Widget.Form.onSubmitWidgetQueue.length; i++) { 980 if (typeof(q[i].destroy) == 'function') { 981 q[i].destroy(); 982 i--; 983 } 984 } 985 } 986}; 987 988////////////////////////////////////////////////////////////////////// 989// 990// Spry.Widget.Utils 991// 992////////////////////////////////////////////////////////////////////// 993 994if (!Spry.Widget.Utils) Spry.Widget.Utils = {}; 995 996Spry.Widget.Utils.setOptions = function(obj, optionsObj, ignoreUndefinedProps) 997{ 998 if (!optionsObj) 999 return; 1000 for (var optionName in optionsObj) 1001 { 1002 if (ignoreUndefinedProps && optionsObj[optionName] == undefined) 1003 continue; 1004 obj[optionName] = optionsObj[optionName]; 1005 } 1006}; 1007 1008Spry.Widget.Utils.firstValid = function() { 1009 var ret = null; 1010 for(var i=0; i<Spry.Widget.Utils.firstValid.arguments.length; i++) { 1011 if (typeof(Spry.Widget.Utils.firstValid.arguments[i]) != 'undefined') { 1012 ret = Spry.Widget.Utils.firstValid.arguments[i]; 1013 break; 1014 } 1015 } 1016 return ret; 1017}; 1018 1019Spry.Widget.Utils.specialSafariNavKeys = ",63232,63233,63234,63235,63272,63273,63275,63276,63277,63289,"; 1020 1021Spry.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,"; 1022Spry.Widget.Utils.specialCharacters += Spry.Widget.Utils.specialSafariNavKeys; 1023 1024Spry.Widget.Utils.isSpecialKey = function (ev) { 1025 return Spry.Widget.Utils.specialCharacters.indexOf("," + ev.keyCode + ",") != -1; 1026}; 1027 1028Spry.Widget.Utils.getFirstChildWithNodeNameAtAnyLevel = function(node, nodeName) { 1029 var elements = node.getElementsByTagName(nodeName); 1030 if (elements) { 1031 return elements[0]; 1032 } 1033 return null; 1034}; 1035 1036Spry.Widget.Utils.getFirstParentWithNodeName = function(node, nodeName) 1037{ 1038 while (node.parentNode 1039 && node.parentNode.nodeName.toLowerCase() != nodeName.toLowerCase() 1040 && node.parentNode.nodeName != 'BODY') { 1041 node = node.parentNode; 1042 } 1043 1044 if (node.parentNode && node.parentNode.nodeName.toLowerCase() == nodeName.toLowerCase()) { 1045 return node.parentNode; 1046 } else { 1047 return null; 1048 } 1049}; 1050 1051Spry.Widget.Utils.destroyWidgets = function (container) 1052{ 1053 if (typeof container == 'string') { 1054 container = document.getElementById(container); 1055 } 1056 1057 var q = Spry.Widget.Form.onSubmitWidgetQueue; 1058 for (var i = 0; i < Spry.Widget.Form.onSubmitWidgetQueue.length; i++) { 1059 if (typeof(q[i].destroy) == 'function' && Spry.Widget.Utils.contains(container, q[i].element)) { 1060 q[i].destroy(); 1061 i--; 1062 } 1063 } 1064}; 1065 1066Spry.Widget.Utils.contains = function (who, what) 1067{ 1068 if (typeof who.contains == 'object') { 1069 return what && who && (who == what || who.contains(what)); 1070 } else { 1071 var el = what; 1072 while(el) { 1073 if (el == who) { 1074 return true; 1075 } 1076 el = el.parentNode; 1077 } 1078 return false; 1079 } 1080}; 1081 1082Spry.Widget.Utils.addEventListener = function(element, eventType, handler, capture) 1083{ 1084 try 1085 { 1086 if (element.addEventListener) 1087 element.addEventListener(eventType, handler, capture); 1088 else if (element.attachEvent) 1089 element.attachEvent("on" + eventType, handler, capture); 1090 } 1091 catch (e) {} 1092}; 1093 1094Spry.Widget.Utils.removeEventListener = function(element, eventType, handler, capture) 1095{ 1096 try 1097 { 1098 if (element.removeEventListener) 1099 element.removeEventListener(eventType, handler, capture); 1100 else if (element.detachEvent) 1101 element.detachEvent("on" + eventType, handler, capture); 1102 } 1103 catch (e) {} 1104}; 1105 1106Spry.Widget.Utils.stopEvent = function(ev) 1107{ 1108 try 1109 { 1110 this.stopPropagation(ev); 1111 this.preventDefault(ev); 1112 } 1113 catch (e) {} 1114}; 1115 1116/** 1117 * Stops event propagation 1118 * @param {Event} ev the event 1119 */ 1120Spry.Widget.Utils.stopPropagation = function(ev) 1121{ 1122 if (ev.stopPropagation) 1123 { 1124 ev.stopPropagation(); 1125 } 1126 else 1127 { 1128 ev.cancelBubble = true; 1129 } 1130}; 1131 1132/** 1133 * Prevents the default behavior of the event 1134 * @param {Event} ev the event 1135 */ 1136Spry.Widget.Utils.preventDefault = function(ev) 1137{ 1138 if (ev.preventDefault) 1139 { 1140 ev.preventDefault(); 1141 } 1142 else 1143 { 1144 ev.returnValue = false; 1145 } 1146};
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.