├── .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 | [![Packagist](https://img.shields.io/badge/JavaScript-Core-brightgreen.svg)](https://github.com/global-source/javascript_form_validator) [![Packagist](https://img.shields.io/badge/JavaScript-ES6-green.svg)](https://github.com/global-source/javascript_form_validator) [![License](https://img.shields.io/badge/Build-V.2.0-blue.svg)](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 |
110 |
111 | 112 | 114 |
115 |
116 | 117 | 119 |
120 |
121 | 122 | 123 |
124 |
125 | 126 | 127 |
128 |
129 | 130 | 131 |
132 |
133 | 134 | 135 |
136 |
137 | 138 | 139 |
140 |
141 | 142 | 143 |
144 |
145 | 146 | 147 |
148 |
149 | 150 | 155 |
156 |
157 | 158 | 159 |
160 |
161 | 162 |
163 |
164 | ``` 165 | 166 | 3. In form use **`novalidate`** to avoid browser interuptions. 167 | 168 | ```html 169 |
170 | ... 171 | ... 172 |
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 |
12 | 13 |
14 |
15 | 16 | 18 |
19 | 20 |






21 | 22 |
23 | 24 | 26 | 27 |
28 | 29 |






30 | 31 |
32 | 33 | 35 |
36 | 37 |







38 | 39 |
40 | 41 | 43 |
44 | 45 |








46 | 47 | 48 | 50 | 51 |
52 | 53 | 55 |
56 | 57 |






58 | 59 | 60 | 61 |
62 | 63 | 64 |
65 | 66 |












67 | 68 | 69 | 71 |
72 | 73 | 75 |
76 |












77 |
78 | 79 | 80 |
81 |
82 | 83 | 84 |
85 | 86 |












87 | 88 | 89 | 90 | 91 |









92 |
93 |
94 | 95 | 96 |
97 |






98 |
99 | 100 | 101 |
102 |






103 | 104 |
105 |
106 | 107 | 108 | 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]}} --------------------------------------------------------------------------------