ant-design-vue/components/calendar/index.jsx

263 lines
7.1 KiB
Vue
Raw Normal View History

2019-01-12 11:33:27 +08:00
import PropTypes from '../_util/vue-types';
import BaseMixin from '../_util/BaseMixin';
2020-01-18 21:34:23 +08:00
import { getOptionProps, hasProp, initDefaultProps, getListeners } from '../_util/props-util';
2019-01-12 11:33:27 +08:00
import * as moment from 'moment';
import FullCalendar from '../vc-calendar/src/FullCalendar';
import LocaleReceiver from '../locale-provider/LocaleReceiver';
import Header from './Header';
import interopDefault from '../_util/interopDefault';
2019-03-13 13:34:40 +08:00
import { ConfigConsumerProps } from '../config-provider';
2019-01-12 11:33:27 +08:00
import enUS from './locale/en_US';
import Base from '../base';
2019-01-12 11:33:27 +08:00
function noop() {
return null;
}
2018-03-19 10:16:27 +08:00
2019-01-12 11:33:27 +08:00
function zerofixed(v) {
2018-03-13 22:40:13 +08:00
if (v < 10) {
2019-01-12 11:33:27 +08:00
return `0${v}`;
2018-03-13 22:40:13 +08:00
}
2019-01-12 11:33:27 +08:00
return `${v}`;
2018-03-13 22:40:13 +08:00
}
export const MomentType = {
type: Object,
2019-01-12 11:33:27 +08:00
validator: function(value) {
return moment.isMoment(value);
2018-03-13 22:40:13 +08:00
},
2019-01-12 11:33:27 +08:00
};
function isMomentArray(value) {
return Array.isArray(value) && !!value.find(val => moment.isMoment(val));
2018-03-13 22:40:13 +08:00
}
2019-01-12 11:33:27 +08:00
export const CalendarMode = PropTypes.oneOf(['month', 'year']);
2018-03-13 22:40:13 +08:00
export const CalendarProps = () => ({
prefixCls: PropTypes.string,
value: MomentType,
defaultValue: MomentType,
mode: CalendarMode,
fullscreen: PropTypes.bool,
2018-03-14 22:00:43 +08:00
// dateCellRender: PropTypes.func,
// monthCellRender: PropTypes.func,
// dateFullCellRender: PropTypes.func,
// monthFullCellRender: PropTypes.func,
locale: PropTypes.object,
2018-03-13 22:40:13 +08:00
// onPanelChange?: (date?: moment.Moment, mode?: CalendarMode) => void;
// onSelect?: (date?: moment.Moment) => void;
disabledDate: PropTypes.func,
2018-04-06 20:56:19 +08:00
validRange: PropTypes.custom(isMomentArray),
2019-01-12 11:33:27 +08:00
});
2018-03-13 22:40:13 +08:00
const Calendar = {
2018-04-08 21:17:20 +08:00
name: 'ACalendar',
2018-03-13 22:40:13 +08:00
mixins: [BaseMixin],
props: initDefaultProps(CalendarProps(), {
locale: {},
fullscreen: true,
mode: 'month',
}),
2018-03-14 22:00:43 +08:00
model: {
prop: 'value',
event: 'change',
},
2019-03-13 13:34:40 +08:00
inject: {
2019-09-11 22:35:25 +08:00
configProvider: { default: () => ConfigConsumerProps },
2019-03-13 13:34:40 +08:00
},
2019-01-12 11:33:27 +08:00
data() {
const value = this.value || this.defaultValue || interopDefault(moment)();
2018-04-06 20:56:19 +08:00
if (!interopDefault(moment).isMoment(value)) {
2019-01-12 11:33:27 +08:00
throw new Error('The value/defaultValue of Calendar must be a moment object, ');
2018-03-13 22:40:13 +08:00
}
2019-03-13 13:34:40 +08:00
this._sPrefixCls = undefined;
2018-03-13 22:40:13 +08:00
return {
sValue: value,
sMode: this.mode,
2019-01-12 11:33:27 +08:00
};
2018-03-13 22:40:13 +08:00
},
watch: {
2019-01-12 11:33:27 +08:00
value(val) {
2018-03-13 22:40:13 +08:00
this.setState({
sValue: val,
2019-01-12 11:33:27 +08:00
});
2018-03-13 22:40:13 +08:00
},
2019-01-12 11:33:27 +08:00
mode(val) {
2018-03-13 22:40:13 +08:00
this.setState({
sMode: val,
2019-01-12 11:33:27 +08:00
});
2018-03-13 22:40:13 +08:00
},
},
methods: {
2019-01-12 11:33:27 +08:00
monthCellRender2(value) {
2019-03-13 13:34:40 +08:00
const { _sPrefixCls, $scopedSlots } = this;
2019-01-12 11:33:27 +08:00
const monthCellRender = this.monthCellRender || $scopedSlots.monthCellRender || noop;
2018-03-13 22:40:13 +08:00
return (
2019-03-13 13:34:40 +08:00
<div class={`${_sPrefixCls}-month`}>
<div class={`${_sPrefixCls}-value`}>{value.localeData().monthsShort(value)}</div>
<div class={`${_sPrefixCls}-content`}>{monthCellRender(value)}</div>
2018-03-13 22:40:13 +08:00
</div>
2019-01-12 11:33:27 +08:00
);
2018-03-13 22:40:13 +08:00
},
2019-01-12 11:33:27 +08:00
dateCellRender2(value) {
2019-03-13 13:34:40 +08:00
const { _sPrefixCls, $scopedSlots } = this;
2019-01-12 11:33:27 +08:00
const dateCellRender = this.dateCellRender || $scopedSlots.dateCellRender || noop;
2018-03-13 22:40:13 +08:00
return (
2019-03-13 13:34:40 +08:00
<div class={`${_sPrefixCls}-date`}>
<div class={`${_sPrefixCls}-value`}>{zerofixed(value.date())}</div>
<div class={`${_sPrefixCls}-content`}>{dateCellRender(value)}</div>
2018-03-13 22:40:13 +08:00
</div>
2019-01-12 11:33:27 +08:00
);
2018-03-13 22:40:13 +08:00
},
2019-01-12 11:33:27 +08:00
setValue(value, way) {
2018-03-13 22:40:13 +08:00
if (way === 'select') {
2019-01-12 11:33:27 +08:00
this.$emit('select', value);
2018-03-13 22:40:13 +08:00
} else if (way === 'changePanel') {
2019-01-12 11:33:27 +08:00
this.onPanelChange(value, this.sMode);
2018-03-13 22:40:13 +08:00
}
if (!hasProp(this, 'value')) {
2019-01-12 11:33:27 +08:00
this.setState({ sValue: value });
}
2018-03-13 22:40:13 +08:00
},
2019-01-12 11:33:27 +08:00
setType(type) {
const mode = type === 'date' ? 'month' : 'year';
2018-03-13 22:40:13 +08:00
if (this.sMode !== mode) {
2019-01-12 11:33:27 +08:00
this.setState({ sMode: mode });
this.onPanelChange(this.sValue, mode);
2018-03-13 22:40:13 +08:00
}
},
2019-01-12 11:33:27 +08:00
onHeaderValueChange(value) {
this.setValue(value, 'changePanel');
2018-03-13 22:40:13 +08:00
},
2019-01-12 11:33:27 +08:00
onHeaderTypeChange(type) {
this.setType(type);
2018-03-13 22:40:13 +08:00
},
2019-01-12 11:33:27 +08:00
onPanelChange(value, mode) {
this.$emit('panelChange', value, mode);
2018-03-14 22:00:43 +08:00
if (value !== this.sValue) {
2019-01-12 11:33:27 +08:00
this.$emit('change', value);
2018-03-14 22:00:43 +08:00
}
2018-03-13 22:40:13 +08:00
},
2019-01-12 11:33:27 +08:00
onSelect(value) {
this.setValue(value, 'select');
2018-03-13 22:40:13 +08:00
},
2019-01-12 11:33:27 +08:00
getDateRange(validRange, disabledDate) {
return current => {
2018-04-06 20:56:19 +08:00
if (!current) {
2019-01-12 11:33:27 +08:00
return false;
2018-04-06 20:56:19 +08:00
}
2019-01-12 11:33:27 +08:00
const [startDate, endDate] = validRange;
const inRange = !current.isBetween(startDate, endDate, 'days', '[]');
2018-04-06 20:56:19 +08:00
if (disabledDate) {
2019-01-12 11:33:27 +08:00
return disabledDate(current) || inRange;
2018-04-06 20:56:19 +08:00
}
2019-01-12 11:33:27 +08:00
return inRange;
};
2018-04-06 20:56:19 +08:00
},
2019-09-10 18:57:08 +08:00
getDefaultLocale() {
const result = {
...enUS,
...this.$props.locale,
};
result.lang = {
...result.lang,
...(this.$props.locale || {}).lang,
};
return result;
},
2019-01-12 11:33:27 +08:00
renderCalendar(locale, localeCode) {
const props = getOptionProps(this);
2020-01-18 21:34:23 +08:00
const { sValue: value, sMode: mode, $scopedSlots } = this;
2018-03-13 22:40:13 +08:00
if (value && localeCode) {
2019-01-12 11:33:27 +08:00
value.locale(localeCode);
2018-03-13 22:40:13 +08:00
}
2019-05-28 11:37:38 +08:00
const {
prefixCls: customizePrefixCls,
fullscreen,
dateFullCellRender,
monthFullCellRender,
} = props;
2019-09-11 22:35:25 +08:00
const getPrefixCls = this.configProvider.getPrefixCls;
2019-03-13 13:34:40 +08:00
const prefixCls = getPrefixCls('fullcalendar', customizePrefixCls);
2019-01-12 11:33:27 +08:00
const type = mode === 'year' ? 'month' : 'date';
2018-03-13 22:40:13 +08:00
2019-03-13 13:34:40 +08:00
// To support old version react.
// Have to add prefixCls on the instance.
// https://github.com/facebook/react/issues/12397
this._sPrefixCls = prefixCls;
2019-01-12 11:33:27 +08:00
let cls = '';
2018-03-13 22:40:13 +08:00
if (fullscreen) {
2019-01-12 11:33:27 +08:00
cls += ` ${prefixCls}-fullscreen`;
2018-03-13 22:40:13 +08:00
}
2019-01-12 11:33:27 +08:00
const monthCellRender =
monthFullCellRender || $scopedSlots.monthFullCellRender || this.monthCellRender2;
const dateCellRender =
dateFullCellRender || $scopedSlots.dateFullCellRender || this.dateCellRender2;
2018-04-06 20:56:19 +08:00
2019-01-12 11:33:27 +08:00
let disabledDate = props.disabledDate;
2018-04-06 20:56:19 +08:00
if (props.validRange) {
2019-01-12 11:33:27 +08:00
disabledDate = this.getDateRange(props.validRange, disabledDate);
2018-04-06 20:56:19 +08:00
}
2018-03-13 22:40:13 +08:00
const fullCalendarProps = {
props: {
...props,
2018-03-14 22:00:43 +08:00
Select: {},
2018-03-13 22:40:13 +08:00
locale: locale.lang,
type: type,
prefixCls: prefixCls,
showHeader: false,
value: value,
monthCellRender: monthCellRender,
dateCellRender: dateCellRender,
2018-04-06 20:56:19 +08:00
disabledDate,
2018-03-13 22:40:13 +08:00
},
on: {
2020-01-18 21:34:23 +08:00
...getListeners(this),
2018-03-13 22:40:13 +08:00
select: this.onSelect,
},
2019-01-12 11:33:27 +08:00
};
2018-03-13 22:40:13 +08:00
return (
<div class={cls}>
<Header
fullscreen={fullscreen}
type={type}
value={value}
locale={locale.lang}
prefixCls={prefixCls}
onTypeChange={this.onHeaderTypeChange}
onValueChange={this.onHeaderValueChange}
2018-04-06 20:56:19 +08:00
validRange={props.validRange}
2018-03-13 22:40:13 +08:00
/>
2019-01-12 11:33:27 +08:00
<FullCalendar {...fullCalendarProps} />
2018-03-13 22:40:13 +08:00
</div>
2019-01-12 11:33:27 +08:00
);
2018-03-13 22:40:13 +08:00
},
},
2019-01-12 11:33:27 +08:00
render() {
2018-03-13 22:40:13 +08:00
return (
<LocaleReceiver
2019-01-12 11:33:27 +08:00
componentName="Calendar"
defaultLocale={this.getDefaultLocale}
2019-01-12 11:33:27 +08:00
scopedSlots={{ default: this.renderCalendar }}
2018-03-13 22:40:13 +08:00
/>
2019-01-12 11:33:27 +08:00
);
2018-03-13 22:40:13 +08:00
},
2019-01-12 11:33:27 +08:00
};
2018-03-19 10:16:27 +08:00
/* istanbul ignore next */
2019-01-12 11:33:27 +08:00
Calendar.install = function(Vue) {
Vue.use(Base);
2019-01-12 11:33:27 +08:00
Vue.component(Calendar.name, Calendar);
};
export { HeaderProps } from './Header';
2019-01-12 11:33:27 +08:00
export default Calendar;