dom-validator
Version:
Validator similar to vee-validator for vuetify Applications
354 lines (300 loc) • 11.5 kB
JavaScript
import Rules from './rules';
import MultipleElementRules from './multi-rules';
import { warn, isObject, getDataAttribute, getComponentType, ComponentTypes } from './utils';
import messages from './messages';
import {parseDateIntoString} from './utilities/date'
import {parseFloatLocale} from './utilities/number'
export default class Validator {
constructor (owner, options) {
this.scopes = {}
this.locale = options.locale
this.owner = owner
this.message_file_suffix = options.xs_small_messages ? '_xs' : '';
}
attach(fieldName, component, binding, type, scope = '__global__', siblings = [] ){
if(!isObject(this.scopes[scope])){
this.scopes[scope] = {}
}
this.scopes[scope][fieldName] = {
component: component,
binding: binding,
type: type,
siblings: siblings
}
}
detach(fieldName, scope = '__global__'){
if(isObject(this.scopes[scope]) && isObject(this.scopes[scope][fieldName])){
delete this.scopes[scope][fieldName];
}
}
validateAll(){
let promises = [];
var scopes = this.scopes;
for(let index1 in scopes){
let fieldNames = scopes[index1];
for(let index2 in fieldNames){
promises.push(this.validate(index2, index1))
}
}
return Promise.all(promises)
.then((result) => {
let resultx = {};
for(let index in result){
let el = result[index];
if(!el){
return false;
}else{
resultx[el.field] = this._parseValue(el.value, el.rules);
}
}
return {
data: resultx
};
})
}
validate(fieldName, scope = '__global__'){
if(!this.scopes[scope] || !this.scopes[scope][fieldName]){
warn("Validator.validate, no scope found!")
return;
}
let scopex = this.scopes[scope][fieldName];
let component = scopex.component;
let type = scopex.type
let siblings = scopex.siblings;
return this._validate(fieldName, type, component, scopex.binding, siblings, scope);
}
setErrors(errorsObj, scope = '__global__'){
let errors = errorsObj.errors;
for(let fieldName in errors){
let fieldErrorValues = errors[fieldName];
let scopex = this.scopes[scope][fieldName];
if(scopex){
let component = scopex.component;
this._setComponentForValidation(component, fieldErrorValues)
}
}
}
_validate(fieldName, componentTag, component, binding, siblings, scope){
return new Promise((resolve, refuse) => {
setTimeout(() => {
let otherComponentsInScope = this.scopes[scope];
let rules = this.getRules(binding.value)
let r = rules.rules
let errors = [];
let requiredController = this._checkForRequired(r, componentTag, component);
let mainValue = null;
for(let index in r){
let a = r[index];
let param = a && Array.isArray(a) && a.length > 0 ? (a.length > 1 ? a : a[0]) : a;
if(param instanceof RegExp){
param = [param];
}
let value = '';
let checkFunction = null;
let functionIndex = String(index).replace(/\*+$/g, '')
switch (componentTag){
case ComponentTypes.TEXT_FIELD:
value = component.lazyValue;
checkFunction = Rules[functionIndex];
break;
case ComponentTypes.SELECT:
let selectItemArray = component.selectedItems;
value = selectItemArray.length ? (isObject(selectItemArray[0]) ? selectItemArray[0][component.itemValue] : selectItemArray[0]) : '';
checkFunction = Rules[functionIndex]
break;
case ComponentTypes.CHECK_BOX:
value = component.inputValue;
checkFunction = MultipleElementRules[functionIndex]
break;
case ComponentTypes.RADIO:
value = component.inputValue;
checkFunction = MultipleElementRules[functionIndex]
break;
case ComponentTypes.SWITCH:
value = component.inputValue;
checkFunction = MultipleElementRules[functionIndex]
break;
default:
warn(`Validator.validate, ${componentTag} vuetify component not binded`)
}
if(requiredController && errors.length === 0 && !checkFunction(value, param, scope, otherComponentsInScope, this, fieldName, this.locale)){
this._addComponentToGlobalArray(component)
let fieldNamex = getDataAttribute(component.$el, 'as') ? getDataAttribute(component.$el, 'as') : fieldName;
let m = messages[this.locale ? this.locale + this.message_file_suffix : 'it_xs'];
if(!m){
m = messages['it_xs'];
}
let c = m[index]
if(!Array.isArray(param)){
param = [String(param)]
}
errors.push((c ? c: m['_default'])(fieldNamex, param))
}
mainValue = value;
}
let ctrl = errors.length === 0;
this._setComponentForValidation(component, errors);
if(!ctrl){
for(let index in siblings){
this._setComponentForValidation(siblings[index], ['']);
}
}else{
for(let index in siblings){
this._setComponentForValidation(siblings[index], []);
}
}
if(!ctrl){
resolve(ctrl)
}else{
resolve({
rules: r,
field: fieldName,
value: mainValue
});
}
})
})
}
_setComponentForValidation(component, errors){
let ctrl = errors.length > 0;
component.shouldValidate = ctrl;
component.errorBucket = errors;
component.$emit('update:error', ctrl)
}
_checkForRequired(rules, componentTag, component){
let value = '';
switch (componentTag){
case ComponentTypes.TEXT_FIELD:
value = component.lazyValue;
break;
case ComponentTypes.SELECT:
let selectItemArray = component.selectedItems;
value = selectItemArray.length ? selectItemArray[0][component.itemValue] : '';
break;
case ComponentTypes.CHECK_BOX:
value = component.inputValue;
break;
case ComponentTypes.RADIO:
value = component.inputValue;
break;
case ComponentTypes.SWITCH:
value = component.inputValue;
break;
default:
warn(`Validator._checkForRequired, ${componentTag} vuetify component not binded(2)`)
}
let ctrl = false;
for(let index in rules){
if(index === 'required' && rules[index]){
ctrl = true;
}
}
if(ctrl){
return true;
}else{
return value && String(value).trim() !== ''
}
}
getRules(validatorParam){
if(isObject(validatorParam)){
return validatorParam;
}
let rules = (validatorParam || '').split('|');
if(rules.length ===1 && rules[0].trim() === ''){
return {
rules: {}
}
}
let foundRules = [];
let validator = {};
for(let index in rules){
let rule = rules[index].split(':');
let params = true;
if(rule.length > 1){
params = rule[1].split(',');
}
let _rule = String(rule[0]);
let frls = '';
foundRules.filter((el) => el === _rule).forEach(() => frls += '*');
foundRules.push(_rule);
validator[rule[0] + frls] = params
}
return {
rules: validator
}
}
_parseValue(value, rules){
for(let index in rules){
let params = rules[index];
switch (index){
case 'decimal':
value = parseFloatLocale(value, this.locale);
break;
case 'decimal_en':
value = parseFloat(String(value).replace(',', ''))
break;
case 'numeric':
value = parseInt(String(value));
break;
case 'date':
value = parseDateIntoString(value, params, this.locale)
break;
}
}
return value;
}
scroll(offset = 130){
let components = this.owner.$root.$validator.globalValidationFailedComponentArray || [];
let pos = 1000000000;
let obj = null
for(let index in components){
let c = components[index];
let coords = this.getCoords(c.$el)
if(coords.top < pos){
pos = coords.top;
obj = c.$el
}
}
if(obj){
//window.scrollTo(0, pos - offset);
$('html, body').animate({
scrollTop: pos - offset
//$("#elementtoScrollToID").offset().top
}, 2000);
}
}
prepareForScroll(){
this.owner.$root.$validator.globalValidationFailedComponentArray = [];
}
getCoords(elem) { // crossbrowser version
var box = elem.getBoundingClientRect();
var body = document.body;
var docEl = document.documentElement;
var scrollTop = window.pageYOffset || docEl.scrollTop || body.scrollTop;
var scrollLeft = window.pageXOffset || docEl.scrollLeft || body.scrollLeft;
var clientTop = docEl.clientTop || body.clientTop || 0;
var clientLeft = docEl.clientLeft || body.clientLeft || 0;
var top = box.top + scrollTop - clientTop;
var left = box.left + scrollLeft - clientLeft;
return { top: Math.round(top), left: Math.round(left) };
}
_addComponentToGlobalArray(component){
if(!this.owner.$root.$validator.globalValidationFailedComponentArray){
this.owner.$root.$validator.globalValidationFailedComponentArray = [];
}
let a = this.owner.$root.$validator.globalValidationFailedComponentArray;
a.push(component)
}
_removeComponentFromGlobalArray(component){
if(!this.owner.$root.$validator.globalValidationFailedComponentArray){
return;
}
let a = this.owner.$root.$validator.globalValidationFailedComponentArray;
for(let index in a){
if(component === a[index]){
a.splice(index, 1);
return;
}
}
}
}