UNPKG

14.1 kBJavaScriptView Raw
1import _toConsumableArray from 'babel-runtime/helpers/toConsumableArray';
2import _classCallCheck from 'babel-runtime/helpers/classCallCheck';
3import _createClass from 'babel-runtime/helpers/createClass';
4import _possibleConstructorReturn from 'babel-runtime/helpers/possibleConstructorReturn';
5import _inherits from 'babel-runtime/helpers/inherits';
6import * as React from 'react';
7import { Models } from './date/DataTypes';
8import { formatDate, shallowEqual } from './util';
9import defaultLocale from './locale/zh_CN';
10
11var DatePicker = function (_React$PureComponent) {
12 _inherits(DatePicker, _React$PureComponent);
13
14 function DatePicker(props) {
15 _classCallCheck(this, DatePicker);
16
17 var _this = _possibleConstructorReturn(this, (DatePicker.__proto__ || Object.getPrototypeOf(DatePicker)).call(this, props));
18
19 _this.visibleMonth = [];
20 _this.getDateWithoutTime = function (date) {
21 if (!date) return 0;
22 return +new Date(date.getFullYear(), date.getMonth(), date.getDate());
23 };
24 _this.genWeekData = function (firstDate) {
25 var minDateTime = _this.getDateWithoutTime(_this.props.minDate);
26 var maxDateTime = _this.getDateWithoutTime(_this.props.maxDate) || Number.POSITIVE_INFINITY;
27 var weeks = [];
28 var nextMonth = _this.getMonthDate(firstDate, 1).firstDate;
29 var currentDay = firstDate;
30 var currentWeek = [];
31 weeks.push(currentWeek);
32 var startWeekday = currentDay.getDay();
33 if (startWeekday > 0) {
34 for (var i = 0; i < startWeekday; i++) {
35 currentWeek.push({});
36 }
37 }
38 while (currentDay < nextMonth) {
39 if (currentWeek.length === 7) {
40 currentWeek = [];
41 weeks.push(currentWeek);
42 }
43 var dayOfMonth = currentDay.getDate();
44 var tick = +currentDay;
45 currentWeek.push({
46 tick: tick,
47 dayOfMonth: dayOfMonth,
48 selected: Models.SelectType.None,
49 isFirstOfMonth: dayOfMonth === 1,
50 isLastOfMonth: false,
51 outOfDate: tick < minDateTime || tick > maxDateTime
52 });
53 currentDay = new Date(currentDay.getTime() + 3600 * 24 * 1000);
54 }
55 currentWeek[currentWeek.length - 1].isLastOfMonth = true;
56 return weeks;
57 };
58 _this.selectDateRange = function (startDate, endDate) {
59 var clear = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
60 var _this$props = _this.props,
61 getDateExtra = _this$props.getDateExtra,
62 type = _this$props.type,
63 onSelectHasDisableDate = _this$props.onSelectHasDisableDate;
64
65 if (type === 'one') {
66 endDate = undefined;
67 }
68 var time1 = _this.getDateWithoutTime(startDate),
69 time2 = _this.getDateWithoutTime(endDate);
70 var startDateTick = !time2 || time1 < time2 ? time1 : time2;
71 var endDateTick = time2 && time1 > time2 ? time1 : time2;
72 var startMonthDate = _this.getMonthDate(new Date(startDateTick)).firstDate;
73 var endMonthDate = endDateTick ? new Date(endDateTick) : _this.getMonthDate(new Date(startDateTick)).lastDate;
74 var unuseable = [],
75 needUpdate = false;
76 _this.state.months.filter(function (m) {
77 return m.firstDate >= startMonthDate && m.firstDate <= endMonthDate;
78 }).forEach(function (m) {
79 m.weeks.forEach(function (w) {
80 return w.filter(function (d) {
81 if (!endDateTick) {
82 return d.tick && _this.inDate(startDateTick, d.tick);
83 } else {
84 return d.tick && d.tick >= startDateTick && d.tick <= endDateTick;
85 }
86 }).forEach(function (d) {
87 var oldValue = d.selected;
88 if (clear) {
89 d.selected = Models.SelectType.None;
90 } else {
91 var info = getDateExtra && getDateExtra(new Date(d.tick)) || {};
92 if (d.outOfDate || info.disable) {
93 unuseable.push(d.tick);
94 }
95 if (_this.inDate(startDateTick, d.tick)) {
96 if (type === 'one') {
97 d.selected = Models.SelectType.Single;
98 } else if (!endDateTick) {
99 d.selected = Models.SelectType.Only;
100 } else if (startDateTick !== endDateTick) {
101 d.selected = Models.SelectType.Start;
102 } else {
103 d.selected = Models.SelectType.All;
104 }
105 } else if (_this.inDate(endDateTick, d.tick)) {
106 d.selected = Models.SelectType.End;
107 } else {
108 d.selected = Models.SelectType.Middle;
109 }
110 }
111 needUpdate = needUpdate || d.selected !== oldValue;
112 });
113 });
114 if (needUpdate && m.componentRef) {
115 m.componentRef.updateWeeks();
116 m.componentRef.forceUpdate();
117 }
118 ;
119 });
120 if (unuseable.length > 0) {
121 if (onSelectHasDisableDate) {
122 onSelectHasDisableDate(unuseable.map(function (tick) {
123 return new Date(tick);
124 }));
125 } else {
126 console.warn('Unusable date. You can handle by onSelectHasDisableDate.', unuseable);
127 }
128 }
129 };
130 _this.computeVisible = function (clientHeight, scrollTop) {
131 var needUpdate = false;
132 var MAX_VIEW_PORT = clientHeight * 2;
133 var MIN_VIEW_PORT = clientHeight;
134 // 大缓冲区外过滤规则
135 var filterFunc = function filterFunc(vm) {
136 return vm.y && vm.height && vm.y + vm.height > scrollTop - MAX_VIEW_PORT && vm.y < scrollTop + clientHeight + MAX_VIEW_PORT;
137 };
138 if (_this.props.infiniteOpt && _this.visibleMonth.length > 12) {
139 _this.visibleMonth = _this.visibleMonth.filter(filterFunc).sort(function (a, b) {
140 return +a.firstDate - +b.firstDate;
141 });
142 }
143 // 当小缓冲区不满时填充
144 if (_this.visibleMonth.length > 0) {
145 var last = _this.visibleMonth[_this.visibleMonth.length - 1];
146 if (last.y !== undefined && last.height && last.y + last.height < scrollTop + clientHeight + MIN_VIEW_PORT) {
147 var lastIndex = _this.state.months.indexOf(last);
148 for (var i = 1; i <= 2; i++) {
149 var index = lastIndex + i;
150 if (index < _this.state.months.length && _this.visibleMonth.indexOf(_this.state.months[index]) < 0) {
151 _this.visibleMonth.push(_this.state.months[index]);
152 } else {
153 _this.canLoadNext() && _this.genMonthData(undefined, 1);
154 }
155 }
156 needUpdate = true;
157 }
158 var first = _this.visibleMonth[0];
159 if (first.y !== undefined && first.height && first.y > scrollTop - MIN_VIEW_PORT) {
160 var firstIndex = _this.state.months.indexOf(first);
161 for (var _i = 1; _i <= 2; _i++) {
162 var _index = firstIndex - _i;
163 if (_index >= 0 && _this.visibleMonth.indexOf(_this.state.months[_index]) < 0) {
164 _this.visibleMonth.unshift(_this.state.months[_index]);
165 needUpdate = true;
166 }
167 }
168 }
169 } else if (_this.state.months.length > 0) {
170 _this.visibleMonth = _this.state.months.filter(filterFunc);
171 needUpdate = true;
172 }
173 return needUpdate;
174 };
175 _this.createOnScroll = function () {
176 var timer = void 0;
177 var clientHeight = 0,
178 scrollTop = 0;
179 return function (data) {
180 var client = data.client,
181 top = data.top;
182
183 clientHeight = client;
184 scrollTop = top;
185 if (timer) {
186 return;
187 }
188 timer = setTimeout(function () {
189 timer = undefined;
190 if (_this.computeVisible(clientHeight, scrollTop)) {
191 _this.forceUpdate();
192 }
193 }, 64);
194 };
195 };
196 _this.onCellClick = function (day) {
197 if (!day.tick) return;
198 _this.props.onCellClick && _this.props.onCellClick(new Date(day.tick));
199 };
200 _this.state = {
201 months: []
202 };
203 return _this;
204 }
205
206 _createClass(DatePicker, [{
207 key: 'shouldComponentUpdate',
208 value: function shouldComponentUpdate(nextProps, nextState, nextContext) {
209 return !shallowEqual(this.props, nextProps, ['startDate', 'endDate']) || !shallowEqual(this.state, nextState) || !shallowEqual(this.context, nextContext);
210 }
211 }, {
212 key: 'componentWillReceiveProps',
213 value: function componentWillReceiveProps(nextProps) {
214 var oldValue = this.props;
215 var newValue = nextProps;
216 if (oldValue.startDate !== newValue.startDate || oldValue.endDate !== newValue.endDate) {
217 if (oldValue.startDate) {
218 this.selectDateRange(oldValue.startDate, oldValue.endDate, true);
219 }
220 if (newValue.startDate) {
221 this.selectDateRange(newValue.startDate, newValue.endDate);
222 }
223 }
224 }
225 }, {
226 key: 'componentWillMount',
227 value: function componentWillMount() {
228 var _props = this.props,
229 _props$initalMonths = _props.initalMonths,
230 initalMonths = _props$initalMonths === undefined ? 6 : _props$initalMonths,
231 defaultDate = _props.defaultDate;
232
233 for (var i = 0; i < initalMonths; i++) {
234 this.canLoadNext() && this.genMonthData(defaultDate, i);
235 }
236 this.visibleMonth = [].concat(_toConsumableArray(this.state.months));
237 }
238 }, {
239 key: 'getMonthDate',
240 value: function getMonthDate() {
241 var date = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : new Date();
242 var addMonth = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
243
244 var y = date.getFullYear(),
245 m = date.getMonth();
246 return {
247 firstDate: new Date(y, m + addMonth, 1),
248 lastDate: new Date(y, m + 1 + addMonth, 0)
249 };
250 }
251 }, {
252 key: 'canLoadPrev',
253 value: function canLoadPrev() {
254 var minDate = this.props.minDate;
255
256 return !minDate || this.state.months.length <= 0 || +this.getMonthDate(minDate).firstDate < +this.state.months[0].firstDate;
257 }
258 }, {
259 key: 'canLoadNext',
260 value: function canLoadNext() {
261 var maxDate = this.props.maxDate;
262
263 return !maxDate || this.state.months.length <= 0 || +this.getMonthDate(maxDate).firstDate > +this.state.months[this.state.months.length - 1].firstDate;
264 }
265 }, {
266 key: 'genMonthData',
267 value: function genMonthData(date) {
268 var addMonth = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
269
270 if (!date) {
271 date = addMonth >= 0 ? this.state.months[this.state.months.length - 1].firstDate : this.state.months[0].firstDate;
272 }
273 if (!date) {
274 date = new Date();
275 }
276 var locale = this.props.locale;
277
278 var _getMonthDate = this.getMonthDate(date, addMonth),
279 firstDate = _getMonthDate.firstDate,
280 lastDate = _getMonthDate.lastDate;
281
282 var weeks = this.genWeekData(firstDate);
283 var title = formatDate(firstDate, locale ? locale.monthTitle : 'yyyy/MM', this.props.locale);
284 var data = {
285 title: title,
286 firstDate: firstDate,
287 lastDate: lastDate,
288 weeks: weeks
289 };
290 data.component = this.genMonthComponent(data);
291 if (addMonth >= 0) {
292 this.state.months.push(data);
293 } else {
294 this.state.months.unshift(data);
295 }
296 var _props2 = this.props,
297 startDate = _props2.startDate,
298 endDate = _props2.endDate;
299
300 if (startDate) {
301 this.selectDateRange(startDate, endDate);
302 }
303 return data;
304 }
305 }, {
306 key: 'inDate',
307 value: function inDate(date, tick) {
308 return date <= tick && tick < date + 24 * 3600000;
309 }
310 }]);
311
312 return DatePicker;
313}(React.PureComponent);
314
315export default DatePicker;
316
317DatePicker.defaultProps = {
318 prefixCls: 'rmc-calendar',
319 infinite: true,
320 infiniteOpt: false,
321 defaultDate: new Date(),
322 initalMonths: 6,
323 locale: defaultLocale
324};
\No newline at end of file