Requires

Provides

Form.Validator.js

A css-class based form validation system.

License:
MIT-style license
Authors:
Aaron Newton
  1. 34
  2. 35
  3. 36
  4. 37
  5. 38
  6. 39
  7. 40
  8. 41
  9. 42
  10. 43
  11. 44
  12. 45
  13. 46
  14. 47
  15. 48
  16. 49
  17. 50
  18. 51
  19. 52
  20. 53
  21. 54
  22. 55
  23. 56
  24. 57
  25. 58
  26. 59
  27. 60
  28. 61
  29. 62
  30. 63
  31. 64
  32. 65
  33. 66
  34. 67
  35. 68
  36. 69
  37. 70
  38. 71
  39. 72
  40. 73
  41. 74
  42. 75
  43. 76
  44. 77
  45. 78
  46. 79
  47. 80
  48. 81
  49. 82
  50. 83
  51. 84
  52. 85
  53. 86
  54. 87
  55. 88
  56. 89
  57. 90
  58. 91
  59. 92
  60. 93
  61. 94
  62. 95
  63. 96
  64. 97
  65. 98
  66. 99
  67. 100
  68. 101
  69. 102
  70. 103
  71. 104
  72. 105
  73. 106
  74. 107
  75. 108
  76. 109
  77. 110
  78. 111
  79. 112
  80. 113
  81. 114
  82. 115
  83. 116
  84. 117
  85. 118
  86. 119
  87. 120
  88. 121
  89. 122
  90. 123
  91. 124
  92. 125
  93. 126
  94. 127
  95. 128
  96. 129
  97. 130
  98. 131
  99. 132
  100. 133
  101. 134
  102. 135
  103. 136
  104. 137
  105. 138
  106. 139
  107. 140
  108. 141
  109. 142
  110. 143
  111. 144
  112. 145
  113. 146
  114. 147
  115. 148
  116. 149
  117. 150
  118. 151
  119. 152
  120. 153
  121. 154
  122. 155
  123. 156
  124. 157
  125. 158
  126. 159
  127. 160
  128. 161
  129. 162
  130. 163
  131. 164
  132. 165
  133. 166
  134. 167
  135. 168
  136. 169
  137. 170
  138. 171
  139. 172
  140. 173
  141. 174
  142. 175
  143. 176
  144. 177
  145. 178
  146. 179
  147. 180
  148. 181
  149. 182
  150. 183
  151. 184
  152. 185
  153. 186
  154. 187
  155. 188
  156. 189
  157. 190
  158. 191
  159. 192
  160. 193
  161. 194
  162. 195
  163. 196
  164. 197
  165. 198
  166. 199
  167. 200
  168. 201
  169. 202
  170. 203
  171. 204
  172. 205
  173. 206
  174. 207
  175. 208
  176. 209
  177. 210
  178. 211
  179. 212
  180. 213
  181. 214
  182. 215
  183. 216
  184. 217
  185. 218
  186. 219
  187. 220
  188. 221
  189. 222
  190. 223
  191. 224
  192. 225
  193. 226
  194. 227
  195. 228
  196. 229
  197. 230
  198. 231
  199. 232
  200. 233
  201. 234
  202. 235
  203. 236
  204. 237
  205. 238
  206. 239
  207. 240
  208. 241
  209. 242
  210. 243
  211. 244
  212. 245
  213. 246
  214. 247
  215. 248
  216. 249
  217. 250
  218. 251
  219. 252
  220. 253
  221. 254
  222. 255
  223. 256
  224. 257
  225. 258
  226. 259
  227. 260
  228. 261
  229. 262
  230. 263
  231. 264
  232. 265
  233. 266
  234. 267
  235. 268
  236. 269
  237. 270
  238. 271
  239. 272
  240. 273
  241. 274
  242. 275
  243. 276
  244. 277
  245. 278
  246. 279
  247. 280
  248. 281
  249. 282
  250. 283
  251. 284
  252. 285
  253. 286
  254. 287
  255. 288
  256. 289
  257. 290
  258. 291
  259. 292
if (!window.Form) window.Form = {}; var InputValidator = new Class({ Implements: [Options], options: { errorMsg: 'Validation failed.', test: function(field){return true;} }, initialize: function(className, options){ this.setOptions(options); this.className = className; }, test: function(field, props){ if (document.id(field)) return this.options.test(document.id(field), props || this.getProps(field)); else return false; }, getError: function(field, props){ var err = this.options.errorMsg; if (typeOf(err) == 'function') err = err(document.id(field), props || this.getProps(field)); return err; }, getProps: function(field){ if (!document.id(field)) return {}; return field.get('validatorProps'); } }); Element.Properties.validatorProps = { set: function(props){ return this.eliminate('$moo:validatorProps').store('$moo:validatorProps', props); }, get: function(props){ if (props) this.set(props); if (this.retrieve('$moo:validatorProps')) return this.retrieve('$moo:validatorProps'); if (this.getProperty('$moo:validatorProps')){ try { this.store('$moo:validatorProps', JSON.decode(this.getProperty('$moo:validatorProps'))); }catch(e){ return {}; } } else { var vals = this.get('class').split(' ').filter(function(cls){ return cls.test(':'); }); if (!vals.length){ this.store('$moo:validatorProps', {}); } else { props = {}; vals.each(function(cls){ var split = cls.split(':'); if (split[1]){ try { props[split[0]] = JSON.decode(split[1]); } catch(e){} } }); this.store('$moo:validatorProps', props); } } return this.retrieve('$moo:validatorProps'); } }; Form.Validator = new Class({ Implements:[Options, Events], Binds: ['onSubmit'], options: {/* onFormValidate: function(isValid, form, event){}, onElementValidate: function(isValid, field, className, warn){}, onElementPass: function(field){}, onElementFail: function(field, validatorsFailed){}, */ fieldSelectors: 'input, select, textarea', ignoreHidden: true, ignoreDisabled: true, useTitles: false, evaluateOnSubmit: true, evaluateFieldsOnBlur: true, evaluateFieldsOnChange: true, serial: true, stopOnFailure: true, warningPrefix: function(){ return Form.Validator.getMsg('warningPrefix') || 'Warning: '; }, errorPrefix: function(){ return Form.Validator.getMsg('errorPrefix') || 'Error: '; } }, initialize: function(form, options){ this.setOptions(options); this.element = document.id(form); this.element.store('validator', this); this.warningPrefix = Function.from(this.options.warningPrefix)(); this.errorPrefix = Function.from(this.options.errorPrefix)(); if (this.options.evaluateOnSubmit) this.element.addEvent('submit', this.onSubmit); if (this.options.evaluateFieldsOnBlur || this.options.evaluateFieldsOnChange) this.watchFields(this.getFields()); }, toElement: function(){ return this.element; }, getFields: function(){ return (this.fields = this.element.getElements(this.options.fieldSelectors)); }, watchFields: function(fields){ fields.each(function(el){ if (this.options.evaluateFieldsOnBlur) el.addEvent('blur', this.validationMonitor.pass([el, false], this)); if (this.options.evaluateFieldsOnChange) el.addEvent('change', this.validationMonitor.pass([el, true], this)); }, this); }, validationMonitor: function(){ clearTimeout(this.timer); this.timer = this.validateField.delay(50, this, arguments); }, onSubmit: function(event){ if (!this.validate(event) && event) event.preventDefault(); else this.reset(); }, reset: function(){ this.getFields().each(this.resetField, this); return this; }, validate: function(event){ var result = this.getFields().map(function(field){ return this.validateField(field, true); }, this).every(function(v){ return v;}); this.fireEvent('formValidate', [result, this.element, event]); if (this.options.stopOnFailure && !result && event) event.preventDefault(); return result; }, validateField: function(field, force){ if (this.paused) return true; field = document.id(field); var passed = !field.hasClass('validation-failed'); var failed, warned; if (this.options.serial && !force){ failed = this.element.getElement('.validation-failed'); warned = this.element.getElement('.warning'); } if (field && (!failed || force || field.hasClass('validation-failed') || (failed && !this.options.serial))){ var validators = field.className.split(' ').some(function(cn){ return this.getValidator(cn); }, this); var validatorsFailed = []; field.className.split(' ').each(function(className){ if (className && !this.test(className, field)) validatorsFailed.include(className); }, this); passed = validatorsFailed.length === 0; if (validators && !field.hasClass('warnOnly')){ if (passed){ field.addClass('validation-passed').removeClass('validation-failed'); this.fireEvent('elementPass', field); } else { field.addClass('validation-failed').removeClass('validation-passed'); this.fireEvent('elementFail', [field, validatorsFailed]); } } if (!warned){ var warnings = field.className.split(' ').some(function(cn){ if (cn.test('^warn-') || field.hasClass('warnOnly')) return this.getValidator(cn.replace(/^warn-/,'')); else return null; }, this); field.removeClass('warning'); var warnResult = field.className.split(' ').map(function(cn){ if (cn.test('^warn-') || field.hasClass('warnOnly')) return this.test(cn.replace(/^warn-/,''), field, true); else return null; }, this); } } return passed; }, test: function(className, field, warn){ field = document.id(field); if ((this.options.ignoreHidden && !field.isVisible()) || (this.options.ignoreDisabled && field.get('disabled'))) return true; var validator = this.getValidator(className); warn = warn != null ? warn : false; if (field.hasClass('warnOnly')) warn = true; var isValid = field.hasClass('ignoreValidation') || (validator ? validator.test(field) : true); if (validator && field.isVisible()) this.fireEvent('elementValidate', [isValid, field, className, warn]); if (warn) return true; return isValid; }, resetField: function(field){ field = document.id(field); if (field){ field.className.split(' ').each(function(className){ if (className.test('^warn-')) className = className.replace(/^warn-/, ''); field.removeClass('validation-failed'); field.removeClass('warning'); field.removeClass('validation-passed'); }, this); } return this; }, stop: function(){ this.paused = true; return this; }, start: function(){ this.paused = false; return this; }, ignoreField: function(field, warn){ field = document.id(field); if (field){ this.enforceField(field); if (warn) field.addClass('warnOnly'); else field.addClass('ignoreValidation'); } return this; }, enforceField: function(field){ field = document.id(field); if (field) field.removeClass('warnOnly').removeClass('ignoreValidation'); return this; } }); Form.Validator.getMsg = function(key){ return Locale.get('FormValidator.' + key); }; Form.Validator.adders = { validators:{}, add : function(className, options){ this.validators[className] = new InputValidator(className, options);

if this is a class (this method is used by instances of Form.Validator and the Form.Validator namespace) extend these validators into it this allows validators to be global and/or per instance

  1. 296
  2. 297
  3. 298
  4. 299
  5. 300
  6. 301
  7. 302
  8. 303
  9. 304
  10. 305
  11. 306
  12. 307
  13. 308
  14. 309
  15. 310
  16. 311
  17. 312
  18. 313
  19. 314
  20. 315
  21. 316
  22. 317
  23. 318
  24. 319
  25. 320
  26. 321
  27. 322
  28. 323
  29. 324
  30. 325
  31. 326
  32. 327
  33. 328
  34. 329
  35. 330
  36. 331
  37. 332
  38. 333
  39. 334
  40. 335
  41. 336
  42. 337
  43. 338
  44. 339
  45. 340
  46. 341
  47. 342
  48. 343
  49. 344
  50. 345
  51. 346
  52. 347
  53. 348
  54. 349
  55. 350
  56. 351
  57. 352
  58. 353
  59. 354
  60. 355
if (!this.initialize){ this.implement({ validators: this.validators }); } }, addAllThese : function(validators){ Array.from(validators).each(function(validator){ this.add(validator[0], validator[1]); }, this); }, getValidator: function(className){ return this.validators[className.split(':')[0]]; } }; Object.append(Form.Validator, Form.Validator.adders); Form.Validator.implement(Form.Validator.adders); Form.Validator.add('IsEmpty', { errorMsg: false, test: function(element){ if (element.type == 'select-one' || element.type == 'select') return !(element.selectedIndex >= 0 && element.options[element.selectedIndex].value != ''); else return ((element.get('value') == null) || (element.get('value').length == 0)); } }); Form.Validator.addAllThese([ ['required', { errorMsg: function(){ return Form.Validator.getMsg('required'); }, test: function(element){ return !Form.Validator.getValidator('IsEmpty').test(element); } }], ['minLength', { errorMsg: function(element, props){ if (typeOf(props.minLength)) return Form.Validator.getMsg('minLength').substitute({minLength:props.minLength,length:element.get('value').length }); else return ''; }, test: function(element, props){ if (typeOf(props.minLength)) return (element.get('value').length >= props.minLength || 0); else return true; } }], ['maxLength', { errorMsg: function(element, props){

props is {maxLength:10}

  1. 357
  2. 358
  3. 359
  4. 360
  5. 361
if (typeOf(props.maxLength)) return Form.Validator.getMsg('maxLength').substitute({maxLength:props.maxLength,length:element.get('value').length }); else return ''; }, test: function(element, props){

if the value is <= than the maxLength value, element passes test

  1. 363
  2. 364
  3. 365
  4. 366
  5. 367
  6. 368
  7. 369
  8. 370
  9. 371
  10. 372
  11. 373
  12. 374
  13. 375
  14. 376
  15. 377
  16. 378
  17. 379
  18. 380
  19. 381
  20. 382
  21. 383
  22. 384
  23. 385
  24. 386
  25. 387
  26. 388
  27. 389
  28. 390
  29. 391
  30. 392
  31. 393
  32. 394
  33. 395
  34. 396
  35. 397
  36. 398
  37. 399
  38. 400
  39. 401
  40. 402
  41. 403
  42. 404
  43. 405
  44. 406
  45. 407
  46. 408
  47. 409
  48. 410
  49. 411
  50. 412
  51. 413
  52. 414
  53. 415
  54. 416
  55. 417
  56. 418
  57. 419
  58. 420
  59. 421
  60. 422
  61. 423
  62. 424
  63. 425
  64. 426
  65. 427
  66. 428
  67. 429
  68. 430
  69. 431
  70. 432
  71. 433
  72. 434
  73. 435
  74. 436
  75. 437
  76. 438
  77. 439
  78. 440
  79. 441
  80. 442
  81. 443
  82. 444
  83. 445
  84. 446
  85. 447
  86. 448
return (element.get('value').length <= props.maxLength || 10000); } }], ['validate-integer', { errorMsg: Form.Validator.getMsg.pass('integer'), test: function(element){ return Form.Validator.getValidator('IsEmpty').test(element) || (/^(-?[1-9]\d*|0)$/).test(element.get('value')); } }], ['validate-numeric', { errorMsg: Form.Validator.getMsg.pass('numeric'), test: function(element){ return Form.Validator.getValidator('IsEmpty').test(element) || (/^-?(?:0$0(?=\d*\.)|[1-9]|0)\d*(\.\d+)?$/).test(element.get('value')); } }], ['validate-digits', { errorMsg: Form.Validator.getMsg.pass('digits'), test: function(element){ return Form.Validator.getValidator('IsEmpty').test(element) || (/^[\d() .:\-\+#]+$/.test(element.get('value'))); } }], ['validate-alpha', { errorMsg: Form.Validator.getMsg.pass('alpha'), test: function(element){ return Form.Validator.getValidator('IsEmpty').test(element) || (/^[a-zA-Z]+$/).test(element.get('value')); } }], ['validate-alphanum', { errorMsg: Form.Validator.getMsg.pass('alphanum'), test: function(element){ return Form.Validator.getValidator('IsEmpty').test(element) || !(/\W/).test(element.get('value')); } }], ['validate-date', { errorMsg: function(element, props){ if (Date.parse){ var format = props.dateFormat || '%x'; return Form.Validator.getMsg('dateSuchAs').substitute({date: new Date().format(format)}); } else { return Form.Validator.getMsg('dateInFormatMDY'); } }, test: function(element, props){ if (Form.Validator.getValidator('IsEmpty').test(element)) return true; var d; if (Date.parse){ var format = props.dateFormat || '%x'; d = Date.parse(element.get('value')); var formatted = d.format(format); if (formatted != 'invalid date') element.set('value', formatted); return !isNaN(d); } else { var regex = /^(\d{2})\/(\d{2})\/(\d{4})$/; if (!regex.test(element.get('value'))) return false; d = new Date(element.get('value').replace(regex, '$1/$2/$3')); return (parseInt(RegExp.$1, 10) == (1 + d.getMonth())) && (parseInt(RegExp.$2, 10) == d.getDate()) && (parseInt(RegExp.$3, 10) == d.getFullYear()); } } }], ['validate-email', { errorMsg: Form.Validator.getMsg.pass('email'), test: function(element){ return Form.Validator.getValidator('IsEmpty').test(element) || (/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i).test(element.get('value')); } }], ['validate-url', { errorMsg: Form.Validator.getMsg.pass('url'), test: function(element){ return Form.Validator.getValidator('IsEmpty').test(element) || (/^(https?|ftp|rmtp|mms):\/\/(([A-Z0-9][A-Z0-9_-]*)(\.[A-Z0-9][A-Z0-9_-]*)+)(:(\d+))?\/?/i).test(element.get('value')); } }], ['validate-currency-dollar', { errorMsg: Form.Validator.getMsg.pass('currencyDollar'), test: function(element){

[$]1[##][,###]+[.##] [$]1###+[.##] [$]0.## [$].##

  1. 453
  2. 454
  3. 455
  4. 456
  5. 457
  6. 458
  7. 459
  8. 460
  9. 461
  10. 462
  11. 463
  12. 464
  13. 465
  14. 466
  15. 467
  16. 468
  17. 469
  18. 470
  19. 471
  20. 472
  21. 473
  22. 474
  23. 475
  24. 476
  25. 477
  26. 478
  27. 479
  28. 480
  29. 481
  30. 482
  31. 483
  32. 484
  33. 485
  34. 486
  35. 487
  36. 488
  37. 489
  38. 490
  39. 491
  40. 492
  41. 493
  42. 494
  43. 495
return Form.Validator.getValidator('IsEmpty').test(element) || (/^\$?\-?([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(element.get('value')); } }], ['validate-one-required', { errorMsg: Form.Validator.getMsg.pass('oneRequired'), test: function(element, props){ var p = document.id(props['validate-one-required']) || element.getParent(props['validate-one-required']); return p.getElements('input').some(function(el){ if (['checkbox', 'radio'].contains(el.get('type'))) return el.get('checked'); return el.get('value'); }); } }] ]); Element.Properties.validator = { set: function(options){ var validator = this.retrieve('validator'); if (validator) validator.setOptions(options); return this.store('$moo:validator:options'); }, get: function(options){ if (options || !this.retrieve('validator')){ if (options || !this.retrieve('$moo:validator:options')) this.set('validator', options); this.store('validator', new Form.Validator(this, this.retrieve('$moo:validator:options'))); } return this.retrieve('validator'); } }; Element.implement({ validate: function(options){ this.set('validator', options); return this.get('validator', options).validate(); } });

<1.2compat> legacy

  1. 498
var FormValidator = Form.Validator;

</1.2compat>