Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DatePicker: add months And years type #21918

Merged
merged 1 commit into from
Sep 13, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 22 additions & 2 deletions examples/docs/en-US/date-picker.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,24 @@ You can choose week, month, year or multiple dates by extending the standard dat
</el-date-picker>
</div>
</div>
<div class="container">
<div class="block">
<span class="demonstration">months</span>
<el-date-picker
type="months"
v-model="value5"
placeholder="Pick one or more months">
</el-date-picker>
</div>
<div class="block">
<span class="demonstration">years</span>
<el-date-picker
type="years"
v-model="value6"
placeholder="Pick one or more years">
</el-date-picker>
</div>
</div>

<script>
export default {
Expand All @@ -120,7 +138,9 @@ You can choose week, month, year or multiple dates by extending the standard dat
value1: '',
value2: '',
value3: '',
value4: ''
value4: '',
value5: '',
value6: ''
};
}
};
Expand Down Expand Up @@ -442,7 +462,7 @@ When picking a date range, you can assign the time part for start date and end d
| placeholder | placeholder in non-range mode | string | — | — |
| start-placeholder | placeholder for the start date in range mode | string | — | — |
| end-placeholder | placeholder for the end date in range mode | string | — | — |
| type | type of the picker | string | year/month/date/dates/datetime/ week/datetimerange/daterange/ monthrange | date |
| type | type of the picker | string | year/month/date/dates/months/years/datetime/ week/datetimerange/daterange/ monthrange | date |
| format | format of the displayed value in the input box | string | see [date formats](#/en-US/component/date-picker#date-formats) | yyyy-MM-dd |
| align | alignment | left/center/right | left |
| popper-class | custom class name for DatePicker's dropdown | string | — | — |
Expand Down
24 changes: 22 additions & 2 deletions examples/docs/es/date-picker.md
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,24 @@ Puede elegir la semana, el mes, el año o varias fechas ampliando el componente
</el-date-picker>
</div>
</div>
<div class="container">
<div class="block">
<span class="demonstration">months</span>
<el-date-picker
type="months"
v-model="value5"
placeholder="Pick one or more months">
</el-date-picker>
</div>
<div class="block">
<span class="demonstration">years</span>
<el-date-picker
type="years"
v-model="value6"
placeholder="Pick one or more years">
</el-date-picker>
</div>
</div>

<script>
export default {
Expand All @@ -122,7 +140,9 @@ Puede elegir la semana, el mes, el año o varias fechas ampliando el componente
value1: '',
value2: '',
value3: '',
value4: ''
value4: '',
value5: '',
value6: ''
};
}
};
Expand Down Expand Up @@ -443,7 +463,7 @@ Al seleccionar un intervalo de fechas, puede asignar la hora para la fecha de in
| placeholder | placeholder cuando el modo NO es rango | string | — | — |
| start-placeholder | placeholder para la fecha de inicio en modo rango | string | — | — |
| end-placeholder | placeholder para la fecha final en modo rango | string | — | — |
| type | tipo de picker | string | year/month/date/dates/datetime/ week/datetimerange/daterange/ monthrange | date |
| type | tipo de picker | string | year/month/date/dates/months/years/datetime/ week/datetimerange/daterange/ monthrange | date |
| format | formato en que se muestra el valor en el input | string | ver [date formats](#/es/component/date-picker#date-formats) | yyyy-MM-dd |
| align | alineación | left/center/right | left | |
| popper-class | nombre de clase personalizada para el dropdown de DatePicker | string | — | — |
Expand Down
24 changes: 22 additions & 2 deletions examples/docs/zh-CN/date-picker.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,24 @@
</el-date-picker>
</div>
</div>
<div class="container">
<div class="block">
<span class="demonstration">多个月</span>
<el-date-picker
type="months"
v-model="value5"
placeholder="选择一个或多个月">
</el-date-picker>
</div>
<div class="block">
<span class="demonstration">多个年</span>
<el-date-picker
type="years"
v-model="value6"
placeholder="选择一个或多个年">
</el-date-picker>
</div>
</div>

<script>
export default {
Expand All @@ -119,7 +137,9 @@
value1: '',
value2: '',
value3: '',
value4: ''
value4: '',
value5: '',
value6: ''
};
}
};
Expand Down Expand Up @@ -395,7 +415,7 @@
| placeholder | 非范围选择时的占位内容 | string | — | — |
| start-placeholder | 范围选择时开始日期的占位内容 | string | — | — |
| end-placeholder | 范围选择时结束日期的占位内容 | string | — | — |
| type | 显示类型 | string | year/month/date/dates/ week/datetime/datetimerange/ daterange/monthrange | date |
| type | 显示类型 | string | year/month/date/dates/months/years week/datetime/datetimerange/ daterange/monthrange | date |
| format | 显示在输入框中的格式 | string | 见[日期格式](#/zh-CN/component/date-picker#ri-qi-ge-shi) | yyyy-MM-dd |
| align | 对齐方式 | string | left, center, right | left |
| popper-class | DatePicker 下拉框的类名 | string | — | — |
Expand Down
15 changes: 15 additions & 0 deletions packages/date-picker/src/basic/month-table.vue
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,14 @@
return NaN;
}
};

// 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 {
props: {
disabledDate: {},
Expand Down Expand Up @@ -205,6 +213,13 @@
}
this.rangeState.selecting = false;
}
} else if (this.selectionMode === 'months') {
const value = this.value || [];
const year = this.date.getFullYear();
const newValue = arrayFindIndex(value, date => date.getFullYear() === year && date.getMonth() === month) >= 0
? removeFromArray(value, date => date.getTime() === newDate.getTime())
: [...value, newDate];
this.$emit('pick', newValue);
} else {
this.$emit('pick', month);
}
Expand Down
14 changes: 12 additions & 2 deletions packages/date-picker/src/basic/year-table.vue
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,8 @@
return val === null || (val instanceof Date && isDate(val));
}
},
date: {}
date: {},
selectionMode: {}
},

computed: {
Expand Down Expand Up @@ -93,7 +94,16 @@
if (target.tagName === 'A') {
if (hasClass(target.parentNode, 'disabled')) return;
const year = target.textContent || target.innerText;
this.$emit('pick', Number(year));
if (this.selectionMode === 'years') {
const value = this.value || [];
const idx = arrayFindIndex(value, date => date.getFullYear() === Number(year));
const newValue = idx > -1
? [...value.slice(0, idx), ...value.slice(idx + 1)]
: [...value, new Date(year)];
this.$emit('pick', newValue);
} else {
this.$emit('pick', Number(year));
}
}
}
}
Expand Down
24 changes: 18 additions & 6 deletions packages/date-picker/src/panel/date.vue
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@
<year-table
v-show="currentView === 'year'"
@pick="handleYearPick"
:selection-mode="selectionMode"
:value="value"
:default-value="defaultValue ? new Date(defaultValue) : null"
:date="date"
Expand All @@ -110,6 +111,7 @@
<month-table
v-show="currentView === 'month'"
@pick="handleMonthPick"
:selection-mode="selectionMode"
:value="value"
:default-value="defaultValue ? new Date(defaultValue) : null"
:date="date"
Expand All @@ -121,13 +123,13 @@

<div
class="el-picker-panel__footer"
v-show="footerVisible && currentView === 'date'">
v-show="footerVisible && (currentView === 'date' || currentView === 'month' || currentView === 'year')">
<el-button
size="mini"
type="text"
class="el-picker-panel__link-btn"
@click="changeToNow"
v-show="selectionMode !== 'dates'">
v-show="selectionMode !== 'dates' && selectionMode !== 'months' && selectionMode !== 'years'">
{{ t('el.datepicker.now') }}
</el-button>
<el-button
Expand Down Expand Up @@ -190,6 +192,8 @@

value(val) {
if (this.selectionMode === 'dates' && this.value) return;
if (this.selectionMode === 'months' && this.value) return;
if (this.selectionMode === 'years' && this.value) return;
if (isDate(val)) {
this.date = new Date(val);
} else {
Expand All @@ -215,6 +219,10 @@
}
} else if (newVal === 'dates') {
this.currentView = 'date';
} else if (newVal === 'years') {
this.currentView = 'year';
} else if (newVal === 'months') {
this.currentView = 'month';
}
}
},
Expand Down Expand Up @@ -328,6 +336,8 @@
if (this.selectionMode === 'month') {
this.date = modifyDate(this.date, this.year, month, 1);
this.emit(this.date);
} else if (this.selectionMode === 'months') {
this.emit(month, true);
} else {
this.date = changeYearMonthAndClampDate(this.date, this.year, month);
// TODO: should emit intermediate value ??
Expand Down Expand Up @@ -358,6 +368,8 @@
if (this.selectionMode === 'year') {
this.date = modifyDate(this.date, year, 0, 1);
this.emit(this.date);
} else if (this.selectionMode === 'years') {
this.emit(year, true);
} else {
this.date = changeYearMonthAndClampDate(this.date, year, this.month);
// TODO: should emit intermediate value ??
Expand All @@ -376,7 +388,7 @@
},

confirm() {
if (this.selectionMode === 'dates') {
if (this.selectionMode === 'dates' || this.selectionMode === 'months' || this.selectionMode === 'years') {
this.emit(this.value);
} else {
// value were emitted in handle{Date,Time}Pick, nothing to update here
Expand All @@ -390,9 +402,9 @@
},

resetView() {
if (this.selectionMode === 'month') {
if (this.selectionMode === 'month' || this.selectionMode === 'months') {
this.currentView = 'month';
} else if (this.selectionMode === 'year') {
} else if (this.selectionMode === 'year' || this.selectionMode === 'years') {
this.currentView = 'year';
} else {
this.currentView = 'date';
Expand Down Expand Up @@ -546,7 +558,7 @@
},

footerVisible() {
return this.showTime || this.selectionMode === 'dates';
return this.showTime || this.selectionMode === 'dates' || this.selectionMode === 'months' || this.selectionMode === 'years';
},

visibleTime() {
Expand Down
36 changes: 31 additions & 5 deletions packages/date-picker/src/picker.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<el-input
class="el-date-editor"
:class="'el-date-editor--' + type"
:readonly="!editable || readonly || type === 'dates' || type === 'week'"
:readonly="!editable || readonly || type === 'dates' || type === 'week' || type === 'years' || type === 'months'"
:disabled="pickerDisabled"
:size="pickerSize"
:name="name"
Expand Down Expand Up @@ -111,14 +111,16 @@ const NewPopper = {
const DEFAULT_FORMATS = {
date: 'yyyy-MM-dd',
month: 'yyyy-MM',
months: 'yyyy-MM',
datetime: 'yyyy-MM-dd HH:mm:ss',
time: 'HH:mm:ss',
week: 'yyyywWW',
timerange: 'HH:mm:ss',
daterange: 'yyyy-MM-dd',
monthrange: 'yyyy-MM',
datetimerange: 'yyyy-MM-dd HH:mm:ss',
year: 'yyyy'
year: 'yyyy',
years: 'yyyy'
};
const HAVE_TRIGGER_TYPES = [
'date',
Expand All @@ -132,7 +134,9 @@ const HAVE_TRIGGER_TYPES = [
'monthrange',
'timerange',
'datetimerange',
'dates'
'dates',
'months',
'years'
];
const DATE_FORMATTER = function(value, format) {
if (format === 'timestamp') return value.getTime();
Expand Down Expand Up @@ -256,6 +260,24 @@ const TYPE_VALUE_RESOLVER_MAP = {
return (typeof value === 'string' ? value.split(', ') : value)
.map(date => date instanceof Date ? date : DATE_PARSER(date, format));
}
},
months: {
formatter(value, format) {
return value.map(date => DATE_FORMATTER(date, format));
},
parser(value, format) {
return (typeof value === 'string' ? value.split(', ') : value)
.map(date => date instanceof Date ? date : DATE_PARSER(date, format));
}
},
years: {
formatter(value, format) {
return value.map(date => DATE_FORMATTER(date, format));
},
parser(value, format) {
return (typeof value === 'string' ? value.split(', ') : value)
.map(date => date instanceof Date ? date : DATE_PARSER(date, format));
}
}
};
const PLACEMENT_MAP = {
Expand Down Expand Up @@ -491,6 +513,10 @@ export default {
return 'year';
} else if (this.type === 'dates') {
return 'dates';
} else if (this.type === 'months') {
return 'months';
} else if (this.type === 'years') {
return 'years';
}

return 'day';
Expand All @@ -513,7 +539,7 @@ export default {
} else if (this.userInput !== null) {
return this.userInput;
} else if (formattedValue) {
return this.type === 'dates'
return (this.type === 'dates' || this.type === 'years' || this.type === 'months')
? formattedValue.join(', ')
: formattedValue;
} else {
Expand Down Expand Up @@ -715,7 +741,7 @@ export default {
if (!this.pickerVisible) return;
this.pickerVisible = false;

if (this.type === 'dates') {
if (this.type === 'dates' || this.type === 'years' || this.type === 'months') {
// restore to former value
const oldValue = parseAsFormatAndType(this.valueOnOpen, this.valueFormat, this.type, this.rangeSeparator) || this.valueOnOpen;
this.emitInput(oldValue);
Expand Down