1
0
mirror of synced 2024-12-01 17:46:07 +03:00
vue-formulario/src/components/FormulateElement.vue

422 lines
11 KiB
Vue
Raw Normal View History

2018-01-31 01:21:21 +03:00
<template>
2018-02-01 01:20:29 +03:00
<div :class="classes">
<slot name="prefix" />
<div
class="formulate-element-input-wrapper"
:data-type="type"
:data-classification="classification"
:data-is-disabled="disabled"
>
2018-01-31 01:21:21 +03:00
<!-- TEXT STYLE INPUTS -->
<label
:for="id"
v-text="label"
2018-02-01 01:20:29 +03:00
v-if="label && (!isBoxInput || optionList.length > 1)"
2018-01-31 01:21:21 +03:00
/>
<input
ref="input"
:class="elementClasses"
2018-01-31 01:21:21 +03:00
:type="type"
:name="name"
v-model="val"
2018-02-01 01:20:29 +03:00
v-bind="attributes"
2018-01-31 01:21:21 +03:00
v-if="isTextInput"
@blur="setBlurState"
@focus="setFocusState"
:disabled="disabled"
2018-10-16 06:21:31 +03:00
:step="step"
2018-01-31 01:21:21 +03:00
>
2018-03-30 21:51:47 +03:00
<textarea
ref="textarea"
:class="elementClasses"
:type="type"
:name="name"
v-model="val"
v-bind="attributes"
v-if="isTextareaInput"
@blur="setBlurState"
@focus="setFocusState"
:disabled="disabled"
2018-03-30 21:51:47 +03:00
/>
2018-01-31 01:21:21 +03:00
<!-- BUTTON INPUTS -->
<button
:type="type"
:class="elementClasses"
2018-01-31 01:21:21 +03:00
v-if="isButtonInput"
:disabled="disabled || (type === 'submit' && (form.hasErrors && form.behavior === 'live'))"
>
<slot
v-if="$slots.button"
name="button"
/>
<span
v-text="label || name"
v-else
/>
</button>
2018-01-31 01:21:21 +03:00
<!-- SELECT INPUTS -->
2018-02-01 01:20:29 +03:00
<select
v-bind="attributes"
v-if="isSelectInput"
:class="elementClasses"
2018-02-01 01:20:29 +03:00
:name="name"
v-model="val"
@blur="setBlurState"
@focus="setFocusState"
:disabled="disabled"
2018-02-01 01:20:29 +03:00
>
<option
v-for="option in optionList"
:value="option.value"
:key="option.id"
v-bind="option.attributes || {}"
2018-02-01 01:20:29 +03:00
v-text="option.label"
/>
</select>
<!-- BOX INPUTS -->
<div
2018-05-19 06:47:14 +03:00
class="formulate-element-box-input-wrap"
2018-02-01 01:20:29 +03:00
v-if="isBoxInput"
>
2018-05-19 06:47:14 +03:00
<div
class="formulate-element-box-input-group"
v-for="option in optionList"
:key="option.id"
>
2018-02-01 01:20:29 +03:00
<input
type="radio"
:class="elementClasses"
2018-02-01 01:20:29 +03:00
:name="name"
:id="option.id"
:value="option.value"
:key="`${option.id}-input`"
v-bind="attributes"
v-model="val"
v-if="type === 'radio'"
@blur="setBlurState"
@focus="setFocusState"
:disabled="disabled"
2018-02-01 01:20:29 +03:00
>
<input
type="checkbox"
:class="elementClasses"
2018-02-01 01:20:29 +03:00
:name="name"
:id="option.id"
:value="option.value"
:key="`${option.id}-input`"
v-bind="attributes"
v-model="val"
v-if="type === 'checkbox'"
@blur="setBlurState"
@focus="setFocusState"
:disabled="disabled"
2018-02-01 01:20:29 +03:00
>
<label
:for="option.id"
:key="`${option.id}-label`"
v-text="option.label"
/>
2018-05-19 06:47:14 +03:00
</div>
2018-02-01 01:20:29 +03:00
</div>
2018-01-31 01:21:21 +03:00
<!-- CUSTOM SLOT INPUTS -->
<slot v-if="hasCustomInput" />
2018-02-01 01:20:29 +03:00
<!-- UNSUPPORTED INPUT -->
2018-02-01 01:20:29 +03:00
<div
style="background-color: red; color: white"
v-if="isUnsupportedInput"
v-text="`Unsupported field type: “${type}”.`"
/>
2018-01-31 01:21:21 +03:00
</div>
New Feature: FormulateElement now supports help text via the new GNU bash, version 3.2.57(1)-release (x86_64-apple-darwin17) These shell commands are defined internally. Type `help' to see this list. Type `help name' to find out more about the function `name'. Use `info bash' to find out more about the shell in general. Use `man -k' or `info' to find out more about commands not in this list. A star (*) next to a name means that the command is disabled. JOB_SPEC [&] (( expression )) . filename [arguments] : [ arg... ] [[ expression ]] alias [-p] [name[=value] ... ] bg [job_spec ...] bind [-lpvsPVS] [-m keymap] [-f fi break [n] builtin [shell-builtin [arg ...]] caller [EXPR] case WORD in [PATTERN [| PATTERN]. cd [-L|-P] [dir] command [-pVv] command [arg ...] compgen [-abcdefgjksuv] [-o option complete [-abcdefgjksuv] [-pr] [-o continue [n] declare [-afFirtx] [-p] [name[=val dirs [-clpv] [+N] [-N] disown [-h] [-ar] [jobspec ...] echo [-neE] [arg ...] enable [-pnds] [-a] [-f filename] eval [arg ...] exec [-cl] [-a name] file [redirec exit [n] export [-nf] [name[=value] ...] or false fc [-e ename] [-nlr] [first] [last fg [job_spec] for NAME [in WORDS ... ;] do COMMA for (( exp1; exp2; exp3 )); do COM function NAME { COMMANDS ; } or NA getopts optstring name [arg] hash [-lr] [-p pathname] [-dt] [na help [-s] [pattern ...] history [-c] [-d offset] [n] or hi if COMMANDS; then COMMANDS; [ elif jobs [-lnprs] [jobspec ...] or job kill [-s sigspec | -n signum | -si let arg [arg ...] local name[=value] ... logout popd [+N | -N] [-n] printf [-v var] format [arguments] pushd [dir | +N | -N] [-n] pwd [-LP] read [-ers] [-u fd] [-t timeout] [ readonly [-af] [name[=value] ...] return [n] select NAME [in WORDS ... ;] do CO set [--abefhkmnptuvxBCHP] [-o opti shift [n] shopt [-pqsu] [-o long-option] opt source filename [arguments] suspend [-f] test [expr] time [-p] PIPELINE times trap [-lp] [arg signal_spec ...] true type [-afptP] name [name ...] typeset [-afFirtx] [-p] name[=valu ulimit [-SHacdfilmnpqstuvx] [limit umask [-p] [-S] [mode] unalias [-a] name [name ...] unset [-f] [-v] [name ...] until COMMANDS; do COMMANDS; done variables - Some variable names an wait [n] while COMMANDS; do COMMANDS; done { COMMANDS ; } prop
2018-05-18 21:46:04 +03:00
<div
class="formulate-help"
v-if="help"
v-text="help"
/>
<transition
name="formulate-errors"
2018-01-31 01:21:21 +03:00
>
<transition-group
tag="ul"
name="formulate-error-list"
class="formulate-errors"
v-if="shouldShowErrors && localAndValidationErrors.length"
>
<li
v-for="error in localAndValidationErrors"
v-text="error"
:key="error"
/>
</transition-group>
</transition>
<slot name="suffix" />
2018-01-31 01:21:21 +03:00
</div>
</template>
<script>
import {inputTypes, equals, reduce, filter} from '../utils'
2018-01-31 01:21:21 +03:00
import shortid from 'shortid'
export default {
props: {
type: {
type: [String, Boolean],
default: 'text'
},
name: {
type: String,
required: true
},
initial: {
type: [String, Number, Boolean],
2018-01-31 01:21:21 +03:00
default: false
},
validation: {
type: [String, Boolean],
default: false
},
errors: {
type: Array,
default: () => []
},
label: {
type: [String, Boolean],
default: false
},
id: {
type: [String],
default: () => shortid.generate()
2018-02-01 01:20:29 +03:00
},
min: {
type: [String, Number, Boolean],
default: () => false
},
max: {
type: [String, Number, Boolean],
default: () => false
},
2018-08-09 06:30:16 +03:00
maxlength: {
type: [String, Number, Boolean],
default: () => false
},
pattern: {
type: [String, Number, Boolean],
default: () => false
},
2018-08-09 06:30:16 +03:00
minlength: {
type: [String, Number, Boolean],
default: () => false
},
2018-02-01 01:20:29 +03:00
placeholder: {
type: [String, Number, Boolean],
default: () => false
},
2018-10-16 06:21:31 +03:00
step: {
type: [String, Number, Boolean],
default: () => false
},
2018-02-01 01:20:29 +03:00
options: {
type: [Object, Array],
default: () => []
},
multiple: {
type: Boolean,
default: false
},
showErrors: {
type: [Object, Boolean],
default: () => ({})
},
validationLabel: {
type: [String, Boolean],
default: false
},
elementClasses: {
type: [String, Array, Object],
default: () => {}
},
disabled: {
type: Boolean,
default: false
New Feature: FormulateElement now supports help text via the new GNU bash, version 3.2.57(1)-release (x86_64-apple-darwin17) These shell commands are defined internally. Type `help' to see this list. Type `help name' to find out more about the function `name'. Use `info bash' to find out more about the shell in general. Use `man -k' or `info' to find out more about commands not in this list. A star (*) next to a name means that the command is disabled. JOB_SPEC [&] (( expression )) . filename [arguments] : [ arg... ] [[ expression ]] alias [-p] [name[=value] ... ] bg [job_spec ...] bind [-lpvsPVS] [-m keymap] [-f fi break [n] builtin [shell-builtin [arg ...]] caller [EXPR] case WORD in [PATTERN [| PATTERN]. cd [-L|-P] [dir] command [-pVv] command [arg ...] compgen [-abcdefgjksuv] [-o option complete [-abcdefgjksuv] [-pr] [-o continue [n] declare [-afFirtx] [-p] [name[=val dirs [-clpv] [+N] [-N] disown [-h] [-ar] [jobspec ...] echo [-neE] [arg ...] enable [-pnds] [-a] [-f filename] eval [arg ...] exec [-cl] [-a name] file [redirec exit [n] export [-nf] [name[=value] ...] or false fc [-e ename] [-nlr] [first] [last fg [job_spec] for NAME [in WORDS ... ;] do COMMA for (( exp1; exp2; exp3 )); do COM function NAME { COMMANDS ; } or NA getopts optstring name [arg] hash [-lr] [-p pathname] [-dt] [na help [-s] [pattern ...] history [-c] [-d offset] [n] or hi if COMMANDS; then COMMANDS; [ elif jobs [-lnprs] [jobspec ...] or job kill [-s sigspec | -n signum | -si let arg [arg ...] local name[=value] ... logout popd [+N | -N] [-n] printf [-v var] format [arguments] pushd [dir | +N | -N] [-n] pwd [-LP] read [-ers] [-u fd] [-t timeout] [ readonly [-af] [name[=value] ...] return [n] select NAME [in WORDS ... ;] do CO set [--abefhkmnptuvxBCHP] [-o opti shift [n] shopt [-pqsu] [-o long-option] opt source filename [arguments] suspend [-f] test [expr] time [-p] PIPELINE times trap [-lp] [arg signal_spec ...] true type [-afptP] name [name ...] typeset [-afFirtx] [-p] name[=valu ulimit [-SHacdfilmnpqstuvx] [limit umask [-p] [-S] [mode] unalias [-a] name [name ...] unset [-f] [-v] [name ...] until COMMANDS; do COMMANDS; done variables - Some variable names an wait [n] while COMMANDS; do COMMANDS; done { COMMANDS ; } prop
2018-05-18 21:46:04 +03:00
},
help: {
type: [Boolean, String],
default: false
2018-02-01 01:20:29 +03:00
}
},
data () {
return {
errorBlurState: false,
focusState: false
2018-01-31 01:21:21 +03:00
}
},
computed: {
classification () {
2018-02-27 06:31:59 +03:00
if (this.isTextInput) return 'text'
if (this.isBoxInput) return 'box'
if (this.isButtonInput) return 'button'
if (this.isSelectInput) return 'select'
if (this.hasCustomInput) return 'custom'
return 'unsupported'
},
2018-01-31 01:21:21 +03:00
hasCustomInput () {
return (this.$slots.default && this.$slots.default.length)
},
isTextInput () {
return !this.hasCustomInput && inputTypes.text.includes(this.type)
},
2018-03-30 21:51:47 +03:00
isTextareaInput () {
return !this.hasCustomInput && inputTypes.textarea.includes(this.type)
},
2018-01-31 01:21:21 +03:00
isButtonInput () {
return !this.hasCustomInput && inputTypes.button.includes(this.type)
},
2018-02-01 01:20:29 +03:00
isSelectInput () {
return !this.hasCustomInput && inputTypes.select.includes(this.type)
},
isBoxInput () {
return !this.hasCustomInput && inputTypes.box.includes(this.type)
},
isUnsupportedInput () {
2018-03-30 21:56:41 +03:00
return (!this.hasCustomInput && !this.isTextInput && !this.isButtonInput && !this.isSelectInput && !this.isBoxInput && !this.isTextareaInput)
2018-01-31 01:21:21 +03:00
},
form () {
let parent = this.$parent
while (parent && parent.$data && parent.$data.parentIdentifier !== 'vue-formulate-wrapper-element') {
parent = parent.$parent
}
if (!parent.$data || parent.$data.parentIdentifier !== 'vue-formulate-wrapper-element') {
throw new Error('FormulateElement has no FormulateWrapper element')
}
return parent
},
values () {
return this.form.values
},
value () {
2018-02-01 01:20:29 +03:00
let value = this.values[this.name]
if (value === undefined) {
switch (this.type) {
case 'color':
return '#000000'
2018-02-01 01:20:29 +03:00
case 'checkbox':
if (this.optionList.length > 1) {
return []
2018-02-01 01:20:29 +03:00
}
break
}
}
return value
2018-01-31 01:21:21 +03:00
},
module () {
return this.form.$props['module']
},
formName () {
return this.form.$props['name']
},
2018-02-01 01:20:29 +03:00
classes () {
return {
'formulate-element': true,
[`formulate-element--type--${this.type}`]: true,
2018-02-01 01:20:29 +03:00
'formulate-element--has-value': !!this.value,
'formulate-element--has-errors': this.localAndValidationErrors.length && this.shouldShowErrors,
'formulate-element--has-prefix': !!this.$slots.prefix,
'formulate-element--has-suffix': !!this.$slots.suffix,
'formulate-element--has-focus': !!this.focusState
2018-02-01 01:20:29 +03:00
}
},
2018-01-31 01:21:21 +03:00
validationErrors () {
return this.form.validationErrors[this.name] || []
},
storeErrors () {
return this.form.storeErrors[this.name] || []
},
formErrors () {
2018-01-31 01:21:21 +03:00
return this.form.errors[this.name] || []
},
localAndValidationErrors () {
return this.errors.concat(this.validationErrors).concat(this.formErrors)
2018-01-31 01:21:21 +03:00
},
2018-02-01 01:20:29 +03:00
shouldShowErrors () {
let show = this.form.shouldShowErrors
if (this.form.behavior === 'blur') {
show = show || this.errorBlurState
2018-02-01 01:20:29 +03:00
}
if (this.showErrors === false || this.showErrors === true) {
show = this.showErrors
}
return show
},
2018-01-31 01:21:21 +03:00
attributes () {
return ['min', 'max', 'minlength', 'maxlength', 'placeholder', 'id', 'multiple', 'pattern']
2018-02-01 01:20:29 +03:00
.filter(prop => this[prop] !== false)
.reduce((attributes, attr) => {
attributes[attr] = this[attr]
return attributes
}, {})
},
optionList () {
if (!Array.isArray(this.options)) {
return reduce(this.options, (options, value, label) => options.concat({value, label, id: shortid.generate()}), [])
} else if (Array.isArray(this.options) && !this.options.length) {
return [{value: this.name, label: (this.label || this.name), id: shortid.generate()}]
}
return this.options
2018-01-31 01:21:21 +03:00
},
val: {
set (value) {
this.form.update({field: this.name, value})
2018-02-01 01:20:29 +03:00
if (this.isTextInput) {
this.$refs.input.value = value
}
2018-01-31 01:21:21 +03:00
},
get () {
return this.value
}
}
},
watch: {
2018-02-01 01:20:29 +03:00
localAndValidationErrors () {
if (!equals(this.localAndValidationErrors, this.storeErrors)) {
this.form.updateFieldErrors({
field: this.name,
errors: this.localAndValidationErrors
})
}
},
initial () {
this.form.update({field: this.name, value: this.initial})
2018-01-31 01:21:21 +03:00
}
},
created () {
if (typeof window === 'undefined') {
this.register()
}
},
mounted () {
this.register()
},
beforeDestroy () {
this.form.deregisterField(this.name)
},
methods: {
register () {
this.form.registerField(
this.name,
filter(this.$props, (prop, value) => ['name', 'type', 'id', 'label', 'validation', 'validationLabel'].includes(prop))
)
if (this.initial !== false) {
this.form.setInitial(this.name, this.initial)
}
},
setBlurState () {
this.errorBlurState = true
this.focusState = false
},
setFocusState () {
this.focusState = true
2018-01-31 01:21:21 +03:00
}
}
}
</script>