-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathvalidator.js
More file actions
348 lines (297 loc) · 12.8 KB
/
validator.js
File metadata and controls
348 lines (297 loc) · 12.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
/*
Copyright (c) 2011 Martin Mahoney | http://bioluminous.net
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/** Initialize the core validator, and returns an object for use in creating instances **/
var UJV = (function() {
/** The Base object from which new instances are created **/
function BaseValidator(map) {
this.RuleMap = map || {};
};
/**
ValidateForm: When bound to a form, it iterates through each assigned rule set, running the rules
against that particular field.
**/
BaseValidator.prototype.ValidateForm = function(formObj) {
// exit if this is not a valid form element
if ( ! this.TestIsValidElement(formObj, "form") ){
return false;
}
// declare all our vars
var invalidFields = [], // <-- store any fields that fail validation
fieldKey,
fieldElm,
ruleKey,
ruleObj,
isValid;
// for each field, get rules
for (fieldKey in this.RuleMap) {
// get the field as a DOM element witht he fieldKey
fieldElm = this.GetElement(formObj, fieldKey);
// if no field found, skip
if(fieldElm === null) continue;
// clean up the input string
fieldElm.value = this.TrimAll(fieldElm.value);
// for each rule..
for (ruleKey in this.RuleMap[fieldKey]) {
// get rule object
ruleObj = this.RuleMap[fieldKey][ruleKey];
// added field element to ruleObj
ruleObj.fieldElm = fieldElm
// validator return state
isValid = false;
// if default validator, passed as a string, look it up and execute
if (typeof ruleObj.validator !== 'function') {
isValid = this[ruleObj.validator](fieldElm, ruleObj.args);
}
// if a custom validator function, execute that
else{
isValid = ruleObj.validator.call(this, fieldElm, ruleObj.args);
}
// if it failed, push it on the invalid stack
if(isValid === false) invalidFields.push(ruleObj);
}
}
// process the validation state and take action accordingly
if(invalidFields.length > 0){
return this.OnFormError(formObj, invalidFields);
}
else{
return this.OnFormSuccess(formObj);
}
};
/**
ValidateField: Runs against a single form field, it iterates through each assigned rule set, running the rules
against that particular field.
**/
BaseValidator.prototype.ValidateField = function(fieldElm){
// exit if this is not a valid form element
if(typeof fieldElm === "undefined" || fieldElm === null){
return false;
}
// declare all our vars
var fieldKey,
rulesObj,
ruleKey,
ruleObj,
isValid;
// get name or id as string
fieldKey = this.GetNameOrID(fieldElm);
// if no field with name or ID found, exit...
if(fieldKey === null){
return false;
}
// get rules for this field only
rulesObj = this.RuleMap[fieldKey];
// clean up the input string
fieldElm.value = this.TrimAll(fieldElm.value);
// for each rule..
for (ruleKey in rulesObj) {
// get rule object
ruleObj = rulesObj[ruleKey];
// added field element to fieldObj for use downstream
ruleObj.fieldElm = fieldElm
// validator return state
isValid = false;
// if default validator, passed as a string, look it up and execute
if (typeof ruleObj.validator !== 'function') {
isValid = this[ruleObj.validator](fieldElm, ruleObj.args);
}
// if a custom validator function, execute that
else{
isValid = ruleObj.validator.call(this, fieldElm, ruleObj.args);
}
// process the validation state and take action accordingly
isValid ? this.OnFieldSuccess(ruleObj) : this.OnFieldError(ruleObj);
// if the rule passed, move on to the next one, otherwise return false to fail validation
if(isValid) {continue;}
else {return false; }
}
// all rules passed, OK
return true;
};
/** BUILT-IN VALIDATION RULES **/
BaseValidator.prototype.Email = function(o) {
return /^[A-Z0-9._%\+\-\']+@(?:[A-Z0-9-]+\.)+[A-Z]{2,10}$/i.test(o.value);
};
BaseValidator.prototype.Required = function(o) {
return o.value.length >= 1 ? true : false;
};
BaseValidator.prototype.ValidChars = function(o){
return /^[A-Za-z\-\s]*$/i.test(o.value);
};
BaseValidator.prototype.ValidCharsExt1 = function(o){
return /^[A-Za-z@&\-'\s]*$/i.test(o.value);
};
// need to add a few more....
/**** utility methods *****/
/* removes leading and trailing whitespace*/
BaseValidator.prototype.TrimEnds = function(str) {
if(!str) return "";
str = str.replace(/^\s\s*/, ""),
ws = /\s/,
i = str.length;
while (ws.test(str.charAt(--i)));
return str.slice(0, i + 1);
};
/* removes leading, trailing, and repeated whitespaces( but leaves one between words ) */
BaseValidator.prototype.TrimAll = function(str) {
if(!str) return "";
str = str.replace(/^\s\s*/, ""),
ws = /\s/,
i = str.length;
while (ws.test(str.charAt(--i)));
var trimmed = str.slice(0, i + 1);
return trimmed.replace(/\s+/, " ");
};
/* check that we have a valid form element */
BaseValidator.prototype.TestIsValidElement = function(obj, tagname) {
if(typeof obj !== "undefined" && obj !== null){
// now test element and tag type are correct
try{
if(obj.nodeType === 1){
if(obj.tagName === tagname.toUpperCase()){ return true; }
}
}
catch(e){ }
}
return false;
};
/* get an element by ID, if no ID, try getting it from the form's elements collection ( f is expected to be a form object ) */
BaseValidator.prototype.GetElement = function(f, str) {
return document.getElementById(str) ? document.getElementById(str) :
f.elements[str] ? f.elements[str] : null;
};
/* look for an ID on this element, if not found, try to get a NAME */
BaseValidator.prototype.GetNameOrID = function(el){
return el.getAttribute("id") ? el.getAttribute("id") :
el.getAttribute("name") ? el.getAttribute("name") : null;
};
/* Test for existence of an error class */
BaseValidator.prototype.HasClass = function(el,cls, expr) {
var ex = cls !== null ? new RegExp("\\b" + cls + "\\b") : expr;
return (el && el.className) ? ex.test(el.className) : false;
};
/* Add an error class */
BaseValidator.prototype.AddClass = function (el,cls) {
if (!el) return;
var expr = new RegExp("\\b" + cls + "\\b");
if ( !this.HasClass(el, null, expr) ) {
el.className += " " + cls;
el.className = this.TrimAll(el.className);
}
};
/* Remove an error class */
BaseValidator.prototype.RemoveClass = function (el,cls) {
if (!el) return;
var expr = new RegExp("\\b" + cls + "\\b");
if(this.HasClass(el, null, expr)){
el.className = el.className.replace(expr, "");
el.className = this.TrimAll(el.className);
}
};
/**** Error styling methods. These functions can be overidden as desired *****/
/* Remove error classes from a single field on successful validation */
BaseValidator.prototype.OnFieldSuccess = function (o) {
var f = o.fieldElm,
l = f.parentNode.getElementsByTagName("label")[0];
this.RemoveClass(f, "fieldErrorBorder");
this.RemoveClass(l, "fieldErrorText");
return true;
};
/* Add error classes to a single field on failed validation */
BaseValidator.prototype.OnFieldError = function (o) {
var f = o.fieldElm,
l = f.parentNode.getElementsByTagName("label")[0];
this.AddClass(f, "fieldErrorBorder");
this.AddClass(l, "fieldErrorText");
return false;
};
/* Remove error classes from a all fields on successful validation */
BaseValidator.prototype.OnFormSuccess = function (form) {
var i, f, l;
for (i=form.elements.length; i--;){
f = form.elements[i];
l = f.parentNode.getElementsByTagName("label")[0];
this.RemoveClass(f, "fieldErrorBorder");
this.RemoveClass(l, "fieldErrorText");
}
return true;
};
/* Add error classes to all fields that failed validation */
BaseValidator.prototype.OnFormError = function (form, errors) {
var i, j, f, l, f2, l2;
for (i=form.elements.length; i--;){
f = form.elements[i];
l = f.parentNode.getElementsByTagName("label")[0];
this.RemoveClass(f, "fieldErrorBorder");
this.RemoveClass(l, "fieldErrorText");
}
for (j=errors.length; j--;){
f2 = errors[j].fieldElm;
l2 = f2.parentNode.getElementsByTagName("label")[0];
this.AddClass(f2, "fieldErrorBorder");
this.AddClass(l2, "fieldErrorText");
}
return false;
};
/** Public object for getting a validator instance **/
return {
GetInstance: function(map) {
return new BaseValidator(map);
}
}
})();
/**
You define rules for each form field. The string key is the fields DOM Id or Name attribute.
You can choose built-in validators, or pass a custom function that runs against the field objects
value and returns true or false. It must always do so, as its the condition the Validator uses
to know if it should flag the field as invalid or not
**/
var ValidatorMap = {
"firstname" : {
"rulel" : { validator : function(o){
return o.value === "BANANAS" ? false : true;
}, msg : "Your name is required to process the application" },
"rule2" : { validator : "Required", msg : "Your name is required to process the application" },
"rule3" : { validator : "ValidChars", msg : "Please enter a valid e-mail address in the format name@provider.com" }
},
"email" : {
"rulel" : { validator : function(o){
return o.value === "fake@fake.com" ? false : true;
}, msg : "Your E-mail Address is required to process the application" },
"rule2" : { validator : "Required", msg : "Your E-mail Address is required to process the application" },
"rule3" : { validator : "Email", msg : "Please enter a valid e-mail address in the format name@provider.com" }
}
};
// get a new instance and pass a validator map to use with it
var v = UJV.GetInstance(ValidatorMap);
// bind to a form and call the validator instance's ValidateForm method, passing the form as a DOM element
var formElm = document.getElementById("form1").addEventListener("submit",
function(e){
var result = v.ValidateForm(this);
e.preventDefault();
},
false);
// bind to an individual form field and call the validator instance's ValidateField method, passing the field as a DOM element
var fieldElm = document.getElementById("firstname").addEventListener("blur",
function(e){
var result = v.ValidateField(this);
e.preventDefault();
},
false);