116 lines
3.4 KiB
JavaScript
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
|
||
|
}
|