854 lines
27 KiB
Vue
854 lines
27 KiB
Vue
import PropTypes from '../../_util/vue-types';
|
|
import BaseMixin from '../../_util/BaseMixin';
|
|
import {
|
|
getOptionProps,
|
|
hasProp,
|
|
mergeProps,
|
|
getComponentFromProp,
|
|
getListeners,
|
|
} from '../../_util/props-util';
|
|
import moment from 'moment';
|
|
import KeyCode from '../../_util/KeyCode';
|
|
import CalendarPart from './range-calendar/CalendarPart';
|
|
import TodayButton from './calendar/TodayButton';
|
|
import OkButton from './calendar/OkButton';
|
|
import TimePickerButton from './calendar/TimePickerButton';
|
|
import CommonMixin from './mixin/CommonMixin';
|
|
import enUs from './locale/en_US';
|
|
import { syncTime, getTodayTime, isAllowedDate } from './util/';
|
|
import { goTime, goStartMonth, goEndMonth, includesTime } from './util/toTime';
|
|
|
|
function noop() {}
|
|
|
|
function isEmptyArray(arr) {
|
|
return Array.isArray(arr) && (arr.length === 0 || arr.every(i => !i));
|
|
}
|
|
|
|
function isArraysEqual(a, b) {
|
|
if (a === b) return true;
|
|
if (a === null || typeof a === 'undefined' || b === null || typeof b === 'undefined') {
|
|
return false;
|
|
}
|
|
if (a.length !== b.length) return false;
|
|
|
|
for (let i = 0; i < a.length; ++i) {
|
|
if (a[i] !== b[i]) return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
function getValueFromSelectedValue(selectedValue) {
|
|
let [start, end] = selectedValue;
|
|
if (end && (start === undefined || start === null)) {
|
|
start = end.clone().subtract(1, 'month');
|
|
}
|
|
|
|
if (start && (end === undefined || end === null)) {
|
|
end = start.clone().add(1, 'month');
|
|
}
|
|
return [start, end];
|
|
}
|
|
|
|
function normalizeAnchor(props, init) {
|
|
const selectedValue = props.selectedValue || (init && props.defaultSelectedValue);
|
|
const value = props.value || (init && props.defaultValue);
|
|
const normalizedValue = value
|
|
? getValueFromSelectedValue(value)
|
|
: getValueFromSelectedValue(selectedValue);
|
|
return !isEmptyArray(normalizedValue)
|
|
? normalizedValue
|
|
: init && [moment(), moment().add(1, 'months')];
|
|
}
|
|
|
|
function generateOptions(length, extraOptionGen) {
|
|
const arr = extraOptionGen ? extraOptionGen().concat() : [];
|
|
for (let value = 0; value < length; value++) {
|
|
if (arr.indexOf(value) === -1) {
|
|
arr.push(value);
|
|
}
|
|
}
|
|
return arr;
|
|
}
|
|
|
|
function onInputSelect(direction, value, cause) {
|
|
if (!value) {
|
|
return;
|
|
}
|
|
const originalValue = this.sSelectedValue;
|
|
const selectedValue = originalValue.concat();
|
|
const index = direction === 'left' ? 0 : 1;
|
|
selectedValue[index] = value;
|
|
if (selectedValue[0] && this.compare(selectedValue[0], selectedValue[1]) > 0) {
|
|
selectedValue[1 - index] = this.sShowTimePicker ? selectedValue[index] : undefined;
|
|
}
|
|
this.__emit('inputSelect', selectedValue);
|
|
this.fireSelectValueChange(selectedValue, null, cause || { source: 'dateInput' });
|
|
}
|
|
|
|
const RangeCalendar = {
|
|
props: {
|
|
locale: PropTypes.object.def(enUs),
|
|
visible: PropTypes.bool.def(true),
|
|
prefixCls: PropTypes.string.def('rc-calendar'),
|
|
dateInputPlaceholder: PropTypes.any,
|
|
seperator: PropTypes.string.def('~'),
|
|
defaultValue: PropTypes.any,
|
|
value: PropTypes.any,
|
|
hoverValue: PropTypes.any,
|
|
mode: PropTypes.arrayOf(PropTypes.oneOf(['time', 'date', 'month', 'year', 'decade'])),
|
|
showDateInput: PropTypes.bool.def(true),
|
|
timePicker: PropTypes.any,
|
|
showOk: PropTypes.bool,
|
|
showToday: PropTypes.bool.def(true),
|
|
defaultSelectedValue: PropTypes.array.def([]),
|
|
selectedValue: PropTypes.array,
|
|
showClear: PropTypes.bool,
|
|
showWeekNumber: PropTypes.bool,
|
|
// locale: PropTypes.object,
|
|
// onChange: PropTypes.func,
|
|
// onSelect: PropTypes.func,
|
|
// onValueChange: PropTypes.func,
|
|
// onHoverChange: PropTypes.func,
|
|
// onPanelChange: PropTypes.func,
|
|
format: PropTypes.oneOfType([PropTypes.string, PropTypes.arrayOf(PropTypes.string)]),
|
|
// onClear: PropTypes.func,
|
|
type: PropTypes.any.def('both'),
|
|
disabledDate: PropTypes.func,
|
|
disabledTime: PropTypes.func.def(noop),
|
|
renderFooter: PropTypes.func.def(() => null),
|
|
renderSidebar: PropTypes.func.def(() => null),
|
|
dateRender: PropTypes.func,
|
|
clearIcon: PropTypes.any,
|
|
inputReadOnly: PropTypes.bool,
|
|
},
|
|
|
|
mixins: [BaseMixin, CommonMixin],
|
|
|
|
data() {
|
|
const props = this.$props;
|
|
const selectedValue = props.selectedValue || props.defaultSelectedValue;
|
|
const value = normalizeAnchor(props, 1);
|
|
return {
|
|
sSelectedValue: selectedValue,
|
|
prevSelectedValue: selectedValue,
|
|
firstSelectedValue: null,
|
|
sHoverValue: props.hoverValue || [],
|
|
sValue: value,
|
|
sShowTimePicker: false,
|
|
sMode: props.mode || ['date', 'date'],
|
|
sPanelTriggerSource: '', // Trigger by which picker panel: 'start' & 'end'
|
|
};
|
|
},
|
|
watch: {
|
|
value() {
|
|
const newState = {};
|
|
newState.sValue = normalizeAnchor(this.$props, 0);
|
|
this.setState(newState);
|
|
},
|
|
hoverValue(val) {
|
|
if (!isArraysEqual(this.sHoverValue, val)) {
|
|
this.setState({ sHoverValue: val });
|
|
}
|
|
},
|
|
selectedValue(val) {
|
|
const newState = {};
|
|
newState.sSelectedValue = val;
|
|
newState.prevSelectedValue = val;
|
|
this.setState(newState);
|
|
},
|
|
mode(val) {
|
|
if (!isArraysEqual(this.sMode, val)) {
|
|
this.setState({ sMode: val });
|
|
}
|
|
},
|
|
},
|
|
|
|
methods: {
|
|
onDatePanelEnter() {
|
|
if (this.hasSelectedValue()) {
|
|
this.fireHoverValueChange(this.sSelectedValue.concat());
|
|
}
|
|
},
|
|
|
|
onDatePanelLeave() {
|
|
if (this.hasSelectedValue()) {
|
|
this.fireHoverValueChange([]);
|
|
}
|
|
},
|
|
|
|
onSelect(value) {
|
|
const { type, sSelectedValue, prevSelectedValue, firstSelectedValue } = this;
|
|
let nextSelectedValue;
|
|
if (type === 'both') {
|
|
if (!firstSelectedValue) {
|
|
syncTime(prevSelectedValue[0], value);
|
|
nextSelectedValue = [value];
|
|
} else if (this.compare(firstSelectedValue, value) < 0) {
|
|
syncTime(prevSelectedValue[1], value);
|
|
nextSelectedValue = [firstSelectedValue, value];
|
|
} else {
|
|
syncTime(prevSelectedValue[0], value);
|
|
syncTime(prevSelectedValue[1], firstSelectedValue);
|
|
nextSelectedValue = [value, firstSelectedValue];
|
|
}
|
|
} else if (type === 'start') {
|
|
syncTime(prevSelectedValue[0], value);
|
|
const endValue = sSelectedValue[1];
|
|
nextSelectedValue =
|
|
endValue && this.compare(endValue, value) > 0 ? [value, endValue] : [value];
|
|
} else {
|
|
// type === 'end'
|
|
const startValue = sSelectedValue[0];
|
|
if (startValue && this.compare(startValue, value) <= 0) {
|
|
syncTime(prevSelectedValue[1], value);
|
|
nextSelectedValue = [startValue, value];
|
|
} else {
|
|
syncTime(prevSelectedValue[0], value);
|
|
nextSelectedValue = [value];
|
|
}
|
|
}
|
|
|
|
this.fireSelectValueChange(nextSelectedValue);
|
|
},
|
|
|
|
onKeyDown(event) {
|
|
if (event.target.nodeName.toLowerCase() === 'input') {
|
|
return;
|
|
}
|
|
|
|
const { keyCode } = event;
|
|
const ctrlKey = event.ctrlKey || event.metaKey;
|
|
|
|
const {
|
|
sSelectedValue: selectedValue,
|
|
sHoverValue: hoverValue,
|
|
firstSelectedValue,
|
|
sValue: value, // Value is used for `CalendarPart` current page
|
|
} = this.$data;
|
|
const { disabledDate } = this.$props;
|
|
|
|
// Update last time of the picker
|
|
const updateHoverPoint = func => {
|
|
// Change hover to make focus in UI
|
|
let currentHoverTime;
|
|
let nextHoverTime;
|
|
let nextHoverValue;
|
|
|
|
if (!firstSelectedValue) {
|
|
currentHoverTime = hoverValue[0] || selectedValue[0] || value[0] || moment();
|
|
nextHoverTime = func(currentHoverTime);
|
|
nextHoverValue = [nextHoverTime];
|
|
this.fireHoverValueChange(nextHoverValue);
|
|
} else {
|
|
if (hoverValue.length === 1) {
|
|
currentHoverTime = hoverValue[0].clone();
|
|
nextHoverTime = func(currentHoverTime);
|
|
nextHoverValue = this.onDayHover(nextHoverTime);
|
|
} else {
|
|
currentHoverTime = hoverValue[0].isSame(firstSelectedValue, 'day')
|
|
? hoverValue[1]
|
|
: hoverValue[0];
|
|
nextHoverTime = func(currentHoverTime);
|
|
nextHoverValue = this.onDayHover(nextHoverTime);
|
|
}
|
|
}
|
|
|
|
// Find origin hover time on value index
|
|
if (nextHoverValue.length >= 2) {
|
|
const miss = nextHoverValue.some(ht => !includesTime(value, ht, 'month'));
|
|
if (miss) {
|
|
const newValue = nextHoverValue.slice().sort((t1, t2) => t1.valueOf() - t2.valueOf());
|
|
if (newValue[0].isSame(newValue[1], 'month')) {
|
|
newValue[1] = newValue[0].clone().add(1, 'month');
|
|
}
|
|
this.fireValueChange(newValue);
|
|
}
|
|
} else if (nextHoverValue.length === 1) {
|
|
// If only one value, let's keep the origin panel
|
|
let oriValueIndex = value.findIndex(time => time.isSame(currentHoverTime, 'month'));
|
|
if (oriValueIndex === -1) oriValueIndex = 0;
|
|
|
|
if (value.every(time => !time.isSame(nextHoverTime, 'month'))) {
|
|
const newValue = value.slice();
|
|
newValue[oriValueIndex] = nextHoverTime.clone();
|
|
this.fireValueChange(newValue);
|
|
}
|
|
}
|
|
|
|
event.preventDefault();
|
|
|
|
return nextHoverTime;
|
|
};
|
|
|
|
switch (keyCode) {
|
|
case KeyCode.DOWN:
|
|
updateHoverPoint(time => goTime(time, 1, 'weeks'));
|
|
return;
|
|
case KeyCode.UP:
|
|
updateHoverPoint(time => goTime(time, -1, 'weeks'));
|
|
return;
|
|
case KeyCode.LEFT:
|
|
if (ctrlKey) {
|
|
updateHoverPoint(time => goTime(time, -1, 'years'));
|
|
} else {
|
|
updateHoverPoint(time => goTime(time, -1, 'days'));
|
|
}
|
|
return;
|
|
case KeyCode.RIGHT:
|
|
if (ctrlKey) {
|
|
updateHoverPoint(time => goTime(time, 1, 'years'));
|
|
} else {
|
|
updateHoverPoint(time => goTime(time, 1, 'days'));
|
|
}
|
|
return;
|
|
case KeyCode.HOME:
|
|
updateHoverPoint(time => goStartMonth(time));
|
|
return;
|
|
case KeyCode.END:
|
|
updateHoverPoint(time => goEndMonth(time));
|
|
return;
|
|
case KeyCode.PAGE_DOWN:
|
|
updateHoverPoint(time => goTime(time, 1, 'month'));
|
|
return;
|
|
case KeyCode.PAGE_UP:
|
|
updateHoverPoint(time => goTime(time, -1, 'month'));
|
|
return;
|
|
case KeyCode.ENTER: {
|
|
let lastValue;
|
|
if (hoverValue.length === 0) {
|
|
lastValue = updateHoverPoint(time => time);
|
|
} else if (hoverValue.length === 1) {
|
|
lastValue = hoverValue[0];
|
|
} else {
|
|
lastValue = hoverValue[0].isSame(firstSelectedValue, 'day')
|
|
? hoverValue[1]
|
|
: hoverValue[0];
|
|
}
|
|
if (lastValue && (!disabledDate || !disabledDate(lastValue))) {
|
|
this.onSelect(lastValue);
|
|
}
|
|
event.preventDefault();
|
|
return;
|
|
}
|
|
default:
|
|
this.__emit('keydown', event);
|
|
}
|
|
},
|
|
|
|
onDayHover(value) {
|
|
let hoverValue = [];
|
|
const { sSelectedValue, firstSelectedValue, type } = this;
|
|
if (type === 'start' && sSelectedValue[1]) {
|
|
hoverValue =
|
|
this.compare(value, sSelectedValue[1]) < 0 ? [value, sSelectedValue[1]] : [value];
|
|
} else if (type === 'end' && sSelectedValue[0]) {
|
|
hoverValue = this.compare(value, sSelectedValue[0]) > 0 ? [sSelectedValue[0], value] : [];
|
|
} else {
|
|
if (!firstSelectedValue) {
|
|
if (this.sHoverValue.length) {
|
|
this.setState({ sHoverValue: [] });
|
|
}
|
|
return hoverValue;
|
|
}
|
|
hoverValue =
|
|
this.compare(value, firstSelectedValue) < 0
|
|
? [value, firstSelectedValue]
|
|
: [firstSelectedValue, value];
|
|
}
|
|
this.fireHoverValueChange(hoverValue);
|
|
return hoverValue;
|
|
},
|
|
|
|
onToday() {
|
|
const startValue = getTodayTime(this.sValue[0]);
|
|
const endValue = startValue.clone().add(1, 'months');
|
|
this.setState({ sValue: [startValue, endValue] });
|
|
},
|
|
|
|
onOpenTimePicker() {
|
|
this.setState({
|
|
sShowTimePicker: true,
|
|
});
|
|
},
|
|
onCloseTimePicker() {
|
|
this.setState({
|
|
sShowTimePicker: false,
|
|
});
|
|
},
|
|
|
|
onOk() {
|
|
const { sSelectedValue } = this;
|
|
if (this.isAllowedDateAndTime(sSelectedValue)) {
|
|
this.__emit('ok', sSelectedValue);
|
|
}
|
|
},
|
|
|
|
onStartInputChange(...oargs) {
|
|
const args = ['left'].concat(oargs);
|
|
return onInputSelect.apply(this, args);
|
|
},
|
|
|
|
onEndInputChange(...oargs) {
|
|
const args = ['right'].concat(oargs);
|
|
return onInputSelect.apply(this, args);
|
|
},
|
|
|
|
onStartInputSelect(value) {
|
|
const args = ['left', value, { source: 'dateInputSelect' }];
|
|
return onInputSelect.apply(this, args);
|
|
},
|
|
|
|
onEndInputSelect(value) {
|
|
const args = ['right', value, { source: 'dateInputSelect' }];
|
|
return onInputSelect.apply(this, args);
|
|
},
|
|
|
|
onStartValueChange(leftValue) {
|
|
const value = [...this.sValue];
|
|
value[0] = leftValue;
|
|
return this.fireValueChange(value);
|
|
},
|
|
|
|
onEndValueChange(rightValue) {
|
|
const value = [...this.sValue];
|
|
value[1] = rightValue;
|
|
return this.fireValueChange(value);
|
|
},
|
|
|
|
onStartPanelChange(value, mode) {
|
|
const { sMode, sValue } = this;
|
|
const newMode = [mode, sMode[1]];
|
|
const newValue = [value || sValue[0], sValue[1]];
|
|
this.__emit('panelChange', newValue, newMode);
|
|
const newState = {
|
|
sPanelTriggerSource: 'start',
|
|
};
|
|
if (!hasProp(this, 'mode')) {
|
|
newState.sMode = newMode;
|
|
}
|
|
this.setState(newState);
|
|
},
|
|
|
|
onEndPanelChange(value, mode) {
|
|
const { sMode, sValue } = this;
|
|
const newMode = [sMode[0], mode];
|
|
const newValue = [sValue[0], value || sValue[1]];
|
|
this.__emit('panelChange', newValue, newMode);
|
|
const newState = {
|
|
sPanelTriggerSource: 'end',
|
|
};
|
|
if (!hasProp(this, 'mode')) {
|
|
newState.sMode = newMode;
|
|
}
|
|
this.setState(newState);
|
|
},
|
|
|
|
getStartValue() {
|
|
const {
|
|
sSelectedValue: selectedValue,
|
|
sShowTimePicker: showTimePicker,
|
|
sValue: value,
|
|
sMode: mode,
|
|
sPanelTriggerSource: panelTriggerSource,
|
|
} = this.$data;
|
|
let startValue = value[0];
|
|
// keep selectedTime when select date
|
|
if (selectedValue[0] && this.$props.timePicker) {
|
|
startValue = startValue.clone();
|
|
syncTime(selectedValue[0], startValue);
|
|
}
|
|
if (showTimePicker && selectedValue[0]) {
|
|
startValue = selectedValue[0];
|
|
}
|
|
|
|
// Adjust month if date not align
|
|
if (
|
|
panelTriggerSource === 'end' &&
|
|
mode[0] === 'date' &&
|
|
mode[1] === 'date' &&
|
|
startValue.isSame(value[1], 'month')
|
|
) {
|
|
startValue = startValue.clone().subtract(1, 'month');
|
|
}
|
|
|
|
return startValue;
|
|
},
|
|
|
|
getEndValue() {
|
|
const {
|
|
sSelectedValue: selectedValue,
|
|
sShowTimePicker: showTimePicker,
|
|
sValue: value,
|
|
sMode: mode,
|
|
sPanelTriggerSource: panelTriggerSource,
|
|
} = this.$data;
|
|
let endValue = value[1] ? value[1].clone() : value[0].clone().add(1, 'month');
|
|
// keep selectedTime when select date
|
|
if (selectedValue[1] && this.$props.timePicker) {
|
|
syncTime(selectedValue[1], endValue);
|
|
}
|
|
if (showTimePicker) {
|
|
endValue = selectedValue[1] ? selectedValue[1] : this.getStartValue();
|
|
}
|
|
|
|
// Adjust month if date not align
|
|
if (
|
|
!showTimePicker &&
|
|
panelTriggerSource !== 'end' &&
|
|
mode[0] === 'date' &&
|
|
mode[1] === 'date' &&
|
|
endValue.isSame(value[0], 'month')
|
|
) {
|
|
endValue = endValue.clone().add(1, 'month');
|
|
}
|
|
|
|
return endValue;
|
|
},
|
|
// get disabled hours for second picker
|
|
getEndDisableTime() {
|
|
const { sSelectedValue, sValue, disabledTime } = this;
|
|
const userSettingDisabledTime = disabledTime(sSelectedValue, 'end') || {};
|
|
const startValue = (sSelectedValue && sSelectedValue[0]) || sValue[0].clone();
|
|
// if startTime and endTime is same day..
|
|
// the second time picker will not able to pick time before first time picker
|
|
if (!sSelectedValue[1] || startValue.isSame(sSelectedValue[1], 'day')) {
|
|
const hours = startValue.hour();
|
|
const minutes = startValue.minute();
|
|
const second = startValue.second();
|
|
let { disabledHours, disabledMinutes, disabledSeconds } = userSettingDisabledTime;
|
|
const oldDisabledMinutes = disabledMinutes ? disabledMinutes() : [];
|
|
const olddisabledSeconds = disabledSeconds ? disabledSeconds() : [];
|
|
disabledHours = generateOptions(hours, disabledHours);
|
|
disabledMinutes = generateOptions(minutes, disabledMinutes);
|
|
disabledSeconds = generateOptions(second, disabledSeconds);
|
|
return {
|
|
disabledHours() {
|
|
return disabledHours;
|
|
},
|
|
disabledMinutes(hour) {
|
|
if (hour === hours) {
|
|
return disabledMinutes;
|
|
}
|
|
return oldDisabledMinutes;
|
|
},
|
|
disabledSeconds(hour, minute) {
|
|
if (hour === hours && minute === minutes) {
|
|
return disabledSeconds;
|
|
}
|
|
return olddisabledSeconds;
|
|
},
|
|
};
|
|
}
|
|
return userSettingDisabledTime;
|
|
},
|
|
|
|
isAllowedDateAndTime(selectedValue) {
|
|
return (
|
|
isAllowedDate(selectedValue[0], this.disabledDate, this.disabledStartTime) &&
|
|
isAllowedDate(selectedValue[1], this.disabledDate, this.disabledEndTime)
|
|
);
|
|
},
|
|
|
|
isMonthYearPanelShow(mode) {
|
|
return ['month', 'year', 'decade'].indexOf(mode) > -1;
|
|
},
|
|
|
|
hasSelectedValue() {
|
|
const { sSelectedValue } = this;
|
|
return !!sSelectedValue[1] && !!sSelectedValue[0];
|
|
},
|
|
|
|
compare(v1, v2) {
|
|
if (this.timePicker) {
|
|
return v1.diff(v2);
|
|
}
|
|
return v1.diff(v2, 'days');
|
|
},
|
|
|
|
fireSelectValueChange(selectedValue, direct, cause) {
|
|
const { timePicker, prevSelectedValue } = this;
|
|
if (timePicker) {
|
|
const timePickerProps = getOptionProps(timePicker);
|
|
if (timePickerProps.defaultValue) {
|
|
const timePickerDefaultValue = timePickerProps.defaultValue;
|
|
if (!prevSelectedValue[0] && selectedValue[0]) {
|
|
syncTime(timePickerDefaultValue[0], selectedValue[0]);
|
|
}
|
|
if (!prevSelectedValue[1] && selectedValue[1]) {
|
|
syncTime(timePickerDefaultValue[1], selectedValue[1]);
|
|
}
|
|
}
|
|
}
|
|
// 尚未选择过时间,直接输入的话
|
|
if (!this.sSelectedValue[0] || !this.sSelectedValue[1]) {
|
|
const startValue = selectedValue[0] || moment();
|
|
const endValue = selectedValue[1] || startValue.clone().add(1, 'months');
|
|
this.setState({
|
|
sSelectedValue: selectedValue,
|
|
sValue:
|
|
selectedValue && selectedValue.length === 2
|
|
? getValueFromSelectedValue([startValue, endValue])
|
|
: this.sValue,
|
|
});
|
|
}
|
|
|
|
if (selectedValue[0] && !selectedValue[1]) {
|
|
this.setState({ firstSelectedValue: selectedValue[0] });
|
|
this.fireHoverValueChange(selectedValue.concat());
|
|
}
|
|
this.__emit('change', selectedValue);
|
|
if (direct || (selectedValue[0] && selectedValue[1])) {
|
|
this.setState({
|
|
prevSelectedValue: selectedValue,
|
|
firstSelectedValue: null,
|
|
});
|
|
this.fireHoverValueChange([]);
|
|
this.__emit('select', selectedValue, cause);
|
|
}
|
|
if (!hasProp(this, 'selectedValue')) {
|
|
this.setState({
|
|
sSelectedValue: selectedValue,
|
|
});
|
|
}
|
|
},
|
|
|
|
fireValueChange(value) {
|
|
if (!hasProp(this, 'value')) {
|
|
this.setState({
|
|
sValue: value,
|
|
});
|
|
}
|
|
this.__emit('valueChange', value);
|
|
},
|
|
|
|
fireHoverValueChange(hoverValue) {
|
|
if (!hasProp(this, 'hoverValue')) {
|
|
this.setState({ sHoverValue: hoverValue });
|
|
}
|
|
this.__emit('hoverChange', hoverValue);
|
|
},
|
|
|
|
clear() {
|
|
this.fireSelectValueChange([], true);
|
|
this.__emit('clear');
|
|
},
|
|
|
|
disabledStartTime(time) {
|
|
return this.disabledTime(time, 'start');
|
|
},
|
|
|
|
disabledEndTime(time) {
|
|
return this.disabledTime(time, 'end');
|
|
},
|
|
|
|
disabledStartMonth(month) {
|
|
const { sValue } = this;
|
|
return month.isAfter(sValue[1], 'month');
|
|
},
|
|
|
|
disabledEndMonth(month) {
|
|
const { sValue } = this;
|
|
return month.isBefore(sValue[0], 'month');
|
|
},
|
|
},
|
|
|
|
render() {
|
|
const props = getOptionProps(this);
|
|
const {
|
|
prefixCls,
|
|
dateInputPlaceholder,
|
|
timePicker,
|
|
showOk,
|
|
locale,
|
|
showClear,
|
|
showToday,
|
|
type,
|
|
seperator,
|
|
} = props;
|
|
const clearIcon = getComponentFromProp(this, 'clearIcon');
|
|
const { sHoverValue, sSelectedValue, sMode: mode, sShowTimePicker, sValue } = this;
|
|
const className = {
|
|
[prefixCls]: 1,
|
|
[`${prefixCls}-hidden`]: !props.visible,
|
|
[`${prefixCls}-range`]: 1,
|
|
[`${prefixCls}-show-time-picker`]: sShowTimePicker,
|
|
[`${prefixCls}-week-number`]: props.showWeekNumber,
|
|
};
|
|
const baseProps = {
|
|
props,
|
|
on: getListeners(this),
|
|
};
|
|
const newProps = {
|
|
props: {
|
|
selectedValue: sSelectedValue,
|
|
},
|
|
on: {
|
|
select: this.onSelect,
|
|
dayHover:
|
|
(type === 'start' && sSelectedValue[1]) ||
|
|
(type === 'end' && sSelectedValue[0]) ||
|
|
!!sHoverValue.length
|
|
? this.onDayHover
|
|
: noop,
|
|
},
|
|
};
|
|
|
|
let placeholder1;
|
|
let placeholder2;
|
|
|
|
if (dateInputPlaceholder) {
|
|
if (Array.isArray(dateInputPlaceholder)) {
|
|
[placeholder1, placeholder2] = dateInputPlaceholder;
|
|
} else {
|
|
placeholder1 = placeholder2 = dateInputPlaceholder;
|
|
}
|
|
}
|
|
const showOkButton = showOk === true || (showOk !== false && !!timePicker);
|
|
const cls = {
|
|
[`${prefixCls}-footer`]: true,
|
|
[`${prefixCls}-range-bottom`]: true,
|
|
[`${prefixCls}-footer-show-ok`]: showOkButton,
|
|
};
|
|
|
|
const startValue = this.getStartValue();
|
|
const endValue = this.getEndValue();
|
|
const todayTime = getTodayTime(startValue);
|
|
const thisMonth = todayTime.month();
|
|
const thisYear = todayTime.year();
|
|
const isTodayInView =
|
|
(startValue.year() === thisYear && startValue.month() === thisMonth) ||
|
|
(endValue.year() === thisYear && endValue.month() === thisMonth);
|
|
const nextMonthOfStart = startValue.clone().add(1, 'months');
|
|
const isClosestMonths =
|
|
nextMonthOfStart.year() === endValue.year() && nextMonthOfStart.month() === endValue.month();
|
|
const leftPartProps = mergeProps(baseProps, newProps, {
|
|
props: {
|
|
hoverValue: sHoverValue,
|
|
direction: 'left',
|
|
disabledTime: this.disabledStartTime,
|
|
disabledMonth: this.disabledStartMonth,
|
|
format: this.getFormat(),
|
|
value: startValue,
|
|
mode: mode[0],
|
|
placeholder: placeholder1,
|
|
showDateInput: this.showDateInput,
|
|
timePicker,
|
|
showTimePicker: sShowTimePicker || mode[0] === 'time',
|
|
enablePrev: true,
|
|
enableNext: !isClosestMonths || this.isMonthYearPanelShow(mode[1]),
|
|
clearIcon,
|
|
},
|
|
on: {
|
|
inputChange: this.onStartInputChange,
|
|
inputSelect: this.onStartInputSelect,
|
|
valueChange: this.onStartValueChange,
|
|
panelChange: this.onStartPanelChange,
|
|
},
|
|
});
|
|
const rightPartProps = mergeProps(baseProps, newProps, {
|
|
props: {
|
|
hoverValue: sHoverValue,
|
|
direction: 'right',
|
|
format: this.getFormat(),
|
|
timePickerDisabledTime: this.getEndDisableTime(),
|
|
placeholder: placeholder2,
|
|
value: endValue,
|
|
mode: mode[1],
|
|
showDateInput: this.showDateInput,
|
|
timePicker,
|
|
showTimePicker: sShowTimePicker || mode[1] === 'time',
|
|
disabledTime: this.disabledEndTime,
|
|
disabledMonth: this.disabledEndMonth,
|
|
enablePrev: !isClosestMonths || this.isMonthYearPanelShow(mode[0]),
|
|
enableNext: true,
|
|
clearIcon,
|
|
},
|
|
on: {
|
|
inputChange: this.onEndInputChange,
|
|
inputSelect: this.onEndInputSelect,
|
|
valueChange: this.onEndValueChange,
|
|
panelChange: this.onEndPanelChange,
|
|
},
|
|
});
|
|
let TodayButtonNode = null;
|
|
if (showToday) {
|
|
const todayButtonProps = mergeProps(baseProps, {
|
|
props: {
|
|
disabled: isTodayInView,
|
|
value: sValue[0],
|
|
text: locale.backToToday,
|
|
},
|
|
on: {
|
|
today: this.onToday,
|
|
},
|
|
});
|
|
TodayButtonNode = <TodayButton key="todayButton" {...todayButtonProps} />;
|
|
}
|
|
|
|
let TimePickerButtonNode = null;
|
|
if (props.timePicker) {
|
|
const timePickerButtonProps = mergeProps(baseProps, {
|
|
props: {
|
|
showTimePicker: sShowTimePicker || (mode[0] === 'time' && mode[1] === 'time'),
|
|
timePickerDisabled: !this.hasSelectedValue() || sHoverValue.length,
|
|
},
|
|
on: {
|
|
openTimePicker: this.onOpenTimePicker,
|
|
closeTimePicker: this.onCloseTimePicker,
|
|
},
|
|
});
|
|
TimePickerButtonNode = <TimePickerButton key="timePickerButton" {...timePickerButtonProps} />;
|
|
}
|
|
|
|
let OkButtonNode = null;
|
|
if (showOkButton) {
|
|
const okButtonProps = mergeProps(baseProps, {
|
|
props: {
|
|
okDisabled:
|
|
!this.isAllowedDateAndTime(sSelectedValue) ||
|
|
!this.hasSelectedValue() ||
|
|
sHoverValue.length,
|
|
},
|
|
on: {
|
|
ok: this.onOk,
|
|
},
|
|
});
|
|
OkButtonNode = <OkButton key="okButtonNode" {...okButtonProps} />;
|
|
}
|
|
const extraFooter = this.renderFooter(mode);
|
|
return (
|
|
<div ref="rootInstance" class={className} tabIndex="0" onKeydown={this.onKeyDown}>
|
|
{props.renderSidebar()}
|
|
<div class={`${prefixCls}-panel`}>
|
|
{showClear && sSelectedValue[0] && sSelectedValue[1] ? (
|
|
<a role="button" title={locale.clear} onClick={this.clear}>
|
|
{clearIcon || <span class={`${prefixCls}-clear-btn`} />}
|
|
</a>
|
|
) : null}
|
|
<div
|
|
class={`${prefixCls}-date-panel`}
|
|
onMouseleave={type !== 'both' ? this.onDatePanelLeave : noop}
|
|
onMouseenter={type !== 'both' ? this.onDatePanelEnter : noop}
|
|
>
|
|
<CalendarPart {...leftPartProps} />
|
|
<span class={`${prefixCls}-range-middle`}>{seperator}</span>
|
|
<CalendarPart {...rightPartProps} />
|
|
</div>
|
|
<div class={cls}>
|
|
{showToday || props.timePicker || showOkButton || extraFooter ? (
|
|
<div class={`${prefixCls}-footer-btn`}>
|
|
{extraFooter}
|
|
{TodayButtonNode}
|
|
{TimePickerButtonNode}
|
|
{OkButtonNode}
|
|
</div>
|
|
) : null}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
},
|
|
};
|
|
|
|
export default RangeCalendar;
|