UNPKG

devextreme

Version:

HTML5 JavaScript Component Suite for Responsive Web Development

497 lines (496 loc) • 23.1 kB
/** * DevExtreme (esm/ui/scheduler/appointmentSettingsGenerator.js) * Version: 21.1.4 * Build date: Mon Jun 21 2021 * * Copyright (c) 2012 - 2021 Developer Express Inc. ALL RIGHTS RESERVED * Read about DevExtreme licensing here: https://js.devexpress.com/Licensing/ */ import _extends from "@babel/runtime/helpers/esm/extends"; import dateUtils from "../../core/utils/date"; import { isEmptyObject } from "../../core/utils/type"; import { extend } from "../../core/utils/extend"; import { getRecurrenceProcessor } from "./recurrence"; import timeZoneUtils from "./utils.timeZone.js"; var toMs = dateUtils.dateToMilliseconds; export class AppointmentSettingsGenerator { constructor(scheduler) { this.scheduler = scheduler; this.settingsStrategy = this.scheduler.isVirtualScrolling() ? new AppointmentSettingsGeneratorVirtualStrategy(this.scheduler) : new AppointmentSettingsGeneratorBaseStrategy(this.scheduler) } create(rawAppointment) { return this.settingsStrategy.create(rawAppointment) } } export class AppointmentSettingsGeneratorBaseStrategy { constructor(scheduler) { this.scheduler = scheduler } get timeZoneCalculator() { return this.scheduler.timeZoneCalculator } get workspace() { return this.scheduler.getWorkSpace() } get viewDataProvider() { return this.workspace.viewDataProvider } create(rawAppointment) { var { scheduler: scheduler } = this; var appointment = scheduler.createAppointmentAdapter(rawAppointment); var itemResources = scheduler._resourcesManager.getResourcesFromItem(rawAppointment); var isAllDay = this._isAllDayAppointment(rawAppointment); var appointmentList = this._createAppointments(appointment, itemResources); appointmentList = this._getProcessedByAppointmentTimeZone(appointmentList, appointment); if (this._canProcessNotNativeTimezoneDates(appointment)) { appointmentList = this._getProcessedNotNativeTimezoneDates(appointmentList, appointment) } var gridAppointmentList = this._createGridAppointmentList(appointmentList, appointment); gridAppointmentList = this._cropAppointmentsByStartDayHour(gridAppointmentList, rawAppointment, isAllDay); gridAppointmentList = this._getProcessedLongAppointmentsIfRequired(gridAppointmentList, appointment); var appointmentInfos = this.createAppointmentInfos(gridAppointmentList, itemResources, isAllDay, appointment.isRecurrent); return appointmentInfos } _getProcessedByAppointmentTimeZone(appointmentList, appointment) { var hasAppointmentTimeZone = !isEmptyObject(appointment.startDateTimeZone) || !isEmptyObject(appointment.endDateTimeZone); if (appointmentList.length > 1 && hasAppointmentTimeZone) { var appointmentOffsets = { startDate: this.timeZoneCalculator.getOffsets(appointment.startDate, appointment.startDateTimeZone), endDate: this.timeZoneCalculator.getOffsets(appointment.endDate, appointment.endDateTimeZone) }; appointmentList.forEach(a => { var sourceOffsets_startDate = this.timeZoneCalculator.getOffsets(a.startDate, appointment.startDateTimeZone), sourceOffsets_endDate = this.timeZoneCalculator.getOffsets(a.endDate, appointment.endDateTimeZone); var startDateOffsetDiff = appointmentOffsets.startDate.appointment - sourceOffsets_startDate.appointment; var endDateOffsetDiff = appointmentOffsets.endDate.appointment - sourceOffsets_endDate.appointment; if (0 !== startDateOffsetDiff) { a.startDate = new Date(a.startDate.getTime() + startDateOffsetDiff * toMs("hour")) } if (0 !== endDateOffsetDiff) { a.endDate = new Date(a.endDate.getTime() + endDateOffsetDiff * toMs("hour")) } }) } return appointmentList } _isAllDayAppointment(rawAppointment) { return this.scheduler.appointmentTakesAllDay(rawAppointment) && this.workspace.supportAllDayRow() } _createAppointments(appointment, resources) { var appointments = this._createRecurrenceAppointments(appointment, resources); if (!appointment.isRecurrent && 0 === appointments.length) { appointments.push({ startDate: appointment.startDate, endDate: appointment.endDate }) } appointments = appointments.map(item => { var _item$endDate; var resultEndTime = null === (_item$endDate = item.endDate) || void 0 === _item$endDate ? void 0 : _item$endDate.getTime(); if (item.startDate.getTime() === resultEndTime) { item.endDate.setTime(resultEndTime + toMs("minute")) } return _extends({}, item, { exceptionDate: new Date(item.startDate) }) }); return appointments } _canProcessNotNativeTimezoneDates(appointment) { var timeZoneName = this.scheduler.option("timeZone"); var isTimeZoneSet = !isEmptyObject(timeZoneName); if (!isTimeZoneSet) { return false } if (!appointment.isRecurrent) { return false } return !timeZoneUtils.isEqualLocalTimeZone(timeZoneName, appointment.startDate) } _getProcessedNotNativeDateIfCrossDST(date, offset) { if (offset < 0) { var newDate = new Date(date); var newDateMinusOneHour = new Date(newDate); newDateMinusOneHour.setHours(newDateMinusOneHour.getHours() - 1); var newDateOffset = this.timeZoneCalculator.getOffsets(newDate).common; var newDateMinusOneHourOffset = this.timeZoneCalculator.getOffsets(newDateMinusOneHour).common; if (newDateOffset !== newDateMinusOneHourOffset) { return 0 } } return offset } _getProcessedNotNativeTimezoneDates(appointmentList, appointment) { var startDateRange = appointment.startDate; var endDateRange = appointmentList[appointmentList.length - 1].endDate; var startDateRangeOffset = this.timeZoneCalculator.getOffsets(startDateRange).common; var endDateRangeOffset = this.timeZoneCalculator.getOffsets(endDateRange).common; var isChangeOffsetInRange = startDateRangeOffset !== endDateRangeOffset; if (isChangeOffsetInRange) { return appointmentList.map(item => { var diffStartDateOffset = this.timeZoneCalculator.getOffsets(appointment.startDate).common - this.timeZoneCalculator.getOffsets(item.startDate).common; var diffEndDateOffset = this.timeZoneCalculator.getOffsets(appointment.endDate).common - this.timeZoneCalculator.getOffsets(item.endDate).common; diffStartDateOffset = this._getProcessedNotNativeDateIfCrossDST(item.startDate, diffStartDateOffset); diffEndDateOffset = this._getProcessedNotNativeDateIfCrossDST(item.endDate, diffEndDateOffset); var newStartDate = new Date(item.startDate.getTime() + diffStartDateOffset * toMs("hour")); var newEndDate = new Date(item.endDate.getTime() + diffEndDateOffset * toMs("hour")); var testNewStartDate = this.timeZoneCalculator.createDate(newStartDate, { path: "toGrid" }); var testNewEndDate = this.timeZoneCalculator.createDate(newEndDate, { path: "toGrid" }); if (appointment.duration > testNewEndDate.getTime() - testNewStartDate.getTime()) { newEndDate = new Date(newStartDate.getTime() + appointment.duration) } return _extends({}, item, { startDate: newStartDate, endDate: newEndDate, exceptionDate: new Date(newStartDate) }) }) } return appointmentList } _getProcessedLongAppointmentsIfRequired(gridAppointmentList, appointment) { var rawAppointment = appointment.source(); var allDay = this.scheduler.appointmentTakesAllDay(rawAppointment); var dateRange = this.workspace.getDateRange(); var renderingStrategy = this.scheduler.getLayoutManager().getRenderingStrategyInstance(); if (renderingStrategy.needSeparateAppointment(allDay)) { var longStartDateParts = []; var resultDates = []; gridAppointmentList.forEach(gridAppointment => { var maxDate = new Date(dateRange[1]); var endDateOfPart = renderingStrategy.normalizeEndDateByViewEnd(rawAppointment, gridAppointment.endDate); longStartDateParts = dateUtils.getDatesOfInterval(gridAppointment.startDate, endDateOfPart, { milliseconds: this.scheduler.getWorkSpace().getIntervalDuration(allDay) }); var list = longStartDateParts.filter(startDatePart => new Date(startDatePart) < maxDate).map(date => ({ startDate: date, endDate: new Date(new Date(date).setMilliseconds(appointment.duration)), source: gridAppointment.source })); resultDates = resultDates.concat(list) }); gridAppointmentList = resultDates } return gridAppointmentList } _createGridAppointmentList(appointmentList, appointment) { return appointmentList.map(source => { var offsetDifference = appointment.startDate.getTimezoneOffset() - source.startDate.getTimezoneOffset(); if (0 !== offsetDifference && this._canProcessNotNativeTimezoneDates(appointment)) { source.startDate = new Date(source.startDate.getTime() + offsetDifference * toMs("minute")); source.endDate = new Date(source.endDate.getTime() + offsetDifference * toMs("minute")); source.exceptionDate = new Date(source.startDate) } var startDate = this.timeZoneCalculator.createDate(source.startDate, { path: "toGrid" }); var endDate = this.timeZoneCalculator.createDate(source.endDate, { path: "toGrid" }); return { startDate: startDate, endDate: endDate, source: source } }) } _createExtremeRecurrenceDates(rawAppointment) { var dateRange = this.scheduler._workSpace.getDateRange(); var startViewDate = this.scheduler.appointmentTakesAllDay(rawAppointment) ? dateUtils.trimTime(dateRange[0]) : dateRange[0]; var endViewDate = dateRange[1]; var commonTimeZone = this.scheduler.option("timeZone"); if (commonTimeZone) { startViewDate = this.timeZoneCalculator.createDate(startViewDate, { path: "fromGrid" }); endViewDate = this.timeZoneCalculator.createDate(endViewDate, { path: "fromGrid" }); var daylightOffset = timeZoneUtils.getDaylightOffsetInMs(startViewDate, endViewDate); if (daylightOffset) { endViewDate = new Date(endViewDate.getTime() + daylightOffset) } } return [startViewDate, endViewDate] } _createRecurrenceOptions(appointment, groupIndex) { var [minRecurrenceDate, maxRecurrenceDate] = this._createExtremeRecurrenceDates(appointment.source(), groupIndex); return { rule: appointment.recurrenceRule, exception: appointment.recurrenceException, min: minRecurrenceDate, max: maxRecurrenceDate, firstDayOfWeek: this.scheduler.getFirstDayOfWeek(), start: appointment.startDate, end: appointment.endDate, getPostProcessedException: date => { var timeZoneName = this.scheduler.option("timeZone"); if (isEmptyObject(timeZoneName) || timeZoneUtils.isEqualLocalTimeZone(timeZoneName, date)) { return date } var appointmentOffset = this.timeZoneCalculator.getOffsets(appointment.startDate).common; var exceptionAppointmentOffset = this.timeZoneCalculator.getOffsets(date).common; var diff = appointmentOffset - exceptionAppointmentOffset; diff = this._getProcessedNotNativeDateIfCrossDST(date, diff); return new Date(date.getTime() - diff * dateUtils.dateToMilliseconds("hour")) } } } _createRecurrenceAppointments(appointment, resources) { var { duration: duration } = appointment; var option = this._createRecurrenceOptions(appointment); var generatedStartDates = getRecurrenceProcessor().generateDates(option); return generatedStartDates.map(date => { var utcDate = timeZoneUtils.createUTCDateWithLocalOffset(date); utcDate.setTime(utcDate.getTime() + duration); var endDate = timeZoneUtils.createDateFromUTCWithLocalOffset(utcDate); return { startDate: new Date(date), endDate: endDate } }) } _cropAppointmentsByStartDayHour(appointments, rawAppointment, isAllDay) { return appointments.map(appointment => { var startDate = new Date(appointment.startDate); var firstViewDate = this._getAppointmentFirstViewDate(appointment, rawAppointment); var startDayHour = this._getViewStartDayHour(firstViewDate); appointment.startDate = this._getAppointmentResultDate({ appointment: appointment, rawAppointment: rawAppointment, startDate: startDate, startDayHour: startDayHour, firstViewDate: firstViewDate }); return appointment }) } _getAppointmentFirstViewDate() { return this.scheduler.getStartViewDate() } _getViewStartDayHour() { return this.scheduler._getCurrentViewOption("startDayHour") } _getAppointmentResultDate(options) { var { appointment: appointment, rawAppointment: rawAppointment, startDayHour: startDayHour, firstViewDate: firstViewDate } = options; var { startDate: startDate } = options; var resultDate = new Date(appointment.startDate); if (this.scheduler.appointmentTakesAllDay(rawAppointment)) { resultDate = dateUtils.normalizeDate(startDate, firstViewDate) } else { if (startDate < firstViewDate) { startDate = firstViewDate } resultDate = dateUtils.normalizeDate(appointment.startDate, startDate) } return dateUtils.roundDateByStartDayHour(resultDate, startDayHour) } createAppointmentInfos(gridAppointments, resources, isAllDay, recurrent) { var _this = this; var result = []; var _loop = function(i) { var appointment = gridAppointments[i]; var coordinates = _this.getCoordinates({ appointment: appointment, resources: resources, isAllDay: isAllDay, recurrent: recurrent }); coordinates.forEach(coordinate => { extend(coordinate, { info: { appointment: gridAppointments[i], sourceAppointment: gridAppointments[i].source } }) }); result = result.concat(coordinates) }; for (var i = 0; i < gridAppointments.length; i++) { _loop(i) } return result } getCoordinates(options) { var { appointment: appointment, resources: resources, isAllDay: isAllDay } = options; return this.workspace.getCoordinatesByDateInGroup(appointment.startDate, resources, isAllDay) } } export class AppointmentSettingsGeneratorVirtualStrategy extends AppointmentSettingsGeneratorBaseStrategy { get viewDataProvider() { return this.workspace.viewDataProvider } get isVerticalGrouping() { return this.workspace._isVerticalGroupedWorkSpace() } createAppointmentInfos(gridAppointments, resources, allDay, recurrent) { var appointments = allDay ? gridAppointments : gridAppointments.filter(_ref => { var { source: source, startDate: startDate, endDate: endDate } = _ref; var { groupIndex: groupIndex } = source; return this.viewDataProvider.isGroupIntersectDateInterval(groupIndex, startDate, endDate) }); if (recurrent) { return this._createRecurrentAppointmentInfos(appointments, resources, allDay) } return super.createAppointmentInfos(appointments, resources, allDay, recurrent) } getCoordinates(options) { var { appointment: appointment, isAllDay: isAllDay, resources: resources, recurrent: recurrent } = options; var { startDate: startDate } = appointment; var { workspace: workspace } = this; var groupIndex = !recurrent ? appointment.source.groupIndex : void 0; return workspace.getCoordinatesByDateInGroup(startDate, resources, isAllDay, groupIndex) } _createRecurrentAppointmentInfos(gridAppointments, resources, allDay) { var result = []; gridAppointments.forEach(appointment => { var { source: source } = appointment; var { groupIndex: groupIndex } = source; var coordinate = this.workspace.getCoordinatesByDate(appointment.startDate, groupIndex, allDay); if (coordinate) { extend(coordinate, { info: { appointment: appointment, sourceAppointment: source } }); result.push(coordinate) } }); return result } _cropAppointmentsByStartDayHour(appointments, rawAppointment, isAllDay) { return appointments.filter(appointment => { var firstViewDate = this._getAppointmentFirstViewDate(appointment, rawAppointment); if (!firstViewDate) { return false } var startDayHour = this._getViewStartDayHour(firstViewDate); var startDate = new Date(appointment.startDate); appointment.startDate = this._getAppointmentResultDate({ appointment: appointment, rawAppointment: rawAppointment, startDate: startDate, startDayHour: startDayHour, firstViewDate: firstViewDate }); return !isAllDay ? appointment.endDate > appointment.startDate : true }) } _createRecurrenceAppointments(appointment, resources) { var { duration: duration } = appointment; var result = []; var groupIndices = this.workspace._getGroupCount() ? this._getGroupIndices(resources) : [0]; groupIndices.forEach(groupIndex => { var option = this._createRecurrenceOptions(appointment, groupIndex); var generatedStartDates = getRecurrenceProcessor().generateDates(option); var recurrentInfo = generatedStartDates.map(date => { var startDate = new Date(date); var utcDate = timeZoneUtils.createUTCDateWithLocalOffset(date); utcDate.setTime(utcDate.getTime() + duration); var endDate = timeZoneUtils.createDateFromUTCWithLocalOffset(utcDate); return { startDate: startDate, endDate: endDate, groupIndex: groupIndex } }); result.push(...recurrentInfo) }); return result } _getViewStartDayHour(firstViewDate) { return firstViewDate.getHours() } _getAppointmentFirstViewDate(appointment, rawAppointment) { var { viewDataProvider: viewDataProvider } = this.scheduler.getWorkSpace(); var { groupIndex: groupIndex } = appointment.source; var { startDate: startDate, endDate: endDate } = appointment; var isAllDay = this._isAllDayAppointment(rawAppointment); return viewDataProvider.findGroupCellStartDate(groupIndex, startDate, endDate, isAllDay) } _updateGroupIndices(appointments, itemResources) { var groupIndices = this._getGroupIndices(itemResources); var result = []; groupIndices.forEach(groupIndex => { var groupStartDate = this.viewDataProvider.getGroupStartDate(groupIndex); if (groupStartDate) { appointments.forEach(appointment => { var appointmentCopy = extend({}, appointment); appointmentCopy.groupIndex = groupIndex; result.push(appointmentCopy) }) } }); return result } _getGroupIndices(resources) { var _groupIndices; var groupIndices = this.workspace._getGroupIndexes(resources); var { viewDataProvider: viewDataProvider } = this.workspace; var viewDataGroupIndices = viewDataProvider.getGroupIndices(); if (!(null !== (_groupIndices = groupIndices) && void 0 !== _groupIndices && _groupIndices.length)) { groupIndices = [0] } return groupIndices.filter(groupIndex => -1 !== viewDataGroupIndices.indexOf(groupIndex)) } _createAppointments(appointment, resources) { var appointments = super._createAppointments(appointment, resources); return !appointment.isRecurrent ? this._updateGroupIndices(appointments, resources) : appointments } }