1
0
mirror of synced 2024-11-22 13:26:06 +03:00
vue-formulario/src/formulate.js

116 lines
3.4 KiB
JavaScript

import FormulateGroup from './components/Formulate'
import FormulateElement from './components/FormulateElement'
import DefaultRules from './rules'
import DefaultErrors from './errors'
class Formulate {
/**
* Initialize vue-formulate.
*/
constructor () {
this.defaultOptions = {
registerComponents: true,
tags: {
Formulate: 'formulate',
FormulateElement: 'formulate-element'
},
errors: {},
rules: {},
vuexModule: false
}
this.errors = DefaultErrors
this.rules = DefaultRules
}
/**
* Install vue-formulate as an instance of Vue.
* @param {Vue} Vue
*/
install (Vue, options = {}) {
Vue.prototype.$formulate = this
options = Object.assign(this.defaultOptions, options)
if (options.registerComponents) {
Vue.component(options.tags.Formulate, FormulateGroup)
Vue.component(options.tags.FormulateElement, FormulateElement)
}
if (options.errors) {
this.errors = Object.assign(this.errors, options.errors)
}
if (options.rules) {
this.rules = Object.assign(this.rules, options.rules)
}
this.options = options
}
/**
* Given a string of rules parse them out to relevant pieces/parts
* @param {string} rulesString
*/
parseRules (rulesString) {
return rulesString.split('|')
.map(rule => rule.trim())
.map(rule => rule.match(/([a-zA-Z0-9]+)\((.*)?\)/) || [null, rule, ''])
.map(([ruleString, rule, args]) => Object.assign({}, {rule}, args ? {
args: args.split(',').map(arg => arg.trim())
} : {args: []}))
}
/**
* Return the function that generates a validation error message for a given
* validation rule.
* @param {string} rule
*/
errorFactory (rule) {
return this.errors[rule] ? this.errors[rule] : this.errors['default']
}
/**
* Given a particular field, value, validation rules, and form values
* perform asynchronous field validation.
* @param {Object} validatee
* @param {string} rulesString
* @param {Object} values
*/
async validationErrors ({field, value, label}, rulesString, values) {
return rulesString ? Promise.all(
this.parseRules(rulesString)
.map(({rule, args}) => {
if (typeof this.rules[rule] !== 'function') {
throw new Error(`Validation rule is invalid: ${rule}`)
}
return this.rules[rule]({field, value, label, error: this.errorFactory(rule), values}, ...args)
})
).then(responses => responses.reduce((errors, error) => {
return error ? (Array.isArray(errors) ? errors.concat(error) : [error]) : errors
}, false)) : false
}
}
const formulate = new Formulate()
export default formulate
export * from './store'
/**
* Mapper to allow bindings to the vuex store for custom fields.
* @param {Object} definitions
*/
export const mapModels = (definitions) => {
const models = {}
for (let mapTo in definitions) {
let [form, field] = definitions[mapTo].split('/')
models[mapTo] = {
set (value) {
let m = formulate.options.vuexModule ? `${formulate.options.vuexModule}/` : ''
this.$store.commit(`${m}setFieldValue`, {form, field, value})
},
get () {
let m = formulate.options.vuexModule ? `${formulate.options.vuexModule}/` : ''
if (this.$store.getters[`${m}formValues`][form]) {
return this.$store.getters[`${m}formValues`][form][field]
}
return ''
}
}
}
return models
}