Merge pull request #3643 from SergioCrisostomo/datepicker-keyboard
Datepicker keyboard
This commit is contained in:
commit
bdb26ef7c8
17 changed files with 494 additions and 77 deletions
|
@ -249,14 +249,17 @@
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div style="width: 500px;margin: 100px;">
|
<div style="width: 500px;margin: 100px;">
|
||||||
<Row>
|
<p><input type="text"></p>
|
||||||
<Col span="12">
|
|
||||||
<DatePicker type="date" show-week-numbers placeholder="Select date" style="width: 200px"></DatePicker>
|
<DatePicker type="month" show-week-numbers placeholder="Select date" style="width: 200px"></DatePicker>
|
||||||
</Col>
|
<DatePicker type="year" show-week-numbers placeholder="Select date" style="width: 200px"></DatePicker>
|
||||||
<Col span="12">
|
|
||||||
<DatePicker type="daterange" show-week-numbers placement="bottom-end" placeholder="Select date" style="width: 200px"></DatePicker>
|
<DatePicker type="date" transfer show-week-numbers placeholder="Select date" style="width: 400px"></DatePicker>
|
||||||
</Col>
|
<DatePicker type="datetime" show-week-numbers confirm placeholder="Select date" style="width: 400px"></DatePicker>
|
||||||
</Row>
|
|
||||||
|
<DatePicker type="daterange" transfer show-week-numbers placeholder="Select date" style="width: 400px"></DatePicker>
|
||||||
|
<DatePicker type="datetimerange" transfer show-week-numbers placeholder="Select date" style="width: 400px"></DatePicker>
|
||||||
|
<Time-Picker :steps="[1, 1, 15]" :value="new Date()"></Time-Picker>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
|
|
|
@ -1,21 +1,25 @@
|
||||||
<template>
|
<template>
|
||||||
<div :class="[prefixCls + '-confirm']">
|
<div :class="[prefixCls + '-confirm']" @keydown.tab.capture="handleTab">
|
||||||
<span :class="timeClasses" v-if="showTime" @click="handleToggleTime">
|
<i-button :class="timeClasses" size="small" type="text" :disabled="timeDisabled" v-if="showTime" @click="handleToggleTime">
|
||||||
<template v-if="isTime">{{ t('i.datepicker.selectDate') }}</template>
|
{{labels.time}}
|
||||||
<template v-else>{{ t('i.datepicker.selectTime') }}</template>
|
</i-button>
|
||||||
</span>
|
<i-button size="small" type="ghost" @click.native="handleClear" @keydown.enter.native="handleClear">
|
||||||
<i-button size="small" type="text" @click.native="handleClear">{{ t('i.datepicker.clear') }}</i-button>
|
{{labels.clear}}
|
||||||
<i-button size="small" type="primary" @click.native="handleSuccess">{{ t('i.datepicker.ok') }}</i-button>
|
</i-button>
|
||||||
|
<i-button size="small" type="primary" @click.native="handleSuccess" @keydown.enter.native="handleSuccess">
|
||||||
|
{{labels.ok}}
|
||||||
|
</i-button>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
import iButton from '../../button/button.vue';
|
import iButton from '../../button/button.vue';
|
||||||
import Locale from '../../../mixins/locale';
|
import Locale from '../../../mixins/locale';
|
||||||
|
import Emitter from '../../../mixins/emitter';
|
||||||
|
|
||||||
const prefixCls = 'ivu-picker';
|
const prefixCls = 'ivu-picker';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
mixins: [ Locale ],
|
mixins: [Locale, Emitter],
|
||||||
components: {iButton},
|
components: {iButton},
|
||||||
props: {
|
props: {
|
||||||
showTime: false,
|
showTime: false,
|
||||||
|
@ -29,9 +33,15 @@
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
timeClasses () {
|
timeClasses () {
|
||||||
return {
|
return `${prefixCls}-confirm-time`;
|
||||||
[`${prefixCls}-confirm-time-disabled`]: this.timeDisabled
|
},
|
||||||
};
|
labels(){
|
||||||
|
const labels = ['time', 'clear', 'ok'];
|
||||||
|
const values = [(this.isTime ? 'selectDate' : 'selectTime'), 'clear', 'ok'];
|
||||||
|
return labels.reduce((obj, key, i) => {
|
||||||
|
obj[key] = this.t('i.datepicker.' + values[i]);
|
||||||
|
return obj;
|
||||||
|
}, {});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
@ -44,6 +54,17 @@
|
||||||
handleToggleTime () {
|
handleToggleTime () {
|
||||||
if (this.timeDisabled) return;
|
if (this.timeDisabled) return;
|
||||||
this.$emit('on-pick-toggle-time');
|
this.$emit('on-pick-toggle-time');
|
||||||
|
this.dispatch('CalendarPicker', 'focus-input');
|
||||||
|
},
|
||||||
|
handleTab(e) {
|
||||||
|
const tabbables = [...this.$el.children];
|
||||||
|
const expectedFocus = tabbables[e.shiftKey ? 'shift' : 'pop']();
|
||||||
|
|
||||||
|
if (document.activeElement === expectedFocus) {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
this.dispatch('CalendarPicker', 'focus-input');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -7,9 +7,9 @@
|
||||||
</div>
|
</div>
|
||||||
<span
|
<span
|
||||||
:class="getCellCls(cell)"
|
:class="getCellCls(cell)"
|
||||||
v-for="(cell, i) in readCells"
|
v-for="(cell, i) in cells"
|
||||||
:key="String(cell.date) + i"
|
:key="String(cell.date) + i"
|
||||||
@click="handleClick(cell)"
|
@click="handleClick(cell, $event)"
|
||||||
@mouseenter="handleMouseMove(cell)"
|
@mouseenter="handleMouseMove(cell)"
|
||||||
>
|
>
|
||||||
<em>{{ cell.desc }}</em>
|
<em>{{ cell.desc }}</em>
|
||||||
|
@ -61,7 +61,7 @@
|
||||||
const weekDays = translatedDays.splice(weekStartDay, 7 - weekStartDay).concat(translatedDays.splice(0, weekStartDay));
|
const weekDays = translatedDays.splice(weekStartDay, 7 - weekStartDay).concat(translatedDays.splice(0, weekStartDay));
|
||||||
return this.showWeekNumbers ? [''].concat(weekDays) : weekDays;
|
return this.showWeekNumbers ? [''].concat(weekDays) : weekDays;
|
||||||
},
|
},
|
||||||
readCells () {
|
cells () {
|
||||||
const tableYear = this.tableDate.getFullYear();
|
const tableYear = this.tableDate.getFullYear();
|
||||||
const tableMonth = this.tableDate.getMonth();
|
const tableMonth = this.tableDate.getMonth();
|
||||||
const today = clearHours(new Date()); // timestamp of today
|
const today = clearHours(new Date()); // timestamp of today
|
||||||
|
@ -99,7 +99,9 @@
|
||||||
[`${prefixCls}-cell-prev-month`]: cell.type === 'prevMonth',
|
[`${prefixCls}-cell-prev-month`]: cell.type === 'prevMonth',
|
||||||
[`${prefixCls}-cell-next-month`]: cell.type === 'nextMonth',
|
[`${prefixCls}-cell-next-month`]: cell.type === 'nextMonth',
|
||||||
[`${prefixCls}-cell-week-label`]: cell.type === 'weekLabel',
|
[`${prefixCls}-cell-week-label`]: cell.type === 'weekLabel',
|
||||||
[`${prefixCls}-cell-range`]: cell.range && !cell.start && !cell.end
|
[`${prefixCls}-cell-range`]: cell.range && !cell.start && !cell.end,
|
||||||
|
[`${prefixCls}-focused`]: clearHours(cell.date) === clearHours(this.focusedDate)
|
||||||
|
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
},
|
},
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
import {clearHours} from '../util';
|
import {clearHours} from '../util';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
name: 'PanelTable',
|
||||||
props: {
|
props: {
|
||||||
tableDate: {
|
tableDate: {
|
||||||
type: Date,
|
type: Date,
|
||||||
|
@ -26,7 +27,10 @@ export default {
|
||||||
selecting: false
|
selecting: false
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
focusedDate: {
|
||||||
|
type: Date,
|
||||||
|
required: true,
|
||||||
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
dates(){
|
dates(){
|
||||||
|
|
|
@ -38,14 +38,16 @@
|
||||||
|
|
||||||
const tableYear = this.tableDate.getFullYear();
|
const tableYear = this.tableDate.getFullYear();
|
||||||
const selectedDays = this.dates.filter(Boolean).map(date => clearHours(new Date(date.getFullYear(), date.getMonth(), 1)));
|
const selectedDays = this.dates.filter(Boolean).map(date => clearHours(new Date(date.getFullYear(), date.getMonth(), 1)));
|
||||||
|
const focusedDate = clearHours(new Date(this.focusedDate.getFullYear(), this.focusedDate.getMonth(), 1));
|
||||||
|
|
||||||
for (let i = 0; i < 12; i++) {
|
for (let i = 0; i < 12; i++) {
|
||||||
const cell = deepCopy(cell_tmpl);
|
const cell = deepCopy(cell_tmpl);
|
||||||
cell.date = new Date(tableYear, i, 1);
|
cell.date = new Date(tableYear, i, 1);
|
||||||
cell.text = this.tCell(i + 1);
|
cell.text = this.tCell(i + 1);
|
||||||
const time = clearHours(cell.date);
|
const day = clearHours(cell.date);
|
||||||
cell.disabled = typeof this.disabledDate === 'function' && this.disabledDate(cell.date) && this.selectionMode === 'month';
|
cell.disabled = typeof this.disabledDate === 'function' && this.disabledDate(cell.date) && this.selectionMode === 'month';
|
||||||
cell.selected = selectedDays.includes(time);
|
cell.selected = selectedDays.includes(day);
|
||||||
|
cell.focused = day === focusedDate;
|
||||||
cells.push(cell);
|
cells.push(cell);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,6 +61,7 @@
|
||||||
{
|
{
|
||||||
[`${prefixCls}-cell-selected`]: cell.selected,
|
[`${prefixCls}-cell-selected`]: cell.selected,
|
||||||
[`${prefixCls}-cell-disabled`]: cell.disabled,
|
[`${prefixCls}-cell-disabled`]: cell.disabled,
|
||||||
|
[`${prefixCls}-cell-focused`]: cell.focused,
|
||||||
[`${prefixCls}-cell-range`]: cell.range && !cell.start && !cell.end
|
[`${prefixCls}-cell-range`]: cell.range && !cell.start && !cell.end
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
|
@ -22,8 +22,10 @@
|
||||||
import { deepCopy, scrollTop, firstUpperCase } from '../../../utils/assist';
|
import { deepCopy, scrollTop, firstUpperCase } from '../../../utils/assist';
|
||||||
|
|
||||||
const prefixCls = 'ivu-time-picker-cells';
|
const prefixCls = 'ivu-time-picker-cells';
|
||||||
|
const timeParts = ['hours', 'minutes', 'seconds'];
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
name: 'TimeSpinner',
|
||||||
mixins: [Options],
|
mixins: [Options],
|
||||||
props: {
|
props: {
|
||||||
hours: {
|
hours: {
|
||||||
|
@ -51,7 +53,9 @@
|
||||||
return {
|
return {
|
||||||
spinerSteps: [1, 1, 1].map((one, i) => Math.abs(this.steps[i]) || one),
|
spinerSteps: [1, 1, 1].map((one, i) => Math.abs(this.steps[i]) || one),
|
||||||
prefixCls: prefixCls,
|
prefixCls: prefixCls,
|
||||||
compiled: false
|
compiled: false,
|
||||||
|
focusedColumn: -1, // which column inside the picker
|
||||||
|
focusedTime: [0, 0, 0] // the values array into [hh, mm, ss]
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
@ -66,6 +70,7 @@
|
||||||
hoursList () {
|
hoursList () {
|
||||||
let hours = [];
|
let hours = [];
|
||||||
const step = this.spinerSteps[0];
|
const step = this.spinerSteps[0];
|
||||||
|
const focusedHour = this.focusedColumn === 0 && this.focusedTime[0];
|
||||||
const hour_tmpl = {
|
const hour_tmpl = {
|
||||||
text: 0,
|
text: 0,
|
||||||
selected: false,
|
selected: false,
|
||||||
|
@ -76,6 +81,7 @@
|
||||||
for (let i = 0; i < 24; i += step) {
|
for (let i = 0; i < 24; i += step) {
|
||||||
const hour = deepCopy(hour_tmpl);
|
const hour = deepCopy(hour_tmpl);
|
||||||
hour.text = i;
|
hour.text = i;
|
||||||
|
hour.focused = i === focusedHour;
|
||||||
|
|
||||||
if (this.disabledHours.length && this.disabledHours.indexOf(i) > -1) {
|
if (this.disabledHours.length && this.disabledHours.indexOf(i) > -1) {
|
||||||
hour.disabled = true;
|
hour.disabled = true;
|
||||||
|
@ -90,6 +96,7 @@
|
||||||
minutesList () {
|
minutesList () {
|
||||||
let minutes = [];
|
let minutes = [];
|
||||||
const step = this.spinerSteps[1];
|
const step = this.spinerSteps[1];
|
||||||
|
const focusedMinute = this.focusedColumn === 1 && this.focusedTime[1];
|
||||||
const minute_tmpl = {
|
const minute_tmpl = {
|
||||||
text: 0,
|
text: 0,
|
||||||
selected: false,
|
selected: false,
|
||||||
|
@ -100,6 +107,7 @@
|
||||||
for (let i = 0; i < 60; i += step) {
|
for (let i = 0; i < 60; i += step) {
|
||||||
const minute = deepCopy(minute_tmpl);
|
const minute = deepCopy(minute_tmpl);
|
||||||
minute.text = i;
|
minute.text = i;
|
||||||
|
minute.focused = i === focusedMinute;
|
||||||
|
|
||||||
if (this.disabledMinutes.length && this.disabledMinutes.indexOf(i) > -1) {
|
if (this.disabledMinutes.length && this.disabledMinutes.indexOf(i) > -1) {
|
||||||
minute.disabled = true;
|
minute.disabled = true;
|
||||||
|
@ -113,6 +121,7 @@
|
||||||
secondsList () {
|
secondsList () {
|
||||||
let seconds = [];
|
let seconds = [];
|
||||||
const step = this.spinerSteps[2];
|
const step = this.spinerSteps[2];
|
||||||
|
const focusedMinute = this.focusedColumn === 2 && this.focusedTime[2];
|
||||||
const second_tmpl = {
|
const second_tmpl = {
|
||||||
text: 0,
|
text: 0,
|
||||||
selected: false,
|
selected: false,
|
||||||
|
@ -123,6 +132,7 @@
|
||||||
for (let i = 0; i < 60; i += step) {
|
for (let i = 0; i < 60; i += step) {
|
||||||
const second = deepCopy(second_tmpl);
|
const second = deepCopy(second_tmpl);
|
||||||
second.text = i;
|
second.text = i;
|
||||||
|
second.focused = i === focusedMinute;
|
||||||
|
|
||||||
if (this.disabledSeconds.length && this.disabledSeconds.indexOf(i) > -1) {
|
if (this.disabledSeconds.length && this.disabledSeconds.indexOf(i) > -1) {
|
||||||
second.disabled = true;
|
second.disabled = true;
|
||||||
|
@ -141,15 +151,32 @@
|
||||||
`${prefixCls}-cell`,
|
`${prefixCls}-cell`,
|
||||||
{
|
{
|
||||||
[`${prefixCls}-cell-selected`]: cell.selected,
|
[`${prefixCls}-cell-selected`]: cell.selected,
|
||||||
|
[`${prefixCls}-cell-focused`]: cell.focused,
|
||||||
[`${prefixCls}-cell-disabled`]: cell.disabled
|
[`${prefixCls}-cell-disabled`]: cell.disabled
|
||||||
|
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
},
|
},
|
||||||
|
chooseValue(values){
|
||||||
|
const changes = timeParts.reduce((obj, part, i) => {
|
||||||
|
const value = values[i];
|
||||||
|
if (this[part] === value) return obj;
|
||||||
|
return {
|
||||||
|
...obj,
|
||||||
|
[part]: value
|
||||||
|
};
|
||||||
|
}, {});
|
||||||
|
if (Object.keys(changes).length > 0) {
|
||||||
|
this.emitChange(changes);
|
||||||
|
}
|
||||||
|
},
|
||||||
handleClick (type, cell) {
|
handleClick (type, cell) {
|
||||||
if (cell.disabled) return;
|
if (cell.disabled) return;
|
||||||
const data = {};
|
const data = {[type]: cell.text};
|
||||||
data[type] = cell.text;
|
this.emitChange(data);
|
||||||
this.$emit('on-change', data);
|
},
|
||||||
|
emitChange(changes){
|
||||||
|
this.$emit('on-change', changes);
|
||||||
this.$emit('on-pick-click');
|
this.$emit('on-pick-click');
|
||||||
},
|
},
|
||||||
scroll (type, index) {
|
scroll (type, index) {
|
||||||
|
@ -168,15 +195,19 @@
|
||||||
return index;
|
return index;
|
||||||
},
|
},
|
||||||
updateScroll () {
|
updateScroll () {
|
||||||
const times = ['hours', 'minutes', 'seconds'];
|
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
times.forEach(type => {
|
timeParts.forEach(type => {
|
||||||
this.$refs[type].scrollTop = 24 * this[`${type}List`].findIndex(obj => obj.text == this[type]);
|
this.$refs[type].scrollTop = 24 * this[`${type}List`].findIndex(obj => obj.text == this[type]);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
formatTime (text) {
|
formatTime (text) {
|
||||||
return text < 10 ? '0' + text : text;
|
return text < 10 ? '0' + text : text;
|
||||||
|
},
|
||||||
|
updateFocusedTime(col, time) {
|
||||||
|
this.focusedColumn = col;
|
||||||
|
this.focusedTime = time.slice();
|
||||||
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
|
@ -191,6 +222,13 @@
|
||||||
seconds (val) {
|
seconds (val) {
|
||||||
if (!this.compiled) return;
|
if (!this.compiled) return;
|
||||||
this.scroll('seconds', this.secondsList.findIndex(obj => obj.text == val));
|
this.scroll('seconds', this.secondsList.findIndex(obj => obj.text == val));
|
||||||
|
},
|
||||||
|
focusedTime(updated, old){
|
||||||
|
timeParts.forEach((part, i) => {
|
||||||
|
if (updated[i] === old[i] || typeof updated[i] === 'undefined') return;
|
||||||
|
const valueIndex = this[`${part}List`].findIndex(obj => obj.text === updated[i]);
|
||||||
|
this.scroll(part, valueIndex);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted () {
|
mounted () {
|
||||||
|
|
|
@ -39,13 +39,15 @@
|
||||||
};
|
};
|
||||||
|
|
||||||
const selectedDays = this.dates.filter(Boolean).map(date => clearHours(new Date(date.getFullYear(), 0, 1)));
|
const selectedDays = this.dates.filter(Boolean).map(date => clearHours(new Date(date.getFullYear(), 0, 1)));
|
||||||
|
const focusedDate = clearHours(new Date(this.focusedDate.getFullYear(), 0, 1));
|
||||||
|
|
||||||
for (let i = 0; i < 10; i++) {
|
for (let i = 0; i < 10; i++) {
|
||||||
const cell = deepCopy(cell_tmpl);
|
const cell = deepCopy(cell_tmpl);
|
||||||
cell.date = new Date(this.startYear + i, 0, 1);
|
cell.date = new Date(this.startYear + i, 0, 1);
|
||||||
cell.disabled = typeof this.disabledDate === 'function' && this.disabledDate(cell.date) && this.selectionMode === 'year';
|
cell.disabled = typeof this.disabledDate === 'function' && this.disabledDate(cell.date) && this.selectionMode === 'year';
|
||||||
const time = clearHours(cell.date);
|
const day = clearHours(cell.date);
|
||||||
cell.selected = selectedDays.includes(time);
|
cell.selected = selectedDays.includes(day);
|
||||||
|
cell.focused = day === focusedDate;
|
||||||
cells.push(cell);
|
cells.push(cell);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,6 +61,7 @@
|
||||||
{
|
{
|
||||||
[`${prefixCls}-cell-selected`]: cell.selected,
|
[`${prefixCls}-cell-selected`]: cell.selected,
|
||||||
[`${prefixCls}-cell-disabled`]: cell.disabled,
|
[`${prefixCls}-cell-disabled`]: cell.disabled,
|
||||||
|
[`${prefixCls}-cell-focused`]: cell.focused,
|
||||||
[`${prefixCls}-cell-range`]: cell.range && !cell.start && !cell.end
|
[`${prefixCls}-cell-range`]: cell.range && !cell.start && !cell.end
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
|
@ -46,6 +46,10 @@ export default {
|
||||||
pickerType: {
|
pickerType: {
|
||||||
type: String,
|
type: String,
|
||||||
require: true
|
require: true
|
||||||
|
},
|
||||||
|
focusedDate: {
|
||||||
|
type: Date,
|
||||||
|
required: true,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
|
|
@ -41,6 +41,8 @@
|
||||||
:range-state="rangeState"
|
:range-state="rangeState"
|
||||||
:show-week-numbers="showWeekNumbers"
|
:show-week-numbers="showWeekNumbers"
|
||||||
:value="preSelecting.left ? [dates[0]] : dates"
|
:value="preSelecting.left ? [dates[0]] : dates"
|
||||||
|
:focused-date="focusedDate"
|
||||||
|
|
||||||
@on-change-range="handleChangeRange"
|
@on-change-range="handleChangeRange"
|
||||||
@on-pick="panelPickerHandlers.left"
|
@on-pick="panelPickerHandlers.left"
|
||||||
@on-pick-click="handlePickClick"
|
@on-pick-click="handlePickClick"
|
||||||
|
@ -80,6 +82,8 @@
|
||||||
:disabled-date="disabledDate"
|
:disabled-date="disabledDate"
|
||||||
:show-week-numbers="showWeekNumbers"
|
:show-week-numbers="showWeekNumbers"
|
||||||
:value="preSelecting.right ? [dates[dates.length - 1]] : dates"
|
:value="preSelecting.right ? [dates[dates.length - 1]] : dates"
|
||||||
|
:focused-date="focusedDate"
|
||||||
|
|
||||||
@on-change-range="handleChangeRange"
|
@on-change-range="handleChangeRange"
|
||||||
@on-pick="panelPickerHandlers.right"
|
@on-pick="panelPickerHandlers.right"
|
||||||
@on-pick-click="handlePickClick"></component>
|
@on-pick-click="handlePickClick"></component>
|
||||||
|
@ -178,7 +182,7 @@
|
||||||
[prefixCls + '-body-time']: this.showTime,
|
[prefixCls + '-body-time']: this.showTime,
|
||||||
[prefixCls + '-body-date']: !this.showTime,
|
[prefixCls + '-body-date']: !this.showTime,
|
||||||
}
|
}
|
||||||
]
|
];
|
||||||
},
|
},
|
||||||
leftDatePanelLabel(){
|
leftDatePanelLabel(){
|
||||||
return this.panelLabelConfig('left');
|
return this.panelLabelConfig('left');
|
||||||
|
@ -224,10 +228,7 @@
|
||||||
|
|
||||||
|
|
||||||
// set panels positioning
|
// set panels positioning
|
||||||
const leftPanelDate = this.startDate || this.dates[0] || new Date();
|
this.setPanelDates(this.startDate || this.dates[0] || new Date());
|
||||||
this.leftPanelDate = leftPanelDate;
|
|
||||||
const rightPanelDate = new Date(leftPanelDate.getFullYear(), leftPanelDate.getMonth() + 1, leftPanelDate.getDate());
|
|
||||||
this.rightPanelDate = this.splitPanels ? new Date(Math.max(this.dates[1], rightPanelDate)) : rightPanelDate;
|
|
||||||
},
|
},
|
||||||
currentView(currentView){
|
currentView(currentView){
|
||||||
const leftMonth = this.leftPanelDate.getMonth();
|
const leftMonth = this.leftPanelDate.getMonth();
|
||||||
|
@ -246,6 +247,9 @@
|
||||||
},
|
},
|
||||||
selectionMode(type){
|
selectionMode(type){
|
||||||
this.currentView = type || 'range';
|
this.currentView = type || 'range';
|
||||||
|
},
|
||||||
|
focusedDate(date){
|
||||||
|
this.setPanelDates(date || new Date());
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
@ -254,6 +258,11 @@
|
||||||
this.leftPickerTable = `${this.currentView}-table`;
|
this.leftPickerTable = `${this.currentView}-table`;
|
||||||
this.rightPickerTable = `${this.currentView}-table`;
|
this.rightPickerTable = `${this.currentView}-table`;
|
||||||
},
|
},
|
||||||
|
setPanelDates(leftPanelDate){
|
||||||
|
this.leftPanelDate = leftPanelDate;
|
||||||
|
const rightPanelDate = new Date(leftPanelDate.getFullYear(), leftPanelDate.getMonth() + 1, leftPanelDate.getDate());
|
||||||
|
this.rightPanelDate = this.splitPanels ? new Date(Math.max(this.dates[1], rightPanelDate)) : rightPanelDate;
|
||||||
|
},
|
||||||
panelLabelConfig (direction) {
|
panelLabelConfig (direction) {
|
||||||
const locale = this.t('i.locale');
|
const locale = this.t('i.locale');
|
||||||
const datePanelLabel = this.t('i.datepicker.datePanelLabel');
|
const datePanelLabel = this.t('i.datepicker.datePanelLabel');
|
||||||
|
|
|
@ -39,6 +39,8 @@
|
||||||
:value="dates"
|
:value="dates"
|
||||||
:selection-mode="selectionMode"
|
:selection-mode="selectionMode"
|
||||||
:disabled-date="disabledDate"
|
:disabled-date="disabledDate"
|
||||||
|
:focused-date="focusedDate"
|
||||||
|
|
||||||
@on-pick="panelPickerHandlers"
|
@on-pick="panelPickerHandlers"
|
||||||
@on-pick-click="handlePickClick"
|
@on-pick-click="handlePickClick"
|
||||||
></component>
|
></component>
|
||||||
|
@ -51,6 +53,8 @@
|
||||||
:format="format"
|
:format="format"
|
||||||
:time-disabled="timeDisabled"
|
:time-disabled="timeDisabled"
|
||||||
:disabled-date="disabledDate"
|
:disabled-date="disabledDate"
|
||||||
|
:focused-date="focusedDate"
|
||||||
|
|
||||||
v-bind="timePickerOptions"
|
v-bind="timePickerOptions"
|
||||||
@on-pick="handlePick"
|
@on-pick="handlePick"
|
||||||
@on-pick-click="handlePickClick"
|
@on-pick-click="handlePickClick"
|
||||||
|
@ -150,7 +154,6 @@
|
||||||
},
|
},
|
||||||
currentView (currentView) {
|
currentView (currentView) {
|
||||||
this.$emit('on-selection-mode-change', currentView);
|
this.$emit('on-selection-mode-change', currentView);
|
||||||
this.pickertable = this.getTableType(currentView);
|
|
||||||
|
|
||||||
if (this.currentView === 'time') {
|
if (this.currentView === 'time') {
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
|
@ -162,6 +165,13 @@
|
||||||
selectionMode(type){
|
selectionMode(type){
|
||||||
this.currentView = type;
|
this.currentView = type;
|
||||||
this.pickerTable = this.getTableType(type);
|
this.pickerTable = this.getTableType(type);
|
||||||
|
},
|
||||||
|
focusedDate(date){
|
||||||
|
const isDifferentYear = date.getFullYear() !== this.panelDate.getFullYear();
|
||||||
|
const isDifferentMonth = isDifferentYear || date.getMonth() !== this.panelDate.getMonth();
|
||||||
|
if (isDifferentYear || isDifferentMonth){
|
||||||
|
this.panelDate = date;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
<template>
|
<template>
|
||||||
<div :class="[prefixCls]" v-clickoutside="handleClose">
|
<div
|
||||||
|
:class="wrapperClasses"
|
||||||
|
v-click-outside:mousedown.capture="handleClose"
|
||||||
|
v-click-outside.capture="handleClose"
|
||||||
|
>
|
||||||
<div ref="reference" :class="[prefixCls + '-rel']">
|
<div ref="reference" :class="[prefixCls + '-rel']">
|
||||||
<slot>
|
<slot>
|
||||||
<i-input
|
<i-input
|
||||||
|
@ -12,10 +16,14 @@
|
||||||
:placeholder="placeholder"
|
:placeholder="placeholder"
|
||||||
:value="visualValue"
|
:value="visualValue"
|
||||||
:name="name"
|
:name="name"
|
||||||
|
ref="input"
|
||||||
|
|
||||||
@on-input-change="handleInputChange"
|
@on-input-change="handleInputChange"
|
||||||
@on-focus="handleFocus"
|
@on-focus="handleFocus"
|
||||||
@on-blur="handleBlur"
|
@on-blur="handleBlur"
|
||||||
@on-click="handleIconClick"
|
@on-click="handleIconClick"
|
||||||
|
@click.native="handleFocus"
|
||||||
|
@keydown.native="handleKeydown"
|
||||||
@mouseenter.native="handleInputMouseenter"
|
@mouseenter.native="handleInputMouseenter"
|
||||||
@mouseleave.native="handleInputMouseleave"
|
@mouseleave.native="handleInputMouseleave"
|
||||||
|
|
||||||
|
@ -48,6 +56,7 @@
|
||||||
:show-week-numbers="showWeekNumbers"
|
:show-week-numbers="showWeekNumbers"
|
||||||
:picker-type="type"
|
:picker-type="type"
|
||||||
:multiple="multiple"
|
:multiple="multiple"
|
||||||
|
:focused-date="focusedDate"
|
||||||
|
|
||||||
:time-picker-options="timePickerOptions"
|
:time-picker-options="timePickerOptions"
|
||||||
|
|
||||||
|
@ -69,21 +78,49 @@
|
||||||
|
|
||||||
import iInput from '../../components/input/input.vue';
|
import iInput from '../../components/input/input.vue';
|
||||||
import Drop from '../../components/select/dropdown.vue';
|
import Drop from '../../components/select/dropdown.vue';
|
||||||
import clickoutside from '../../directives/clickoutside';
|
import vClickOutside from 'v-click-outside-x/index';
|
||||||
import TransferDom from '../../directives/transfer-dom';
|
import TransferDom from '../../directives/transfer-dom';
|
||||||
import { oneOf } from '../../utils/assist';
|
import { oneOf } from '../../utils/assist';
|
||||||
import { DEFAULT_FORMATS, RANGE_SEPARATOR, TYPE_VALUE_RESOLVER_MAP } from './util';
|
import { DEFAULT_FORMATS, RANGE_SEPARATOR, TYPE_VALUE_RESOLVER_MAP, getDayCountOfMonth } from './util';
|
||||||
|
import {findComponentsDownward} from '../../utils/assist';
|
||||||
import Emitter from '../../mixins/emitter';
|
import Emitter from '../../mixins/emitter';
|
||||||
|
|
||||||
const prefixCls = 'ivu-date-picker';
|
const prefixCls = 'ivu-date-picker';
|
||||||
|
const pickerPrefixCls = 'ivu-picker';
|
||||||
|
|
||||||
const isEmptyArray = val => val.reduce((isEmpty, str) => isEmpty && !str || (typeof str === 'string' && str.trim() === ''), true);
|
const isEmptyArray = val => val.reduce((isEmpty, str) => isEmpty && !str || (typeof str === 'string' && str.trim() === ''), true);
|
||||||
|
const keyValueMapper = {
|
||||||
|
40: 'up',
|
||||||
|
39: 'right',
|
||||||
|
38: 'down',
|
||||||
|
37: 'left',
|
||||||
|
};
|
||||||
|
|
||||||
|
const mapPossibleValues = (key, horizontal, vertical) => {
|
||||||
|
if (key === 'left') return horizontal * -1;
|
||||||
|
if (key === 'right') return horizontal * 1;
|
||||||
|
if (key === 'up') return vertical * 1;
|
||||||
|
if (key === 'down') return vertical * -1;
|
||||||
|
};
|
||||||
|
|
||||||
|
const pulseElement = (el) => {
|
||||||
|
const pulseClass = 'ivu-date-picker-btn-pulse';
|
||||||
|
el.classList.add(pulseClass);
|
||||||
|
setTimeout(() => el.classList.remove(pulseClass), 200);
|
||||||
|
};
|
||||||
|
|
||||||
|
const extractTime = date => {
|
||||||
|
if (!date) return [0, 0, 0];
|
||||||
|
return [
|
||||||
|
date.getHours(), date.getMinutes(), date.getSeconds()
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'CalendarPicker',
|
|
||||||
mixins: [ Emitter ],
|
mixins: [ Emitter ],
|
||||||
components: { iInput, Drop },
|
components: { iInput, Drop },
|
||||||
directives: { clickoutside, TransferDom },
|
directives: { clickOutside: vClickOutside.directive, TransferDom },
|
||||||
props: {
|
props: {
|
||||||
format: {
|
format: {
|
||||||
type: String
|
type: String
|
||||||
|
@ -172,6 +209,7 @@
|
||||||
const isRange = this.type.includes('range');
|
const isRange = this.type.includes('range');
|
||||||
const emptyArray = isRange ? [null, null] : [null];
|
const emptyArray = isRange ? [null, null] : [null];
|
||||||
const initialValue = isEmptyArray((isRange ? this.value : [this.value]) || []) ? emptyArray : this.parseDate(this.value);
|
const initialValue = isEmptyArray((isRange ? this.value : [this.value]) || []) ? emptyArray : this.parseDate(this.value);
|
||||||
|
const focusedTime = initialValue.map(extractTime);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
prefixCls: prefixCls,
|
prefixCls: prefixCls,
|
||||||
|
@ -181,10 +219,24 @@
|
||||||
disableClickOutSide: false, // fixed when click a date,trigger clickoutside to close picker
|
disableClickOutSide: false, // fixed when click a date,trigger clickoutside to close picker
|
||||||
disableCloseUnderTransfer: false, // transfer 模式下,点击Drop也会触发关闭,
|
disableCloseUnderTransfer: false, // transfer 模式下,点击Drop也会触发关闭,
|
||||||
selectionMode: this.onSelectionModeChange(this.type),
|
selectionMode: this.onSelectionModeChange(this.type),
|
||||||
forceInputRerender: 1
|
forceInputRerender: 1,
|
||||||
|
isFocused: false,
|
||||||
|
focusedDate: initialValue[0] || this.startDate || new Date(),
|
||||||
|
focusedTime: {
|
||||||
|
column: 0, // which column inside the picker
|
||||||
|
picker: 0, // which picker
|
||||||
|
time: focusedTime, // the values array into [hh, mm, ss],
|
||||||
|
active: false
|
||||||
|
},
|
||||||
|
internalFocus: false,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
wrapperClasses(){
|
||||||
|
return [prefixCls, {
|
||||||
|
[prefixCls + '-focused']: this.isFocused
|
||||||
|
}];
|
||||||
|
},
|
||||||
publicVModelValue(){
|
publicVModelValue(){
|
||||||
if (this.multiple){
|
if (this.multiple){
|
||||||
return this.internalValue.slice();
|
return this.internalValue.slice();
|
||||||
|
@ -232,32 +284,254 @@
|
||||||
handleTransferClick () {
|
handleTransferClick () {
|
||||||
if (this.transfer) this.disableCloseUnderTransfer = true;
|
if (this.transfer) this.disableCloseUnderTransfer = true;
|
||||||
},
|
},
|
||||||
handleClose () {
|
handleClose (e) {
|
||||||
if (this.disableCloseUnderTransfer) {
|
if (this.disableCloseUnderTransfer) {
|
||||||
this.disableCloseUnderTransfer = false;
|
this.disableCloseUnderTransfer = false;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (this.open !== null) return;
|
|
||||||
|
if (e && e.type === 'mousedown' && this.visible) {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.visible) {
|
||||||
|
const pickerPanel = this.$refs.pickerPanel && this.$refs.pickerPanel.$el;
|
||||||
|
if (e && pickerPanel && pickerPanel.contains(e.target)) return; // its a click inside own component, lets ignore it.
|
||||||
|
|
||||||
this.visible = false;
|
this.visible = false;
|
||||||
|
e && e.preventDefault();
|
||||||
|
e && e.stopPropagation();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.isFocused = false;
|
||||||
this.disableClickOutSide = false;
|
this.disableClickOutSide = false;
|
||||||
},
|
},
|
||||||
handleFocus () {
|
handleFocus (e) {
|
||||||
if (this.readonly) return;
|
if (this.readonly) return;
|
||||||
|
this.isFocused = true;
|
||||||
|
if (e && e.type === 'focus') return; // just focus, don't open yet
|
||||||
this.visible = true;
|
this.visible = true;
|
||||||
this.$refs.pickerPanel.onToggleVisibility(true);
|
|
||||||
},
|
},
|
||||||
handleBlur () {
|
handleBlur (e) {
|
||||||
this.visible = false;
|
if (this.internalFocus){
|
||||||
|
this.internalFocus = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (this.visible) {
|
||||||
|
e.preventDefault();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.isFocused = false;
|
||||||
this.onSelectionModeChange(this.type);
|
this.onSelectionModeChange(this.type);
|
||||||
this.internalValue = this.internalValue.slice(); // trigger panel watchers to reset views
|
this.internalValue = this.internalValue.slice(); // trigger panel watchers to reset views
|
||||||
this.reset();
|
this.reset();
|
||||||
this.$refs.pickerPanel.onToggleVisibility(false);
|
this.$refs.pickerPanel.onToggleVisibility(false);
|
||||||
|
|
||||||
},
|
},
|
||||||
|
handleKeydown(e){
|
||||||
|
const keyCode = e.keyCode;
|
||||||
|
|
||||||
|
// handle "tab" key
|
||||||
|
if (keyCode === 9){
|
||||||
|
if (this.visible){
|
||||||
|
e.stopPropagation();
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
if (this.isConfirm){
|
||||||
|
const selector = `.${pickerPrefixCls}-confirm > *`;
|
||||||
|
const tabbable = this.$refs.drop.$el.querySelectorAll(selector);
|
||||||
|
this.internalFocus = true;
|
||||||
|
const element = [...tabbable][e.shiftKey ? 'pop' : 'shift']();
|
||||||
|
element.focus();
|
||||||
|
} else {
|
||||||
|
this.handleClose();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.focused = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// open the panel
|
||||||
|
const arrows = [37, 38, 39, 40];
|
||||||
|
if (!this.visible && arrows.includes(keyCode)){
|
||||||
|
this.visible = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// close on "esc" key
|
||||||
|
if (keyCode === 27){
|
||||||
|
if (this.visible) {
|
||||||
|
e.stopPropagation();
|
||||||
|
this.handleClose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// select date, "Enter" key
|
||||||
|
if (keyCode === 13){
|
||||||
|
const timePickers = findComponentsDownward(this, 'TimeSpinner');
|
||||||
|
if (timePickers.length > 0){
|
||||||
|
const columnsPerPicker = timePickers[0].showSeconds ? 3 : 2;
|
||||||
|
const pickerIndex = Math.floor(this.focusedTime.column / columnsPerPicker);
|
||||||
|
const value = this.focusedTime.time[pickerIndex];
|
||||||
|
|
||||||
|
timePickers[pickerIndex].chooseValue(value);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.type.match(/range/)){
|
||||||
|
this.$refs.pickerPanel.handleRangePick(this.focusedDate, 'date');
|
||||||
|
} else {
|
||||||
|
const panels = findComponentsDownward(this, 'PanelTable');
|
||||||
|
const compareDate = (d) => {
|
||||||
|
const sliceIndex = ['year', 'month', 'date'].indexOf((this.type)) + 1;
|
||||||
|
return [d.getFullYear(), d.getMonth(), d.getDate()].slice(0, sliceIndex).join('-');
|
||||||
|
};
|
||||||
|
const dateIsValid = panels.find(({cells}) => {
|
||||||
|
return cells.find(({date, disabled}) => compareDate(date) === compareDate(this.focusedDate) && !disabled);
|
||||||
|
});
|
||||||
|
if (dateIsValid) this.onPick(this.focusedDate, false, 'date');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!arrows.includes(keyCode)) return; // ignore rest of keys
|
||||||
|
|
||||||
|
// navigate times and dates
|
||||||
|
if (this.focusedTime.active) e.preventDefault(); // to prevent cursor from moving
|
||||||
|
this.navigateDatePanel(keyValueMapper[keyCode], e.shiftKey);
|
||||||
|
},
|
||||||
reset(){
|
reset(){
|
||||||
this.$refs.pickerPanel.reset && this.$refs.pickerPanel.reset();
|
this.$refs.pickerPanel.reset && this.$refs.pickerPanel.reset();
|
||||||
},
|
},
|
||||||
|
navigateTimePanel(direction){
|
||||||
|
|
||||||
|
this.focusedTime.active = true;
|
||||||
|
const horizontal = direction.match(/left|right/);
|
||||||
|
const vertical = direction.match(/up|down/);
|
||||||
|
const timePickers = findComponentsDownward(this, 'TimeSpinner');
|
||||||
|
|
||||||
|
const maxNrOfColumns = (timePickers[0].showSeconds ? 3 : 2) * timePickers.length;
|
||||||
|
const column = (currentColumn => {
|
||||||
|
const incremented = currentColumn + (horizontal ? (direction === 'left' ? -1 : 1) : 0);
|
||||||
|
return (incremented + maxNrOfColumns) % maxNrOfColumns;
|
||||||
|
})(this.focusedTime.column);
|
||||||
|
|
||||||
|
const columnsPerPicker = maxNrOfColumns / timePickers.length;
|
||||||
|
const pickerIndex = Math.floor(column / columnsPerPicker);
|
||||||
|
const col = column % columnsPerPicker;
|
||||||
|
|
||||||
|
|
||||||
|
if (horizontal){
|
||||||
|
const time = this.internalValue.map(extractTime);
|
||||||
|
|
||||||
|
this.focusedTime = {
|
||||||
|
...this.focusedTime,
|
||||||
|
column: column,
|
||||||
|
time: time
|
||||||
|
};
|
||||||
|
timePickers.forEach((instance, i) => {
|
||||||
|
if (i === pickerIndex) instance.updateFocusedTime(col, time[pickerIndex]);
|
||||||
|
else instance.updateFocusedTime(-1, instance.focusedTime);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vertical){
|
||||||
|
const increment = direction === 'up' ? 1 : -1;
|
||||||
|
const timeParts = ['hours', 'minutes', 'seconds'];
|
||||||
|
|
||||||
|
|
||||||
|
const pickerPossibleValues = timePickers[pickerIndex][`${timeParts[col]}List`];
|
||||||
|
const nextIndex = pickerPossibleValues.findIndex(({text}) => this.focusedTime.time[pickerIndex][col] === text) + increment;
|
||||||
|
const nextValue = pickerPossibleValues[nextIndex % pickerPossibleValues.length].text;
|
||||||
|
const times = this.focusedTime.time.map((time, i) => {
|
||||||
|
if (i !== pickerIndex) return time;
|
||||||
|
time[col] = nextValue;
|
||||||
|
return time;
|
||||||
|
});
|
||||||
|
this.focusedTime = {
|
||||||
|
...this.focusedTime,
|
||||||
|
time: times
|
||||||
|
};
|
||||||
|
|
||||||
|
timePickers.forEach((instance, i) => {
|
||||||
|
if (i === pickerIndex) instance.updateFocusedTime(col, times[i]);
|
||||||
|
else instance.updateFocusedTime(-1, instance.focusedTime);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
navigateDatePanel(direction, shift){
|
||||||
|
|
||||||
|
const timePickers = findComponentsDownward(this, 'TimeSpinner');
|
||||||
|
if (timePickers.length > 0) {
|
||||||
|
// we are in TimePicker mode
|
||||||
|
this.navigateTimePanel(direction, shift, timePickers);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shift){
|
||||||
|
if (this.type === 'year'){
|
||||||
|
this.focusedDate = new Date(
|
||||||
|
this.focusedDate.getFullYear() + mapPossibleValues(direction, 0, 10),
|
||||||
|
this.focusedDate.getMonth(),
|
||||||
|
this.focusedDate.getDate()
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
this.focusedDate = new Date(
|
||||||
|
this.focusedDate.getFullYear() + mapPossibleValues(direction, 0, 1),
|
||||||
|
this.focusedDate.getMonth() + mapPossibleValues(direction, 1, 0),
|
||||||
|
this.focusedDate.getDate()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const position = direction.match(/left|down/) ? 'prev' : 'next';
|
||||||
|
const double = direction.match(/up|down/) ? '-double' : '';
|
||||||
|
|
||||||
|
// pulse button
|
||||||
|
const button = this.$refs.drop.$el.querySelector(`.ivu-date-picker-${position}-btn-arrow${double}`);
|
||||||
|
if (button) pulseElement(button);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const initialDate = this.focusedDate || (this.internalValue && this.internalValue[0]) || new Date();
|
||||||
|
const focusedDate = new Date(initialDate);
|
||||||
|
|
||||||
|
if (this.type.match(/^date/)){
|
||||||
|
const lastOfMonth = getDayCountOfMonth(initialDate.getFullYear(), initialDate.getMonth());
|
||||||
|
const startDay = initialDate.getDate();
|
||||||
|
const nextDay = focusedDate.getDate() + mapPossibleValues(direction, 1, 7);
|
||||||
|
|
||||||
|
if (nextDay < 1) {
|
||||||
|
if (direction.match(/left|right/)) {
|
||||||
|
focusedDate.setMonth(focusedDate.getMonth() + 1);
|
||||||
|
focusedDate.setDate(nextDay);
|
||||||
|
} else {
|
||||||
|
focusedDate.setDate(startDay + Math.floor((lastOfMonth - startDay) / 7) * 7);
|
||||||
|
}
|
||||||
|
} else if (nextDay > lastOfMonth){
|
||||||
|
if (direction.match(/left|right/)) {
|
||||||
|
focusedDate.setMonth(focusedDate.getMonth() - 1);
|
||||||
|
focusedDate.setDate(nextDay);
|
||||||
|
} else {
|
||||||
|
focusedDate.setDate(startDay % 7);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
focusedDate.setDate(nextDay);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.type.match(/^month/)) {
|
||||||
|
focusedDate.setMonth(focusedDate.getMonth() + mapPossibleValues(direction, 1, 3));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.type.match(/^year/)) {
|
||||||
|
focusedDate.setFullYear(focusedDate.getFullYear() + mapPossibleValues(direction, 1, 3));
|
||||||
|
}
|
||||||
|
|
||||||
|
this.focusedDate = focusedDate;
|
||||||
|
},
|
||||||
handleInputChange (event) {
|
handleInputChange (event) {
|
||||||
const isArrayValue = this.type.includes('range') || this.multiple;
|
const isArrayValue = this.type.includes('range') || this.multiple;
|
||||||
const oldValue = this.visualValue;
|
const oldValue = this.visualValue;
|
||||||
|
@ -377,6 +651,12 @@
|
||||||
this.internalValue = Array.isArray(dates) ? dates : [dates];
|
this.internalValue = Array.isArray(dates) ? dates : [dates];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.focusedDate = this.internalValue[0];
|
||||||
|
this.focusedTime = {
|
||||||
|
...this.focusedTime,
|
||||||
|
time: this.internalValue.map(extractTime)
|
||||||
|
};
|
||||||
|
|
||||||
if (!this.isConfirm) this.onSelectionModeChange(this.type); // reset the selectionMode
|
if (!this.isConfirm) this.onSelectionModeChange(this.type); // reset the selectionMode
|
||||||
if (!this.isConfirm) this.visible = visible;
|
if (!this.isConfirm) this.visible = visible;
|
||||||
this.emitChange(type);
|
this.emitChange(type);
|
||||||
|
@ -384,22 +664,23 @@
|
||||||
onPickSuccess(){
|
onPickSuccess(){
|
||||||
this.visible = false;
|
this.visible = false;
|
||||||
this.$emit('on-ok');
|
this.$emit('on-ok');
|
||||||
|
this.focus();
|
||||||
this.reset();
|
this.reset();
|
||||||
},
|
},
|
||||||
|
focus() {
|
||||||
|
this.$refs.input.focus();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
visible (state) {
|
visible (state) {
|
||||||
if (state === false){
|
if (state === false){
|
||||||
this.$refs.drop.destroy();
|
this.$refs.drop.destroy();
|
||||||
const input = this.$el.querySelector('input');
|
|
||||||
if (input) input.blur();
|
|
||||||
}
|
}
|
||||||
this.$refs.drop.update();
|
this.$refs.drop.update();
|
||||||
this.$emit('on-open-change', state);
|
this.$emit('on-open-change', state);
|
||||||
},
|
},
|
||||||
value(val) {
|
value(val) {
|
||||||
this.internalValue = this.parseDate(val);
|
this.internalValue = this.parseDate(val);
|
||||||
|
|
||||||
},
|
},
|
||||||
open (val) {
|
open (val) {
|
||||||
this.visible = val === true;
|
this.visible = val === true;
|
||||||
|
@ -421,6 +702,9 @@
|
||||||
this.$emit('input', this.publicVModelValue); // to update v-model
|
this.$emit('input', this.publicVModelValue); // to update v-model
|
||||||
}
|
}
|
||||||
if (this.open !== null) this.visible = this.open;
|
if (this.open !== null) this.visible = this.open;
|
||||||
|
|
||||||
|
// to handle focus from confirm buttons
|
||||||
|
this.$on('focus-input', () => this.focus());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -5,6 +5,7 @@ import RangeDatePickerPanel from '../panel/Date/date-range.vue';
|
||||||
import { oneOf } from '../../../utils/assist';
|
import { oneOf } from '../../../utils/assist';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
name: 'CalendarPicker',
|
||||||
mixins: [Picker],
|
mixins: [Picker],
|
||||||
props: {
|
props: {
|
||||||
type: {
|
type: {
|
||||||
|
|
|
@ -3,7 +3,7 @@ import TimePickerPanel from '../panel/Time/time.vue';
|
||||||
import RangeTimePickerPanel from '../panel/Time/time-range.vue';
|
import RangeTimePickerPanel from '../panel/Time/time-range.vue';
|
||||||
import Options from '../time-mixins';
|
import Options from '../time-mixins';
|
||||||
|
|
||||||
import { oneOf } from '../../../utils/assist';
|
import { findComponentsDownward, oneOf } from '../../../utils/assist';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
mixins: [Picker, Options],
|
mixins: [Picker, Options],
|
||||||
|
@ -30,4 +30,14 @@ export default {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
watch: {
|
||||||
|
visible(visible){
|
||||||
|
if (visible) {
|
||||||
|
this.$nextTick(() => {
|
||||||
|
const spinners = findComponentsDownward(this, 'TimeSpinner');
|
||||||
|
spinners.forEach(instance => instance.updateScroll());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -44,17 +44,23 @@
|
||||||
margin: 2px;
|
margin: 2px;
|
||||||
color: @btn-disable-color;
|
color: @btn-disable-color;
|
||||||
}
|
}
|
||||||
|
&-cell:hover{
|
||||||
|
em{
|
||||||
|
background: @date-picker-cell-hover-bg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&-focused{
|
||||||
|
em{
|
||||||
|
box-shadow: 0 0 0 1px @primary-color inset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
&-cell{
|
&-cell{
|
||||||
span&{
|
span&{
|
||||||
width: 28px;
|
width: 28px;
|
||||||
height: 28px;
|
height: 28px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
&:hover{
|
|
||||||
em{
|
|
||||||
background: @date-picker-cell-hover-bg;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
&-prev-month,&-next-month{
|
&-prev-month,&-next-month{
|
||||||
em{
|
em{
|
||||||
color: @btn-disable-color;
|
color: @btn-disable-color;
|
||||||
|
@ -154,6 +160,11 @@
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.@{date-picker-prefix-cls}-cells-cell-focused{
|
||||||
|
background-color: tint(@primary-color, 80%);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&-header{
|
&-header{
|
||||||
|
@ -169,6 +180,11 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
&-btn-pulse{
|
||||||
|
background-color: tint(@primary-color, 80%) !important;
|
||||||
|
border-radius: @border-radius-small;
|
||||||
|
transition: background-color @transition-time @ease-in-out;
|
||||||
|
}
|
||||||
&-prev-btn{
|
&-prev-btn{
|
||||||
float: left;
|
float: left;
|
||||||
&-arrow-double{
|
&-arrow-double{
|
||||||
|
@ -216,6 +232,10 @@
|
||||||
max-height: none;
|
max-height: none;
|
||||||
width: auto;
|
width: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&-focused input{
|
||||||
|
.active();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.@{picker-prefix-cls} {
|
.@{picker-prefix-cls} {
|
||||||
|
@ -289,9 +309,9 @@
|
||||||
color: @link-active-color;
|
color: @link-active-color;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
& > span&-time-disabled{
|
|
||||||
color: @btn-disable-color;
|
&-time{
|
||||||
cursor: @cursor-disabled;
|
float: left;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,6 +70,9 @@
|
||||||
color: @primary-color;
|
color: @primary-color;
|
||||||
background: @background-color-select-hover;
|
background: @background-color-select-hover;
|
||||||
}
|
}
|
||||||
|
&-focused{
|
||||||
|
background-color: tint(@primary-color, 80%);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -116,7 +116,7 @@ describe('DatePicker.vue', () => {
|
||||||
`);
|
`);
|
||||||
|
|
||||||
const picker = vm.$children[0];
|
const picker = vm.$children[0];
|
||||||
picker.handleIconClick();
|
picker.handleFocus({type: 'focus'});
|
||||||
vm.$nextTick(() => {
|
vm.$nextTick(() => {
|
||||||
const displayField = vm.$el.querySelector('.ivu-input');
|
const displayField = vm.$el.querySelector('.ivu-input');
|
||||||
const clickableCells = vm.$el.querySelectorAll('.ivu-date-picker-cells-cell');
|
const clickableCells = vm.$el.querySelectorAll('.ivu-date-picker-cells-cell');
|
||||||
|
@ -169,7 +169,7 @@ describe('DatePicker.vue', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
const picker = vm.$children[0];
|
const picker = vm.$children[0];
|
||||||
picker.handleIconClick();
|
picker.handleFocus({type: 'focus'});
|
||||||
vm.$nextTick(() => {
|
vm.$nextTick(() => {
|
||||||
const panel = vm.$el.querySelector('.ivu-picker-panel-content');
|
const panel = vm.$el.querySelector('.ivu-picker-panel-content');
|
||||||
const dayPanel = panel.querySelector('[class="ivu-date-picker-cells"]');
|
const dayPanel = panel.querySelector('[class="ivu-date-picker-cells"]');
|
||||||
|
@ -243,7 +243,7 @@ describe('DatePicker.vue', () => {
|
||||||
`);
|
`);
|
||||||
|
|
||||||
const picker = vm.$children[0];
|
const picker = vm.$children[0];
|
||||||
picker.handleIconClick();
|
picker.handleFocus({type: 'focus'});
|
||||||
vm.$nextTick(() => {
|
vm.$nextTick(() => {
|
||||||
const displayField = vm.$el.querySelector('.ivu-input');
|
const displayField = vm.$el.querySelector('.ivu-input');
|
||||||
const clickableCells = vm.$el.querySelectorAll('.ivu-date-picker-cells-cell');
|
const clickableCells = vm.$el.querySelectorAll('.ivu-date-picker-cells-cell');
|
||||||
|
@ -266,7 +266,9 @@ describe('DatePicker.vue', () => {
|
||||||
// it should be closed by now
|
// it should be closed by now
|
||||||
expect(picker.visible).to.equal(false);
|
expect(picker.visible).to.equal(false);
|
||||||
// open picker again
|
// open picker again
|
||||||
picker.handleIconClick();
|
picker.handleFocus({type: 'focus'});
|
||||||
|
picker.visible = true;
|
||||||
|
|
||||||
|
|
||||||
vm.$nextTick(() => {
|
vm.$nextTick(() => {
|
||||||
expect(picker.visible).to.equal(true);
|
expect(picker.visible).to.equal(true);
|
||||||
|
@ -355,7 +357,7 @@ describe('DatePicker.vue', () => {
|
||||||
`);
|
`);
|
||||||
|
|
||||||
const picker = vm.$children[0];
|
const picker = vm.$children[0];
|
||||||
picker.handleIconClick();
|
picker.handleFocus({type: 'focus'});
|
||||||
vm.$nextTick(() => {
|
vm.$nextTick(() => {
|
||||||
const now = new Date();
|
const now = new Date();
|
||||||
const labels = vm.$el.querySelectorAll('.ivu-picker-panel-body .ivu-date-picker-header-label');
|
const labels = vm.$el.querySelectorAll('.ivu-picker-panel-body .ivu-date-picker-header-label');
|
||||||
|
|
|
@ -11,7 +11,7 @@ describe('TimePicker.vue', () => {
|
||||||
<Time-Picker></Time-Picker>
|
<Time-Picker></Time-Picker>
|
||||||
`);
|
`);
|
||||||
const picker = vm.$children[0];
|
const picker = vm.$children[0];
|
||||||
picker.handleIconClick(); // open the picker panels
|
picker.handleFocus({type: 'focus'}); // open the picker panels
|
||||||
|
|
||||||
vm.$nextTick(() => {
|
vm.$nextTick(() => {
|
||||||
const spiners = picker.$el.querySelectorAll('.ivu-time-picker-cells-list');
|
const spiners = picker.$el.querySelectorAll('.ivu-time-picker-cells-list');
|
||||||
|
@ -28,7 +28,7 @@ describe('TimePicker.vue', () => {
|
||||||
<Time-Picker format="HH:mm"></Time-Picker>
|
<Time-Picker format="HH:mm"></Time-Picker>
|
||||||
`);
|
`);
|
||||||
const picker = vm.$children[0];
|
const picker = vm.$children[0];
|
||||||
picker.handleIconClick(); // open the picker panels
|
picker.handleFocus({type: 'focus'}); // open the picker panels
|
||||||
|
|
||||||
vm.$nextTick(() => {
|
vm.$nextTick(() => {
|
||||||
const spiners = picker.$el.querySelectorAll('.ivu-time-picker-cells-list');
|
const spiners = picker.$el.querySelectorAll('.ivu-time-picker-cells-list');
|
||||||
|
@ -44,7 +44,7 @@ describe('TimePicker.vue', () => {
|
||||||
<Time-Picker :steps="[1, 15]"></Time-Picker>
|
<Time-Picker :steps="[1, 15]"></Time-Picker>
|
||||||
`);
|
`);
|
||||||
const picker = vm.$children[0];
|
const picker = vm.$children[0];
|
||||||
picker.handleIconClick(); // open the picker panels
|
picker.handleFocus({type: 'focus'}); // open the picker panels
|
||||||
|
|
||||||
vm.$nextTick(() => {
|
vm.$nextTick(() => {
|
||||||
const spiners = picker.$el.querySelectorAll('.ivu-time-picker-cells-list');
|
const spiners = picker.$el.querySelectorAll('.ivu-time-picker-cells-list');
|
||||||
|
|
Loading…
Add table
Reference in a new issue