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-code-event', 'Please do not use "event" for an attribute code.', function (v) { 486 return Validation.get('IsEmpty').test(v) || !/^(event)$/.test(v) 487 }], 488 ['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) { 489 return Validation.get('IsEmpty').test(v) || /^[a-zA-Z0-9]+$/.test(v) 490 }], 491 ['validate-alphanum-with-spaces', 'Please use only letters (a-z or A-Z), numbers (0-9) or spaces only in this field.', function(v) { 492 return Validation.get('IsEmpty').test(v) || /^[a-zA-Z0-9 ]+$/.test(v) 493 }], 494 ['validate-street', 'Please use only letters (a-z or A-Z) or numbers (0-9) or spaces and # only in this field.', function(v) { 495 return Validation.get('IsEmpty').test(v) || /^[ \w]{3,}([A-Za-z]\.)?([ \w]*\#\d+)?(\r\n| )[ \w]{3,}/.test(v) 496 }], 497 ['validate-phoneStrict', '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{3}(\))?(-|\s)?\d{3}(-|\s)\d{4}$/.test(v); 499 }], 500 ['validate-phoneLax', 'Please enter a valid phone number. For example (123) 456-7890 or 123-456-7890.', function(v) { 501 return Validation.get('IsEmpty').test(v) || /^((\d[-. ]?)?((\(\d{3}\))|\d{3}))?[-. ]?\d{3}[-. ]?\d{4}$/.test(v); 502 }], 503 ['validate-fax', 'Please enter a valid fax number. For example (123) 456-7890 or 123-456-7890.', function(v) { 504 return Validation.get('IsEmpty').test(v) || /^(\()?\d{3}(\))?(-|\s)?\d{3}(-|\s)\d{4}$/.test(v); 505 }], 506 ['validate-date', 'Please enter a valid date.', function(v) { 507 var test = new Date(v); 508 return Validation.get('IsEmpty').test(v) || !isNaN(test); 509 }], 510 ['validate-date-range', 'The From Date value should be less than or equal to the To Date value.', function(v, elm) { 511 var m = /\bdate-range-(\w+)-(\w+)\b/.exec(elm.className); 512 if (!m || m[2] == 'to' || Validation.get('IsEmpty').test(v)) { 513 return true; 514 } 515 516 var currentYear = new Date().getFullYear() + ''; 517 var normalizedTime = function(v) { 518 v = v.split(/[.\/]/); 519 if (v[2] && v[2].length < 4) { 520 v[2] = currentYear.substr(0, v[2].length) + v[2]; 521 } 522 return new Date(v.join('/')).getTime(); 523 }; 524 525 var dependentElements = Element.select(elm.form, '.validate-date-range.date-range-' + m[1] + '-to'); 526 return !dependentElements.length || Validation.get('IsEmpty').test(dependentElements[0].value) 527 || normalizedTime(v) <= normalizedTime(dependentElements[0].value); 528 }], 529 ['validate-email', 'Please enter a valid email address. For example [email protected].', function (v) { 530 //return Validation.get('IsEmpty').test(v) || /\w{1,}[@][\w\-]{1,}([.]([\w\-]{1,})){1,3}$/.test(v) 531 //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) 532 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) 533 }], 534 ['validate-emailSender', 'Please use only visible characters and spaces.', function (v) { 535 return Validation.get('IsEmpty').test(v) || /^[\S ]+$/.test(v) 536 }], 537 ['validate-password', 'Please enter more characters or clean leading or trailing space
537s.', function(v, elm) { 538 var pass=v.strip(); /*strip leading and trailing spaces*/ 539 var reMin = new RegExp(/^min-pass-length-[0-9]+$/); 540 var minLength = 7; 541 $w(elm.className).each(function(name, index) { 542 if (name.match(reMin)) { 543 minLength = name.split('-')[3]; 544 } 545 }); 546 return (!(v.length > 0 && v.length < minLength) && v.length == pass.length); 547 }], 548 ['validate-admin-password', 'Please enter more characters. Password should contain both numeric and alphabetic characters.', function(v, elm) { 549 var pass=v.strip(); 550 if (0 == pass.length) { 551 return true; 552 } 553 if (!(/[a-z]/i.test(v)) || !(/[0-9]/.test(v))) { 554 return false; 555 } 556 var reMin = new RegExp(/^min-admin-pass-length-[0-9]+$/); 557 var minLength = 7; 558 $w(elm.className).each(function(name, index) { 559 if (name.match(reMin)) { 560 minLength = name.split('-')[4]; 561 } 562 }); 563 return !(pass.length < minLength); 564 }], 565 ['validate-cpassword', 'Please make sure your passwords match.', function(v) { 566 var conf = $('confirmation') ? $('confirmation') : $$('.validate-cpassword')[0]; 567 var pass = false; 568 if ($('password')) { 569 pass = $('password'); 570 } 571 var passwordElements = $$('.validate-password'); 572 for (var i = 0; i < passwordElements.size(); i++) { 573 var passwordElement = passwordElements[i]; 574 if (passwordElement.up('form').id == conf.up('form').id) { 575 pass = passwordElement; 576 } 577 } 578 if ($$('.validate-admin-password').size()) { 579 pass = $$('.validate-admin-password')[0]; 580 } 581 return (pass.value == conf.value); 582 }], 583 ['validate-both-passwords', 'Please make sure your passwords match.', function(v, input) { 584 var dependentInput = $(input.form[input.name == 'password' ? 'confirmation' : 'password']), 585 isEqualValues = input.value == dependentInput.value; 586 587 if (isEqualValues && dependentInput.hasClassName('validation-failed')) { 588 Validation.test(this.className, dependentInput); 589 } 590 591 return dependentInput.value == '' || isEqualValues; 592 }], 593 ['validate-url', 'Please enter a valid URL. Protocol is required (http://, https:// or ftp://)', function (v) { 594 v = (v || '').replace(/^\s+/, '').replace(/\s+$/, ''); 595 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) 596 }], 597 ['validate-clean-url', 'Please enter a valid URL. For example http://www.example.com or www.example.com', function (v) { 598 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) 599 }], 600 ['validate-identifier', 'Please enter a valid URL Key. For example "example-page", "example-page.html" or "anotherlevel/example-page".', function (v) { 601 return Validation.get('IsEmpty').test(v) || /^[a-z0-9][a-z0-9_\/-]+(\.[a-z0-9_-]+)?$/.test(v) 602 }], 603 ['validate-xml-identifier', 'Please enter a valid XML-identifier. For example something_1, block5, id-4.', function (v) { 604 return Validation.get('IsEmpty').test(v) || /^[A-Z][A-Z0-9_\/-]*$/i.test(v) 605 }], 606 ['validate-ssn', 'Please enter a valid social security number. For example 123-45-6789.', function(v) { 607 return Validation.get('IsEmpty').test(v) || /^\d{3}-?\d{2}-?\d{4}$/.test(v); 608 }], 609 ['validate-zip', 'Please enter a valid zip code. For example 90602 or 90602-1234.', function(v) { 610 return Validation.get('IsEmpty').test(v) || /(^\d{5}$)|(^\d{5}-\d{4}$)/.test(v); 611 }], 612 ['validate-zip-international', 'Please enter a valid zip code.', function(v) { 613 //return Validation.get('IsEmpty').test(v) || /(^[A-z0-9]{2,10}([\s]{0,1}|[\-]{0,1})[A-z0-9]{2,10}$)/.test(v); 614 return true; 615 }], 616 ['validate-date-au', 'Please use this date format: dd/mm/yyyy. For example 17/03/2006 for the 17th of March, 2006.', function(v) { 617 if(Validation.get('IsEmpty').test(v)) return true; 618 var regex = /^(\d{2})\/(\d{2})\/(\d{4})$/; 619 if(!regex.test(v)) return false;
620 var d = new Date(v.replace(regex, '$2/$1/$3')); 621 return ( parseInt(RegExp.$2, 10) == (1+d.getMonth()) ) && 622 (parseInt(RegExp.$1, 10) == d.getDate()) && 623 (parseInt(RegExp.$3, 10) == d.getFullYear() ); 624 }], 625 ['validate-currency-dollar', 'Please enter a valid $ amount. For example $100.00.', function(v) { 626 // [$]1[##][,###]+[.##] 627 // [$]1###+[.##] 628 // [$]0.## 629 // [$].## 630 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) 631 }], 632 ['validate-one-required', 'Please select one of the above options.', function (v,elm) { 633 var p = elm.parentNode; 634 var options = p.getElementsByTagName('INPUT'); 635 return $A(options).any(function(elm) { 636 return $F(elm); 637 }); 638 }], 639 ['validate-one-required-by-name', 'Please select one of the options.', function (v,elm) { 640 var inputs = $$('input[name="' + elm.name.replace(/([\\"])/g, '\\$1') + '"]'); 641 642 var error = 1; 643 for(var i=0;i<inputs.length;i++) { 644 if((inputs[i].type == 'checkbox' || inputs[i].type == 'radio') && inputs[i].checked == true) { 645 error = 0; 646 } 647 648 if(Validation.isOnChange && (inputs[i].type == 'checkbox' || inputs[i].type == 'radio')) { 649 Validation.reset(inputs[i]); 650 } 651 } 652 653 if( error == 0 ) { 654 return true; 655 } else { 656 return false; 657 } 658 }], 659 ['validate-not-negative-number', 'Please enter a number 0 or greater in this field.', function(v) { 660 if (Validation.get('IsEmpty').test(v)) { 661 return true; 662 } 663 v = parseNumber(v); 664 return !isNaN(v) && v >= 0; 665 }], 666 ['validate-zero-or-greater', 'Please enter a number 0 or greater in this field.', function(v) { 667 return Validation.get('validate-not-negative-number').test(v); 668 }], 669 ['validate-greater-than-zero', 'Please enter a number greater than 0 in this field.', function(v) { 670 if (Validation.get('IsEmpty').test(v)) { 671 return true; 672 } 673 v = parseNumber(v); 674 return !isNaN(v) && v > 0; 675 }], 676 677 ['validate-special-price', 'The Special Price is active only when lower than the Actual Price.', function(v) { 678 var priceInput = $('price'); 679 var priceType = $('price_type'); 680 var priceValue = parseFloat(v); 681 682 // Passed on non-related validators conditions (to not change order of validation) 683 if( 684 !priceInput 685 || Validation.get('IsEmpty').test(v) 686 || !Validation.get('validate-number').test(v) 687 ) { 688 return true; 689 } 690 if(priceType) { 691 return (priceType && priceValue <= 99.99); 692 } 693 return priceValue < parseFloat($F(priceInput)); 694 }], 695 ['validate-state', 'Please select State/Province.', function(v) { 696 return (v!=0 || v == ''); 697 }], 698 ['validate-new-password', 'Please enter more characters or clean leading or trailing spaces.', function(v, elm) { 699 if (!Validation.get('validate-password').test(v, elm)) return false; 700 if (Validation.get('IsEmpty').test(v) && v != '') return false; 701 return true; 702 }], 703 ['validate-cc-number', 'Please enter a valid credit card number.', function(v, elm) { 704 // remove non-numerics 705 var ccTypeContainer = $(elm.id.substr(0,elm.id.indexOf('_cc_number')) + '_cc_type'); 706 if (ccTypeContainer && typeof Validation.creditCartTypes.get(ccTypeContainer.value) != 'undefined' 707 && Validation.creditCartTypes.get(ccTypeContainer.value)[2] == false) { 708 if (!Validation.get('IsEmpty').test(v) && Validation.get('validate-digits').test(v)) { 709 return true; 710 } else { 711 return false;
712 } 713 } 714 return validateCreditCard(v); 715 }], 716 ['validate-cc-type', 'Credit card number does not match credit card type.', function(v, elm) { 717 // remove credit card number delimiters such as "-" and space 718 elm.value = removeDelimiters(elm.value); 719 v = removeDelimiters(v); 720 721 var ccTypeContainer = $(elm.id.substr(0,elm.id.indexOf('_cc_number')) + '_cc_type'); 722 if (!ccTypeContainer) { 723 return true; 724 } 725 var ccType = ccTypeContainer.value; 726 727 if (typeof Validation.creditCartTypes.get(ccType) == 'undefined') { 728 return false; 729 } 730 731 // Other card type or switch or solo card 732 if (Validation.creditCartTypes.get(ccType)[0]==false) { 733 return true; 734 } 735 736 var validationFailure = false; 737 Validation.creditCartTypes.each(function (pair) { 738 if (pair.key == ccType) { 739 if (pair.value[0] && !v.match(pair.value[0])) { 740 validationFailure = true; 741 } 742 throw $break; 743 } 744 }); 745 746 if (validationFailure) { 747 return false; 748 } 749 750 if (ccTypeContainer.hasClassName('validation-failed') && Validation.isOnChange) { 751 Validation.validate(ccTypeContainer); 752 } 753 754 return true; 755 }], 756 ['validate-cc-type-select', 'Card type does not match credit card number.', function(v, elm) { 757 var ccNumberContainer = $(elm.id.substr(0,elm.id.indexOf('_cc_type')) + '_cc_number'); 758 if (Validation.isOnChange && Validation.get('IsEmpty').test(ccNumberContainer.value)) { 759 return true; 760 } 761 if (Validation.get('validate-cc-type').test(ccNumberContainer.value, ccNumberContainer)) { 762 Validation.validate(ccNumberContainer); 763 } 764 return Validation.get('validate-cc-type').test(ccNumberContainer.value, ccNumberContainer); 765 }], 766 ['validate-cc-exp', 'Incorrect credit card expiration date.', function(v, elm) { 767 var ccExpMonth = v; 768 var ccExpYear = $(elm.id.substr(0,elm.id.indexOf('_expiration')) + '_expiration_yr').value; 769 var currentTime = new Date(); 770 var currentMonth = currentTime.getMonth() + 1; 771 var currentYear = currentTime.getFullYear(); 772 if (ccExpMonth < currentMonth && ccExpYear == currentYear) { 773 return false; 774 } 775 return true; 776 }], 777 ['validate-cc-cvn', 'Please enter a valid credit card verification number.', function(v, elm) { 778 var ccTypeContainer = $(elm.id.substr(0,elm.id.indexOf('_cc_cid')) + '_cc_type'); 779 if (!ccTypeContainer) { 780 return true; 781 } 782 var ccType = ccTypeContainer.value; 783 784 if (typeof Validation.creditCartTypes.get(ccType) == 'undefined') { 785 return false; 786 } 787 788 var re = Validation.creditCartTypes.get(ccType)[1]; 789 790 if (v.match(re)) { 791 return true; 792 } 793 794 return false; 795 }], 796 ['validate-ajax', '', function(v, elm) { return true; }], 797 ['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) { 798 if(v != '' && v) { 799 return /^[A-Za-z]+[A-Za-z0-9_]+$/.test(v); 800 } 801 return true; 802 }], 803 ['validate-css-length', 'Please input a valid CSS-length. For example 100px or 77pt or 20em or .5ex or 50%.', function (v) { 804 if (v != '' && v) { 805 return /^[0-9\.]+(px|pt|em|ex|%)?$/.test(v) && (!(/\..*\./.test(v))) && !(/\.$/.test(v)); 806 } 807 return true; 808 }], 809 ['validate-length', 'Text length does not satisfy specified text range.', function (v, elm) { 810 var reMax = new RegExp(/^maximum-length-[0-9]+$/); 811 var reMin = new RegExp(/^minimum-length-[0-9]+$/); 812 var result = true; 813 $w(elm.className).each(function(name, index) { 814 if (name.match(reMax) && result) { 815 var length = name.split('-')[2]; 816 result = (v.length <= length); 817 } 818 if (name.match(reMin) && result && !Validation.get('IsEmpty').test(v)) { 819 var length = name.split('-')[2]; 820 result = (v.length >= length); 821 } 822 }); 823 return result; 824 }], 825 ['validate-percents', 'Please enter a number lower than 100.', {max:100}], 826 ['required-file', 'Please select a file', function(v, elm) { 827 var result = !Validation.get('IsEmpty').test(v); 828 if (result === false) { 829 ovId = elm.id + '_value'; 830 if ($(ovId)) { 831 result = !Validation.get('IsEmpty').test($(ovId).value); 832 } 833 } 834 return result; 835 }], 836 ['validate-cc-ukss', 'Please enter issue number or start date for switch/solo card type.', function(v,elm) { 837 var endposition; 838 839 if (elm.id.match(/(.)+_cc_issue$/)) { 840 endposition = elm.id.indexOf('_cc_issue'); 841 } else if (elm.id.match(/(.)+_start_month$/)) { 842 endposition = elm.id.indexOf('_start_month'); 843 } else { 844 endposition = elm.id.indexOf('_start_year'); 845 } 846 847 var prefix = elm.id.substr(0,endposition); 848 849 var ccTypeContainer = $(prefix + '_cc_type'); 850 851 if (!ccTypeContainer) { 852 return true; 853 } 854 var ccType = ccTypeContainer.value; 855 856 if(['SS','SM','SO'].indexOf(ccType) == -1){ 857 return true; 858 } 859 860 $(prefix + '_cc_issue').advaiceContainer 861 = $(prefix + '_start_month').advaiceContainer 862 = $(prefix + '_start_year').advaiceContainer 863 = $(prefix + '_cc_type_ss_div').down('ul li.adv-container'); 864 865 var ccIssue = $(prefix + '_cc_issue').value; 866 var ccSMonth = $(prefix + '_start_month').value; 867 var ccSYear = $(prefix + '_start_year').value; 868 869 var ccStartDatePresent = (ccSMonth && ccSYear) ? true : false;
870 871 if (!ccStartDatePresent && !ccIssue){ 872 return false; 873 } 874 return true; 875 }] 876]); 877 878function removeDelimiters (v) { 879 v = v.replace(/\s/g, ''); 880 v = v.replace(/\-/g, ''); 881 return v; 882} 883 884function parseNumber(v) 885{ 886 if (typeof v != 'string') { 887 return parseFloat(v); 888 } 889 890 var isDot = v.indexOf('.'); 891 var isComa = v.indexOf(','); 892 893 if (isDot != -1 && isComa != -1) { 894 if (isComa > isDot) { 895 v = v.replace('.', '').replace(',', '.'); 896 } 897 else { 898 v = v.replace(',', ''); 899 } 900 } 901 else if (isComa != -1) { 902 v = v.replace(',', '.'); 903 } 904 905 return parseFloat(v); 906} 907 908/** 909 * Hash with credit card types which can be simply extended in payment modules 910 * 0 - regexp for card number 911 * 1 - regexp for cvn 912 * 2 - check or not credit card number trough Luhn algorithm by 913 * function validateCreditCard which you can find above in this file 914 */ 915Validation.creditCartTypes = $H({ 916// '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], 917 '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], 918 'VI': [new RegExp('^4[0-9]{12}([0-9]{3})?$'), new RegExp('^[0-9]{3}$'), true], 919 '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], 920 'AE': [new RegExp('^3[47][0-9]{13}$'), new RegExp('^[0-9]{4}$'), true], 921 '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], 922 '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], 923 '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], 924 '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], 925 'OT': [false, new RegExp('^([0-9]{3}|[0-9]{4})?$'), false] 926});
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.