1
0
mirror of synced 2024-11-22 05:16:05 +03:00

Adds new registry class

This commit is contained in:
Justin Schroeder 2020-04-22 00:00:02 -04:00
parent 978a209e3e
commit f7248d029c
15 changed files with 138 additions and 46 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

9
dist/snow.css vendored
View File

@ -28,7 +28,14 @@
line-height: 1.5;
margin-bottom: .25em; }
.formulate-input .formulate-input-group-item {
margin-bottom: .5em; }
margin-bottom: 1.5em;
padding: 1.5em;
border: 1px solid #efefef;
border-radius: .25em; }
.formulate-input .formulate-input-group-item:last-child {
margin-bottom: 1.5em;
border-bottom: 0;
padding-bottom: 0; }
.formulate-input:last-child {
margin-bottom: 0; }
.formulate-input[data-classification='text'] input {

2
dist/snow.min.css vendored

File diff suppressed because one or more lines are too long

View File

@ -2,7 +2,7 @@ import library from './libs/library'
import rules from './libs/rules'
import mimes from './libs/mimes'
import FileUpload from './FileUpload'
import { arrayify, parseLocale } from './libs/utils'
import { arrayify, parseLocale, has } from './libs/utils'
import isPlainObject from 'is-plain-object'
import { en } from '@braid/vue-formulate-i18n'
import fauxUploader from './libs/faux-uploader'
@ -210,7 +210,7 @@ class Formulate {
}
if (locale) {
const option = parseLocale(locale)
.find(locale => Object.prototype.hasOwnProperty.call(this.options.locales, locale))
.find(locale => has(this.options.locales, locale))
if (option) {
selection = option
}

View File

@ -12,7 +12,8 @@
</template>
<script>
import { shallowEqualObjects, arrayify } from './libs/utils'
import { shallowEqualObjects, arrayify, has } from './libs/utils'
import Registry from './libs/registry'
import FormSubmission from './FormSubmission'
export default {
@ -55,7 +56,7 @@ export default {
},
data () {
return {
registry: {},
registry: new Registry(),
internalFormModelProxy: {},
formShouldShowErrors: false,
errorObservers: [],
@ -87,13 +88,13 @@ export default {
},
initialValues () {
if (
Object.prototype.hasOwnProperty.call(this.$options.propsData, 'formulateValue') &&
has(this.$options.propsData, 'formulateValue') &&
typeof this.formulateValue === 'object'
) {
// If there is a v-model on the form, use those values as first priority
return Object.assign({}, this.formulateValue) // @todo - use a deep clone to detach reference types
} else if (
Object.prototype.hasOwnProperty.call(this.$options.propsData, 'values') &&
has(this.$options.propsData, 'values') &&
typeof this.values === 'object'
) {
// If there are values, use them as secondary priority
@ -135,9 +136,9 @@ export default {
typeof newValue === 'object'
) {
for (const field in newValue) {
if (this.registry.hasOwnProperty(field) &&
if (this.registry.has(field) &&
!shallowEqualObjects(newValue[field], this.internalFormModelProxy[field]) &&
!shallowEqualObjects(newValue[field], this.registry[field].internalModelProxy[field])
!shallowEqualObjects(newValue[field], this.registry.get(field).internalModelProxy[field])
) {
this.setFieldValue(field, newValue[field])
this.registry[field].context.model = newValue[field]
@ -184,7 +185,7 @@ export default {
this.errorObservers.push(observer)
if (observer.type === 'form') {
observer.callback(this.mergedFormErrors)
} else if (Object.prototype.hasOwnProperty.call(this.mergedFieldErrors, observer.field)) {
} else if (has(this.mergedFieldErrors, observer.field)) {
observer.callback(this.mergedFieldErrors[observer.field])
}
}
@ -196,21 +197,16 @@ export default {
Object.assign(this.internalFormModelProxy, { [field]: value })
this.$emit('input', Object.assign({}, this.internalFormModelProxy))
},
getUniqueRegistryName (base, count = 0) {
if (Object.prototype.hasOwnProperty.call(this.registry, base + (count || ''))) {
return this.getUniqueRegistryName(base, count + 1)
}
return base + (count || '')
},
register (field, component) {
// Don't re-register fields... @todo come up with another way of handling this that doesn't break multi option
if (Object.prototype.hasOwnProperty.call(this.registry, field)) {
if (this.registry.has(field)) {
return false
}
this.registry[field] = component
const hasVModelValue = Object.prototype.hasOwnProperty.call(component.$options.propsData, 'formulateValue')
const hasValue = Object.prototype.hasOwnProperty.call(component.$options.propsData, 'value')
this.registry.add(field, component)
const hasVModelValue = has(component.$options.propsData, 'formulateValue')
const hasValue = has(component.$options.propsData, 'value')
if (
!component.context.isSubField() &&
!hasVModelValue &&
this.hasInitialValue &&
this.initialValues[field]
@ -222,6 +218,8 @@ export default {
(hasVModelValue || hasValue) &&
!shallowEqualObjects(component.internalModelProxy, this.initialValues[field])
) {
// In this case, the field is v-modeled or has an initial value and the
// form has no value or a different value, so use the field value
this.setFieldValue(field, component.internalModelProxy)
}
},
@ -246,9 +244,9 @@ export default {
})
},
showErrors () {
for (const fieldName in this.registry) {
this.registry[fieldName].formShouldShowErrors = true
}
this.registry.map(input => {
input.formShouldShowErrors = true
})
},
getFormValues () {
return this.internalFormModelProxy
@ -257,13 +255,10 @@ export default {
this.$emit('validation', errorObject)
},
hasValidationErrors () {
const resolvers = []
for (const fieldName in this.registry) {
if (typeof this.registry[fieldName].getValidationErrors === 'function') {
resolvers.push(this.registry[fieldName].getValidationErrors())
}
}
return Promise.all(resolvers).then((errorObjects) => {
return Promise.all(this.registry.reduce((resolvers, cmp, name) => {
resolvers.push(cmp.getValidationErrors())
return resolvers
}, [])).then((errorObjects) => {
return errorObjects.some(item => item.hasErrors)
})
}

View File

@ -35,7 +35,8 @@ export default {
provide () {
return {
formulateFormSetter: this.setFieldValue,
formulateFormRegister: this.register
formulateFormRegister: this.register,
isSubField: () => true
}
},
computed: {
@ -63,7 +64,7 @@ export default {
))
this.context.model = values
},
register () {
register (field, component) {
}
}

View File

@ -67,7 +67,7 @@
<script>
import context from './libs/context'
import { shallowEqualObjects, parseRules, snakeToCamel, arrayify } from './libs/utils'
import { shallowEqualObjects, parseRules, snakeToCamel, arrayify, has } from './libs/utils'
import nanoid from 'nanoid/non-secure'
export default {
@ -79,7 +79,8 @@ export default {
formulateFormRegister: { default: undefined },
getFormValues: { default: () => () => ({}) },
observeErrors: { default: undefined },
removeErrorObserver: { default: undefined }
removeErrorObserver: { default: undefined },
isSubField: { default: () => () => false }
},
model: {
prop: 'formulateValue',
@ -290,9 +291,9 @@ export default {
classification = (classification === 'box' && this.options) ? 'group' : classification
if (classification === 'box' && this.checked) {
return this.value || true
} else if (Object.prototype.hasOwnProperty.call(this.$options.propsData, 'value') && classification !== 'box') {
} else if (has(this.$options.propsData, 'value') && classification !== 'box') {
return this.value
} else if (Object.prototype.hasOwnProperty.call(this.$options.propsData, 'formulateValue')) {
} else if (has(this.$options.propsData, 'formulateValue')) {
return this.formulateValue
}
return ''

View File

@ -58,6 +58,7 @@ export default {
component,
hasLabel,
slotComponents,
isSubField,
...context
} = this.context
return this.options.map(option => this.groupItemContext(

View File

@ -37,6 +37,7 @@ export default {
validationErrors: this.validationErrors,
value: this.value,
visibleValidationErrors: this.visibleValidationErrors,
isSubField: this.isSubField,
...this.typeContext
})
},

69
src/libs/registry.js Normal file
View File

@ -0,0 +1,69 @@
/**
* Component registry with inherent depth to handle complex nesting. This is
* important for features such as grouped fields.
*/
class Registry {
/**
* Create a new registry of components.
*/
constructor () {
this.registry = new Map()
}
/**
* Add an item to the registry.
* @param {string|array} key
* @param {vue} component
*/
add (name, component) {
this.registry.set(name, component)
return this
}
/**
* Remove an item from the registry.
* @param {string} name
*/
remove (name) {
this.registry.delete(name)
return this
}
/**
* Check if the registry has the given key.
* @param {string|array} key
*/
has (key) {
return this.registry.has(key)
}
/**
* Map over the registry (recursively).
* @param {function} callback
*/
map (callback) {
const value = {}
this.registry.forEach((component, field) => Object.assign(value, { [field]: callback(component, field) }))
return value
}
/**
* Return the keys of the registry.
*/
keys () {
return Array.from(this.registry.keys())
}
/**
* Reduce the registry.
* @param {function} callback
*/
reduce (callback, accumulator) {
this.registry.forEach((component, field) => {
accumulator = callback(accumulator, component, field)
})
return accumulator
}
}
export default Registry

View File

@ -206,3 +206,18 @@ export function parseLocale (locale) {
return options.length ? options : [segment]
}, [])
}
/**
* Shorthand for Object.prototype.hasOwnProperty.call (space saving)
*/
export function has (ctx, prop) {
return Object.prototype.hasOwnProperty.call(ctx, prop)
}
/**
* Given a registry object, map over it recursively entering groups.
* @param {Object} registry key => component
*/
export function mapRegistry (registry) {
//
}

View File

@ -1,8 +1,10 @@
<template>
<div class="formulate-input-group-add-more">
<button @click="$emit('add')">
Add more
</button>
<FormulateInput
type="button"
label="Add more"
@click.native="$emit('add')"
/>
</div>
</template>

View File

@ -42,7 +42,7 @@ describe('FormulateForm', () => {
propsData: { formulateValue: { testinput: 'has initial value' } },
slots: { default: '<FormulateInput type="text" name="subinput1" /><FormulateInput type="checkbox" name="subinput2" />' }
})
expect(Object.keys(wrapper.vm.registry)).toEqual(['subinput1', 'subinput2'])
expect(wrapper.vm.registry.keys()).toEqual(['subinput1', 'subinput2'])
})
it('can set a fields initial value', async () => {