diff --git a/packages/date-picker/src/panel/date-range.vue b/packages/date-picker/src/panel/date-range.vue index de3c8dd0d..ff9b3130b 100644 --- a/packages/date-picker/src/panel/date-range.vue +++ b/packages/date-picker/src/panel/date-range.vue @@ -28,18 +28,19 @@ :placeholder="t('el.datepicker.startDate')" class="el-date-range-picker__editor" :value="minVisibleDate" - @input.native="handleDateInput($event, 'min')" - @change.native="handleDateChange($event, 'min')" /> + @input="val => handleDateInput(val, 'min')" + @change="val => handleDateChange(val, 'min')" /> + @input="val => handleTimeInput(val, 'min')" + @change="val => handleTimeChange(val, 'min')" /> + @input="val => handleDateInput(val, 'max')" + @change="val => handleDateChange(val, 'max')" /> + @focus="minDate && (maxTimePickerVisible = true)" + @input="val => handleTimeInput(val, 'max')" + @change="val => handleTimeChange(val, 'max')" /> { if (this.$refs.maxTimePicker && this.maxDate && this.maxDate < this.minDate) { const format = 'HH:mm:ss'; @@ -354,6 +373,8 @@ }, maxDate(val) { + this.dateUserInput.max = null; + this.timeUserInput.max = null; if (val && this.$refs.maxTimePicker) { this.$refs.maxTimePicker.date = val; this.$refs.maxTimePicker.value = val; @@ -433,8 +454,8 @@ this.rangeState = val.rangeState; }, - handleDateInput(event, type) { - const value = event.target.value; + handleDateInput(value, type) { + this.dateUserInput[type] = value; if (value.length !== this.dateFormat.length) return; const parsedValue = parseDate(value, this.dateFormat); @@ -444,19 +465,22 @@ return; } if (type === 'min') { - this.minDate = new Date(parsedValue); + this.minDate = modifyDate(this.minDate || new Date(), parsedValue.getFullYear(), parsedValue.getMonth(), parsedValue.getDate()); this.leftDate = new Date(parsedValue); - this.rightDate = nextMonth(this.leftDate); + if (!this.unlinkPanels) { + this.rightDate = nextMonth(this.leftDate); + } } else { - this.maxDate = new Date(parsedValue); - this.leftDate = prevMonth(parsedValue); + this.maxDate = modifyDate(this.maxDate || new Date(), parsedValue.getFullYear(), parsedValue.getMonth(), parsedValue.getDate()); this.rightDate = new Date(parsedValue); + if (!this.unlinkPanels) { + this.leftDate = prevMonth(parsedValue); + } } } }, - handleDateChange(event, type) { - const value = event.target.value; + handleDateChange(value, type) { const parsedValue = parseDate(value, this.dateFormat); if (parsedValue) { if (type === 'min') { @@ -473,8 +497,23 @@ } }, - handleTimeChange(event, type) { - const value = event.target.value; + handleTimeInput(value, type) { + this.timeUserInput[type] = value; + if (value.length !== this.timeFormat.length) return; + const parsedValue = parseDate(value, this.timeFormat); + + if (parsedValue) { + if (type === 'min') { + this.minDate = modifyTime(this.minDate, parsedValue.getHours(), parsedValue.getMinutes(), parsedValue.getSeconds()); + this.$nextTick(_ => this.$refs.minTimePicker.adjustSpinners()); + } else { + this.maxDate = modifyTime(this.maxDate, parsedValue.getHours(), parsedValue.getMinutes(), parsedValue.getSeconds()); + this.$nextTick(_ => this.$refs.maxTimePicker.adjustSpinners()); + } + } + }, + + handleTimeChange(value, type) { const parsedValue = parseDate(value, this.timeFormat); if (parsedValue) { if (type === 'min') { diff --git a/packages/input-number/src/input-number.vue b/packages/input-number/src/input-number.vue index 91e6bdf1b..03462d7e6 100644 --- a/packages/input-number/src/input-number.vue +++ b/packages/input-number/src/input-number.vue @@ -28,7 +28,7 @@ @@ -102,7 +103,8 @@ }, data() { return { - currentValue: 0 + currentValue: 0, + userInput: null }; }, watch: { @@ -121,6 +123,7 @@ if (newVal >= this.max) newVal = this.max; if (newVal <= this.min) newVal = this.min; this.currentValue = newVal; + this.userInput = null; this.$emit('input', newVal); } } @@ -156,7 +159,10 @@ inputNumberDisabled() { return this.disabled || (this.elForm || {}).disabled; }, - currentInputValue() { + displayValue() { + if (this.userInput !== null) { + return this.userInput; + } const currentValue = this.currentValue; if (typeof currentValue === 'number' && this.precision !== undefined) { return currentValue.toFixed(this.precision); @@ -208,7 +214,6 @@ }, handleBlur(event) { this.$emit('blur', event); - this.$refs.input.setCurrentValue(this.currentInputValue); }, handleFocus(event) { this.$emit('focus', event); @@ -220,19 +225,21 @@ } if (newVal >= this.max) newVal = this.max; if (newVal <= this.min) newVal = this.min; - if (oldVal === newVal) { - this.$refs.input.setCurrentValue(this.currentInputValue); - return; - } + if (oldVal === newVal) return; + this.userInput = null; this.$emit('input', newVal); this.$emit('change', newVal, oldVal); this.currentValue = newVal; }, + handleInput(value) { + this.userInput = value; + }, handleInputChange(value) { const newVal = value === '' ? undefined : Number(value); if (!isNaN(newVal) || value === '') { this.setCurrentValue(newVal); } + this.userInput = null; }, select() { this.$refs.input.select(); diff --git a/packages/input/src/input.vue b/packages/input/src/input.vue index 5c3254ba7..e7798dab4 100644 --- a/packages/input/src/input.vue +++ b/packages/input/src/input.vue @@ -28,7 +28,7 @@ :disabled="inputDisabled" :readonly="readonly" :autocomplete="autoComplete || autocomplete" - :value="currentValue" + :value="nativeInputValue" ref="input" @compositionstart="handleComposition" @compositionupdate="handleComposition" @@ -78,7 +78,7 @@ v-else :tabindex="tabindex" class="el-textarea__inner" - :value="currentValue" + :value="nativeInputValue" @compositionstart="handleComposition" @compositionupdate="handleComposition" @compositionend="handleComposition" @@ -102,7 +102,6 @@ import Migrating from 'element-ui/src/mixins/migrating'; import calcTextareaHeight from './calcTextareaHeight'; import merge from 'element-ui/src/utils/merge'; - import { isKorean } from 'element-ui/src/utils/shared'; export default { name: 'ElInput', @@ -124,14 +123,10 @@ data() { return { - currentValue: this.value === undefined || this.value === null - ? '' - : this.value, textareaCalcStyle: {}, hovering: false, focused: false, - isOnComposition: false, - valueBeforeComposition: null + isOnComposition: false }; }, @@ -203,18 +198,24 @@ inputDisabled() { return this.disabled || (this.elForm || {}).disabled; }, + nativeInputValue() { + return this.value === null || this.value === undefined ? '' : this.value; + }, showClear() { return this.clearable && !this.inputDisabled && !this.readonly && - this.currentValue !== '' && + this.nativeInputValue && (this.focused || this.hovering); } }, watch: { - value(val, oldValue) { - this.setCurrentValue(val); + value(val) { + this.$nextTick(this.resizeTextarea); + if (this.validateEvent) { + this.dispatch('ElFormItem', 'el.form.change', [val]); + } } }, @@ -240,7 +241,7 @@ this.focused = false; this.$emit('blur', event); if (this.validateEvent) { - this.dispatch('ElFormItem', 'el.form.blur', [this.currentValue]); + this.dispatch('ElFormItem', 'el.form.blur', [this.value]); } }, select() { @@ -266,38 +267,30 @@ this.$emit('focus', event); }, handleComposition(event) { + if (event.type === 'compositionstart') { + this.isOnComposition = true; + } if (event.type === 'compositionend') { this.isOnComposition = false; - this.currentValue = this.valueBeforeComposition; - this.valueBeforeComposition = null; this.handleInput(event); - } else { - const text = event.target.value; - const lastCharacter = text[text.length - 1] || ''; - this.isOnComposition = !isKorean(lastCharacter); - if (this.isOnComposition && event.type === 'compositionstart') { - this.valueBeforeComposition = text; - } } }, handleInput(event) { - const value = event.target.value; - this.setCurrentValue(value); if (this.isOnComposition) return; - this.$emit('input', value); + + // hack for https://github.com/ElemeFE/element/issues/8548 + // should remove the following line when we don't support IE + if (event.target.value === this.nativeInputValue) return; + + this.$emit('input', event.target.value); + + // set input's value, in case parent refuses the change + // see: https://github.com/ElemeFE/element/issues/12850 + this.$nextTick(() => { this.$refs.input.value = this.value; }); }, handleChange(event) { this.$emit('change', event.target.value); }, - setCurrentValue(value) { - if (this.isOnComposition && value === this.valueBeforeComposition) return; - this.currentValue = value; - if (this.isOnComposition) return; - this.$nextTick(this.resizeTextarea); - if (this.validateEvent && this.currentValue === this.value) { - this.dispatch('ElFormItem', 'el.form.change', [value]); - } - }, calcIconOffset(place) { let elList = [].slice.call(this.$el.querySelectorAll(`.el-input__${place}`) || []); if (!elList.length) return; @@ -329,7 +322,6 @@ this.$emit('input', ''); this.$emit('change', ''); this.$emit('clear'); - this.setCurrentValue(''); } }, diff --git a/packages/pagination/src/pagination.js b/packages/pagination/src/pagination.js index 0bb2c67cd..86e6e898d 100644 --- a/packages/pagination/src/pagination.js +++ b/packages/pagination/src/pagination.js @@ -215,56 +215,36 @@ export default { Jumper: { mixins: [Locale], + components: { ElInput }, + data() { return { - oldValue: null + userInput: null }; }, - components: { ElInput }, - watch: { - '$parent.internalPageSize'() { - this.$nextTick(() => { - this.$refs.input.$el.querySelector('input').value = this.$parent.internalCurrentPage; - }); + '$parent.internalCurrentPage'() { + this.userInput = null; } }, methods: { - handleFocus(event) { - this.oldValue = event.target.value; - }, - handleBlur({ target }) { - this.resetValueIfNeed(target.value); - this.reassignMaxValue(target.value); - }, handleKeyup({ keyCode, target }) { - if (keyCode === 13 && this.oldValue && target.value !== this.oldValue) { + // Chrome, Safari, Firefox triggers change event on Enter + // Hack for IE: https://github.com/ElemeFE/element/issues/11710 + // Drop this method when we no longer supports IE + if (keyCode === 13) { this.handleChange(target.value); } }, + handleInput(value) { + this.userInput = value; + }, handleChange(value) { this.$parent.internalCurrentPage = this.$parent.getValidCurrentPage(value); this.$parent.emitChange(); - this.oldValue = null; - this.resetValueIfNeed(value); - }, - resetValueIfNeed(value) { - const num = parseInt(value, 10); - if (!isNaN(num)) { - if (num < 1) { - this.$refs.input.setCurrentValue(1); - } else { - this.reassignMaxValue(value); - } - } - }, - reassignMaxValue(value) { - const { internalPageCount } = this.$parent; - if (+value > internalPageCount) { - this.$refs.input.setCurrentValue(internalPageCount || 1); - } + this.userInput = null; } }, @@ -276,15 +256,12 @@ export default { class="el-pagination__editor is-in-pagination" min={ 1 } max={ this.$parent.internalPageCount } - value={ this.$parent.internalCurrentPage } - domPropsValue={ this.$parent.internalCurrentPage } + value={ this.userInput !== null ? this.userInput : this.$parent.internalCurrentPage } type="number" - ref="input" disabled={ this.$parent.disabled } nativeOnKeyup={ this.handleKeyup } - onChange={ this.handleChange } - onFocus={ this.handleFocus } - onBlur={ this.handleBlur }/> + onInput={ this.handleInput } + onChange={ this.handleChange }/> { this.t('el.pagination.pageClassifier') } ); @@ -380,7 +357,7 @@ export default { currentPage: { immediate: true, handler(val) { - this.internalCurrentPage = val; + this.internalCurrentPage = this.getValidCurrentPage(val); } }, @@ -393,24 +370,8 @@ export default { internalCurrentPage: { immediate: true, - handler(newVal, oldVal) { - newVal = parseInt(newVal, 10); - - /* istanbul ignore if */ - if (isNaN(newVal)) { - newVal = oldVal || 1; - } else { - newVal = this.getValidCurrentPage(newVal); - } - - if (newVal !== undefined) { - this.internalCurrentPage = newVal; - if (oldVal !== newVal) { - this.$emit('update:currentPage', newVal); - } - } else { - this.$emit('update:currentPage', newVal); - } + handler(newVal) { + this.$emit('update:currentPage', newVal); this.lastEmittedPage = -1; } }, diff --git a/test/unit/specs/date-picker.spec.js b/test/unit/specs/date-picker.spec.js index 7e713779b..6a1c25349 100644 --- a/test/unit/specs/date-picker.spec.js +++ b/test/unit/specs/date-picker.spec.js @@ -2159,16 +2159,16 @@ describe('DatePicker', () => { triggerEvent(rightCell, 'click', true); setTimeout(_ => { - triggerEvent(input2, 'input'); input2.value = '1988-6-4'; + triggerEvent(input2, 'input'); triggerEvent(input2, 'change'); setTimeout(_ => { - triggerEvent(input, 'input'); input.value = '1989-6-4'; + triggerEvent(input, 'input'); triggerEvent(input, 'change', true); setTimeout(_ => { - expect(vm.picker.maxDate > vm.picker.minDate).to.true; + expect(vm.picker.maxDate >= vm.picker.minDate).to.true; done(); }, DELAY); }, DELAY); @@ -2213,7 +2213,7 @@ describe('DatePicker', () => { input.focus(); setTimeout(_ => { // simulate user input of invalid date - vm.$refs.compo.picker.handleDateChange({ target: { value: '2000-09-01'} }, 'min'); + vm.$refs.compo.picker.handleDateChange('2000-09-01', 'min'); setTimeout(_ => { expect(vm.$refs.compo.picker.btnDisabled).to.equal(true); // invalid input disables button vm.$refs.compo.picker.handleConfirm(); diff --git a/test/unit/specs/input.spec.js b/test/unit/specs/input.spec.js index 22f791c78..d2cb33d4c 100644 --- a/test/unit/specs/input.spec.js +++ b/test/unit/specs/input.spec.js @@ -194,7 +194,8 @@ describe('Input', () => { `, data() { return { - value: '1234' + value: '1234', + select: '1' }; } }, true); diff --git a/test/unit/specs/pagination.spec.js b/test/unit/specs/pagination.spec.js index 8858f8719..d83dc4414 100644 --- a/test/unit/specs/pagination.spec.js +++ b/test/unit/specs/pagination.spec.js @@ -249,7 +249,6 @@ describe('Pagination', () => { const input = vm.inputer; const changeValue = (value) => { input.$emit('input', value); - input.setCurrentValue(value); input.$emit('change', value); };