├── .gitignore
├── LICENSE
├── README.md
├── _config.yml
├── composer.json
└── src
├── demo
└── index.html
└── js
├── formValidator.es6.js
├── formValidator.es6.min.js
├── formValidator.js
└── formValidator.min.js
/.gitignore:
--------------------------------------------------------------------------------
1 | # Created by .ignore support plugin (hsz.mobi)
2 | .idea
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2016 Shankar Thiyagaraajan
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## Global Source - JavaScript Form Validator [Ready to Use]
2 |
3 |
4 | [](https://github.com/global-source/javascript_form_validator) [](https://github.com/global-source/javascript_form_validator) [](https://github.com/shankarThiyagaraajan/PHP_Migration/blob/master/LICENSE)
5 |
6 |
7 | ### Installation
8 |
9 | git clone https://github.com/global-source/javascript_form_validator.git
10 | git checkout -b [VERSION]
11 |
12 |
13 | ## Why me ?
14 |
15 | * Support **Native** and **ES6** Javascript,
16 | * Pure Javascript Code (**No Dependency**),
17 | * Simplified Implementations,
18 | * **HTML 5 validation** for all Browsers,
19 | * Reliable and **Dynamic** level **DOM** Validations,
20 | * Dynamic auto scroll with element.
21 |
22 |
23 | **Steps to Integrate to Form :**
24 |
25 | ```html
26 |
27 | or
28 |
29 | ```
30 |
31 | Then Integrate your form with Validator.
32 |
33 | ```javascript
34 |
35 | var myform = new jsValidator().init({
36 | form: 'form2submit', // #id
37 | });
38 |
39 | ```
40 |
41 |
42 | ## Options
43 |
44 | | Name | Values | Descriptions | Mandatory |
45 | | ----------- | --------------- | ----------------------------------------------------------------------------- | --------- |
46 | | form | #ID | **ID** of the Form to handle validations and filters. | Yes |
47 | | forceFilter | Bool | **True**, to allow form filter without form validations. **False**, default. | No |
48 | | message | Object | Response message for all HTML elements. | No |
49 | | Log | Bool | To enable error log on console. | No |
50 |
51 | ---
52 |
53 | ## Actions
54 |
55 | ### `check()` : Return as Form is Valid or Not.
56 |
57 | ```javascript
58 | // Retrun status as True|False.
59 | myform.check()
60 | ```
61 |
62 | ### `update()` : Update Newly created DOM elements to Validator.
63 |
64 | ```javascript
65 | // It will update the DOM.
66 | myform.update()
67 | ```
68 | ---
69 |
70 | ## Attributes
71 |
72 | | Name | Values | Descriptions |
73 | | ----------------- | --------------- | ---------------------------------------------------------------------------- |
74 | | required | True, False | Set the fields is required to submit the Form. |
75 | | min | Integer | To set the Minimun value to proceed. |
76 | | max | Integer | To set the Maximum value to proceed. |
77 | | data-maxlength="10" | Integer | To set the Maximum length of characters to proceed. |
78 | | maxLength="10" | Integer | To set the Maximum length of characters to proceed. |
79 | | type="password" | AlphaNumeric | To set and compare password. |
80 | | type="email" | AlphaNumeric | To check the email is valid or not. |
81 | | type="file" | string ['png,jpeg..'] | To check the file format is allowed or not. |
82 | | data-message="Error Message"| String | User defined, element based direct error message to handle. |
83 | | data-allow="onlyAlpha"| Alphabets Only | Allow only string, no digits and no special characters. |
84 | | data-allow="string"| Alphabets + Numbers Only | Allow only string and digits, no special characters. |
85 | | data-allowSpecial="/_+"| Special characters | Allow only given special characters. |
86 | | [INDEX] | Numeric | Now supports Min&Max validation to show the limit. |
87 |
88 | Currently the validation will trigger on submit button trigger.
89 |
90 | It has automated listener to monitor every changes on form.
91 |
92 | **Note:**
93 |
94 | 1. Validation take place between tags, so need to specify the **ID**
95 | of the Form or any other tags.
96 |
97 | ```html
98 |
// Preferred
99 |
100 |
// Not-Preferred.
101 | ```
102 |
103 |
104 | #### For General Input Validation
105 |
106 | 2. Input Fields should specify the type of validation.
107 |
108 | ```html
109 |
164 | ```
165 |
166 | 3. In form use **`novalidate`** to avoid browser interuptions.
167 |
168 | ```html
169 |
173 | ```
174 |
175 | #### Sample
176 |
177 | ```javascript
178 |
179 | // For Native & ES6 Javascript.
180 | var myform = new jsValidator().init({
181 | form: 'form2submit', // #id
182 | forceFilter: true,
183 | message: {
184 | required: 'This field is required !',
185 | min: ' This field is less then the limit',
186 | max: 'This field is exceeds the limit',
187 | password: 'Password doesn\'t match !',
188 | email: 'Invalid Email found !',
189 | file: 'Invalid File format given'
190 | }
191 | });
192 |
193 | ```
194 |
195 | It Will listen the **Submit** event **Automatically** and initiating the validation checks.
196 | And based on response, it will allow to submit or throw messages.
197 |
198 |
199 | License
200 | ===
201 |
202 | Copyright (c) 2016 Shankar Thiyagaraajan
203 |
204 | ### MIT License
205 |
206 |
207 |
208 |
--------------------------------------------------------------------------------
/_config.yml:
--------------------------------------------------------------------------------
1 | theme: jekyll-theme-cayman
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "global-source/javascript-form-validator",
3 | "description": "JavaScript Based Form Validator.",
4 | "license": "MIT"
5 | }
6 |
--------------------------------------------------------------------------------
/src/demo/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Demo 2 | Javascript Validator
6 |
7 |
8 |
9 |
10 |
Input Client Information
11 |
105 |
106 |
107 |
108 |
128 |
129 |
130 |
--------------------------------------------------------------------------------
/src/js/formValidator.es6.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * JavaScript Validator Library v2.0
3 | * To perform effective validation and filter with form elements.
4 | *
5 | * Author : Shankar Thiyagaraajan
6 | * Email : shankarthiyagaraajan@gmail.com
7 | * GitHub : https://github.com/shankarThiyagaraajan
8 | *
9 | * Source
10 | * https://github.com/global-source/javascript_form_validator
11 | *
12 | * Site
13 | * https://global-source.github.io/javascript_form_validator/
14 | *
15 | * Copyright 2017
16 | *
17 | * Released under the MIT license
18 | * https://github.com/global-source/javascript_form_validator/blob/master/LICENSE
19 | *
20 | * Date: 2017-08-03
21 | */
22 |
23 |
24 | /*
25 | * For Managing overall Validation flow.
26 | */
27 | let __err_id_suffix_rand_hash = '_new1_1_1xv_resp';
28 | let __status_log = false;
29 |
30 | /**
31 | * Core Js Validator.
32 | */
33 | class jsValidator {
34 | constructor() {
35 | // Holding form element data.
36 | this.formData = false;
37 | // Switch complete validation and input filter.
38 | this.onlyFilter = false;
39 | // JS form.
40 | this.jsForm = false;
41 | // JS setting.
42 | this.jsSettings = false;
43 | // JS form error.
44 | this.jsFormError = false;
45 | // Overall error list.
46 | this.formErrorList = {};
47 | // To Filter non-required fields.
48 | this.forceFilter = false;
49 | // To Filter the First load.
50 | this.initialLoad = true;
51 | // Global options.
52 | this.option = false;
53 | // To apply global validator.
54 | this.onChange = false;
55 | this.validateResponse = false;
56 | }
57 |
58 | /*
59 | * Initiating the Validator.
60 | */
61 | init(option) {
62 | // Update overall log status.
63 | __status_log = option.log;
64 | // To Update global options.
65 | this.option = option;
66 | jsLogger.table(option);
67 | // Updating the filter flag to global.
68 | this.onlyFilter = option.onlyFilter;
69 | // To Enable/Disable global validator.
70 | this.onChange = option.onChange;
71 | // Update default response "class".
72 | if ('undefined' === typeof option.errorClass) option.errorClass = 'js-error-cop';
73 | this.validateResponse = new validationResponse();
74 | // Update "jsSettings" to global object.
75 | this.jsSettings = new jsSettings().init(option);
76 | // Update "jsForm" to global object.
77 | this.jsForm = new jsForm().init(option);
78 | // Initiate form error setup.
79 | this.jsFormError = new jsFormError().init();
80 | // Update Force Field status.
81 | this.forceFilter = option.forceFilter;
82 | // To check the form elements.
83 | this.check();
84 | // To register the listener.
85 | this.submitListener(this.jsForm.formCore, this);
86 | // Send back "this".
87 | return this;
88 | };
89 |
90 | /*
91 | * To make listen on submit action of the form.
92 | */
93 | submitListener(formID, obj) {
94 | // To off submit listener, if only filter needed.
95 | if (false === this.onlyFilter || typeof (this.onlyFilter) === 'undefined') {
96 | // Initiate listener for form submission.
97 | document.querySelector('#' + formID).addEventListener('submit', function (e) {
98 | // To start form validations.
99 | // Check validation status.
100 | if (false === obj.check()) {
101 | //stop form from submitting, if validation fails
102 | e.preventDefault();
103 | }
104 | });
105 | }
106 | };
107 |
108 | /*
109 | * To Refresh the DOM and enable Dynamic-Elements to Access.
110 | */
111 | update() {
112 | let option = this.option;
113 | // Updating the filter flag to global.
114 | this.onlyFilter = option.onlyFilter;
115 | // Update "jsSettings" to global object.
116 | this.jsSettings = new jsSettings().init(option);
117 | // Update "jsForm" to global object.
118 | this.jsForm = new jsForm().init(option);
119 | // Initiate form error setup.
120 | this.jsFormError = new jsFormError().init();
121 | };
122 |
123 | /*
124 | * To checking all elements from registered form.
125 | */
126 | check() {
127 | let status = false;
128 | // Loading JS Form.
129 | let jsFormObj = this.jsForm;
130 | // Loading JS error list.
131 | let errorList = this.formErrorList;
132 | let option = [];
133 | // Looping the "input" elements for validation and filter implementation.
134 | errorList.input = this.elemLoop('input', jsFormObj.input);
135 | // Looping the "textArea" elements fro validation filter implementation.
136 | errorList.textArea = this.elemLoop('textArea', jsFormObj.textArea);
137 | // Looping the "select" elements fro validation filter implementation.
138 | errorList.select = this.elemLoop('select', jsFormObj.select);
139 | jsLogger.out('Error List', this.formErrorList);
140 | option.push({
141 | 'errorElem': errorList
142 | });
143 | // To Update global Validation Status.
144 | // If, Input elements have no errors.
145 | if (errorList.input.length === 0) {
146 | // If, Text Area elements have no errors.
147 | if (errorList.textArea.length === 0) {
148 | // If, Select elements have no errors.
149 | if (errorList.select.length === 0) {
150 | // If validation pass, then update "status" object.
151 | status = true;
152 | }
153 | }
154 | }
155 | if (false == this.initialLoad) this.validateResponse.init(errorList, this.option);
156 | this.initialLoad = false;
157 | helper.scrollToError(this.validateResponse);
158 | return status;
159 | };
160 |
161 | /*
162 | * To looping all elements for actions.
163 | */
164 | elemLoop(index, formElem) {
165 | // Initiate empty array for keep list of errors.
166 | let log = [];
167 | // Sanity check with "formElem".
168 | if (formElem === null || typeof formElem === 'undefined') return false;
169 | formElem = formElem.reverse();
170 | // Looping elements.
171 | for (let i in formElem) {
172 | if (formElem[i]) {
173 | // Switch to static letiable.
174 | let activeElem = formElem[i];
175 | // Apply filter to element.
176 | this.applyFilters(activeElem);
177 | // Register the DOM with live onChange validations.
178 | if (true == this.onChange) {
179 | this.applyGlobalListener(activeElem);
180 | }
181 | //jsLogger.out('Only Filter', this.onlyFilter);
182 | // If not only filter, then start validations.
183 | if (false === this.onlyFilter || typeof (this.onlyFilter) === 'undefined') {
184 | // Initiate validations and update to log.
185 | log = new jsRuleSets().checkValidation(activeElem, log);
186 | }
187 | }
188 | }
189 | // jsLogger.out('Log', log);
190 | return log;
191 | };
192 |
193 | /*
194 | * To apply filter to all relevant elements by it's attributes.
195 | */
196 | applyFilters(activeElem) {
197 | // Apply filter for Number elements.
198 | if (activeElem.type == 'number') new jsFilter().number(activeElem);
199 | // Apply filter for Email elements.
200 | if (activeElem.type == 'email') new jsFilter().email(activeElem);
201 | // Apply filter for Numeric elements.
202 | if ('' !== activeElem.min || '' !== activeElem.max || activeElem.getAttribute('data-maxlength') || -1 !== activeElem.maxLength) new jsFilter().limit(activeElem);
203 | // Apply filter File elements.
204 | if (activeElem.type == 'file') new jsFilter().file(activeElem);
205 | // Apply filter with string, alphaNumeric and pregMatch.
206 | if (activeElem.getAttribute('data-allow')) new jsFilter().string(activeElem);
207 | // Apply filter with pattern.
208 | if (activeElem.getAttribute('pattern')) new jsFilter().pattern(activeElem);
209 | };
210 |
211 | /*
212 | * To make it active to listen changes of those error fields.
213 | */
214 | applyGlobalListener(element) {
215 | element.addEventListener('change', this.quickValidation, false);
216 | };
217 |
218 | /*
219 | * To perform quick validation to respond those fields.
220 | */
221 | quickValidation(event) {
222 | // jsLogger.out('Quick', event);
223 | let log = [];
224 | let target = event.target;
225 | // To check the validation of an element.
226 | log = new jsRuleSets().checkValidation(target, log);
227 | // jsLogger.out('Quick Out', log);
228 | new validationResponse().process(log);
229 | };
230 |
231 | /*
232 | * Single step instance validator for Ajax form submissions.
233 | */
234 | validate() {
235 | // Initiate form Check.
236 | return this.check();
237 | };
238 | }
239 | /**
240 | * Common Filter instances.
241 | */
242 | class jsFilter {
243 | checkStatus(elem) {
244 | let status;
245 | status = true;
246 | if (false === new jsValidator().forceFilter) {
247 | status = false;
248 | if (true === elem.required) {
249 | status = true;
250 | }
251 | }
252 | return status;
253 | };
254 |
255 | // Number elements filter listener.
256 | number(element) {
257 | let status = this.checkStatus(element);
258 | if (true === status) element.addEventListener('keypress', this.isNumberKey, false);
259 | };
260 |
261 | /*
262 | * String elements filter listener.
263 | */
264 | string(element) {
265 | // Getting "data" attribute for actions.
266 | let type = element.getAttribute('data-allow');
267 | let current = this;
268 | let status = this.checkStatus(element);
269 |
270 | // Switching actions.
271 | switch (type) {
272 | // Allow only alphabets [a-zA-Z] not [0-9] and special characters.
273 | case 'onlyAlpha':
274 | if (true === status) element.addEventListener('keypress', current.isAlpha, false);
275 | break;
276 | // Allow only alpha Numeric [a-zA-Z0-9] not special characters.
277 | case 'string':
278 | if (true === status) element.addEventListener('keypress', current.isAlphaNumeric, false);
279 | break;
280 | // Allow based on the pattern given.
281 | default:
282 | if (true === status) element.addEventListener('keypress', current.isPatternValid, false);
283 | break;
284 | }
285 | };
286 |
287 | /*
288 | * Pattern based filter and listener.
289 | */
290 | pattern(element) {
291 | let current = this;
292 | let status = this.checkStatus(element);
293 | if (true === status) element.addEventListener('keypress', current.isPatternValid, false);
294 | };
295 |
296 | /*
297 | * Email elements filter listener.
298 | */
299 | email(element) {
300 | let status = this.checkStatus(element);
301 | if (true === status) element.addEventListener('keypress', jsRuleSets.email, false);
302 | };
303 |
304 | file(element) {
305 | let status = this.checkStatus(element);
306 | if (true === status) element.addEventListener('change', jsRuleSets.file, false);
307 | };
308 |
309 | /*
310 | * Numeric with Limited elements filter listener.
311 | */
312 | limit(element) {
313 | let current = this;
314 | let status = this.checkStatus(element);
315 | if (true === status) element.addEventListener('change', current.isInLimit, false);
316 | };
317 |
318 | /*
319 | * Restrict element with it's limit.
320 | */
321 | isInLimit(event) {
322 |
323 | // Load the element value.
324 | let value = event.target.value;
325 |
326 | // To check is this action is from "windows" action or not.
327 | if (true === helper.isWindowAction(event)) return true;
328 |
329 | // Getting target element.
330 | let target = event.target;
331 |
332 | // Final value to load back.
333 | let final_value = value;
334 |
335 | // Getting object from element.
336 | let min = event.target.min;
337 | let max = event.target.max;
338 |
339 | // Get max-length attribute from element.
340 | let max_length = event.target.getAttribute('data-maxlength') ? event.target.getAttribute('data-maxlength') : 0;
341 | max_length = parseInt(max_length);
342 | let num = value;
343 |
344 | // if "max_length" is "0", then its don't have limit letiables.
345 | if (0 === max_length) {
346 |
347 | // Default values for Min and Max.
348 | if (!min) min = 1;
349 | if (!max) max = 100;
350 |
351 | // Forming pattern for Restriction.
352 | let regex = new RegExp('^[0-9]+$');
353 |
354 | // Validation with Code.
355 | let key = String.fromCharCode(!event.charCode ? event.which : event.charCode);
356 |
357 | // Return status of the Action.
358 | if (false === regex.test(key) || parseInt(value) > max || parseInt(value) < min) {
359 | event.preventDefault();
360 | }
361 |
362 | // Parse to INT.
363 | num = parseInt(num, 10);
364 |
365 | // // converts value to a Number.
366 | if (isNaN(num)) {
367 | target.value = "";
368 | return;
369 | }
370 |
371 | // Check value is greater than "max", then replace "max".
372 | if (parseInt(num) > max) final_value = max;
373 |
374 | // Check value is greater than "min", then replace "min".
375 | if (parseInt(num) < min) final_value = min;
376 |
377 | } else {
378 | //TODO: Min length later.
379 | // Validate the length of the string.
380 | if ((num.length > max_length) && 0 < max_length) {
381 | // If length is more, then cutoff the remaining letters.
382 | final_value = num.substr(0, max_length);
383 | }
384 | }
385 |
386 | // Revert value back to an element.
387 | this.value = final_value;
388 | };
389 |
390 | /*
391 | * Only allow alpha([a-zA-Z]).
392 | */
393 | isAlpha(event) {
394 | // To check is this action is from "windows" action or not.
395 | if (true === helper.isWindowAction(event)) return true;
396 | // Managing the Pattern.
397 | let status = new pattern().validate(event, 'a-zA-Z');
398 | // Return status of the Action.
399 | if (false === status) event.preventDefault();
400 | };
401 |
402 | /*
403 | * Only allow alpha([a-zA-Z0-9]).
404 | */
405 | isAlphaNumeric(event) {
406 | // To check is this action is from "windows" action or not.
407 | if (true === helper.isWindowAction(event)) return true;
408 | // Managing the Pattern.
409 | let status = new pattern().validate(event, 'a-zA-Z0-9');
410 | // Return status of the Action.
411 | if (false === status) event.preventDefault();
412 | };
413 |
414 | /*
415 | * To check password is valid or not.
416 | */
417 | isValidPassword(event) {
418 | // Prevent using "space".
419 | let charCode = (event.which) ? event.which : event.keyCode;
420 | // If event is "space" then prevent to enter.
421 | if (charCode === 32) {
422 | event.preventDefault();
423 | return false;
424 | } // To check is this action is from "windows" action or not.
425 |
426 | if (true === helper.isWindowAction(event)) return true;
427 | // Managing the Pattern.
428 | let status = new pattern().validate(event, 'a-zA-Z0-9');
429 | // Return status of the Action.
430 | if (false === status) event.preventDefault();
431 | };
432 |
433 | /*
434 | * Only allow by pattern(ex. ^[a-zA-Z0-3@#$!_.]+$).
435 | */
436 | isPatternValid(event) {
437 | // To check is this action is from "windows" action or not.
438 | if (true === helper.isWindowAction(event)) return true;
439 | // Managing the Pattern.
440 | let status = new pattern().validate(event, 'a-zA-Z0-4');
441 | // Return status of the Action.
442 | if (false === status) event.preventDefault();
443 | };
444 |
445 | /*
446 | * Check is numeric or not.
447 | */
448 | isNumberKey(event) {
449 | // To check is this action is from "windows" action or not.
450 | if (true === helper.isWindowAction(event)) return true;
451 | // Validation with Code.
452 | let charCode = (event.which) ? event.which : event.keyCode;
453 | if (charCode === 46 || charCode > 31 && (charCode < 48 || charCode > 57)) {
454 | event.preventDefault();
455 | return false;
456 | } // Return status of the Action.
457 |
458 | return true;
459 | };
460 | }
461 |
462 | /**
463 | * To Update overall JsValidator Settings.
464 | */
465 | class jsSettings {
466 | constructor() {
467 | // Common error message color for form validation.
468 | this.errorColor = false;
469 | // Set common template for error message
470 | this.errorTemplate = false;
471 | }
472 |
473 | /*
474 | * To Initiate the Configurations.
475 | */
476 | init(option) {
477 | // To update error message color to global object.
478 | this.errorColor = option.errorColor;
479 | // To update error template to handle error message.
480 | this.errorTemplate = option.errorTemplate;
481 | // Return "this" object.
482 | return this;
483 | };
484 |
485 | /*
486 | * General Log.
487 | */
488 | log() {
489 | jsLogger.out(this.errorColor);
490 | jsLogger.out(this.errorTemplate);
491 | };
492 | }
493 | /**
494 | * To Perform all Form based Operations.
495 | */
496 | class jsForm {
497 | constructor() {
498 | // Form element.
499 | this.form = false;
500 | // Form ID.
501 | this.formCore = false;
502 | // Form element's inputs.
503 | this.input = false;
504 | // Form element's selects.
505 | this.select = false;
506 | // Form element's textAreas.
507 | this.textArea = false;
508 | // Form element's labels.
509 | this.label = false;
510 | // Perform Force Filter on Elements.
511 | this.forceFilter = false;
512 | }
513 |
514 | /*
515 | * To Initiating the "jsForm".
516 | */
517 | init(option) {
518 | jsLogger.out('Form', option.form);
519 | // Update Global Option.
520 | this.options = option;
521 | // Enable/Disable Force Filter.
522 | this.forceFilter = option.forceFilter;
523 | // To Register Form.
524 | this.registerForm(option.form);
525 | // To Parsing the Form.
526 | this.parseForm(this.form);
527 | // To Filter Required Elements.
528 | this.required();
529 | return this;
530 | };
531 |
532 | /*
533 | * To Register Active Form to Global Object.
534 | */
535 | registerForm(form) {
536 | // validate and Update Log.
537 | if (typeof form === 'undefined') jsLogger.out('Form Identification', 'Form Identification is Missing !');
538 | // Form should not be an ID.
539 | if (null === form) return false;
540 | // Fetch Form element from Document.
541 | this.form = document.getElementById(form);
542 | if (null === this.form) jsLogger.out('Status 503', 'Failed to Proceed !');
543 | // Update Direct Form ID.
544 | this.formCore = form;
545 | };
546 |
547 | /*
548 | * To Parse all Relative Form components.
549 | */
550 | parseForm(form) {
551 | if (form === null) return false;
552 | // "Input" elements like "text, date, time..."
553 | this.input = form.getElementsByTagName('input');
554 | // "Select" element.
555 | this.select = form.getElementsByTagName('select');
556 | // "TextArea" element.
557 | this.textArea = form.getElementsByTagName('textarea');
558 | // "Label" element.
559 | this.label = form.getElementsByTagName('label');
560 | };
561 |
562 | /*
563 | * To set fields are required.
564 | */
565 | required() {
566 | // let jsField = new jsField().init(this.options);
567 | let forceFilter = this.forceFilter;
568 | let jsField_obj = new jsField();
569 | // Filter all required "input" elements.
570 | this.input = jsField_obj.required(this.input, forceFilter);
571 | // Filter all required "select" elements.
572 | this.select = jsField_obj.required(this.select, forceFilter);
573 | // Filter all required "textArea" elements.
574 | this.textArea = jsField_obj.required(this.textArea, forceFilter);
575 | };
576 |
577 | /*
578 | * General Log.
579 | */
580 | log() {
581 | jsLogger.out('Form', this.form);
582 | jsLogger.out('input', this.input);
583 | jsLogger.out('select', this.select);
584 | jsLogger.out('textarea', this.textArea);
585 | jsLogger.out('labels', this.label);
586 | };
587 | }
588 | /**
589 | * Perform Operations in Field level.
590 | */
591 | class jsField {
592 | /*
593 | * Return all required elements list.
594 | */
595 | required(field, forceFilter) {
596 | let requiredFieldsList = [];
597 | // Looping fields to filter.
598 | for (let i = 0; i < field.length; i++) {
599 | // Check and push elements.
600 | if (field[i].required === true || true === forceFilter) {
601 | // Pushing to required elements list.
602 | requiredFieldsList.push(field[i]);
603 | }
604 | } // Return list of required elements.
605 |
606 | return requiredFieldsList;
607 | };
608 | }
609 | /**
610 | * List of Validation Rules.
611 | */
612 | class jsRuleSets {
613 | /*
614 | * To start validation process.
615 | */
616 | checkValidation(activeElem, log) {
617 | //jsLogger.out('Active Elem', activeElem);
618 | let validElem = true;
619 | let jsRuleSets_obj = new jsRuleSets();
620 | // To Generally checks, the field is empty or not.
621 | if (!jsRuleSets_obj.isSet(activeElem)) {
622 | log.push({
623 | 'el': activeElem,
624 | 'type': 'required',
625 | 'id': activeElem.name + __err_id_suffix_rand_hash
626 | });
627 | validElem = false;
628 | }
629 |
630 | // To Check the Value is less than minimum or not.
631 | if (activeElem.min) {
632 | if (jsRuleSets_obj.isSet(activeElem)) {
633 | if (!jsRuleSets_obj.min(activeElem)) {
634 | log.push({
635 | 'el': activeElem,
636 | 'type': 'min',
637 | 'id': activeElem.name + __err_id_suffix_rand_hash
638 | });
639 | validElem = false;
640 | }
641 | }
642 | }
643 |
644 | // To Check the Value is grater than max or not.
645 | if (activeElem.max) {
646 | if (jsRuleSets_obj.isSet(activeElem)) {
647 | if (!jsRuleSets_obj.max(activeElem)) {
648 | log.push({
649 | 'el': activeElem,
650 | 'type': 'max',
651 | 'id': activeElem.name + __err_id_suffix_rand_hash
652 | });
653 | validElem = false;
654 | }
655 | }
656 | }
657 |
658 | // To Check the Entered E-mail is Valid or Not.
659 | if (activeElem.type == 'email') {
660 | if (jsRuleSets_obj.isSet(activeElem)) {
661 | if (!jsRuleSets_obj.email(activeElem)) {
662 | log.push({
663 | 'el': activeElem,
664 | 'type': 'email',
665 | 'id': activeElem.name + __err_id_suffix_rand_hash
666 | });
667 | validElem = false;
668 | }
669 | }
670 | }
671 |
672 | // To Compare the Password is Same or Not with Re-Password.
673 | // TODO: Implement Simplified Comparison.
674 | if (activeElem.type == 'password') {
675 | if (jsRuleSets_obj.isSet(activeElem)) {
676 | if (!jsRuleSets_obj.compare(activeElem)) {
677 | log.push({
678 | 'el': activeElem,
679 | 'type': 'password',
680 | 'id': activeElem.name + __err_id_suffix_rand_hash
681 | });
682 | validElem = false;
683 | }
684 | }
685 | } // If valid, then reset validation message.
686 |
687 | if (true === validElem) {
688 | //jsLogger.out('Valid Elem', activeElem);
689 | if (activeElem.name !== '') {
690 | let elem = document.getElementById(activeElem.name + __err_id_suffix_rand_hash);
691 | if (typeof (elem) !== 'undefined' && elem !== null) {
692 | // Remove element to avoid un-necessary buffer.
693 | elem.remove();
694 | }
695 | }
696 | }
697 | // If error occurred, then locate that error
698 | if (false !== validElem) {
699 | //
700 | }
701 |
702 | // Return overall log report of validation.
703 |
704 | return log;
705 | };
706 |
707 | /*
708 | * To Check, whether the element have value or not.
709 | */
710 | isSet(elem) {
711 | // If field is not required, then return "true".
712 | if (false === elem.required) return true;
713 | let status = true;
714 | let value = elem.value;
715 | //TODO: Implement suitable solution for this.
716 | if (value.length === 0 || value === '' || value === ' ' || value === '[]') status = false;
717 | return status;
718 | };
719 |
720 | /*
721 | * To Check Element with Min Condition.
722 | */
723 | min(elem) {
724 | // If field is not required, then return "true".
725 | if (false === elem.required) return true;
726 | let status = true;
727 | let value = elem.value;
728 | let min = elem.min;
729 | //TODO: Implement suitable solution for this.
730 | if (value.length < min && value.length != 0) status = false;
731 | return status;
732 | };
733 |
734 | /*
735 | * To Check Element with Max Condition.
736 | */
737 | max(elem) {
738 | // If field is not required, then return "true".
739 | if (false === elem.required) return true;
740 | let status = true;
741 | let value = elem.value;
742 | let max = elem.max;
743 | //TODO: Implement suitable solution for this.
744 | if (value.length > max && value.length != 0) status = false;
745 | return status;
746 | };
747 |
748 | /*
749 | * To Check Element Email is Valid or Not.
750 | */
751 | email(elem) {
752 | // If field is not required, then return "true".
753 | if (false === elem.required) return true;
754 | let status = false;
755 | let email = elem.value;
756 | if (typeof email === 'undefined') return false;
757 | // To Validate Email.
758 | // Convert to Native String Format.
759 | email = email.toString();
760 | // To Check it as String or Not.
761 | if (/^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$/.test(email)) {
762 | // Valid Email.
763 | status = true;
764 | }
765 | if (!email) status = false;
766 | return status;
767 | };
768 |
769 | file(elem) {
770 | let list_to_allow = elem.target.getAttribute('data-extensions');
771 | let target = elem.target;
772 | let list_to_allow_array;
773 | let file_response;
774 | if ('' === list_to_allow) return true;
775 | // Slit into array of extensions.
776 | if (-1 === list_to_allow.indexOf(',')) {
777 | list_to_allow_array = [list_to_allow];
778 | } else {
779 | list_to_allow_array = list_to_allow.split(',');
780 | }
781 | // Get file name.
782 | let fileName = target.value;
783 | // Convert to lower case for native validation.
784 | fileName = fileName.toLowerCase();
785 | file_response = (new RegExp('(' + list_to_allow_array.join('|').replace(/\./g, '\\.') + ')$')).test(fileName);
786 | if (false === file_response) {
787 | alert('Allowed file types are "' + list_to_allow + '" !');
788 | // Reset file type.
789 | elem.target.value = '';
790 | return false;
791 | }
792 | return true;
793 | };
794 |
795 | /*
796 | * To Check Element Phone Value is Valid or Not.
797 | */
798 | phone(elem, pattern) {
799 | // If field is not required, then return "true".
800 | if (false === elem.required) return true;
801 | let status = true;
802 | if (elem.value === '') status = false;
803 | return status;
804 | };
805 |
806 | /*
807 | * To Compare two Elements Values.
808 | */
809 | compare(elem1) {
810 | let status = false;
811 | // If field is not required, then return "true".
812 | if (false === elem1.required) status = true;
813 | // 2'nd element's ID.
814 | let elem2_id = elem1.getAttribute('data-check');
815 | // Default 2'nd element comparision.
816 | let elem2_value = '';
817 | // Secondary element.
818 | let elem2 = false;
819 | // Verify, 2'nd element is defined or not.
820 | if (typeof elem2_id == 'undefined' || elem2_id == null) status = false;
821 | // If null, then take it's a primary element.
822 | if (elem2_id === null) elem2_id = elem1.getAttribute('data-parent');
823 | // If secondary element not defined, then "status" will FALSE.
824 | if (elem2_id === null) {
825 | status = false;
826 | } else {
827 | // If set, then take secondary element's id.
828 | elem2_id = elem2_id.toString();
829 | // Get value of secondary element.
830 | elem2 = document.getElementById(elem2_id);
831 | // If both values are same, then "status" will TRUE.
832 | if (elem1.value === elem2.value) status = true;
833 | // Value of secondary element.
834 | elem2_value = elem2.value;
835 | }
836 |
837 | // Throw error message for password validation.
838 | if (true === status || '' === elem2_value) {
839 | // Hardly remove the error message.
840 | document.getElementById(elem1.name + __err_id_suffix_rand_hash).remove();
841 | // Verify and remove error message.
842 | if (false !== elem2) document.getElementById(elem2.name + __err_id_suffix_rand_hash).remove();
843 | }
844 |
845 | //jsLogger.out('Compare Status', status);
846 | return status;
847 | };
848 | }
849 | /**
850 | * To Manage JsValidator Errors.
851 | */
852 | class jsFormError {
853 | constructor() {
854 | // Global constant to specify, error happened or not.
855 | this.errorHit = false;
856 | // Error Css.
857 | this.errorCss = false;
858 | // Success Css.
859 | this.successCss = false;
860 | }
861 |
862 | /*
863 | * Initiate overall form error handler.
864 | */
865 | init() {
866 | this.errorHit = false;
867 | this.errorCss = 'border-color: red;border-radius: 5px;color: red;';
868 | this.successCss = 'border-color: green;border-radius: 5px;color: green;';
869 | };
870 |
871 | /*
872 | * Form error log.
873 | */
874 | log() {
875 | // jsLogger.out('Form Error Hit', this.errorHit);
876 | };
877 |
878 | /*
879 | * Form error style.
880 | */
881 | style(css) {
882 | this.errorCss = css.error;
883 | this.successCss = css.success;
884 | };
885 | }
886 | /**
887 | * For manage overall logging with validator.
888 | */
889 | let jsLogger = {
890 | status: function () {
891 | // return jsValidator.option.log;
892 | return __status_log;
893 | },
894 | /*
895 | * Simple log with "heading" and "message".
896 | */
897 | out: function (heading, message) {
898 |
899 | if (true !== this.status()) return false;
900 | console.log('======' + heading + '======');
901 | console.log(message);
902 | console.log('------------------------');
903 | },
904 | /*
905 | * For bulk data logging.
906 | */
907 | bulk: function (data) {
908 | if (true !== this.status()) return false;
909 | console.log(data);
910 | },
911 | /*
912 | * For log data with table.
913 | */
914 | table: function (data) {
915 | if (true !== this.status()) return false;
916 | console.table(data);
917 | }
918 | };
919 | /**
920 | * General Helping methods.jsField_obj
921 | */
922 | let helper = {
923 | /*
924 | * To check the keyboard action is window action or not.
925 | */
926 | isWindowAction: function (event) {
927 | // Getting the event to be triggered.
928 | let theEvent = event || window.event;
929 | // Getting the type of event or code.
930 | let key = theEvent.shiftKey || theEvent.which;
931 | // Check with list of code and ignore holding.
932 | // Tab, Space, Home, End, Up, Down, Left, Right...
933 | if (key === 9 || key === 0 || key === 8 || key === 32 || key === 13 || key === 8 || (key >= 35 && key <= 40)) {
934 | return true;
935 | } // If not in list then check return with corresponding data.
936 |
937 | key = String.fromCharCode(key);
938 | // Return also if length is 0.
939 | if (key.length === 0) return true;
940 | // Finally return "false" for general keys.
941 | return false;
942 | },
943 | /*
944 | * To Scroll Up / Down to notify the item that have validation message.
945 | */
946 | scrollToError: function (validateResponse) {
947 | let dummy_id = '__header_error_target_temp';
948 | let active_class = validateResponse.getClass();
949 |
950 | if (false === active_class) {
951 | jsLogger.out('Active Class Error', 'ACTIVE CLASS NOT DEFINED, GET :' + active_class);
952 | return false;
953 | }
954 |
955 | if (0 === document.getElementsByClassName(active_class).length) return false;
956 | // Getting current ID of the element.
957 | let active_id = document.getElementsByClassName(active_class)[0].id;
958 | // Update first element with dummy index ID.
959 | document.getElementsByClassName(active_class)[0].setAttribute('id', dummy_id);
960 | // Forming ID.
961 | let id = document.getElementsByClassName(active_class)[0].id;
962 | // Retrieve the element name.
963 | let elem_name = active_id.replace(__err_id_suffix_rand_hash, '');
964 | // Taking active element to navigate.
965 | let top = document.getElementsByName(elem_name)[0].offsetTop;
966 | // Format as ID.
967 | id = '#' + id;
968 | // Navigate to ID.
969 | // window.location.href = id;
970 | // Scroll to error element as close as possible.
971 | window.scroll(0, parseInt(top) - 15);
972 | // Restore with actual ID.
973 | document.getElementsByClassName(active_class)[0].setAttribute('id', active_id);
974 | // Remove the navigated value.
975 | this.removeHash(id);
976 | },
977 | /*
978 | * To Scroll Up / Down to notify the item that have validation message.
979 | */
980 | scrollToItem: function (item) {
981 | // Form hash value.
982 | let hash = item;
983 | // If "#" is missing, then add back to the ID.
984 | if (-1 === hash.indexOf('#')) hash = '#' + hash;
985 | // Navigate with the hash value.
986 | window.location.href = hash;
987 | // Remove the navigated value.
988 | this.removeHash(hash);
989 | },
990 | /*
991 | * To remove the hash value from the URL.
992 | */
993 | removeHash: function (hash) {
994 | // Getting the actual URL.
995 | let path = window.location.href;
996 | // Replacing the URL with specific hash value.
997 | path = path.replace(hash, '');
998 | // Update to url history.
999 | window.history.pushState('', 'Title', path);
1000 | }
1001 | };
1002 | /**
1003 | * Simple library for Pattern.
1004 | */
1005 | class pattern {
1006 | /*
1007 | * To generate pattern from element attribute.
1008 | */
1009 | getDefault(event, originalPattern) {
1010 | if (typeof originalPattern == 'undefined') originalPattern = '';
1011 | // Getting special characters list.
1012 | let allow_special = event.target.getAttribute('data-allowSpecial');
1013 | let pattern = event.target.pattern;
1014 | console.log(pattern.length);
1015 | let defaultPattern;
1016 | // Set default values for special characters.
1017 | if (!allow_special && allow_special === null) allow_special = '';
1018 | // Format to string.
1019 | allow_special = allow_special.toString();
1020 | if (pattern !== '' && pattern.length > 0 && pattern !== null) {
1021 | defaultPattern = pattern;
1022 | } else {
1023 | defaultPattern = '^[' + originalPattern + allow_special + ']+$';
1024 | }
1025 | return defaultPattern;
1026 | };
1027 |
1028 | /*
1029 | * To validate event with the pattern.
1030 | */
1031 | validate(event, pattern) {
1032 | // Managing the Pattern.
1033 | let defaultPattern = this.getDefault(event, pattern);
1034 | // Validate with special formed pattern.
1035 | let regex = new RegExp(defaultPattern);
1036 | // Validation with Code.
1037 | let key = String.fromCharCode(!event.charCode ? event.which : event.charCode);
1038 | return regex.test(key);
1039 | };
1040 | }
1041 | /**
1042 | * To Manage all kind of error response.
1043 | */
1044 | class validationResponse {
1045 | constructor() {
1046 | this.active_class = false;
1047 | }
1048 |
1049 | /*
1050 | * Initiating the Response handler.
1051 | */
1052 | init(errorList, option) {
1053 | this.errorMessage = option.message;
1054 | // Updating the class.
1055 | this.active_class = option.errorClass;
1056 | // let errorElements = option.errorElem;
1057 | // jsLogger.out('Errors', errorList);
1058 | this.input(errorList.input);
1059 | this.select(errorList.select);
1060 | this.textArea(errorList.textArea);
1061 |
1062 | };
1063 |
1064 | /*
1065 | * To handle the "input" element.
1066 | */
1067 | input(elem) {
1068 | // Initiate process for Input.
1069 | this.process(elem);
1070 | };
1071 |
1072 | /*
1073 | * To handle the "select" element.
1074 | */
1075 | select(elem) {
1076 | // Initiate process for Select.
1077 | this.process(elem);
1078 | };
1079 |
1080 | /*
1081 | * To return active class for validation response style.
1082 | */
1083 | getClass() {
1084 | return this.active_class;
1085 | };
1086 |
1087 | /*
1088 | * To handle the "textArea" element.
1089 | */
1090 | textArea(elem) {
1091 | // Initiate process for TextArea.
1092 | this.process(elem);
1093 | };
1094 |
1095 | /*
1096 | * To process all handlers.
1097 | */
1098 | process(elem) {
1099 | // Process with initial response.
1100 | let elementDefaultResponse = '';
1101 | // Get active class for error response element
1102 | let active_class = this.getClass();
1103 | for (let i in elem) {
1104 | // jsLogger.out('Element', document.getElementById(elem[i].id));
1105 | if (elem[i].el && true === elem[i].el.required) {
1106 | // Manage active element.
1107 | let activeElem = elem[i];
1108 | let errorType = elem[i].type;
1109 | // Fetch from Element's direct message.
1110 | elementDefaultResponse = this.template(activeElem, errorType);
1111 | let spanTag = document.getElementById(activeElem.id);
1112 | // jsLogger.out('Element Hit', errorType);
1113 | // Create new response Message SPAN.
1114 | if (typeof spanTag === 'undefined' || spanTag === 'undefined' || spanTag === null) {
1115 | // jsLogger.out('Element Found', false);
1116 | spanTag = document.createElement('span');
1117 | spanTag.setAttribute('id', activeElem.id);
1118 | spanTag.setAttribute('class', active_class);
1119 | spanTag.innerHTML = elementDefaultResponse;
1120 | } else {
1121 | // Re-use Existing response Message SPAN.
1122 | spanTag.innerHTML = elementDefaultResponse;
1123 | }
1124 | // Append HTML response to the Element.
1125 | activeElem.el.parentNode.insertBefore(spanTag, activeElem.el.nextSibling);
1126 | }
1127 | }
1128 | };
1129 |
1130 | /*
1131 | * Perform template creation and update.
1132 | */
1133 | template(activeElem, errorType) {
1134 | //jsLogger.out('error Type 0', errorType);
1135 | let errorIndex = '';
1136 | let activeError = '';
1137 | // Getting error response message from elemnet.
1138 | let elementDefaultResponse = activeElem.el.getAttribute('data-message');
1139 | if (typeof elementDefaultResponse === 'undefined' || elementDefaultResponse === '' || elementDefaultResponse === null) {
1140 | // Sanity check with error message object.
1141 | if (typeof this.errorMessage !== 'undefined' && typeof this.errorMessage[errorType] !== 'undefined') {
1142 | // Getting error type. [ex. Required, Min, Max...]
1143 | errorType = this.errorMessage[errorType];
1144 |
1145 | // activeElem.el.getAttribute('data-message');
1146 | if (errorType) {
1147 | //jsLogger.out('errorType', errorType);
1148 | activeError = errorType;
1149 | // If error type is Min or Max, then it will proceed responsive.
1150 | if (activeElem.type == 'min' || activeElem.type == 'max') {
1151 | if ('min' == activeElem.type) errorIndex = activeElem.el.min;
1152 | if ('max' == activeElem.type) errorIndex = activeElem.el.max;
1153 | activeError = activeError.replace('[INDEX]', errorIndex);
1154 | }
1155 | }
1156 | } else {
1157 | activeError = this.default(errorType);
1158 | }
1159 | elementDefaultResponse = activeError;
1160 | }
1161 | return elementDefaultResponse;
1162 | };
1163 |
1164 | /*
1165 | * Default error handling messages.
1166 | * If user not specify the messages,
1167 | * then it will be replaces.
1168 | */
1169 | default(errorType) {
1170 | let active_class = this.getClass();
1171 | let errorMessages = {
1172 | required: 'This field is required.',
1173 | min: 'This field length is too low.',
1174 | max: 'This field length is exceeds the limit.',
1175 | password: 'Password does not match.',
1176 | email: 'Email is not valid.',
1177 | file: 'This file is not allowed.'
1178 | };
1179 | if (typeof errorType !== 'string') return false;
1180 | if (typeof errorMessages[errorType] === 'undefined') return false;
1181 | return errorMessages[errorType];
1182 | };
1183 | }
--------------------------------------------------------------------------------
/src/js/formValidator.es6.min.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * JavaScript Validator Library v2.0
3 | * To perform effective validation and filter with form elements.
4 | *
5 | * Author : Shankar Thiyagaraajan
6 | * Email : shankarthiyagaraajan@gmail.com
7 | * GitHub : https://github.com/shankarThiyagaraajan
8 | *
9 | * Source
10 | * https://github.com/global-source/javascript_form_validator
11 | *
12 | * Site
13 | * https://global-source.github.io/javascript_form_validator/
14 | *
15 | * Copyright 2017
16 | *
17 | * Released under the MIT license
18 | * https://github.com/global-source/javascript_form_validator/blob/master/LICENSE
19 | *
20 | * Date: 2017-08-03
21 | */
22 |
23 | let __err_id_suffix_rand_hash='_new1_1_1xv_resp';let __status_log=!1;class jsValidator{constructor(){this.formData=!1;this.onlyFilter=!1;this.jsForm=!1;this.jsSettings=!1;this.jsFormError=!1;this.formErrorList={};this.forceFilter=!1;this.initialLoad=!0;this.option=!1;this.onChange=!1;this.validateResponse=!1}
24 | init(option){__status_log=option.log;this.option=option;jsLogger.table(option);this.onlyFilter=option.onlyFilter;this.onChange=option.onChange;if('undefined'===typeof option.errorClass)option.errorClass='js-error-cop';this.validateResponse=new validationResponse();this.jsSettings=new jsSettings().init(option);this.jsForm=new jsForm().init(option);this.jsFormError=new jsFormError().init();this.forceFilter=option.forceFilter;this.check();this.submitListener(this.jsForm.formCore,this);return this};submitListener(formID,obj){if(!1===this.onlyFilter||typeof(this.onlyFilter)==='undefined'){document.querySelector('#'+formID).addEventListener('submit',function(e){if(!1===obj.check()){e.preventDefault()}})}};update(){let option=this.option;this.onlyFilter=option.onlyFilter;this.jsSettings=new jsSettings().init(option);this.jsForm=new jsForm().init(option);this.jsFormError=new jsFormError().init()};check(){let status=!1;let jsFormObj=this.jsForm;let errorList=this.formErrorList;let option=[];errorList.input=this.elemLoop('input',jsFormObj.input);errorList.textArea=this.elemLoop('textArea',jsFormObj.textArea);errorList.select=this.elemLoop('select',jsFormObj.select);jsLogger.out('Error List',this.formErrorList);option.push({'errorElem':errorList});if(errorList.input.length===0){if(errorList.textArea.length===0){if(errorList.select.length===0){status=!0}}}
25 | if(!1==this.initialLoad)this.validateResponse.init(errorList,this.option);this.initialLoad=!1;helper.scrollToError(this.validateResponse);return status};elemLoop(index,formElem){let log=[];if(formElem===null||typeof formElem==='undefined')return!1;formElem=formElem.reverse();for(let i in formElem){if(formElem[i]){let activeElem=formElem[i];this.applyFilters(activeElem);if(!0==this.onChange){this.applyGlobalListener(activeElem)}
26 | if(!1===this.onlyFilter||typeof(this.onlyFilter)==='undefined'){log=new jsRuleSets().checkValidation(activeElem,log)}}}
27 | return log};applyFilters(activeElem){if(activeElem.type=='number')new jsFilter().number(activeElem);if(activeElem.type=='email')new jsFilter().email(activeElem);if(''!==activeElem.min||''!==activeElem.max||activeElem.getAttribute('data-maxlength')||-1!==activeElem.maxLength)new jsFilter().limit(activeElem);if(activeElem.type=='file')new jsFilter().file(activeElem);if(activeElem.getAttribute('data-allow'))new jsFilter().string(activeElem);if(activeElem.getAttribute('pattern'))new jsFilter().pattern(activeElem)};applyGlobalListener(element){element.addEventListener('change',this.quickValidation,!1)};quickValidation(event){let log=[];let target=event.target;log=new jsRuleSets().checkValidation(target,log);new validationResponse().process(log)};validate(){return this.check()}}
28 | class jsFilter{checkStatus(elem){let status;status=!0;if(!1===new jsValidator().forceFilter){status=!1;if(!0===elem.required){status=!0}}
29 | return status};number(element){let status=this.checkStatus(element);if(!0===status)element.addEventListener('keypress',this.isNumberKey,!1)};string(element){let type=element.getAttribute('data-allow');let current=this;let status=this.checkStatus(element);switch(type){case 'onlyAlpha':if(!0===status)element.addEventListener('keypress',current.isAlpha,!1);break;case 'string':if(!0===status)element.addEventListener('keypress',current.isAlphaNumeric,!1);break;default:if(!0===status)element.addEventListener('keypress',current.isPatternValid,!1);break}};pattern(element){let current=this;let status=this.checkStatus(element);if(!0===status)element.addEventListener('keypress',current.isPatternValid,!1)};email(element){let status=this.checkStatus(element);if(!0===status)element.addEventListener('keypress',jsRuleSets.email,!1)};file(element){let status=this.checkStatus(element);if(!0===status)element.addEventListener('change',jsRuleSets.file,!1)};limit(element){let current=this;let status=this.checkStatus(element);if(!0===status)element.addEventListener('change',current.isInLimit,!1)};isInLimit(event){let value=event.target.value;if(!0===helper.isWindowAction(event))return!0;let target=event.target;let final_value=value;let min=event.target.min;let max=event.target.max;let max_length=event.target.getAttribute('data-maxlength')?event.target.getAttribute('data-maxlength'):0;max_length=parseInt(max_length);let num=value;if(0===max_length){if(!min)min=1;if(!max)max=100;let regex=new RegExp('^[0-9]+$');let key=String.fromCharCode(!event.charCode?event.which:event.charCode);if(!1===regex.test(key)||parseInt(value)>max||parseInt(value)max)final_value=max;if(parseInt(num)max_length)&&031&&(charCode<48||charCode>57)){event.preventDefault();return!1}
34 | return!0}}
35 | class jsSettings{constructor(){this.errorColor=!1;this.errorTemplate=!1}
36 | init(option){this.errorColor=option.errorColor;this.errorTemplate=option.errorTemplate;return this};log(){jsLogger.out(this.errorColor);jsLogger.out(this.errorTemplate)}}
37 | class jsForm{constructor(){this.form=!1;this.formCore=!1;this.input=!1;this.select=!1;this.textArea=!1;this.label=!1;this.forceFilter=!1}
38 | init(option){jsLogger.out('Form',option.form);this.options=option;this.forceFilter=option.forceFilter;this.registerForm(option.form);this.parseForm(this.form);this.required();return this};registerForm(form){if(typeof form==='undefined')jsLogger.out('Form Identification','Form Identification is Missing !');if(null===form)return!1;this.form=document.getElementById(form);if(null===this.form)jsLogger.out('Status 503','Failed to Proceed !');this.formCore=form};parseForm(form){if(form===null)return!1;this.input=form.getElementsByTagName('input');this.select=form.getElementsByTagName('select');this.textArea=form.getElementsByTagName('textarea');this.label=form.getElementsByTagName('label')};required(){let forceFilter=this.forceFilter;let jsField_obj=new jsField();this.input=jsField_obj.required(this.input,forceFilter);this.select=jsField_obj.required(this.select,forceFilter);this.textArea=jsField_obj.required(this.textArea,forceFilter)};log(){jsLogger.out('Form',this.form);jsLogger.out('input',this.input);jsLogger.out('select',this.select);jsLogger.out('textarea',this.textArea);jsLogger.out('labels',this.label)}}
39 | class jsField{required(field,forceFilter){let requiredFieldsList=[];for(let i=0;imax&&value.length!=0)status=!1;return status};email(elem){if(!1===elem.required)return!0;let status=!1;let email=elem.value;if(typeof email==='undefined')return!1;email=email.toString();if(/^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$/.test(email)){status=!0}
49 | if(!email)status=!1;return status};file(elem){let list_to_allow=elem.target.getAttribute('data-extensions');let target=elem.target;let list_to_allow_array;let file_response;if(''===list_to_allow)return!0;if(-1===list_to_allow.indexOf(',')){list_to_allow_array=[list_to_allow]}else{list_to_allow_array=list_to_allow.split(',')}
50 | let fileName=target.value;fileName=fileName.toLowerCase();file_response=(new RegExp('('+list_to_allow_array.join('|').replace(/\./g,'\\.')+')$')).test(fileName);if(!1===file_response){alert('Allowed file types are "'+list_to_allow+'" !');elem.target.value='';return!1}
51 | return!0};phone(elem,pattern){if(!1===elem.required)return!0;let status=!0;if(elem.value==='')status=!1;return status};compare(elem1){let status=!1;if(!1===elem1.required)status=!0;let elem2_id=elem1.getAttribute('data-check');let elem2_value='';let elem2=!1;if(typeof elem2_id=='undefined'||elem2_id==null)status=!1;if(elem2_id===null)elem2_id=elem1.getAttribute('data-parent');if(elem2_id===null){status=!1}else{elem2_id=elem2_id.toString();elem2=document.getElementById(elem2_id);if(elem1.value===elem2.value)status=!0;elem2_value=elem2.value}
52 | if(!0===status||''===elem2_value){document.getElementById(elem1.name+__err_id_suffix_rand_hash).remove();if(!1!==elem2)document.getElementById(elem2.name+__err_id_suffix_rand_hash).remove()}
53 | return status}}
54 | class jsFormError{constructor(){this.errorHit=!1;this.errorCss=!1;this.successCss=!1}
55 | init(){this.errorHit=!1;this.errorCss='border-color: red;border-radius: 5px;color: red;';this.successCss='border-color: green;border-radius: 5px;color: green;'};log(){};style(css){this.errorCss=css.error;this.successCss=css.success}}
56 | let jsLogger={status:function(){return __status_log},out:function(heading,message){if(!0!==this.status())return!1;console.log('======'+heading+'======');console.log(message);console.log('------------------------')},bulk:function(data){if(!0!==this.status())return!1;console.log(data)},table:function(data){if(!0!==this.status())return!1;console.table(data)}};let helper={isWindowAction:function(event){let theEvent=event||window.event;let key=theEvent.shiftKey||theEvent.which;if(key===9||key===0||key===8||key===32||key===13||key===8||(key>=35&&key<=40)){return!0}
57 | key=String.fromCharCode(key);if(key.length===0)return!0;return!1},scrollToError:function(validateResponse){let dummy_id='__header_error_target_temp';let active_class=validateResponse.getClass();if(!1===active_class){jsLogger.out('Active Class Error','ACTIVE CLASS NOT DEFINED, GET :'+active_class);return!1}
58 | if(0===document.getElementsByClassName(active_class).length)return!1;let active_id=document.getElementsByClassName(active_class)[0].id;document.getElementsByClassName(active_class)[0].setAttribute('id',dummy_id);let id=document.getElementsByClassName(active_class)[0].id;let elem_name=active_id.replace(__err_id_suffix_rand_hash,'');let top=document.getElementsByName(elem_name)[0].offsetTop;id='#'+id;window.scroll(0,parseInt(top)-15);document.getElementsByClassName(active_class)[0].setAttribute('id',active_id);this.removeHash(id)},scrollToItem:function(item){let hash=item;if(-1===hash.indexOf('#'))hash='#'+hash;window.location.href=hash;this.removeHash(hash)},removeHash:function(hash){let path=window.location.href;path=path.replace(hash,'');window.history.pushState('','Title',path)}};class pattern{getDefault(event,originalPattern){if(typeof originalPattern=='undefined')originalPattern='';let allow_special=event.target.getAttribute('data-allowSpecial');let pattern=event.target.pattern;console.log(pattern.length);let defaultPattern;if(!allow_special&&allow_special===null)allow_special='';allow_special=allow_special.toString();if(pattern!==''&&pattern.length>0&&pattern!==null){defaultPattern=pattern}else{defaultPattern='^['+originalPattern+allow_special+']+$'}
59 | return defaultPattern};validate(event,pattern){let defaultPattern=this.getDefault(event,pattern);let regex=new RegExp(defaultPattern);let key=String.fromCharCode(!event.charCode?event.which:event.charCode);return regex.test(key)}}
60 | class validationResponse{constructor(){this.active_class=!1}
61 | init(errorList,option){this.errorMessage=option.message;this.active_class=option.errorClass;this.input(errorList.input);this.select(errorList.select);this.textArea(errorList.textArea)};input(elem){this.process(elem)};select(elem){this.process(elem)};getClass(){return this.active_class};textArea(elem){this.process(elem)};process(elem){let elementDefaultResponse='';let active_class=this.getClass();for(let i in elem){if(elem[i].el&&!0===elem[i].el.required){let activeElem=elem[i];let errorType=elem[i].type;elementDefaultResponse=this.template(activeElem,errorType);let spanTag=document.getElementById(activeElem.id);if(typeof spanTag==='undefined'||spanTag==='undefined'||spanTag===null){spanTag=document.createElement('span');spanTag.setAttribute('id',activeElem.id);spanTag.setAttribute('class',active_class);spanTag.innerHTML=elementDefaultResponse}else{spanTag.innerHTML=elementDefaultResponse}
62 | activeElem.el.parentNode.insertBefore(spanTag,activeElem.el.nextSibling)}}};template(activeElem,errorType){let errorIndex='';let activeError='';let elementDefaultResponse=activeElem.el.getAttribute('data-message');if(typeof elementDefaultResponse==='undefined'||elementDefaultResponse===''||elementDefaultResponse===null){if(typeof this.errorMessage!=='undefined'&&typeof this.errorMessage[errorType]!=='undefined'){errorType=this.errorMessage[errorType];if(errorType){activeError=errorType;if(activeElem.type=='min'||activeElem.type=='max'){if('min'==activeElem.type)errorIndex=activeElem.el.min;if('max'==activeElem.type)errorIndex=activeElem.el.max;activeError=activeError.replace('[INDEX]',errorIndex)}}}else{activeError=this.default(errorType)}
63 | elementDefaultResponse=activeError}
64 | return elementDefaultResponse};default(errorType){let active_class=this.getClass();let errorMessages={required:'This field is required.',min:'This field length is too low.',max:'This field length is exceeds the limit.',password:'Password does not match.',email:'Email is not valid.',file:'This file is not allowed.'};if(typeof errorType!=='string')return!1;if(typeof errorMessages[errorType]==='undefined')return!1;return errorMessages[errorType]}}
--------------------------------------------------------------------------------
/src/js/formValidator.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * JavaScript Validator Library v2.0
3 | * To perform effective validation and filter with form elements.
4 | *
5 | * Author : Shankar Thiyagaraajan
6 | * Email : shankarthiyagaraajan@gmail.com
7 | * GitHub : https://github.com/shankarThiyagaraajan
8 | *
9 | * Source
10 | * https://github.com/global-source/javascript_form_validator
11 | *
12 | * Site
13 | * https://global-source.github.io/javascript_form_validator/
14 | *
15 | * Copyright 2017
16 | *
17 | * Released under the MIT license
18 | * https://github.com/global-source/javascript_form_validator/blob/master/LICENSE
19 | *
20 | * Date: 2017-08-03
21 | */
22 |
23 | /*
24 | * For Managing overall Validation flow.
25 | */
26 | var __err_id_suffix_rand_hash = '_new1_1_1xv_resp';
27 | var __status_log = false;
28 | /**
29 | * Core Js Validator.
30 | */
31 | function jsValidator() {
32 | // Holding form element data.
33 | this.formData = false;
34 | // Switch complete validation and input filter.
35 | this.onlyFilter = false;
36 | // JS form.
37 | this.jsForm = false;
38 | // JS setting.
39 | this.jsSettings = false;
40 | // JS form error.
41 | this.jsFormError = false;
42 | // Overall error list.
43 | this.formErrorList = {};
44 | // To Filter non-required fields.
45 | this.forceFilter = false;
46 | // To Filter the First load.
47 | this.initialLoad = true;
48 | // Global options.
49 | this.option = false;
50 | // To apply global validator.
51 | this.onChange = false;
52 | this.validateResponse = false;
53 | /*
54 | * Initiating the Validator.
55 | */
56 | this.init = function (option) {
57 | // Update overall log status.
58 | __status_log = option.log;
59 | // To Update global options.
60 | this.option = option;
61 | jsLogger.table(option);
62 | // Updating the filter flag to global.
63 | this.onlyFilter = option.onlyFilter;
64 | // To Enable/Disable global validator.
65 | this.onChange = option.onChange;
66 | // Update default response "class".
67 | if ('undefined' === typeof option.errorClass) option.errorClass = 'js-error-cop';
68 | this.validateResponse = new validationResponse();
69 | // Update "jsSettings" to global object.
70 | this.jsSettings = new jsSettings().init(option);
71 | // Update "jsForm" to global object.
72 | this.jsForm = new jsForm().init(option);
73 | // Initiate form error setup.
74 | this.jsFormError = new jsFormError().init();
75 | // Update Force Field status.
76 | this.forceFilter = option.forceFilter;
77 | // To check the form elements.
78 | this.check();
79 | // To register the listener.
80 | this.submitListener(this.jsForm.formCore, this);
81 | // Send back "this".
82 | return this;
83 | };
84 | /*
85 | * To make listen on submit action of the form.
86 | */
87 | this.submitListener = function (formID, obj) {
88 | // To off submit listener, if only filter needed.
89 | if (false === this.onlyFilter || typeof (this.onlyFilter) === 'undefined') {
90 | // Initiate listener for form submission.
91 | document.querySelector('#' + formID).addEventListener('submit', function (e) {
92 | // To start form validations.
93 | // Check validation status.
94 | if (false === obj.check()) {
95 | //stop form from submitting, if validation fails
96 | e.preventDefault();
97 | }
98 | });
99 | }
100 | };
101 | /*
102 | * To Refresh the DOM and enable Dynamic-Elements to Access.
103 | */
104 | this.update = function () {
105 | var option = this.option;
106 | // Updating the filter flag to global.
107 | this.onlyFilter = option.onlyFilter;
108 | // Update "jsSettings" to global object.
109 | this.jsSettings = new jsSettings().init(option);
110 | // Update "jsForm" to global object.
111 | this.jsForm = new jsForm().init(option);
112 | // Initiate form error setup.
113 | this.jsFormError = new jsFormError().init();
114 | };
115 | /*
116 | * To checking all elements from registered form.
117 | */
118 | this.check = function () {
119 | var status = false;
120 | // Loading JS Form.
121 | var jsFormObj = this.jsForm;
122 | // Loading JS error list.
123 | var errorList = this.formErrorList;
124 | var option = [];
125 | // Looping the "input" elements for validation and filter implementation.
126 | errorList.input = this.elemLoop('input', jsFormObj.input);
127 | // Looping the "textArea" elements fro validation filter implementation.
128 | errorList.textArea = this.elemLoop('textArea', jsFormObj.textArea);
129 | // Looping the "select" elements fro validation filter implementation.
130 | errorList.select = this.elemLoop('select', jsFormObj.select);
131 | jsLogger.out('Error List', this.formErrorList);
132 | option.push({
133 | 'errorElem': errorList
134 | });
135 | // To Update global Validation Status.
136 | // If, Input elements have no errors.
137 | if (errorList.input.length === 0) {
138 | // If, Text Area elements have no errors.
139 | if (errorList.textArea.length === 0) {
140 | // If, Select elements have no errors.
141 | if (errorList.select.length === 0) {
142 | // If validation pass, then update "status" object.
143 | status = true;
144 | }
145 | }
146 | }
147 | if (false == this.initialLoad) this.validateResponse.init(errorList, this.option);
148 | this.initialLoad = false;
149 | helper.scrollToError(this.validateResponse);
150 | return status;
151 | };
152 | /*
153 | * To looping all elements for actions.
154 | */
155 | this.elemLoop = function (index, formElem) {
156 | // Initiate empty array for keep list of errors.
157 | var log = [];
158 | // Sanity check with "formElem".
159 | if (formElem === null || typeof formElem === 'undefined') return false;
160 | formElem = formElem.reverse();
161 | // Looping elements.
162 | for (var i in formElem) {
163 | if (formElem[i]) {
164 | // Switch to static variable.
165 | var activeElem = formElem[i];
166 | // Apply filter to element.
167 | this.applyFilters(activeElem);
168 | // Register the DOM with live onChange validations.
169 | if (true == this.onChange) {
170 | this.applyGlobalListener(activeElem);
171 | }
172 | //jsLogger.out('Only Filter', this.onlyFilter);
173 | // If not only filter, then start validations.
174 | if (false === this.onlyFilter || typeof (this.onlyFilter) === 'undefined') {
175 | // Initiate validations and update to log.
176 | log = new jsRuleSets().checkValidation(activeElem, log);
177 | }
178 | }
179 | }
180 | // jsLogger.out('Log', log);
181 | return log;
182 | };
183 | /*
184 | * To apply filter to all relevant elements by it's attributes.
185 | */
186 | this.applyFilters = function (activeElem) {
187 | // Apply filter for Number elements.
188 | if (activeElem.type == 'number') new jsFilter().number(activeElem);
189 | // Apply filter for Email elements.
190 | if (activeElem.type == 'email') new jsFilter().email(activeElem);
191 | // Apply filter for Numeric elements.
192 | if ('' !== activeElem.min || '' !== activeElem.max || activeElem.getAttribute('data-maxlength') || -1 !== activeElem.maxLength) new jsFilter().limit(activeElem);
193 | // Apply filter File elements.
194 | if (activeElem.type == 'file') new jsFilter().file(activeElem);
195 | // Apply filter with string, alphaNumeric and pregMatch.
196 | if (activeElem.getAttribute('data-allow')) new jsFilter().string(activeElem);
197 | // Apply filter with pattern.
198 | if (activeElem.getAttribute('pattern')) new jsFilter().pattern(activeElem);
199 | };
200 | /*
201 | * To make it active to listen changes of those error fields.
202 | */
203 | this.applyGlobalListener = function (element) {
204 | element.addEventListener('change', this.quickValidation, false);
205 | };
206 | /*
207 | * To perform quick validation to respond those fields.
208 | */
209 | this.quickValidation = function (event) {
210 | // jsLogger.out('Quick', event);
211 | var log = [];
212 | var target = event.target;
213 | // To check the validation of an element.
214 | log = new jsRuleSets().checkValidation(target, log);
215 | // jsLogger.out('Quick Out', log);
216 | new validationResponse().process(log);
217 | };
218 | /*
219 | * Single step instance validator for Ajax form submissions.
220 | */
221 | this.validate = function () {
222 | // Initiate form Check.
223 | return this.check();
224 | };
225 | }
226 | /**
227 | * Common Filter instances.
228 | */
229 | function jsFilter() {
230 | this.checkStatus = function (elem) {
231 | var status;
232 | status = true;
233 | if (false === new jsValidator().forceFilter) {
234 | status = false;
235 | if (true === elem.required) {
236 | status = true;
237 | }
238 | }
239 | return status;
240 | };
241 | // Number elements filter listener.
242 | this.number = function (element) {
243 | var status = this.checkStatus(element);
244 | if (true === status) element.addEventListener('keypress', this.isNumberKey, false);
245 | };
246 | /*
247 | * String elements filter listener.
248 | */
249 | this.string = function (element) {
250 | // Getting "data" attribute for actions.
251 | var type = element.getAttribute('data-allow');
252 | var current = this;
253 | var status = this.checkStatus(element);
254 |
255 | // Switching actions.
256 | switch (type) {
257 | // Allow only alphabets [a-zA-Z] not [0-9] and special characters.
258 | case 'onlyAlpha':
259 | if (true === status) element.addEventListener('keypress', current.isAlpha, false);
260 | break;
261 | // Allow only alpha Numeric [a-zA-Z0-9] not special characters.
262 | case 'string':
263 | if (true === status) element.addEventListener('keypress', current.isAlphaNumeric, false);
264 | break;
265 | // Allow based on the pattern given.
266 | default:
267 | if (true === status) element.addEventListener('keypress', current.isPatternValid, false);
268 | break;
269 | }
270 | };
271 | /*
272 | * Pattern based filter and listener.
273 | */
274 | this.pattern = function (element) {
275 | var current = this;
276 | var status = this.checkStatus(element);
277 | if (true === status) element.addEventListener('keypress', current.isPatternValid, false);
278 | };
279 | /*
280 | * Email elements filter listener.
281 | */
282 | this.email = function (element) {
283 | var status = this.checkStatus(element);
284 | if (true === status) element.addEventListener('keypress', jsRuleSets.email, false);
285 | };
286 | this.file = function (element) {
287 | var status = this.checkStatus(element);
288 | if (true === status) element.addEventListener('change', jsRuleSets.file, false);
289 | };
290 | /*
291 | * Numeric with Limited elements filter listener.
292 | */
293 | this.limit = function (element) {
294 | var status = this.checkStatus(element);
295 | if (true === status) element.addEventListener('change', this.isInLimit, false);
296 | };
297 | /*
298 | * Restrict element with it's limit.
299 | */
300 | this.isInLimit = function (event) {
301 | // Load the element value.
302 | var value = event.target.value;
303 |
304 | // To check is this action is from "windows" action or not.
305 | if (true === helper.isWindowAction(event)) return true;
306 |
307 | // Getting target element.
308 | var target = event.target;
309 |
310 | // Final value to load back.
311 | var final_value = value;
312 |
313 | // Getting object from element.
314 | var min = event.target.min;
315 | var max = event.target.max;
316 |
317 | // Get max-length attribute from element.
318 | var max_length = event.target.getAttribute('data-maxlength') ? event.target.getAttribute('data-maxlength') : 0;
319 | max_length = parseInt(max_length);
320 | var num = value;
321 |
322 | // if "max_length" is "0", then its don't have limit variables.
323 | if (0 === max_length) {
324 |
325 | // Default values for Min and Max.
326 | if (!min) min = 1;
327 | if (!max) max = 100;
328 |
329 | // Forming pattern for Restriction.
330 | var regex = new RegExp('^[0-9]+$');
331 |
332 | // Validation with Code.
333 | var key = String.fromCharCode(!event.charCode ? event.which : event.charCode);
334 |
335 | // Return status of the Action.
336 | if (false === regex.test(key) || parseInt(value) > max || parseInt(value) < min) {
337 | event.preventDefault();
338 | }
339 |
340 | // Parse to INT.
341 | num = parseInt(num, 10);
342 |
343 | // // converts value to a Number.
344 | if (isNaN(num)) {
345 | target.value = "";
346 | return;
347 | }
348 |
349 | // Check value is greater than "max", then replace "max".
350 | if (parseInt(num) > max) final_value = max;
351 |
352 | // Check value is greater than "min", then replace "min".
353 | if (parseInt(num) < min) final_value = min;
354 |
355 | } else {
356 | //TODO: Min length later.
357 | // Validate the length of the string.
358 | if ((num.length > max_length) && 0 < max_length) {
359 | // If length is more, then cutoff the remaining letters.
360 | final_value = num.substr(0, max_length);
361 | }
362 | }
363 |
364 | // Revert value back to an element.
365 | this.value = final_value;
366 | };
367 | /*
368 | * Only allow alpha([a-zA-Z]).
369 | */
370 | this.isAlpha = function (event) {
371 | // To check is this action is from "windows" action or not.
372 | if (true === helper.isWindowAction(event)) return true;
373 | // Managing the Pattern.
374 | var status = new pattern().validate(event, 'a-zA-Z');
375 | // Return status of the Action.
376 | if (false === status) event.preventDefault();
377 | };
378 | /*
379 | * Only allow alpha([a-zA-Z0-9]).
380 | */
381 | this.isAlphaNumeric = function (event) {
382 | // To check is this action is from "windows" action or not.
383 | if (true === helper.isWindowAction(event)) return true;
384 | // Managing the Pattern.
385 | var status = new pattern().validate(event, 'a-zA-Z0-9');
386 | // Return status of the Action.
387 | if (false === status) event.preventDefault();
388 | };
389 | /*
390 | * To check password is valid or not.
391 | */
392 | this.isValidPassword = function (event) {
393 | // Prevent using "space".
394 | var charCode = (event.which) ? event.which : event.keyCode;
395 | // If event is "space" then prevent to enter.
396 | if (charCode === 32) {
397 | event.preventDefault();
398 | return false;
399 | } // To check is this action is from "windows" action or not.
400 |
401 | if (true === helper.isWindowAction(event)) return true;
402 | // Managing the Pattern.
403 | var status = new pattern().validate(event, 'a-zA-Z0-9');
404 | // Return status of the Action.
405 | if (false === status) event.preventDefault();
406 | };
407 | /*
408 | * Only allow by pattern(ex. ^[a-zA-Z0-3@#$!_.]+$).
409 | */
410 | this.isPatternValid = function (event) {
411 | // To check is this action is from "windows" action or not.
412 | if (true === helper.isWindowAction(event)) return true;
413 | // Managing the Pattern.
414 | var status = new pattern().validate(event, 'a-zA-Z0-4');
415 | // Return status of the Action.
416 | if (false === status) event.preventDefault();
417 | };
418 | /*
419 | * Check is numeric or not.
420 | */
421 | this.isNumberKey = function (event) {
422 | // To check is this action is from "windows" action or not.
423 | if (true === helper.isWindowAction(event)) return true;
424 | // Validation with Code.
425 | var charCode = (event.which) ? event.which : event.keyCode;
426 | if (charCode === 46 || charCode > 31 && (charCode < 48 || charCode > 57)) {
427 | event.preventDefault();
428 | return false;
429 | } // Return status of the Action.
430 |
431 | return true;
432 | };
433 | }
434 |
435 | /**
436 | * To Update overall JsValidator Settings.
437 | */
438 | function jsSettings() {
439 | // Common error message color for form validation.
440 | this.errorColor = false;
441 | // Set common template for error message
442 | this.errorTemplate = false;
443 | /*
444 | * To Initiate the Configurations.
445 | */
446 | this.init = function (option) {
447 | // To update error message color to global object.
448 | this.errorColor = option.errorColor;
449 | // To update error template to handle error message.
450 | this.errorTemplate = option.errorTemplate;
451 | // Return "this" object.
452 | return this;
453 | };
454 | /*
455 | * General Log.
456 | */
457 | this.log = function () {
458 | jsLogger.out(this.errorColor);
459 | jsLogger.out(this.errorTemplate);
460 | };
461 | }
462 | /**
463 | * To Perform all Form based Operations.
464 | */
465 | function jsForm() {
466 | // Form element.
467 | this.form = false;
468 | // Form ID.
469 | this.formCore = false;
470 | // Form element's inputs.
471 | this.input = false;
472 | // Form element's selects.
473 | this.select = false;
474 | // Form element's textAreas.
475 | this.textArea = false;
476 | // Form element's labels.
477 | this.label = false;
478 | // Perform Force Filter on Elements.
479 | this.forceFilter = false;
480 | /*
481 | * To Initiating the "jsForm".
482 | */
483 | this.init = function (option) {
484 | jsLogger.out('Form', option.form);
485 | // Update Global Option.
486 | this.options = option;
487 | // Enable/Disable Force Filter.
488 | this.forceFilter = option.forceFilter;
489 | // To Register Form.
490 | this.registerForm(option.form);
491 | // To Parsing the Form.
492 | this.parseForm(this.form);
493 | // To Filter Required Elements.
494 | this.required();
495 | return this;
496 | };
497 | /*
498 | * To Register Active Form to Global Object.
499 | */
500 | this.registerForm = function (form) {
501 | // validate and Update Log.
502 | if (typeof form === 'undefined') jsLogger.out('Form Identification', 'Form Identification is Missing !');
503 | // Form should not be an ID.
504 | if (null === form) return false;
505 | // Fetch Form element from Document.
506 | this.form = document.getElementById(form);
507 | if (null === this.form) jsLogger.out('Status 503', 'Failed to Proceed !');
508 | // Update Direct Form ID.
509 | this.formCore = form;
510 | };
511 | /*
512 | * To Parse all Relative Form components.
513 | */
514 | this.parseForm = function (form) {
515 | if (form === null) return false;
516 | // "Input" elements like "text, date, time..."
517 | this.input = form.getElementsByTagName('input');
518 | // "Select" element.
519 | this.select = form.getElementsByTagName('select');
520 | // "TextArea" element.
521 | this.textArea = form.getElementsByTagName('textarea');
522 | // "Label" element.
523 | this.label = form.getElementsByTagName('label');
524 | };
525 | /*
526 | * To set fields are required.
527 | */
528 | this.required = function () {
529 | // var jsField = new jsField().init(this.options);
530 | var forceFilter = this.forceFilter;
531 | var jsField_obj = new jsField();
532 | // Filter all required "input" elements.
533 | this.input = jsField_obj.required(this.input, forceFilter);
534 | // Filter all required "select" elements.
535 | this.select = jsField_obj.required(this.select, forceFilter);
536 | // Filter all required "textArea" elements.
537 | this.textArea = jsField_obj.required(this.textArea, forceFilter);
538 | };
539 | /*
540 | * General Log.
541 | */
542 | this.log = function () {
543 | jsLogger.out('Form', this.form);
544 | jsLogger.out('input', this.input);
545 | jsLogger.out('select', this.select);
546 | jsLogger.out('textarea', this.textArea);
547 | jsLogger.out('labels', this.label);
548 | };
549 | }
550 | /**
551 | * Perform Operations in Field level.
552 | */
553 | function jsField() {
554 | /*
555 | * Return all required elements list.
556 | */
557 | this.required = function (field, forceFilter) {
558 | var requiredFieldsList = [];
559 | // Looping fields to filter.
560 | for (var i = 0; i < field.length; i++) {
561 | // Check and push elements.
562 | if (field[i].required === true || true === forceFilter) {
563 | // Pushing to required elements list.
564 | requiredFieldsList.push(field[i]);
565 | }
566 | } // Return list of required elements.
567 |
568 | return requiredFieldsList;
569 | };
570 | }
571 | /**
572 | * List of Validation Rules.
573 | */
574 | function jsRuleSets() {
575 | /*
576 | * To start validation process.
577 | */
578 | this.checkValidation = function (activeElem, log) {
579 | //jsLogger.out('Active Elem', activeElem);
580 | var validElem = true;
581 | var jsRuleSets_obj = new jsRuleSets();
582 | // To Generally checks, the field is empty or not.
583 | if (!jsRuleSets_obj.isSet(activeElem)) {
584 | log.push({
585 | 'el': activeElem,
586 | 'type': 'required',
587 | 'id': activeElem.name + __err_id_suffix_rand_hash
588 | });
589 | validElem = false;
590 | }
591 |
592 | // To Check the Value is less than minimum or not.
593 | if (activeElem.min) {
594 | if (jsRuleSets_obj.isSet(activeElem)) {
595 | if (!jsRuleSets_obj.min(activeElem)) {
596 | log.push({
597 | 'el': activeElem,
598 | 'type': 'min',
599 | 'id': activeElem.name + __err_id_suffix_rand_hash
600 | });
601 | validElem = false;
602 | }
603 | }
604 | }
605 |
606 | // To Check the Value is grater than max or not.
607 | if (activeElem.max) {
608 | if (jsRuleSets_obj.isSet(activeElem)) {
609 | if (!jsRuleSets_obj.max(activeElem)) {
610 | log.push({
611 | 'el': activeElem,
612 | 'type': 'max',
613 | 'id': activeElem.name + __err_id_suffix_rand_hash
614 | });
615 | validElem = false;
616 | }
617 | }
618 | }
619 |
620 | // To Check the Entered E-mail is Valid or Not.
621 | if (activeElem.type == 'email') {
622 | if (jsRuleSets_obj.isSet(activeElem)) {
623 | if (!jsRuleSets_obj.email(activeElem)) {
624 | log.push({
625 | 'el': activeElem,
626 | 'type': 'email',
627 | 'id': activeElem.name + __err_id_suffix_rand_hash
628 | });
629 | validElem = false;
630 | }
631 | }
632 | }
633 |
634 | // To Compare the Password is Same or Not with Re-Password.
635 | // TODO: Implement Simplified Comparison.
636 | if (activeElem.type == 'password') {
637 | if (jsRuleSets_obj.isSet(activeElem)) {
638 | if (!jsRuleSets_obj.compare(activeElem)) {
639 | log.push({
640 | 'el': activeElem,
641 | 'type': 'password',
642 | 'id': activeElem.name + __err_id_suffix_rand_hash
643 | });
644 | validElem = false;
645 | }
646 | }
647 | } // If valid, then reset validation message.
648 |
649 | if (true === validElem) {
650 | //jsLogger.out('Valid Elem', activeElem);
651 | if (activeElem.name !== '') {
652 | var elem = document.getElementById(activeElem.name + __err_id_suffix_rand_hash);
653 | if (typeof (elem) !== 'undefined' && elem !== null) {
654 | // Remove element to avoid un-necessary buffer.
655 | elem.remove();
656 | }
657 | }
658 | }
659 |
660 | // If error occurred, then locate that error
661 | if (false !== validElem) {
662 | //
663 | }
664 |
665 | // Return overall log report of validation.
666 | return log;
667 | }
668 | /*
669 | * To Check, whether the element have value or not.
670 | */
671 | this.isSet = function (elem) {
672 | // If field is not required, then return "true".
673 | if (false === elem.required) return true;
674 | var status = true;
675 | var value = elem.value;
676 | //TODO: Implement suitable solution for this.
677 | if (value.length === 0 || value === '' || value === ' ' || value === '[]') status = false;
678 | return status;
679 | };
680 | /*
681 | * To Check Element with Min Condition.
682 | */
683 | this.min = function (elem) {
684 | // If field is not required, then return "true".
685 | if (false === elem.required) return true;
686 | var status = true;
687 | var value = elem.value;
688 | var min = elem.min;
689 | //TODO: Implement suitable solution for this.
690 | if (value.length < min && value.length != 0) status = false;
691 | return status;
692 | };
693 | /*
694 | * To Check Element with Max Condition.
695 | */
696 | this.max = function (elem) {
697 | // If field is not required, then return "true".
698 | if (false === elem.required) return true;
699 | var status = true;
700 | var value = elem.value;
701 | var max = elem.max;
702 | //TODO: Implement suitable solution for this.
703 | if (value.length > max && value.length != 0) status = false;
704 | return status;
705 | };
706 | /*
707 | * To Check Element Email is Valid or Not.
708 | */
709 | this.email = function (elem) {
710 | // If field is not required, then return "true".
711 | if (false === elem.required) return true;
712 | var status = false;
713 | var email = elem.value;
714 | if (typeof email === 'undefined') return false;
715 | // To Validate Email.
716 | // Convert to Native String Format.
717 | email = email.toString();
718 | // To Check it as String or Not.
719 | if (/^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$/.test(email)) {
720 | // Valid Email.
721 | status = true;
722 | }
723 | if (!email) status = false;
724 | return status;
725 | };
726 | /*
727 | * To Check Element's file is valid or not.
728 | */
729 | this.file = function (elem) {
730 | var list_to_allow = elem.target.getAttribute('data-extensions');
731 | var target = elem.target;
732 | var list_to_allow_array;
733 | var file_response;
734 | if ('' === list_to_allow) return true;
735 | // Slit into array of extensions.
736 | if (-1 === list_to_allow.indexOf(',')) {
737 | list_to_allow_array = [list_to_allow];
738 | } else {
739 | list_to_allow_array = list_to_allow.split(',');
740 | }
741 | // Get file name.
742 | var fileName = target.value;
743 | // Convert to lower case for native validation.
744 | fileName = fileName.toLowerCase();
745 | file_response = (new RegExp('(' + list_to_allow_array.join('|').replace(/\./g, '\\.') + ')$')).test(fileName);
746 | if (false === file_response) {
747 | alert('Allowed file types are "' + list_to_allow + '" !');
748 | // Reset file type.
749 | elem.target.value = '';
750 | return false;
751 | }
752 | return true;
753 | };
754 | /*
755 | * To Check Element Phone Value is Valid or Not.
756 | */
757 | this.phone = function (elem, pattern) {
758 | // If field is not required, then return "true".
759 | if (false === elem.required) return true;
760 | var status = true;
761 | if (elem.value === '') status = false;
762 | return status;
763 | };
764 | /*
765 | * To Compare two Elements Values.
766 | */
767 | this.compare = function (elem1) {
768 | var status = false;
769 | // If field is not required, then return "true".
770 | if (false === elem1.required) status = true;
771 | // 2'nd element's ID.
772 | var elem2_id = elem1.getAttribute('data-check');
773 | // Default 2'nd element comparision.
774 | var elem2_value = '';
775 | // Secondary element.
776 | var elem2 = false;
777 | // Verify, 2'nd element is defined or not.
778 | if (typeof elem2_id == 'undefined' || elem2_id == null) status = false;
779 | // If null, then take it's a primary element.
780 | if (elem2_id === null) elem2_id = elem1.getAttribute('data-parent');
781 | // If secondary element not defined, then "status" will FALSE.
782 | if (elem2_id === null) {
783 | status = false;
784 | } else {
785 | // If set, then take secondary element's id.
786 | elem2_id = elem2_id.toString();
787 | // Get value of secondary element.
788 | elem2 = document.getElementById(elem2_id);
789 | // If both values are same, then "status" will TRUE.
790 | if (elem1.value === elem2.value) status = true;
791 | // Value of secondary element.
792 | elem2_value = elem2.value;
793 | }
794 |
795 | // Throw error message for password validation.
796 | if (true === status || '' === elem2_value) {
797 | // Hardly remove the error message.
798 | document.getElementById(elem1.name + __err_id_suffix_rand_hash).remove();
799 | // Verify and remove error message.
800 | if (false !== elem2) document.getElementById(elem2.name + __err_id_suffix_rand_hash).remove();
801 | }
802 |
803 | //jsLogger.out('Compare Status', status);
804 | return status;
805 | };
806 | }
807 | /**
808 | * To Manage JsValidator Errors.
809 | */
810 | function jsFormError() {
811 | // Global constant to specify, error happened or not.
812 | this.errorHit = false;
813 | // Error Css.
814 | this.errorCss = false;
815 | // Success Css.
816 | this.successCss = false;
817 | /*
818 | * Initiate overall form error handler.
819 | */
820 | this.init = function () {
821 | this.errorHit = false;
822 | this.errorCss = 'border-color: red;border-radius: 5px;color: red;';
823 | this.successCss = 'border-color: green;border-radius: 5px;color: green;';
824 | };
825 | /*
826 | * Form error log.
827 | */
828 | this.log = function () {
829 | // jsLogger.out('Form Error Hit', this.errorHit);
830 | };
831 | /*
832 | * Form error style.
833 | */
834 | this.style = function (css) {
835 | this.errorCss = css.error;
836 | this.successCss = css.success;
837 | };
838 | }
839 | /**
840 | * For manage overall logging with validator.
841 | */
842 | var jsLogger = {
843 | status: function () {
844 | // return jsValidator.option.log;
845 | return __status_log;
846 | },
847 | /*
848 | * Simple log with "heading" and "message".
849 | */
850 | out: function (heading, message) {
851 |
852 | if (true !== this.status()) return false;
853 | console.log('======' + heading + '======');
854 | console.log(message);
855 | console.log('------------------------');
856 | },
857 | /*
858 | * For bulk data logging.
859 | */
860 | bulk: function (data) {
861 | if (true !== this.status()) return false;
862 | console.log(data);
863 | },
864 | /*
865 | * For log data with table.
866 | */
867 | table: function (data) {
868 | if (true !== this.status()) return false;
869 | console.table(data);
870 | }
871 | };
872 | /**
873 | * General Helping methods.jsField_obj
874 | */
875 | var helper = {
876 | /*
877 | * To check the keyboard action is window action or not.
878 | */
879 | isWindowAction: function (event) {
880 | // Getting the event to be triggered.
881 | var theEvent = event || window.event;
882 | // Getting the type of event or code.
883 | var key = theEvent.shiftKey || theEvent.which;
884 | // Check with list of code and ignore holding.
885 | // Tab, Space, Home, End, Up, Down, Left, Right...
886 | if (key === 9 || key === 0 || key === 8 || key === 32 || key === 13 || key === 8 || (key >= 35 && key <= 40)) {
887 | return true;
888 | } // If not in list then check return with corresponding data.
889 |
890 | key = String.fromCharCode(key);
891 | // Return also if length is 0.
892 | if (key.length === 0) return true;
893 | // Finally return "false" for general keys.
894 | return false;
895 | },
896 | /*
897 | * To Scroll Up / Down to notify the item that have validation message.
898 | */
899 | scrollToError: function (validateResponse) {
900 | var dummy_id = '__header_error_target_temp';
901 | var active_class = validateResponse.getClass();
902 |
903 | if (false === active_class) {
904 | jsLogger.out('Active Class Error', 'ACTIVE CLASS NOT DEFINED, GET :' + active_class);
905 | return false;
906 | }
907 |
908 | if (0 === document.getElementsByClassName(active_class).length) return false;
909 | // Getting current ID of the element.
910 | var active_id = document.getElementsByClassName(active_class)[0].id;
911 | // Update first element with dummy index ID.
912 | document.getElementsByClassName(active_class)[0].setAttribute('id', dummy_id);
913 | // Forming ID.
914 | var id = document.getElementsByClassName(active_class)[0].id;
915 | // Retrieve the element name.
916 | var elem_name = active_id.replace(__err_id_suffix_rand_hash, '');
917 | // Taking active element to navigate.
918 | var top = document.getElementsByName(elem_name)[0].offsetTop;
919 | // Format as ID.
920 | id = '#' + id;
921 | // Navigate to ID.
922 | // window.location.href = id;
923 | // Scroll to error element as close as possible.
924 | window.scroll(0, parseInt(top) - 15);
925 | // Restore with actual ID.
926 | document.getElementsByClassName(active_class)[0].setAttribute('id', active_id);
927 | // Remove the navigated value.
928 | this.removeHash(id);
929 | },
930 | /*
931 | * To Scroll Up / Down to notify the item that have validation message.
932 | */
933 | scrollToItem: function (item) {
934 | // Form hash value.
935 | var hash = item;
936 | // If "#" is missing, then add back to the ID.
937 | if (-1 === hash.indexOf('#')) hash = '#' + hash;
938 | // Navigate with the hash value.
939 | window.location.href = hash;
940 | // Remove the navigated value.
941 | this.removeHash(hash);
942 | },
943 | /*
944 | * To remove the hash value from the URL.
945 | */
946 | removeHash: function (hash) {
947 | // Getting the actual URL.
948 | var path = window.location.href;
949 | // Replacing the URL with specific hash value.
950 | path = path.replace(hash, '');
951 | // Update to url history.
952 | window.history.pushState('', 'Title', path);
953 | }
954 | };
955 | /**
956 | * Simple library for Pattern.
957 | */
958 | function pattern() {
959 | /*
960 | * To generate pattern from element attribute.
961 | */
962 | this.getDefault = function (event, originalPattern) {
963 | if (typeof originalPattern == 'undefined') originalPattern = '';
964 | // Getting special characters list.
965 | var allow_special = event.target.getAttribute('data-allowSpecial');
966 | var pattern = event.target.pattern;
967 | console.log(pattern.length);
968 | var defaultPattern;
969 | // Set default values for special characters.
970 | if (!allow_special && allow_special === null) allow_special = '';
971 | // Format to string.
972 | allow_special = allow_special.toString();
973 | if (pattern !== '' && pattern.length > 0 && pattern !== null) {
974 | defaultPattern = pattern;
975 | } else {
976 | defaultPattern = '^[' + originalPattern + allow_special + ']+$';
977 | }
978 | return defaultPattern;
979 | };
980 | /*
981 | * To validate event with the pattern.
982 | */
983 | this.validate = function (event, pattern) {
984 | // Managing the Pattern.
985 | var defaultPattern = this.getDefault(event, pattern);
986 | // Validate with special formed pattern.
987 | var regex = new RegExp(defaultPattern);
988 | // Validation with Code.
989 | var key = String.fromCharCode(!event.charCode ? event.which : event.charCode);
990 | return regex.test(key);
991 | };
992 | }
993 | /**
994 | * To Manage all kind of error response.
995 | */
996 | function validationResponse() {
997 | this.active_class = false;
998 | /*
999 | * Initiating the Response handler.
1000 | */
1001 | this.init = function (errorList, option) {
1002 | this.errorMessage = option.message;
1003 | // Updating the class.
1004 | this.active_class = option.errorClass;
1005 | // var errorElements = option.errorElem;
1006 | // jsLogger.out('Errors', errorList);
1007 | this.input(errorList.input);
1008 | this.select(errorList.select);
1009 | this.textArea(errorList.textArea);
1010 |
1011 | };
1012 | /*
1013 | * To handle the "input" element.
1014 | */
1015 | this.input = function (elem) {
1016 | // Initiate process for Input.
1017 | this.process(elem);
1018 | };
1019 | /*
1020 | * To handle the "select" element.
1021 | */
1022 | this.select = function (elem) {
1023 | // Initiate process for Select.
1024 | this.process(elem);
1025 | };
1026 | /*
1027 | * To return active class for validation response style.
1028 | */
1029 | this.getClass = function () {
1030 | return this.active_class;
1031 | };
1032 | /*
1033 | * To handle the "textArea" element.
1034 | */
1035 | this.textArea = function (elem) {
1036 | // Initiate process for TextArea.
1037 | this.process(elem);
1038 | };
1039 | /*
1040 | * To process all handlers.
1041 | */
1042 | this.process = function (elem) {
1043 | // Process with initial response.
1044 | var elementDefaultResponse = '';
1045 | // Get active class for error response element
1046 | var active_class = this.getClass();
1047 | for (var i in elem) {
1048 | // jsLogger.out('Element', document.getElementById(elem[i].id));
1049 | if (elem[i].el && true === elem[i].el.required) {
1050 | // Manage active element.
1051 | var activeElem = elem[i];
1052 | var errorType = elem[i].type;
1053 | // Fetch from Element's direct message.
1054 | elementDefaultResponse = this.template(activeElem, errorType);
1055 | var spanTag = document.getElementById(activeElem.id);
1056 | // jsLogger.out('Element Hit', errorType);
1057 | // Create new response Message SPAN.
1058 | if (typeof spanTag === 'undefined' || spanTag === 'undefined' || spanTag === null) {
1059 | // jsLogger.out('Element Found', false);
1060 | spanTag = document.createElement('span');
1061 | spanTag.setAttribute('id', activeElem.id);
1062 | spanTag.setAttribute('class', active_class);
1063 | spanTag.innerHTML = elementDefaultResponse;
1064 | } else {
1065 | // Re-use Existing response Message SPAN.
1066 | spanTag.innerHTML = elementDefaultResponse;
1067 | }
1068 | // Append HTML response to the Element.
1069 | activeElem.el.parentNode.insertBefore(spanTag, activeElem.el.nextSibling);
1070 | }
1071 | }
1072 | };
1073 | /*
1074 | * Perform template creation and update.
1075 | */
1076 | this.template = function (activeElem, errorType) {
1077 | //jsLogger.out('error Type 0', errorType);
1078 | var errorIndex = '';
1079 | var activeError = '';
1080 | // Getting error response message from elemnet.
1081 | var elementDefaultResponse = activeElem.el.getAttribute('data-message');
1082 | if (typeof elementDefaultResponse === 'undefined' || elementDefaultResponse === '' || elementDefaultResponse === null) {
1083 | // Sanity check with error message object.
1084 | if (typeof this.errorMessage !== 'undefined' && typeof this.errorMessage[errorType] !== 'undefined') {
1085 | // Getting error type. [ex. Required, Min, Max...]
1086 | errorType = this.errorMessage[errorType];
1087 |
1088 | // activeElem.el.getAttribute('data-message');
1089 | if (errorType) {
1090 | //jsLogger.out('errorType', errorType);
1091 | activeError = errorType;
1092 | // If error type is Min or Max, then it will proceed responsive.
1093 | if (activeElem.type == 'min' || activeElem.type == 'max') {
1094 | if ('min' == activeElem.type) errorIndex = activeElem.el.min;
1095 | if ('max' == activeElem.type) errorIndex = activeElem.el.max;
1096 | activeError = activeError.replace('[INDEX]', errorIndex);
1097 | }
1098 | }
1099 | } else {
1100 | activeError = this.default(errorType);
1101 | }
1102 | elementDefaultResponse = activeError;
1103 | }
1104 | return elementDefaultResponse;
1105 | };
1106 | /*
1107 | * Default error handling messages.
1108 | * If user not specify the messages,
1109 | * then it will be replaces.
1110 | */
1111 | this.default = function (errorType) {
1112 | var active_class = this.getClass();
1113 | var errorMessages = {
1114 | required: 'This field is required.',
1115 | min: 'This field length is too low.',
1116 | max: 'This field length is exceeds the limit.',
1117 | password: 'Password does not match.',
1118 | email: 'Email is not valid.',
1119 | file: 'This file is not allowed.'
1120 | };
1121 | if (typeof errorType !== 'string') return false;
1122 | if (typeof errorMessages[errorType] === 'undefined') return false;
1123 | return errorMessages[errorType];
1124 | };
1125 | }
--------------------------------------------------------------------------------
/src/js/formValidator.min.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * JavaScript Validator Library v2.0
3 | * To perform effective validation and filter with form elements.
4 | *
5 | * Author : Shankar Thiyagaraajan
6 | * Email : shankarthiyagaraajan@gmail.com
7 | * GitHub : https://github.com/shankarThiyagaraajan
8 | *
9 | * Source
10 | * https://github.com/global-source/javascript_form_validator
11 | *
12 | * Site
13 | * https://global-source.github.io/javascript_form_validator/
14 | *
15 | * Copyright 2017
16 | *
17 | * Released under the MIT license
18 | * https://github.com/global-source/javascript_form_validator/blob/master/LICENSE
19 | *
20 | * Date: 2017-08-03
21 | */
22 |
23 | var __err_id_suffix_rand_hash='_new1_1_1xv_resp';var __status_log=!1;function jsValidator(){this.formData=!1;this.onlyFilter=!1;this.jsForm=!1;this.jsSettings=!1;this.jsFormError=!1;this.formErrorList={};this.forceFilter=!1;this.initialLoad=!0;this.option=!1;this.onChange=!1;this.validateResponse=!1;this.init=function(option){__status_log=option.log;this.option=option;jsLogger.table(option);this.onlyFilter=option.onlyFilter;this.onChange=option.onChange;if('undefined'===typeof option.errorClass)option.errorClass='js-error-cop';this.validateResponse=new validationResponse();this.jsSettings=new jsSettings().init(option);this.jsForm=new jsForm().init(option);this.jsFormError=new jsFormError().init();this.forceFilter=option.forceFilter;this.check();this.submitListener(this.jsForm.formCore,this);return this};this.submitListener=function(formID,obj){if(!1===this.onlyFilter||typeof(this.onlyFilter)==='undefined'){document.querySelector('#'+formID).addEventListener('submit',function(e){if(!1===obj.check()){e.preventDefault()}})}};this.update=function(){var option=this.option;this.onlyFilter=option.onlyFilter;this.jsSettings=new jsSettings().init(option);this.jsForm=new jsForm().init(option);this.jsFormError=new jsFormError().init()};this.check=function(){var status=!1;var jsFormObj=this.jsForm;var errorList=this.formErrorList;var option=[];errorList.input=this.elemLoop('input',jsFormObj.input);errorList.textArea=this.elemLoop('textArea',jsFormObj.textArea);errorList.select=this.elemLoop('select',jsFormObj.select);jsLogger.out('Error List',this.formErrorList);option.push({'errorElem':errorList});if(errorList.input.length===0){if(errorList.textArea.length===0){if(errorList.select.length===0){status=!0}}}
24 | if(!1==this.initialLoad)this.validateResponse.init(errorList,this.option);this.initialLoad=!1;helper.scrollToError(this.validateResponse);return status};this.elemLoop=function(index,formElem){var log=[];if(formElem===null||typeof formElem==='undefined')return!1;formElem=formElem.reverse();for(var i in formElem){if(formElem[i]){var activeElem=formElem[i];this.applyFilters(activeElem);if(!0==this.onChange){this.applyGlobalListener(activeElem)}
25 | if(!1===this.onlyFilter||typeof(this.onlyFilter)==='undefined'){log=new jsRuleSets().checkValidation(activeElem,log)}}}
26 | return log};this.applyFilters=function(activeElem){if(activeElem.type=='number')new jsFilter().number(activeElem);if(activeElem.type=='email')new jsFilter().email(activeElem);if(''!==activeElem.min||''!==activeElem.max||activeElem.getAttribute('data-maxlength')||-1!==activeElem.maxLength)new jsFilter().limit(activeElem);if(activeElem.type=='file')new jsFilter().file(activeElem);if(activeElem.getAttribute('data-allow'))new jsFilter().string(activeElem);if(activeElem.getAttribute('pattern'))new jsFilter().pattern(activeElem)};this.applyGlobalListener=function(element){element.addEventListener('change',this.quickValidation,!1)};this.quickValidation=function(event){var log=[];var target=event.target;log=new jsRuleSets().checkValidation(target,log);new validationResponse().process(log)};this.validate=function(){return this.check()}}
27 | function jsFilter(){this.checkStatus=function(elem){var status;status=!0;if(!1===new jsValidator().forceFilter){status=!1;if(!0===elem.required){status=!0}}
28 | return status};this.number=function(element){var status=this.checkStatus(element);if(!0===status)element.addEventListener('keypress',this.isNumberKey,!1)};this.string=function(element){var type=element.getAttribute('data-allow');var current=this;var status=this.checkStatus(element);switch(type){case 'onlyAlpha':if(!0===status)element.addEventListener('keypress',current.isAlpha,!1);break;case 'string':if(!0===status)element.addEventListener('keypress',current.isAlphaNumeric,!1);break;default:if(!0===status)element.addEventListener('keypress',current.isPatternValid,!1);break}};this.pattern=function(element){var current=this;var status=this.checkStatus(element);if(!0===status)element.addEventListener('keypress',current.isPatternValid,!1)};this.email=function(element){var status=this.checkStatus(element);if(!0===status)element.addEventListener('keypress',jsRuleSets.email,!1)};this.file=function(element){var status=this.checkStatus(element);if(!0===status)element.addEventListener('change',jsRuleSets.file,!1)};this.limit=function(element){var status=this.checkStatus(element);if(!0===status)element.addEventListener('change',this.isInLimit,!1)};this.isInLimit=function(event){var value=event.target.value;if(!0===helper.isWindowAction(event))return!0;var target=event.target;var final_value=value;var min=event.target.min;var max=event.target.max;var max_length=event.target.getAttribute('data-maxlength')?event.target.getAttribute('data-maxlength'):0;max_length=parseInt(max_length);var num=value;if(0===max_length){if(!min)min=1;if(!max)max=100;var regex=new RegExp('^[0-9]+$');var key=String.fromCharCode(!event.charCode?event.which:event.charCode);if(!1===regex.test(key)||parseInt(value)>max||parseInt(value)max)final_value=max;if(parseInt(num)max_length)&&031&&(charCode<48||charCode>57)){event.preventDefault();return!1}
33 | return!0}}
34 | function jsSettings(){this.errorColor=!1;this.errorTemplate=!1;this.init=function(option){this.errorColor=option.errorColor;this.errorTemplate=option.errorTemplate;return this};this.log=function(){jsLogger.out(this.errorColor);jsLogger.out(this.errorTemplate)}}
35 | function jsForm(){this.form=!1;this.formCore=!1;this.input=!1;this.select=!1;this.textArea=!1;this.label=!1;this.forceFilter=!1;this.init=function(option){jsLogger.out('Form',option.form);this.options=option;this.forceFilter=option.forceFilter;this.registerForm(option.form);this.parseForm(this.form);this.required();return this};this.registerForm=function(form){if(typeof form==='undefined')jsLogger.out('Form Identification','Form Identification is Missing !');if(null===form)return!1;this.form=document.getElementById(form);if(null===this.form)jsLogger.out('Status 503','Failed to Proceed !');this.formCore=form};this.parseForm=function(form){if(form===null)return!1;this.input=form.getElementsByTagName('input');this.select=form.getElementsByTagName('select');this.textArea=form.getElementsByTagName('textarea');this.label=form.getElementsByTagName('label')};this.required=function(){var forceFilter=this.forceFilter;var jsField_obj=new jsField();this.input=jsField_obj.required(this.input,forceFilter);this.select=jsField_obj.required(this.select,forceFilter);this.textArea=jsField_obj.required(this.textArea,forceFilter)};this.log=function(){jsLogger.out('Form',this.form);jsLogger.out('input',this.input);jsLogger.out('select',this.select);jsLogger.out('textarea',this.textArea);jsLogger.out('labels',this.label)}}
36 | function jsField(){this.required=function(field,forceFilter){var requiredFieldsList=[];for(var i=0;imax&&value.length!=0)status=!1;return status};this.email=function(elem){if(!1===elem.required)return!0;var status=!1;var email=elem.value;if(typeof email==='undefined')return!1;email=email.toString();if(/^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$/.test(email)){status=!0}
47 | if(!email)status=!1;return status};this.file=function(elem){var list_to_allow=elem.target.getAttribute('data-extensions');var target=elem.target;var list_to_allow_array;var file_response;if(''===list_to_allow)return!0;if(-1===list_to_allow.indexOf(',')){list_to_allow_array=[list_to_allow]}else{list_to_allow_array=list_to_allow.split(',')}
48 | var fileName=target.value;fileName=fileName.toLowerCase();file_response=(new RegExp('('+list_to_allow_array.join('|').replace(/\./g,'\\.')+')$')).test(fileName);if(!1===file_response){alert('Allowed file types are "'+list_to_allow+'" !');elem.target.value='';return!1}
49 | return!0};this.phone=function(elem,pattern){if(!1===elem.required)return!0;var status=!0;if(elem.value==='')status=!1;return status};this.compare=function(elem1){var status=!1;if(!1===elem1.required)status=!0;var elem2_id=elem1.getAttribute('data-check');var elem2_value='';var elem2=!1;if(typeof elem2_id=='undefined'||elem2_id==null)status=!1;if(elem2_id===null)elem2_id=elem1.getAttribute('data-parent');if(elem2_id===null){status=!1}else{elem2_id=elem2_id.toString();elem2=document.getElementById(elem2_id);if(elem1.value===elem2.value)status=!0;elem2_value=elem2.value}
50 | if(!0===status||''===elem2_value){document.getElementById(elem1.name+__err_id_suffix_rand_hash).remove();if(!1!==elem2)document.getElementById(elem2.name+__err_id_suffix_rand_hash).remove()}
51 | return status}}
52 | function jsFormError(){this.errorHit=!1;this.errorCss=!1;this.successCss=!1;this.init=function(){this.errorHit=!1;this.errorCss='border-color: red;border-radius: 5px;color: red;';this.successCss='border-color: green;border-radius: 5px;color: green;'};this.log=function(){};this.style=function(css){this.errorCss=css.error;this.successCss=css.success}}
53 | var jsLogger={status:function(){return __status_log},out:function(heading,message){if(!0!==this.status())return!1;console.log('======'+heading+'======');console.log(message);console.log('------------------------')},bulk:function(data){if(!0!==this.status())return!1;console.log(data)},table:function(data){if(!0!==this.status())return!1;console.table(data)}};var helper={isWindowAction:function(event){var theEvent=event||window.event;var key=theEvent.shiftKey||theEvent.which;if(key===9||key===0||key===8||key===32||key===13||key===8||(key>=35&&key<=40)){return!0}
54 | key=String.fromCharCode(key);if(key.length===0)return!0;return!1},scrollToError:function(validateResponse){var dummy_id='__header_error_target_temp';var active_class=validateResponse.getClass();if(!1===active_class){jsLogger.out('Active Class Error','ACTIVE CLASS NOT DEFINED, GET :'+active_class);return!1}
55 | if(0===document.getElementsByClassName(active_class).length)return!1;var active_id=document.getElementsByClassName(active_class)[0].id;document.getElementsByClassName(active_class)[0].setAttribute('id',dummy_id);var id=document.getElementsByClassName(active_class)[0].id;var elem_name=active_id.replace(__err_id_suffix_rand_hash,'');var top=document.getElementsByName(elem_name)[0].offsetTop;id='#'+id;window.scroll(0,parseInt(top)-15);document.getElementsByClassName(active_class)[0].setAttribute('id',active_id);this.removeHash(id)},scrollToItem:function(item){var hash=item;if(-1===hash.indexOf('#'))hash='#'+hash;window.location.href=hash;this.removeHash(hash)},removeHash:function(hash){var path=window.location.href;path=path.replace(hash,'');window.history.pushState('','Title',path)}};function pattern(){this.getDefault=function(event,originalPattern){if(typeof originalPattern=='undefined')originalPattern='';var allow_special=event.target.getAttribute('data-allowSpecial');var pattern=event.target.pattern;console.log(pattern.length);var defaultPattern;if(!allow_special&&allow_special===null)allow_special='';allow_special=allow_special.toString();if(pattern!==''&&pattern.length>0&&pattern!==null){defaultPattern=pattern}else{defaultPattern='^['+originalPattern+allow_special+']+$'}
56 | return defaultPattern};this.validate=function(event,pattern){var defaultPattern=this.getDefault(event,pattern);var regex=new RegExp(defaultPattern);var key=String.fromCharCode(!event.charCode?event.which:event.charCode);return regex.test(key)}}
57 | function validationResponse(){this.active_class=!1;this.init=function(errorList,option){this.errorMessage=option.message;this.active_class=option.errorClass;this.input(errorList.input);this.select(errorList.select);this.textArea(errorList.textArea)};this.input=function(elem){this.process(elem)};this.select=function(elem){this.process(elem)};this.getClass=function(){return this.active_class};this.textArea=function(elem){this.process(elem)};this.process=function(elem){var elementDefaultResponse='';var active_class=this.getClass();for(var i in elem){if(elem[i].el&&!0===elem[i].el.required){var activeElem=elem[i];var errorType=elem[i].type;elementDefaultResponse=this.template(activeElem,errorType);var spanTag=document.getElementById(activeElem.id);if(typeof spanTag==='undefined'||spanTag==='undefined'||spanTag===null){spanTag=document.createElement('span');spanTag.setAttribute('id',activeElem.id);spanTag.setAttribute('class',active_class);spanTag.innerHTML=elementDefaultResponse}else{spanTag.innerHTML=elementDefaultResponse}
58 | activeElem.el.parentNode.insertBefore(spanTag,activeElem.el.nextSibling)}}};this.template=function(activeElem,errorType){var errorIndex='';var activeError='';var elementDefaultResponse=activeElem.el.getAttribute('data-message');if(typeof elementDefaultResponse==='undefined'||elementDefaultResponse===''||elementDefaultResponse===null){if(typeof this.errorMessage!=='undefined'&&typeof this.errorMessage[errorType]!=='undefined'){errorType=this.errorMessage[errorType];if(errorType){activeError=errorType;if(activeElem.type=='min'||activeElem.type=='max'){if('min'==activeElem.type)errorIndex=activeElem.el.min;if('max'==activeElem.type)errorIndex=activeElem.el.max;activeError=activeError.replace('[INDEX]',errorIndex)}}}else{activeError=this.default(errorType)}
59 | elementDefaultResponse=activeError}
60 | return elementDefaultResponse};this.default=function(errorType){var active_class=this.getClass();var errorMessages={required:'This field is required.',min:'This field length is too low.',max:'This field length is exceeds the limit.',password:'Password does not match.',email:'Email is not valid.',file:'This file is not allowed.'};if(typeof errorType!=='string')return!1;if(typeof errorMessages[errorType]==='undefined')return!1;return errorMessages[errorType]}}
--------------------------------------------------------------------------------