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: '',
|
||||
value11: '',
|
||||
value12: '',
|
||||
value13: [],
|
||||
value14: []
|
||||
value13: '',
|
||||
value14: ''
|
||||
};
|
||||
}
|
||||
};
|
||||
|
@ -232,7 +232,7 @@ You can choose week, month, year or multiple dates by extending the standard dat
|
|||
value3: '',
|
||||
value4: '',
|
||||
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 {
|
||||
data() {
|
||||
return {
|
||||
value13: []
|
||||
value13: ''
|
||||
};
|
||||
}
|
||||
};
|
||||
|
|
|
@ -66,8 +66,8 @@
|
|||
value10: '',
|
||||
value11: '',
|
||||
value12: '',
|
||||
value13: [],
|
||||
value14: []
|
||||
value13: '',
|
||||
value14: ''
|
||||
};
|
||||
}
|
||||
};
|
||||
|
@ -234,7 +234,7 @@ You can choose week, month, year or multiple dates by extending the standard dat
|
|||
value3: '',
|
||||
value4: '',
|
||||
value5: '',
|
||||
value14: []
|
||||
value14: ''
|
||||
};
|
||||
}
|
||||
};
|
||||
|
@ -466,7 +466,7 @@ Al seleccionar un intervalo de fechas, puede asignar la hora para la fecha de in
|
|||
export default {
|
||||
data() {
|
||||
return {
|
||||
value12: []
|
||||
value12: ''
|
||||
};
|
||||
}
|
||||
};
|
||||
|
|
|
@ -66,8 +66,8 @@
|
|||
value10: '',
|
||||
value11: '',
|
||||
value12: '',
|
||||
value13: [],
|
||||
value14: []
|
||||
value13: '',
|
||||
value14: ''
|
||||
};
|
||||
}
|
||||
};
|
||||
|
@ -89,7 +89,7 @@
|
|||
border-right: none;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.demo-date-picker .container {
|
||||
flex: 1;
|
||||
border-right: solid 1px #EFF2F6;
|
||||
|
@ -232,7 +232,7 @@
|
|||
value3: '',
|
||||
value4: '',
|
||||
value5: '',
|
||||
value14: []
|
||||
value14: ''
|
||||
};
|
||||
}
|
||||
};
|
||||
|
@ -418,7 +418,7 @@
|
|||
export default {
|
||||
data() {
|
||||
return {
|
||||
value13: []
|
||||
value13: ''
|
||||
};
|
||||
}
|
||||
};
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
import { getFirstDayOfMonth, getDayCountOfMonth, getWeekNumber, getStartDateOfMonth, nextDate, isDate } from '../util';
|
||||
import { hasClass } from 'element-ui/src/utils/dom';
|
||||
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 clearHours = function(time) {
|
||||
|
@ -43,6 +44,14 @@
|
|||
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 {
|
||||
mixins: [Locale],
|
||||
|
||||
|
@ -75,10 +84,6 @@
|
|||
|
||||
disabledDate: {},
|
||||
|
||||
selectedDate: {
|
||||
type: Array
|
||||
},
|
||||
|
||||
minDate: {},
|
||||
|
||||
maxDate: {},
|
||||
|
@ -135,7 +140,7 @@
|
|||
|
||||
const startDate = this.startDate;
|
||||
const disabledDate = this.disabledDate;
|
||||
const selectedDate = this.selectedDate || this.value;
|
||||
const selectedDate = this.selectionMode === 'dates' ? coerceTruthyValueToArray(this.value) : [];
|
||||
const now = clearHours(new Date());
|
||||
|
||||
for (let i = 0; i < 6; i++) {
|
||||
|
@ -188,10 +193,9 @@
|
|||
}
|
||||
}
|
||||
|
||||
let newDate = new Date(time);
|
||||
cell.disabled = typeof disabledDate === 'function' && disabledDate(newDate);
|
||||
cell.selected = Array.isArray(selectedDate) &&
|
||||
selectedDate.filter(date => date.toString() === newDate.toString())[0];
|
||||
let cellDate = new Date(time);
|
||||
cell.disabled = typeof disabledDate === 'function' && disabledDate(cellDate);
|
||||
cell.selected = arrayFind(selectedDate, date => date.getTime() === cellDate.getTime());
|
||||
|
||||
this.$set(row, this.showWeekNumber ? j + 1 : j, cell);
|
||||
}
|
||||
|
@ -483,19 +487,11 @@
|
|||
date: newDate
|
||||
});
|
||||
} else if (selectionMode === 'dates') {
|
||||
let selectedDate = this.selectedDate;
|
||||
|
||||
if (!cell.selected) {
|
||||
selectedDate.push(newDate);
|
||||
} else {
|
||||
selectedDate.forEach((date, index) => {
|
||||
if (date.toString() === newDate.toString()) {
|
||||
selectedDate.splice(index, 1);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
this.$emit('select', selectedDate);
|
||||
const value = this.value || [];
|
||||
const newValue = cell.selected
|
||||
? removeFromArray(value, date => date.getTime() === newDate.getTime())
|
||||
: [...value, newDate];
|
||||
this.$emit('pick', newValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -51,6 +51,7 @@
|
|||
import Locale from 'element-ui/src/mixins/locale';
|
||||
import { isDate, range, getDayCountOfMonth, nextDate } from '../util';
|
||||
import { hasClass } from 'element-ui/src/utils/dom';
|
||||
import { arrayFindIndex, coerceTruthyValueToArray } from 'element-ui/src/utils/util';
|
||||
|
||||
const datesInMonth = (year, month) => {
|
||||
const numOfDays = getDayCountOfMonth(year, month);
|
||||
|
@ -80,7 +81,7 @@
|
|||
style.disabled = typeof this.disabledDate === 'function'
|
||||
? datesInMonth(year, month).every(this.disabledDate)
|
||||
: 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.default = this.defaultValue &&
|
||||
this.defaultValue.getFullYear() === year &&
|
||||
|
|
|
@ -46,6 +46,7 @@
|
|||
<script type="text/babel">
|
||||
import { hasClass } from 'element-ui/src/utils/dom';
|
||||
import { isDate, range, nextDate, getDayCountOfYear } from '../util';
|
||||
import { arrayFindIndex, coerceTruthyValueToArray } from 'element-ui/src/utils/util';
|
||||
|
||||
const datesInYear = year => {
|
||||
const numOfDays = getDayCountOfYear(year);
|
||||
|
@ -80,7 +81,7 @@
|
|||
style.disabled = typeof this.disabledDate === 'function'
|
||||
? datesInYear(year).every(this.disabledDate)
|
||||
: false;
|
||||
style.current = this.value.getFullYear() === year;
|
||||
style.current = arrayFindIndex(coerceTruthyValueToArray(this.value), date => date.getFullYear() === year) >= 0;
|
||||
style.today = today.getFullYear() === year;
|
||||
style.default = this.defaultValue && this.defaultValue.getFullYear() === year;
|
||||
|
||||
|
|
|
@ -91,19 +91,17 @@
|
|||
<date-table
|
||||
v-show="currentView === 'date'"
|
||||
@pick="handleDatePick"
|
||||
@select="handleDateSelect"
|
||||
:selection-mode="selectionMode"
|
||||
:first-day-of-week="firstDayOfWeek"
|
||||
:value="new Date(value)"
|
||||
:value="value"
|
||||
:default-value="defaultValue ? new Date(defaultValue) : null"
|
||||
:date="date"
|
||||
:disabled-date="disabledDate"
|
||||
:selected-date="selectedDate">
|
||||
:disabled-date="disabledDate">
|
||||
</date-table>
|
||||
<year-table
|
||||
v-show="currentView === 'year'"
|
||||
@pick="handleYearPick"
|
||||
:value="new Date(value)"
|
||||
:value="value"
|
||||
:default-value="defaultValue ? new Date(defaultValue) : null"
|
||||
:date="date"
|
||||
:disabled-date="disabledDate">
|
||||
|
@ -111,7 +109,7 @@
|
|||
<month-table
|
||||
v-show="currentView === 'month'"
|
||||
@pick="handleMonthPick"
|
||||
:value="new Date(value)"
|
||||
:value="value"
|
||||
:default-value="defaultValue ? new Date(defaultValue) : null"
|
||||
:date="date"
|
||||
:disabled-date="disabledDate">
|
||||
|
@ -333,12 +331,6 @@
|
|||
}
|
||||
},
|
||||
|
||||
handleDateSelect(value) {
|
||||
if (this.selectionMode === 'dates') {
|
||||
this.selectedDate = value;
|
||||
}
|
||||
},
|
||||
|
||||
handleDatePick(value) {
|
||||
if (this.selectionMode === 'day') {
|
||||
this.date = this.value
|
||||
|
@ -347,6 +339,8 @@
|
|||
this.emit(this.date, this.showTime);
|
||||
} else if (this.selectionMode === 'week') {
|
||||
this.emit(value.date);
|
||||
} else if (this.selectionMode === 'dates') {
|
||||
this.emit(value, true); // set false to keep panel open
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -373,7 +367,7 @@
|
|||
|
||||
confirm() {
|
||||
if (this.selectionMode === 'dates') {
|
||||
this.emit(this.selectedDate);
|
||||
this.emit(this.value);
|
||||
} else {
|
||||
// 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
|
||||
|
@ -506,7 +500,6 @@
|
|||
visible: false,
|
||||
currentView: 'date',
|
||||
disabledDate: '',
|
||||
selectedDate: [],
|
||||
firstDayOfWeek: 7,
|
||||
showWeekNumber: false,
|
||||
timePickerVisible: false,
|
||||
|
|
|
@ -419,7 +419,6 @@ export default {
|
|||
handler(val) {
|
||||
if (this.picker) {
|
||||
this.picker.value = val;
|
||||
this.picker.selectedDate = Array.isArray(val) ? val : [];
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -705,15 +704,11 @@ export default {
|
|||
handleClose() {
|
||||
if (!this.pickerVisible) return;
|
||||
this.pickerVisible = false;
|
||||
const {
|
||||
type,
|
||||
valueOnOpen,
|
||||
valueFormat,
|
||||
rangeSeparator
|
||||
} = this;
|
||||
if (type === 'dates' && this.picker) {
|
||||
this.picker.selectedDate = parseAsFormatAndType(valueOnOpen, valueFormat, type, rangeSeparator) || valueOnOpen;
|
||||
this.emitInput(this.picker.selectedDate);
|
||||
|
||||
if (this.type === 'dates') {
|
||||
// restore to former value
|
||||
const oldValue = parseAsFormatAndType(this.valueOnOpen, this.valueFormat, this.type, this.rangeSeparator) || this.valueOnOpen;
|
||||
this.emitInput(oldValue);
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -828,7 +823,6 @@ export default {
|
|||
this.picker.selectionMode = this.selectionMode;
|
||||
this.picker.unlinkPanels = this.unlinkPanels;
|
||||
this.picker.arrowControl = this.arrowControl || this.timeArrowControl || false;
|
||||
this.picker.selectedDate = Array.isArray(this.value) && this.value || [];
|
||||
this.$watch('format', (format) => {
|
||||
this.picker.format = format;
|
||||
});
|
||||
|
|
|
@ -84,3 +84,29 @@ export const valueEquals = (a, b) => {
|
|||
};
|
||||
|
||||
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');
|
||||
td.click();
|
||||
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);
|
||||
done();
|
||||
}, 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 => {
|
||||
const td = vm.$refs.compo.picker.$el.querySelector('.el-date-table__row .available');
|
||||
td.click();
|
||||
|
|
Loading…
Reference in New Issue