mirror of https://github.com/ElemeFE/element
Date picker refactor dates selection: fix 12323 (#12347)
* date-picker: refactor type='dates' fix issue #12323 {month, year} table highlights all selected dates nuke selectedDates to provide cleaner data flow * doc: correct date-picker's array usage empty value must be falsy (empty array should not be used)pull/12357/merge
parent
74e62819c0
commit
02176e26f4
|
@ -66,8 +66,8 @@
|
||||||
value10: '',
|
value10: '',
|
||||||
value11: '',
|
value11: '',
|
||||||
value12: '',
|
value12: '',
|
||||||
value13: [],
|
value13: '',
|
||||||
value14: []
|
value14: ''
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -232,7 +232,7 @@ You can choose week, month, year or multiple dates by extending the standard dat
|
||||||
value3: '',
|
value3: '',
|
||||||
value4: '',
|
value4: '',
|
||||||
value5: '',
|
value5: '',
|
||||||
value14: []
|
value14: ''
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -463,7 +463,7 @@ When picking a date range, you can assign the time part for start date and end d
|
||||||
export default {
|
export default {
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
value13: []
|
value13: ''
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -66,8 +66,8 @@
|
||||||
value10: '',
|
value10: '',
|
||||||
value11: '',
|
value11: '',
|
||||||
value12: '',
|
value12: '',
|
||||||
value13: [],
|
value13: '',
|
||||||
value14: []
|
value14: ''
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -234,7 +234,7 @@ You can choose week, month, year or multiple dates by extending the standard dat
|
||||||
value3: '',
|
value3: '',
|
||||||
value4: '',
|
value4: '',
|
||||||
value5: '',
|
value5: '',
|
||||||
value14: []
|
value14: ''
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -466,7 +466,7 @@ Al seleccionar un intervalo de fechas, puede asignar la hora para la fecha de in
|
||||||
export default {
|
export default {
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
value12: []
|
value12: ''
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -66,8 +66,8 @@
|
||||||
value10: '',
|
value10: '',
|
||||||
value11: '',
|
value11: '',
|
||||||
value12: '',
|
value12: '',
|
||||||
value13: [],
|
value13: '',
|
||||||
value14: []
|
value14: ''
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -232,7 +232,7 @@
|
||||||
value3: '',
|
value3: '',
|
||||||
value4: '',
|
value4: '',
|
||||||
value5: '',
|
value5: '',
|
||||||
value14: []
|
value14: ''
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -418,7 +418,7 @@
|
||||||
export default {
|
export default {
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
value13: []
|
value13: ''
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -35,6 +35,7 @@
|
||||||
import { getFirstDayOfMonth, getDayCountOfMonth, getWeekNumber, getStartDateOfMonth, nextDate, isDate } from '../util';
|
import { getFirstDayOfMonth, getDayCountOfMonth, getWeekNumber, getStartDateOfMonth, nextDate, isDate } from '../util';
|
||||||
import { hasClass } from 'element-ui/src/utils/dom';
|
import { hasClass } from 'element-ui/src/utils/dom';
|
||||||
import Locale from 'element-ui/src/mixins/locale';
|
import Locale from 'element-ui/src/mixins/locale';
|
||||||
|
import { arrayFindIndex, arrayFind, coerceTruthyValueToArray } from 'element-ui/src/utils/util';
|
||||||
|
|
||||||
const WEEKS = ['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'];
|
const WEEKS = ['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'];
|
||||||
const clearHours = function(time) {
|
const clearHours = function(time) {
|
||||||
|
@ -43,6 +44,14 @@
|
||||||
return cloneDate.getTime();
|
return cloneDate.getTime();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// remove the first element that satisfies `pred` from arr
|
||||||
|
// return a new array if modification occurs
|
||||||
|
// return the original array otherwise
|
||||||
|
const removeFromArray = function(arr, pred) {
|
||||||
|
const idx = typeof pred === 'function' ? arrayFindIndex(arr, pred) : arr.indexOf(pred);
|
||||||
|
return idx >= 0 ? [...arr.slice(0, idx), ...arr.slice(idx + 1)] : arr;
|
||||||
|
};
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
mixins: [Locale],
|
mixins: [Locale],
|
||||||
|
|
||||||
|
@ -75,10 +84,6 @@
|
||||||
|
|
||||||
disabledDate: {},
|
disabledDate: {},
|
||||||
|
|
||||||
selectedDate: {
|
|
||||||
type: Array
|
|
||||||
},
|
|
||||||
|
|
||||||
minDate: {},
|
minDate: {},
|
||||||
|
|
||||||
maxDate: {},
|
maxDate: {},
|
||||||
|
@ -135,7 +140,7 @@
|
||||||
|
|
||||||
const startDate = this.startDate;
|
const startDate = this.startDate;
|
||||||
const disabledDate = this.disabledDate;
|
const disabledDate = this.disabledDate;
|
||||||
const selectedDate = this.selectedDate || this.value;
|
const selectedDate = this.selectionMode === 'dates' ? coerceTruthyValueToArray(this.value) : [];
|
||||||
const now = clearHours(new Date());
|
const now = clearHours(new Date());
|
||||||
|
|
||||||
for (let i = 0; i < 6; i++) {
|
for (let i = 0; i < 6; i++) {
|
||||||
|
@ -188,10 +193,9 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let newDate = new Date(time);
|
let cellDate = new Date(time);
|
||||||
cell.disabled = typeof disabledDate === 'function' && disabledDate(newDate);
|
cell.disabled = typeof disabledDate === 'function' && disabledDate(cellDate);
|
||||||
cell.selected = Array.isArray(selectedDate) &&
|
cell.selected = arrayFind(selectedDate, date => date.getTime() === cellDate.getTime());
|
||||||
selectedDate.filter(date => date.toString() === newDate.toString())[0];
|
|
||||||
|
|
||||||
this.$set(row, this.showWeekNumber ? j + 1 : j, cell);
|
this.$set(row, this.showWeekNumber ? j + 1 : j, cell);
|
||||||
}
|
}
|
||||||
|
@ -483,19 +487,11 @@
|
||||||
date: newDate
|
date: newDate
|
||||||
});
|
});
|
||||||
} else if (selectionMode === 'dates') {
|
} else if (selectionMode === 'dates') {
|
||||||
let selectedDate = this.selectedDate;
|
const value = this.value || [];
|
||||||
|
const newValue = cell.selected
|
||||||
if (!cell.selected) {
|
? removeFromArray(value, date => date.getTime() === newDate.getTime())
|
||||||
selectedDate.push(newDate);
|
: [...value, newDate];
|
||||||
} else {
|
this.$emit('pick', newValue);
|
||||||
selectedDate.forEach((date, index) => {
|
|
||||||
if (date.toString() === newDate.toString()) {
|
|
||||||
selectedDate.splice(index, 1);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
this.$emit('select', selectedDate);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,6 +51,7 @@
|
||||||
import Locale from 'element-ui/src/mixins/locale';
|
import Locale from 'element-ui/src/mixins/locale';
|
||||||
import { isDate, range, getDayCountOfMonth, nextDate } from '../util';
|
import { isDate, range, getDayCountOfMonth, nextDate } from '../util';
|
||||||
import { hasClass } from 'element-ui/src/utils/dom';
|
import { hasClass } from 'element-ui/src/utils/dom';
|
||||||
|
import { arrayFindIndex, coerceTruthyValueToArray } from 'element-ui/src/utils/util';
|
||||||
|
|
||||||
const datesInMonth = (year, month) => {
|
const datesInMonth = (year, month) => {
|
||||||
const numOfDays = getDayCountOfMonth(year, month);
|
const numOfDays = getDayCountOfMonth(year, month);
|
||||||
|
@ -80,7 +81,7 @@
|
||||||
style.disabled = typeof this.disabledDate === 'function'
|
style.disabled = typeof this.disabledDate === 'function'
|
||||||
? datesInMonth(year, month).every(this.disabledDate)
|
? datesInMonth(year, month).every(this.disabledDate)
|
||||||
: false;
|
: false;
|
||||||
style.current = this.value.getFullYear() === year && this.value.getMonth() === month;
|
style.current = arrayFindIndex(coerceTruthyValueToArray(this.value), date => date.getFullYear() === year && date.getMonth() === month) >= 0;
|
||||||
style.today = today.getFullYear() === year && today.getMonth() === month;
|
style.today = today.getFullYear() === year && today.getMonth() === month;
|
||||||
style.default = this.defaultValue &&
|
style.default = this.defaultValue &&
|
||||||
this.defaultValue.getFullYear() === year &&
|
this.defaultValue.getFullYear() === year &&
|
||||||
|
|
|
@ -46,6 +46,7 @@
|
||||||
<script type="text/babel">
|
<script type="text/babel">
|
||||||
import { hasClass } from 'element-ui/src/utils/dom';
|
import { hasClass } from 'element-ui/src/utils/dom';
|
||||||
import { isDate, range, nextDate, getDayCountOfYear } from '../util';
|
import { isDate, range, nextDate, getDayCountOfYear } from '../util';
|
||||||
|
import { arrayFindIndex, coerceTruthyValueToArray } from 'element-ui/src/utils/util';
|
||||||
|
|
||||||
const datesInYear = year => {
|
const datesInYear = year => {
|
||||||
const numOfDays = getDayCountOfYear(year);
|
const numOfDays = getDayCountOfYear(year);
|
||||||
|
@ -80,7 +81,7 @@
|
||||||
style.disabled = typeof this.disabledDate === 'function'
|
style.disabled = typeof this.disabledDate === 'function'
|
||||||
? datesInYear(year).every(this.disabledDate)
|
? datesInYear(year).every(this.disabledDate)
|
||||||
: false;
|
: false;
|
||||||
style.current = this.value.getFullYear() === year;
|
style.current = arrayFindIndex(coerceTruthyValueToArray(this.value), date => date.getFullYear() === year) >= 0;
|
||||||
style.today = today.getFullYear() === year;
|
style.today = today.getFullYear() === year;
|
||||||
style.default = this.defaultValue && this.defaultValue.getFullYear() === year;
|
style.default = this.defaultValue && this.defaultValue.getFullYear() === year;
|
||||||
|
|
||||||
|
|
|
@ -91,19 +91,17 @@
|
||||||
<date-table
|
<date-table
|
||||||
v-show="currentView === 'date'"
|
v-show="currentView === 'date'"
|
||||||
@pick="handleDatePick"
|
@pick="handleDatePick"
|
||||||
@select="handleDateSelect"
|
|
||||||
:selection-mode="selectionMode"
|
:selection-mode="selectionMode"
|
||||||
:first-day-of-week="firstDayOfWeek"
|
:first-day-of-week="firstDayOfWeek"
|
||||||
:value="new Date(value)"
|
:value="value"
|
||||||
:default-value="defaultValue ? new Date(defaultValue) : null"
|
:default-value="defaultValue ? new Date(defaultValue) : null"
|
||||||
:date="date"
|
:date="date"
|
||||||
:disabled-date="disabledDate"
|
:disabled-date="disabledDate">
|
||||||
:selected-date="selectedDate">
|
|
||||||
</date-table>
|
</date-table>
|
||||||
<year-table
|
<year-table
|
||||||
v-show="currentView === 'year'"
|
v-show="currentView === 'year'"
|
||||||
@pick="handleYearPick"
|
@pick="handleYearPick"
|
||||||
:value="new Date(value)"
|
:value="value"
|
||||||
:default-value="defaultValue ? new Date(defaultValue) : null"
|
:default-value="defaultValue ? new Date(defaultValue) : null"
|
||||||
:date="date"
|
:date="date"
|
||||||
:disabled-date="disabledDate">
|
:disabled-date="disabledDate">
|
||||||
|
@ -111,7 +109,7 @@
|
||||||
<month-table
|
<month-table
|
||||||
v-show="currentView === 'month'"
|
v-show="currentView === 'month'"
|
||||||
@pick="handleMonthPick"
|
@pick="handleMonthPick"
|
||||||
:value="new Date(value)"
|
:value="value"
|
||||||
:default-value="defaultValue ? new Date(defaultValue) : null"
|
:default-value="defaultValue ? new Date(defaultValue) : null"
|
||||||
:date="date"
|
:date="date"
|
||||||
:disabled-date="disabledDate">
|
:disabled-date="disabledDate">
|
||||||
|
@ -333,12 +331,6 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
handleDateSelect(value) {
|
|
||||||
if (this.selectionMode === 'dates') {
|
|
||||||
this.selectedDate = value;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
handleDatePick(value) {
|
handleDatePick(value) {
|
||||||
if (this.selectionMode === 'day') {
|
if (this.selectionMode === 'day') {
|
||||||
this.date = this.value
|
this.date = this.value
|
||||||
|
@ -347,6 +339,8 @@
|
||||||
this.emit(this.date, this.showTime);
|
this.emit(this.date, this.showTime);
|
||||||
} else if (this.selectionMode === 'week') {
|
} else if (this.selectionMode === 'week') {
|
||||||
this.emit(value.date);
|
this.emit(value.date);
|
||||||
|
} else if (this.selectionMode === 'dates') {
|
||||||
|
this.emit(value, true); // set false to keep panel open
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -373,7 +367,7 @@
|
||||||
|
|
||||||
confirm() {
|
confirm() {
|
||||||
if (this.selectionMode === 'dates') {
|
if (this.selectionMode === 'dates') {
|
||||||
this.emit(this.selectedDate);
|
this.emit(this.value);
|
||||||
} else {
|
} else {
|
||||||
// value were emitted in handle{Date,Time}Pick, nothing to update here
|
// value were emitted in handle{Date,Time}Pick, nothing to update here
|
||||||
// deal with the scenario where: user opens the picker, then confirm without doing anything
|
// deal with the scenario where: user opens the picker, then confirm without doing anything
|
||||||
|
@ -506,7 +500,6 @@
|
||||||
visible: false,
|
visible: false,
|
||||||
currentView: 'date',
|
currentView: 'date',
|
||||||
disabledDate: '',
|
disabledDate: '',
|
||||||
selectedDate: [],
|
|
||||||
firstDayOfWeek: 7,
|
firstDayOfWeek: 7,
|
||||||
showWeekNumber: false,
|
showWeekNumber: false,
|
||||||
timePickerVisible: false,
|
timePickerVisible: false,
|
||||||
|
|
|
@ -419,7 +419,6 @@ export default {
|
||||||
handler(val) {
|
handler(val) {
|
||||||
if (this.picker) {
|
if (this.picker) {
|
||||||
this.picker.value = val;
|
this.picker.value = val;
|
||||||
this.picker.selectedDate = Array.isArray(val) ? val : [];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -705,15 +704,11 @@ export default {
|
||||||
handleClose() {
|
handleClose() {
|
||||||
if (!this.pickerVisible) return;
|
if (!this.pickerVisible) return;
|
||||||
this.pickerVisible = false;
|
this.pickerVisible = false;
|
||||||
const {
|
|
||||||
type,
|
if (this.type === 'dates') {
|
||||||
valueOnOpen,
|
// restore to former value
|
||||||
valueFormat,
|
const oldValue = parseAsFormatAndType(this.valueOnOpen, this.valueFormat, this.type, this.rangeSeparator) || this.valueOnOpen;
|
||||||
rangeSeparator
|
this.emitInput(oldValue);
|
||||||
} = this;
|
|
||||||
if (type === 'dates' && this.picker) {
|
|
||||||
this.picker.selectedDate = parseAsFormatAndType(valueOnOpen, valueFormat, type, rangeSeparator) || valueOnOpen;
|
|
||||||
this.emitInput(this.picker.selectedDate);
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -828,7 +823,6 @@ export default {
|
||||||
this.picker.selectionMode = this.selectionMode;
|
this.picker.selectionMode = this.selectionMode;
|
||||||
this.picker.unlinkPanels = this.unlinkPanels;
|
this.picker.unlinkPanels = this.unlinkPanels;
|
||||||
this.picker.arrowControl = this.arrowControl || this.timeArrowControl || false;
|
this.picker.arrowControl = this.arrowControl || this.timeArrowControl || false;
|
||||||
this.picker.selectedDate = Array.isArray(this.value) && this.value || [];
|
|
||||||
this.$watch('format', (format) => {
|
this.$watch('format', (format) => {
|
||||||
this.picker.format = format;
|
this.picker.format = format;
|
||||||
});
|
});
|
||||||
|
|
|
@ -84,3 +84,29 @@ export const valueEquals = (a, b) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
export const escapeRegexpString = (value = '') => String(value).replace(/[|\\{}()[\]^$+*?.]/g, '\\$&');
|
export const escapeRegexpString = (value = '') => String(value).replace(/[|\\{}()[\]^$+*?.]/g, '\\$&');
|
||||||
|
|
||||||
|
// TODO: use native Array.find, Array.findIndex when IE support is dropped
|
||||||
|
export const arrayFindIndex = function(arr, pred) {
|
||||||
|
for (let i = 0; i !== arr.length; ++i) {
|
||||||
|
if (pred(arr[i])) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const arrayFind = function(arr, pred) {
|
||||||
|
const idx = arrayFindIndex(arr, pred);
|
||||||
|
return idx !== -1 ? arr[idx] : undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
// coerce truthy value to array
|
||||||
|
export const coerceTruthyValueToArray = function(val) {
|
||||||
|
if (Array.isArray(val)) {
|
||||||
|
return val;
|
||||||
|
} else if (val) {
|
||||||
|
return [val];
|
||||||
|
} else {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
|
@ -1517,25 +1517,14 @@ describe('DatePicker', () => {
|
||||||
const td = vm.$refs.compo.picker.$el.querySelector('.el-date-table__row .available');
|
const td = vm.$refs.compo.picker.$el.querySelector('.el-date-table__row .available');
|
||||||
td.click();
|
td.click();
|
||||||
setTimeout(_ => {
|
setTimeout(_ => {
|
||||||
expect(vm.$refs.compo.picker.selectedDate).to.exist;
|
expect(vm.$refs.compo.value).to.be.an('array');
|
||||||
|
expect(vm.$refs.compo.value.length).to.equal(1);
|
||||||
|
expect(vm.$refs.compo.value[0]).to.be.a('number');
|
||||||
expect(vm.value.length).to.equal(1);
|
expect(vm.value.length).to.equal(1);
|
||||||
done();
|
done();
|
||||||
}, DELAY);
|
}, DELAY);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('value format', done => {
|
|
||||||
const td = vm.$refs.compo.picker.$el.querySelector('.el-date-table__row .available');
|
|
||||||
td.click();
|
|
||||||
setTimeout(_ => {
|
|
||||||
vm.$refs.compo.picker.$el.querySelector('.el-button--default').click();
|
|
||||||
setTimeout(() => {
|
|
||||||
expect(vm.$refs.compo.picker.selectedDate).to.exist;
|
|
||||||
expect(vm.value.length).to.equal(1);
|
|
||||||
done();
|
|
||||||
}, DELAY);
|
|
||||||
}, DELAY);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('restore value when cancel', done => {
|
it('restore value when cancel', done => {
|
||||||
const td = vm.$refs.compo.picker.$el.querySelector('.el-date-table__row .available');
|
const td = vm.$refs.compo.picker.$el.querySelector('.el-date-table__row .available');
|
||||||
td.click();
|
td.click();
|
||||||
|
|
Loading…
Reference in New Issue