diff --git a/src/demo/index3.html b/src/demo/index3.html index b636af1..df32609 100644 --- a/src/demo/index3.html +++ b/src/demo/index3.html @@ -13,14 +13,15 @@
- +







-
diff --git a/src/js/multi_formValidator.es6.js b/src/js/multi_formValidator.es6.js new file mode 100644 index 0000000..b5f7919 --- /dev/null +++ b/src/js/multi_formValidator.es6.js @@ -0,0 +1,1120 @@ +/*! + * JavaScript Validator Library v1.0 + * To perform effective validation and filter with form elements. + * + * Author : Shankar Thiyagaraajan + * Email : shankarthiyagaraajan@gmail.com + * GitHub : https://github.com/shankarThiyagaraajan + * + * Source + * https://github.com/global-source/javascript_form_validator + * + * Site + * https://global-source.github.io/javascript_form_validator/ + * + * Copyright 2017 + * + * Released under the MIT license + * https://github.com/global-source/javascript_form_validator/blob/master/LICENSE + * + * Date: 2017-07-21 + */ + +/* + * For Managing overall Validation flow. + */ +let firstErrorHit = false; +let __err_id_suffix_rand_hash = '_new1_1_1xv_resp'; + +/** + * Core Js Validator. + */ +class jsValidator { + constructor() { + // Holding form element data. + this.formData = false; + // Switch complete validation and input filter. + this.onlyFilter = false; + // JS form. + this.jsForm = false; + // JS setting. + this.jsSettings = false; + // JS form error. + this.jsFormError = false; + // Overall error list. + this.formErrorList = {}; + // To Filter non-required fields. + this.forceFilter = false; + // To Filter the First load. + this.initialLoad = true; + // Global options. + this.option = false; + // To apply global validator. + this.onChange = false; + this.validateResponse = false; + } + + /* + * Initiating the Validator. + */ + init(option) { + // To Update global options. + this.option = option; + jsLogger.table(option); + // Updating the filter flag to global. + this.onlyFilter = option.onlyFilter; + // To Enable/Disable global validator. + this.onChange = option.onChange; + // Update default response "class". + if ('undefined' === typeof option.errorClass) option.errorClass = 'js-error-cop'; + this.validateResponse = new validationResponse(); + // Update "jsSettings" to global object. + this.jsSettings = new jsSettings().init(option); + // Update "jsForm" to global object. + this.jsForm = new jsForm().init(option); + // Initiate form error setup. + this.jsFormError = new jsFormError().init(); + // Update Force Field status. + this.forceFilter = option.forceFilter; + // To check the form elements. + this.check(); + // To register the listener. + this.submitListener(this.jsForm.formCore, this); + // Send back "this". + return this; + }; + + /* + * To make listen on submit action of the form. + */ + submitListener(formID, obj) { + // To off submit listener, if only filter needed. + if (false === this.onlyFilter || typeof (this.onlyFilter) === 'undefined') { + // Initiate listener for form submission. + document.querySelector('#' + formID).addEventListener('submit', function (e) { + // To start form validations. + // Check validation status. + if (false === obj.check()) { + //stop form from submitting, if validation fails + e.preventDefault(); + } + }); + } + }; + + /* + * To Refresh the DOM and enable Dynamic-Elements to Access. + */ + update() { + let option = this.option; + // Updating the filter flag to global. + this.onlyFilter = option.onlyFilter; + // Update "jsSettings" to global object. + this.jsSettings = new jsSettings().init(option); + // Update "jsForm" to global object. + this.jsForm = new jsForm().init(option); + // Initiate form error setup. + this.jsFormError = new jsFormError().init(); + }; + + /* + * To checking all elements from registered form. + */ + check() { + let status = false; + // Loading JS Form. + let jsFormObj = this.jsForm; + // Loading JS error list. + let errorList = this.formErrorList; + let option = []; + // Looping the "input" elements for validation and filter implementation. + errorList.input = this.elemLoop('input', jsFormObj.input); + // Looping the "textArea" elements fro validation filter implementation. + errorList.textArea = this.elemLoop('textArea', jsFormObj.textArea); + // Looping the "select" elements fro validation filter implementation. + errorList.select = this.elemLoop('select', jsFormObj.select); + jsLogger.out('Error List', this.formErrorList); + option.push({ + 'errorElem': errorList + }); + // To Update global Validation Status. + // If, Input elements have no errors. + if (errorList.input.length === 0) { + // If, Text Area elements have no errors. + if (errorList.textArea.length === 0) { + // If, Select elements have no errors. + if (errorList.select.length === 0) { + // If validation pass, then update "status" object. + status = true; + } + } + } + if (false == this.initialLoad) this.validateResponse.init(errorList, this.option); + this.initialLoad = false; + helper.scrollToError(this.validateResponse); + return status; + }; + + /* + * To looping all elements for actions. + */ + elemLoop(index, formElem) { + // Initiate empty array for keep list of errors. + let log = []; + // Sanity check with "formElem". + if (formElem === null || typeof formElem === 'undefined') return false; + formElem = formElem.reverse(); + // Looping elements. + for (let i in formElem) { + if (formElem[i]) { + // Switch to static letiable. + let activeElem = formElem[i]; + // Apply filter to element. + this.applyFilters(activeElem); + // Register the DOM with live onChange validations. + if (true == this.onChange) { + this.applyGlobalListener(activeElem); + } + //jsLogger.out('Only Filter', this.onlyFilter); + // If not only filter, then start validations. + if (false === this.onlyFilter || typeof (this.onlyFilter) === 'undefined') { + // Initiate validations and update to log. + log = new jsRuleSets().checkValidation(activeElem, log); + } + } + } + // jsLogger.out('Log', log); + return log; + }; + + /* + * To apply filter to all relevant elements by it's attributes. + */ + applyFilters(activeElem) { + // Apply filter for Number elements. + if (activeElem.type == 'number') new jsFilter().number(activeElem); + // Apply filter for Email elements. + if (activeElem.type == 'email') new jsFilter().email(activeElem); + // Apply filter for Numeric elements. + // if (activeElem.min || activeElem.max || activeElem.minLength || activeElem.maxLength) jsFilter.limit(activeElem); + // Apply filter File elements. + if (activeElem.type == 'file') new jsFilter().file(activeElem); + // Apply filter with string, alphaNumeric and pregMatch. + if (activeElem.getAttribute('data-allow')) new jsFilter().string(activeElem); + // Apply filter with pattern. + if (activeElem.getAttribute('pattern')) new jsFilter().pattern(activeElem); + }; + + /* + * To make it active to listen changes of those error fields. + */ + applyGlobalListener(element) { + element.addEventListener('change', this.quickValidation, false); + }; + + /* + * To perform quick validation to respond those fields. + */ + quickValidation(event) { + // jsLogger.out('Quick', event); + let log = []; + let target = event.target; + // To check the validation of an element. + log = new jsRuleSets().checkValidation(target, log); + // jsLogger.out('Quick Out', log); + new validationResponse().process(log); + }; + + /* + * Single step instance validator for Ajax form submissions. + */ + validate() { + // Initiate form Check. + return this.check(); + }; +} +/** + * Common Filter instances. + */ +class jsFilter { + checkStatus(elem) { + let status; + status = true; + if (false === new jsValidator().forceFilter) { + status = false; + if (true === elem.required) { + status = true; + } + } + return status; + }; + + // Number elements filter listener. + number(element) { + let status = this.checkStatus(element); + if (true === status) element.addEventListener('keypress', this.isNumberKey, false); + }; + + /* + * String elements filter listener. + */ + string(element) { + // Getting "data" attribute for actions. + let type = element.getAttribute('data-allow'); + let current = this; + let status = this.checkStatus(element); + + // Switching actions. + switch (type) { + // Allow only alphabets [a-zA-Z] not [0-9] and special characters. + case 'onlyAlpha': + if (true === status) element.addEventListener('keypress', current.isAlpha, false); + break; + // Allow only alpha Numeric [a-zA-Z0-9] not special characters. + case 'string': + if (true === status) element.addEventListener('keypress', current.isAlphaNumeric, false); + break; + // Allow based on the pattern given. + default: + if (true === status) element.addEventListener('keypress', current.isPatternValid, false); + break; + } + }; + + /* + * Pattern based filter and listener. + */ + pattern(element) { + let current = this; + let status = this.checkStatus(element); + if (true === status) element.addEventListener('keypress', current.isPatternValid, false); + }; + + /* + * Email elements filter listener. + */ + email(element) { + let status = this.checkStatus(element); + if (true === status) element.addEventListener('keypress', jsRuleSets.email, false); + }; + + file(element) { + let status = this.checkStatus(element); + if (true === status) element.addEventListener('change', jsRuleSets.file, false); + }; + + /* + * Numeric with Limited elements filter listener. + */ + limit(element) { + let status = this.checkStatus(element); + if (true === status) element.addEventListener('input', this.isInLimit, false); + }; + + /* + * Restrict element with it's limit. + */ + isInLimit(event) { + let value = event.target.value; + // To check is this action is from "windows" action or not. + if (true === helper.isWindowAction(event)) return true; + // Getting object from element. + let min = event.target.min; + let max = event.target.max; + // Default values for Min and Max. + if (!min) min = 1; + if (!max) max = 31; + // Forming pattern for Restriction. + let regex = new RegExp('^[0-9]+$'); + // Validation with Code. + let key = String.fromCharCode(!event.charCode ? event.which : event.charCode); + //jsLogger.out('Limit', regex.test(key) + ' | min |' + min + ' | max | ' + max); + //jsLogger.out('Regex', regex.test(key)); + // Return status of the Action. + if (false === regex.test(key) || parseInt(value) > max || parseInt(value) < min) { + event.preventDefault(); + } + + let num = +this.value; //converts value to a Number + if (!this.value.length) return false; //allows empty field + this.value = isNaN(num) ? min : num > max ? max : num < min ? min : num; + + event.target.value = event.target.value.substring(0, event.target.value.length - 1); + }; + + /* + * Only allow alpha([a-zA-Z]). + */ + isAlpha(event) { + // To check is this action is from "windows" action or not. + if (true === helper.isWindowAction(event)) return true; + // Managing the Pattern. + let status = new pattern().validate(event, 'a-zA-Z'); + // Return status of the Action. + if (false === status) event.preventDefault(); + }; + + /* + * Only allow alpha([a-zA-Z0-9]). + */ + isAlphaNumeric(event) { + // To check is this action is from "windows" action or not. + if (true === helper.isWindowAction(event)) return true; + // Managing the Pattern. + let status = new pattern().validate(event, 'a-zA-Z0-9'); + // Return status of the Action. + if (false === status) event.preventDefault(); + }; + + /* + * To check password is valid or not. + */ + isValidPassword(event) { + // Prevent using "space". + let charCode = (event.which) ? event.which : event.keyCode; + // If event is "space" then prevent to enter. + if (charCode === 32) { + event.preventDefault(); + return false; + } // To check is this action is from "windows" action or not. + + if (true === helper.isWindowAction(event)) return true; + // Managing the Pattern. + let status = new pattern().validate(event, 'a-zA-Z0-9'); + // Return status of the Action. + if (false === status) event.preventDefault(); + }; + + /* + * Only allow by pattern(ex. ^[a-zA-Z0-3@#$!_.]+$). + */ + isPatternValid(event) { + // To check is this action is from "windows" action or not. + if (true === helper.isWindowAction(event)) return true; + // Managing the Pattern. + let status = new pattern().validate(event, 'a-zA-Z0-4'); + // Return status of the Action. + if (false === status) event.preventDefault(); + }; + + /* + * Check is numeric or not. + */ + isNumberKey(event) { + // To check is this action is from "windows" action or not. + if (true === helper.isWindowAction(event)) return true; + // Validation with Code. + let charCode = (event.which) ? event.which : event.keyCode; + if (charCode === 46 || charCode > 31 && (charCode < 48 || charCode > 57)) { + event.preventDefault(); + return false; + } // Return status of the Action. + + return true; + }; +} + +/** + * To Update overall JsValidator Settings. + */ +class jsSettings { + constructor() { + // Common error message color for form validation. + this.errorColor = false; + // Set common template for error message + this.errorTemplate = false; + } + + /* + * To Initiate the Configurations. + */ + init(option) { + // To update error message color to global object. + this.errorColor = option.errorColor; + // To update error template to handle error message. + this.errorTemplate = option.errorTemplate; + // Return "this" object. + return this; + }; + + /* + * General Log. + */ + log() { + jsLogger.out(this.errorColor); + jsLogger.out(this.errorTemplate); + }; +} +/** + * To Perform all Form based Operations. + */ +class jsForm { + constructor() { + // Form element. + this.form = false; + // Form ID. + this.formCore = false; + // Form element's inputs. + this.input = false; + // Form element's selects. + this.select = false; + // Form element's textAreas. + this.textArea = false; + // Form element's labels. + this.label = false; + // Perform Force Filter on Elements. + this.forceFilter = false; + } + + /* + * To Initiating the "jsForm". + */ + init(option) { + jsLogger.out('Form', option.form); + // Update Global Option. + this.options = option; + // Enable/Disable Force Filter. + this.forceFilter = option.forceFilter; + // To Register Form. + this.registerForm(option.form); + // To Parsing the Form. + this.parseForm(this.form); + // To Filter Required Elements. + this.required(); + return this; + }; + + /* + * To Register Active Form to Global Object. + */ + registerForm(form) { + // validate and Update Log. + if (typeof form === 'undefined') jsLogger.out('Form Identification', 'Form Identification is Missing !'); + // Form should not be an ID. + if (null === form) return false; + // Fetch Form element from Document. + this.form = document.getElementById(form); + if (null === this.form) jsLogger.out('Status 503', 'Failed to Proceed !'); + // Update Direct Form ID. + this.formCore = form; + }; + + /* + * To Parse all Relative Form components. + */ + parseForm(form) { + if (form === null) return false; + // "Input" elements like "text, date, time..." + this.input = form.getElementsByTagName('input'); + // "Select" element. + this.select = form.getElementsByTagName('select'); + // "TextArea" element. + this.textArea = form.getElementsByTagName('textarea'); + // "Label" element. + this.label = form.getElementsByTagName('label'); + }; + + /* + * To set fields are required. + */ + required() { + // let jsField = new jsField().init(this.options); + let forceFilter = this.forceFilter; + let jsField_obj = new jsField(); + // Filter all required "input" elements. + this.input = jsField_obj.required(this.input, forceFilter); + // Filter all required "select" elements. + this.select = jsField_obj.required(this.select, forceFilter); + // Filter all required "textArea" elements. + this.textArea = jsField_obj.required(this.textArea, forceFilter); + }; + + /* + * General Log. + */ + 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); + }; +} +/** + * Perform Operations in Field level. + */ +class jsField { + /* + * Return all required elements list. + */ + required(field, forceFilter) { + let requiredFieldsList = []; + // Looping fields to filter. + for (let i = 0; i < field.length; i++) { + // Check and push elements. + if (field[i].required === true || true === forceFilter) { + // Pushing to required elements list. + requiredFieldsList.push(field[i]); + } + } // Return list of required elements. + + return requiredFieldsList; + }; +} +/** + * List of Validation Rules. + */ +class jsRuleSets { + /* + * To start validation process. + */ + checkValidation(activeElem, log) { + //jsLogger.out('Active Elem', activeElem); + let validElem = true; + let jsRuleSets_obj = new jsRuleSets(); + // To Generally checks, the field is empty or not. + if (!jsRuleSets_obj.isSet(activeElem)) { + log.push({ + 'el': activeElem, + 'type': 'required', + 'id': activeElem.name + __err_id_suffix_rand_hash + }); + firstErrorHit = activeElem.name + __err_id_suffix_rand_hash; + } + + // To Check the Value is less than minimum or not. + if (activeElem.min) { + if (jsRuleSets_obj.isSet(activeElem)) { + if (!jsRuleSets_obj.min(activeElem)) { + log.push({ + 'el': activeElem, + 'type': 'min', + 'id': activeElem.name + __err_id_suffix_rand_hash + }); + firstErrorHit = activeElem.name + __err_id_suffix_rand_hash; + validElem = false; + } + } + } + + // To Check the Value is grater than max or not. + if (activeElem.max) { + if (jsRuleSets_obj.isSet(activeElem)) { + if (!jsRuleSets_obj.max(activeElem)) { + log.push({ + 'el': activeElem, + 'type': 'max', + 'id': activeElem.name + __err_id_suffix_rand_hash + }); + firstErrorHit = activeElem.name + __err_id_suffix_rand_hash; + validElem = false; + } + } + } + + // To Check the Entered E-mail is Valid or Not. + if (activeElem.type == 'email') { + if (jsRuleSets_obj.isSet(activeElem)) { + if (!jsRuleSets_obj.email(activeElem)) { + log.push({ + 'el': activeElem, + 'type': 'email', + 'id': activeElem.name + __err_id_suffix_rand_hash + }); + firstErrorHit = activeElem.name + __err_id_suffix_rand_hash; + validElem = false; + } + } + } + + // To Compare the Password is Same or Not with Re-Password. + // TODO: Implement Simplified Comparison. + if (activeElem.type == 'password') { + if (jsRuleSets_obj.isSet(activeElem)) { + if (!jsRuleSets_obj.compare(activeElem)) { + log.push({ + 'el': activeElem, + 'type': 'password', + 'id': activeElem.name + __err_id_suffix_rand_hash + }); + firstErrorHit = activeElem.name + __err_id_suffix_rand_hash; + validElem = false; + } + } + } // If valid, then reset validation message. + + if (true === validElem) { + //jsLogger.out('Valid Elem', activeElem); + if (activeElem.name !== '') { + let elem = document.getElementById(activeElem.name + __err_id_suffix_rand_hash); + if (typeof (elem) !== 'undefined' && elem !== null) { + // Remove element to avoid un-necessary buffer. + elem.remove(); + } + } + } + // If error occurred, then locate that error + if (false !== firstErrorHit) { + //helper.scrollToItem(firstErrorHit); + } + // } + // Return overall log report of validation. + + return log; + }; + + /* + * To Check, whether the element have value or not. + */ + isSet(elem) { + // If field is not required, then return "true". + if (false === elem.required) return true; + let status = true; + let value = elem.value; + //TODO: Implement suitable solution for this. + if (value.length === 0 || value === '' || value === ' ' || value === '[]') status = false; + return status; + }; + + /* + * To Check Element with Min Condition. + */ + min(elem) { + // If field is not required, then return "true". + if (false === elem.required) return true; + let status = true; + let value = elem.value; + let min = elem.min; + //TODO: Implement suitable solution for this. + if (value.length < min && value.length != 0) status = false; + return status; + }; + + /* + * To Check Element with Max Condition. + */ + max(elem) { + // If field is not required, then return "true". + if (false === elem.required) return true; + let status = true; + let value = elem.value; + let max = elem.max; + //TODO: Implement suitable solution for this. + if (value.length > max && value.length != 0) status = false; + return status; + }; + + /* + * To Check Element Email is Valid or Not. + */ + email(elem) { + // If field is not required, then return "true". + if (false === elem.required) return true; + let status = false; + let email = elem.value; + if (typeof email === 'undefined') return false; + // To Validate Email. + // Convert to Native String Format. + email = email.toString(); + // To Check it as String or Not. + if (/^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$/.test(email)) { + // Valid Email. + status = true; + } + if (!email) status = false; + 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 true; + // Slit into array of extensions. + if (-1 === list_to_allow.indexOf(',')) { + list_to_allow_array = [list_to_allow]; + } else { + list_to_allow_array = list_to_allow.split(','); + } + // Get file name. + let fileName = target.value; + // Convert to lower case for native validation. + fileName = fileName.toLowerCase(); + file_response = (new RegExp('(' + list_to_allow_array.join('|').replace(/\./g, '\\.') + ')$')).test(fileName); + if (false === file_response) { + alert('Allowed file types are "' + list_to_allow + '" !'); + // Reset file type. + elem.target.value = ''; + return false; + } + return true; + }; + + /* + * To Check Element Phone Value is Valid or Not. + */ + phone(elem, pattern) { + // If field is not required, then return "true". + if (false === elem.required) return true; + let status = true; + if (elem.value === '') status = false; + return status; + }; + + /* + * To Compare two Elements Values. + */ + compare(elem1) { + let status = false; + // If field is not required, then return "true". + if (false === elem1.required) status = true; + let elem2_id = elem1.getAttribute('data-check'); + if (typeof elem2_id == 'undefined' || elem2_id == null) status = false; + if (elem2_id === null) elem2_id = elem1.getAttribute('data-parent'); + if (elem2_id === null) { + status = false; + } else { + elem2_id = elem2_id.toString(); + let elem2 = document.getElementById(elem2_id); + if (elem1.value === elem2.value) status = true; + } + //jsLogger.out('Compare Status', status); + return status; + }; +} +/** + * To Manage JsValidator Errors. + */ +class jsFormError { + constructor() { + // Global constant to specify, error happened or not. + this.errorHit = false; + // Error Css. + this.errorCss = false; + // Success Css. + this.successCss = false; + } + + /* + * Initiate overall form error handler. + */ + init() { + this.errorHit = false; + this.errorCss = 'border-color: red;border-radius: 5px;color: red;'; + this.successCss = 'border-color: green;border-radius: 5px;color: green;'; + }; + + /* + * Form error log. + */ + log() { + // jsLogger.out('Form Error Hit', this.errorHit); + }; + + /* + * Form error style. + */ + style(css) { + this.errorCss = css.error; + this.successCss = css.success; + }; +} +/** + * For manage overall logging with validator. + */ +let jsLogger = { + status: function () { + // return jsValidator.option.log; + return '[]'; + }, + /* + * Simple log with "heading" and "message". + */ + out: function (heading, message) { + + if (true !== this.status()) return false; + console.log('======' + heading + '======'); + console.log(message); + console.log('------------------------'); + }, + /* + * For bulk data logging. + */ + bulk: function (data) { + if (true !== this.status()) return false; + console.log(data); + }, + /* + * For log data with table. + */ + table: function (data) { + if (true !== this.status()) return false; + console.table(data); + } +}; +/** + * General Helping methods.jsField_obj + */ +let helper = { + /* + * To check the keyboard action is window action or not. + */ + isWindowAction: function (event) { + // Getting the event to be triggered. + let theEvent = event || window.event; + // Getting the type of event or code. + let key = theEvent.shiftKey || theEvent.which; + // Check with list of code and ignore holding. + // Tab, Space, Home, End, Up, Down, Left, Right... + if (key === 9 || key === 0 || key === 8 || key === 32 || key === 13 || key === 8 || (key >= 35 && key <= 40)) { + return true; + } // If not in list then check return with corresponding data. + + key = String.fromCharCode(key); + // Return also if length is 0. + if (key.length === 0) return true; + // Finally return "false" for general keys. + return false; + }, + /* + * To Scroll Up / Down to notify the item that have validation message. + */ + scrollToError: function (validateResponse) { + let dummy_id = '__header_error_target_temp'; + let active_class = validateResponse.getClass(); + + if (false === active_class) { + jsLogger.out('Active Class Error', 'ACTIVE CLASS NOT DEFINED, GET :' + active_class); + return false; + } + + if (0 === document.getElementsByClassName(active_class).length) return false; + // Getting current ID of the element. + let active_id = document.getElementsByClassName(active_class)[0].id; + // Update first element with dummy index ID. + document.getElementsByClassName(active_class)[0].setAttribute('id', dummy_id); + // Forming ID. + let id = document.getElementsByClassName(active_class)[0].id; + // Retrieve the element name. + let elem_name = active_id.replace(__err_id_suffix_rand_hash, ''); + // Taking active element to navigate. + let top = document.getElementsByName(elem_name)[0].offsetTop; + // Format as ID. + id = '#' + id; + // Navigate to ID. + // window.location.href = id; + // Scroll to error element as close as possible. + window.scroll(0, parseInt(top) - 15); + // Restore with actual ID. + document.getElementsByClassName(active_class)[0].setAttribute('id', active_id); + // Remove the navigated value. + this.removeHash(id); + }, + /* + * To Scroll Up / Down to notify the item that have validation message. + */ + scrollToItem: function (item) { + // Form hash value. + let hash = item; + // If "#" is missing, then add back to the ID. + if (-1 === hash.indexOf('#')) hash = '#' + hash; + // Navigate with the hash value. + window.location.href = hash; + // Remove the navigated value. + this.removeHash(hash); + }, + /* + * To remove the hash value from the URL. + */ + removeHash: function (hash) { + // Getting the actual URL. + let path = window.location.href; + // Replacing the URL with specific hash value. + path = path.replace(hash, ''); + // Update to url history. + window.history.pushState('', 'Title', path); + } +}; +/** + * Simple library for Pattern. + */ +class pattern { + /* + * To generate pattern from element attribute. + */ + getDefault(event, originalPattern) { + if (typeof originalPattern == 'undefined') originalPattern = ''; + // Getting special characters list. + let allow_special = event.target.getAttribute('data-allowSpecial'); + let pattern = event.target.pattern; + console.log(pattern.length); + let defaultPattern; + // Set default values for special characters. + if (!allow_special && allow_special === null) allow_special = ''; + // Format to string. + allow_special = allow_special.toString(); + if (pattern !== '' && pattern.length > 0 && pattern !== null) { + defaultPattern = pattern; + } else { + defaultPattern = '^[' + originalPattern + allow_special + ']+$'; + } + return defaultPattern; + }; + + /* + * To validate event with the pattern. + */ + validate(event, pattern) { + // Managing the Pattern. + let defaultPattern = this.getDefault(event, pattern); + // Validate with special formed pattern. + let regex = new RegExp(defaultPattern); + // Validation with Code. + let key = String.fromCharCode(!event.charCode ? event.which : event.charCode); + return regex.test(key); + }; +} +/** + * To Manage all kind of error response. + */ +class validationResponse { + constructor() { + this.active_class = false; + } + + /* + * Initiating the Response handler. + */ + init(errorList, option) { + this.errorMessage = option.message; + // Updating the class. + this.active_class = option.errorClass; + // let errorElements = option.errorElem; + // jsLogger.out('Errors', errorList); + this.input(errorList.input); + this.select(errorList.select); + this.textArea(errorList.textArea); + + }; + + /* + * To handle the "input" element. + */ + input(elem) { + // Initiate process for Input. + this.process(elem); + }; + + /* + * To handle the "select" element. + */ + select(elem) { + // Initiate process for Select. + this.process(elem); + }; + + /* + * To return active class for validation response style. + */ + getClass() { + return this.active_class; + }; + + /* + * To handle the "textArea" element. + */ + textArea(elem) { + // Initiate process for TextArea. + this.process(elem); + }; + + /* + * To process all handlers. + */ + process(elem) { + // Process with initial response. + let elementDefaultResponse = ''; + // Get active class for error response element + let active_class = this.getClass(); + for (let i in elem) { + // jsLogger.out('Element', document.getElementById(elem[i].id)); + if (elem[i].el && true === elem[i].el.required) { + // Manage active element. + let activeElem = elem[i]; + let errorType = elem[i].type; + // Fetch from Element's direct message. + elementDefaultResponse = this.template(activeElem, errorType); + let spanTag = document.getElementById(activeElem.id); + // jsLogger.out('Element Hit', errorType); + // Create new response Message SPAN. + if (typeof spanTag === 'undefined' || spanTag === 'undefined' || spanTag === null) { + // jsLogger.out('Element Found', false); + spanTag = document.createElement('span'); + spanTag.setAttribute('id', activeElem.id); + spanTag.setAttribute('class', active_class); + spanTag.innerHTML = elementDefaultResponse; + } else { + // Re-use Existing response Message SPAN. + spanTag.innerHTML = elementDefaultResponse; + } + // Append HTML response to the Element. + activeElem.el.parentNode.insertBefore(spanTag, activeElem.el.nextSibling); + } + } + }; + + /* + * Perform template creation and update. + */ + template(activeElem, errorType) { + //jsLogger.out('error Type 0', errorType); + let errorIndex = ''; + let activeError = ''; + // Getting error response message from elemnet. + let elementDefaultResponse = activeElem.el.getAttribute('data-message'); + if (typeof elementDefaultResponse === 'undefined' || elementDefaultResponse === '' || elementDefaultResponse === null) { + // Sanity check with error message object. + if (typeof this.errorMessage !== 'undefined' && typeof this.errorMessage[errorType] !== 'undefined') { + // Getting error type. [ex. Required, Min, Max...] + errorType = this.errorMessage[errorType]; + + // activeElem.el.getAttribute('data-message'); + if (errorType) { + //jsLogger.out('errorType', errorType); + activeError = errorType; + // If error type is Min or Max, then it will proceed responsive. + 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); + } + elementDefaultResponse = activeError; + } + return elementDefaultResponse; + }; + + /* + * Default error handling messages. + * If user not specify the messages, + * then it will be replaces. + */ + 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 false; + if (typeof errorMessages[errorType] === 'undefined') return false; + return errorMessages[errorType]; + }; +} \ No newline at end of file diff --git a/src/js/multi_formValidator.js b/src/js/multi_formValidator.js index 4b8aebd..0f5478f 100644 --- a/src/js/multi_formValidator.js +++ b/src/js/multi_formValidator.js @@ -24,6 +24,7 @@ * For Managing overall Validation flow. */ var firstErrorHit = false; +var __err_id_suffix_rand_hash = '_new1_1_1xv_resp'; /** * Core Js Validator. */ @@ -328,7 +329,7 @@ function jsFilter() { // To check is this action is from "windows" action or not. if (true === helper.isWindowAction(event)) return true; // Managing the Pattern. - var status = pattern.validate(event, 'a-zA-Z'); + var status = new pattern().validate(event, 'a-zA-Z'); // Return status of the Action. if (false === status) event.preventDefault(); }; @@ -541,9 +542,9 @@ function jsRuleSets() { log.push({ 'el': activeElem, 'type': 'required', - 'id': activeElem.name + '_new1_1_1xv_resp' + 'id': activeElem.name + __err_id_suffix_rand_hash }); - firstErrorHit = activeElem.name + '_new1_1_1xv_resp'; + firstErrorHit = activeElem.name + __err_id_suffix_rand_hash; } // To Check the Value is less than minimum or not. @@ -553,9 +554,9 @@ function jsRuleSets() { log.push({ 'el': activeElem, 'type': 'min', - 'id': activeElem.name + '_new1_1_1xv_resp' + 'id': activeElem.name + __err_id_suffix_rand_hash }); - firstErrorHit = activeElem.name + '_new1_1_1xv_resp'; + firstErrorHit = activeElem.name + __err_id_suffix_rand_hash; validElem = false; } } @@ -568,9 +569,9 @@ function jsRuleSets() { log.push({ 'el': activeElem, 'type': 'max', - 'id': activeElem.name + '_new1_1_1xv_resp' + 'id': activeElem.name + __err_id_suffix_rand_hash }); - firstErrorHit = activeElem.name + '_new1_1_1xv_resp'; + firstErrorHit = activeElem.name + __err_id_suffix_rand_hash; validElem = false; } } @@ -583,9 +584,9 @@ function jsRuleSets() { log.push({ 'el': activeElem, 'type': 'email', - 'id': activeElem.name + '_new1_1_1xv_resp' + 'id': activeElem.name + __err_id_suffix_rand_hash }); - firstErrorHit = activeElem.name + '_new1_1_1xv_resp'; + firstErrorHit = activeElem.name + __err_id_suffix_rand_hash; validElem = false; } } @@ -599,9 +600,9 @@ function jsRuleSets() { log.push({ 'el': activeElem, 'type': 'password', - 'id': activeElem.name + '_new1_1_1xv_resp' + 'id': activeElem.name + __err_id_suffix_rand_hash }); - firstErrorHit = activeElem.name + '_new1_1_1xv_resp'; + firstErrorHit = activeElem.name + __err_id_suffix_rand_hash; validElem = false; } } @@ -610,7 +611,7 @@ function jsRuleSets() { if (true === validElem) { //jsLogger.out('Valid Elem', activeElem); if (activeElem.name !== '') { - var elem = document.getElementById(activeElem.name + '_new1_1_1xv_resp'); + var elem = document.getElementById(activeElem.name + __err_id_suffix_rand_hash); if (typeof (elem) !== 'undefined' && elem !== null) { // Remove element to avoid un-necessary buffer. elem.remove(); @@ -849,7 +850,7 @@ var helper = { // Forming ID. var id = document.getElementsByClassName(active_class)[0].id; // Retrieve the element name. - var elem_name = active_id.replace('_new1_1_1xv_resp', ''); + var elem_name = active_id.replace(__err_id_suffix_rand_hash, ''); // Taking active element to navigate. var top = document.getElementsByName(elem_name)[0].offsetTop; // Format as ID.