UNPKG

devextreme

Version:

JavaScript/TypeScript Component Suite for Responsive Web Development

1,155 lines • 82.5 kB
/** * DevExtreme (esm/__internal/scheduler/m_scheduler.js) * Version: 25.2.7 * Build date: Tue May 05 2026 * * Copyright (c) 2012 - 2026 Developer Express Inc. ALL RIGHTS RESERVED * Read about DevExtreme licensing here: https://js.devexpress.com/Licensing/ */ import { triggerResizeEvent } from "../../common/core/events/visibility_change"; import dateLocalization from "../../common/core/localization/date"; import messageLocalization from "../../common/core/localization/message"; import registerComponent from "../../core/component_registrator"; import config from "../../core/config"; import { getPublicElement } from "../../core/element"; import $ from "../../core/renderer"; import { BindableTemplate } from "../../core/templates/bindable_template"; import { EmptyTemplate } from "../../core/templates/empty_template"; import Callbacks from "../../core/utils/callbacks"; import { noop } from "../../core/utils/common"; import { compileGetter } from "../../core/utils/data"; import dateUtils from "../../core/utils/date"; import dateSerialization from "../../core/utils/date_serialization"; import { Deferred, fromPromise, when } from "../../core/utils/deferred"; import { extend } from "../../core/utils/extend"; import { getBoundingRect } from "../../core/utils/position"; import { isDeferred, isDefined, isEmptyObject, isFunction, isObject, isPromise } from "../../core/utils/type"; import { hasWindow } from "../../core/utils/window"; import DataHelperMixin from "../../data_helper"; import { custom as customDialog } from "../../ui/dialog"; import errors from "../../ui/widget/ui.errors"; import { dateUtilsTs } from "../core/utils/date"; import { createA11yStatusContainer } from "./a11y_status/a11y_status_render"; import { getA11yStatusText } from "./a11y_status/a11y_status_text"; import { AppointmentForm } from "./appointment_popup/m_form"; import { AppointmentPopup } from "./appointment_popup/m_popup"; import AppointmentCollection from "./appointments/m_appointment_collection"; import { Appointments } from "./appointments_new/appointments"; import NotifyScheduler from "./base/m_widget_notify_scheduler"; import { SchedulerHeader } from "./header/m_header"; import { CompactAppointmentsHelper } from "./m_compact_appointments_helper"; import { hide as hideLoading, show as showLoading } from "./m_loading"; import subscribes from "./m_subscribes"; import { utils } from "./m_utils"; import timeZoneUtils from "./m_utils_time_zone"; import { combineRemoteFilter } from "./r1/filterting/remote"; import { createTimeZoneCalculator } from "./r1/timezone_calculator/index"; import { excludeFromRecurrence, getToday, isAppointmentTakesAllDay, isDateAndTimeView, isTimelineView } from "./r1/utils/index"; import { validateRRule } from "./recurrence/validate_rule"; import { SchedulerOptionsBaseWidget } from "./scheduler_options_base_widget"; import { DesktopTooltipStrategy } from "./tooltip_strategies/m_desktop_tooltip_strategy"; import { MobileTooltipStrategy } from "./tooltip_strategies/m_mobile_tooltip_strategy"; import { AppointmentAdapter } from "./utils/appointment_adapter/appointment_adapter"; import { AppointmentDataAccessor } from "./utils/data_accessor/appointment_data_accessor"; import { getTargetedAppointment } from "./utils/get_targeted_appointment"; import { macroTaskArray } from "./utils/index"; import { isAgendaWorkspaceComponent } from "./utils/is_agenda_workpace_component"; import { VIEWS } from "./utils/options/constants_view"; import { getAppointmentGroupValues, setAppointmentGroupValues } from "./utils/resource_manager/appointment_groups_utils"; import { ResourceManager } from "./utils/resource_manager/resource_manager"; import AppointmentLayoutManager from "./view_model/appointments_layout_manager"; import { AppointmentDataSource } from "./view_model/m_appointment_data_source"; import SchedulerAgenda from "./workspaces/m_agenda"; import SchedulerTimelineDay from "./workspaces/m_timeline_day"; import SchedulerTimelineMonth from "./workspaces/m_timeline_month"; import SchedulerTimelineWeek from "./workspaces/m_timeline_week"; import SchedulerTimelineWorkWeek from "./workspaces/m_timeline_work_week"; import SchedulerWorkSpaceDay from "./workspaces/m_work_space_day"; import SchedulerWorkSpaceMonth from "./workspaces/m_work_space_month"; import SchedulerWorkSpaceWeek from "./workspaces/m_work_space_week"; import SchedulerWorkSpaceWorkWeek from "./workspaces/m_work_space_work_week"; const toMs = dateUtils.dateToMilliseconds; const WIDGET_CLASS = "dx-scheduler"; const WIDGET_SMALL_CLASS = `${WIDGET_CLASS}-small`; const WIDGET_ADAPTIVE_CLASS = `${WIDGET_CLASS}-adaptive`; const WIDGET_READONLY_CLASS = `${WIDGET_CLASS}-readonly`; export const POPUP_DIALOG_CLASS = "dx-dialog"; const WIDGET_SMALL_WIDTH = 400; const FULL_DATE_FORMAT = "yyyyMMddTHHmmss"; const UTC_FULL_DATE_FORMAT = `${FULL_DATE_FORMAT}Z`; const VIEWS_CONFIG = { day: { workSpace: SchedulerWorkSpaceDay, renderingStrategy: "vertical" }, week: { workSpace: SchedulerWorkSpaceWeek, renderingStrategy: "vertical" }, workWeek: { workSpace: SchedulerWorkSpaceWorkWeek, renderingStrategy: "vertical" }, month: { workSpace: SchedulerWorkSpaceMonth, renderingStrategy: "horizontalMonth" }, timelineDay: { workSpace: SchedulerTimelineDay, renderingStrategy: "horizontal" }, timelineWeek: { workSpace: SchedulerTimelineWeek, renderingStrategy: "horizontal" }, timelineWorkWeek: { workSpace: SchedulerTimelineWorkWeek, renderingStrategy: "horizontal" }, timelineMonth: { workSpace: SchedulerTimelineMonth, renderingStrategy: "horizontalMonthLine" }, agenda: { workSpace: SchedulerAgenda, renderingStrategy: "agenda" } }; const StoreEventNames = { ADDING: "onAppointmentAdding", ADDED: "onAppointmentAdded", DELETING: "onAppointmentDeleting", DELETED: "onAppointmentDeleted", UPDATING: "onAppointmentUpdating", UPDATED: "onAppointmentUpdated" }; const RECURRENCE_EDITING_MODE = { SERIES: "editSeries", OCCURRENCE: "editOccurrence", CANCEL: "cancel" }; class Scheduler extends SchedulerOptionsBaseWidget { constructor() { super(...arguments); this.updatingAppointments = new Set } get timeZoneCalculator() { if (!this.timeZoneCalculatorInstance) { this.timeZoneCalculatorInstance = createTimeZoneCalculator(this.option("timeZone")) } return this.timeZoneCalculatorInstance } postponeDataSourceLoading(promise) { this.postponedOperations.add("_reloadDataSource", this.reloadDataSource.bind(this), promise) } postponeResourceLoading() { let forceReload = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : false; const whenLoaded = this.postponedOperations.add("loadResources", () => { const groups = this.getViewOption("groups"); return fromPromise(this.resourceManager.loadGroupResources(groups, forceReload)) }); const resolveCallbacks = new Deferred; whenLoaded.done(() => { resolveCallbacks.resolve() }); this.postponeDataSourceLoading(whenLoaded); return resolveCallbacks.promise() } _optionChanged(args) { var _this$resourceManager; this.schedulerOptionChanged(args); const { value: value, name: name } = args; switch (args.name) { case "customizeDateNavigatorText": this.updateOption("header", name, value); break; case "firstDayOfWeek": this.updateOption("workSpace", name, value); this.updateOption("header", name, value); this.cleanPopup(); break; case "currentDate": { const dateValue = this.getViewOption(name); this.option("selectedCellData", []); this.updateOption("workSpace", name, dateValue); this.updateOption("header", name, dateValue); this.updateOption("header", "startViewDate", this.getStartViewDate()); this._appointments.option("items", []); this.setRemoteFilterIfNeeded(); this.postponeDataSourceLoading(); break } case "dataSource": this._initDataSource(); this.postponeResourceLoading().done(() => { this.appointmentDataSource.setDataSource(this._dataSource); this.setRemoteFilterIfNeeded(); this.updateOption("workSpace", "showAllDayPanel", this.option("showAllDayPanel")) }); break; case "min": case "max": { const value = this.getViewOption(name); this.updateOption("header", name, value); this.updateOption("workSpace", name, value); break } case "views": if (this.currentView) { this.repaint() } else { this.updateOption("header", "views", this.views) } break; case "useDropDownViewSwitcher": this.updateOption("header", name, value); break; case "currentView": if (this.option("_newAppointments")) { this._appointments.option({ currentView: value, viewModel: [], appointmentTemplate: this.getViewOption("appointmentTemplate"), appointmentCollectorTemplate: this.getViewOption("appointmentCollectorTemplate") }) } else { this._appointments.option({ items: [], allowDrag: this.allowDragging(), allowResize: this.allowResizing(), itemTemplate: this.getAppointmentTemplate("appointmentTemplate") }) } this.postponeResourceLoading().done(() => { var _this$header; this.refreshWorkSpace(); null === (_this$header = this.header) || void 0 === _this$header || _this$header.option(this.headerConfig()); this.setRemoteFilterIfNeeded(); if (!this.option("_newAppointments")) { this._appointments.option("allowAllDayResize", "day" !== value) } }); this.postponedOperations.callPostponedOperations(); break; case "appointmentTemplate": if (this.option("_newAppointments")) { this._appointments.option("appointmentTemplate", this.getViewOption("appointmentTemplate")) } else { this._appointments.option("itemTemplate", value) } break; case "dateCellTemplate": case "resourceCellTemplate": case "dataCellTemplate": case "timeCellTemplate": this.repaint(); break; case "groups": this.postponeResourceLoading().done(() => { this.refreshWorkSpace(); this.setRemoteFilterIfNeeded() }); break; case "resources": null === (_this$resourceManager = this.resourceManager) || void 0 === _this$resourceManager || _this$resourceManager.dispose(); this.resourceManager = new ResourceManager(this.option("resources")); this.updateAppointmentDataSource(); this.postponeResourceLoading().done(() => { this._appointments.option("items", []); this.refreshWorkSpace(); this.setRemoteFilterIfNeeded(); this.createAppointmentPopupForm() }); break; case "startDayHour": case "endDayHour": this.updateAppointmentDataSource(); this._appointments.option("items", []); this.updateOption("workSpace", name, value); if (!this.option("_newAppointments")) { this._appointments.repaint() } this.setRemoteFilterIfNeeded(); this.postponeDataSourceLoading(); break; case "offset": this.updateAppointmentDataSource(); this._appointments.option("items", []); this.updateOption("workSpace", "viewOffset", this.normalizeViewOffsetValue(value)); if (!this.option("_newAppointments")) { this._appointments.repaint() } this.setRemoteFilterIfNeeded(); this.postponeDataSourceLoading(); break; case StoreEventNames.ADDING: case StoreEventNames.ADDED: case StoreEventNames.UPDATING: case StoreEventNames.UPDATED: case StoreEventNames.DELETING: case StoreEventNames.DELETED: case "onAppointmentFormOpening": case "onAppointmentTooltipShowing": this.actions[name] = this._createActionByOption(name); break; case "onAppointmentRendered": if (this.option("_newAppointments")) { this.createAppointmentRenderedAction() } else { this._appointments.option("onItemRendered", this.getAppointmentRenderedAction()) } break; case "onAppointmentClick": this._appointments.option("onItemClick", this._createActionByOption(name)); break; case "onAppointmentDblClick": this._appointments.option(name, this._createActionByOption(name)); break; case "onAppointmentContextMenu": this._appointments.option("onItemContextMenu", this._createActionByOption(name)); this.appointmentTooltip._options.onItemContextMenu = this._createActionByOption(name); break; case "noDataText": case "allowMultipleCellSelection": case "selectedCellData": case "accessKey": case "onCellClick": case "onCellContextMenu": this.updateOption("workSpace", name, value); break; case "crossScrollingEnabled": this.postponeResourceLoading().done(() => { this._appointments.option("items", []); this.refreshWorkSpace(); if (this.readyToRenderAppointments) { this._appointments.option("items", this._layoutManager.generateViewModel()) } }); break; case "cellDuration": this.updateOption("workSpace", name, value); this._appointments.option("items", []); if (this.readyToRenderAppointments) { this.updateOption("workSpace", "hoursInterval", value / 60); this._appointments.option("items", this._layoutManager.generateViewModel()) } break; case "tabIndex": case "focusStateEnabled": this.updateOption("header", name, value); this.updateOption("workSpace", name, value); this._appointments.option(name, value); super._optionChanged(args); break; case "width": this.updateOption("header", name, value); if (this.option("crossScrollingEnabled")) { this.updateOption("workSpace", "width", value) } this.updateOption("workSpace", "schedulerWidth", value); super._optionChanged(args); this._dimensionChanged(null, true); break; case "height": super._optionChanged(args); this._dimensionChanged(null, true); this.updateOption("workSpace", "schedulerHeight", value); break; case "editing": { this.initEditing(); const { editing: editing } = this; this.bringEditingModeToAppointments(editing); this.hideAppointmentTooltip(); this.cleanPopup(); break } case "showAllDayPanel": this.updateAppointmentDataSource(); this.repaint(); break; case "showCurrentTimeIndicator": case "indicatorUpdateInterval": case "shadeUntilCurrentTime": case "groupByDate": this.updateOption("workSpace", name, value); this.repaint(); break; case "indicatorTime": this.updateOption("workSpace", name, value); this.updateOption("header", name, value); this.repaint(); break; case "appointmentDragging": case "appointmentTooltipTemplate": case "appointmentPopupTemplate": case "recurrenceEditMode": case "remoteFiltering": case "timeZone": this.updateAppointmentDataSource(); this.repaint(); break; case "appointmentCollectorTemplate": if (this.option("_newAppointments")) { this._appointments.option("appointmentCollectorTemplate", this.getViewOption("appointmentCollectorTemplate")) } else { this.repaint() } break; case "_appointmentTooltipOffset": this.repaint(); break; case "dateSerializationFormat": break; case "maxAppointmentsPerCell": this.repaint(); break; case "startDateExpr": case "endDateExpr": case "startDateTimeZoneExpr": case "endDateTimeZoneExpr": case "textExpr": case "descriptionExpr": case "allDayExpr": case "recurrenceRuleExpr": case "recurrenceExceptionExpr": case "disabledExpr": case "visibleExpr": this.updateExpression(name, value); this.initAppointmentTemplate(); this.repaint(); break; case "adaptivityEnabled": this.toggleAdaptiveClass(); this.repaint(); break; case "scrolling": this.option("crossScrollingEnabled", this.isHorizontalVirtualScrolling() || this.option("crossScrollingEnabled")); this.updateOption("workSpace", args.fullName, value); break; case "allDayPanelMode": this.updateAppointmentDataSource(); this.updateOption("workSpace", args.fullName, value); break; case "renovateRender": this.updateOption("workSpace", name, value); break; case "_draggingMode": this.updateOption("workSpace", "draggingMode", value); break; case "toolbar": this.header ? this.header.onToolbarOptionChanged(args.fullName, value) : this.repaint(); break; default: super._optionChanged(args) } } bringEditingModeToAppointments(editing) { const editingConfig = { allowDelete: editing.allowUpdating && editing.allowDeleting }; if (!this.isAgenda()) { editingConfig.allowDrag = editing.allowDragging; editingConfig.allowResize = editing.allowResizing; editingConfig.allowAllDayResize = editing.allowResizing && this.supportAllDayResizing() } this._appointments.option(editingConfig); this.repaint() } isAgenda() { return "agenda" === this.currentView.type } allowDragging() { return this.editing.allowDragging && !this.isAgenda() } allowResizing() { return this.editing.allowResizing && !this.isAgenda() } allowAllDayResizing() { return this.editing.allowResizing && this.supportAllDayResizing() } supportAllDayResizing() { return "day" !== this.currentView.type || this.currentView.intervalCount > 1 } isAllDayExpanded() { return this.option("showAllDayPanel") && this._layoutManager.hasAllDayAppointments() } setRemoteFilterIfNeeded() { const dataSource = this._dataSource; const remoteFiltering = this.option("remoteFiltering"); if (!this._workSpace || !remoteFiltering || !dataSource) { return } const dateRange = this._workSpace.getDateRange(); const startDate = this.timeZoneCalculator.createDate(dateRange[0], "fromGrid"); const endDate = this.timeZoneCalculator.createDate(dateRange[1], "fromGrid"); const dateSerializationFormat = this.option("dateSerializationFormat"); const dataSourceFilter = dataSource.filter(); const filter = combineRemoteFilter({ dataSourceFilter: dataSourceFilter, dataAccessors: this._dataAccessors, min: startDate, max: endDate, dateSerializationFormat: dateSerializationFormat, forceIsoDateParsing: config().forceIsoDateParsing }); dataSource.filter(filter) } reloadDataSource() { const result = new Deferred; if (this._dataSource) { this._dataSource.load().done(() => { hideLoading(); this._fireContentReadyAction(result) }).fail(() => { hideLoading(); result.reject() }); this._dataSource.isLoading() && showLoading({ container: this.$element(), position: { of: this.$element() } }) } else { this._fireContentReadyAction(result) } return result.promise() } _fireContentReadyAction(result) { const contentReadyBase = super._fireContentReadyAction.bind(this); const fireContentReady = () => { contentReadyBase(); null === result || void 0 === result || result.resolve() }; if (this.workSpaceRecalculation) { var _this$workSpaceRecalc; null === (_this$workSpaceRecalc = this.workSpaceRecalculation) || void 0 === _this$workSpaceRecalc || _this$workSpaceRecalc.done(() => { fireContentReady() }) } else { fireContentReady() } } _dimensionChanged(value) { let isForce = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : false; const isFixedHeight = "number" === typeof this.option("height"); const isFixedWidth = "number" === typeof this.option("width"); if (!this._isVisible()) { return } this.toggleSmallClass(); const workspace = this.getWorkSpace(); if (!this.isAgenda() && this._layoutManager && workspace && !isAgendaWorkspaceComponent(workspace)) { if (isForce || !isFixedHeight || !isFixedWidth) { workspace.option("allDayExpanded", this.isAllDayExpanded()); workspace._dimensionChanged(); const appointments = this._layoutManager.generateViewModel(); this._appointments.option("items", appointments) } } this.hideAppointmentTooltip(); this.appointmentPopup.triggerResize(); this.appointmentPopup.updatePopupFullScreenMode() } _clean() { this.cleanPopup(); super._clean() } toggleSmallClass() { const { width: width } = getBoundingRect(this.$element().get(0)); this.$element().toggleClass(WIDGET_SMALL_CLASS, width < 400) } toggleAdaptiveClass() { this.$element().toggleClass(WIDGET_ADAPTIVE_CLASS, this.option("adaptivityEnabled")) } _visibilityChanged(visible) { visible && this._dimensionChanged(null, true) } _dataSourceOptions() { return { paginate: false } } initAllDayPanel() { if ("hidden" === this.option("allDayPanelMode")) { this.option("showAllDayPanel", false) } } _init() { this.timeZonesPromise = timeZoneUtils.cacheTimeZones(); this.initExpressions({ startDateExpr: this.option("startDateExpr"), endDateExpr: this.option("endDateExpr"), startDateTimeZoneExpr: this.option("startDateTimeZoneExpr"), endDateTimeZoneExpr: this.option("endDateTimeZoneExpr"), allDayExpr: this.option("allDayExpr"), textExpr: this.option("textExpr"), descriptionExpr: this.option("descriptionExpr"), recurrenceRuleExpr: this.option("recurrenceRuleExpr"), recurrenceExceptionExpr: this.option("recurrenceExceptionExpr"), disabledExpr: this.option("disabledExpr"), visibleExpr: this.option("visibleExpr") }); super._init(); this.initAllDayPanel(); this._initDataSource(); this.customizeDataSourceLoadOptions(); this.$element().addClass(WIDGET_CLASS); this.initEditing(); this.updateAppointmentDataSource(); this.initActions(); this._compactAppointmentsHelper = new CompactAppointmentsHelper(this); this.asyncTemplatesTimers = []; this.dataSourceLoadedCallback = Callbacks(); this.subscribes = subscribes; this.resourceManager = new ResourceManager(this.option("resources")); this.notifyScheduler = new NotifyScheduler({ scheduler: this }); this.createAppointmentRenderedAction() } createAppointmentRenderedAction() { this.appointmentRenderedAction = this._createActionByOption("onAppointmentRendered") } createAppointmentDataSource() { var _this$appointmentData; null === (_this$appointmentData = this.appointmentDataSource) || void 0 === _this$appointmentData || _this$appointmentData.destroy(); this.appointmentDataSource = new AppointmentDataSource(this._dataSource) } updateAppointmentDataSource() { this.timeZoneCalculatorInstance = null; if (this.getWorkSpace()) { this.createAppointmentDataSource() } } customizeDataSourceLoadOptions() { var _this$_dataSource; null === (_this$_dataSource = this._dataSource) || void 0 === _this$_dataSource || _this$_dataSource.on("customizeStoreLoadOptions", _ref => { let { storeLoadOptions: storeLoadOptions } = _ref; storeLoadOptions.startDate = this.getStartViewDate(); storeLoadOptions.endDate = this.getEndViewDate() }) } _initTemplates() { this.initAppointmentTemplate(); this._templateManager.addDefaultTemplates({ appointmentTooltip: new EmptyTemplate, dropDownAppointment: new EmptyTemplate }); super._initTemplates() } initAppointmentTemplate() { const { expr: expr } = this._dataAccessors; const createGetter = property => compileGetter(`appointmentData.${property}`); const getDate = getter => data => { const value = getter(data); if (value instanceof Date) { return value.valueOf() } return value }; this._templateManager.addDefaultTemplates({ item: new BindableTemplate(($container, data, model) => this.getAppointmentsInstance()._renderAppointmentTemplate($container, data, model), ["html", "text", "startDate", "endDate", "allDay", "description", "recurrenceRule", "recurrenceException", "startDateTimeZone", "endDateTimeZone"], this.option("integrationOptions.watchMethod"), { text: createGetter(expr.textExpr), startDate: getDate(createGetter(expr.startDateExpr)), endDate: getDate(createGetter(expr.endDateExpr)), startDateTimeZone: createGetter(expr.startDateTimeZoneExpr), endDateTimeZone: createGetter(expr.endDateTimeZoneExpr), allDay: createGetter(expr.allDayExpr), recurrenceRule: createGetter(expr.recurrenceRuleExpr) }) }) } _renderContent() { this._renderContentImpl() } _dataSourceChangedHandler(result) { if (this.readyToRenderAppointments) { this.workSpaceRecalculation.done(() => { this._layoutManager.prepareAppointments(result); this.renderAppointments(); this.updateA11yStatus() }) } } isVirtualScrolling() { const workspace = this.getWorkSpace(); if (workspace) { return workspace.isVirtualScrolling() } const scrolling = this.getViewOption("scrolling"); return "virtual" === (null === scrolling || void 0 === scrolling ? void 0 : scrolling.mode) } renderAppointments() { const workspace = this.getWorkSpace(); this._layoutManager.filterAppointments(); workspace.option("allDayExpanded", this.isAllDayExpanded()); const viewModel = this._isVisible() ? this._layoutManager.generateViewModel() : []; this._appointments.option("items", viewModel); this.appointmentDataSource.cleanState(); if (this.isAgenda()) { this._workSpace.renderAgendaLayout(viewModel) } } initExpressions(fields) { this._dataAccessors = new AppointmentDataAccessor(fields, Boolean(config().forceIsoDateParsing), this.option("dateSerializationFormat")) } updateExpression(name, value) { this._dataAccessors.updateExpression(name, value) } initEditing() { const editing = this.option("editing"); this.editing = { allowAdding: Boolean(editing), allowUpdating: Boolean(editing), allowDeleting: Boolean(editing), allowResizing: Boolean(editing), allowDragging: Boolean(editing) }; if (isObject(editing)) { this.editing = extend(this.editing, editing) } this.editing.allowDragging = this.editing.allowDragging && this.editing.allowUpdating; this.editing.allowResizing = this.editing.allowResizing && this.editing.allowUpdating; const isReadOnly = Object.values(Object.assign({}, this.editing, { form: void 0, popup: void 0 })).every(value => !value); this.$element().toggleClass(WIDGET_READONLY_CLASS, isReadOnly) } _dispose() { var _this$resourceManager2, _this$appointmentTool, _this$recurrenceDialo; null === (_this$resourceManager2 = this.resourceManager) || void 0 === _this$resourceManager2 || _this$resourceManager2.dispose(); null === (_this$appointmentTool = this.appointmentTooltip) || void 0 === _this$appointmentTool || _this$appointmentTool.dispose(); null === (_this$recurrenceDialo = this.recurrenceDialog) || void 0 === _this$recurrenceDialo || _this$recurrenceDialo.hide(RECURRENCE_EDITING_MODE.CANCEL); this.hideAppointmentPopup(); this.hideAppointmentTooltip(); this.asyncTemplatesTimers.forEach(clearTimeout); this.asyncTemplatesTimers = []; macroTaskArray.dispose(); super._dispose() } initActions() { this.actions = { onAppointmentAdding: this._createActionByOption(StoreEventNames.ADDING), onAppointmentAdded: this._createActionByOption(StoreEventNames.ADDED), onAppointmentUpdating: this._createActionByOption(StoreEventNames.UPDATING), onAppointmentUpdated: this._createActionByOption(StoreEventNames.UPDATED), onAppointmentDeleting: this._createActionByOption(StoreEventNames.DELETING), onAppointmentDeleted: this._createActionByOption(StoreEventNames.DELETED), onAppointmentFormOpening: this._createActionByOption("onAppointmentFormOpening"), onAppointmentTooltipShowing: this._createActionByOption("onAppointmentTooltipShowing") } } getAppointmentRenderedAction() { return this._createActionByOption("onAppointmentRendered", { excludeValidators: ["disabled", "readOnly"] }) } _renderFocusTarget() { return noop() } updateA11yStatus() { const dateRange = this._workSpace.getDateRange(); const indicatorTime = this.option("showCurrentTimeIndicator") ? getToday(this.option("indicatorTime"), this.timeZoneCalculator) : void 0; const label = getA11yStatusText(this.currentView, dateRange[0], dateRange[1], this._layoutManager.filteredItems.length, indicatorTime); this.setAria({ label: label }); this.a11yStatus.text(label) } renderA11yStatus() { this.a11yStatus = createA11yStatusContainer(); this.a11yStatus.prependTo(this.$element()); this.setAria({ role: "group" }) } initMarkupOnResourceLoaded() { if (!this._disposed) { this.initMarkupCore(); this.reloadDataSource() } } _initMarkup() { super._initMarkup(); this.renderA11yStatus(); this.renderMainContainer(); this.renderHeader(); this.toggleAdaptiveClass(); this._layoutManager = new AppointmentLayoutManager(this); if (this.option("_newAppointments")) { const appointmentsConfig = { tabIndex: this.option("tabIndex"), currentView: this.option("currentView"), appointmentTemplate: this.getViewOption("appointmentTemplate"), appointmentCollectorTemplate: this.getViewOption("appointmentCollectorTemplate"), onAppointmentRendered: e => { this.appointmentRenderedAction({ appointmentElement: e.element, appointmentData: e.appointmentData, targetedAppointmentData: e.targetedAppointmentData }) }, getResourceManager: () => this.resourceManager, getAppointmentDataSource: () => this.appointmentDataSource, getDataAccessor: () => this._dataAccessors, getStartViewDate: () => this.getStartViewDate(), getSortedAppointments: () => this._layoutManager.sortedItems, isVirtualScrolling: () => this.isVirtualScrolling(), scrollTo: this.scrollTo.bind(this) }; this._appointments = this._createComponent("<div>", Appointments, appointmentsConfig) } else { this._appointments = this._createComponent("<div>", AppointmentCollection, this.appointmentsConfig()); this._appointments.option("itemTemplate", this.getAppointmentTemplate("appointmentTemplate")) } this.appointmentTooltip = new(this.option("adaptivityEnabled") ? MobileTooltipStrategy : DesktopTooltipStrategy)(this.getAppointmentTooltipOptions()); this.createAppointmentPopupForm(); if (this.isDataSourceLoaded() || this._isDataSourceLoading()) { this.initMarkupCore(); this._dataSourceChangedHandler(this._dataSource.items()); this._fireContentReadyAction() } else { const groups = this.getViewOption("groups"); if (null !== groups && void 0 !== groups && groups.length) { this.resourceManager.loadGroupResources(groups, true).then(() => this.initMarkupOnResourceLoaded()) } else { this.initMarkupOnResourceLoaded() } } } createAppointmentPopupForm() { var _this$appointmentPopu; if (this.appointmentForm) { this.appointmentForm.dispose() } this.appointmentForm = this.createAppointmentForm(); null === (_this$appointmentPopu = this.appointmentPopup) || void 0 === _this$appointmentPopu || _this$appointmentPopu.dispose(); this.appointmentPopup = this.createAppointmentPopup(this.appointmentForm) } renderMainContainer() { this.mainContainer = $("<div>").addClass("dx-scheduler-container"); this.$element().append(this.mainContainer) } createAppointmentForm() { const scheduler = { getResourceById: () => this.resourceManager.resourceById, getDataAccessors: () => this._dataAccessors, createComponent: (element, component, options) => this._createComponent(element, component, options), getEditingConfig: () => this.editing, getResourceManager: () => this.resourceManager, getFirstDayOfWeek: () => this.option("firstDayOfWeek"), getStartDayHour: () => this.option("startDayHour"), getCalculatedEndDate: startDateWithStartHour => this._workSpace.calculateEndDate(startDateWithStartHour), getTimeZoneCalculator: () => this.timeZoneCalculator }; return new AppointmentForm(scheduler) } createAppointmentPopup(form) { const scheduler = { getElement: () => this.$element(), createComponent: (element, component, options) => this._createComponent(element, component, options), focus: () => this.focus(), getResourceManager: () => this.resourceManager, getEditingConfig: () => this.editing, getTimeZoneCalculator: () => this.timeZoneCalculator, getDataAccessors: () => this._dataAccessors, getAppointmentFormOpening: () => this.actions.onAppointmentFormOpening, processActionResult: (arg, canceled) => this.processActionResult(arg, canceled), addAppointment: appointment => this.addAppointment(appointment), updateAppointment: (sourceAppointment, updatedAppointment) => this.updateAppointment(sourceAppointment, updatedAppointment) }; return new AppointmentPopup(scheduler, form) } scrollToAppointment(appointment) { const adapter = new AppointmentAdapter(appointment, this._dataAccessors); const { startDate: startDate, endDate: endDate, allDay: allDay } = adapter; if (!startDate) { return } const startTime = startDate.getTime(); const endTime = endDate ? endDate.getTime() : startTime; const dayInMs = toMs("day"); const inAllDayRow = allDay || endTime - startTime >= dayInMs; const appointmentGroupValues = getAppointmentGroupValues(appointment, this.resourceManager.resources); this._workSpace.updateScrollPosition(startDate, appointmentGroupValues, inAllDayRow) } getAppointmentTooltipOptions() { return { createComponent: this._createComponent.bind(this), container: this.$element(), getScrollableContainer: this.getWorkSpaceScrollableContainer.bind(this), addDefaultTemplates: this._templateManager.addDefaultTemplates.bind(this._templateManager), getAppointmentTemplate: this.getAppointmentTemplate.bind(this), showAppointmentPopup: this.showAppointmentPopup.bind(this), checkAndDeleteAppointment: this.checkAndDeleteAppointment.bind(this), isAppointmentInAllDayPanel: this.isAppointmentInAllDayPanel.bind(this), createFormattedDateText: (appointment, targetedAppointment, format) => this.fire("createFormattedDateText", appointment, targetedAppointment, format), getAppointmentDisabled: appointment => this._dataAccessors.get("disabled", appointment), onItemContextMenu: this._createActionByOption("onAppointmentContextMenu"), createEventArgs: this._createEventArgs.bind(this) } } _createEventArgs(e) { const config = { itemData: e.itemData.appointment, itemElement: e.itemElement, targetedAppointment: e.itemData.targetedAppointment }; return extend({}, this.fire("mapAppointmentFields", config), { component: e.component, element: e.element, event: e.event, model: e.model }) } checkAndDeleteAppointment(appointment, targetedAppointment) { const targetedAdapter = new AppointmentAdapter(targetedAppointment, this._dataAccessors); const deletingOptions = this.fireOnAppointmentDeleting(appointment, targetedAdapter); this.checkRecurringAppointment(appointment, targetedAppointment, targetedAdapter.startDate, () => { this.processDeleteAppointment(appointment, deletingOptions) }, true) } getExtraAppointmentTooltipOptions() { return { rtlEnabled: this.option("rtlEnabled"), focusStateEnabled: this.option("focusStateEnabled"), editing: this.option("editing"), offset: this.option("_appointmentTooltipOffset") } } isAppointmentInAllDayPanel(appointmentData) { const workSpace = this._workSpace; const itTakesAllDay = this.appointmentTakesAllDay(appointmentData); return itTakesAllDay && workSpace.supportAllDayRow() && workSpace.option("showAllDayPanel") } initMarkupCore() { this.readyToRenderAppointments = hasWindow(); this._workSpace && this.cleanWorkSpace(); this.renderWorkSpace(); if (this.option("_newAppointments")) { this._appointments.option("$allDayContainer", this._workSpace.getAllDayContainer()) } else { this._appointments.option({ fixedContainer: this._workSpace.getFixedContainer(), allDayContainer: this._workSpace.getAllDayContainer() }) } this.waitAsyncTemplate(() => { var _this$workSpaceRecalc2; return null === (_this$workSpaceRecalc2 = this.workSpaceRecalculation) || void 0 === _this$workSpaceRecalc2 ? void 0 : _this$workSpaceRecalc2.resolve() }); this.createAppointmentDataSource(); this.setRemoteFilterIfNeeded(); this.validateKeyFieldIfAgendaExist(); this.updateA11yStatus() } isDataSourceLoaded() { var _this$_dataSource2; return null === (_this$_dataSource2 = this._dataSource) || void 0 === _this$_dataSource2 ? void 0 : _this$_dataSource2.isLoaded() } _render() { var _this$getWorkSpace; null === (_this$getWorkSpace = this.getWorkSpace()) || void 0 === _this$getWorkSpace || _this$getWorkSpace.updateHeaderEmptyCellWidth(); super._render() } renderHeader() { var _toolbarOptions$items; const toolbarOptions = this.option("toolbar"); const isHeaderShown = Boolean(toolbarOptions.visible ?? (null === (_toolbarOptions$items = toolbarOptions.items) || void 0 === _toolbarOptions$items ? void 0 : _toolbarOptions$items.length)); if (isHeaderShown) { const $header = $("<div>").appendTo(this.mainContainer); const headerOptions = this.headerConfig(); this.header = this._createComponent($header, SchedulerHeader, headerOptions) } } headerConfig() { return { currentView: this.currentView, views: this.views, currentDate: this.getViewOption("currentDate"), min: this.getViewOption("min"), max: this.getViewOption("max"), indicatorTime: this.option("indicatorTime"), startViewDate: this.getStartViewDate(), tabIndex: this.option("tabIndex"), focusStateEnabled: this.option("focusStateEnabled"), useDropDownViewSwitcher: this.option("useDropDownViewSwitcher"), firstDayOfWeek: this.getFirstDayOfWeek(), toolbar: this.option("toolbar"), customizeDateNavigatorText: this.option("customizeDateNavigatorText"), onCurrentViewChange: name => { this.option("currentView", name) }, onCurrentDateChange: date => { this.option("currentDate", date) } } } appointmentsConfig() { const config = { getResourceManager: () => this.resourceManager, getAppointmentDataSource: () => this.appointmentDataSource, getSortedAppointments: () => this._layoutManager.sortedItems, scrollTo: this.scrollTo.bind(this), dataAccessors: this._dataAccessors, notifyScheduler: this.notifyScheduler, onItemRendered: this.getAppointmentRenderedAction(), onItemClick: this._createActionByOption("onAppointmentClick"), onItemContextMenu: this._createActionByOption("onAppointmentContextMenu"), onAppointmentDblClick: this._createActionByOption("onAppointmentDblClick"), tabIndex: this.option("tabIndex"), focusStateEnabled: this.option("focusStateEnabled"), allowDrag: this.allowDragging(), allowDelete: this.editing.allowUpdating && this.editing.allowDeleting, allowResize: this.allowResizing(), allowAllDayResize: this.allowAllDayResizing(), rtlEnabled: this.option("rtlEnabled"), groups: this.getViewOption("groups"), groupByDate: this.getViewOption("groupByDate"), timeZoneCalculator: this.timeZoneCalculator, getResizableStep: () => this._workSpace ? this._workSpace.positionHelper.getResizableStep() : 0, getDOMElementsMetaData: () => { var _this$_workSpace; return null === (_this$_workSpace = this._workSpace) || void 0 === _this$_workSpace ? void 0 : _this$_workSpace.getDOMElementsMetaData() }, getViewDataProvider: () => { var _this$_workSpace2; return null === (_this$_workSpace2 = this._workSpace) || void 0 === _this$_workSpace2 ? void 0 : _this$_workSpace2.viewDataProvider }, isVerticalGroupedWorkSpace: () => this._workSpace.isVerticalGroupedWorkSpace(), isDateAndTimeView: () => isDateAndTimeView(this._workSpace.type), onContentReady: () => { var _this$_workSpace3; null === (_this$_workSpace3 = this._workSpace) || void 0 === _this$_workSpace3 || _this$_workSpace3.option("allDayExpanded", this.isAllDayExpanded()) } }; return config } renderWorkSpace() { const currentViewOptions = this.currentView; if (!currentViewOptions) { return } if (this.isAgenda()) { this.renderAgendaWorkspace() } else { this.renderGridWorkspace() } this.recalculateWorkspace(); if (currentViewOptions.startDate) { this.updateOption("header", "currentDate", this._workSpace.getHeaderDate()) } } renderGridWorkspace() { if (this.readyToRenderAppointments) { this.toggleSmallClass(); Promise.resolve().then(() => { var _this$_workSpace4; this.toggleSmallClass(); null === (_this$_workSpace4 = this._workSpace) || void 0 === _this$_workSpace4 || _this$_w