devextreme
Version:
HTML5 JavaScript Component Suite for Responsive Web Development
1,039 lines (1,036 loc) • 49.8 kB
JavaScript
/**
* DevExtreme (cjs/__internal/scheduler/appointments/m_appointment_collection.js)
* Version: 24.2.6
* Build date: Mon Mar 17 2025
*
* Copyright (c) 2012 - 2025 Developer Express Inc. ALL RIGHTS RESERVED
* Read about DevExtreme licensing here: https://js.devexpress.com/Licensing/
*/
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _translator = require("../../../common/core/animation/translator");
var _events_engine = _interopRequireDefault(require("../../../common/core/events/core/events_engine"));
var _double_click = require("../../../common/core/events/double_click");
var _index = require("../../../common/core/events/utils/index");
var _component_registrator = _interopRequireDefault(require("../../../core/component_registrator"));
var _dom_adapter = _interopRequireDefault(require("../../../core/dom_adapter"));
var _element = require("../../../core/element");
var _element_data = require("../../../core/element_data");
var _renderer = _interopRequireDefault(require("../../../core/renderer"));
var _array = require("../../../core/utils/array");
var _common = require("../../../core/utils/common");
var _date = _interopRequireDefault(require("../../../core/utils/date"));
var _dom = require("../../../core/utils/dom");
var _extend = require("../../../core/utils/extend");
var _iterator = require("../../../core/utils/iterator");
var _object = require("../../../core/utils/object");
var _position = require("../../../core/utils/position");
var _size = require("../../../core/utils/size");
var _type = require("../../../core/utils/type");
var _uiCollection_widget = _interopRequireDefault(require("../../../ui/collection/ui.collection_widget.edit"));
var _date2 = require("../../core/utils/date");
var _m_appointment_adapter = require("../m_appointment_adapter");
var _m_classes = require("../m_classes");
var _m_constants = require("../m_constants");
var _m_expression_utils = require("../m_expression_utils");
var _m_recurrence = require("../m_recurrence");
var _m_utils_time_zone = _interopRequireDefault(require("../m_utils_time_zone"));
var _m_utils = require("../resources/m_utils");
var _m_utils2 = require("./data_provider/m_utils");
var _m_appointment = require("./m_appointment");
var _m_appointment_layout = require("./m_appointment_layout");
var _m_core = require("./resizing/m_core");
function _interopRequireDefault(e) {
return e && e.__esModule ? e : {
default: e
}
}
function _extends() {
return _extends = Object.assign ? Object.assign.bind() : function(n) {
for (var e = 1; e < arguments.length; e++) {
var t = arguments[e];
for (var r in t) {
({}).hasOwnProperty.call(t, r) && (n[r] = t[r])
}
}
return n
}, _extends.apply(null, arguments)
}
const COMPONENT_CLASS = "dx-scheduler-scrollable-appointments";
const DBLCLICK_EVENT_NAME = (0, _index.addNamespace)(_double_click.name, "dxSchedulerAppointment");
const toMs = _date.default.dateToMilliseconds;
class SchedulerAppointments extends _uiCollection_widget.default {
get isAgendaView() {
return this.invoke("isCurrentViewAgenda")
}
get isVirtualScrolling() {
return this.invoke("isVirtualScrolling")
}
get appointmentDataProvider() {
return this.option("getAppointmentDataProvider")()
}
constructor(element, options) {
super(element, options);
this._virtualAppointments = {}
}
option(optionName, value) {
return super.option(...arguments)
}
notifyObserver(subject, args) {
const observer = this.option("observer");
if (observer) {
observer.fire(subject, args)
}
}
invoke(funcName) {
for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
args[_key - 1] = arguments[_key]
}
const observer = this.option("observer");
if (observer) {
return observer.fire.apply(observer, arguments)
}
}
_dispose() {
clearTimeout(this._appointmentClickTimeout);
super._dispose()
}
_supportedKeys() {
const parent = super._supportedKeys();
const currentAppointment = this._$currentAppointment;
return (0, _extend.extend)(parent, {
escape: function() {
if (this.resizeOccur) {
var _currentAppointment$d, _currentAppointment$d2, _currentAppointment$d3;
this.moveAppointmentBack();
this.resizeOccur = false;
null === (_currentAppointment$d = currentAppointment.dxResizable("instance")) || void 0 === _currentAppointment$d || _currentAppointment$d._detachEventHandlers();
null === (_currentAppointment$d2 = currentAppointment.dxResizable("instance")) || void 0 === _currentAppointment$d2 || _currentAppointment$d2._attachEventHandlers();
null === (_currentAppointment$d3 = currentAppointment.dxResizable("instance")) || void 0 === _currentAppointment$d3 || _currentAppointment$d3._toggleResizingClass(false)
}
}.bind(this),
del: function(e) {
if (this.option("allowDelete")) {
e.preventDefault();
const data = this._getItemData(e.target);
this.notifyObserver("onDeleteButtonPress", {
data: data,
target: e.target
})
}
}.bind(this),
tab: function(e) {
const navigatableItems = this._getNavigatableItems();
const focusedItem = navigatableItems.filter(".dx-state-focused");
let index = focusedItem.data(_m_constants.APPOINTMENT_SETTINGS_KEY).sortedIndex;
const lastIndex = navigatableItems.length - 1;
if (index > 0 && e.shiftKey || index < lastIndex && !e.shiftKey) {
e.preventDefault();
e.shiftKey ? index-- : index++;
const $nextAppointment = this._getNavigatableItemByIndex(index);
this._resetTabIndex($nextAppointment);
_events_engine.default.trigger($nextAppointment, "focus")
}
}
})
}
_getNavigatableItemByIndex(sortedIndex) {
const appointments = this._getNavigatableItems();
return appointments.filter(((_, $item) => (0, _element_data.data)($item, _m_constants.APPOINTMENT_SETTINGS_KEY).sortedIndex === sortedIndex)).eq(0)
}
_getNavigatableItems() {
const appts = this._itemElements().filter(":visible").not(".dx-state-disabled");
const apptCollectors = this.$element().find(".dx-scheduler-appointment-collector");
return appts.add(apptCollectors)
}
_resetTabIndex($appointment) {
this._focusTarget().attr("tabIndex", -1);
$appointment.attr("tabIndex", this.option("tabIndex"))
}
_moveFocus() {}
_focusTarget() {
return this._getNavigatableItems()
}
_renderFocusTarget() {
const $appointment = this._getNavigatableItemByIndex(0);
this._resetTabIndex($appointment)
}
_focusInHandler(e) {
super._focusInHandler(e);
this._$currentAppointment = (0, _renderer.default)(e.target);
this.option("focusedElement", (0, _element.getPublicElement)((0, _renderer.default)(e.target)))
}
_focusOutHandler(e) {
const $appointment = this._getNavigatableItemByIndex(0);
this.option("focusedElement", (0, _element.getPublicElement)($appointment));
super._focusOutHandler(e)
}
_eventBindingTarget() {
return this._itemContainer()
}
_getDefaultOptions() {
return (0, _extend.extend)(super._getDefaultOptions(), {
noDataText: null,
activeStateEnabled: true,
hoverStateEnabled: true,
tabIndex: 0,
fixedContainer: null,
allDayContainer: null,
allowDrag: true,
allowResize: true,
allowAllDayResize: true,
onAppointmentDblClick: null,
_collectorOffset: 0,
groups: [],
resources: []
})
}
_optionChanged(args) {
switch (args.name) {
case "items":
this._cleanFocusState();
this._clearDropDownItems();
this._clearDropDownItemsElements();
this._repaintAppointments(args.value);
this._renderDropDownAppointments();
this._attachAppointmentsEvents();
break;
case "fixedContainer":
case "allDayContainer":
case "onAppointmentDblClick":
case "allowDelete":
break;
case "allowDrag":
case "allowResize":
case "allowAllDayResize":
this._invalidate();
break;
case "focusedElement":
this._resetTabIndex((0, _renderer.default)(args.value));
super._optionChanged(args);
break;
case "focusStateEnabled":
this._clearDropDownItemsElements();
this._renderDropDownAppointments();
super._optionChanged(args);
break;
default:
super._optionChanged(args)
}
}
_isAllDayAppointment(appointment) {
return appointment.settings.length && appointment.settings[0].allDay || false
}
_isRepaintAppointment(appointment) {
return !(0, _type.isDefined)(appointment.needRepaint) || true === appointment.needRepaint
}
_isRepaintAll(appointments) {
if (this.isAgendaView) {
return true
}
for (let i = 0; i < appointments.length; i++) {
if (!this._isRepaintAppointment(appointments[i])) {
return false
}
}
return true
}
_applyFragment(fragment, allDay) {
if (fragment.children().length > 0) {
this._getAppointmentContainer(allDay).append(fragment)
}
}
_onEachAppointment(appointment, index, container, isRepaintAll) {
const repaintAppointment = () => {
appointment.needRepaint = false;
this._clearItem(appointment);
this._renderItem(index, appointment, container)
};
if (true === (null === appointment || void 0 === appointment ? void 0 : appointment.needRemove)) {
this._clearItem(appointment)
} else if (isRepaintAll || this._isRepaintAppointment(appointment)) {
repaintAppointment()
}
}
_repaintAppointments(appointments) {
this._renderByFragments((($commonFragment, $allDayFragment) => {
const isRepaintAll = this._isRepaintAll(appointments);
if (isRepaintAll) {
this._getAppointmentContainer(true).html("");
this._getAppointmentContainer(false).html("")
}!appointments.length && this._cleanItemContainer();
appointments.forEach(((appointment, index) => {
const container = this._isAllDayAppointment(appointment) ? $allDayFragment : $commonFragment;
this._onEachAppointment(appointment, index, container, isRepaintAll)
}))
}))
}
_renderByFragments(renderFunction) {
if (this.isVirtualScrolling) {
const $commonFragment = (0, _renderer.default)(_dom_adapter.default.createDocumentFragment());
const $allDayFragment = (0, _renderer.default)(_dom_adapter.default.createDocumentFragment());
renderFunction($commonFragment, $allDayFragment);
this._applyFragment($commonFragment, false);
this._applyFragment($allDayFragment, true)
} else {
renderFunction(this._getAppointmentContainer(false), this._getAppointmentContainer(true))
}
}
_refreshActiveDescendant() {}
_attachAppointmentsEvents() {
this._attachClickEvent();
this._attachHoldEvent();
this._attachContextMenuEvent();
this._attachAppointmentDblClick();
this._renderFocusState();
this._attachFeedbackEvents();
this._attachHoverEvents()
}
_clearItem(item) {
const $items = this._findItemElementByItem(item.itemData);
if (!$items.length) {
return
}(0, _iterator.each)($items, ((_, $item) => {
$item.detach();
$item.remove()
}))
}
_clearDropDownItems() {
this._virtualAppointments = {}
}
_clearDropDownItemsElements() {
this.invoke("clearCompactAppointments")
}
_findItemElementByItem(item) {
const result = [];
const that = this;
this.itemElements().each((function() {
const $item = (0, _renderer.default)(this);
if ($item.data(that._itemDataKey()) === item) {
result.push($item)
}
}));
return result
}
_itemClass() {
return _m_classes.APPOINTMENT_ITEM_CLASS
}
_itemContainer() {
const $container = super._itemContainer();
let $result = $container;
const $allDayContainer = this.option("allDayContainer");
if ($allDayContainer) {
$result = $container.add($allDayContainer)
}
return $result
}
_cleanItemContainer() {
super._cleanItemContainer();
const $allDayContainer = this.option("allDayContainer");
if ($allDayContainer) {
$allDayContainer.empty()
}
this._virtualAppointments = {}
}
_clean() {
super._clean();
delete this._$currentAppointment;
delete this._initialSize;
delete this._initialCoordinates
}
_init() {
super._init();
this.$element().addClass(COMPONENT_CLASS);
this._preventSingleAppointmentClick = false
}
_renderAppointmentTemplate($container, appointment, model) {
var _this$_currentAppoint;
const config = {
isAllDay: appointment.allDay,
isRecurrence: appointment.recurrenceRule,
html: (0, _type.isPlainObject)(appointment) && appointment.html ? appointment.html : void 0
};
const formatText = this.invoke("getTextAndFormatDate", model.appointmentData, (null === (_this$_currentAppoint = this._currentAppointmentSettings) || void 0 === _this$_currentAppoint ? void 0 : _this$_currentAppoint.agendaSettings) || model.targetedAppointmentData, "TIME");
$container.append(this.isAgendaView ? (0, _m_appointment_layout.createAgendaAppointmentLayout)(formatText, config) : (0, _m_appointment_layout.createAppointmentLayout)(formatText, config));
if (!this.isAgendaView) {
$container.parent().prepend((0, _renderer.default)("<div>").addClass(_m_classes.APPOINTMENT_CONTENT_CLASSES.STRIP))
}
}
_executeItemRenderAction(index, itemData, itemElement) {
const action = this._getItemRenderAction();
if (action) {
action(this.invoke("mapAppointmentFields", {
itemData: itemData,
itemElement: itemElement
}))
}
delete this._currentAppointmentSettings
}
_itemClickHandler(e) {
super._itemClickHandler(e, {}, {
afterExecute: function(e) {
this._processItemClick(e.args[0].event)
}.bind(this)
})
}
_processItemClick(e) {
const $target = (0, _renderer.default)(e.currentTarget);
const data = this._getItemData($target);
if ($target.is(".dx-scheduler-appointment-collector")) {
return
}
if ("keydown" === e.type || (0, _index.isFakeClickEvent)(e)) {
this.notifyObserver("showEditAppointmentPopup", {
data: data,
target: $target
});
return
}
this._appointmentClickTimeout = setTimeout((() => {
if (!this._preventSingleAppointmentClick && (0, _dom.isElementInDom)($target)) {
this.notifyObserver("showAppointmentTooltip", {
data: data,
target: $target
})
}
this._preventSingleAppointmentClick = false
}), 300)
}
_extendActionArgs($itemElement) {
const args = super._extendActionArgs($itemElement);
return this.invoke("mapAppointmentFields", args)
}
_render() {
super._render();
this._attachAppointmentDblClick()
}
_attachAppointmentDblClick() {
const that = this;
const itemSelector = that._itemSelector();
const itemContainer = this._itemContainer();
_events_engine.default.off(itemContainer, DBLCLICK_EVENT_NAME, itemSelector);
_events_engine.default.on(itemContainer, DBLCLICK_EVENT_NAME, itemSelector, (e => {
that._itemDXEventHandler(e, "onAppointmentDblClick", {}, {
afterExecute(e) {
that._dblClickHandler(e.args[0].event)
}
})
}))
}
_dblClickHandler(e) {
const $targetAppointment = (0, _renderer.default)(e.currentTarget);
const appointmentData = this._getItemData($targetAppointment);
clearTimeout(this._appointmentClickTimeout);
this._preventSingleAppointmentClick = true;
this.notifyObserver("showEditAppointmentPopup", {
data: appointmentData,
target: $targetAppointment
})
}
_renderItem(index, item, container) {
const {
itemData: itemData
} = item;
const $items = [];
for (let i = 0; i < item.settings.length; i++) {
const setting = item.settings[i];
this._currentAppointmentSettings = setting;
const $item = super._renderItem(index, itemData, container);
$item.data(_m_constants.APPOINTMENT_SETTINGS_KEY, setting);
$items.push($item)
}
return $items
}
_getItemContent($itemFrame) {
$itemFrame.data(_m_constants.APPOINTMENT_SETTINGS_KEY, this._currentAppointmentSettings);
const $itemContent = super._getItemContent($itemFrame);
return $itemContent
}
_createItemByTemplate(itemTemplate, renderArgs) {
const {
itemData: itemData,
container: container,
index: index
} = renderArgs;
return itemTemplate.render({
model: {
appointmentData: itemData,
targetedAppointmentData: this.invoke("getTargetedAppointmentData", itemData, (0, _renderer.default)(container).parent())
},
container: container,
index: index
})
}
_getAppointmentContainer(allDay) {
const $allDayContainer = this.option("allDayContainer");
let $container = this.itemsContainer().not($allDayContainer);
if (allDay && $allDayContainer) {
$container = $allDayContainer
}
return $container
}
_postprocessRenderItem(args) {
this._renderAppointment(args.itemElement, this._currentAppointmentSettings)
}
_getGroupTexts(groupIndex, loadedResources) {
if (!(null !== loadedResources && void 0 !== loadedResources && loadedResources.length)) {
return []
}
const idPath = (0, _m_utils.getPathToLeaf)(groupIndex, loadedResources);
const textPath = idPath.map(((id, index) => loadedResources[index].items.find((item => item.id === id)).text));
return textPath
}
_renderAppointment(element, settings) {
element.data(_m_constants.APPOINTMENT_SETTINGS_KEY, settings);
this._applyResourceDataAttr(element);
const rawAppointment = this._getItemData(element);
const geometry = this.invoke("getAppointmentGeometry", settings);
const allowResize = this.option("allowResize") && (!(0, _type.isDefined)(settings.skipResizing) || (0, _type.isString)(settings.skipResizing));
const allowDrag = this.option("allowDrag");
const {
allDay: allDay
} = settings;
this.invoke("setCellDataCacheAlias", this._currentAppointmentSettings, geometry);
if (settings.virtual) {
const appointmentConfig = {
itemData: rawAppointment,
groupIndex: settings.groupIndex,
groups: this.option("groups")
};
const deferredColor = this.option("getAppointmentColor")(appointmentConfig);
this._processVirtualAppointment(settings, element, rawAppointment, deferredColor)
} else {
var _settings$info;
const config = {
data: rawAppointment,
groupIndex: settings.groupIndex,
groupTexts: this._getGroupTexts(settings.groupIndex, this.option("getLoadedResources")()),
observer: this.option("observer"),
geometry: geometry,
direction: settings.direction || "vertical",
allowResize: allowResize,
allowDrag: allowDrag,
allDay: allDay,
reduced: settings.appointmentReduced,
isCompact: settings.isCompact,
startDate: new Date(null === (_settings$info = settings.info) || void 0 === _settings$info ? void 0 : _settings$info.appointment.startDate),
cellWidth: this.invoke("getCellWidth"),
cellHeight: this.invoke("getCellHeight"),
resizableConfig: this._resizableConfig(rawAppointment, settings),
groups: this.option("groups"),
partIndex: settings.partIndex,
partTotalCount: settings.partTotalCount,
getAppointmentColor: this.option("getAppointmentColor"),
getResourceDataAccessors: this.option("getResourceDataAccessors"),
timeZoneCalculator: this.option("timeZoneCalculator")
};
if (this.isAgendaView) {
const agendaResourceProcessor = this.option("getAgendaResourceProcessor")();
config.createPlainResourceListAsync = rawAppointment => agendaResourceProcessor.createListAsync(rawAppointment)
}
this._createComponent(element, this.isAgendaView ? _m_appointment.AgendaAppointment : _m_appointment.Appointment, _extends({}, config, {
dataAccessors: this.option("dataAccessors"),
getResizableStep: this.option("getResizableStep")
}))
}
}
_applyResourceDataAttr($appointment) {
const dataAccessors = this.option("getResourceDataAccessors")();
const rawAppointment = this._getItemData($appointment);
(0, _iterator.each)(dataAccessors.getter, (key => {
const value = dataAccessors.getter[key](rawAppointment);
if ((0, _type.isDefined)(value)) {
const prefix = `data-${(0,_common.normalizeKey)(key.toLowerCase())}-`;
(0, _array.wrapToArray)(value).forEach((value => $appointment.attr(prefix + (0, _common.normalizeKey)(value), true)))
}
}))
}
_resizableConfig(appointmentData, itemSetting) {
return {
area: this._calculateResizableArea(itemSetting, appointmentData),
onResizeStart: function(e) {
this.resizeOccur = true;
this._$currentAppointment = (0, _renderer.default)(e.element);
if (this.invoke("needRecalculateResizableArea")) {
const updatedArea = this._calculateResizableArea(this._$currentAppointment.data(_m_constants.APPOINTMENT_SETTINGS_KEY), this._$currentAppointment.data("dxItemData"));
e.component.option("area", updatedArea);
e.component._renderDragOffsets(e.event)
}
this._initialSize = {
width: e.width,
height: e.height
};
this._initialCoordinates = (0, _translator.locate)(this._$currentAppointment)
}.bind(this),
onResizeEnd: function(e) {
this.resizeOccur = false;
this._resizeEndHandler(e)
}.bind(this)
}
}
_calculateResizableArea(itemSetting, appointmentData) {
const area = this.$element().closest(".dx-scrollable-content");
return this.invoke("getResizableAppointmentArea", {
coordinates: {
left: itemSetting.left,
top: 0,
groupIndex: itemSetting.groupIndex
},
allDay: itemSetting.allDay
}) || area
}
_resizeEndHandler(e) {
const $element = (0, _renderer.default)(e.element);
const {
allDay: allDay,
info: info
} = $element.data("dxAppointmentSettings");
const sourceAppointment = this._getItemData($element);
const viewOffset = this.invoke("getViewOffsetMs");
let dateRange;
if (allDay) {
dateRange = this.resizeAllDay(e)
} else {
const startDate = this._getEndResizeAppointmentStartDate(e, sourceAppointment, info.appointment);
const {
endDate: endDate
} = info.appointment;
const shiftedStartDate = _date2.dateUtilsTs.addOffsets(startDate, [-viewOffset]);
const shiftedEndDate = _date2.dateUtilsTs.addOffsets(endDate, [-viewOffset]);
dateRange = this._getDateRange(e, shiftedStartDate, shiftedEndDate);
dateRange.startDate = _date2.dateUtilsTs.addOffsets(dateRange.startDate, [viewOffset]);
dateRange.endDate = _date2.dateUtilsTs.addOffsets(dateRange.endDate, [viewOffset])
}
this.updateResizedAppointment($element, dateRange, this.option("dataAccessors"), this.option("timeZoneCalculator"))
}
resizeAllDay(e) {
const $element = (0, _renderer.default)(e.element);
const timeZoneCalculator = this.option("timeZoneCalculator");
const dataAccessors = this.option("dataAccessors");
return (0, _m_core.getAppointmentDateRange)({
handles: e.handles,
appointmentSettings: $element.data("dxAppointmentSettings"),
isVerticalViewDirection: this.option("isVerticalViewDirection")(),
isVerticalGroupedWorkSpace: this.option("isVerticalGroupedWorkSpace")(),
appointmentRect: (0, _position.getBoundingRect)($element[0]),
parentAppointmentRect: (0, _position.getBoundingRect)($element.parent()[0]),
viewDataProvider: this.option("getViewDataProvider")(),
isDateAndTimeView: this.option("isDateAndTimeView")(),
startDayHour: this.invoke("getStartDayHour"),
endDayHour: this.invoke("getEndDayHour"),
timeZoneCalculator: timeZoneCalculator,
dataAccessors: dataAccessors,
rtlEnabled: this.option("rtlEnabled"),
DOMMetaData: this.option("getDOMElementsMetaData")(),
viewOffset: this.invoke("getViewOffsetMs")
})
}
updateResizedAppointment($element, dateRange, dataAccessors, timeZoneCalculator) {
const sourceAppointment = this._getItemData($element);
const gridAdapter = (0, _m_appointment_adapter.createAppointmentAdapter)(sourceAppointment, dataAccessors, timeZoneCalculator);
gridAdapter.startDate = new Date(dateRange.startDate);
gridAdapter.endDate = new Date(dateRange.endDate);
const convertedBackAdapter = gridAdapter.clone();
convertedBackAdapter.calculateDates("fromGrid").calculateDates("toGrid");
const startDateDelta = gridAdapter.startDate.getTime() - convertedBackAdapter.startDate.getTime();
const endDateDelta = gridAdapter.endDate.getTime() - convertedBackAdapter.endDate.getTime();
gridAdapter.startDate = _date2.dateUtilsTs.addOffsets(gridAdapter.startDate, [startDateDelta]);
gridAdapter.endDate = _date2.dateUtilsTs.addOffsets(gridAdapter.endDate, [endDateDelta]);
this.notifyObserver("updateAppointmentAfterResize", {
target: sourceAppointment,
data: gridAdapter.calculateDates("fromGrid").source(),
$appointment: $element
})
}
_getEndResizeAppointmentStartDate(e, rawAppointment, appointmentInfo) {
const timeZoneCalculator = this.option("timeZoneCalculator");
const appointmentAdapter = (0, _m_appointment_adapter.createAppointmentAdapter)(rawAppointment, this.option("dataAccessors"), timeZoneCalculator);
let {
startDate: startDate
} = appointmentInfo;
const recurrenceProcessor = (0, _m_recurrence.getRecurrenceProcessor)();
const {
recurrenceRule: recurrenceRule,
startDateTimeZone: startDateTimeZone
} = appointmentAdapter;
const isAllDay = this.invoke("isAllDay", rawAppointment);
const isRecurrent = recurrenceProcessor.isValidRecurrenceRule(recurrenceRule);
if (!e.handles.top && !isRecurrent && !isAllDay) {
startDate = timeZoneCalculator.createDate(appointmentAdapter.startDate, {
appointmentTimeZone: startDateTimeZone,
path: "toGrid"
})
}
return startDate
}
_getDateRange(e, startDate, endDate) {
const itemData = this._getItemData(e.element);
const deltaTime = this.invoke("getDeltaTime", e, this._initialSize, itemData);
const renderingStrategyDirection = this.invoke("getRenderingStrategyDirection");
let isStartDateChanged = false;
const isAllDay = this.invoke("isAllDay", itemData);
const needCorrectDates = this.invoke("needCorrectAppointmentDates") && !isAllDay;
let startTime;
let endTime;
if ("vertical" !== renderingStrategyDirection || isAllDay) {
isStartDateChanged = this.option("rtlEnabled") ? e.handles.right : e.handles.left
} else {
isStartDateChanged = e.handles.top
}
if (isStartDateChanged) {
startTime = needCorrectDates ? this._correctStartDateByDelta(startDate, deltaTime) : startDate.getTime() - deltaTime;
startTime += _m_utils_time_zone.default.getTimezoneOffsetChangeInMs(startDate, endDate, startTime, endDate);
endTime = endDate.getTime()
} else {
startTime = startDate.getTime();
endTime = needCorrectDates ? this._correctEndDateByDelta(endDate, deltaTime) : endDate.getTime() + deltaTime;
endTime -= _m_utils_time_zone.default.getTimezoneOffsetChangeInMs(startDate, endDate, startDate, endTime)
}
return {
startDate: new Date(startTime),
endDate: new Date(endTime)
}
}
_correctEndDateByDelta(endDate, deltaTime) {
const endDayHour = this.invoke("getEndDayHour");
const startDayHour = this.invoke("getStartDayHour");
const maxDate = new Date(endDate);
const minDate = new Date(endDate);
const correctEndDate = new Date(endDate);
minDate.setHours(startDayHour, 0, 0, 0);
maxDate.setHours(endDayHour, 0, 0, 0);
if (correctEndDate > maxDate) {
correctEndDate.setHours(endDayHour, 0, 0, 0)
}
let result = correctEndDate.getTime() + deltaTime;
const visibleDayDuration = (endDayHour - startDayHour) * toMs("hour");
const daysCount = deltaTime > 0 ? Math.ceil(deltaTime / visibleDayDuration) : Math.floor(deltaTime / visibleDayDuration);
if (result > maxDate.getTime() || result <= minDate.getTime()) {
const tailOfCurrentDay = maxDate.getTime() - correctEndDate.getTime();
const tailOfPrevDays = deltaTime - tailOfCurrentDay;
const correctedEndDate = new Date(correctEndDate).setDate(correctEndDate.getDate() + daysCount);
const lastDay = new Date(correctedEndDate);
lastDay.setHours(startDayHour, 0, 0, 0);
result = lastDay.getTime() + tailOfPrevDays - visibleDayDuration * (daysCount - 1)
}
return result
}
_correctStartDateByDelta(startDate, deltaTime) {
const endDayHour = this.invoke("getEndDayHour");
const startDayHour = this.invoke("getStartDayHour");
const maxDate = new Date(startDate);
const minDate = new Date(startDate);
const correctStartDate = new Date(startDate);
minDate.setHours(startDayHour, 0, 0, 0);
maxDate.setHours(endDayHour, 0, 0, 0);
if (correctStartDate < minDate) {
correctStartDate.setHours(startDayHour, 0, 0, 0)
}
let result = correctStartDate.getTime() - deltaTime;
const visibleDayDuration = (endDayHour - startDayHour) * toMs("hour");
const daysCount = deltaTime > 0 ? Math.ceil(deltaTime / visibleDayDuration) : Math.floor(deltaTime / visibleDayDuration);
if (result < minDate.getTime() || result >= maxDate.getTime()) {
const tailOfCurrentDay = correctStartDate.getTime() - minDate.getTime();
const tailOfPrevDays = deltaTime - tailOfCurrentDay;
const firstDay = new Date(correctStartDate.setDate(correctStartDate.getDate() - daysCount));
firstDay.setHours(endDayHour, 0, 0, 0);
result = firstDay.getTime() - tailOfPrevDays + visibleDayDuration * (daysCount - 1)
}
return result
}
_processVirtualAppointment(appointmentSetting, $appointment, appointmentData, color) {
const virtualAppointment = appointmentSetting.virtual;
const virtualGroupIndex = virtualAppointment.index;
if (!(0, _type.isDefined)(this._virtualAppointments[virtualGroupIndex])) {
this._virtualAppointments[virtualGroupIndex] = {
coordinates: {
top: virtualAppointment.top,
left: virtualAppointment.left
},
items: {
data: [],
colors: [],
settings: []
},
isAllDay: !!virtualAppointment.isAllDay,
buttonColor: color,
sortedIndex: appointmentSetting.sortedIndex
}
}
appointmentSetting.targetedAppointmentData = this.invoke("getTargetedAppointmentData", appointmentData, $appointment);
this._virtualAppointments[virtualGroupIndex].items.settings.push(appointmentSetting);
this._virtualAppointments[virtualGroupIndex].items.data.push(appointmentData);
this._virtualAppointments[virtualGroupIndex].items.colors.push(color);
$appointment.remove()
}
_renderContentImpl() {
super._renderContentImpl();
this._renderDropDownAppointments()
}
_renderDropDownAppointments() {
this._renderByFragments((($commonFragment, $allDayFragment) => {
(0, _iterator.each)(this._virtualAppointments, (groupIndex => {
const virtualGroup = this._virtualAppointments[groupIndex];
const virtualItems = virtualGroup.items;
const virtualCoordinates = virtualGroup.coordinates;
const $fragment = virtualGroup.isAllDay ? $allDayFragment : $commonFragment;
const {
left: left
} = virtualCoordinates;
const buttonWidth = this.invoke("getDropDownAppointmentWidth", virtualGroup.isAllDay);
const buttonHeight = this.invoke("getDropDownAppointmentHeight");
const rtlOffset = this.option("rtlEnabled") ? buttonWidth : 0;
this.notifyObserver("renderCompactAppointments", {
$container: $fragment,
coordinates: {
top: virtualCoordinates.top,
left: left + rtlOffset
},
items: virtualItems,
buttonColor: virtualGroup.buttonColor,
sortedIndex: virtualGroup.sortedIndex,
width: buttonWidth - this.option("_collectorOffset"),
height: buttonHeight,
onAppointmentClick: this.option("onItemClick"),
allowDrag: this.option("allowDrag"),
cellWidth: this.invoke("getCellWidth"),
isCompact: this.invoke("isAdaptive") || this._isGroupCompact(virtualGroup)
})
}))
}))
}
_isGroupCompact(virtualGroup) {
return !virtualGroup.isAllDay && this.invoke("supportCompactDropDownAppointments")
}
_sortAppointmentsByStartDate(appointments) {
return (0, _m_utils2.sortAppointmentsByStartDate)(appointments, this.option("dataAccessors"))
}
_processRecurrenceAppointment(appointment, index, skipLongAppointments) {
const recurrenceRule = _m_expression_utils.ExpressionUtils.getField(this.option("dataAccessors"), "recurrenceRule", appointment);
const result = {
parts: [],
indexes: []
};
if (recurrenceRule) {
const dates = appointment.settings || appointment;
const startDate = new Date(_m_expression_utils.ExpressionUtils.getField(this.option("dataAccessors"), "startDate", dates));
const startDateTimeZone = _m_expression_utils.ExpressionUtils.getField(this.option("dataAccessors"), "startDateTimeZone", appointment);
const endDate = new Date(_m_expression_utils.ExpressionUtils.getField(this.option("dataAccessors"), "endDate", dates));
const appointmentDuration = endDate.getTime() - startDate.getTime();
const recurrenceException = _m_expression_utils.ExpressionUtils.getField(this.option("dataAccessors"), "recurrenceException", appointment);
const startViewDate = this.invoke("getStartViewDate");
const endViewDate = this.invoke("getEndViewDate");
const timezoneCalculator = this.option("timeZoneCalculator");
const recurrentDates = (0, _m_recurrence.getRecurrenceProcessor)().generateDates({
rule: recurrenceRule,
exception: recurrenceException,
start: startDate,
end: endDate,
min: startViewDate,
max: endViewDate,
appointmentTimezoneOffset: timezoneCalculator.getOriginStartDateOffsetInMs(startDate, startDateTimeZone, false)
});
const recurrentDateCount = appointment.settings ? 1 : recurrentDates.length;
for (let i = 0; i < recurrentDateCount; i++) {
const appointmentPart = (0, _extend.extend)({}, appointment, true);
if (recurrentDates[i]) {
const appointmentSettings = this._applyStartDateToObj(recurrentDates[i], {});
this._applyEndDateToObj(new Date(recurrentDates[i].getTime() + appointmentDuration), appointmentSettings);
appointmentPart.settings = appointmentSettings
} else {
appointmentPart.settings = dates
}
result.parts.push(appointmentPart);
if (!skipLongAppointments) {
this._processLongAppointment(appointmentPart, result)
}
}
result.indexes.push(index)
}
return result
}
_processLongAppointment(appointment, result) {
const parts = this.splitAppointmentByDay(appointment);
const partCount = parts.length;
const endViewDate = this.invoke("getEndViewDate").getTime();
const startViewDate = this.invoke("getStartViewDate").getTime();
const timeZoneCalculator = this.option("timeZoneCalculator");
result = result || {
parts: []
};
if (partCount > 1) {
(0, _extend.extend)(appointment, parts[0]);
for (let i = 1; i < partCount; i++) {
let startDate = _m_expression_utils.ExpressionUtils.getField(this.option("dataAccessors"), "startDate", parts[i].settings).getTime();
startDate = timeZoneCalculator.createDate(startDate, {
path: "toGrid"
});
if (startDate < endViewDate && startDate > startViewDate) {
result.parts.push(parts[i])
}
}
}
return result
}
_reduceRecurrenceAppointments(recurrenceIndexes, appointments) {
(0, _iterator.each)(recurrenceIndexes, ((i, index) => {
appointments.splice(index - i, 1)
}))
}
_combineAppointments(appointments, additionalAppointments) {
if (additionalAppointments.length) {
appointments.push(...additionalAppointments)
}
this._sortAppointmentsByStartDate(appointments)
}
_applyStartDateToObj(startDate, obj) {
_m_expression_utils.ExpressionUtils.setField(this.option("dataAccessors"), "startDate", obj, startDate);
return obj
}
_applyEndDateToObj(endDate, obj) {
_m_expression_utils.ExpressionUtils.setField(this.option("dataAccessors"), "endDate", obj, endDate);
return obj
}
moveAppointmentBack(dragEvent) {
const $appointment = this._$currentAppointment;
const size = this._initialSize;
const coords = this._initialCoordinates;
if (dragEvent) {
this._removeDragSourceClassFromDraggedAppointment();
if ((0, _type.isDeferred)(dragEvent.cancel)) {
dragEvent.cancel.resolve(true)
} else {
dragEvent.cancel = true
}
}
if ($appointment && !dragEvent) {
if (coords) {
(0, _translator.move)($appointment, coords);
delete this._initialSize
}
if (size) {
(0, _size.setOuterWidth)($appointment, size.width);
(0, _size.setOuterHeight)($appointment, size.height);
delete this._initialCoordinates
}
}
}
focus() {
if (this._$currentAppointment) {
const focusedElement = (0, _element.getPublicElement)(this._$currentAppointment);
this.option("focusedElement", focusedElement);
_events_engine.default.trigger(focusedElement, "focus")
}
}
splitAppointmentByDay(appointment) {
const dates = appointment.settings || appointment;
const dataAccessors = this.option("dataAccessors");
const originalStartDate = new Date(_m_expression_utils.ExpressionUtils.getField(dataAccessors, "startDate", dates));
let startDate = _date.default.makeDate(originalStartDate);
let endDate = _date.default.makeDate(_m_expression_utils.ExpressionUtils.getField(dataAccessors, "endDate", dates));
const maxAllowedDate = this.invoke("getEndViewDate");
const startDayHour = this.invoke("getStartDayHour");
const endDayHour = this.invoke("getEndDayHour");
const timeZoneCalculator = this.option("timeZoneCalculator");
const adapter = (0, _m_appointment_adapter.createAppointmentAdapter)(appointment, dataAccessors, timeZoneCalculator);
const appointmentIsLong = (0, _m_utils2.getAppointmentTakesSeveralDays)(adapter);
const result = [];
startDate = timeZoneCalculator.createDate(startDate, {
path: "toGrid"
});
endDate = timeZoneCalculator.createDate(endDate, {
path: "toGrid"
});
if (startDate.getHours() <= endDayHour && startDate.getHours() >= startDayHour && !appointmentIsLong) {
result.push(this._applyStartDateToObj(new Date(startDate), {
appointmentData: appointment
}));
startDate.setDate(startDate.getDate() + 1)
}
while (appointmentIsLong && startDate.getTime() < endDate.getTime() && startDate < maxAllowedDate) {
const currentStartDate = new Date(startDate);
const currentEndDate = new Date(startDate);
this._checkStartDate(currentStartDate, originalStartDate, startDayHour);
this._checkEndDate(currentEndDate, endDate, endDayHour);
const appointmentData = (0, _object.deepExtendArraySafe)({}, appointment, true);
const appointmentSettings = {};
this._applyStartDateToObj(currentStartDate, appointmentSettings);
this._applyEndDateToObj(currentEndDate, appointmentSettings);
appointmentData.settings = appointmentSettings;
result.push(appointmentData);
startDate = _date.default.trimTime(startDate);
startDate.setDate(startDate.getDate() + 1);
startDate.setHours(startDayHour)
}
return result
}
_checkStartDate(currentDate, originalDate, startDayHour) {
if (!_date.default.sameDate(currentDate, originalDate) || currentDate.getHours() <= startDayHour) {
currentDate.setHours(startDayHour, 0, 0, 0)
} else {
currentDate.setHours(originalDate.getHours(), originalDate.getMinutes(), originalDate.getSeconds(), originalDate.getMilliseconds())
}
}
_checkEndDate(currentDate, originalDate, endDayHour) {
if (!_date.default.sameDate(currentDate, originalDate) || currentDate.getHours() > endDayHour) {
currentDate.setHours(endDayHour, 0, 0, 0)
} else {
currentDate.setHours(originalDate.getHours(), originalDate.getMinutes(), originalDate.getSeconds(), originalDate.getMilliseconds())
}
}
_removeDragSourceClassFromDraggedAppointment() {
const $appointments = this._itemElements().filter(`.${_m_classes.APPOINTMENT_DRAG_SOURCE_CLASS}`);
$appointments.each(((_, element) => {
const appointmentInstance = (0, _renderer.default)(element).dxSchedulerAppointment("instance");
appointmentInstance.option("isDragSource", false)
}))
}
_setDragSourceAppointment(appointment, settings) {
const $appointments = this._findItemElementByItem(appointment);
const {
startDate: startDate,
endDate: endDate
} = settings.info.sourceAppointment;
const {
groupIndex: groupIndex
} = settings;
$appointments.forEach(($item => {
const {
info: itemInfo,
groupIndex: itemGroupIndex
} = $item.data(_m_constants.APPOINTMENT_SETTINGS_KEY);
const {
startDate: itemStartDate,
endDate: itemEndDate
} = itemInfo.sourceAppointment;
const appointmentInstance = $item.dxSchedulerAppointment("instance");
const isDragSource = startDate.getTime() === itemStartDate.getTime() && endDate.getTime() === itemEndDate.getTime() && groupIndex === itemGroupIndex;
appointmentInstance.option("isDragSource", isDragSource)
}))
}
updateResizableArea() {
const $allResizableElements = this.$element().find(".dx-scheduler-appointment.dx-resizable");
const horizontalResizables = (0, _common.grep)($allResizableElements, (el => {
const $el = (0, _renderer.default)(el);
const resizableInst = $el.dxResizable("instance");
const {
area: area,
handles: handles
} = resizableInst.option();
return ("right left" === handles || "left right" === handles) && (0, _type.isPlainObject)(area)
}));
(0, _iterator.each)(horizontalResizables, ((_, el) => {
const $el = (0, _renderer.default)(el);
const position = (0, _translator.locate)($el);
const appointmentData = this._getItemData($el);
const area = this._calculateResizableArea({
left: position.left
}, appointmentData);
$el.dxResizable("instance").option("area", area)
}))
}
}(0, _component_registrator.default)("dxSchedulerAppointments", SchedulerAppointments);
var _default = exports.default = SchedulerAppointments;