univalid-strategy-form
Version:
Form strategy implementation for univalid module (extends 'univalid-strategy')
287 lines (246 loc) • 8.57 kB
JavaScript
'use strict';
const {checkOption, checkSelector, collectNodes, collectPackage, setResult} = require('./lib/univalid-strategy-form-services');
const UnivalidStrategy = require('univalid-strategy');
const keyLogger = require('univalid-key-logger')();
const {passScore} = require('pass-power');
const axios = require('axios');
const serialize = require('form-serialize');
module.exports = (opt) => {
let _controller = {
submit(){
this.$form.addEventListener('submit', e => {
e.preventDefault();
this.core.emit('e:submit', this.core, e);
this.core.check(collectNodes(this.$form));
if(this.core.getCommonState === 'success'){
this.send();
}
}, false);
},
blur(){
if(this.keyLogger){
let inputs = collectNodes(this.$form);
inputs.forEach(input => {
input.addEventListener('blur', e => {
this.core.emit('e:blur', this.core, e);
var elem = e.target,
val = elem.value,
tag = elem.tagName,
type = elem.type,
validType = elem.getAttribute('data-f');
if(val && tag === 'INPUT' && type === 'text'){
if(keyLogger.logXss(val)){
this.clearInputs(elem);
}
if(validType){
if(!keyLogger.applyFilter(validType, val)){
this.core.check([elem]);
}
}
}
});
});
}
},
focus(){
collectNodes(this.$form)
.forEach(elem => {
elem.addEventListener('focus', e => {
this.core.emit('e:focus', this.core, e);
this.clearStatuses([e.target]);
}, false);
});
},
keyup(){
if(this.keyLogger){
let inputs = collectNodes(this.$form);
inputs.forEach(input => {
input.addEventListener('keyup', e => {
this.core.emit('e:keyup', this.core, e);
if(e.key !== 'Tab'){
let elem = e.target,
val = elem.value,
validType = elem.getAttribute('data-f');
if(!keyLogger.applyFilter(validType, val)){
this.core.check([elem]);
return false;
}else{
this.clearStatuses([e.target]);
}
}
});
});
}
if(this.checkPassScore){
if(this.checkPassScore.target){
this.$form.querySelector(this.checkPassScore.target).addEventListener('keyup', e => {
this.checkPassScore.cb && this.checkPassScore.cb(passScore(e.target.value, this.passConfig.min, this.passConfig.analysis).power);
});
}
}
}
};
class UnivalidStrategyForm extends UnivalidStrategy {
constructor(opt){
super();
if(opt){
if(!opt.core){
return console.warn(new Error("Don't finded the 'core' field during initialized UnivalidStrategyForm. This filed is required. See more to link ..."));
}
//Required props
this.core = opt.core;
this.$form = checkSelector(
checkOption('$form', opt.$form, 'string', true, err => this.core.emit('error', err)),
true,
err => this.core.emit('error', err)
);
if(!this.$form)
return;
//Option props
this.clsConfig = checkOption('clsConfig', opt.clsConfig, 'object', false, err => this.core.emit('error', err)) || {error: 'error', success: 'success'};
this.passConfig = checkOption('passConfig', opt.passConfig, 'object', false, err => this.core.emit('error', err)) || {min: 6, analysis: ['hasUppercase', 'hasLowercase', 'hasDigits', 'hasSpecials']};
this.statusConfig = checkOption('statusConfig', opt.statusConfig, 'object', false, err => this.core.emit('error', err));
this.sendConfig = checkOption('sendConfig', opt.sendConfig, 'object', false, err => this.core.emit('error', err));
this.keyLogger = checkOption('keyLogger', opt.keyLogger, 'boolean', false, err => this.core.emit('error', err));
this.checkPassScore = checkOption('checkPassScore', opt.checkPassScore, 'object', false, err => this.core.emit('error', err));
this.controller();
}else{
return console.warn(new Error("Don't finded the 'core' field during initialized UnivalidStrategyForm. This filed is required. See more to link ..."));
}
}
clearStatuses(pack){
this.core.emit('clear:statuses', this.core, pack);
this.$form.classList.remove(`${this.clsConfig.error}`, `${this.clsConfig.success}`);
if(!this.statusConfig || !this.statusConfig.targetParent){
return this.core.emit('error', 'Not determined "statusConfig" property in UnivalidStrategyForm. Can`t clear statuses');
}
let relevantPack = pack ? pack : collectNodes(this.$form);
relevantPack.forEach(elem => {
let parent = elem.closest(this.statusConfig.targetParent),
statusContainer = parent.querySelector(this.statusConfig.targetStatus);
parent.classList.remove(this.clsConfig.error, this.clsConfig.success);
elem.classList.remove(this.clsConfig.error, this.clsConfig.success);
if(statusContainer){
statusContainer.innerText = '';
}
});
}
send({
newAjaxBody = this.sendConfig || {},
cbSendSuccess = this.sendConfig ? this.sendConfig.cbSendSuccess : null,
cbSendError = this.sendConfig ? this.sendConfig.cbSendError : null,
} = {}){
if(newAjaxBody){
this.core.emit('send:form', this.core);
let type = !newAjaxBody.type ? this.$form.getAttribute('method') : newAjaxBody.type,
url = !newAjaxBody.url ? this.$form.getAttribute('action') : newAjaxBody.url,
data = !newAjaxBody.data ? serialize(this.$form, {hash: true}) : newAjaxBody.data,
notDisableSubmit = newAjaxBody.notDisableSubmit;
let $submit = this.$form.querySelector('[type="submit"]');
$submit && !notDisableSubmit ? $submit['disabled'] = true : null;
if(!type){
return this.core.emit('error', 'Http Method is not defined. Define it in attributes "send" method or html attribute of form "method"');
}
if(!url){
return this.core.emit('error', 'Url to send is not defined. Define it in attributes "send" method or html attribute of form "action"');
}
axios[type.toLowerCase()](url, data)
.then(res => {
$submit && !notDisableSubmit ? $submit['disabled'] = false : null;
this.clearInputs();
cbSendSuccess && cbSendSuccess(res, this);
})
.catch(err => {
$submit && !notDisableSubmit ? $submit['disabled'] = false : null;
cbSendError && cbSendError(err, this);
})
}
}
check(pack = collectNodes(this.$form)){
this.core.clearState();
let packageValidation = collectPackage(pack, this.$form, err => this.core.emit('error', err));
for(let i = 0; i < packageValidation.length; i++){
this.core.validate(packageValidation[i]);
}
this.clearStatuses(pack);
this.setStatuses(this.core.getState);
}
clearInputs(inputs){
this.core.emit('clear:inputs', this.core);
if(!inputs){
this.$form.reset();
}else{
if(inputs.length > 1){
inputs.forEach(elem => caseInput(elem));
}else{
caseInput(inputs);
}
}
function caseInput(elem){
elem = elem.length && elem.tagName !== 'SELECT' ? elem[0] : elem;
let tag = elem.tagName,
type = elem.getAttribute('type');
if(tag == 'INPUT' && type !== 'radio' && type !== 'checkbox'){
elem.value = '';
}else if(type == 'radio' || type == 'checkbox'){
elem['checked'] = false;
}else if(tag == 'SELECT'){
if(!elem.multiple){
elem.options[0]['selected'] = true;
}else{
for(let i = 0; i < elem.options.length; i++){
elem.options[i]['selected'] = false;
}
}
}
}
}
setStatuses(data){
Array.isArray(data) && data.length &&
setResult(data, this, err => this.core.emit('error', err));
}
addEvent(events){
if(events){
for(var e in events){
if(_controller[e]){
return this.core.emit('error', 'This event name is already exist');
}else{
_controller[e] = events[e];
this.controller(e);
}
}
}
}
disable(){
collectNodes(this.$form)
.forEach(elem => {
elem.disabled = true;
});
}
enable(){
collectNodes(this.$form)
.forEach(elem => {
elem.disabled = false;
});
}
getValidationHandlers(){
return this.validHandlers;
}
set(option, val){
this[option] = val;
}
get(val){
return this[val];
}
controller(event){
if(event){
_controller[event].call(this);
}else{
for(let e in _controller){
_controller[e].call(this);
}
}
}
}
return new UnivalidStrategyForm(opt);
};