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 }