2019-10-07 17:24:30 +03:00
|
|
|
<template>
|
|
|
|
<div
|
|
|
|
class="formulate-input"
|
|
|
|
:data-classification="classification"
|
2019-11-07 01:17:19 +03:00
|
|
|
:data-has-errors="hasErrors"
|
2019-11-14 00:10:17 +03:00
|
|
|
:data-is-showing-errors="hasErrors && showFieldErrors"
|
2019-10-07 17:24:30 +03:00
|
|
|
:data-type="type"
|
|
|
|
>
|
|
|
|
<div class="formulate-input-wrapper">
|
|
|
|
<slot
|
2020-01-28 20:12:08 +03:00
|
|
|
v-if="context.hasLabel && context.labelPosition === 'before'"
|
2019-10-07 17:24:30 +03:00
|
|
|
name="label"
|
|
|
|
v-bind="context"
|
|
|
|
>
|
|
|
|
<label
|
|
|
|
class="formulate-input-label formulate-input-label--before"
|
2019-10-08 20:50:53 +03:00
|
|
|
:for="context.attributes.id"
|
2019-10-07 17:24:30 +03:00
|
|
|
v-text="context.label"
|
|
|
|
/>
|
|
|
|
</slot>
|
2020-01-28 20:12:08 +03:00
|
|
|
<slot
|
|
|
|
name="element"
|
|
|
|
v-bind="context"
|
|
|
|
>
|
2019-10-07 17:24:30 +03:00
|
|
|
<component
|
|
|
|
:is="context.component"
|
|
|
|
:context="context"
|
2020-01-28 20:12:08 +03:00
|
|
|
>
|
|
|
|
<slot v-bind="context" />
|
|
|
|
</component>
|
2019-10-07 17:24:30 +03:00
|
|
|
</slot>
|
|
|
|
<slot
|
2020-01-28 20:12:08 +03:00
|
|
|
v-if="context.hasLabel && context.labelPosition === 'after'"
|
2019-10-07 17:24:30 +03:00
|
|
|
name="label"
|
|
|
|
v-bind="context.label"
|
|
|
|
>
|
|
|
|
<label
|
|
|
|
class="formulate-input-label formulate-input-label--after"
|
2019-10-08 20:50:53 +03:00
|
|
|
:for="context.attributes.id"
|
2019-10-07 17:24:30 +03:00
|
|
|
v-text="context.label"
|
|
|
|
/>
|
|
|
|
</slot>
|
|
|
|
</div>
|
|
|
|
<div
|
|
|
|
v-if="help"
|
|
|
|
class="formulate-input-help"
|
|
|
|
v-text="help"
|
|
|
|
/>
|
2019-11-07 01:17:19 +03:00
|
|
|
<FormulateInputErrors
|
2019-11-14 00:10:17 +03:00
|
|
|
v-if="showFieldErrors"
|
2019-11-07 01:17:19 +03:00
|
|
|
:errors="mergedErrors"
|
|
|
|
/>
|
2019-10-07 17:24:30 +03:00
|
|
|
</div>
|
|
|
|
</template>
|
|
|
|
|
|
|
|
<script>
|
|
|
|
import context from './libs/context'
|
2019-11-08 01:03:34 +03:00
|
|
|
import { shallowEqualObjects, parseRules } from './libs/utils'
|
2019-10-07 17:24:30 +03:00
|
|
|
import nanoid from 'nanoid'
|
|
|
|
|
|
|
|
export default {
|
|
|
|
name: 'FormulateInput',
|
|
|
|
inheritAttrs: false,
|
2019-10-09 06:54:16 +03:00
|
|
|
inject: {
|
|
|
|
formulateFormSetter: { default: undefined },
|
2019-11-14 00:10:17 +03:00
|
|
|
formulateFormRegister: { default: undefined },
|
|
|
|
getFormValues: { default: () => () => ({}) }
|
2019-10-09 06:54:16 +03:00
|
|
|
},
|
2019-10-07 17:24:30 +03:00
|
|
|
model: {
|
|
|
|
prop: 'formulateValue',
|
|
|
|
event: 'input'
|
|
|
|
},
|
|
|
|
props: {
|
|
|
|
type: {
|
|
|
|
type: String,
|
|
|
|
default: 'text'
|
|
|
|
},
|
2019-10-09 06:54:16 +03:00
|
|
|
name: {
|
2020-01-29 00:53:13 +03:00
|
|
|
type: [String, Boolean],
|
2019-10-09 06:54:16 +03:00
|
|
|
default: true
|
|
|
|
},
|
|
|
|
/* eslint-disable */
|
2019-10-07 17:24:30 +03:00
|
|
|
formulateValue: {
|
2019-10-30 06:33:31 +03:00
|
|
|
default: ''
|
2019-10-07 17:24:30 +03:00
|
|
|
},
|
|
|
|
value: {
|
|
|
|
default: false
|
|
|
|
},
|
2019-10-09 06:54:16 +03:00
|
|
|
/* eslint-enable */
|
2019-10-07 17:24:30 +03:00
|
|
|
options: {
|
|
|
|
type: [Object, Array, Boolean],
|
|
|
|
default: false
|
|
|
|
},
|
|
|
|
optionGroups: {
|
|
|
|
type: [Object, Boolean],
|
|
|
|
default: false
|
|
|
|
},
|
|
|
|
id: {
|
|
|
|
type: [String, Boolean, Number],
|
2019-10-08 20:50:53 +03:00
|
|
|
default: false
|
2019-10-07 17:24:30 +03:00
|
|
|
},
|
|
|
|
label: {
|
|
|
|
type: [String, Boolean],
|
|
|
|
default: false
|
|
|
|
},
|
|
|
|
labelPosition: {
|
|
|
|
type: [String, Boolean],
|
|
|
|
default: false
|
|
|
|
},
|
|
|
|
help: {
|
|
|
|
type: [String, Boolean],
|
|
|
|
default: false
|
2019-10-08 20:50:53 +03:00
|
|
|
},
|
|
|
|
debug: {
|
|
|
|
type: Boolean,
|
|
|
|
default: false
|
2019-11-07 01:17:19 +03:00
|
|
|
},
|
|
|
|
errors: {
|
|
|
|
type: [String, Array, Boolean],
|
|
|
|
default: false
|
|
|
|
},
|
|
|
|
validation: {
|
|
|
|
type: [String, Boolean, Array],
|
|
|
|
default: false
|
|
|
|
},
|
2019-11-14 00:10:17 +03:00
|
|
|
validationName: {
|
|
|
|
type: [String, Boolean],
|
|
|
|
default: false
|
|
|
|
},
|
|
|
|
error: {
|
|
|
|
type: [String, Boolean],
|
|
|
|
default: false
|
|
|
|
},
|
|
|
|
errorBehavior: {
|
2019-11-07 01:17:19 +03:00
|
|
|
type: String,
|
|
|
|
default: 'blur',
|
|
|
|
validator: function (value) {
|
|
|
|
return ['blur', 'live'].includes(value)
|
|
|
|
}
|
|
|
|
},
|
2019-11-14 00:10:17 +03:00
|
|
|
showErrors: {
|
|
|
|
type: Boolean,
|
2019-11-07 01:17:19 +03:00
|
|
|
default: false
|
2019-11-15 22:44:01 +03:00
|
|
|
},
|
2019-11-21 08:29:28 +03:00
|
|
|
imageBehavior: {
|
|
|
|
type: String,
|
|
|
|
default: 'preview'
|
2019-11-15 22:44:01 +03:00
|
|
|
},
|
|
|
|
uploadUrl: {
|
|
|
|
type: [String, Boolean],
|
|
|
|
default: false
|
|
|
|
},
|
|
|
|
uploader: {
|
|
|
|
type: [Function, Object, Boolean],
|
|
|
|
default: false
|
|
|
|
},
|
2019-11-19 15:15:13 +03:00
|
|
|
uploadBehavior: {
|
2019-11-21 07:16:31 +03:00
|
|
|
type: String,
|
|
|
|
default: 'live'
|
2019-11-19 15:15:13 +03:00
|
|
|
},
|
|
|
|
preventWindowDrops: {
|
2019-11-15 22:44:01 +03:00
|
|
|
type: Boolean,
|
|
|
|
default: true
|
2019-10-08 20:50:53 +03:00
|
|
|
}
|
|
|
|
},
|
|
|
|
data () {
|
|
|
|
return {
|
2020-01-28 20:12:08 +03:00
|
|
|
/**
|
|
|
|
* @todo consider swapping out nanoid for this._uid
|
|
|
|
*/
|
2019-10-08 20:50:53 +03:00
|
|
|
defaultId: nanoid(9),
|
2019-10-30 06:33:31 +03:00
|
|
|
localAttributes: {},
|
2019-11-08 01:03:34 +03:00
|
|
|
internalModelProxy: this.formulateValue,
|
2019-11-14 00:10:17 +03:00
|
|
|
behavioralErrorVisibility: (this.errorBehavior === 'live'),
|
2020-01-29 00:53:13 +03:00
|
|
|
formShouldShowErrors: false,
|
2019-11-21 07:16:31 +03:00
|
|
|
validationErrors: [],
|
|
|
|
pendingValidation: Promise.resolve()
|
2019-10-07 17:24:30 +03:00
|
|
|
}
|
|
|
|
},
|
|
|
|
computed: {
|
2019-10-08 20:50:53 +03:00
|
|
|
...context,
|
2019-10-07 17:24:30 +03:00
|
|
|
classification () {
|
|
|
|
const classification = this.$formulate.classify(this.type)
|
|
|
|
return (classification === 'box' && this.options) ? 'group' : classification
|
|
|
|
},
|
|
|
|
component () {
|
2019-10-08 20:50:53 +03:00
|
|
|
return (this.classification === 'group') ? 'FormulateInputGroup' : this.$formulate.component(this.type)
|
|
|
|
}
|
|
|
|
},
|
|
|
|
watch: {
|
|
|
|
'$attrs': {
|
|
|
|
handler (value) {
|
|
|
|
this.updateLocalAttributes(value)
|
|
|
|
},
|
|
|
|
deep: true
|
2019-10-30 06:33:31 +03:00
|
|
|
},
|
|
|
|
internalModelProxy (newValue, oldValue) {
|
2019-11-08 01:03:34 +03:00
|
|
|
this.performValidation()
|
2019-10-30 06:33:31 +03:00
|
|
|
if (!this.isVmodeled && !shallowEqualObjects(newValue, oldValue)) {
|
|
|
|
this.context.model = newValue
|
|
|
|
}
|
|
|
|
},
|
|
|
|
formulateValue (newValue, oldValue) {
|
|
|
|
if (this.isVmodeled && !shallowEqualObjects(newValue, oldValue)) {
|
|
|
|
this.context.model = newValue
|
|
|
|
}
|
2019-10-08 20:50:53 +03:00
|
|
|
}
|
|
|
|
},
|
|
|
|
created () {
|
2019-10-09 06:54:16 +03:00
|
|
|
if (this.formulateFormRegister && typeof this.formulateFormRegister === 'function') {
|
2019-10-30 06:33:31 +03:00
|
|
|
this.formulateFormRegister(this.nameOrFallback, this)
|
2019-10-09 06:54:16 +03:00
|
|
|
}
|
2019-10-08 20:50:53 +03:00
|
|
|
this.updateLocalAttributes(this.$attrs)
|
2019-11-08 01:03:34 +03:00
|
|
|
this.performValidation()
|
2019-10-08 20:50:53 +03:00
|
|
|
},
|
|
|
|
methods: {
|
|
|
|
updateLocalAttributes (value) {
|
|
|
|
if (!shallowEqualObjects(value, this.localAttributes)) {
|
|
|
|
this.localAttributes = value
|
|
|
|
}
|
2019-11-08 01:03:34 +03:00
|
|
|
},
|
|
|
|
performValidation () {
|
|
|
|
const rules = parseRules(this.validation, this.$formulate.rules())
|
2019-11-21 07:16:31 +03:00
|
|
|
this.pendingValidation = Promise.all(
|
2019-11-08 01:03:34 +03:00
|
|
|
rules.map(([rule, args]) => {
|
|
|
|
return rule(this.context.model, ...args)
|
2019-11-14 00:10:17 +03:00
|
|
|
.then(res => res ? false : this.$formulate.validationMessage(rule.name, {
|
|
|
|
args,
|
|
|
|
name: this.mergedValidationName,
|
|
|
|
value: this.context.model,
|
|
|
|
vm: this,
|
|
|
|
formValues: this.getFormValues()
|
|
|
|
}))
|
2019-11-08 01:03:34 +03:00
|
|
|
})
|
|
|
|
)
|
|
|
|
.then(result => result.filter(result => result))
|
2019-11-21 08:29:28 +03:00
|
|
|
.then(errorMessages => { this.validationErrors = errorMessages })
|
2019-11-21 07:16:31 +03:00
|
|
|
return this.pendingValidation
|
|
|
|
},
|
|
|
|
hasValidationErrors () {
|
|
|
|
return new Promise(resolve => {
|
|
|
|
this.$nextTick(() => {
|
|
|
|
this.pendingValidation.then(() => resolve(!!this.validationErrors.length))
|
|
|
|
})
|
|
|
|
})
|
2019-10-07 17:24:30 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
</script>
|