UNPKG

framework7-vue

Version:

Build full featured iOS & Android apps using Framework7 & Vue

495 lines (450 loc) 13.7 kB
import Utils from '../utils/utils'; import Mixins from '../utils/mixins'; 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-list-input', props: Object.assign({ id: [String, Number], sortable: Boolean, media: String, dropdown: { type: [String, Boolean], default: 'auto' }, wrap: { type: Boolean, default: true }, input: { type: Boolean, default: true }, type: { type: String, default: 'text' }, name: String, value: [String, Number, Array], defaultValue: [String, Number, Array], readonly: Boolean, required: Boolean, disabled: Boolean, placeholder: String, inputId: [String, Number], size: [String, Number], accept: [String, Number], autocomplete: [String], autocorrect: [String], autocapitalize: [String], spellcheck: [String], autofocus: Boolean, autosave: String, max: [String, Number], min: [String, Number], step: [String, Number], maxlength: [String, Number], minlength: [String, Number], multiple: 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, label: [String, Number], inlineLabel: Boolean, floatingLabel: Boolean }, Mixins.colorProps), data() { const props = __vueComponentProps(this); const state = (() => { return { isSortable: props.sortable, inputFocused: false, inputInvalid: false }; })(); return { state }; }, render() { const _h = this.$createElement; const self = this; const { inputFocused, inputInvalid } = self.state; const props = self.props; const { id, style, className, sortable, media, dropdown, input: renderInput, wrap, type, name, value, defaultValue, readonly, required, disabled, placeholder, inputId, size, accept, autocomplete, autocorrect, autocapitalize, spellcheck, autofocus, autosave, max, min, step, maxlength, minlength, multiple, inputStyle, pattern, validate, validateOnBlur, tabindex, resizable, clearButton, noFormStoreData, noStoreData, ignoreStoreData, errorMessage, errorMessageForce, info, label, inlineLabel, floatingLabel } = props; const domValue = self.domValue(); const inputHasValue = self.inputHasValue(); const isSortable = sortable || self.state.isSortable; const createInput = (InputTag, children) => { const needsValue = type !== 'file'; const needsType = InputTag === 'input'; const inputClassName = Utils.classNames({ resizable: type === 'textarea' && resizable, 'no-store-data': noFormStoreData || noStoreData || ignoreStoreData, 'input-invalid': errorMessage && errorMessageForce || inputInvalid, 'input-with-value': inputHasValue, 'input-focused': 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({ 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; }; let inputEl; if (renderInput) { if (type === 'select' || type === 'textarea' || type === 'file') { if (type === 'select') { inputEl = createInput('select', self.$slots.default); } else if (type === 'file') { inputEl = createInput('input'); } else { inputEl = createInput('textarea'); } } else { inputEl = createInput('input'); } } const hasErrorMessage = !!errorMessage || self.$slots['error-message'] && self.$slots['error-message'].length; const ItemContent = _h('div', { ref: 'itemContentEl', class: Utils.classNames('item-content item-input', !wrap && className, !wrap && { disabled }, !wrap && Mixins.colorClasses(props), { 'inline-label': inlineLabel, 'item-input-focused': inputFocused, 'item-input-with-info': !!info || self.$slots.info && self.$slots.info.length, 'item-input-with-value': inputHasValue, 'item-input-with-error-message': hasErrorMessage && errorMessageForce || inputInvalid, 'item-input-invalid': hasErrorMessage && errorMessageForce || inputInvalid }) }, [this.$slots['content-start'], (media || self.$slots.media) && _h('div', { class: 'item-media' }, [media && _h('img', { attrs: { src: media } }), this.$slots['media']]), _h('div', { class: 'item-inner' }, [this.$slots['inner-start'], (label || self.$slots.label) && _h('div', { class: Utils.classNames('item-title item-label', { 'item-floating-label': floatingLabel }) }, [label, this.$slots['label']]), _h('div', { class: Utils.classNames('item-input-wrap', { 'input-dropdown': dropdown === 'auto' ? type === 'select' : dropdown }) }, [inputEl, this.$slots['input'], hasErrorMessage && errorMessageForce && _h('div', { class: 'item-input-error-message' }, [errorMessage, this.$slots['error-message']]), clearButton && _h('span', { class: 'input-clear-button' }), (info || self.$slots.info) && _h('div', { class: 'item-input-info' }, [info, this.$slots['info']])]), this.$slots['inner'], this.$slots['inner-end']]), this.$slots['content'], this.$slots['content-end']]); if (!wrap) { return ItemContent; } return _h('li', { ref: 'el', style: style, class: Utils.classNames(className, { disabled }, Mixins.colorClasses(props)), attrs: { id: id } }, [this.$slots['root-start'], ItemContent, isSortable && _h('div', { class: 'sortable-handler' }), this.$slots['root'], this.$slots['root-end']]); }, watch: { 'props.value': function watchValue() { const self = this; if (!self.$f7) return; self.updateInputOnDidUpdate = true; } }, created() { Utils.bindMethods(this, 'onChange onInput onFocus onBlur onTextareaResize onInputNotEmpty onInputEmpty onInputClear'.split(' ')); }, mounted() { const self = this; const el = self.$refs.el; const itemContentEl = self.$refs.itemContentEl; if (!el && !itemContentEl) return; self.$f7ready(f7 => { const { validate, validateOnBlur, resizable, value, defaultValue, type } = self.props; const inputEl = self.$refs.inputEl; if (!inputEl) return; inputEl.addEventListener('input:notempty', self.onInputNotEmpty, false); inputEl.addEventListener('textarea:resze', self.onTextareaResize, false); inputEl.addEventListener('input:empty', self.onInputEmpty, false); inputEl.addEventListener('input:clear', self.onInputClear, false); if (!(validateOnBlur || validateOnBlur === '') && (validate || validate === '') && (typeof value !== 'undefined' && value !== null && value !== '' || typeof defaultValue !== 'undefined' && defaultValue !== null && defaultValue !== '')) { setTimeout(() => { self.validateInput(inputEl); }, 0); } if (type === 'textarea' && resizable) { f7.input.resizeTextarea(inputEl); } }); self.$listEl = self.$$(el || itemContentEl).parents('.list, .list-group').eq(0); if (self.$listEl.length) { self.setState({ isSortable: self.$listEl.hasClass('sortable') }); } }, updated() { const self = this; const { $listEl } = self; if (!$listEl || $listEl && $listEl.length === 0) return; const isSortable = $listEl.hasClass('sortable'); if (isSortable !== self.state.isSortable) { self.setState({ isSortable }); } const { validate, validateOnBlur, resizable, type } = self.props; const f7 = self.$f7; if (!f7) return; if (self.updateInputOnDidUpdate) { const inputEl = self.$refs.inputEl; if (!inputEl) return; self.updateInputOnDidUpdate = false; if (validate && !validateOnBlur) { self.validateInput(inputEl); } if (type === 'textarea' && resizable) { f7.input.resizeTextarea(inputEl); } } }, beforeDestroy() { const self = this; const inputEl = self.$refs.inputEl; if (!inputEl) return; inputEl.removeEventListener('input:notempty', self.onInputNotEmpty, false); inputEl.removeEventListener('textarea:resze', self.onTextareaResize, false); 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); } } };