UNPKG

framework7-vue

Version:

Build full featured iOS & Android apps using Framework7 & Vue

481 lines (436 loc) 12.5 kB
import Utils from '../utils/utils'; import Mixins from '../utils/mixins'; import F7Toggle from './toggle'; import F7Range from './range'; import __vueComponentSetState from '../runtime-helpers/vue-component-set-state.js'; import __vueComponentDispatchEvent from '../runtime-helpers/vue-component-dispatch-event.js'; import __vueComponentProps from '../runtime-helpers/vue-component-props.js'; export default { name: 'f7-input', props: Object.assign({ type: String, name: String, value: [String, Number, Array], defaultValue: [String, Number, Array], placeholder: String, id: [String, Number], inputId: [String, Number], size: [String, Number], accept: [String, Number], autocomplete: [String], autocorrect: [String], autocapitalize: [String], spellcheck: [String], autofocus: Boolean, autosave: String, checked: Boolean, disabled: Boolean, max: [String, Number], min: [String, Number], step: [String, Number], maxlength: [String, Number], minlength: [String, Number], multiple: Boolean, readonly: Boolean, required: Boolean, inputStyle: [String, Object], pattern: String, validate: [Boolean, String], validateOnBlur: Boolean, tabindex: [String, Number], resizable: Boolean, clearButton: Boolean, noFormStoreData: Boolean, noStoreData: Boolean, ignoreStoreData: Boolean, errorMessage: String, errorMessageForce: Boolean, info: String, wrap: { type: Boolean, default: true }, dropdown: { type: [String, Boolean], default: 'auto' } }, Mixins.colorProps), data() { const props = __vueComponentProps(this); const state = (() => { return { inputFocused: false, inputInvalid: false }; })(); return { state }; }, render() { const _h = this.$createElement; const self = this; const props = self.props; const { type, name, value, defaultValue, placeholder, id, inputId, size, accept, autocomplete, autocorrect, autocapitalize, spellcheck, autofocus, autosave, checked, disabled, max, min, step, maxlength, minlength, multiple, readonly, required, inputStyle, pattern, validate, validateOnBlur, tabindex, resizable, clearButton, errorMessage, errorMessageForce, info, wrap, dropdown, style, className, noStoreData, noFormStoreData, ignoreStoreData } = props; const domValue = self.domValue(); const inputHasValue = self.inputHasValue(); let inputEl; const createInput = (InputTag, children) => { const needsValue = type !== 'file'; const needsType = InputTag === 'input'; const inputClassName = Utils.classNames(!wrap && className, { resizable: type === 'textarea' && resizable, 'no-store-data': noFormStoreData || noStoreData || ignoreStoreData, 'input-invalid': errorMessage && errorMessageForce || self.state.inputInvalid, 'input-with-value': inputHasValue, 'input-focused': self.state.inputFocused }); let input; let inputValue; if (needsValue) { if (typeof value !== 'undefined') inputValue = value;else inputValue = domValue; } const valueProps = {}; if ('value' in props) valueProps.value = inputValue; if ('defaultValue' in props) valueProps.defaultValue = defaultValue; { input = _h(InputTag, { ref: 'inputEl', style: inputStyle, class: inputClassName, domProps: Object.assign({ checked, disabled, readOnly: readonly, multiple, required }, valueProps), on: { focus: self.onFocus, blur: self.onBlur, input: self.onInput, change: self.onChange }, attrs: { name: name, type: needsType ? type : undefined, placeholder: placeholder, id: inputId, size: size, accept: accept, autocomplete: autocomplete, autocorrect: autocorrect, autocapitalize: autocapitalize, spellcheck: spellcheck, autofocus: autofocus, autoSave: autosave, max: max, maxlength: maxlength, min: min, minlength: minlength, step: step, pattern: pattern, validate: typeof validate === 'string' && validate.length ? validate : undefined, 'data-validate': validate === true || validate === '' || validateOnBlur === true || validateOnBlur === '' ? true : undefined, 'data-validate-on-blur': validateOnBlur === true || validateOnBlur === '' ? true : undefined, tabindex: tabindex, 'data-error-message': errorMessageForce ? undefined : errorMessage } }, [children]); } return input; }; const { default: slotsDefault, info: slotsInfo } = self.$slots; if (type === 'select' || type === 'textarea' || type === 'file') { if (type === 'select') { inputEl = createInput('select', slotsDefault); } else if (type === 'file') { inputEl = createInput('input'); } else { inputEl = createInput('textarea'); } } else if (slotsDefault && slotsDefault.length > 0 || !type) { inputEl = slotsDefault; } else if (type === 'toggle') { inputEl = _h(F7Toggle, { on: { change: self.onChange }, attrs: { checked: checked, readonly: readonly, name: name, value: value, disabled: disabled, id: inputId } }); } else if (type === 'range') { inputEl = _h(F7Range, { on: { rangeChange: self.onChange }, attrs: { value: value, disabled: disabled, min: min, max: max, step: step, name: name, id: inputId, input: true } }); } else { inputEl = createInput('input'); } if (wrap) { const wrapClasses = Utils.classNames(className, 'input', { 'input-dropdown': dropdown === 'auto' ? type === 'select' : dropdown }, Mixins.colorClasses(props)); return _h('div', { ref: 'wrapEl', class: wrapClasses, style: style, attrs: { id: id } }, [inputEl, errorMessage && errorMessageForce && _h('div', { class: 'input-error-message' }, [errorMessage]), clearButton && _h('span', { class: 'input-clear-button' }), (info || slotsInfo && slotsInfo.length) && _h('div', { class: 'input-info' }, [info, this.$slots['info']])]); } return inputEl; }, watch: { 'props.value': function watchValue() { const self = this; const { type } = self.props; if (type === 'range' || type === 'toggle') return; if (!self.$f7) return; self.updateInputOnDidUpdate = true; } }, created() { Utils.bindMethods(this, 'onFocus onBlur onInput onChange onTextareaResize onInputNotEmpty onInputEmpty onInputClear'.split(' ')); }, mounted() { const self = this; self.$f7ready(f7 => { const { validate, validateOnBlur, resizable, type, clearButton, value, defaultValue } = self.props; if (type === 'range' || type === 'toggle') return; const inputEl = self.$refs.inputEl; if (!inputEl) return; inputEl.addEventListener('input:notempty', self.onInputNotEmpty, false); if (type === 'textarea' && resizable) { inputEl.addEventListener('textarea:resze', self.onTextareaResize, false); } if (clearButton) { inputEl.addEventListener('input:empty', self.onInputEmpty, false); inputEl.addEventListener('input:clear', self.onInputClear, false); } f7.input.checkEmptyState(inputEl); if (!(validateOnBlur || validateOnBlur === '') && (validate || validate === '') && (typeof value !== 'undefined' && value !== null && value !== '' || typeof defaultValue !== 'undefined' && defaultValue !== null && defaultValue !== '')) { setTimeout(() => { self.validateInput(inputEl); }, 0); } if (resizable) { f7.input.resizeTextarea(inputEl); } }); }, updated() { const self = this; const { validate, validateOnBlur, resizable } = self.props; const f7 = self.$f7; if (!f7) return; if (self.updateInputOnDidUpdate) { const inputEl = self.$refs.inputEl; if (!inputEl) return; self.updateInputOnDidUpdate = false; f7.input.checkEmptyState(inputEl); if (validate && !validateOnBlur) { self.validateInput(inputEl); } if (resizable) { f7.input.resizeTextarea(inputEl); } } }, beforeDestroy() { const self = this; const { type, resizable, clearButton } = self.props; if (type === 'range' || type === 'toggle') return; const inputEl = self.$refs.inputEl; if (!inputEl) return; inputEl.removeEventListener('input:notempty', self.onInputNotEmpty, false); if (type === 'textarea' && resizable) { inputEl.removeEventListener('textarea:resze', self.onTextareaResize, false); } if (clearButton) { inputEl.removeEventListener('input:empty', self.onInputEmpty, false); inputEl.removeEventListener('input:clear', self.onInputClear, false); } }, methods: { domValue() { const self = this; const { inputEl } = self.$refs; if (!inputEl) return undefined; return inputEl.value; }, inputHasValue() { const self = this; const { value } = self.props; const domValue = self.domValue(); return typeof value === 'undefined' ? domValue || domValue === 0 : value || value === 0; }, validateInput(inputEl) { const self = this; const f7 = self.$f7; if (!f7 || !inputEl) return; const validity = inputEl.validity; if (!validity) return; if (!validity.valid) { if (self.state.inputInvalid !== true) { self.setState({ inputInvalid: true }); } } else if (self.state.inputInvalid !== false) { self.setState({ inputInvalid: false }); } }, onTextareaResize(event) { this.dispatchEvent('textarea:resize textareaResize', event); }, onInputNotEmpty(event) { this.dispatchEvent('input:notempty inputNotEmpty', event); }, onInputEmpty(event) { this.dispatchEvent('input:empty inputEmpty', event); }, onInputClear(event) { this.dispatchEvent('input:clear inputClear', event); }, onInput(event) { const self = this; const { validate, validateOnBlur } = self.props; self.dispatchEvent('input', event); if (!(validateOnBlur || validateOnBlur === '') && (validate || validate === '') && self.$refs && self.$refs.inputEl) { self.validateInput(self.$refs.inputEl); } }, onFocus(event) { this.dispatchEvent('focus', event); this.setState({ inputFocused: true }); }, onBlur(event) { const self = this; const { validate, validateOnBlur } = self.props; self.dispatchEvent('blur', event); if ((validate || validate === '' || validateOnBlur || validateOnBlur === '') && self.$refs && self.$refs.inputEl) { self.validateInput(self.$refs.inputEl); } self.setState({ inputFocused: false }); }, onChange(event) { this.dispatchEvent('change', event); }, dispatchEvent(events, ...args) { __vueComponentDispatchEvent(this, events, ...args); }, setState(updater, callback) { __vueComponentSetState(this, updater, callback); } }, computed: { props() { return __vueComponentProps(this); } } };