1/* 2* Really easy field validation with Prototype 3* http://tetlaw.id.au/view/javascript/really-easy-field-validation 4* Andrew Tetlaw 5* Version 1.5.4.1 (2007-01-05) 6* 7* Copyright (c) 2007 Andrew Tetlaw 8* Permission is hereby granted, free of charge, to any person 9* obtaining a copy of this software and associated documentation 10* files (the "Software"), to deal in the Software without 11* restriction, including without limitation the rights to use, copy, 12* modify, merge, publish, distribute, sublicense, and/or sell copies 13* of the Software, and to permit persons to whom the Software is 14* furnished to do so, subject to the following conditions: 15* 16* The above copyright notice and this permission notice shall be 17* included in all copies or substantial portions of the Software. 18* 19* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 20* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 22* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 23* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 24* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 25* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 26* SOFTWARE. 27* 28*/ 29var Validator = Class.create(); 30 31Validator.prototype = { 32 initialize : function(className, error, test, options) { 33 if(typeof test == 'function'){ 34 this.options = $H(options); 35 this._test = test; 36 } else { 37 this.options = $H(test); 38 this._test = function(){return true}; 39 } 40 this.error = error || 'Validation failed.'; 41 this.className = className; 42 }, 43 test : function(v, elm) { 44 return (this._test(v,elm) && this.options.all(function(p){ 45 return Validator.methods[p.key] ? Validator.methods[p.key](v,elm,p.value) : true; 46 })); 47 } 48} 49Validator.methods = { 50 pattern : function(v,elm,opt) {return Validation.get('IsEmpty').test(v) || opt.test(v)}, 51 minLength : function(v,elm,opt) {return v.length >= opt}, 52 maxLength : function(v,elm,opt) {return v.length <= opt}, 53 min : function(v,elm,opt) {return v >= parseFloat(opt)}, 54 max : function(v,elm,opt) {return v <= parseFloat(opt)}, 55 notOneOf : function(v,elm,opt) {return $A(opt).all(function(value) { 56 return v != value; 57 })}, 58 oneOf : function(v,elm,opt) {return $A(opt).any(function(value) { 59 return v == value; 60 })}, 61 is : function(v,elm,opt) {return v == opt}, 62 isNot : function(v,elm,opt) {return v != opt}, 63 equalToField : function(v,elm,opt) {return v == $F(opt)}, 64 notEqualToField : function(v,elm,opt) {return v != $F(opt)}, 65 include : function(v,elm,opt) {return $A(opt).all(function(value) { 66 return Validation.get(value).test(v,elm); 67 })} 68} 69 70var Validation = Class.create(); 71Validation.defaultOptions = { 72 onSubmit : true, 73 stopOnFirst : false, 74 immediate : false, 75 focusOnError : true, 76 useTitles : false, 77 addClassNameToContainer: false, 78 containerClassName: '.input-box', 79 onFormValidate : function(result, form) {}, 80 onElementValidate : function(result, elm) {} 81}; 82 83Validation.prototype = { 84 initialize : function(form, options){ 85 this.form = $(form); 86 if (!this.form) { 87 return; 88 } 89 this.options = Object.extend({ 90 onSubmit : Validation.defaultOptions.onSubmit, 91 stopOnFirst : Validation.defaultOptions.stopOnFirst, 92 immediate : Validation.defaultOptions.immediate, 93 focusOnError : Validation.defaultOptions.focusOnError, 94 useTitles : Validation.defaultOptions.useTitles, 95 onFormValidate : Validation.defaultOptions.onFormValidate, 96 onElementValidate : Validation.defaultOptions.onElementValidate 97 }, options || {}); 98 if(this.options.onSubmit) Event.observe(this.form,'submit',this.onSubmit.bind(this),false); 99 if(this.options.immediate) { 100 Form.getElements(this.form).each(function(input) { // Thanks Mike! 101 if (input.tagName.toLowerCase() == 'select') { 102 Event.observe(input, 'blur', this.onChange.bindAsEventListener(this)); 103 } 104 if (input.type.toLowerCase() == 'radio' || input.type.toLowerCase() == 'checkbox') { 105 Event.observe(input, 'click', this.onChange.bindAsEventListener(this)); 106 } else { 107 Event.observe(input, 'change', this.onChange.bindAsEventListener(this)); 108 } 109 }, this); 110 } 111 }, 112 onChange : function (ev) { 113 Validation.isOnChange = true; 114 Validation.validate(Event.element(ev),{ 115 useTitle : this.options.useTitles, 116 onElementValidate : this.options.onElementValidate 117 }); 118 Validation.isOnChange = false;
119 }, 120 onSubmit : function(ev){ 121 if(!this.validate()) Event.stop(ev); 122 }, 123 validate : function() { 124 var result = false; 125 var useTitles = this.options.useTitles; 126 var callback = this.options.onElementValidate; 127 try { 128 if(this.options.stopOnFirst) { 129 result = Form.getElements(this.form).all(function(elm) { 130 if (elm.hasClassName('local-validation') && !this.isElementInForm(elm, this.form)) { 131 return true; 132 } 133 return Validation.validate(elm,{useTitle : useTitles, onElementValidate : callback}); 134 }, this); 135 } else { 136 result = Form.getElements(this.form).collect(function(elm) { 137 if (elm.hasClassName('local-validation') && !this.isElementInForm(elm, this.form)) { 138 return true; 139 } 140 return Validation.validate(elm,{useTitle : useTitles, onElementValidate : callback}); 141 }, this).all(); 142 } 143 } catch (e) { 144 } 145 if(!result && this.options.focusOnError) { 146 try{ 147 Form.getElements(this.form).findAll(function(elm){return $(elm).hasClassName('validation-failed')}).first().focus() 148 } 149 catch(e){ 150 } 151 } 152 this.options.onFormValidate(result, this.form); 153 return result; 154 }, 155 reset : function() { 156 Form.getElements(this.form).each(Validation.reset); 157 }, 158 isElementInForm : function(elm, form) { 159 var domForm = elm.up('form'); 160 if (domForm == form) { 161 return true; 162 } 163 return false; 164 } 165} 166 167Object.extend(Validation, { 168 validate : function(elm, options){ 169 options = Object.extend({ 170 useTitle : false, 171 onElementValidate : function(result, elm) {} 172 }, options || {}); 173 elm = $(elm); 174 175 var cn = $w(elm.className); 176 return result = cn.all(function(value) { 177 var test = Validation.test(value,elm,options.useTitle); 178 options.onElementValidate(test, elm); 179 return test; 180 }); 181 }, 182 insertAdvice : function(elm, advice){ 183 var container = $(elm).up('.field-row'); 184 if(container){ 185 Element.insert(container, {after: advice}); 186 } else if (elm.up('td.value')) { 187 elm.up('td.value').insert({bottom: advice}); 188 } else if (elm.advaiceContainer && $(elm.advaiceContainer)) { 189 $(elm.advaiceContainer).update(advice); 190 } 191 else { 192 switch (elm.type.toLowerCase()) { 193 case 'checkbox': 194 case 'radio': 195 var p = elm.parentNode; 196 if(p) { 197 Element.insert(p, {'bottom': advice}); 198 } else { 199 Element.insert(elm, {'after': advice}); 200 } 201 break; 202 default: 203 Element.insert(elm, {'after': advice}); 204 } 205 } 206 }, 207 showAdvice : function(elm, advice, adviceName){ 208 if(!elm.advices){ 209 elm.advices = new Hash(); 210 } 211 else{ 212 elm.advices.each(function(pair){ 213 if (!advice || pair.value.id != advice.id) { 214 // hide non-current advice after delay 215 this.hideAdvice(elm, pair.value); 216 } 217 }.bind(this)); 218 } 219 elm.advices.set(adviceName, advice); 220 if(typeof Effect == 'undefined') { 221 advice.style.display = 'block'; 222 } else { 223 if(!advice._adviceAbsolutize) { 224 new Effect.Appear(advice, {duration : 1 }); 225 } else { 226 Position.absolutize(advice); 227 advice.show(); 228 advice.setStyle({ 229 'top':advice._adviceTop, 230 'left': advice._adviceLeft, 231 'width': advice._adviceWidth, 232 'z-index': 1000 233 }); 234 advice.addClassName('advice-absolute'); 235 } 236 } 237 }, 238 hideAdvice : function(elm, advice){ 239 if (advice != null) { 240 new Effect.Fade(advice, {duration : 1, afterFinishInternal : function() {advice.hide();}}); 241 } 242 }, 243 updateCallback : function(elm, status) { 244 if (typeof elm.callbackFunction != 'undefined') { 245 eval(elm.callbackFunction+'(\''+elm.id+'\',\''+status+'\')'); 246 } 247 }, 248 ajaxError : function(elm, errorMsg) { 249 var name = 'validate-ajax'; 250 var advice = Validation.getAdvice(name, elm); 251 if (advice == null) { 252 advice = this.createAdvice(name, elm, false, errorMsg); 253 } 254 this.showAdvice(elm, advice, 'validate-ajax'); 255 this.updateCallback(elm, 'failed'); 256 257 elm.addClassName('validation-failed'); 258 elm.addClassName('validate-ajax'); 259 if (Validation.defaultOptions.addClassNameToContainer && Validation.defaultOptions.containerClassName != '') { 260 var container = elm.up(Validation.defaultOptions.containerClassName); 261 if (container && this.allowContainerClassName(elm)) { 262 container.removeClassName('validation-passed'); 263 container.addClassName('validation-error'); 264 } 265 } 266 }, 267 allowContainerClassName: function (elm) { 268 if (elm.type == 'radio' || elm.type == 'checkbox') { 269 return elm.hasClassName('change-container-classname'); 270 } 271 272 return true; 273 }, 274 test : function(name, elm, useTitle) { 275 var v = Validation.get(name); 276 var prop = '__advice'+name.camelize(); 277 try { 278 if(Validation.isVisible(elm) && !v.test($F(elm), elm)) { 279 //if(!elm[prop]) { 280 var advice = Validation.getAdvice(name, elm); 281 if (advice == null) { 282 advice = this.createAdvice(name, elm, useTitle); 283 } 284 this.showAdvice(elm, advice, name); 285 this.updateCallback(elm, 'failed'); 286 //} 287 elm[prop] = 1; 288 if (!elm.advaiceContainer) { 289 elm.removeClassName('validation-passed'); 290 elm.addClassName('validation-failed'); 291 } 292 293 if (Validation.defaultOptions.addClassNameToContainer && Validation.defaultOptions.containerClassName != '') { 294 var container = elm.up(Validation.defaultOptions.containerClassName); 295 if (container && this.allowContainerClassName(elm)) { 296 container.removeClassName('validation-passed'); 297 container.addClassName('validation-error'); 298 } 299 } 300 return false;
301 } else { 302 var advice = Validation.getAdvice(name, elm); 303 this.hideAdvice(elm, advice); 304 this.updateCallback(elm, 'passed'); 305 elm[prop] = ''; 306 elm.removeClassName('validation-failed'); 307 elm.addClassName('validation-passed'); 308 if (Validation.defaultOptions.addClassNameToContainer && Validation.defaultOptions.containerClassName != '') { 309 var container = elm.up(Validation.defaultOptions.containerClassName); 310 if (container && !container.down('.validation-failed') && this.allowContainerClassName(elm)) { 311 if (!Validation.get('IsEmpty').test(elm.value) || !this.isVisible(elm)) { 312 container.addClassName('validation-passed'); 313 } else { 314 container.removeClassName('validation-passed'); 315 } 316 container.removeClassName('validation-error'); 317 } 318 } 319 return true; 320 } 321 } catch(e) { 322 throw(e) 323 } 324 }, 325 isVisible : function(elm) { 326 while(elm.tagName != 'BODY') { 327 if(!$(elm).visible()) return false; 328 elm = elm.parentNode; 329 } 330 return true; 331 }, 332 getAdvice : function(name, elm) { 333 return $('advice-' + name + '-' + Validation.getElmID(elm)) || $('advice-' + Validation.getElmID(elm)); 334 }, 335 createAdvice : function(name, elm, useTitle, customError) { 336 var v = Validation.get(name); 337 var errorMsg = useTitle ? ((elm && elm.title) ? elm.title : v.error) : v.error; 338 if (customError) { 339 errorMsg = customError; 340 } 341 try { 342 if (Translator){ 343 errorMsg = Translator.translate(errorMsg); 344 } 345 } 346 catch(e){} 347 348 advice = '<div class="validation-advice" id="advice-' + name + '-' + Validation.getElmID(elm) +'" style="display:none">' + errorMsg + '</div>' 349 350 351 Validation.insertAdvice(elm, advice); 352 advice = Validation.getAdvice(name, elm); 353 if($(elm).hasClassName('absolute-advice')) { 354 var dimensions = $(elm).getDimensions(); 355 var originalPosition = Position.cumulativeOffset(elm); 356 357 advice._adviceTop = (originalPosition[1] + dimensions.height) + 'px'; 358 advice._adviceLeft = (originalPosition[0]) + 'px'; 359 advice._adviceWidth = (dimensions.width) + 'px'; 360 advice._adviceAbsolutize = true; 361 } 362 return advice; 363 }, 364 getElmID : function(elm) { 365 return elm.id ? elm.id : elm.name; 366 }, 367 reset : function(elm) { 368 elm = $(elm); 369 var cn = $w(elm.className); 370 cn.each(function(value) { 371 var prop = '__advice'+value.camelize(); 372 if(elm[prop]) { 373 var advice = Validation.getAdvice(value, elm); 374 if (advice) { 375 advice.hide(); 376 } 377 elm[prop] = ''; 378 } 379 elm.removeClassName('validation-failed'); 380 elm.removeClassName('validation-passed'); 381 if (Validation.defaultOptions.addClassNameToContainer && Validation.defaultOptions.containerClassName != '') { 382 var container = elm.up(Validation.defaultOptions.containerClassName); 383 if (container) { 384 container.removeClassName('validation-passed'); 385 container.removeClassName('validation-error'); 386 } 387 } 388 }); 389 }, 390 add : function(className, error, test, options) { 391 var nv = {}; 392 nv[className] = new Validator(className, error, test, options); 393 Object.extend(Validation.methods, nv); 394 }, 395 addAllThese : function(validators) { 396 var nv = {}; 397 $A(validators).each(function(value) { 398 nv[value[0]] = new Validator(value[0], value[1], value[2], (value.length > 3 ? value[3] : {})); 399 }); 400 Object.extend(Validation.methods, nv); 401 }, 402 get : function(name) { 403 return Validation.methods[name] ? Validation.methods[name] : Validation.methods['_LikeNoIDIEverSaw_']; 404 }, 405 methods : { 406 '_LikeNoIDIEverSaw_' : new Validator('_LikeNoIDIEverSaw_','',{}) 407 } 408}); 409 410Validation.add('IsEmpty', '', function(v) { 411 return (v == '' || (v == null) || (v.length == 0) || /^\s+$/.test(v)); 412}); 413 414Validation.addAllThese([ 415 ['validate-no-html-tags', 'HTML tags are not allowed', function(v) { 416 return !/<(\/)?\w+/.test(v); 417 }], 418 ['validate-select', 'Please select an option.', function(v) { 419 return ((v != "none") && (v != null) && (v.length != 0)); 420 }], 421 ['required-entry', 'This is a required field.', function(v) { 422 return !Validation.get('IsEmpty').test(v); 423 }], 424 ['validate-number', 'Please enter a valid number in this field.', function(v) { 425 return Validation.get('IsEmpty').test(v) 426 || (!isNaN(parseNumber(v)) && /^\s*-?\d*(\.\d*)?\s*$/.test(v)); 427 }], 428 ['validate-number-range', 'The value is not within the specified range.', function(v, elm) { 429 if (Validation.get('IsEmpty').test(v)) { 430 return true; 431 } 432 433 var numValue = parseNumber(v); 434 if (isNaN(numValue)) { 435 return false;
436 } 437 438 var reRange = /^number-range-(-?[\d.,]+)?-(-?[\d.,]+)?$/, 439 result = true; 440 441 $w(elm.className).each(function(name) { 442 var m = reRange.exec(name); 443 if (m) { 444 result = result 445 && (m[1] == null || m[1] == '' || numValue >= parseNumber(m[1])) 446 && (m[2] == null || m[2] == '' || numValue <= parseNumber(m[2])); 447 } 448 }); 449 450 return result; 451 }], 452 ['validate-digits', 'Please use numbers only in this field. Please avoid spaces or other characters such as dots or commas.', function(v) { 453 return Validation.get('IsEmpty').test(v) || !/[^\d]/.test(v); 454 }], 455 ['validate-digits-range', 'The value is not within the specified range.', function(v, elm) { 456 if (Validation.get('IsEmpty').test(v)) { 457 return true; 458 } 459 460 var numValue = parseNumber(v); 461 if (isNaN(numValue)) { 462 return false; 463 } 464 465 var reRange = /^digits-range-(-?\d+)?-(-?\d+)?$/, 466 result = true; 467 468 $w(elm.className).each(function(name) { 469 var m = reRange.exec(name); 470 if (m) { 471 result = result 472 && (m[1] == null || m[1] == '' || numValue >= parseNumber(m[1])) 473 && (m[2] == null || m[2] == '' || numValue <= parseNumber(m[2])); 474 } 475 }); 476 477 return result; 478 }], 479 ['validate-alpha', 'Please use letters only (a-z or A-Z) in this field.', function (v) { 480 return Validation.get('IsEmpty').test(v) || /^[a-zA-Z]+$/.test(v) 481 }], 482 ['validate-code', 'Please use only letters (a-z), numbers (0-9) or underscore(_) in this field, first character should be a letter.', function (v) { 483 return Validation.get('IsEmpty').test(v) || /^[a-z]+[a-z0-9_]+$/.test(v) 484 }], 485 ['validate-alphanum', 'Please use only letters (a-z or A-Z) or numbers (0-9) only in this field. No spaces or other characters are allowed.', function(v) { 486 return Validation.get('IsEmpty').test(v) || /^[a-zA-Z0-9]+$/.test(v) 487 }], 488 ['validate-alphanum-with-spaces', 'Please use only letters (a-z or A-Z), numbers (0-9) or spaces only in this field.', function(v) { 489 return Validation.get('IsEmpty').test(v) || /^[a-zA-Z0-9 ]+$/.test(v) 490 }], 491 ['validate-street', 'Please use only letters (a-z or A-Z) or numbers (0-9) or spaces and # only in this field.', function(v) { 492 return Validation.get('IsEmpty').test(v) || /^[ \w]{3,}([A-Za-z]\.)?([ \w]*\#\d+)?(\r\n| )[ \w]{3,}/.test(v) 493 }], 494 ['validate-phoneStrict', 'Please enter a valid phone number. For example (123) 456-7890 or 123-456-7890.', function(v) { 495 return Validation.get('IsEmpty').test(v) || /^(\()?\d{3}(\))?(-|\s)?\d{3}(-|\s)\d{4}$/.test(v); 496 }], 497 ['validate-phoneLax', 'Please enter a valid phone number. For example (123) 456-7890 or 123-456-7890.', function(v) { 498 return Validation.get('IsEmpty').test(v) || /^((\d[-. ]?)?((\(\d{3}\))|\d{3}))?[-. ]?\d{3}[-. ]?\d{4}$/.test(v); 499 }], 500 ['validate-fax', 'Please enter a valid fax number. For example (123) 456-7890 or 123-456-7890.', function(v) { 501 return Validation.get('IsEmpty').test(v) || /^(\()?\d{3}(\))?(-|\s)?\d{3}(-|\s)\d{4}$/.test(v); 502 }], 503 ['validate-date', 'Please enter a valid date.', function(v) { 504 var test = new Date(v); 505 return Validation.get('IsEmpty').test(v) || !isNaN(test); 506 }], 507 ['validate-date-range', 'The From Date value should be less than or equal to the To Date value.', function(v, elm) { 508 var m = /\bdate-range-(\w+)-(\w+)\b/.exec(elm.className); 509 if (!m || m[2] == 'to' || Validation.get('IsEmpty').test(v)) { 510 return true; 511 } 512 513 var currentYear = new Date().getFullYear() + ''; 514 var normalizedTime = function(v) { 515 v = v.split(/[.\/]/); 516 if (v[2] && v[2].length < 4) { 517 v[2] = currentYear.substr(0, v[2].length) + v[2]; 518 } 519 return new Date(v.join('/')).getTime(); 520 }; 521 522 var dependentElements = Element.select(elm.form, '.validate-date-range.date-range-' + m[1] + '-to'); 523 return !dependentElements.length || Validation.get('IsEmpty').test(dependentElements[0].value) 524 || normalizedTime(v) <= normalizedTime(dependentElements[0].value); 525 }], 526 ['validate-email', 'Please enter a valid email address. For example [email protected].', function (v) { 527 //return Validation.get('IsEmpty').test(v) || /\w{1,}[@][\w\-]{1,}([.]([\w\-]{1,})){1,3}$/.test(v) 528 //return Validation.get('IsEmpty').test(v) || /^[\!\#$%\*/?|\^\{\}`~&\'\+\-=_a-z0-9][\!\#$%\*/?|\^\{\}`~&\'\+\-=_a-z0-9\.]{1,30}[\!\#$%\*/?|\^\{\}`~&\'\+\-=_a-z0-9]@([a-z0-9_-]{1,30}\.){1,5}[a-z]{2,4}$/i.test(v) 529 return Validation.get('IsEmpty').test(v) || /^([a-z0-9,!\#\$%&'\*\+\/=\?\^_`\{\|\}~-]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z0-9,!\#\$%&'\*\+\/=\?\^_`\{\|\}~-]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*@([a-z0-9-]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z0-9-]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*\.(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]){2,})$/i.test(v) 530 }], 531 ['validate-emailSender', 'Please use only visible characters and spaces.', function (v) { 532 return Validation.get('IsEmpty').test(v) || /^[\S ]+$/.test(v) 533 }], 534 ['validate-password', 'Please enter more characters or clean leading or trailing space
534s.', function(v, elm) { 535 var pass=v.strip(); /*strip leading and trailing spaces*/ 536 var reMin = new RegExp(/^min-pass-length-[0-9]+$/); 537 var minLength = 7; 538 $w(elm.className).each(function(name, index) { 539 if (name.match(reMin)) { 540 minLength = name.split('-')[3]; 541 } 542 }); 543 return (!(v.length > 0 && v.length < minLength) && v.length == pass.length); 544 }], 545 ['validate-admin-password', 'Please enter more characters. Password should contain both numeric and alphabetic characters.', function(v, elm) { 546 var pass=v.strip(); 547 if (0 == pass.length) { 548 return true; 549 } 550 if (!(/[a-z]/i.test(v)) || !(/[0-9]/.test(v))) { 551 return false; 552 } 553 var reMin = new RegExp(/^min-admin-pass-length-[0-9]+$/); 554 var minLength = 7; 555 $w(elm.className).each(function(name, index) { 556 if (name.match(reMin)) { 557 minLength = name.split('-')[4]; 558 } 559 }); 560 return !(pass.length < minLength); 561 }], 562 ['validate-cpassword', 'Please make sure your passwords match.', function(v) { 563 var conf = $('confirmation') ? $('confirmation') : $$('.validate-cpassword')[0]; 564 var pass = false; 565 if ($('password')) { 566 pass = $('password'); 567 } 568 var passwordElements = $$('.validate-password'); 569 for (var i = 0; i < passwordElements.size(); i++) { 570 var passwordElement = passwordElements[i]; 571 if (passwordElement.up('form').id == conf.up('form').id) { 572 pass = passwordElement; 573 } 574 } 575 if ($$('.validate-admin-password').size()) { 576 pass = $$('.validate-admin-password')[0]; 577 } 578 return (pass.value == conf.value); 579 }], 580 ['validate-both-passwords', 'Please make sure your passwords match.', function(v, input) { 581 var dependentInput = $(input.form[input.name == 'password' ? 'confirmation' : 'password']), 582 isEqualValues = input.value == dependentInput.value; 583 584 if (isEqualValues && dependentInput.hasClassName('validation-failed')) { 585 Validation.test(this.className, dependentInput); 586 } 587 588 return dependentInput.value == '' || isEqualValues; 589 }], 590 ['validate-url', 'Please enter a valid URL. Protocol is required (http://, https:// or ftp://)', function (v) { 591 v = (v || '').replace(/^\s+/, '').replace(/\s+$/, ''); 592 return Validation.get('IsEmpty').test(v) || /^(https?|ftp):\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(\#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i.test(v) 593 }], 594 ['validate-clean-url', 'Please enter a valid URL. For example http://www.example.com or www.example.com', function (v) { 595 return Validation.get('IsEmpty').test(v) || /^(http|https|ftp):\/\/(([A-Z0-9][A-Z0-9_-]*)(\.[A-Z0-9][A-Z0-9_-]*)+.(com|org|net|dk|at|us|tv|info|uk|co.uk|biz|se)$)(:(\d+))?\/?/i.test(v) || /^(www)((\.[A-Z0-9][A-Z0-9_-]*)+.(com|org|net|dk|at|us|tv|info|uk|co.uk|biz|se)$)(:(\d+))?\/?/i.test(v) 596 }], 597 ['validate-identifier', 'Please enter a valid URL Key. For example "example-page", "example-page.html" or "anotherlevel/example-page".', function (v) { 598 return Validation.get('IsEmpty').test(v) || /^[a-z0-9][a-z0-9_\/-]+(\.[a-z0-9_-]+)?$/.test(v) 599 }], 600 ['validate-xml-identifier', 'Please enter a valid XML-identifier. For example something_1, block5, id-4.', function (v) { 601 return Validation.get('IsEmpty').test(v) || /^[A-Z][A-Z0-9_\/-]*$/i.test(v) 602 }], 603 ['validate-ssn', 'Please enter a valid social security number. For example 123-45-6789.', function(v) { 604 return Validation.get('IsEmpty').test(v) || /^\d{3}-?\d{2}-?\d{4}$/.test(v); 605 }], 606 ['validate-zip', 'Please enter a valid zip code. For example 90602 or 90602-1234.', function(v) { 607 return Validation.get('IsEmpty').test(v) || /(^\d{5}$)|(^\d{5}-\d{4}$)/.test(v); 608 }], 609 ['validate-zip-international', 'Please enter a valid zip code.', function(v) { 610 //return Validation.get('IsEmpty').test(v) || /(^[A-z0-9]{2,10}([\s]{0,1}|[\-]{0,1})[A-z0-9]{2,10}$)/.test(v); 611 return true; 612 }], 613 ['validate-date-au', 'Please use this date format: dd/mm/yyyy. For example 17/03/2006 for the 17th of March, 2006.', function(v) { 614 if(Validation.get('IsEmpty').test(v)) return true; 615 var regex = /^(\d{2})\/(\d{2})\/(\d{4})$/; 616 if(!regex.test(v)) return false;
617 var d = new Date(v.replace(regex, '$2/$1/$3')); 618 return ( parseInt(RegExp.$2, 10) == (1+d.getMonth()) ) && 619 (parseInt(RegExp.$1, 10) == d.getDate()) && 620 (parseInt(RegExp.$3, 10) == d.getFullYear() ); 621 }], 622 ['validate-currency-dollar', 'Please enter a valid $ amount. For example $100.00.', function(v) { 623 // [$]1[##][,###]+[.##] 624 // [$]1###+[.##] 625 // [$]0.## 626 // [$].## 627 return Validation.get('IsEmpty').test(v) || /^\$?\-?([1-9]{1}[0-9]{0,2}(\,[0-9]{3})*(\.[0-9]{0,2})?|[1-9]{1}\d*(\.[0-9]{0,2})?|0(\.[0-9]{0,2})?|(\.[0-9]{1,2})?)$/.test(v) 628 }], 629 ['validate-one-required', 'Please select one of the above options.', function (v,elm) { 630 var p = elm.parentNode; 631 var options = p.getElementsByTagName('INPUT'); 632 return $A(options).any(function(elm) { 633 return $F(elm); 634 }); 635 }], 636 ['validate-one-required-by-name', 'Please select one of the options.', function (v,elm) { 637 var inputs = $$('input[name="' + elm.name.replace(/([\\"])/g, '\\$1') + '"]'); 638 639 var error = 1; 640 for(var i=0;i<inputs.length;i++) { 641 if((inputs[i].type == 'checkbox' || inputs[i].type == 'radio') && inputs[i].checked == true) { 642 error = 0; 643 } 644 645 if(Validation.isOnChange && (inputs[i].type == 'checkbox' || inputs[i].type == 'radio')) { 646 Validation.reset(inputs[i]); 647 } 648 } 649 650 if( error == 0 ) { 651 return true; 652 } else { 653 return false; 654 } 655 }], 656 ['validate-not-negative-number', 'Please enter a number 0 or greater in this field.', function(v) { 657 if (Validation.get('IsEmpty').test(v)) { 658 return true; 659 } 660 v = parseNumber(v); 661 return !isNaN(v) && v >= 0; 662 }], 663 ['validate-zero-or-greater', 'Please enter a number 0 or greater in this field.', function(v) { 664 return Validation.get('validate-not-negative-number').test(v); 665 }], 666 ['validate-greater-than-zero', 'Please enter a number greater than 0 in this field.', function(v) { 667 if (Validation.get('IsEmpty').test(v)) { 668 return true; 669 } 670 v = parseNumber(v); 671 return !isNaN(v) && v > 0; 672 }], 673 ['validate-state', 'Please select State/Province.', function(v) { 674 return (v!=0 || v == ''); 675 }], 676 ['validate-new-password', 'Please enter more characters or clean leading or trailing spaces.', function(v, elm) { 677 if (!Validation.get('validate-password').test(v, elm)) return false; 678 if (Validation.get('IsEmpty').test(v) && v != '') return false; 679 return true; 680 }], 681 ['validate-cc-number', 'Please enter a valid credit card number.', function(v, elm) { 682 // remove non-numerics 683 var ccTypeContainer = $(elm.id.substr(0,elm.id.indexOf('_cc_number')) + '_cc_type'); 684 if (ccTypeContainer && typeof Validation.creditCartTypes.get(ccTypeContainer.value) != 'undefined' 685 && Validation.creditCartTypes.get(ccTypeContainer.value)[2] == false) { 686 if (!Validation.get('IsEmpty').test(v) && Validation.get('validate-digits').test(v)) { 687 return true; 688 } else { 689 return false; 690 } 691 } 692 return validateCreditCard(v); 693 }], 694 ['validate-cc-type', 'Credit card number does not match credit card type.', function(v, elm) { 695 // remove credit card number delimiters such as "-" and space 696 elm.value = removeDelimiters(elm.value); 697 v = removeDelimiters(v); 698 699 var ccTypeContainer = $(elm.id.substr(0,elm.id.indexOf('_cc_number')) + '_cc_type'); 700 if (!ccTypeContainer) { 701 return true; 702 } 703 var ccType = ccTypeContainer.value; 704 705 if (typeof Validation.creditCartTypes.get(ccType) == 'undefined') { 706 return false;
707 } 708 709 // Other card type or switch or solo card 710 if (Validation.creditCartTypes.get(ccType)[0]==false) { 711 return true; 712 } 713 714 var validationFailure = false; 715 Validation.creditCartTypes.each(function (pair) { 716 if (pair.key == ccType) { 717 if (pair.value[0] && !v.match(pair.value[0])) { 718 validationFailure = true; 719 } 720 throw $break; 721 } 722 }); 723 724 if (validationFailure) { 725 return false; 726 } 727 728 if (ccTypeContainer.hasClassName('validation-failed') && Validation.isOnChange) { 729 Validation.validate(ccTypeContainer); 730 } 731 732 return true; 733 }], 734 ['validate-cc-type-select', 'Card type does not match credit card number.', function(v, elm) { 735 var ccNumberContainer = $(elm.id.substr(0,elm.id.indexOf('_cc_type')) + '_cc_number'); 736 if (Validation.isOnChange && Validation.get('IsEmpty').test(ccNumberContainer.value)) { 737 return true; 738 } 739 if (Validation.get('validate-cc-type').test(ccNumberContainer.value, ccNumberContainer)) { 740 Validation.validate(ccNumberContainer); 741 } 742 return Validation.get('validate-cc-type').test(ccNumberContainer.value, ccNumberContainer); 743 }], 744 ['validate-cc-exp', 'Incorrect credit card expiration date.', function(v, elm) { 745 var ccExpMonth = v; 746 var ccExpYear = $(elm.id.substr(0,elm.id.indexOf('_expiration')) + '_expiration_yr').value; 747 var currentTime = new Date(); 748 var currentMonth = currentTime.getMonth() + 1; 749 var currentYear = currentTime.getFullYear(); 750 if (ccExpMonth < currentMonth && ccExpYear == currentYear) { 751 return false; 752 } 753 return true; 754 }], 755 ['validate-cc-cvn', 'Please enter a valid credit card verification number.', function(v, elm) { 756 var ccTypeContainer = $(elm.id.substr(0,elm.id.indexOf('_cc_cid')) + '_cc_type'); 757 if (!ccTypeContainer) { 758 return true; 759 } 760 var ccType = ccTypeContainer.value; 761 762 if (typeof Validation.creditCartTypes.get(ccType) == 'undefined') { 763 return false; 764 } 765 766 var re = Validation.creditCartTypes.get(ccType)[1]; 767 768 if (v.match(re)) { 769 return true; 770 } 771 772 return false; 773 }], 774 ['validate-ajax', '', function(v, elm) { return true; }], 775 ['validate-data', 'Please use only letters (a-z or A-Z), numbers (0-9) or underscore(_) in this field, first character should be a letter.', function (v) { 776 if(v != '' && v) { 777 return /^[A-Za-z]+[A-Za-z0-9_]+$/.test(v); 778 } 779 return true; 780 }], 781 ['validate-css-length', 'Please input a valid CSS-length. For example 100px or 77pt or 20em or .5ex or 50%.', function (v) { 782 if (v != '' && v) { 783 return /^[0-9\.]+(px|pt|em|ex|%)?$/.test(v) && (!(/\..*\./.test(v))) && !(/\.$/.test(v)); 784 } 785 return true; 786 }], 787 ['validate-length', 'Text length does not satisfy specified text range.', function (v, elm) { 788 var reMax = new RegExp(/^maximum-length-[0-9]+$/); 789 var reMin = new RegExp(/^minimum-length-[0-9]+$/); 790 var result = true; 791 $w(elm.className).each(function(name, index) { 792 if (name.match(reMax) && result) { 793 var length = name.split('-')[2]; 794 result = (v.length <= length); 795 } 796 if (name.match(reMin) && result && !Validation.get('IsEmpty').test(v)) { 797 var length = name.split('-')[2]; 798 result = (v.length >= length); 799 } 800 }); 801 return result; 802 }], 803 ['validate-percents', 'Please enter a number lower than 100.', {max:100}], 804 ['required-file', 'Please select a file', function(v, elm) { 805 var result = !Validation.get('IsEmpty').test(v); 806 if (result === false) { 807 ovId = elm.id + '_value'; 808 if ($(ovId)) { 809 result = !Validation.get('IsEmpty').test($(ovId).value); 810 } 811 } 812 return result; 813 }], 814 ['validate-cc-ukss', 'Please enter issue number or start date for switch/solo card type.', function(v,elm) { 815 var endposition; 816 817 if (elm.id.match(/(.)+_cc_issue$/)) { 818 endposition = elm.id.indexOf('_cc_issue'); 819 } else if (elm.id.match(/(.)+_start_month$/)) { 820 endposition = elm.id.indexOf('_start_month'); 821 } else { 822 endposition = elm.id.indexOf('_start_year'); 823 } 824 825 var prefix = elm.id.substr(0,endposition); 826 827 var ccTypeContainer = $(prefix + '_cc_type'); 828 829 if (!ccTypeContainer) { 830 return true; 831 } 832 var ccType = ccTypeContainer.value; 833 834 if(['SS','SM','SO'].indexOf(ccType) == -1){ 835 return true; 836 } 837 838 $(prefix + '_cc_issue').advaiceContainer 839 = $(prefix + '_start_month').advaiceContainer 840 = $(prefix + '_start_year').advaiceContainer 841 = $(prefix + '_cc_type_ss_div').down('ul li.adv-container'); 842 843 var ccIssue = $(prefix + '_cc_issue').value; 844 var ccSMonth = $(prefix + '_start_month').value; 845 var ccSYear = $(prefix + '_start_year').value; 846 847 var ccStartDatePresent = (ccSMonth && ccSYear) ? true : false;
848 849 if (!ccStartDatePresent && !ccIssue){ 850 return false; 851 } 852 return true; 853 }] 854]); 855 856function removeDelimiters (v) { 857 v = v.replace(/\s/g, ''); 858 v = v.replace(/\-/g, ''); 859 return v; 860} 861 862function parseNumber(v) 863{ 864 if (typeof v != 'string') { 865 return parseFloat(v); 866 } 867 868 var isDot = v.indexOf('.'); 869 var isComa = v.indexOf(','); 870 871 if (isDot != -1 && isComa != -1) { 872 if (isComa > isDot) { 873 v = v.replace('.', '').replace(',', '.'); 874 } 875 else { 876 v = v.replace(',', ''); 877 } 878 } 879 else if (isComa != -1) { 880 v = v.replace(',', '.'); 881 } 882 883 return parseFloat(v); 884} 885 886/** 887 * Hash with credit card types which can be simply extended in payment modules 888 * 0 - regexp for card number 889 * 1 - regexp for cvn 890 * 2 - check or not credit card number trough Luhn algorithm by 891 * function validateCreditCard which you can find above in this file 892 */ 893Validation.creditCartTypes = $H({ 894// 'SS': [new RegExp('^((6759[0-9]{12})|(5018|5020|5038|6304|6759|6761|6763[0-9]{12,19})|(49[013][1356][0-9]{12})|(6333[0-9]{12})|(6334[0-4]\d{11})|(633110[0-9]{10})|(564182[0-9]{10}))([0-9]{2,3})?$'), new RegExp('^([0-9]{3}|[0-9]{4})?$'), true], 895 'SO': [new RegExp('^(6334[5-9]([0-9]{11}|[0-9]{13,14}))|(6767([0-9]{12}|[0-9]{14,15}))$'), new RegExp('^([0-9]{3}|[0-9]{4})?$'), true], 896 'VI': [new RegExp('^4[0-9]{12}([0-9]{3})?$'), new RegExp('^[0-9]{3}$'), true], 897 'MC': [new RegExp('^(5[1-5][0-9]{14}|2(22[1-9][0-9]{12}|2[3-9][0-9]{13}|[3-6][0-9]{14}|7[0-1][0-9]{13}|720[0-9]{12}))$'), new RegExp('^[0-9]{3}$'), true], 898 'AE': [new RegExp('^3[47][0-9]{13}$'), new RegExp('^[0-9]{4}$'), true], 899 'DI': [new RegExp('^(30[0-5][0-9]{13}|3095[0-9]{12}|35(2[8-9][0-9]{12}|[3-8][0-9]{13})|36[0-9]{12}|3[8-9][0-9]{14}|6011(0[0-9]{11}|[2-4][0-9]{11}|74[0-9]{10}|7[7-9][0-9]{10}|8[6-9][0-9]{10}|9[0-9]{11})|62(2(12[6-9][0-9]{10}|1[3-9][0-9]{11}|[2-8][0-9]{12}|9[0-1][0-9]{11}|92[0-5][0-9]{10})|[4-6][0-9]{13}|8[2-8][0-9]{12})|6(4[4-9][0-9]{13}|5[0-9]{14}))$'), new RegExp('^[0-9]{3}$'), true], 900 'JCB': [new RegExp('^(30[0-5][0-9]{13}|3095[0-9]{12}|35(2[8-9][0-9]{12}|[3-8][0-9]{13})|36[0-9]{12}|3[8-9][0-9]{14}|6011(0[0-9]{11}|[2-4][0-9]{11}|74[0-9]{10}|7[7-9][0-9]{10}|8[6-9][0-9]{10}|9[0-9]{11})|62(2(12[6-9][0-9]{10}|1[3-9][0-9]{11}|[2-8][0-9]{12}|9[0-1][0-9]{11}|92[0-5][0-9]{10})|[4-6][0-9]{13}|8[2-8][0-9]{12})|6(4[4-9][0-9]{13}|5[0-9]{14}))$'), new RegExp('^[0-9]{3,4}$'), true], 901 'DICL': [new RegExp('^(30[0-5][0-9]{13}|3095[0-9]{12}|35(2[8-9][0-9]{12}|[3-8][0-9]{13})|36[0-9]{12}|3[8-9][0-9]{14}|6011(0[0-9]{11}|[2-4][0-9]{11}|74[0-9]{10}|7[7-9][0-9]{10}|8[6-9][0-9]{10}|9[0-9]{11})|62(2(12[6-9][0-9]{10}|1[3-9][0-9]{11}|[2-8][0-9]{12}|9[0-1][0-9]{11}|92[0-5][0-9]{10})|[4-6][0-9]{13}|8[2-8][0-9]{12})|6(4[4-9][0-9]{13}|5[0-9]{14}))$'), new RegExp('^[0-9]{3}$'), true], 902 'SM': [new RegExp('(^(5[0678])[0-9]{11,18}$)|(^(6[^05])[0-9]{11,18}$)|(^(601)[^1][0-9]{9,16}$)|(^(6011)[0-9]{9,11}$)|(^(6011)[0-9]{13,16}$)|(^(65)[0-9]{11,13}$)|(^(65)[0-9]{15,18}$)|(^(49030)[2-9]([0-9]{10}$|[0-9]{12,13}$))|(^(49033)[5-9]([0-9]{10}$|[0-9]{12,13}$))|(^(49110)[1-2]([0-9]{10}$|[0-9]{12,13}$))|(^(49117)[4-9]([0-9]{10}$|[0-9]{12,13}$))|(^(49118)[0-2]([0-9]{10}$|[0-9]{12,13}$))|(^(4936)([0-9]{12}$|[0-9]{14,15}$))'), new RegExp('^([0-9]{3}|[0-9]{4})?$'), true], 903 'OT': [false, new RegExp('^([0-9]{3}|[0-9]{4})?$'), false] 904});
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.