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.