UNPKG

devextreme

Version:

HTML5 JavaScript Component Suite for Responsive Web Development

757 lines (580 loc) • 29 kB
"use strict"; var $ = require("../../core/renderer"), array = require("../../core/utils/array"), recurrenceUtils = require("./utils.recurrence"), dateUtils = require("../../core/utils/date"), each = require("../../core/utils/iterator").each, translator = require("../../animation/translator"), grep = require("../../core/utils/common").grep, typeUtils = require("../../core/utils/type"), extend = require("../../core/utils/extend").extend, inArray = require("../../core/utils/array").inArray, dateLocalization = require("../../localization/date"), SchedulerTimezones = require("./ui.scheduler.timezones"), Deferred = require("../../core/utils/deferred").Deferred; var toMs = dateUtils.dateToMilliseconds; var subscribes = { currentViewUpdated: function currentViewUpdated(currentView) { this.option("currentView", currentView); }, currentDateUpdated: function currentDateUpdated(date) { this.option("currentDate", date); }, setCellDataCacheAlias: function setCellDataCacheAlias(appointment, geometry) { this._workSpace.setCellDataCacheAlias(appointment, geometry); }, needCoordinates: function needCoordinates(options) { var appointmentData = options.appointmentData, startDate = options.startDate, endDate = this._getEndDate(appointmentData), recurrenceRule = this.fire("getField", "recurrenceRule", appointmentData), recurrenceException = this._getRecurrenceException(appointmentData), dateRange = this._workSpace.getDateRange(), startViewDate = this.appointmentTakesAllDay(appointmentData) ? dateUtils.trimTime(new Date(dateRange[0])) : dateRange[0], originalStartDate = options.originalStartDate || startDate; var recurrenceOptions = { rule: recurrenceRule, exception: recurrenceException, start: originalStartDate, end: endDate, min: startViewDate, max: dateRange[1] }; var dates = recurrenceUtils.getDatesByRecurrence(recurrenceOptions); if (!dates.length) { dates.push(startDate); } var itemResources = this._resourcesManager.getResourcesFromItem(appointmentData), allDay = this.appointmentTakesAllDay(appointmentData) && this._workSpace.supportAllDayRow(); options.callback(this._getCoordinates(dates, itemResources, allDay)); }, showAppointmentTooltip: function showAppointmentTooltip(options) { options.skipDateCalculation = true; options.$appointment = $(options.target); var appointmentData = options.data, singleAppointmentData = this._getSingleAppointmentData(appointmentData, options); this.showAppointmentTooltip(appointmentData, options.target, singleAppointmentData); }, hideAppointmentTooltip: function hideAppointmentTooltip() { this.hideAppointmentTooltip(); }, showAddAppointmentPopup: function showAddAppointmentPopup(appointmentData) { var processedData = {}; each(["startDate", "endDate", "allDay"], function (_, field) { if (appointmentData[field] !== undefined) { this.fire("setField", field, processedData, appointmentData[field]); delete appointmentData[field]; } }.bind(this)); this.showAppointmentPopup(extend(processedData, appointmentData), true); }, showEditAppointmentPopup: function showEditAppointmentPopup(options) { var appointmentData = options.data; options.$appointment = $(options.target); options.skipHoursProcessing = true; var singleAppointmentData = this._getSingleAppointmentData(appointmentData, options), startDate = this.fire("getField", "startDate", singleAppointmentData); this.showAppointmentPopup(appointmentData, false, singleAppointmentData, startDate); }, updateAppointmentAfterResize: function updateAppointmentAfterResize(options) { var targetAppointment = options.target, singleAppointment = this._getSingleAppointmentData(targetAppointment, options), startDate = this.fire("getField", "startDate", singleAppointment), updatedData = extend(true, {}, options.data); this._convertDatesByTimezoneBack(true, updatedData); this._checkRecurringAppointment(targetAppointment, singleAppointment, startDate, function () { this._updateAppointment(targetAppointment, updatedData, function () { this._appointments.moveAppointmentBack(); }); }.bind(this)); }, updateAppointmentAfterDrag: function updateAppointmentAfterDrag(options) { var target = options.data, updatedData = this._getUpdatedData(options), newCellIndex = this._workSpace.getDroppableCellIndex(), oldCellIndex = this._workSpace.getCellIndexByCoordinates(options.coordinates), becomeAllDay = this.fire("getField", "allDay", updatedData), wasAllDay = this.fire("getField", "allDay", target); var appointment = extend({}, target, updatedData); var movedToAllDay = this._workSpace.supportAllDayRow() && becomeAllDay, cellData = this._workSpace.getCellDataByCoordinates(options.coordinates, movedToAllDay), movedBetweenAllDayAndSimple = this._workSpace.supportAllDayRow() && (wasAllDay && !becomeAllDay || !wasAllDay && becomeAllDay); if (newCellIndex !== oldCellIndex || movedBetweenAllDayAndSimple) { this._checkRecurringAppointment(target, appointment, cellData.startDate, function () { this._convertDatesByTimezoneBack(true, updatedData, appointment); this._updateAppointment(target, appointment, function () { this._appointments.moveAppointmentBack(); }); }.bind(this)); } else { this._appointments.moveAppointmentBack(); } }, deleteAppointment: function deleteAppointment(options) { options.$appointment = $(options.target); var appointmentData = options.data, singleAppointmentData = this._getSingleAppointmentData(appointmentData, options), startDate = this.fire("getField", "startDate", singleAppointmentData); this._checkRecurringAppointment(appointmentData, singleAppointmentData, startDate, function () { this.deleteAppointment(appointmentData); }.bind(this), true); }, getResourceForPainting: function getResourceForPainting() { return this._resourcesManager.getResourceForPainting(this._getCurrentViewOption("groups")); }, getAppointmentColor: function getAppointmentColor(options) { var resourcesManager = this._resourcesManager, resourceForPainting = resourcesManager.getResourceForPainting(this._getCurrentViewOption("groups")), response = new Deferred().resolve().promise(); if (resourceForPainting) { var field = resourcesManager.getField(resourceForPainting), groupIndex = options.groupIndex, groups = this._workSpace._getCellGroups(groupIndex), resourceValues = array.wrapToArray(resourcesManager.getDataAccessors(field, "getter")(options.itemData)), groupId = resourceValues.length ? resourceValues[0] : undefined; for (var i = 0; i < groups.length; i++) { if (groups[i].name === field) { groupId = groups[i].id; break; } } response = resourcesManager.getResourceColor(field, groupId); } options.callback(response); }, getHeaderHeight: function getHeaderHeight() { return this._header._$element && parseInt(this._header._$element.outerHeight(), 10); }, getResourcesFromItem: function getResourcesFromItem(options) { options.callback(this._resourcesManager.getResourcesFromItem(options.itemData)); }, getBoundOffset: function getBoundOffset(options) { options.callback({ top: -this.getWorkSpaceAllDayHeight() }); }, appointmentTakesAllDay: function appointmentTakesAllDay(options) { options.callback(this.appointmentTakesAllDay(options.appointment)); }, appointmentTakesSeveralDays: function appointmentTakesSeveralDays(appointment) { return this._appointmentModel.appointmentTakesSeveralDays(appointment); }, // NOTE: T312051, remove after fix scrollable bug T324196 appointmentFocused: function appointmentFocused() { this._workSpace.restoreScrollTop(); }, getResizableAppointmentArea: function getResizableAppointmentArea(options) { var area, allDay = options.allDay, groups = this._getCurrentViewOption("groups"), isGrouped = groups && groups.length; if (isGrouped) { if (allDay || this.getLayoutManager().getRenderingStrategyInstance()._needHorizontalGroupBounds()) { var horizontalGroupBounds = this._workSpace.getGroupBounds(options.coordinates); area = { left: horizontalGroupBounds.left, right: horizontalGroupBounds.right, top: 0, bottom: 0 }; } if (this.getLayoutManager().getRenderingStrategyInstance()._needVerticalGroupBounds(allDay) && this._workSpace._isVerticalGroupedWorkSpace()) { var verticalGroupBounds = this._workSpace.getGroupBounds(options.coordinates); area = { left: 0, right: 0, top: verticalGroupBounds.top, bottom: verticalGroupBounds.bottom }; } } options.callback(area); }, needRecalculateResizableArea: function needRecalculateResizableArea() { return this.getWorkSpace().needRecalculateResizableArea(); }, getDraggableAppointmentArea: function getDraggableAppointmentArea(options) { options.callback(this.getWorkSpaceScrollableContainer()); }, getAppointmentGeometry: function getAppointmentGeometry(settings) { return this.getLayoutManager().getRenderingStrategyInstance().getAppointmentGeometry(settings); }, isAllDay: function isAllDay(appointmentData) { return this.getLayoutManager().getRenderingStrategyInstance().isAllDay(appointmentData); }, getDeltaTime: function getDeltaTime(e, initialSize, itemData) { return this.getLayoutManager().getRenderingStrategyInstance().getDeltaTime(e, initialSize, itemData); }, getCompactAppointmentGroupMaxWidth: function getCompactAppointmentGroupMaxWidth() { return this.getLayoutManager().getRenderingStrategyInstance().getCompactAppointmentGroupMaxWidth(this._getViewCountConfig().intervalCount); }, getStartDate: function getStartDate(appointmentData, skipNormalize) { return this._getStartDate(appointmentData, skipNormalize); }, getCellWidth: function getCellWidth() { return this._cellWidth; }, getCellHeight: function getCellHeight() { return this._cellHeight; }, getEndDate: function getEndDate(appointmentData) { return this._getEndDate(appointmentData); }, getRenderingStrategy: function getRenderingStrategy() { return this._getAppointmentsRenderingStrategy(); }, needCorrectAppointmentDates: function needCorrectAppointmentDates() { return this.getRenderingStrategyInstance().needCorrectAppointmentDates(); }, getRenderingStrategyDirection: function getRenderingStrategyDirection() { return this.getRenderingStrategyInstance().getDirection(); }, getWorkSpaceDateTableOffset: function getWorkSpaceDateTableOffset() { return this.getWorkSpaceDateTableOffset(); }, correctAppointmentCoordinates: function correctAppointmentCoordinates(options) { var isAllDay = options.allDay, containerSign = options.isFixedContainer ? -1 : 1; var scrollTop = this.getWorkSpaceScrollableScrollTop(isAllDay), allDayPanelTopOffset = !isAllDay ? this.getWorkSpaceAllDayOffset() : 0, headerHeight = this.getWorkSpaceHeaderPanelHeight(), scrollLeft = this.getWorkSpaceScrollableScrollLeft(), tableLeftOffset = this.getWorkSpaceDateTableOffset(); var topOffset = -scrollTop + allDayPanelTopOffset + headerHeight, leftOffset = -scrollLeft - tableLeftOffset; options.callback({ top: options.coordinates.top + containerSign * topOffset, left: options.coordinates.left + containerSign * leftOffset }); }, allDayPanelToggled: function allDayPanelToggled() { this._appointments.updateDraggablesBoundOffsets(); }, formatDates: function formatDates(options) { var startDate = options.startDate, endDate = options.endDate, formatType = options.formatType; var formatTypes = { "DATETIME": function DATETIME() { var dateTimeFormat = "mediumdatemediumtime", startDateString = dateLocalization.format(startDate, dateTimeFormat) + " - "; var endDateString = startDate.getDate() === endDate.getDate() ? dateLocalization.format(endDate, "shorttime") : dateLocalization.format(endDate, dateTimeFormat); return startDateString + endDateString; }, "TIME": function TIME() { return dateLocalization.format(startDate, "shorttime") + " - " + dateLocalization.format(endDate, "shorttime"); }, "DATE": function DATE() { var dateTimeFormat = "monthAndDay", startDateString = dateLocalization.format(startDate, dateTimeFormat), isDurationMoreThanDay = endDate.getTime() - startDate.getTime() > 24 * 3600000; var endDateString = isDurationMoreThanDay || endDate.getDate() !== startDate.getDate() ? " - " + dateLocalization.format(endDate, dateTimeFormat) : ""; return startDateString + endDateString; } }; options.callback(formatTypes[formatType]()); }, getFullWeekAppointmentWidth: function getFullWeekAppointmentWidth(options) { var groupIndex = options.groupIndex, groupWidth = this._workSpace.getGroupWidth(groupIndex); options.callback(groupWidth); }, getMaxAppointmentWidth: function getMaxAppointmentWidth(options) { var cellCountToLastViewDate = this._workSpace.getCellCountToLastViewDate(options.date); options.callback(cellCountToLastViewDate * this._workSpace.getCellWidth()); }, updateAppointmentStartDate: function updateAppointmentStartDate(options) { var appointment = options.appointment, firstViewDate = this._workSpace.getStartViewDate(), startDate = new Date(options.startDate), startDayHour = this._getCurrentViewOption("startDayHour"), updatedStartDate; if (this.appointmentTakesAllDay(appointment)) { updatedStartDate = dateUtils.normalizeDate(startDate, firstViewDate); } else { if (startDate < firstViewDate) { startDate = firstViewDate; } updatedStartDate = dateUtils.normalizeDate(options.startDate, new Date(startDate)); } if (updatedStartDate.getHours() < startDayHour) { updatedStartDate.setHours(startDayHour, 0, 0, 0); } options.callback(updatedStartDate); }, updateAppointmentEndDate: function updateAppointmentEndDate(options) { var endDate = new Date(options.endDate), endDayHour = this._getCurrentViewOption("endDayHour"), updatedEndDate = endDate; if (endDate.getHours() >= endDayHour) { updatedEndDate.setHours(endDayHour, 0, 0, 0); } options.callback(updatedEndDate); }, renderDropDownAppointments: function renderDropDownAppointments(options) { this._dropDownAppointments.render(options, this); }, getGroupCount: function getGroupCount(options) { var groupCount = this._workSpace._getGroupCount(); options.callback(groupCount); }, mapAppointmentFields: function mapAppointmentFields(config) { var result = { appointmentData: config.itemData, appointmentElement: config.itemElement, itemData: undefined, itemElement: undefined, itemIndex: undefined }; if (config.itemData) { result.targetedAppointmentData = this.fire("getTargetedAppointmentData", config.itemData, config.itemElement, config.itemIndex); } return result; }, updateResizableArea: function updateResizableArea() { var $allResizableElements = this.$element().find(".dx-scheduler-appointment.dx-resizable"); var horizontalResizables = grep($allResizableElements, function (el) { var $el = $(el), resizableInst = $el.dxResizable("instance"), area = resizableInst.option("area"); return inArray(resizableInst.option("handles"), ["right left", "left right"]) > -1 && typeUtils.isPlainObject(area); }); each(horizontalResizables, function (_, el) { var $el = $(el), position = translator.locate($el), appointmentData = this._appointments._getItemData($el); var area = this._appointments._calculateResizableArea({ left: position.left }, appointmentData); $el.dxResizable("instance").option("area", area); }.bind(this)); }, recurrenceEditorVisibilityChanged: function recurrenceEditorVisibilityChanged(options) { this.recurrenceEditorVisibilityChanged(options.visible); }, getField: function getField(field, obj) { if (!typeUtils.isDefined(this._dataAccessors.getter[field])) { return; } return this._dataAccessors.getter[field](obj); }, setField: function setField(field, obj, value) { if (!typeUtils.isDefined(this._dataAccessors.setter[field])) { return; } var splitExprStr = this.option(field + "Expr").split("."), rootField = splitExprStr[0]; if (obj[rootField] === undefined && splitExprStr.length > 1) { var emptyChain = function (arr) { var result = {}, tmp = result, arrLength = arr.length - 1; for (var i = 1; i < arrLength; i++) { tmp = tmp[arr[i]] = {}; } return result; }(splitExprStr); obj[rootField] = emptyChain; } this._dataAccessors.setter[field](obj, value); return obj; }, prerenderFilter: function prerenderFilter() { var dateRange = this.getWorkSpace().getDateRange(), resources = this._resourcesManager.getResourcesData(), allDay; if (!this.option("showAllDayPanel") && this._workSpace.supportAllDayRow()) { allDay = false; } return this._appointmentModel.filterLoadedAppointments({ startDayHour: this._getCurrentViewOption("startDayHour"), endDayHour: this._getCurrentViewOption("endDayHour"), min: dateRange[0], max: dateRange[1], resources: resources, allDay: allDay }, this._subscribes["convertDateByTimezone"].bind(this)); }, dayHasAppointment: function dayHasAppointment(day, appointment, trimTime) { return this.dayHasAppointment(day, appointment, trimTime); }, createResourcesTree: function createResourcesTree() { return this._resourcesManager.createResourcesTree(this._loadedResources); }, getResourceTreeLeaves: function getResourceTreeLeaves(tree, appointmentResources) { return this._resourcesManager.getResourceTreeLeaves(tree, appointmentResources); }, createReducedResourcesTree: function createReducedResourcesTree() { var tree = this._resourcesManager.createResourcesTree(this._loadedResources); return this._resourcesManager.reduceResourcesTree(tree, this.getFilteredItems()); }, groupAppointmentsByResources: function groupAppointmentsByResources(appointments) { var result = { "0": appointments }, groups = this._getCurrentViewOption("groups"); if (groups && groups.length && this._resourcesManager.getResourcesData().length) { result = this._resourcesManager.groupAppointmentsByResources(appointments, this._loadedResources); } var totalResourceCount = 0; each(this._loadedResources, function (i, resource) { if (!i) { totalResourceCount = resource.items.length; } else { totalResourceCount *= resource.items.length; } }); for (var j = 0; j < totalResourceCount; j++) { var index = j.toString(); if (result[index]) { continue; } result[index] = []; } return result; }, getAgendaRows: function getAgendaRows(options) { var renderingStrategy = this._layoutManager.getRenderingStrategyInstance(), calculateRows = renderingStrategy.calculateRows.bind(renderingStrategy), d = new Deferred(); function rowsCalculated(appointments) { var result = calculateRows(appointments, options.agendaDuration, options.currentDate); this._dataSourceLoadedCallback.remove(rowsCalculated); d.resolve(result); } this._dataSourceLoadedCallback.add(rowsCalculated); return d.promise(); }, getAgendaVerticalStepHeight: function getAgendaVerticalStepHeight() { return this.getWorkSpace().getAgendaVerticalStepHeight(); }, getAgendaDuration: function getAgendaDuration() { return this._getCurrentViewOption("agendaDuration"); }, getStartViewDate: function getStartViewDate() { return this.getStartViewDate(); }, getEndViewDate: function getEndViewDate() { return this.getEndViewDate(); }, getMaxAppointmentsPerCell: function getMaxAppointmentsPerCell() { return this.getMaxAppointmentsPerCell(); }, agendaIsReady: function agendaIsReady(rows, innerRowOffset, outerRowOffset) { var $appts = this.getAppointmentsInstance()._itemElements(), total = 0; $appts.css("marginBottom", innerRowOffset); var applyOffset = function applyOffset(_, count) { var index = count + total - 1; $appts.eq(index).css("marginBottom", outerRowOffset); total += count; }; for (var i = 0; i < rows.length; i++) { each(rows[i], applyOffset); } }, getTimezone: function getTimezone() { return this._getTimezoneOffsetByOption(); }, getClientTimezoneOffset: function getClientTimezoneOffset(date) { date = date || new Date(); return SchedulerTimezones.getClientTimezoneOffset(date); }, convertDateByTimezone: function convertDateByTimezone(date, appointmentTimezone) { date = new Date(date); var clientTzOffset = -(this._subscribes["getClientTimezoneOffset"](date) / 3600000); var commonTimezoneOffset = this._getTimezoneOffsetByOption(date); var appointmentTimezoneOffset = this._calculateTimezoneByValue(appointmentTimezone, date); if (typeof appointmentTimezoneOffset !== "number") { appointmentTimezoneOffset = clientTzOffset; } var dateInUTC = date.getTime() - clientTzOffset * 3600000; date = new Date(dateInUTC + appointmentTimezoneOffset * 3600000); if (typeof commonTimezoneOffset === "number") { date = new Date(date.setHours(date.getHours() + (commonTimezoneOffset - appointmentTimezoneOffset))); } return date; }, convertDateByTimezoneBack: function convertDateByTimezoneBack(date, appointmentTimezone) { date = new Date(date); var clientTzOffset = -(this._subscribes["getClientTimezoneOffset"](date) / 3600000); var commonTimezoneOffset = this._getTimezoneOffsetByOption(date); var appointmentTimezoneOffset = this._calculateTimezoneByValue(appointmentTimezone, date); if (typeof appointmentTimezoneOffset !== "number") { appointmentTimezoneOffset = clientTzOffset; } var dateInUTC = date.getTime() + clientTzOffset * 3600000; date = new Date(dateInUTC - appointmentTimezoneOffset * 3600000); if (typeof commonTimezoneOffset === "number") { date = new Date(date.setHours(date.getHours() - (commonTimezoneOffset - appointmentTimezoneOffset))); } return date; }, getDaylightOffset: function getDaylightOffset(startDate, endDate) { return startDate.getTimezoneOffset() - endDate.getTimezoneOffset(); }, getTimezonesDisplayName: function getTimezonesDisplayName() { return SchedulerTimezones.getTimezonesDisplayName(); }, getTimezoneDisplayNameById: function getTimezoneDisplayNameById(id) { return SchedulerTimezones.getTimezoneDisplayNameById(id); }, getSimilarTimezones: function getSimilarTimezones(id) { return SchedulerTimezones.getSimilarTimezones(id); }, getTimezonesIdsByDisplayName: function getTimezonesIdsByDisplayName(displayName) { return SchedulerTimezones.getTimezonesIdsByDisplayName(displayName); }, getTargetedAppointmentData: function getTargetedAppointmentData(appointmentData, appointmentElement, appointmentIndex) { var recurringData = this._getSingleAppointmentData(appointmentData, { skipDateCalculation: true, $appointment: $(appointmentElement), skipHoursProcessing: true }), result = {}; extend(true, result, appointmentData, recurringData); this._convertDatesByTimezoneBack(false, result); // TODO: _getSingleAppointmentData already uses a related cell data for appointment that contains info about resources this.setTargetedAppointmentResources(result, appointmentElement, appointmentIndex); return result; }, getAppointmentDurationInMs: function getAppointmentDurationInMs(options) { var startDate = options.startDate, endDate = options.endDate, allDay = options.allDay, appointmentDuration = endDate.getTime() - startDate.getTime(); var dayDuration = toMs("day"), visibleDayDuration = this._getDayDuration() * toMs("hour"), result = 0; if (allDay) { var ceilQuantityOfDays = Math.ceil(appointmentDuration / dayDuration); result = ceilQuantityOfDays * visibleDayDuration; } else { var isDifferentDate = !dateUtils.sameDate(startDate, new Date(endDate.getTime() - 1)), floorQuantityOfDays = Math.floor(appointmentDuration / dayDuration), tailDuration; if (isDifferentDate) { var hiddenDayDuration = dayDuration - visibleDayDuration; tailDuration = appointmentDuration - (floorQuantityOfDays ? floorQuantityOfDays * dayDuration : hiddenDayDuration); var startDayTime = this.option("startDayHour") * toMs("hour"), endPartDuration = endDate - dateUtils.trimTime(endDate); if (endPartDuration < startDayTime) { if (floorQuantityOfDays) { tailDuration -= hiddenDayDuration; } tailDuration += startDayTime - endPartDuration; } } else { tailDuration = appointmentDuration % dayDuration; } if (tailDuration > visibleDayDuration) { tailDuration = visibleDayDuration; } result = floorQuantityOfDays * visibleDayDuration + tailDuration; } options.callback(result); }, getEndDayHour: function getEndDayHour() { return this.option("endDayHour"); }, getStartDayHour: function getStartDayHour() { return this.option("startDayHour"); } }; module.exports = subscribes;