diff --git a/e2e/testcafe-devextreme/helpers/domUtils.ts b/e2e/testcafe-devextreme/helpers/domUtils.ts index 085e8c0b183e..1c0b4f9570c7 100644 --- a/e2e/testcafe-devextreme/helpers/domUtils.ts +++ b/e2e/testcafe-devextreme/helpers/domUtils.ts @@ -137,8 +137,8 @@ export const addFocusableElementBefore = ClientFunction(( return button.id; }); -export const hasHorizontalScroll = async (container: Selector): Promise => { - const scrollWidth = await container.scrollWidth; - const clientWidth = await container.clientWidth; - return scrollWidth > clientWidth; -}; +export const hasHorizontalScroll = ClientFunction((selector) => { + const element = selector(); + + return element.scrollWidth > element.clientWidth; +}); diff --git a/packages/devextreme/js/__internal/scheduler/__tests__/__mock__/mock_scheduler.ts b/packages/devextreme/js/__internal/scheduler/__tests__/__mock__/mock_scheduler.ts index fed1a99c3eb8..eef2332334a9 100644 --- a/packages/devextreme/js/__internal/scheduler/__tests__/__mock__/mock_scheduler.ts +++ b/packages/devextreme/js/__internal/scheduler/__tests__/__mock__/mock_scheduler.ts @@ -2,7 +2,7 @@ import { jest } from '@jest/globals'; import { logger } from '@ts/core/utils/m_console'; import DOMComponent from '@ts/core/widget/dom_component'; -import SchedulerWorkSpace from '../../workspaces/m_work_space'; +import SchedulerWorkSpace from '../../workspaces/work_space'; type ClassRects = Record>; diff --git a/packages/devextreme/js/__internal/scheduler/__tests__/workspace.base.test.ts b/packages/devextreme/js/__internal/scheduler/__tests__/workspace.base.test.ts index 6d4b97c3aadd..6b4b519ae3d7 100644 --- a/packages/devextreme/js/__internal/scheduler/__tests__/workspace.base.test.ts +++ b/packages/devextreme/js/__internal/scheduler/__tests__/workspace.base.test.ts @@ -4,10 +4,10 @@ import { import { logger } from '@ts/core/utils/m_console'; import { getResourceManagerMock } from '../__mock__/resource_manager.mock'; -import type SchedulerWorkSpace from '../workspaces/m_work_space'; import SchedulerTimelineDay from '../workspaces/timeline_day'; import SchedulerTimelineMonth from '../workspaces/timeline_month'; import SchedulerTimelineWeek from '../workspaces/timeline_week'; +import type SchedulerWorkSpace from '../workspaces/work_space'; import SchedulerWorkSpaceDay from '../workspaces/work_space_day'; import SchedulerWorkSpaceMonth from '../workspaces/work_space_month'; import SchedulerWorkSpaceWeek from '../workspaces/work_space_week'; diff --git a/packages/devextreme/js/__internal/scheduler/m_scheduler.ts b/packages/devextreme/js/__internal/scheduler/m_scheduler.ts index 9f6c5c7d607c..5a02a006afb0 100644 --- a/packages/devextreme/js/__internal/scheduler/m_scheduler.ts +++ b/packages/devextreme/js/__internal/scheduler/m_scheduler.ts @@ -171,12 +171,12 @@ class Scheduler extends SchedulerOptionsBaseWidget { private a11yStatus!: dxElementWrapper; - // TODO: used externally in m_appointment_drag_behavior.ts, m_subscribes.ts, workspaces/m_work_space.ts + // TODO: used externally in m_appointment_drag_behavior.ts, m_subscribes.ts, workspaces/work_space.ts _workSpace: any; private header?: SchedulerHeader; - // TODO: used externally in m_appointment_drag_behavior.ts, m_subscribes.ts, workspaces/m_work_space.ts + // TODO: used externally in m_appointment_drag_behavior.ts, m_subscribes.ts, workspaces/work_space.ts _appointments: any; private appointmentDragController!: AppointmentDragController; diff --git a/packages/devextreme/js/__internal/scheduler/shaders/current_time_shader_horizontal.ts b/packages/devextreme/js/__internal/scheduler/shaders/current_time_shader_horizontal.ts index 8ce46e773efe..0c69830b30c9 100644 --- a/packages/devextreme/js/__internal/scheduler/shaders/current_time_shader_horizontal.ts +++ b/packages/devextreme/js/__internal/scheduler/shaders/current_time_shader_horizontal.ts @@ -2,7 +2,7 @@ import type { dxElementWrapper } from '@js/core/renderer'; import { getBoundingRect } from '@js/core/utils/position'; import { setWidth } from '@js/core/utils/size'; -import type SchedulerWorkSpace from '../workspaces/m_work_space'; +import type SchedulerWorkSpace from '../workspaces/work_space'; import CurrentTimeShader from './current_time_shader'; class HorizontalCurrentTimeShader extends CurrentTimeShader { diff --git a/packages/devextreme/js/__internal/scheduler/shaders/current_time_shader_vertical.ts b/packages/devextreme/js/__internal/scheduler/shaders/current_time_shader_vertical.ts index 18a62a49d5f1..f32ec8b2f58f 100644 --- a/packages/devextreme/js/__internal/scheduler/shaders/current_time_shader_vertical.ts +++ b/packages/devextreme/js/__internal/scheduler/shaders/current_time_shader_vertical.ts @@ -1,7 +1,7 @@ import $, { type dxElementWrapper } from '@js/core/renderer'; import { setHeight, setWidth } from '@js/core/utils/size'; -import type SchedulerWorkSpace from '../workspaces/m_work_space'; +import type SchedulerWorkSpace from '../workspaces/work_space'; import CurrentTimeShader from './current_time_shader'; const DATE_TIME_SHADER_ALL_DAY_CLASS = 'dx-scheduler-date-time-shader-all-day'; @@ -141,23 +141,23 @@ class VerticalCurrentTimeShader extends CurrentTimeShader { } private getShaderOffset(i: number, width: number): number { - return this.workSpace.getGroupedStrategy().getShaderOffset(i, width) as number; + return this.workSpace.getGroupedStrategy().getShaderOffset(i, width); } private getShaderTopOffset(i: number): number { - return this.workSpace.getGroupedStrategy().getShaderTopOffset(i) as number; + return this.workSpace.getGroupedStrategy().getShaderTopOffset(i); } private getShaderHeight(): number { - return this.workSpace.getGroupedStrategy().getShaderHeight() as number; + return this.workSpace.getGroupedStrategy().getShaderHeight(); } private getShaderMaxHeight(): number { - return this.workSpace.getGroupedStrategy().getShaderMaxHeight() as number; + return this.workSpace.getGroupedStrategy().getShaderMaxHeight(); } private getShaderWidth(): number { - return this.workSpace.getGroupedStrategy().getShaderWidth() as number; + return this.workSpace.getGroupedStrategy().getShaderWidth(); } clean(): void { diff --git a/packages/devextreme/js/__internal/scheduler/utils.ts b/packages/devextreme/js/__internal/scheduler/utils.ts index 65dfddc1be7d..f330c8aef070 100644 --- a/packages/devextreme/js/__internal/scheduler/utils.ts +++ b/packages/devextreme/js/__internal/scheduler/utils.ts @@ -6,9 +6,10 @@ import { getOuterHeight, setHeight, setWidth } from '@js/core/utils/size'; import { APPOINTMENT_SETTINGS_KEY } from './constants'; import type { AppointmentViewModelPlain } from './view_model/types'; -interface RenovationWidget { +export interface RenovationWidget { $element: () => dxElementWrapper; option: (options: Record) => void; + dispose: () => void; } type CreateComponentFn = ( diff --git a/packages/devextreme/js/__internal/scheduler/workspaces/agenda.ts b/packages/devextreme/js/__internal/scheduler/workspaces/agenda.ts index 002c6d6ca92c..b007f58caa95 100644 --- a/packages/devextreme/js/__internal/scheduler/workspaces/agenda.ts +++ b/packages/devextreme/js/__internal/scheduler/workspaces/agenda.ts @@ -28,7 +28,7 @@ import { VIEWS } from '../utils/options/constants_view'; import { reduceResourcesTree } from '../utils/resource_manager/agenda_group_utils'; import type { GroupNode } from '../utils/resource_manager/types'; import type { ListEntity } from '../view_model/types'; -import WorkSpace, { type WorkspaceOptionsInternal } from './m_work_space'; +import WorkSpace, { type WorkspaceOptionsInternal } from './work_space'; const { tableCreator } = tableCreatorModule; @@ -136,7 +136,7 @@ class SchedulerAgenda extends WorkSpace { } protected override getRowCount(): number { - return this.option('agendaDuration'); + return this.option().agendaDuration; } getCellCount(): number { @@ -144,7 +144,7 @@ class SchedulerAgenda extends WorkSpace { } protected override getTimePanelRowCount(): number { - return this.option('agendaDuration'); + return this.option().agendaDuration; } protected renderAllDayPanel(): void { return noop(); } @@ -160,7 +160,7 @@ class SchedulerAgenda extends WorkSpace { } private initGroupTable(): void { - const groups = this.option('groups'); + const { groups } = this.option(); if (groups?.length) { this.$groupTable = $('').attr('aria-hidden', true).addClass(GROUP_TABLE_CLASS); } @@ -168,8 +168,8 @@ class SchedulerAgenda extends WorkSpace { protected override renderView(): void { this.startViewDate = agendaUtils.calculateStartViewDate( - this.option('currentDate'), - this.option('startDayHour'), + this.option().currentDate, + this.option().startDayHour, ); this.rows = []; } @@ -197,7 +197,7 @@ class SchedulerAgenda extends WorkSpace { private renderNoData(): void { this.$noDataContainer = $('
').addClass(NODATA_CONTAINER_CLASS) - .html(this.option('noDataText')); + .html(this.option().noDataText); this.$dateTableScrollable.$content().append(this.$noDataContainer); } @@ -211,7 +211,9 @@ class SchedulerAgenda extends WorkSpace { } private setGroupHeaderCellsHeight(): void { - const $cells = this.getGroupHeaderCells().filter((_, element) => !element.getAttribute('rowSpan')); + const $cells = $( + this.getGroupHeaderCells().toArray().filter((element) => !element.getAttribute('rowSpan')), + ); const rows = this.removeEmptyRows(this.rows); if (!rows.length) { @@ -229,7 +231,7 @@ class SchedulerAgenda extends WorkSpace { } protected override attachGroupCountClass(): void { - const className = getVerticalGroupCountClass(this.option('groups')); + const className = getVerticalGroupCountClass(this.option().groups); if (className) { this.$element().addClass(className); } @@ -245,8 +247,8 @@ class SchedulerAgenda extends WorkSpace { } protected override makeGroupRows(): GroupRows { - const resourceManager = this.option('getResourceManager')(); - const allAppointments = (this.option('getFilteredItems') as () => ListEntity[])(); + const resourceManager = this.option().getResourceManager(); + const allAppointments = this.option().getFilteredItems(); const tree = reduceResourcesTree( resourceManager.resourceById, resourceManager.groupsTree, @@ -277,7 +279,9 @@ class SchedulerAgenda extends WorkSpace { const resourceItem = resource?.items .find((rItem) => rItem.id === value); + // @ts-expect-error if (cellTemplate?.render) { + // @ts-expect-error cellTemplates.push(cellTemplate.render.bind(cellTemplate, { model: { data: resourceData, @@ -332,7 +336,7 @@ class SchedulerAgenda extends WorkSpace { this.$dateTableScrollableContent.prepend(this.$groupTable); } - this.$dateTableScrollableContent.append(this.$timePanel, this.$dateTableContainer); + this.$dateTableScrollableContent.append([this.$timePanel, this.$dateTableContainer]); this.$element().append(this.$dateTableScrollable.$element()); } @@ -458,7 +462,7 @@ class SchedulerAgenda extends WorkSpace { cellCount: 1, rowClass: TIME_PANEL_ROW_CLASS, cellClass: TIME_PANEL_CELL_CLASS, - cellTemplate: this.option('dateCellTemplate'), + cellTemplate: this.option().dateCellTemplate, getStartDate: this.getTimePanelStartDate.bind(this), }); } @@ -471,7 +475,7 @@ class SchedulerAgenda extends WorkSpace { } private getRowHeight(rowSize: number): number { - const baseHeight = this.option('rowHeight'); + const baseHeight = this.option().rowHeight; const innerOffset = (rowSize - 1) * INNER_CELL_MARGIN; return rowSize ? (baseHeight * rowSize) + innerOffset + OUTER_CELL_MARGIN : 0; @@ -490,7 +494,7 @@ class SchedulerAgenda extends WorkSpace { const rows = agendaUtils.calculateRows( appointments, - this.option('agendaDuration'), + this.option().agendaDuration, this.getStartViewDate(), this.resourceManager.groupCount(), ); @@ -498,14 +502,14 @@ class SchedulerAgenda extends WorkSpace { } getAgendaVerticalStepHeight(): number { - return this.option('rowHeight'); + return this.option().rowHeight; } getEndViewDate(): Date { return agendaUtils.calculateEndViewDate( this.getStartViewDate(), - this.option('endDayHour'), - this.option('agendaDuration'), + this.option().endDayHour, + this.option().agendaDuration, ); } @@ -514,7 +518,7 @@ class SchedulerAgenda extends WorkSpace { } updateScrollPosition(date: Date): void { - const newDate = this.timeZoneCalculator.createDate(date, 'toGrid'); + const newDate = this.timeZoneCalculator?.createDate(date, 'toGrid') ?? date; if (this.needUpdateScrollPosition(newDate)) { this.scrollTo(newDate); @@ -547,7 +551,7 @@ class SchedulerAgenda extends WorkSpace { override isVirtualScrolling(): boolean { return false; } protected override getTotalViewDuration(): number { - return dateUtils.dateToMilliseconds('day') * this.option('intervalCount'); + return dateUtils.dateToMilliseconds('day') * this.option().intervalCount; } getDOMElementsMetaData(): { diff --git a/packages/devextreme/js/__internal/scheduler/workspaces/timeline.ts b/packages/devextreme/js/__internal/scheduler/workspaces/timeline.ts index 98710b1d3f64..bf52d84ecc0f 100644 --- a/packages/devextreme/js/__internal/scheduler/workspaces/timeline.ts +++ b/packages/devextreme/js/__internal/scheduler/workspaces/timeline.ts @@ -21,8 +21,8 @@ import tableCreatorModule, { type GroupRows } from '../table_creator'; import type { ResourceLoader } from '../utils/loader/resource_loader'; import { getFirstVisibleDate } from '../utils/skipped_days'; import timezoneUtils from '../utils_time_zone'; -import type { WorkspaceOptionsInternal } from './m_work_space'; import type { ViewDataProviderOptions } from './view_model/types'; +import type { WorkspaceOptionsInternal } from './work_space'; import SchedulerWorkSpace from './work_space_indicator'; const { tableCreator } = tableCreatorModule; @@ -104,7 +104,7 @@ class SchedulerTimeline extends SchedulerWorkSpace { protected override getGroupHeaderContainer(): dxElementWrapper { if (this.isHorizontalGroupedWorkSpace()) { - return this.$thead as dxElementWrapper; + return this.$thead; } return this.$sidebarTable; } @@ -118,7 +118,7 @@ class SchedulerTimeline extends SchedulerWorkSpace { } protected incrementDate(date: Date): void { - const skippedDays = this.option('skippedDays') ?? []; + const skippedDays = this.option().skippedDays ?? []; const nextDate = new Date(date); nextDate.setDate(nextDate.getDate() + 1); @@ -161,9 +161,9 @@ class SchedulerTimeline extends SchedulerWorkSpace { this.getIndicationFirstViewDate(), differenceInDays, ); - let duration = (timeDiff - differenceInDays * toMs('day') - this.option('startDayHour') * toMs('hour')) / this.getCellDuration(); + let duration = (timeDiff - differenceInDays * toMs('day') - this.option().startDayHour * toMs('hour')) / this.getCellDuration(); - if (today.getHours() > this.option('endDayHour')) { + if (today.getHours() > this.option().endDayHour) { duration = this.getCellCountInDay(); } @@ -227,13 +227,13 @@ class SchedulerTimeline extends SchedulerWorkSpace { cellCoordinates: { rowIndex: number; columnIndex: number }, groupIndex: number, ): dxElementWrapper { - const indexes = this.groupedStrategy.prepareCellIndexes(cellCoordinates, groupIndex); + const indexes = this.groupedStrategy.prepareCellIndexes(cellCoordinates, groupIndex, false); return this.$dateTable .find('tr') .eq(indexes.rowIndex) .find('td') - .eq(indexes.columnIndex) as dxElementWrapper; + .eq(indexes.columnIndex); } protected override getWorkSpaceWidth(): number { @@ -245,8 +245,7 @@ class SchedulerTimeline extends SchedulerWorkSpace { } protected override getIntervalBetween(currentDate: Date, allDay?: boolean): number { - const startDayHour = this.option('startDayHour'); - const endDayHour = this.option('endDayHour'); + const { startDayHour, endDayHour } = this.option(); const firstViewDate = this.getStartViewDate(); const firstViewDateTime = firstViewDate.getTime(); const hiddenInterval = (24 - endDayHour + startDayHour) * toMs('hour'); @@ -259,7 +258,7 @@ class SchedulerTimeline extends SchedulerWorkSpace { const skippedDaysCount = this.getSkippedDaysCount(firstViewDate, fullDays); const cellCount = this.getCellCountInDay() * (fullDays - skippedDaysCount); const gapBeforeAppt = apptStart - dateUtils.trimTime(new Date(currentDate)).getTime(); - let result = cellCount * this.option('hoursInterval') * toMs('hour'); + let result = cellCount * this.option().hoursInterval * toMs('hour'); if (!allDay) { const hour = currentDate.getHours(); @@ -358,7 +357,7 @@ class SchedulerTimeline extends SchedulerWorkSpace { protected override updateAllDayVisibility(): void { return noop(); } protected override getDateHeaderTemplate(): TemplateBase | null | undefined { - return this.option('timeCellTemplate'); + return this.option().timeCellTemplate; } protected override renderView(): void { @@ -411,7 +410,7 @@ class SchedulerTimeline extends SchedulerWorkSpace { let $indicator: dxElementWrapper | undefined; const width = this.getIndicationWidth(); - if (this.option('groupOrientation') === 'vertical') { + if (this.option().groupOrientation === 'vertical') { $indicator = this.createIndicator($container); setHeight($indicator, getBoundingRect($container.get(0)).height); $indicator.css('left', rtlOffset ? rtlOffset - width : width); @@ -431,7 +430,7 @@ class SchedulerTimeline extends SchedulerWorkSpace { groups: ResourceLoader[], groupByDate: boolean, ): GroupRows { - const tableCreatorStrategy = this.option('groupOrientation') === 'vertical' ? tableCreator.VERTICAL : tableCreator.HORIZONTAL; + const tableCreatorStrategy = this.option().groupOrientation === 'vertical' ? tableCreator.VERTICAL : tableCreator.HORIZONTAL; return tableCreator.makeGroupedTable( tableCreatorStrategy, @@ -443,7 +442,7 @@ class SchedulerTimeline extends SchedulerWorkSpace { groupHeaderContentClass: GROUP_HEADER_CONTENT_CLASS, }, this.getCellCount() || 1, - this.option('resourceCellTemplate'), + this.option().resourceCellTemplate, this.getTotalRowCount(this.getGroupCount()), groupByDate, ); diff --git a/packages/devextreme/js/__internal/scheduler/workspaces/timeline_month.ts b/packages/devextreme/js/__internal/scheduler/workspaces/timeline_month.ts index 20bdccdc8bbc..af80e5f18990 100644 --- a/packages/devextreme/js/__internal/scheduler/workspaces/timeline_month.ts +++ b/packages/devextreme/js/__internal/scheduler/workspaces/timeline_month.ts @@ -29,7 +29,7 @@ class SchedulerTimelineMonth extends SchedulerTimeline { } protected override getDateHeaderTemplate(): TemplateBase | null | undefined { - return this.option('dateCellTemplate'); + return this.option().dateCellTemplate; } protected override calculateDurationInCells(timeDiff: number): number { @@ -47,7 +47,7 @@ class SchedulerTimelineMonth extends SchedulerTimeline { protected override getIntervalBetween(currentDate: Date): number { const firstViewDate = this.getStartViewDate(); const timeZoneOffset = dateUtils.getTimezonesDifference(firstViewDate, currentDate); - const startDayHour = this.option('startDayHour'); + const { startDayHour } = this.option(); return currentDate.getTime() - (firstViewDate.getTime() - startDayHour * 3600000) @@ -55,14 +55,14 @@ class SchedulerTimelineMonth extends SchedulerTimeline { } protected override getViewStartByOptions(): Date { - const currentDate: Date = this.option('currentDate') ?? new Date(); - const startDate: Date = this.option('startDate') ?? currentDate; + const currentDate: Date = this.option().currentDate ?? new Date(); + const startDate: Date = this.option().startDate ?? currentDate; const firstMonthDate = dateUtils.getFirstMonthDate(startDate) ?? startDate; return monthUtils.getViewStartByOptions( startDate, currentDate, - this.option('intervalCount'), + this.option().intervalCount, firstMonthDate, ); } diff --git a/packages/devextreme/js/__internal/scheduler/workspaces/timeline_week.ts b/packages/devextreme/js/__internal/scheduler/workspaces/timeline_week.ts index 00fe6f796d92..eb040a3e223b 100644 --- a/packages/devextreme/js/__internal/scheduler/workspaces/timeline_week.ts +++ b/packages/devextreme/js/__internal/scheduler/workspaces/timeline_week.ts @@ -9,7 +9,7 @@ const TIMELINE_WORK_WEEK_CLASS = 'dx-scheduler-timeline-work-week'; export default class SchedulerTimelineWeek extends SchedulerTimeline { get type(): ViewType { - return this.option('type') ?? VIEWS.TIMELINE_WEEK; + return this.option().type ?? VIEWS.TIMELINE_WEEK; } protected override getElementClass(): string { diff --git a/packages/devextreme/js/__internal/scheduler/workspaces/view_model/types.ts b/packages/devextreme/js/__internal/scheduler/workspaces/view_model/types.ts index e6be7f254c6e..7d11791d92ef 100644 --- a/packages/devextreme/js/__internal/scheduler/workspaces/view_model/types.ts +++ b/packages/devextreme/js/__internal/scheduler/workspaces/view_model/types.ts @@ -21,7 +21,7 @@ interface CommonOptions extends CountGenerationConfig { viewType: ViewType; startDate?: Date; skippedDays?: number[]; - cellCount: number; + cellCount?: number; isProvideVirtualCellsWidth: boolean; isGenerateTimePanelData?: boolean; isGenerateWeekDaysHeaderData?: boolean; diff --git a/packages/devextreme/js/__internal/scheduler/workspaces/virtual_scrolling.ts b/packages/devextreme/js/__internal/scheduler/workspaces/virtual_scrolling.ts index 7e6bfc895432..485d506496e5 100644 --- a/packages/devextreme/js/__internal/scheduler/workspaces/virtual_scrolling.ts +++ b/packages/devextreme/js/__internal/scheduler/workspaces/virtual_scrolling.ts @@ -8,7 +8,7 @@ import { getWindow } from '@js/core/utils/window'; import type { ScrollOffset } from '@ts/core/utils/scroll'; import type { CellPositionData, ViewCellData } from '../types'; -import type SchedulerWorkSpace from './m_work_space'; +import type SchedulerWorkSpace from './work_space'; const DEFAULT_CELL_HEIGHT = 50; const MIN_CELL_WIDTH = 1; @@ -805,7 +805,7 @@ export class VirtualScrollingRenderer { this.renderAppointments(); } - // TODO: make private once external usage in m_work_space.ts is removed + // TODO: make private once external usage in work_space.ts is removed _renderGrid(): void { this.workspace.renderWorkSpace({ generateNewData: false, diff --git a/packages/devextreme/js/__internal/scheduler/workspaces/m_work_space.ts b/packages/devextreme/js/__internal/scheduler/workspaces/work_space.ts similarity index 61% rename from packages/devextreme/js/__internal/scheduler/workspaces/m_work_space.ts rename to packages/devextreme/js/__internal/scheduler/workspaces/work_space.ts index 247c2c94862d..a0799c73adcc 100644 --- a/packages/devextreme/js/__internal/scheduler/workspaces/m_work_space.ts +++ b/packages/devextreme/js/__internal/scheduler/workspaces/work_space.ts @@ -12,7 +12,7 @@ import pointerEvents from '@js/common/core/events/pointer'; import { addNamespace, isMouseEvent } from '@js/common/core/events/utils/index'; import domAdapter from '@js/core/dom_adapter'; import { getPublicElement } from '@js/core/element'; -import type { dxElementWrapper } from '@js/core/renderer'; +import type { Coordinates, dxElementWrapper } from '@js/core/renderer'; import $ from '@js/core/renderer'; import type { TemplateBase } from '@js/core/templates/template_base'; import { noop } from '@js/core/utils/common'; @@ -30,14 +30,24 @@ import { } from '@js/core/utils/size'; import { isDefined } from '@js/core/utils/type'; import { getWindow, hasWindow } from '@js/core/utils/window'; +import type { DxEvent, InitializedEventInfo } from '@js/events'; import type { - AllDayPanelMode, CellClickEvent, CellContextMenuEvent, ScrollMode, + AllDayPanelMode, + AppointmentDraggingEndEvent, + AppointmentDraggingRemoveEvent, + AppointmentDraggingStartEvent, + CellClickEvent, + CellContextMenuEvent, + ScrollMode, } from '@js/ui/scheduler'; import type { ScrollEvent } from '@js/ui/scroll_view'; import errors from '@js/ui/widget/ui.errors'; -import Widget from '@js/ui/widget/ui.widget'; -import { getMemoizeScrollTo } from '@ts/core/utils/scroll'; +import type { TranslateVector } from '@ts/common/core/animation/translator'; +import { getMemoizeScrollTo, type ScrollToFunc } from '@ts/core/utils/scroll'; +import type { ActionConfig } from '@ts/core/widget/component'; import type { OptionChanged } from '@ts/core/widget/types'; +import type { SupportedKeys, WidgetProperties } from '@ts/core/widget/widget'; +import Widget from '@ts/core/widget/widget'; import { AllDayPanelTitleComponent, AllDayTableComponent, @@ -75,9 +85,17 @@ import { Cache } from '../global_cache'; import AppointmentDragBehavior from '../m_appointment_drag_behavior'; import { CompactAppointmentsHelper } from '../m_compact_appointments_helper'; import type { SubscribeKey, SubscribeMethods } from '../m_subscribes'; +import type HorizontalCurrentTimeShader from '../shaders/current_time_shader_horizontal'; import VerticalShader from '../shaders/current_time_shader_vertical'; import tableCreatorModule, { type GroupRows } from '../table_creator'; -import type { ViewCellData } from '../types'; +import type { + CellPositionData, + CellRect, + DOMMetaData, + GroupBoundsOffset, + ViewCellData, +} from '../types'; +import type { RenovationWidget } from '../utils'; import { utils } from '../utils'; import type { ResourceLoader } from '../utils/loader/resource_loader'; import { @@ -88,7 +106,8 @@ import { getLeafGroupValues } from '../utils/resource_manager/group_utils'; import type { ResourceManager } from '../utils/resource_manager/resource_manager'; import type { GroupValues, RawGroupValues } from '../utils/resource_manager/types'; import { getSkippedDaysCount as countSkippedDays } from '../utils/skipped_days'; -import type { ListEntity } from '../view_model/types'; +import type { CollectorCSS, RealSize } from '../view_model/generate_view_model/steps/add_geometry/types'; +import type { AppointmentViewModelPlain, ListEntity, PanelName } from '../view_model/types'; import { CellsSelectionController } from './cells_selection_controller'; import CellsSelectionState from './cells_selection_state'; import { @@ -100,7 +119,7 @@ import { } from './helpers/position_helper'; import type { ViewDataProviderOptions } from './view_model/types'; import ViewDataProvider from './view_model/view_data_provider'; -import { VirtualScrollingDispatcher, VirtualScrollingRenderer } from './virtual_scrolling'; +import { VirtualScrollingDispatcher, type VirtualScrollingDispatcherOptions, VirtualScrollingRenderer } from './virtual_scrolling'; import type { GroupedStrategyConfig } from './work_space_grouped_strategy_config'; import HorizontalGroupedStrategy from './work_space_grouped_strategy_horizontal'; import VerticalGroupedStrategy from './work_space_grouped_strategy_vertical'; @@ -130,6 +149,26 @@ export interface ViewDateGenerationOptions { viewType: ViewType; } +interface ScrollSync { + dateTable: ScrollToFunc; + header: ScrollToFunc; + sidebar: ScrollToFunc; +} + +interface NormalizedCellData { + startDate: Date; + endDate: Date; + startDateUTC?: Date | false | undefined; + endDateUTC?: Date | false | undefined; + groups?: ViewCellData['groups']; + groupIndex: ViewCellData['groupIndex']; + allDay?: ViewCellData['allDay']; + index?: ViewCellData['index']; + isFirstGroupCell?: ViewCellData['isFirstGroupCell']; + isLastGroupCell?: ViewCellData['isLastGroupCell']; + key?: ViewCellData['key']; +} + const { tableCreator } = tableCreatorModule; // The constant is needed so that the dragging is not sharp. To prevent small twitches @@ -214,13 +253,30 @@ const DEFAULT_WORKSPACE_RENDER_OPTIONS: RenderRWorkspaceOptions = { generateNewData: true, }; -export interface WorkspaceOptionsInternal { +interface SelectedCellsEventArgs { + selectedCellData: ViewCellData[]; +} + +interface WorkspaceOptionActionMap { + onSelectionChanged: SelectedCellsEventArgs; + onSelectionEnd: SelectedCellsEventArgs; + onCellClick: Pick; + onCellContextMenu: Pick; +} + +type WorkspaceCoordinates = Coordinates & { groupIndex?: number }; + +type DroppableCellData = Pick; + +export interface WorkspaceOptionsInternal extends WidgetProperties { newAppointments: boolean; resources: ResourceLoader[]; getResourceManager: () => ResourceManager; getFilteredItems: () => ListEntity[]; noDataText: string; - firstDayOfWeek: number; + activeStateEnabled: boolean; + hoverStateEnabled: boolean; + firstDayOfWeek?: number; startDayHour: number; endDayHour: number; viewOffset: number; @@ -239,25 +295,25 @@ export interface WorkspaceOptionsInternal { dateCellTemplate: TemplateBase | null; allowMultipleCellSelection: boolean; selectedCellData: ViewCellData[]; - onSelectionChanged: ((args: { selectedCellData: ViewCellData[] }) => void); - onSelectionEnd: ((args: { selectedCellData: ViewCellData[] }) => void); + onSelectionChanged: ((args: SelectedCellsEventArgs) => void); + onSelectionEnd: ((args: SelectedCellsEventArgs) => void); groupByDate: boolean; - skippedDays: number[]; + skippedDays?: number[]; scrolling: { mode: ScrollMode; - orientation: ScrollDirection; + orientation?: ScrollDirection; }; draggingMode: 'outlook' | 'default'; - timeZoneCalculator: TimeZoneCalculator; + timeZoneCalculator?: TimeZoneCalculator; schedulerHeight: string | number | undefined; schedulerWidth: string | number | undefined; allDayPanelMode: AllDayPanelMode; onSelectedCellsClick: (result: object, groups: GroupValues) => void; renderAppointments: () => void; onShowAllDayPanel: (isVisible: boolean) => void; - getHeaderHeight: (() => number); + getHeaderHeight?: (() => number); onScrollEnd: () => void; - onInitialized: (e: { element: dxElementWrapper }) => void; + onInitialized: (e: InitializedEventInfo) => void; onDisposing: () => void; notifyScheduler: NotifyScheduler; @@ -271,7 +327,7 @@ export interface WorkspaceOptionsInternal { agendaDuration: number; intervalCount: number; rowHeight: number; - startDate?: Date; + startDate?: Date | null; type?: ViewType; groupOrientation: GroupOrientation; width?: number | string | undefined; @@ -280,121 +336,125 @@ export interface WorkspaceOptionsInternal { } class SchedulerWorkSpace extends Widget { - private viewDataProviderValue: any; + private viewDataProviderValue!: ViewDataProvider | null; - private cacheValue: any; + private cacheValue!: Cache | null; - private cellsSelectionStateValue: any; + private cellsSelectionStateValue!: CellsSelectionState | null; - private cellsSelectionControllerValue: any; + private cellsSelectionControllerValue!: CellsSelectionController | null; protected $dateTableScrollable!: Scrollable; - private selectionChangedAction: any; + private selectionChangedAction: + | ((args: WorkspaceOptionActionMap['onSelectionChanged']) => void) + | undefined; - private selectionEndAction: any; + private selectionEndAction: + | ((args: WorkspaceOptionActionMap['onSelectionEnd']) => void) + | undefined; private isSelectionStartedOnCell = false; private documentPointerUpHandler: (() => void) | undefined; - private isCellClick: any; + private isCellClick?: boolean; - private contextMenuHandled: any; + private contextMenuHandled?: boolean; - _disposed: any; + _disposed: boolean | undefined; protected getToday?(): Date; - protected $allDayPanel: any; + protected $allDayPanel!: dxElementWrapper; - private $allDayTitle: any; + private $allDayTitle!: dxElementWrapper; - private $headerPanelEmptyCell: any; + private $headerPanelEmptyCell!: dxElementWrapper; - protected groupedStrategy: any; + protected groupedStrategy!: HorizontalGroupedStrategy | VerticalGroupedStrategy; - public virtualScrollingDispatcher: any; + public virtualScrollingDispatcher!: VirtualScrollingDispatcher; - private scrollSync: any; + private scrollSync!: Partial; - private $headerPanel: any; + private $headerPanel!: dxElementWrapper; - protected $dateTable: any; + protected $dateTable!: dxElementWrapper; - private $allDayTable: any; + private $allDayTable: dxElementWrapper | undefined; - private renderer: any; + private renderer!: VirtualScrollingRenderer; - _createAction: any; + _createAction!: (fn: (e: { event: Event }) => void) => (event?: unknown) => void; - private cellClickAction: any; + private cellClickAction: + | ((args: WorkspaceOptionActionMap['onCellClick']) => void) + | undefined; - _createActionByOption: any; + _createActionByOption!: ( + name: keyof WorkspaceOptionsInternal, + options?: ActionConfig, + ) => (event?: unknown) => void; - private showPopup: any; + private showPopup?: boolean; - private readonly NAME: any; - - private contextMenuAction: any; + private contextMenuAction: + | ((args: WorkspaceOptionActionMap['onCellContextMenu']) => void) + | undefined; protected $groupTable: dxElementWrapper | null | undefined; - protected $thead: any; + protected $thead!: dxElementWrapper; - private headerScrollable: any; + private headerScrollable!: Scrollable; - protected $sidebarScrollable: any; + protected $sidebarScrollable!: Scrollable; - private preventDefaultDragging: any; + private preventDefaultDragging = false; - public dragBehavior: any; + public dragBehavior: AppointmentDragBehavior | null = null; - protected $dateTableContainer: any; + protected $dateTableContainer!: dxElementWrapper; - protected $timePanel: any; + protected $timePanel!: dxElementWrapper; positionHelper!: PositionHelper; - protected $headerPanelContainer: any; - - private $headerTablesContainer: any; - - private $fixedContainer: any; + protected $headerPanelContainer!: dxElementWrapper; - private $allDayContainer: any; + private $headerTablesContainer!: dxElementWrapper; - protected $dateTableScrollableContent: any; + private $fixedContainer!: dxElementWrapper; - private $sidebarScrollableContent: any; + private $allDayContainer!: dxElementWrapper; - private allDayTitles!: any[]; + protected $dateTableScrollableContent!: dxElementWrapper; - private allDayTables!: any[]; + private $sidebarScrollableContent!: dxElementWrapper; - private allDayPanels!: any[]; + private allDayTables!: dxElementWrapper[]; - protected $flexContainer: any; + protected $flexContainer!: dxElementWrapper; - protected shader: any; + protected shader!: VerticalShader | HorizontalCurrentTimeShader; - protected $sidebarTable: any; + protected $sidebarTable: dxElementWrapper | undefined; - private interval: any; + private interval?: ReturnType; - private renovatedAllDayPanel: any; + private renovatedAllDayPanel: RenovationWidget | undefined; - public renovatedDateTable: any; + public renovatedDateTable: RenovationWidget | undefined; - private renovatedTimePanel: any; + private renovatedTimePanel: RenovationWidget | undefined; - private renovatedGroupPanel: any; + private renovatedGroupPanel: RenovationWidget | undefined; - public renovatedHeaderPanel: any; + public renovatedHeaderPanel: RenovationWidget | undefined; readonly viewDirection: 'vertical' | 'horizontal' = 'vertical'; - // eslint-disable-next-line class-methods-use-this protected _activeStateUnit(): string { return CELL_SELECTOR; } @@ -404,29 +464,25 @@ class SchedulerWorkSpace extends Widget { } get viewDataProvider(): ViewDataProvider { - if (!this.viewDataProviderValue) { - this.viewDataProviderValue = new ViewDataProvider(this.type); - } + this.viewDataProviderValue ??= new ViewDataProvider(this.type); return this.viewDataProviderValue; } - get cache() { - if (!this.cacheValue) { - this.cacheValue = new Cache(); - } - + get cache(): Cache { + this.cacheValue ??= new Cache(); return this.cacheValue; } get resourceManager(): ResourceManager { - return this.option('getResourceManager')(); + return this.option().getResourceManager(); } - get cellsSelectionState() { - if (!this.cellsSelectionStateValue) { - this.cellsSelectionStateValue = new CellsSelectionState(this.viewDataProvider); + get cellsSelectionState(): CellsSelectionState { + const isFirstInit = this.cellsSelectionStateValue == null; + this.cellsSelectionStateValue ??= new CellsSelectionState(this.viewDataProvider); - const selectedCellsOption: any = this.option('selectedCellData'); + if (isFirstInit) { + const selectedCellsOption = this.option().selectedCellData; if (selectedCellsOption?.length > 0) { const validSelectedCells = selectedCellsOption.map((selectedCell) => { @@ -454,28 +510,25 @@ class SchedulerWorkSpace extends Widget { return this.cellsSelectionStateValue; } - get cellsSelectionController() { - if (!this.cellsSelectionControllerValue) { - this.cellsSelectionControllerValue = new CellsSelectionController(); - } - + get cellsSelectionController(): CellsSelectionController { + this.cellsSelectionControllerValue ??= new CellsSelectionController(); return this.cellsSelectionControllerValue; } - get isAllDayPanelVisible() { + get isAllDayPanelVisible(): boolean { return this.isShowAllDayPanel() && this.supportAllDayRow(); } - get verticalGroupTableClass() { return WORKSPACE_VERTICAL_GROUP_TABLE_CLASS; } + get verticalGroupTableClass(): string { return WORKSPACE_VERTICAL_GROUP_TABLE_CLASS; } - get renovatedHeaderPanelComponent() { return HeaderPanelComponent; } + get renovatedHeaderPanelComponent(): typeof HeaderPanelComponent { return HeaderPanelComponent; } - get timeZoneCalculator(): any { - return this.option('timeZoneCalculator'); + get timeZoneCalculator(): TimeZoneCalculator | undefined { + return this.option().timeZoneCalculator; } - get isDefaultDraggingMode() { - return this.option('draggingMode') === 'default'; + get isDefaultDraggingMode(): boolean { + return this.option().draggingMode === 'default'; } notifyObserver( @@ -489,32 +542,45 @@ class SchedulerWorkSpace extends Widget { funcName: Subject, ...args: Parameters ): ReturnType | undefined { - const notifyScheduler = this.option('notifyScheduler') as NotifyScheduler | undefined; + const { notifyScheduler } = this.option(); if (!notifyScheduler) { return undefined; } + // eslint-disable-next-line @typescript-eslint/no-unsafe-return return notifyScheduler.invoke(funcName, ...args); } - _supportedKeys() { - const clickHandler = function (e) { + _supportedKeys(): SupportedKeys { + const clickHandler = ( + e: { preventDefault: () => void; stopPropagation: () => void; target: unknown }, + ): void => { e.preventDefault(); e.stopPropagation(); const selectedCells = this.getSelectedCellsData(); if (selectedCells?.length) { - const selectedCellsElement = selectedCells.map((cellData) => this.getCellByData(cellData)).filter((cell) => Boolean(cell)); + const selectedCellsElement = selectedCells + .map((cellData) => this.getCellByData(cellData)) + .filter((cell): cell is dxElementWrapper => Boolean(cell)); e.target = selectedCellsElement; this.showPopup = true; - this.cellClickAction({ event: e, cellElement: $(selectedCellsElement), cellData: selectedCells[0] }); + const cellElements = selectedCellsElement.map(($cell) => $cell.get(0)); + + this.cellClickAction?.( + { + event: e as CellClickEvent['event'], + cellElement: getPublicElement($(cellElements)), + cellData: selectedCells[0], + }, + ); } }; - const onArrowPressed = (e, key) => { + const onArrowPressed = (e: KeyboardEvent, key: 'up' | 'down' | 'left' | 'right'): void => { e.preventDefault(); e.stopPropagation(); @@ -523,7 +589,7 @@ class SchedulerWorkSpace extends Widget { if (focusedCellData) { const isAllDayPanelCell = focusedCellData.allDay && !this.isVerticalGroupedWorkSpace(); const isMultiSelection = e.shiftKey; - const isMultiSelectionAllowed = this.option('allowMultipleCellSelection'); + const isMultiSelectionAllowed = this.option().allowMultipleCellSelection; const isRTL = this.isRTL(); const groupCount = this.getGroupCount(); const isGroupedByDate = this.isGroupedByDate(); @@ -531,8 +597,11 @@ class SchedulerWorkSpace extends Widget { const focusedCellPosition = this.viewDataProvider.findCellPositionInMap(focusedCellData); const edgeIndices = isHorizontalGrouping && isMultiSelection && !isGroupedByDate - ? this.viewDataProvider.getGroupEdgeIndices(focusedCellData.groupIndex, isAllDayPanelCell) - : this.viewDataProvider.getViewEdgeIndices(isAllDayPanelCell); + ? this.viewDataProvider.getGroupEdgeIndices( + focusedCellData.groupIndex ?? 0, + Boolean(isAllDayPanelCell), + ) + : this.viewDataProvider.getViewEdgeIndices(Boolean(isAllDayPanelCell)); const nextCellData = this.cellsSelectionController.handleArrowClick({ focusedCellPosition, @@ -540,25 +609,24 @@ class SchedulerWorkSpace extends Widget { isRTL, isGroupedByDate, groupCount, - isMultiSelection, + isMultiSelection: Boolean(isMultiSelection), isMultiSelectionAllowed, viewType: this.type, key, getCellDataByPosition: this.viewDataProvider.getCellData.bind(this.viewDataProvider), - isAllDayPanelCell, + isAllDayPanelCell: Boolean(isAllDayPanelCell), focusedCellData, }); this.processNextSelectedCell( nextCellData, focusedCellData, - isMultiSelection && isMultiSelectionAllowed, + Boolean(isMultiSelection) && isMultiSelectionAllowed, ); } }; - // @ts-expect-error - return extend(super._supportedKeys(), { + const supportedKeys: SupportedKeys = { enter: clickHandler, space: clickHandler, downArrow: (e) => { @@ -573,20 +641,26 @@ class SchedulerWorkSpace extends Widget { leftArrow: (e) => { onArrowPressed(e, 'left'); }, - }); + }; + + return extend(super._supportedKeys(), supportedKeys) as SupportedKeys; } private isRTL(): boolean { - return this.option('rtlEnabled'); + return this.option().rtlEnabled; } - private moveToCell($cell, isMultiSelection) { + private moveToCell($cell: dxElementWrapper, isMultiSelection: boolean): void { if (!isDefined($cell) || !$cell.length) { return; } - const isMultiSelectionAllowed = this.option('allowMultipleCellSelection'); + const isMultiSelectionAllowed = this.option().allowMultipleCellSelection; const currentCellData = this.getFullCellData($cell); + if (!currentCellData) { + return; + } + const focusedCell = this.cellsSelectionState.getFocusedCell(); if (!focusedCell) { @@ -610,7 +684,11 @@ class SchedulerWorkSpace extends Widget { ); } - private processNextSelectedCell(nextCellData, focusedCellData, isMultiSelection) { + private processNextSelectedCell( + nextCellData: ViewCellData, + focusedCellData: ViewCellData, + isMultiSelection: boolean, + ): void { const nextCellPosition = this.viewDataProvider.findCellPositionInMap(nextCellData); if (!nextCellPosition) { @@ -623,13 +701,23 @@ class SchedulerWorkSpace extends Widget { : this.domGetDateCell(nextCellPosition); const isNextCellAllDay = nextCellData.allDay; - this.setSelectedCellsStateAndUpdateSelection(isNextCellAllDay, nextCellPosition, isMultiSelection, $cell); + this.setSelectedCellsStateAndUpdateSelection( + Boolean(isNextCellAllDay), + nextCellPosition, + isMultiSelection, + $cell, + ); this.$dateTableScrollable.scrollToElement($cell); } } - private setSelectedCellsStateAndUpdateSelection(isAllDay, cellPosition, isMultiSelection, $nextFocusedCell) { + private setSelectedCellsStateAndUpdateSelection( + isAllDay: boolean, + cellPosition: CellPositionData, + isMultiSelection: boolean, + $nextFocusedCell: dxElementWrapper, + ): void { const nextCellCoordinates = { rowIndex: cellPosition.rowIndex, columnIndex: cellPosition.columnIndex, @@ -652,12 +740,12 @@ class SchedulerWorkSpace extends Widget { this.updateSelectedCellDataOption(this.getSelectedCellsData(), $nextFocusedCell); } - private hasAllDayClass($cell) { + private hasAllDayClass($cell: dxElementWrapper): boolean { return $cell.hasClass(ALL_DAY_TABLE_CELL_CLASS); } - _focusInHandler(e) { - const $target = $(e.target); + _focusInHandler(e: DxEvent): void { + const $target = $(e.target as Element | null); const $focusTarget = this._focusTarget(); // T1312256: On macOS, e.target can be a child element of the workspace root const isTargetInsideWorkspace = $target.is($focusTarget) @@ -666,8 +754,7 @@ class SchedulerWorkSpace extends Widget { if (isTargetInsideWorkspace && this.isCellClick) { delete this.isCellClick; delete this.contextMenuHandled; - // @ts-expect-error - super._focusInHandler.apply(this, arguments); + super._focusInHandler(e); this.cellsSelectionState.restoreSelectedAndFocusedCells(); @@ -690,9 +777,8 @@ class SchedulerWorkSpace extends Widget { } } - _focusOutHandler() { - // @ts-expect-error - super._focusOutHandler.apply(this, arguments); + _focusOutHandler(e: DxEvent): void { + super._focusOutHandler(e); if (!this.contextMenuHandled && !this._disposed) { this.cellsSelectionState.releaseSelectedAndFocusedCells(); @@ -702,33 +788,27 @@ class SchedulerWorkSpace extends Widget { } } - _focusTarget() { + _focusTarget(): dxElementWrapper { return this.$element(); } - protected isVerticalGroupedWorkSpace() { // TODO move to the Model - return Boolean(this.option('groups')?.length) && this.option('groupOrientation') === 'vertical'; + protected isVerticalGroupedWorkSpace(): boolean { // TODO move to the Model + return Boolean(this.option().groups?.length) && this.option().groupOrientation === 'vertical'; } - protected isHorizontalGroupedWorkSpace() { - return Boolean(this.option('groups')?.length) && this.option('groupOrientation') === 'horizontal'; + protected isHorizontalGroupedWorkSpace(): boolean { + return Boolean(this.option().groups?.length) && this.option().groupOrientation === 'horizontal'; } - protected isWorkSpaceWithCount() { - return this.option('intervalCount') > 1; + protected isWorkSpaceWithCount(): boolean { + return this.option().intervalCount > 1; } - private isWorkspaceWithOddCells() { - return this.option('hoursInterval') === 0.5 && !this.isVirtualScrolling(); + private isWorkspaceWithOddCells(): boolean { + return this.option().hoursInterval === 0.5 && !this.isVirtualScrolling(); } - private getRealGroupOrientation() { - return this.isVerticalGroupedWorkSpace() - ? 'vertical' - : 'horizontal'; - } - - createRAllDayPanelElements() { + createRAllDayPanelElements(): void { this.$allDayPanel = $('
').addClass(ALL_DAY_PANEL_CLASS); this.$allDayTitle = $('
').appendTo(this.$headerPanelEmptyCell); } @@ -739,7 +819,9 @@ class SchedulerWorkSpace extends Widget { bounceEnabled: false, updateManually: true, onScroll: () => { - this.groupedStrategy.cache?.clear(); + if (this.groupedStrategy instanceof VerticalGroupedStrategy) { + this.groupedStrategy.cache.clear(); + } }, // TODO (Scrollable:useKeyboard) -> remove this WA // after ScrollView private option "useKeyboard" will be extended to useNative: true @@ -771,7 +853,7 @@ class SchedulerWorkSpace extends Widget { const currentOnScroll = config.onScroll; config = { ...config, - onScroll: (e: ScrollEvent) => { + onScroll: (e: ScrollEvent): void => { currentOnScroll?.(e); this.virtualScrollingDispatcher.handleOnScrollEvent(e?.scrollOffset); @@ -787,22 +869,22 @@ class SchedulerWorkSpace extends Widget { ): Pick { return { direction: 'both', - onScroll: (event: ScrollEvent) => { + onScroll: (event: ScrollEvent): void => { onScroll?.(event); const top = event.scrollOffset?.top; const left = event.scrollOffset?.left; if (top !== undefined) { - this.scrollSync.sidebar({ top }); + this.scrollSync.sidebar?.({ top }); } if (left !== undefined) { - this.scrollSync.header({ left }); + this.scrollSync.header?.({ left }); } }, - onEnd: () => { - (this.option('onScrollEnd') as any)(); + onEnd: (): void => { + this.option().onScrollEnd(); }, }; } @@ -815,13 +897,13 @@ class SchedulerWorkSpace extends Widget { useNative: false, updateManually: true, bounceEnabled: false, - onScroll: (event: ScrollEvent) => { - this.scrollSync.dateTable({ left: event.scrollOffset.left }); + onScroll: (event: ScrollEvent): void => { + this.scrollSync.dateTable?.({ left: event.scrollOffset.left }); }, }; } - _visibilityChanged(visible) { + _visibilityChanged(visible: boolean): void { this.cache.clear(); if (visible) { @@ -833,7 +915,7 @@ class SchedulerWorkSpace extends Widget { } } - protected setTableSizes() { + protected setTableSizes(): void { this.cache.clear(); this.attachTableClasses(); @@ -867,18 +949,16 @@ class SchedulerWorkSpace extends Widget { this.updateScrollable(); } - getWorkSpaceMinWidth() { + getWorkSpaceMinWidth(): number { return this.groupedStrategy.getWorkSpaceMinWidth(); } - _dimensionChanged() { - // NOTE: It's a base widget method. Be careful :) - // @ts-expect-error + _dimensionChanged(): void { if (!this._isVisible()) { return; } - if (this.option('crossScrollingEnabled')) { + if (this.option().crossScrollingEnabled) { this.setTableSizes(); } @@ -889,109 +969,111 @@ class SchedulerWorkSpace extends Widget { this.cache.clear(); } - protected needCreateCrossScrolling() { - return this.option('crossScrollingEnabled'); + protected needCreateCrossScrolling(): boolean { + return this.option().crossScrollingEnabled; } - protected getElementClass() { return noop(); } + protected getElementClass(): string { return ''; } - protected getRowCount() { + protected getRowCount(): number { return this.viewDataProvider.getRowCount({ - intervalCount: this.option('intervalCount'), - currentDate: this.option('currentDate'), + intervalCount: this.option().intervalCount, + currentDate: this.option().currentDate, viewType: this.type, - hoursInterval: this.option('hoursInterval'), - startDayHour: this.option('startDayHour'), - endDayHour: this.option('endDayHour'), + hoursInterval: this.option().hoursInterval, + startDayHour: this.option().startDayHour, + endDayHour: this.option().endDayHour, }); } - protected getCellCount() { + protected getCellCount(): number { return this.viewDataProvider.getCellCount({ - intervalCount: this.option('intervalCount'), - currentDate: this.option('currentDate'), + intervalCount: this.option().intervalCount, + currentDate: this.option().currentDate, viewType: this.type, - hoursInterval: this.option('hoursInterval'), - startDayHour: this.option('startDayHour'), - endDayHour: this.option('endDayHour'), + hoursInterval: this.option().hoursInterval, + startDayHour: this.option().startDayHour, + endDayHour: this.option().endDayHour, }); } - private isVirtualModeOn() { - return this.option('scrolling.mode') === 'virtual'; + private isVirtualModeOn(): boolean { + return this.option().scrolling.mode === 'virtual'; } - isVirtualScrolling() { + isVirtualScrolling(): boolean { return this.renovatedRenderSupported() && this.isVirtualModeOn(); } - private initVirtualScrolling() { + private initVirtualScrolling(): void { if (this.virtualScrollingDispatcher) { this.virtualScrollingDispatcher.dispose(); - this.virtualScrollingDispatcher = null; } - this.virtualScrollingDispatcher = new VirtualScrollingDispatcher(this.getVirtualScrollingDispatcherOptions()); + this.virtualScrollingDispatcher = new VirtualScrollingDispatcher( + this.getVirtualScrollingDispatcherOptions(), + ); this.virtualScrollingDispatcher.attachScrollableEvents(); this.renderer = new VirtualScrollingRenderer(this); } - isGroupedAllDayPanel() { + isGroupedAllDayPanel(): boolean { return calculateIsGroupedAllDayPanel( - this.option('groups').length, - this.option('groupOrientation') as any, - this.isAllDayPanelVisible as any, + this.option().groups.length, + this.option().groupOrientation, + this.isAllDayPanelVisible, ); } generateRenderOptions(isProvideVirtualCellsWidth = false): ViewDataProviderOptions { const groupCount = this.getGroupCount(); - const groupOrientation = groupCount > 0 - ? this.option('groupOrientation') + const groupOrientation: GroupOrientation = groupCount > 0 + ? this.option().groupOrientation : this.getDefaultGroupStrategy(); + const renderState = this.virtualScrollingDispatcher.getRenderState(); const options: ViewDataProviderOptions = { - groupByDate: this.option('groupByDate'), - startRowIndex: 0, - startCellIndex: 0, + groupByDate: this.option().groupByDate, groupOrientation, - today: this.getToday?.(), - getResourceManager: this.option('getResourceManager'), + today: this.getToday?.() ?? new Date(), + getResourceManager: this.option().getResourceManager, isProvideVirtualCellsWidth, isAllDayPanelVisible: this.isAllDayPanelVisible, selectedCells: this.cellsSelectionState.getSelectedCells(), focusedCell: this.cellsSelectionState.getFocusedCell(), headerCellTextFormat: this.getFormat(), - getDateForHeaderText: (_, date) => date, - viewOffset: this.option('viewOffset'), - startDayHour: this.option('startDayHour'), - endDayHour: this.option('endDayHour'), + getDateForHeaderText: (_: number, date: Date): Date => date, + viewOffset: this.option().viewOffset, + startDayHour: this.option().startDayHour, + endDayHour: this.option().endDayHour, cellDuration: this.getCellDuration(), viewType: this.type, - intervalCount: this.option('intervalCount'), - hoursInterval: this.option('hoursInterval'), - currentDate: this.option('currentDate'), - startDate: this.option('startDate'), - firstDayOfWeek: this.option('firstDayOfWeek'), - showCurrentTimeIndicator: this.option('showCurrentTimeIndicator'), - skippedDays: this.option('skippedDays'), - - ...this.virtualScrollingDispatcher.getRenderState(), + intervalCount: this.option().intervalCount, + hoursInterval: this.option().hoursInterval, + currentDate: this.option().currentDate, + startDate: this.option().startDate ?? undefined, + firstDayOfWeek: this.option().firstDayOfWeek ?? 0, + showCurrentTimeIndicator: this.option().showCurrentTimeIndicator, + skippedDays: this.option().skippedDays, + + ...renderState, + startRowIndex: renderState.startRowIndex ?? 0, + startCellIndex: renderState.startCellIndex ?? 0, }; return options; } - renovatedRenderSupported() { return true; } + renovatedRenderSupported(): boolean { return true; } - private updateGroupTableHeight() { + private updateGroupTableHeight(): void { if (this.isVerticalGroupedWorkSpace() && hasWindow()) { this.setHorizontalGroupHeaderCellsHeight(); } } - updateHeaderEmptyCellWidth() { + updateHeaderEmptyCellWidth(): void { if (hasWindow() && this.isRenderHeaderPanelEmptyCell()) { const timePanelWidth = this.getTimePanelWidth(); const groupPanelWidth = this.getGroupTableWidth(); @@ -1000,66 +1082,67 @@ class SchedulerWorkSpace extends Widget { } } - updateHeaderPanelScrollbarPadding() { + updateHeaderPanelScrollbarPadding(): void { if (hasWindow() && this.$headerPanelContainer) { const scrollbarWidth = this.getScrollbarWidth(); this.$headerPanelContainer.css('paddingRight', `${scrollbarWidth}px`); } } - private getScrollbarWidth() { + private getScrollbarWidth(): number { const containerElement = $(this.$dateTableScrollable.container()).get(0) as HTMLElement; const scrollbarWidth = containerElement.offsetWidth - containerElement.clientWidth; return scrollbarWidth; } - private isGroupsSpecified(groupValues?: GroupValues) { - return this.option('groups')?.length && groupValues; + private isGroupsSpecified(groupValues?: GroupValues): number | GroupValues | undefined { + return this.option().groups?.length && groupValues; } - private getGroupIndexByGroupValues(groupValues?: RawGroupValues | GroupValues) { + private getGroupIndexByGroupValues( + groupValues?: RawGroupValues | GroupValues, + ): number | undefined { return groupValues && getAppointmentGroupIndex( getSafeGroupValues(groupValues), this.resourceManager.groupsLeafs, )[0]; } - protected getViewStartByOptions() { + protected getViewStartByOptions(): Date { return getViewStartByOptions( - this.option('startDate'), - this.option('currentDate'), + this.option().startDate ?? undefined, + this.option().currentDate, this.getTotalViewDuration(), - this.option('startDate') ? this.calculateViewStartDate() : undefined, + this.option().startDate ? this.calculateViewStartDate() : undefined, ); } - protected getTotalViewDuration() { - return this.viewDataProvider.getIntervalDuration(this.option('intervalCount')); + protected getTotalViewDuration(): number { + return this.viewDataProvider.getIntervalDuration(this.option().intervalCount); } - protected getHeaderDate() { + protected getHeaderDate(): Date { return this.getStartViewDate(); } - protected calculateViewStartDate() { - return calculateViewStartDate(this.option('startDate')); + protected calculateViewStartDate(): Date | undefined { + return calculateViewStartDate(this.option().startDate ?? undefined); } - protected firstDayOfWeek() { - return this.viewDataProvider.getFirstDayOfWeek(this.option('firstDayOfWeek')); + protected firstDayOfWeek(): number { + return this.viewDataProvider.getFirstDayOfWeek(this.option().firstDayOfWeek ?? 0); } - protected attachEvents() { + protected attachEvents(): void { this.createSelectionChangedAction(); this.createSelectionEndAction(); this.attachClickEvent(); this.attachContextMenuEvent(); } - private attachClickEvent() { - const that = this; + private attachClickEvent(): void { const pointerDownAction = this._createAction((e) => { - that.pointerDownHandler(e.event); + this.pointerDownHandler(e.event); }); this.createCellClickAction(); @@ -1067,8 +1150,8 @@ class SchedulerWorkSpace extends Widget { const cellSelector = `.${DATE_TABLE_CELL_CLASS},.${ALL_DAY_TABLE_CELL_CLASS}`; const $element = this.$element(); - (eventsEngine.off as any)($element, SCHEDULER_WORKSPACE_DXPOINTERDOWN_EVENT_NAME); - (eventsEngine.off as any)($element, SCHEDULER_CELL_DXCLICK_EVENT_NAME); + eventsEngine.off($element, SCHEDULER_WORKSPACE_DXPOINTERDOWN_EVENT_NAME); + eventsEngine.off($element, SCHEDULER_CELL_DXCLICK_EVENT_NAME); eventsEngine.on($element, SCHEDULER_WORKSPACE_DXPOINTERDOWN_EVENT_NAME, (e) => { if (isMouseEvent(e) && e.which > 1) { e.preventDefault(); @@ -1077,38 +1160,60 @@ class SchedulerWorkSpace extends Widget { pointerDownAction({ event: e }); }); eventsEngine.on($element, SCHEDULER_CELL_DXCLICK_EVENT_NAME, cellSelector, (e) => { - const $cell = $(e.target); - that.cellClickAction({ event: e, cellElement: getPublicElement($cell), cellData: that.getCellData($cell) }); + const $cell = $(e.target as Element | null); + this.cellClickAction?.( + { + event: e, + cellElement: getPublicElement($cell), + cellData: this.getCellData($cell), + }, + ); }); if (this.documentPointerUpHandler) { - (eventsEngine.off as any)(domAdapter.getDocument(), SCHEDULER_TABLE_DXPOINTERUP_EVENT_NAME, this.documentPointerUpHandler); + eventsEngine.off( + domAdapter.getDocument(), + SCHEDULER_TABLE_DXPOINTERUP_EVENT_NAME, + this.documentPointerUpHandler, + ); } - this.documentPointerUpHandler = () => { + this.documentPointerUpHandler = (): void => { if (this.isSelectionStartedOnCell && !this._disposed) { this.fireSelectionEndEvent(); this.isSelectionStartedOnCell = false; } }; - eventsEngine.on(domAdapter.getDocument(), SCHEDULER_TABLE_DXPOINTERUP_EVENT_NAME, this.documentPointerUpHandler); + eventsEngine.on( + domAdapter.getDocument(), + SCHEDULER_TABLE_DXPOINTERUP_EVENT_NAME, + this.documentPointerUpHandler, + ); + } + + private createWorkspaceOptionAction( + optionName: K, + config?: ActionConfig, + ): (args: WorkspaceOptionActionMap[K]) => void { + return this._createActionByOption(optionName, config) as ( + args: WorkspaceOptionActionMap[K], + ) => void; } - private createCellClickAction() { - this.cellClickAction = this._createActionByOption('onCellClick', { - afterExecute: (e) => this.cellClickHandler(e.args[0].event), + private createCellClickAction(): void { + this.cellClickAction = this.createWorkspaceOptionAction('onCellClick', { + afterExecute: () => this.cellClickHandler(), }); } - private createSelectionChangedAction() { - this.selectionChangedAction = this._createActionByOption('onSelectionChanged'); + private createSelectionChangedAction(): void { + this.selectionChangedAction = this.createWorkspaceOptionAction('onSelectionChanged'); } - private createSelectionEndAction() { - this.selectionEndAction = this._createActionByOption('onSelectionEnd'); + private createSelectionEndAction(): void { + this.selectionEndAction = this.createWorkspaceOptionAction('onSelectionEnd'); } - // eslint-disable-next-line @typescript-eslint/no-unused-vars - private cellClickHandler(argument?: any) { + private cellClickHandler(): void { if (this.showPopup) { delete this.showPopup; this.isSelectionStartedOnCell = false; @@ -1116,8 +1221,8 @@ class SchedulerWorkSpace extends Widget { } } - private pointerDownHandler(e) { - const $target = $(e.target); + private pointerDownHandler(e: { target: EventTarget | null; which?: number }): void { + const $target = $(e.target as Element | null); if (!$target.hasClass(DATE_TABLE_CELL_CLASS) && !$target.hasClass(ALL_DAY_TABLE_CELL_CLASS)) { this.isCellClick = false; @@ -1137,13 +1242,19 @@ class SchedulerWorkSpace extends Widget { } } - private handleSelectedCellsClick() { + private handleSelectedCellsClick(): void { const selectedCells = this.getSelectedCellsData(); const firstCellData = selectedCells[0]; const lastCellData = selectedCells[selectedCells.length - 1]; - const result: any = { + const result: { + startDate: Date; + endDate: Date; + startDateUTC: NormalizedCellData['startDateUTC']; + endDateUTC: NormalizedCellData['endDateUTC']; + allDay?: NormalizedCellData['allDay']; + } = { startDate: firstCellData.startDate, endDate: lastCellData.endDate, startDateUTC: firstCellData.startDateUTC, @@ -1154,31 +1265,37 @@ class SchedulerWorkSpace extends Widget { result.allDay = lastCellData.allDay; } - (this.option('onSelectedCellsClick') as any)(result, lastCellData.groups); + this.option().onSelectedCellsClick(result, lastCellData.groups as GroupValues); } - private attachContextMenuEvent() { + private attachContextMenuEvent(): void { this.createContextMenuAction(); const cellSelector = `.${DATE_TABLE_CELL_CLASS},.${ALL_DAY_TABLE_CELL_CLASS}`; const $element = this.$element(); - const eventName = addNamespace(contextMenuEventName, this.NAME); + const eventName = addNamespace(contextMenuEventName, this.NAME as string); eventsEngine.off($element, eventName, cellSelector); eventsEngine.on($element, eventName, cellSelector, this.contextMenuHandler.bind(this)); } - private contextMenuHandler(e) { - const $cell = $(e.target); - this.contextMenuAction({ event: e, cellElement: getPublicElement($cell), cellData: this.getCellData($cell) }); + private contextMenuHandler(e: DxEvent): void { + const $cell = $(e.target as Element | null); + this.contextMenuAction?.( + { + event: e as CellContextMenuEvent['event'], + cellElement: getPublicElement($cell), + cellData: this.getCellData($cell), + }, + ); this.contextMenuHandled = true; } - private createContextMenuAction() { - this.contextMenuAction = this._createActionByOption('onCellContextMenu'); + private createContextMenuAction(): void { + this.contextMenuAction = this.createWorkspaceOptionAction('onCellContextMenu'); } - protected getGroupHeaderContainer() { + protected getGroupHeaderContainer(): dxElementWrapper | null | undefined { if (this.isVerticalGroupedWorkSpace()) { return this.$groupTable; } @@ -1186,39 +1303,29 @@ class SchedulerWorkSpace extends Widget { return this.$thead; } - private getDateHeaderContainer() { - return this.$thead; - } - - private getCalculateHeaderCellRepeatCount() { - return this.groupedStrategy.calculateHeaderCellRepeatCount(); - } - - protected updateScrollable() { + protected updateScrollable(): void { this.$dateTableScrollable.update(); this.headerScrollable?.update(); this.$sidebarScrollable?.update(); this.updateHeaderPanelScrollbarPadding(); } - protected getTimePanelRowCount() { + protected getTimePanelRowCount(): number { return this.getCellCountInDay(); } - protected getCellCountInDay() { - const hoursInterval = this.option('hoursInterval'); - const startDayHour = this.option('startDayHour'); - const endDayHour = this.option('endDayHour'); + protected getCellCountInDay(): number { + const { hoursInterval, startDayHour, endDayHour } = this.option(); return this.viewDataProvider.getCellCountInDay(startDayHour, endDayHour, hoursInterval); } - private getTotalCellCount(groupCount) { + private getTotalCellCount(groupCount: number): number { return this.groupedStrategy.getTotalCellCount(groupCount); } - protected getTotalRowCount(groupCount: number, includeAllDayPanelRows?: boolean) { - let result = this.groupedStrategy.getTotalRowCount(groupCount); + protected getTotalRowCount(groupCount: number, includeAllDayPanelRows?: boolean): number { + let result = this.groupedStrategy.getTotalRowCount(); if (includeAllDayPanelRows && this.isAllDayPanelVisible) { result += groupCount; @@ -1227,64 +1334,68 @@ class SchedulerWorkSpace extends Widget { return result; } - private getGroupIndex(rowIndex, columnIndex) { + private getGroupIndex(rowIndex: number, columnIndex: number): number { return this.groupedStrategy.getGroupIndex(rowIndex, columnIndex); } - calculateEndDate(startDate) { + calculateEndDate(startDate: Date): Date { const { viewDataGenerator } = this.viewDataProvider; return viewDataGenerator.calculateEndDate( startDate, - viewDataGenerator.getInterval(this.option('hoursInterval')), - this.option('endDayHour'), + viewDataGenerator.getInterval(this.option().hoursInterval), + this.option().endDayHour, ); } - protected getGroupCount() { + protected getGroupCount(): number { return this.resourceManager.groupCount(); } - protected attachTablesEvents() { + protected attachTablesEvents(): void { const element = this.$element(); this.attachDragEvents(element); this.attachPointerEvents(element); } - private detachDragEvents(element) { - (eventsEngine.off as any)(element, DragEventNames.ENTER); - (eventsEngine.off as any)(element, DragEventNames.LEAVE); - (eventsEngine.off as any)(element, DragEventNames.DROP); + private detachDragEvents(element: dxElementWrapper): void { + eventsEngine.off(element, DragEventNames.ENTER); + eventsEngine.off(element, DragEventNames.LEAVE); + eventsEngine.off(element, DragEventNames.DROP); } - private attachDragEvents(element) { - if (this.option('newAppointments')) { + private attachDragEvents(element: dxElementWrapper): void { + if (this.option().newAppointments) { return; } this.detachDragEvents(element); - const onDragEnter = (e) => { + const onDragEnter = (e: { target: Element }): void => { if (!this.preventDefaultDragging) { this.removeDroppableCellClass(); $(e.target).addClass(DATE_TABLE_DROPPABLE_CELL_CLASS); } }; - const removeClasses = () => { + const removeClasses = (): void => { if (!this.preventDefaultDragging) { this.removeDroppableCellClass(); } }; - const onCheckDropTarget = (target, event) => !this.isOutsideScrollable(target, event); + const onCheckDropTarget = ( + target: Element, + event: { pageX: number; pageY: number }, + ): boolean => !this.isOutsideScrollable(target, event); - (eventsEngine.on as any)( + eventsEngine.on( element, DragEventNames.ENTER, DRAG_AND_DROP_SELECTOR, { checkDropTarget: onCheckDropTarget }, + // @ts-expect-error onDragEnter, ); eventsEngine.on(element, DragEventNames.LEAVE, removeClasses); @@ -1299,85 +1410,104 @@ class SchedulerWorkSpace extends Widget { } this.dragBehavior.dragBetweenComponentsPromise?.then(() => { - this.dragBehavior.removeDroppableClasses(); + this.dragBehavior?.removeDroppableClasses(); }); }); } - private attachPointerEvents(element) { + private attachPointerEvents(element: dxElementWrapper): void { let isPointerDown = false; - (eventsEngine.off as any)(element, SCHEDULER_CELL_DXPOINTERMOVE_EVENT_NAME); - (eventsEngine.off as any)(element, SCHEDULER_CELL_DXPOINTERDOWN_EVENT_NAME); - - eventsEngine.on(element, SCHEDULER_CELL_DXPOINTERDOWN_EVENT_NAME, DRAG_AND_DROP_SELECTOR, (e) => { - if ((isMouseEvent(e) || (e.originalEvent && isMouseEvent(e.originalEvent))) && e.which === 1) { - isPointerDown = true; - (this.$element() as any).addClass(WORKSPACE_WITH_MOUSE_SELECTION_CLASS); - (eventsEngine.off as any)(domAdapter.getDocument(), SCHEDULER_CELL_DXPOINTERUP_EVENT_NAME); - eventsEngine.on(domAdapter.getDocument(), SCHEDULER_CELL_DXPOINTERUP_EVENT_NAME, () => { - isPointerDown = false; - (this.$element() as any).removeClass(WORKSPACE_WITH_MOUSE_SELECTION_CLASS); - }); - } - }); + eventsEngine.off(element, SCHEDULER_CELL_DXPOINTERMOVE_EVENT_NAME); + eventsEngine.off(element, SCHEDULER_CELL_DXPOINTERDOWN_EVENT_NAME); - eventsEngine.on(element, SCHEDULER_CELL_DXPOINTERMOVE_EVENT_NAME, DRAG_AND_DROP_SELECTOR, (e) => { - if (isPointerDown && this.$dateTableScrollable) { - e.preventDefault(); - e.stopPropagation(); - this.moveToCell($(e.target), true); - } - }); + eventsEngine.on( + element, + SCHEDULER_CELL_DXPOINTERDOWN_EVENT_NAME, + DRAG_AND_DROP_SELECTOR, + (e: { + type: string; + target: Element; + originalEvent: Event; + which: number; + }): void => { + if (( + isMouseEvent(e) || (e.originalEvent && isMouseEvent(e.originalEvent)) + ) && e.which === 1) { + isPointerDown = true; + this.$element().addClass(WORKSPACE_WITH_MOUSE_SELECTION_CLASS); + eventsEngine.off(domAdapter.getDocument(), SCHEDULER_CELL_DXPOINTERUP_EVENT_NAME); + eventsEngine.on(domAdapter.getDocument(), SCHEDULER_CELL_DXPOINTERUP_EVENT_NAME, () => { + isPointerDown = false; + this.$element().removeClass(WORKSPACE_WITH_MOUSE_SELECTION_CLASS); + }); + } + }, + ); + + eventsEngine.on( + element, + SCHEDULER_CELL_DXPOINTERMOVE_EVENT_NAME, + DRAG_AND_DROP_SELECTOR, + (e) => { + if (isPointerDown && this.$dateTableScrollable) { + e.preventDefault(); + e.stopPropagation(); + this.moveToCell($(e.target), true); + } + }, + ); } - protected getFormat(): string | ((date: Date) => string) { return abstract(); } + protected getFormat(): string | ((date: Date) => string) { + return abstract() as string; + } - getWorkArea() { + getWorkArea(): dxElementWrapper { return this.$dateTableContainer; } - getScrollable() { + getScrollable(): Scrollable { return this.$dateTableScrollable; } - getScrollableScrollTop() { + getScrollableScrollTop(): number { return this.$dateTableScrollable.scrollTop(); } - getGroupedScrollableScrollTop(allDay) { + getGroupedScrollableScrollTop(allDay: boolean): number { return this.groupedStrategy.getScrollableScrollTop(allDay); } - getScrollableScrollLeft() { + getScrollableScrollLeft(): number { return this.$dateTableScrollable.scrollLeft(); } - getScrollableOuterWidth() { + getScrollableOuterWidth(): number { return this.$dateTableScrollable.scrollWidth(); } - getScrollableContainer() { + getScrollableContainer(): dxElementWrapper { return $(this.$dateTableScrollable.container()); } - getHeaderPanelHeight() { - return this.$headerPanel && getOuterHeight(this.$headerPanel, true); + getHeaderPanelHeight(): number | false { + return this.$headerPanel && getOuterHeight(this.$headerPanel, true) as number; } getTimePanelWidth(): number { - return this.$timePanel && getBoundingRect(this.$timePanel.get(0)).width; + return this.$timePanel && getBoundingRect(this.$timePanel.get(0)).width as number; } getGroupTableWidth(): number { - return this.$groupTable ? getOuterWidth(this.$groupTable) : 0; + return this.$groupTable ? getOuterWidth(this.$groupTable) as number : 0; } - getWorkSpaceLeftOffset() { + getWorkSpaceLeftOffset(): number { return this.groupedStrategy.getLeftOffset(); } - protected getCellCoordinatesByIndex(index) { + protected getCellCoordinatesByIndex(index: number): CellPositionData { const columnIndex = Math.floor(index / this.getRowCount()); const rowIndex = index - this.getRowCount() * columnIndex; @@ -1389,24 +1519,24 @@ class SchedulerWorkSpace extends Widget { protected getDateGenerationOptions(): ViewDateGenerationOptions { return { - startDayHour: this.option('startDayHour'), - endDayHour: this.option('endDayHour'), - hoursInterval: this.option('hoursInterval'), - interval: this.viewDataProvider.viewDataGenerator?.getInterval(this.option('hoursInterval')), - intervalCount: this.option('intervalCount'), + startDayHour: this.option().startDayHour, + endDayHour: this.option().endDayHour, + hoursInterval: this.option().hoursInterval, + interval: this.viewDataProvider.viewDataGenerator?.getInterval(this.option().hoursInterval), + intervalCount: this.option().intervalCount, startViewDate: this.getStartViewDate(), firstDayOfWeek: this.firstDayOfWeek(), - skippedDays: this.option('skippedDays'), + skippedDays: this.option().skippedDays, viewOffset: 0, viewType: this.type, }; } // TODO: refactor current time indicator - protected getIntervalBetween(currentDate, allDay) { + protected getIntervalBetween(currentDate: Date, allDay: boolean): number { const firstViewDate = this.getStartViewDate(); - const startDayTime = this.option('startDayHour') * HOUR_MS; + const startDayTime = this.option().startDayHour * HOUR_MS; const timeZoneOffset = dateUtils.getTimezonesDifference(firstViewDate, currentDate); const fullInterval = currentDate.getTime() - firstViewDate.getTime() - timeZoneOffset; const days = this.getDaysOfInterval(fullInterval, startDayTime); @@ -1423,32 +1553,32 @@ class SchedulerWorkSpace extends Widget { return result; } - protected getSkippedDaysCount(startDate: Date, days: number) { + protected getSkippedDaysCount(startDate: Date, days: number): number { return countSkippedDays( startDate, days, - this.option('skippedDays'), + this.option().skippedDays, ); } - private getDaysOfInterval(fullInterval, startDayTime) { + private getDaysOfInterval(fullInterval: number, startDayTime: number): number { return Math.floor((fullInterval + startDayTime) / DAY_MS); } - protected updateIndex(index) { + protected updateIndex(index: number): number { return index * this.getRowCount(); } - getDroppableCell() { + getDroppableCell(): dxElementWrapper { return this.getDateTables().find(`.${DATE_TABLE_DROPPABLE_CELL_CLASS}`); } protected getWorkSpaceWidth(): number { - return this.cache.memo('workspaceWidth', () => { + return this.cache.memo('workspaceWidth', (): number => { if (this.needCreateCrossScrolling()) { - return getBoundingRect(this.$dateTable.get(0)).width; + return getBoundingRect(this.$dateTable.get(0)).width as number; } - const totalWidth = getBoundingRect((this.$element() as any).get(0)).width; + const totalWidth = getBoundingRect(this.$element().get(0)).width; const timePanelWidth = this.getTimePanelWidth(); const groupTableWidth = this.getGroupTableWidth(); @@ -1456,12 +1586,20 @@ class SchedulerWorkSpace extends Widget { }); } - protected getCellElementByPosition(cellCoordinates, groupIndex, inAllDayRow) { - const indexes = this.groupedStrategy.prepareCellIndexes(cellCoordinates, groupIndex, inAllDayRow); + protected getCellElementByPosition( + cellCoordinates: CellPositionData, + groupIndex: number, + inAllDayRow: boolean, + ): dxElementWrapper { + const indexes = this.groupedStrategy.prepareCellIndexes( + cellCoordinates, + groupIndex, + inAllDayRow, + ); return this.domGetDateCell(indexes); } - private domGetDateCell(position) { + private domGetDateCell(position: CellPositionData): dxElementWrapper { return this.$dateTable .find(`tr:not(.${VIRTUAL_ROW_CLASS})`) .eq(position.rowIndex) @@ -1469,36 +1607,36 @@ class SchedulerWorkSpace extends Widget { .eq(position.columnIndex); } - private domGetAllDayPanelCell(columnIndex) { + private domGetAllDayPanelCell(columnIndex: number): dxElementWrapper { return this.$allDayPanel .find('tr').eq(0) .find('td').eq(columnIndex); } - protected getCells(allDay?: any, direction?: any) { + protected getCells(allDay?: boolean, direction?: string): dxElementWrapper { const cellClass = allDay ? ALL_DAY_TABLE_CELL_CLASS : DATE_TABLE_CELL_CLASS; if (direction === 'vertical') { - let result: any = []; - for (let i = 1; ; i++) { - const cells = (this.$element() as any).find(`tr .${cellClass}:nth-child(${i})`); + let result: Element[] = []; + for (let i = 1; ; i += 1) { + const cells = this.$element().find(`tr .${cellClass}:nth-child(${i})`); if (!cells.length) break; result = result.concat(cells.toArray()); } return $(result); } - return (this.$element() as any).find(`.${cellClass}`); + return this.$element().find(`.${cellClass}`); } - private getFirstAndLastDataTableCell() { + private getFirstAndLastDataTableCell(): Element[] { const selector = this.isVirtualScrolling() ? `.${DATE_TABLE_CELL_CLASS}, .${VIRTUAL_CELL_CLASS}` : `.${DATE_TABLE_CELL_CLASS}`; - const $cells = (this.$element() as any).find(selector); - return [$cells[0], $cells[$cells.length - 1]]; + const $cells = this.$element().find(selector); + return [$cells.get(0), $cells.get(-1)]; } - private getAllCells(allDay) { + private getAllCells(allDay: boolean): dxElementWrapper { if (this.isVerticalGroupedWorkSpace()) { return this.$dateTable.find(`td:not(.${VIRTUAL_CELL_CLASS})`); } @@ -1507,22 +1645,31 @@ class SchedulerWorkSpace extends Widget { ? ALL_DAY_TABLE_CELL_CLASS : DATE_TABLE_CELL_CLASS; - return (this.$element() as any).find(`.${cellClass}`); + return this.$element().find(`.${cellClass}`); } - protected setHorizontalGroupHeaderCellsHeight() { + protected setHorizontalGroupHeaderCellsHeight(): void { const { height } = getBoundingRect(this.$dateTable.get(0)); setOuterHeight(this.$groupTable, height); } - protected getGroupHeaderCells() { - return (this.$element() as any).find(`.${GROUP_HEADER_CLASS}`); + protected getGroupHeaderCells(): dxElementWrapper { + return this.$element().find(`.${GROUP_HEADER_CLASS}`); } - private getScrollCoordinates(date, groupIndex?: any, allDay?: any) { - const currentDate = date || new Date(this.option('currentDate')); + private getScrollCoordinates( + date: Date, + groupIndex?: number, + allDay?: boolean, + ): Coordinates | undefined { + const currentDate = date || new Date(this.option().currentDate); - const cell = this.viewDataProvider.findGlobalCellPosition(currentDate, groupIndex, allDay, true); + const cell = this.viewDataProvider.findGlobalCellPosition( + currentDate, + groupIndex, + allDay, + true, + ); if (!cell) { return undefined; @@ -1534,18 +1681,20 @@ class SchedulerWorkSpace extends Widget { cell.cellData, cell.position, currentDate, - isDateAndTimeView(this.type as any), + isDateAndTimeView(this.type), this.viewDirection === 'vertical', ); } - private isOutsideScrollable(target, event) { + private isOutsideScrollable(target: Element, event: { pageX: number; pageY: number }): boolean { const $dateTableScrollableElement = this.$dateTableScrollable.$element(); const scrollableSize = getBoundingRect($dateTableScrollableElement.get(0)); const window = getWindow(); const isTargetInAllDayPanel = !$(target).closest($dateTableScrollableElement).length; - const isOutsideHorizontalScrollable = event.pageX < scrollableSize.left || event.pageX > (scrollableSize.left + scrollableSize.width + (window.scrollX || 0)); - const isOutsideVerticalScrollable = event.pageY < scrollableSize.top || event.pageY > (scrollableSize.top + scrollableSize.height + (window.scrollY || 0)); + const isOutsideHorizontalScrollable = event.pageX < scrollableSize.left + || event.pageX > (scrollableSize.left + scrollableSize.width + (window.scrollX || 0)); + const isOutsideVerticalScrollable = event.pageY < scrollableSize.top + || event.pageY > (scrollableSize.top + scrollableSize.height + (window.scrollY || 0)); if (isTargetInAllDayPanel && !isOutsideHorizontalScrollable) { return false; @@ -1554,39 +1703,43 @@ class SchedulerWorkSpace extends Widget { return isOutsideVerticalScrollable || isOutsideHorizontalScrollable; } - supportAllDayRow() { + supportAllDayRow(): boolean { return true; } - keepOriginalHours() { + keepOriginalHours(): boolean { return false; } - private normalizeCellData(cellData) { - return extend(true, {}, { - startDate: cellData.startDate, - endDate: cellData.endDate, - startDateUTC: cellData.startDate && this.timeZoneCalculator?.createDate(cellData.startDate, 'fromGrid'), - endDateUTC: cellData.endDate && this.timeZoneCalculator?.createDate(cellData.endDate, 'fromGrid'), - groups: cellData.groups, + private normalizeCellData(cellData: Partial): NormalizedCellData { + const startDateUTC = cellData.startDate + && this.timeZoneCalculator?.createDate(cellData.startDate, 'fromGrid'); + const endDateUTC = cellData.endDate + && this.timeZoneCalculator?.createDate(cellData.endDate, 'fromGrid'); + return { + startDate: cellData.startDate ?? new Date(), + endDate: cellData.endDate ?? new Date(), + ...(startDateUTC !== undefined && { startDateUTC }), + ...(endDateUTC !== undefined && { endDateUTC }), + ...(cellData.allDay !== undefined && { allDay: cellData.allDay }), + ...(cellData.groups !== undefined && { groups: { ...cellData.groups } }), groupIndex: cellData.groupIndex, - allDay: cellData.allDay, - }); + }; } - private getSelectedCellsData() { + private getSelectedCellsData(): NormalizedCellData[] { const selected = this.cellsSelectionState.getSelectedCells(); - return selected?.map(this.normalizeCellData.bind(this)); + return selected?.map(this.normalizeCellData.bind(this)) ?? []; } - getCellData($cell) { + getCellData($cell: dxElementWrapper): NormalizedCellData { const cellData = this.getFullCellData($cell) ?? {}; return this.normalizeCellData(cellData); } - private getFullCellData($cell) { + private getFullCellData($cell: dxElementWrapper): ViewCellData | undefined { const currentCell = $cell[0]; if (currentCell) { return this.getDataByCell($cell); @@ -1595,15 +1748,7 @@ class SchedulerWorkSpace extends Widget { return undefined; } - private getVirtualRowOffset() { - return this.virtualScrollingDispatcher.virtualRowOffset; - } - - private getVirtualCellOffset() { - return this.virtualScrollingDispatcher.virtualCellOffset; - } - - private getDataByCell($cell) { + private getDataByCell($cell: dxElementWrapper): ViewCellData | undefined { const rowIndex = $cell.parent().index() - this.virtualScrollingDispatcher.topVirtualRowsCount; const columnIndex = $cell.index() - this.virtualScrollingDispatcher.leftVirtualCellsCount; @@ -1615,21 +1760,24 @@ class SchedulerWorkSpace extends Widget { return cellData || undefined; } - isGroupedByDate() { - return this.option('groupByDate') + isGroupedByDate(): boolean { + return this.option().groupByDate && this.isHorizontalGroupedWorkSpace() && this.getGroupCount() > 0; } // TODO: refactor current time indicator - getCellIndexByDate(date, inAllDayRow?: any) { + getCellIndexByDate(date: Date, inAllDayRow?: boolean): number { const { viewDataGenerator } = this.viewDataProvider; const timeInterval = inAllDayRow ? 24 * 60 * 60 * 1000 - : viewDataGenerator.getInterval(this.option('hoursInterval')); - const startViewDateOffset = getStartViewDateTimeOffset(this.getStartViewDate(), this.option('startDayHour') as any); - const dateTimeStamp = this.getIntervalBetween(date, inAllDayRow) + startViewDateOffset; + : viewDataGenerator.getInterval(this.option().hoursInterval); + const startViewDateOffset = getStartViewDateTimeOffset( + this.getStartViewDate(), + this.option().startDayHour, + ); + const dateTimeStamp = this.getIntervalBetween(date, inAllDayRow ?? false) + startViewDateOffset; let index = Math.floor(dateTimeStamp / timeInterval); @@ -1644,7 +1792,7 @@ class SchedulerWorkSpace extends Widget { return index; } - getDataByDroppableCell() { + getDataByDroppableCell(): DroppableCellData { const cellData = this.getCellData($(this.getDroppableCell())); const { allDay } = cellData; const { startDate } = cellData; @@ -1658,29 +1806,29 @@ class SchedulerWorkSpace extends Widget { }; } - getDateRange() { + getDateRange(): Date[] { return [ this.getStartViewDate(), this.getEndViewDateByEndDayHour(), ]; } - getCellMinWidth() { + getCellMinWidth(): number { return DATE_TABLE_MIN_CELL_WIDTH; } // Mappings - getCellWidth() { + getCellWidth(): number { return getCellWidth(this.getDOMElementsMetaData()); } - getCellHeight() { + getCellHeight(): number { return getCellHeight(this.getDOMElementsMetaData()); } - getAllDayHeight() { + getAllDayHeight(): number { return getAllDayHeight( - this.option('showAllDayPanel'), + this.option().showAllDayPanel, this.isVerticalGroupedWorkSpace(), this.getDOMElementsMetaData(), ); @@ -1698,24 +1846,25 @@ class SchedulerWorkSpace extends Widget { return 0; } - getMaxAllowedPosition(groupIndex) { + getMaxAllowedPosition(groupIndex: number): number { return getMaxAllowedPosition( groupIndex, this.viewDataProvider, - this.option('rtlEnabled'), + this.option().rtlEnabled, this.getDOMElementsMetaData(), ); } - getAllDayOffset() { + getAllDayOffset(): number { return this.groupedStrategy.getAllDayOffset(); } // NOTE: refactor leftIndex calculation - getCellIndexByCoordinates(coordinates, allDay?) { + getCellIndexByCoordinates(coordinates: Coordinates, allDay?: boolean): number { const { horizontalScrollingState, verticalScrollingState } = this.virtualScrollingDispatcher; - const cellCount = horizontalScrollingState?.itemCount ?? this.getTotalCellCount(this.getGroupCount()); + const cellCount = horizontalScrollingState?.itemCount + ?? this.getTotalCellCount(this.getGroupCount()); const cellWidth = this.getCellWidth(); const cellHeight = allDay ? this.getAllDayHeight() : this.getCellHeight(); @@ -1723,7 +1872,9 @@ class SchedulerWorkSpace extends Widget { const leftCoordinateOffset = horizontalScrollingState?.virtualItemSizeBefore ?? 0; const topCoordinateOffset = verticalScrollingState?.virtualItemSizeBefore ?? 0; - const topIndex = Math.floor(Math.floor(coordinates.top - topCoordinateOffset) / Math.floor(cellHeight)); + const topIndex = Math.floor( + Math.floor(coordinates.top - topCoordinateOffset) / Math.floor(cellHeight), + ); let leftIndex = (coordinates.left - leftCoordinateOffset) / cellWidth; leftIndex = Math.floor(leftIndex + CELL_INDEX_CALCULATION_EPSILON); @@ -1734,67 +1885,77 @@ class SchedulerWorkSpace extends Widget { return cellCount * topIndex + leftIndex; } - getStartViewDate() { + getStartViewDate(): Date { return this.viewDataProvider.getStartViewDate(); } - getEndViewDate() { + getEndViewDate(): Date { return this.viewDataProvider.getLastCellEndDate(); } - getEndViewDateByEndDayHour() { - return this.viewDataProvider.getLastViewDateByEndDayHour(this.option('endDayHour')); + getEndViewDateByEndDayHour(): Date { + return this.viewDataProvider.getLastViewDateByEndDayHour(this.option().endDayHour); } - getCellDuration() { + getCellDuration(): number { return getCellDuration( - this.type as any, - this.option('startDayHour') as any, - this.option('endDayHour') as any, - this.option('hoursInterval') as any, + this.type, + this.option().startDayHour, + this.option().endDayHour, + this.option().hoursInterval, ); } - getIntervalDuration(allDay) { + getIntervalDuration(allDay: boolean): number { return allDay ? toMs('day') : this.getCellDuration(); } - getVisibleDayDuration() { - const startDayHour = this.option('startDayHour'); - const endDayHour = this.option('endDayHour'); - const hoursInterval = this.option('hoursInterval'); + getVisibleDayDuration(): number { + const { startDayHour, endDayHour, hoursInterval } = this.option(); return this.viewDataProvider.getVisibleDayDuration(startDayHour, endDayHour, hoursInterval); } - getGroupBounds(coordinates) { + getGroupBounds( + coordinates: WorkspaceCoordinates, + ): GroupBoundsOffset | undefined { const groupBounds = this.groupedStrategy instanceof VerticalGroupedStrategy - ? this.getGroupBoundsVertical(coordinates.groupIndex) + ? this.getGroupBoundsVertical(coordinates.groupIndex ?? 0) : this.getGroupBoundsHorizontal(coordinates); - return this.isRTL() + return this.isRTL() && groupBounds ? this.getGroupBoundsRtlCorrection(groupBounds) : groupBounds; } - getGroupBoundsVertical(groupIndex) { + getGroupBoundsVertical(groupIndex: number): GroupBoundsOffset | undefined { const $firstAndLastCells = this.getFirstAndLastDataTableCell(); - return this.groupedStrategy.getGroupBoundsOffset(groupIndex, $firstAndLastCells); + if (this.groupedStrategy instanceof VerticalGroupedStrategy) { + return this.groupedStrategy.getGroupBoundsOffset(groupIndex, [ + $firstAndLastCells[0], $firstAndLastCells[1], + ]); + } + return undefined; } - getGroupBoundsHorizontal(coordinates) { + getGroupBoundsHorizontal( + coordinates: WorkspaceCoordinates, + ): GroupBoundsOffset | undefined { const cellCount = this.getCellCount(); const $cells = this.getCells(); const cellWidth = this.getCellWidth(); const { groupedDataMap } = this.viewDataProvider; - return this.groupedStrategy - .getGroupBoundsOffset(cellCount, $cells, cellWidth, coordinates, groupedDataMap); + if (this.groupedStrategy instanceof HorizontalGroupedStrategy) { + return this.groupedStrategy + .getGroupBoundsOffset(cellCount, $cells, cellWidth, coordinates, groupedDataMap); + } + return undefined; } - getGroupBoundsRtlCorrection(groupBounds) { + getGroupBoundsRtlCorrection(groupBounds: GroupBoundsOffset): GroupBoundsOffset { const cellWidth = this.getCellWidth(); return { @@ -1804,39 +1965,48 @@ class SchedulerWorkSpace extends Widget { }; } - needRecalculateResizableArea() { + needRecalculateResizableArea(): boolean { return this.isVerticalGroupedWorkSpace() && this.getScrollable().scrollTop() !== 0; } - getCellByCoordinates(coordinates, allDay) { + getCellByCoordinates( + coordinates: Coordinates, + allDay: boolean, + ): dxElementWrapper { const $cells = this.getCells(allDay); const cellIndex = this.getCellIndexByCoordinates(coordinates, allDay); return $cells.eq(cellIndex); } - getVisibleBounds() { // TODO - this method is only used by the Agenda - const result: any = {}; + // TODO - this method is only used by the Agenda + getVisibleBounds(): { + top: { hours: number; minutes: number }; + bottom: { hours: number; minutes: number }; + } { const $scrollable = this.getScrollable().$element(); const cellHeight = this.getCellHeight(); const scrolledCellCount = this.getScrollableScrollTop() / cellHeight; const totalCellCount = scrolledCellCount + getHeight($scrollable) / cellHeight; - result.top = { - hours: Math.floor(scrolledCellCount * (this.option('hoursInterval') as any)) + (this.option('startDayHour') as any), - minutes: scrolledCellCount % 2 ? 30 : 0, - }; - - result.bottom = { - hours: Math.floor(totalCellCount * (this.option('hoursInterval') as any)) + (this.option('startDayHour') as any), - minutes: Math.floor(totalCellCount) % 2 ? 30 : 0, + const result = { + top: { + hours: Math.floor(scrolledCellCount * this.option().hoursInterval) + + this.option().startDayHour, + minutes: scrolledCellCount % 2 ? 30 : 0, + }, + bottom: { + hours: Math.floor(totalCellCount * this.option().hoursInterval) + + this.option().startDayHour, + minutes: Math.floor(totalCellCount) % 2 ? 30 : 0, + }, }; return result; } - updateScrollPosition(date, appointmentGroupValues?: GroupValues, allDay = false) { - const newDate = this.timeZoneCalculator.createDate(date, 'toGrid'); + updateScrollPosition(date: Date, appointmentGroupValues?: GroupValues, allDay = false): void { + const newDate = this.timeZoneCalculator?.createDate(date, 'toGrid') ?? date; const inAllDayRow = allDay && this.isAllDayPanelVisible; if (this.needUpdateScrollPosition(newDate, appointmentGroupValues, inAllDayRow)) { @@ -1844,7 +2014,11 @@ class SchedulerWorkSpace extends Widget { } } - needUpdateScrollPosition(date, appointmentGroupValues?: GroupValues, inAllDayRow = false) { + needUpdateScrollPosition( + date: Date, + appointmentGroupValues?: GroupValues, + inAllDayRow = false, + ): boolean { const cells = this.getCellsInViewport(inAllDayRow); const groupIndex = this.isGroupsSpecified(appointmentGroupValues) ? this.getGroupIndexByGroupValues(appointmentGroupValues) @@ -1872,7 +2046,7 @@ class SchedulerWorkSpace extends Widget { }, true); } - private getCellsInViewport(inAllDayRow) { + private getCellsInViewport(inAllDayRow: boolean): dxElementWrapper[] { const $scrollable = this.getScrollable().$element(); const cellHeight = this.getCellHeight(); const cellWidth = this.getCellWidth(); @@ -1880,7 +2054,8 @@ class SchedulerWorkSpace extends Widget { const scrollableScrollTop = this.getScrollableScrollTop(); const scrollableScrollLeft = this.getScrollableScrollLeft(); - const fullScrolledRowCount = scrollableScrollTop / cellHeight - this.virtualScrollingDispatcher.topVirtualRowsCount; + const fullScrolledRowCount = scrollableScrollTop / cellHeight + - this.virtualScrollingDispatcher.topVirtualRowsCount; let scrolledRowCount = Math.floor(fullScrolledRowCount); if (scrollableScrollTop % cellHeight !== 0) { @@ -1898,10 +2073,10 @@ class SchedulerWorkSpace extends Widget { const columnCount = Math.floor(fullScrolledColumnCount + getWidth($scrollable) / cellWidth); const $cells = this.getAllCells(inAllDayRow); - const result: any = []; + const result: dxElementWrapper[] = []; - $cells.each(function (index) { - const $cell = $(this); + $cells.toArray().forEach((_, index) => { + const $cell = $cells.eq(index); const columnIndex = index % totalColumnCount; const rowIndex = index / totalColumnCount; @@ -1916,7 +2091,7 @@ class SchedulerWorkSpace extends Widget { return result; } - scrollTo(date: Date, groupValues?: RawGroupValues | GroupValues, allDay = false, throwWarning = true, align: 'start' | 'center' = 'center') { + scrollTo(date: Date, groupValues?: RawGroupValues | GroupValues, allDay = false, throwWarning = true, align: 'start' | 'center' = 'center'): void { if (!this.isValidScrollDate(date, throwWarning)) { return; } @@ -1936,7 +2111,7 @@ class SchedulerWorkSpace extends Widget { const $scrollable = scrollable.$element(); const cellWidth = this.getCellWidth(); - const offset = this.option('rtlEnabled') + const offset = this.option().rtlEnabled ? cellWidth : 0; const scrollableHeight = getHeight($scrollable); @@ -1952,7 +2127,8 @@ class SchedulerWorkSpace extends Widget { top = 0; } - if (this.option('templatesRenderAsynchronously')) { + if (this.option().templatesRenderAsynchronously) { + // eslint-disable-next-line no-restricted-globals setTimeout(() => { scrollable.scrollBy({ left, top }); }); @@ -1961,29 +2137,31 @@ class SchedulerWorkSpace extends Widget { } } - private isValidScrollDate(date, throwWarning = true) { - const viewOffset = this.option('viewOffset'); + private isValidScrollDate(date: Date, throwWarning = true): boolean { + const { viewOffset } = this.option(); const min = new Date(this.getStartViewDate().getTime() + viewOffset); const max = new Date(this.getEndViewDate().getTime() + viewOffset); if (date < min || date > max) { - throwWarning && errors.log('W1008', date); + if (throwWarning) { + errors.log('W1008', date); + } return false; } return true; } - needApplyCollectorOffset() { + needApplyCollectorOffset(): boolean { return false; } - removeDroppableCellClass($cellElement?: any) { - const $cell = $cellElement || this.getDroppableCell(); + removeDroppableCellClass($cellElement?: dxElementWrapper): void { + const $cell = $cellElement ?? this.getDroppableCell(); $cell?.removeClass(DATE_TABLE_DROPPABLE_CELL_CLASS); } - private getCoordinatesByCell($cell) { + private getCoordinatesByCell($cell: dxElementWrapper): CellPositionData { const columnIndex = $cell.index() - this.virtualScrollingDispatcher.leftVirtualCellsCount; let rowIndex = $cell.parent().index(); const isAllDayCell = this.hasAllDayClass($cell); @@ -1996,21 +2174,21 @@ class SchedulerWorkSpace extends Widget { return { rowIndex, columnIndex }; } - private isShowAllDayPanel() { - return this.option('showAllDayPanel'); + private isShowAllDayPanel(): boolean { + return this.option().showAllDayPanel; } - protected getTimePanelCells() { - return (this.$element() as any).find(`.${TIME_PANEL_CELL_CLASS}`); + protected getTimePanelCells(): dxElementWrapper { + return this.$element().find(`.${TIME_PANEL_CELL_CLASS}`); } - protected getRDateTableProps() { + protected getRDateTableProps(): Record { return { viewData: this.viewDataProvider.viewData, viewContext: this.getR1ComponentsViewContext(), - dataCellTemplate: this.option('dataCellTemplate'), - addDateTableClass: !this.option('crossScrollingEnabled') || this.isVirtualScrolling(), - groupOrientation: this.option('groupOrientation'), + dataCellTemplate: this.option().dataCellTemplate, + addDateTableClass: !this.option().crossScrollingEnabled || this.isVirtualScrolling(), + groupOrientation: this.option().groupOrientation, addVerticalSizesClassToRows: false, }; } @@ -2020,26 +2198,38 @@ class SchedulerWorkSpace extends Widget { view: { type: this.type, }, - crossScrollingEnabled: Boolean(this.option('crossScrollingEnabled')), + crossScrollingEnabled: Boolean(this.option().crossScrollingEnabled), }; } - // eslint-disable-next-line @typescript-eslint/no-unused-vars - private updateSelectedCellDataOption(selectedCellData, $nextFocusedCell?: any) { - this.option('selectedCellData', selectedCellData); - this.selectionChangedAction({ selectedCellData }); + private updateSelectedCellDataOption( + selectedCellData: NormalizedCellData[], + // eslint-disable-next-line @typescript-eslint/no-unused-vars + nextFocusedCell?: dxElementWrapper, + ): void { + this.option().selectedCellData = selectedCellData as ViewCellData[]; + this.selectionChangedAction?.({ + selectedCellData: selectedCellData as ViewCellData[], + }); } - private fireSelectionEndEvent() { - const selectedCellData = this.option('selectedCellData') ?? []; + private fireSelectionEndEvent(): void { + const selectedCellData = this.option().selectedCellData ?? []; if (selectedCellData.length > 0 && this.selectionEndAction) { this.selectionEndAction({ selectedCellData }); } } - private getCellByData(cellData) { + private getCellByData(cellData: NormalizedCellData | ViewCellData): dxElementWrapper | undefined { const { allDay } = cellData; - const position = this.viewDataProvider.findCellPositionInMap(cellData); + const position = this.viewDataProvider.findCellPositionInMap( + { + startDate: cellData.startDate, + allDay: cellData.allDay, + groupIndex: cellData.groupIndex, + index: cellData.index ?? 0, + }, + ); if (!position) { return undefined; @@ -2051,27 +2241,32 @@ class SchedulerWorkSpace extends Widget { } // Must replace all DOM manipulations - getDOMElementsMetaData() { + getDOMElementsMetaData(): DOMMetaData { return this.cache.memo('cellElementsMeta', () => ({ dateTableCellsMeta: this.getDateTableDOMElementsInfo(), allDayPanelCellsMeta: this.getAllDayPanelDOMElementsInfo(), })); } - getPanelDOMSize(panelName: 'allDayPanel' | 'regularPanel'): { width: number; height: number } { + getPanelDOMSize(panelName: PanelName): RealSize { + const getElementSize = (element: Element | undefined): RealSize => { + const { width, height } = getBoundingRect(element) as Pick; + return { width, height }; + }; + return panelName === 'allDayPanel' - ? this.cache.memo('allDayPanelSize', () => getBoundingRect(this.$allDayPanel.get(0))) - : this.cache.memo('regularPanelSize', () => getBoundingRect(this.getDateTable().get(0))); + ? this.cache.memo('allDayPanelSize', () => getElementSize(this.$allDayPanel.get(0))) + : this.cache.memo('regularPanelSize', () => getElementSize(this.getDateTable().get(0))); } - getCollectorDimension(isCollectorCompact: boolean, panelName: 'allDayPanel' | 'regularPanel') { + getCollectorDimension(isCollectorCompact: boolean, panelName: PanelName): CollectorCSS { return this.cache.memo(`collectorSize-${panelName}`, () => CompactAppointmentsHelper.measureCollectorDimensions( panelName === 'allDayPanel' ? this.getAllDayContainer() : this.getFixedContainer(), isCollectorCompact, )); } - private getDateTableDOMElementsInfo() { + private getDateTableDOMElementsInfo(): CellRect[][] { const dateTableCells = this.getAllCells(false); if (!dateTableCells.length || !hasWindow()) { return [[{ @@ -2085,9 +2280,9 @@ class SchedulerWorkSpace extends Widget { const columnsCount = this.viewDataProvider.getColumnsCount(); - const result: any = []; + const result: CellRect[][] = []; - dateTableCells.each((index, cell) => { + dateTableCells.toArray().forEach((cell, index) => { const rowIndex = Math.floor(index / columnsCount); if (result.length === rowIndex) { @@ -2100,7 +2295,7 @@ class SchedulerWorkSpace extends Widget { return result; } - private getAllDayPanelDOMElementsInfo() { + private getAllDayPanelDOMElementsInfo(): CellRect[] { const result = []; if (this.isAllDayPanelVisible && !this.isVerticalGroupedWorkSpace() && hasWindow()) { @@ -2115,7 +2310,7 @@ class SchedulerWorkSpace extends Widget { const allDayAppointmentContainer = this.$allDayPanel; const allDayPanelRect = getBoundingRect(allDayAppointmentContainer.get(0)); - allDayCells.each((_, cell) => { + allDayCells.toArray().forEach((cell) => { this.addCellMetaData(result, cell, allDayPanelRect); }); } @@ -2123,7 +2318,11 @@ class SchedulerWorkSpace extends Widget { return result; } - private addCellMetaData(cellMetaDataArray, cell, parentRect) { + private addCellMetaData( + cellMetaDataArray: CellRect[], + cell: Element, + parentRect: Coordinates, + ): void { const cellRect = getBoundingRect(cell); cellMetaDataArray.push({ @@ -2143,7 +2342,7 @@ class SchedulerWorkSpace extends Widget { timePanel, dateTable, allDayPanel, - }: RenderComponentOptions = DEFAULT_WORKSPACE_RENDER_OPTIONS.renderComponents) { + }: RenderComponentOptions = DEFAULT_WORKSPACE_RENDER_OPTIONS.renderComponents): void { if (header) { this.renderRHeaderPanel(); } @@ -2161,7 +2360,7 @@ class SchedulerWorkSpace extends Widget { } } - renderRDateTable() { + renderRDateTable(): void { utils.renovation.renderComponent( this, this.$dateTable, @@ -2171,34 +2370,37 @@ class SchedulerWorkSpace extends Widget { ); } - renderRGroupPanel() { + renderRGroupPanel(): void { const options = { viewContext: this.getR1ComponentsViewContext(), - groups: this.option('groups'), - groupOrientation: this.option('groupOrientation'), + groups: this.option().groups, + groupOrientation: this.option().groupOrientation, groupByDate: this.isGroupedByDate(), - resourceCellTemplate: this.option('resourceCellTemplate'), + resourceCellTemplate: this.option().resourceCellTemplate, className: this.verticalGroupTableClass, groupPanelData: this.viewDataProvider.getGroupPanelData( this.generateRenderOptions(), ), }; - if (this.option('groups')?.length) { + if (this.option().groups?.length) { this.attachGroupCountClass(); - utils.renovation.renderComponent( - this, - this.getGroupHeaderContainer(), - GroupPanelComponent, - 'renovatedGroupPanel', - options, - ); + const $groupHeaderContainer = this.getGroupHeaderContainer(); + if ($groupHeaderContainer) { + utils.renovation.renderComponent( + this, + $groupHeaderContainer, + GroupPanelComponent, + 'renovatedGroupPanel', + options, + ); + } } else { this.detachGroupCountClass(); } } - renderRAllDayPanel() { + renderRAllDayPanel(): void { const visible = this.isAllDayPanelVisible && !this.isGroupedAllDayPanel(); if (visible) { @@ -2207,12 +2409,14 @@ class SchedulerWorkSpace extends Widget { const options = { viewData: this.viewDataProvider.viewData, viewContext: this.getR1ComponentsViewContext(), - dataCellTemplate: this.option('dataCellTemplate'), + dataCellTemplate: this.option().dataCellTemplate, startCellIndex: 0, - ...this.virtualScrollingDispatcher.horizontalVirtualScrolling?.getRenderState() || {}, + ...(this.virtualScrollingDispatcher.horizontalVirtualScrolling?.getRenderState() ?? {}), }; - utils.renovation.renderComponent(this, this.$allDayTable, AllDayTableComponent, 'renovatedAllDayPanel', options); + if (this.$allDayTable) { + utils.renovation.renderComponent(this, this.$allDayTable, AllDayTableComponent, 'renovatedAllDayPanel', options); + } utils.renovation.renderComponent(this, this.$allDayTitle, AllDayPanelTitleComponent, 'renovatedAllDayPanelTitle', {}); } @@ -2220,7 +2424,7 @@ class SchedulerWorkSpace extends Widget { this.updateScrollable(); } - renderRTimeTable() { + renderRTimeTable(): void { utils.renovation.renderComponent( this, this.$timePanel, @@ -2229,14 +2433,14 @@ class SchedulerWorkSpace extends Widget { { viewContext: this.getR1ComponentsViewContext(), timePanelData: this.viewDataProvider.timePanelData, - timeCellTemplate: this.option('timeCellTemplate'), - groupOrientation: this.option('groupOrientation'), + timeCellTemplate: this.option().timeCellTemplate, + groupOrientation: this.option().groupOrientation, }, ); } - renderRHeaderPanel(isRenderDateHeader = true) { - if (this.option('groups')?.length) { + renderRHeaderPanel(isRenderDateHeader = true): void { + if (this.option().groups?.length) { this.attachGroupCountClass(); } else { this.detachGroupCountClass(); @@ -2253,12 +2457,12 @@ class SchedulerWorkSpace extends Widget { groupPanelData: this.viewDataProvider.getGroupPanelData( this.generateRenderOptions(), ), - dateCellTemplate: this.option('dateCellTemplate'), - timeCellTemplate: this.option('timeCellTemplate'), - groups: this.option('groups'), + dateCellTemplate: this.option().dateCellTemplate, + timeCellTemplate: this.option().timeCellTemplate, + groups: this.option().groups, groupByDate: this.isGroupedByDate(), - groupOrientation: this.option('groupOrientation'), - resourceCellTemplate: this.option('resourceCellTemplate'), + groupOrientation: this.option().groupOrientation, + resourceCellTemplate: this.option().resourceCellTemplate, isRenderDateHeader, }, ); @@ -2270,7 +2474,8 @@ class SchedulerWorkSpace extends Widget { } const point = this.getPointFromDragTarget($dragTarget); - const elements = (domAdapter as any).elementsFromPoint(point.x, point.y); + // @ts-expect-error + const elements = domAdapter.elementsFromPoint(point.x, point.y) as Element[]; const cell = elements.find((element) => element.classList.contains('dx-scheduler-date-table-cell') || element.classList.contains('dx-scheduler-all-day-table-cell')); @@ -2278,7 +2483,7 @@ class SchedulerWorkSpace extends Widget { return cell ? $(cell) : null; } - private getPointFromDragTarget($dragTarget: dxElementWrapper): { x: number; y: number } { + private getPointFromDragTarget($dragTarget: dxElementWrapper): TranslateVector { const THRESHOLD = 10; const dragElementContainer = $dragTarget.get(0); @@ -2313,7 +2518,7 @@ class SchedulerWorkSpace extends Widget { // ------------ // TODO: dragBehavior when old impl is removed - initDragBehavior(scheduler) { + initDragBehavior(scheduler: { element: () => Element }): void { if (!this.dragBehavior && scheduler) { this.dragBehavior = new AppointmentDragBehavior(scheduler); @@ -2326,9 +2531,19 @@ class SchedulerWorkSpace extends Widget { } } - private createDragBehavior($targetElement, $rootElement) { - const getItemData = (itemElement, appointments) => appointments._getItemData(itemElement); - const getItemSettings = ($itemElement) => $itemElement.data(APPOINTMENT_SETTINGS_KEY); + private createDragBehavior( + $targetElement: dxElementWrapper, + $rootElement: dxElementWrapper, + ): void { + const getItemData = ( + itemElement: Element | dxElementWrapper, + appointments: AppointmentsList, + ): unknown => appointments._getItemData(itemElement); + + const getItemSettings = ( + $itemElement: dxElementWrapper, + ): AppointmentViewModelPlain => ( + $itemElement.data(APPOINTMENT_SETTINGS_KEY) as unknown as AppointmentViewModelPlain); const options = { getItemData, @@ -2338,21 +2553,30 @@ class SchedulerWorkSpace extends Widget { this.createDragBehaviorBase($targetElement, $rootElement, options); } - protected createDragBehaviorBase(targetElement, rootElement, options) { - const container = (this.$element() as any).find(`.${FIXED_CONTAINER_CLASS}`); + protected createDragBehaviorBase( + targetElement: dxElementWrapper, + rootElement: dxElementWrapper, + options: DragBehaviorOptions, + ): void { + const container = this.$element().find(`.${FIXED_CONTAINER_CLASS}`); - const disableDefaultDragging = () => { + const disableDefaultDragging = (): void => { if (!this.isDefaultDraggingMode) { this.preventDefaultDragging = true; } }; - const enableDefaultDragging = () => { + const enableDefaultDragging = (): void => { if (!this.isDefaultDraggingMode) { this.preventDefaultDragging = false; } }; + if (!this.dragBehavior) { + return; + } + + // eslint-disable-next-line @typescript-eslint/no-use-before-define this.dragBehavior.addTo(targetElement, createDragBehaviorConfig( container, rootElement, @@ -2372,24 +2596,27 @@ class SchedulerWorkSpace extends Widget { // We do not need these methods in renovation // -------------- - protected isRenderHeaderPanelEmptyCell() { + protected isRenderHeaderPanelEmptyCell(): boolean { return this.isVerticalGroupedWorkSpace(); } - _dispose() { - // @ts-expect-error + _dispose(): void { super._dispose(); if (this.documentPointerUpHandler) { - (eventsEngine.off as any)(domAdapter.getDocument(), SCHEDULER_TABLE_DXPOINTERUP_EVENT_NAME, this.documentPointerUpHandler); + eventsEngine.off( + domAdapter.getDocument(), + SCHEDULER_TABLE_DXPOINTERUP_EVENT_NAME, + this.documentPointerUpHandler, + ); this.documentPointerUpHandler = undefined; } this.virtualScrollingDispatcher.dispose(); } _getDefaultOptions(): WorkspaceOptionsInternal { - // @ts-expect-error - const defaultOptions = extend(super._getDefaultOptions(), { + const defaultOptions: WorkspaceOptionsInternal = { + ...super._getDefaultOptions(), currentDate: new Date(), intervalCount: 1, startDate: null, @@ -2403,7 +2630,7 @@ class SchedulerWorkSpace extends Widget { groups: [], showAllDayPanel: true, allDayExpanded: false, - onCellClick: null, + onCellClick: undefined, crossScrollingEnabled: false, dataCellTemplate: null, timeCellTemplate: null, @@ -2421,7 +2648,6 @@ class SchedulerWorkSpace extends Widget { mode: 'standard', }, allDayPanelMode: 'all', - height: undefined, draggingMode: 'outlook', onScrollEnd: noop, getHeaderHeight: undefined, @@ -2431,7 +2657,7 @@ class SchedulerWorkSpace extends Widget { timeZoneCalculator: undefined, schedulerHeight: undefined, schedulerWidth: undefined, - }); + }; return defaultOptions; } @@ -2508,7 +2734,6 @@ class SchedulerWorkSpace extends Widget { this.renderAppointments(); break; case 'width': - // @ts-expect-error super._optionChanged(args); this._dimensionChanged(); break; @@ -2525,31 +2750,29 @@ class SchedulerWorkSpace extends Widget { this.virtualScrollingDispatcher.updateDimensions(true); break; default: - // @ts-expect-error super._optionChanged(args); } } - updateShowAllDayPanel() { - const isHiddenAllDayPanel = this.option('allDayPanelMode') === 'hidden'; - (this.option('onShowAllDayPanel') as any)(!isHiddenAllDayPanel); + updateShowAllDayPanel(): void { + const isHiddenAllDayPanel = this.option().allDayPanelMode === 'hidden'; + this.option().onShowAllDayPanel(!isHiddenAllDayPanel); } - private getVirtualScrollingDispatcherOptions() { + private getVirtualScrollingDispatcherOptions(): VirtualScrollingDispatcherOptions { return { getCellHeight: this.getCellHeight.bind(this), getCellWidth: this.getCellWidth.bind(this), getCellMinWidth: this.getCellMinWidth.bind(this), isRTL: this.isRTL.bind(this), - getSchedulerHeight: () => this.option('schedulerHeight'), - getSchedulerWidth: () => this.option('schedulerWidth'), - getViewHeight: () => ((this.$element() as any).height ? (this.$element() as any).height() : getHeight(this.$element())), - getViewWidth: () => ((this.$element() as any).width ? (this.$element() as any).width() : getWidth(this.$element())), + getSchedulerHeight: () => this.option().schedulerHeight, + getSchedulerWidth: () => this.option().schedulerWidth, + getViewHeight: () => getHeight(this.$element()) as number, + getViewWidth: () => getWidth(this.$element()) as number, getWindowHeight: () => getWindow().innerHeight, getWindowWidth: () => getWindow().innerWidth, - getScrolling: () => this.option('scrolling'), + getScrolling: (): WorkspaceOptionsInternal['scrolling'] => this.option().scrolling, getScrollableOuterWidth: this.getScrollableOuterWidth.bind(this), - getScrollable: this.getScrollable.bind(this), createAction: this._createAction.bind(this), updateRender: this.updateRender.bind(this), updateGrid: this.updateGrid.bind(this), @@ -2560,23 +2783,24 @@ class SchedulerWorkSpace extends Widget { }; } - protected cleanWorkSpace() { + protected cleanWorkSpace(): void { this.cleanView(); this.toggleGroupedClass(); this.toggleWorkSpaceWithOddCells(); this.virtualScrollingDispatcher.updateDimensions(true); this.renderView(); - this.option('crossScrollingEnabled') && this.setTableSizes(); + if (this.option().crossScrollingEnabled) { + this.setTableSizes(); + } this.cache.clear(); } - _init() { + _init(): void { this.scrollSync = {}; this.viewDataProviderValue = null; this.cellsSelectionStateValue = null; - // @ts-expect-error super._init(); this.initGrouping(); @@ -2586,16 +2810,16 @@ class SchedulerWorkSpace extends Widget { this.toggleGroupByDateClass(); this.toggleWorkSpaceWithOddCells(); - (this.$element() as any) + this.$element() .addClass(COMPONENT_CLASS) .addClass(this.getElementClass()); } - private initPositionHelper() { + private initPositionHelper(): void { this.positionHelper = new PositionHelper({ viewDataProvider: this.viewDataProvider, isGroupedByDate: this.isGroupedByDate(), - rtlEnabled: this.option('rtlEnabled'), + rtlEnabled: this.option().rtlEnabled, isVerticalGrouping: this.isVerticalGroupedWorkSpace(), groupCount: this.getGroupCount(), isVirtualScrolling: this.isVirtualScrolling(), @@ -2603,21 +2827,21 @@ class SchedulerWorkSpace extends Widget { }); } - private initGrouping() { + private initGrouping(): void { this.initGroupedStrategy(); this.toggleGroupingDirectionClass(); this.toggleGroupByDateClass(); } - isVerticalOrientation() { - const orientation = this.option('groups')?.length - ? this.option('groupOrientation') + isVerticalOrientation(): boolean { + const orientation = this.option().groups?.length + ? this.option().groupOrientation : this.getDefaultGroupStrategy(); return orientation === 'vertical'; } - private initGroupedStrategy() { + private initGroupedStrategy(): void { const Strategy = this.isVerticalOrientation() ? VerticalGroupedStrategy : HorizontalGroupedStrategy; @@ -2647,54 +2871,73 @@ class SchedulerWorkSpace extends Widget { getCellIndexByCoordinates: (coordinates) => this.getCellIndexByCoordinates(coordinates), supportAllDayRow: () => this.supportAllDayRow(), isGroupedByDate: () => this.isGroupedByDate(), - showAllDayPanel: () => this.option('showAllDayPanel'), - startDayHour: () => this.option('startDayHour'), - endDayHour: () => this.option('endDayHour'), - hoursInterval: () => this.option('hoursInterval'), - crossScrollingEnabled: () => this.option('crossScrollingEnabled'), - rtlEnabled: () => this.option('rtlEnabled'), - getHeaderHeight: () => this.option('getHeaderHeight')?.() ?? 0, + showAllDayPanel: () => this.option().showAllDayPanel, + startDayHour: () => this.option().startDayHour, + endDayHour: () => this.option().endDayHour, + hoursInterval: () => this.option().hoursInterval, + crossScrollingEnabled: () => this.option().crossScrollingEnabled, + rtlEnabled: () => this.option().rtlEnabled, + getHeaderHeight: () => this.option().getHeaderHeight?.() ?? 0, }; } - protected getDefaultGroupStrategy() { + protected getDefaultGroupStrategy(): GroupOrientation { return 'horizontal'; } - protected toggleHorizontalScrollClass() { - (this.$element() as any).toggleClass(WORKSPACE_WITH_BOTH_SCROLLS_CLASS, this.option('crossScrollingEnabled')); + protected toggleHorizontalScrollClass(): void { + this.$element().toggleClass( + WORKSPACE_WITH_BOTH_SCROLLS_CLASS, + this.option().crossScrollingEnabled, + ); } - private toggleGroupByDateClass() { - (this.$element() as any).toggleClass(WORKSPACE_WITH_GROUP_BY_DATE_CLASS, this.isGroupedByDate()); + private toggleGroupByDateClass(): void { + this.$element().toggleClass(WORKSPACE_WITH_GROUP_BY_DATE_CLASS, this.isGroupedByDate()); } - private toggleWorkSpaceCountClass() { - (this.$element() as any).toggleClass(WORKSPACE_WITH_COUNT_CLASS, this.isWorkSpaceWithCount()); + private toggleWorkSpaceCountClass(): void { + this.$element().toggleClass(WORKSPACE_WITH_COUNT_CLASS, this.isWorkSpaceWithCount()); } - protected toggleWorkSpaceWithOddCells() { - (this.$element() as any).toggleClass(WORKSPACE_WITH_ODD_CELLS_CLASS, this.isWorkspaceWithOddCells()); + protected toggleWorkSpaceWithOddCells(): void { + this.$element().toggleClass(WORKSPACE_WITH_ODD_CELLS_CLASS, this.isWorkspaceWithOddCells()); } - protected toggleGroupingDirectionClass() { - (this.$element() as any).toggleClass(VERTICAL_GROUPED_WORKSPACE_CLASS, this.isVerticalGroupedWorkSpace()); + protected toggleGroupingDirectionClass(): void { + this.$element().toggleClass( + VERTICAL_GROUPED_WORKSPACE_CLASS, + this.isVerticalGroupedWorkSpace(), + ); } - protected getDateTableCellClass(rowIndex?: any, columnIndex?: any) { + protected getDateTableCellClass(rowIndex?: number, columnIndex?: number): string { const cellClass = `${DATE_TABLE_CELL_CLASS} ${HORIZONTAL_SIZES_CLASS} ${VERTICAL_SIZES_CLASS}`; + if (rowIndex === undefined && columnIndex === undefined) { + return cellClass; + } + return this.groupedStrategy - .addAdditionalGroupCellClasses(cellClass, columnIndex + 1, rowIndex, columnIndex); + .addAdditionalGroupCellClasses( + cellClass, + (columnIndex ?? 0) + 1, + rowIndex ?? 0, + columnIndex ?? 0, + ); } - protected getGroupHeaderClass(i?: any) { + protected getGroupHeaderClass(i?: number): string { const cellClass = GROUP_HEADER_CLASS; - return this.groupedStrategy.addAdditionalGroupCellClasses(cellClass, i + 1); + if (i === undefined) { + return cellClass; + } + + return this.groupedStrategy.addAdditionalGroupCellClasses(cellClass, i + 1, 0, 0); } - protected initWorkSpaceUnits() { + protected initWorkSpaceUnits(): void { this.$headerPanelContainer = $('
').addClass('dx-scheduler-header-panel-container'); this.$headerTablesContainer = $('
').addClass('dx-scheduler-header-tables-container'); this.$headerPanel = $('
').attr('aria-hidden', true); @@ -2717,37 +2960,38 @@ class SchedulerWorkSpace extends Widget { this.$groupTable = $('
').addClass(WORKSPACE_VERTICAL_GROUP_TABLE_CLASS); } - private initAllDayPanelElements() { - this.allDayTitles = []; + private initAllDayPanelElements(): void { this.allDayTables = []; - this.allDayPanels = []; } - private initDateTableScrollable() { + private initDateTableScrollable(): void { const $dateTableScrollable = $('
').addClass(SCHEDULER_DATE_TABLE_SCROLLABLE_CLASS); - // @ts-expect-error - this.$dateTableScrollable = this._createComponent($dateTableScrollable, Scrollable, this.dateTableScrollableConfig()); + this.$dateTableScrollable = this._createComponent( + $dateTableScrollable, + Scrollable, + this.dateTableScrollableConfig(), + ); this.scrollSync.dateTable = getMemoizeScrollTo(() => this.$dateTableScrollable); } - protected createWorkSpaceElements() { - if (this.option('crossScrollingEnabled')) { + protected createWorkSpaceElements(): void { + if (this.option().crossScrollingEnabled) { this.createWorkSpaceScrollableElements(); } else { this.createWorkSpaceStaticElements(); } } - protected createWorkSpaceStaticElements() { + protected createWorkSpaceStaticElements(): void { this.$dateTableContainer.append(this.$dateTable); if (this.isVerticalGroupedWorkSpace()) { this.$dateTableContainer.append(this.$allDayContainer); this.$dateTableScrollableContent.append( - this.$groupTable, - this.$timePanel, - this.$dateTableContainer, + [this.$groupTable, + this.$timePanel, + this.$dateTableContainer].filter(Boolean) as dxElementWrapper[], ); this.$dateTableScrollable.$content().append( this.$dateTableScrollableContent, @@ -2756,13 +3000,16 @@ class SchedulerWorkSpace extends Widget { this.$headerTablesContainer.append(this.$headerPanel); } else { this.$dateTableScrollableContent.append( - this.$timePanel, - this.$dateTableContainer, + [this.$timePanel, this.$dateTableContainer], ); this.$dateTableScrollable.$content().append(this.$dateTableScrollableContent); - this.$headerTablesContainer.append(this.$headerPanel, this.$allDayPanel); - this.$allDayPanel?.append(this.$allDayContainer, this.$allDayTable); + this.$headerTablesContainer.append([this.$headerPanel, this.$allDayPanel]); + if (this.$allDayPanel) { + this.$allDayPanel.append( + [this.$allDayContainer, this.$allDayTable].filter(Boolean) as dxElementWrapper[], + ); + } } this.appendHeaderPanelEmptyCellIfNecessary(); @@ -2774,7 +3021,7 @@ class SchedulerWorkSpace extends Widget { .append(this.$dateTableScrollable.$element()); } - protected createWorkSpaceScrollableElements() { + protected createWorkSpaceScrollableElements(): void { this.$element().append(this.$fixedContainer); this.$flexContainer = $('
').addClass('dx-scheduler-work-space-flex-container'); @@ -2798,36 +3045,46 @@ class SchedulerWorkSpace extends Widget { if (this.isVerticalGroupedWorkSpace()) { this.$dateTableContainer.append(this.$allDayContainer); - this.$sidebarScrollableContent.append(this.$groupTable, this.$timePanel); + this.$sidebarScrollableContent.append( + [this.$groupTable, this.$timePanel].filter(Boolean) as dxElementWrapper[], + ); } else { this.headerScrollable.$content().append(this.$allDayPanel); - this.$allDayPanel?.append(this.$allDayContainer, this.$allDayTable); + if (this.$allDayPanel) { + this.$allDayPanel.append( + [this.$allDayContainer, this.$allDayTable].filter(Boolean) as dxElementWrapper[], + ); + } this.$sidebarScrollableContent.append(this.$timePanel); } this.$sidebarScrollable.$content().append(this.$sidebarScrollableContent); } - private appendHeaderPanelEmptyCellIfNecessary() { - this.isRenderHeaderPanelEmptyCell() && this.$headerPanelContainer.append(this.$headerPanelEmptyCell); + private appendHeaderPanelEmptyCellIfNecessary(): void { + if (this.isRenderHeaderPanelEmptyCell()) { + this.$headerPanelContainer.append(this.$headerPanelEmptyCell); + } } - private createHeaderScrollable() { + private createHeaderScrollable(): void { const $headerScrollable = $('
') .addClass(SCHEDULER_HEADER_SCROLLABLE_CLASS) .appendTo(this.$headerTablesContainer); - // @ts-expect-error - this.headerScrollable = this._createComponent($headerScrollable, Scrollable, this.headerScrollableConfig()); + this.headerScrollable = this._createComponent( + $headerScrollable, + Scrollable, + this.headerScrollableConfig(), + ); this.scrollSync.header = getMemoizeScrollTo(() => this.headerScrollable); } - private createSidebarScrollable() { + private createSidebarScrollable(): void { const $timePanelScrollable = $('
') .addClass(SCHEDULER_SIDEBAR_SCROLLABLE_CLASS) .appendTo(this.$flexContainer); - // @ts-expect-error this.$sidebarScrollable = this._createComponent($timePanelScrollable, Scrollable, { useKeyboard: false, showScrollbar: 'never', @@ -2836,33 +3093,35 @@ class SchedulerWorkSpace extends Widget { updateManually: true, bounceEnabled: false, onScroll: (event) => { - this.scrollSync.dateTable({ top: event.scrollOffset.top }); + this.scrollSync.dateTable?.({ top: event.scrollOffset.top }); }, }); this.scrollSync.sidebar = getMemoizeScrollTo(() => this.$sidebarScrollable); } - private attachTableClasses() { + private attachTableClasses(): void { this.addTableClass(this.$dateTable, DATE_TABLE_CLASS); if (this.isVerticalGroupedWorkSpace()) { const groupCount = this.getGroupCount(); - for (let i = 0; i < groupCount; i++) { + for (let i = 0; i < groupCount; i += 1) { this.addTableClass(this.allDayTables[i], ALL_DAY_TABLE_CLASS); } } } - private attachHeaderTableClasses() { + private attachHeaderTableClasses(): void { this.addTableClass(this.$headerPanel, HEADER_PANEL_CLASS); } - private addTableClass($el, className) { - ($el && !$el.hasClass(className)) && $el.addClass(className); + private addTableClass($el: dxElementWrapper | undefined, className: string): void { + if ($el && !$el.hasClass(className)) { + $el.addClass(className); + } } - _initMarkup() { + _initMarkup(): void { this.cache.clear(); this.initWorkSpaceUnits(); @@ -2873,10 +3132,9 @@ class SchedulerWorkSpace extends Widget { this.createWorkSpaceElements(); - // @ts-expect-error super._initMarkup(); - if (!this.option('crossScrollingEnabled')) { + if (!this.option().crossScrollingEnabled) { this.attachTableClasses(); this.attachHeaderTableClasses(); } @@ -2887,18 +3145,17 @@ class SchedulerWorkSpace extends Widget { this.attachEvents(); } - _render() { - // @ts-expect-error + _render(): void { super._render(); this.renderDateTimeIndication(); this.setIndicationUpdateInterval(); } - private toggleGroupedClass() { - (this.$element() as any).toggleClass(GROUPED_WORKSPACE_CLASS, this.getGroupCount() > 0); + private toggleGroupedClass(): void { + this.$element().toggleClass(GROUPED_WORKSPACE_CLASS, this.getGroupCount() > 0); } - protected renderView() { + protected renderView(): void { if (this.isVerticalGroupedWorkSpace()) { this.renderRGroupPanel(); } @@ -2912,7 +3169,7 @@ class SchedulerWorkSpace extends Widget { this.shader = new VerticalShader(this); } - updateCellsSelection() { + updateCellsSelection(): void { const renderOptions = this.generateRenderOptions(); this.viewDataProvider.updateViewData(renderOptions); this.renderRWorkSpace({ @@ -2922,28 +3179,30 @@ class SchedulerWorkSpace extends Widget { }); } - protected renderDateTimeIndication() { return noop(); } + protected renderDateTimeIndication(): void { return noop(); } protected renderCurrentDateTimeLineAndShader(): void { return noop(); } protected renderCurrentDateTimeIndication(): void { return noop(); } - protected setIndicationUpdateInterval() { return noop(); } + protected setIndicationUpdateInterval(): void { return noop(); } - protected detachGroupCountClass() { + protected detachGroupCountClass(): void { VERTICAL_GROUP_COUNT_CLASSES.forEach((className) => { this.$element().removeClass(className); }); } - protected attachGroupCountClass() { - const className = this.groupedStrategy.getGroupCountClass(this.option('groups')); + protected attachGroupCountClass(): void { + const className = this.groupedStrategy.getGroupCountClass(this.option().groups); - this.$element().addClass(className); + if (className) { + this.$element().addClass(className); + } } protected getDateHeaderTemplate(): TemplateBase | null | undefined { - return this.option('dateCellTemplate'); + return this.option().dateCellTemplate; } protected updateAllDayVisibility(): void { @@ -2952,21 +3211,23 @@ class SchedulerWorkSpace extends Widget { } private updateAllDayExpansion(): void { - const isExpanded = !this.option('allDayExpanded') && this.isShowAllDayPanel(); + const isExpanded = !this.option().allDayExpanded && this.isShowAllDayPanel(); this.cache.clear(); this.$element().toggleClass(WORKSPACE_WITH_COLLAPSED_ALL_DAY_CLASS, isExpanded); } - private getDateTables() { - return this.$dateTable.add(this.$allDayTable); + private getDateTables(): dxElementWrapper { + return this.$allDayTable + ? this.$dateTable.add(this.$allDayTable) + : this.$dateTable; } - private getDateTable() { + private getDateTable(): dxElementWrapper { return this.$dateTable; } - private removeAllDayElements() { + private removeAllDayElements(): void { this.$allDayTable?.remove(); this.$allDayTitle?.remove(); } @@ -2976,26 +3237,28 @@ class SchedulerWorkSpace extends Widget { this.cleanTableWidths(); this.cellsSelectionState.clearSelectedAndFocusedCells(); - this.shader?.clean(); + this.isCellClick = false; + this.showPopup = false; + this.interval = undefined; + this.isSelectionStartedOnCell = false; - delete this.interval; + this.shader?.clean(); } - _clean() { - (eventsEngine.off as any)(domAdapter.getDocument(), SCHEDULER_CELL_DXPOINTERUP_EVENT_NAME); + _clean(): void { + eventsEngine.off(domAdapter.getDocument(), SCHEDULER_CELL_DXPOINTERUP_EVENT_NAME); this.disposeRenovatedComponents(); - // @ts-expect-error super._clean(); } - private cleanTableWidths() { + private cleanTableWidths(): void { this.$headerPanel.css('width', ''); this.$dateTable.css('width', ''); this.$allDayTable?.css('width', ''); } - private disposeRenovatedComponents() { + private disposeRenovatedComponents(): void { this.renovatedAllDayPanel?.dispose(); this.renovatedAllDayPanel = undefined; @@ -3012,29 +3275,29 @@ class SchedulerWorkSpace extends Widget { this.renovatedHeaderPanel = undefined; } - getGroupedStrategy() { + getGroupedStrategy(): HorizontalGroupedStrategy | VerticalGroupedStrategy { return this.groupedStrategy; } - getFixedContainer() { + getFixedContainer(): dxElementWrapper { return this.$fixedContainer; } - getAllDayContainer() { + getAllDayContainer(): dxElementWrapper | null { return this.$allDayContainer; } - updateRender() { + updateRender(): void { this.renderer.updateRender(); } - updateGrid() { + updateGrid(): void { this.renderer._renderGrid(); } - renderAppointments() { - (this.option('renderAppointments') as any)(); - this.dragBehavior?.updateDragSource(); + renderAppointments(): void { + (this.option().renderAppointments)(); + this.dragBehavior?.updateDragSource(undefined, undefined); } renderWorkSpace({ @@ -3050,14 +3313,15 @@ class SchedulerWorkSpace extends Widget { this.initPositionHelper(); } - protected renderGroupHeader() { + protected renderGroupHeader(): (() => dxElementWrapper)[] { const $container = this.getGroupHeaderContainer(); const groupCount = this.getGroupCount(); let cellTemplates: (() => dxElementWrapper)[] = []; - if (groupCount) { - const groupRows = this.makeGroupRows(this.option('groups'), this.option('groupByDate')); + if (groupCount && $container) { + const groupRows = this.makeGroupRows(this.option().groups, this.option().groupByDate); this.attachGroupCountClass(); - $container.append(groupRows.elements); + const { elements } = groupRows; + $container.append(Array.isArray(elements) ? elements : elements.toArray()); cellTemplates = groupRows.cellTemplates; } else { this.detachGroupCountClass(); @@ -3066,14 +3330,15 @@ class SchedulerWorkSpace extends Widget { return cellTemplates; } - protected applyCellTemplates(templates) { + protected applyCellTemplates(templates: (() => void)[] | undefined): void { templates?.forEach((template) => { template(); }); } protected makeGroupRows(groups: ResourceLoader[], groupByDate: boolean): GroupRows { - const tableCreatorStrategy = this.isVerticalGroupedWorkSpace() ? tableCreator.VERTICAL : tableCreator.HORIZONTAL; + const tableCreatorStrategy = this.isVerticalGroupedWorkSpace() + ? tableCreator.VERTICAL : tableCreator.HORIZONTAL; return tableCreator.makeGroupedTable( tableCreatorStrategy, @@ -3085,13 +3350,16 @@ class SchedulerWorkSpace extends Widget { groupHeaderContentClass: GROUP_HEADER_CONTENT_CLASS, }, this.getCellCount() || 1, - this.option('resourceCellTemplate'), + this.option().resourceCellTemplate, this.getGroupCount(), groupByDate, ); } - protected getGroupsForDateHeaderTemplate(templateIndex, indexMultiplier = 1) { + protected getGroupsForDateHeaderTemplate(templateIndex: number, indexMultiplier = 1): { + groups?: RawGroupValues | GroupValues; + groupIndex?: number; + } { if (this.isHorizontalGroupedWorkSpace() && !this.isGroupedByDate()) { const groupIndex = this.getGroupIndex(0, templateIndex * indexMultiplier); const groups = getLeafGroupValues(this.resourceManager.groupsLeafs, groupIndex); @@ -3108,49 +3376,95 @@ class SchedulerWorkSpace extends Widget { protected getHeaderPanelCellClass(i: number): string { const cellClass = `${HEADER_PANEL_CELL_CLASS} ${HORIZONTAL_SIZES_CLASS}`; - return this.groupedStrategy.addAdditionalGroupCellClasses(cellClass, i + 1, undefined, undefined, this.isGroupedByDate()); + return this.groupedStrategy.addAdditionalGroupCellClasses( + cellClass, + i + 1, + 0, + 0, + this.isGroupedByDate(), + ); } - protected insertAllDayRowsIntoDateTable() { + protected insertAllDayRowsIntoDateTable(): boolean { return this.groupedStrategy.insertAllDayRowsIntoDateTable(); } } +type DomAdapterWithElementsFromPoint = typeof domAdapter & { + elementsFromPoint: (x: number, y: number, element?: Element) => Element[]; +}; + +const domAdapterExt = domAdapter as DomAdapterWithElementsFromPoint; + +interface AppointmentsList { + option: (name: string) => { length: number }; + _renderItem: (index: number, data: Record) => dxElementWrapper; + // eslint-disable-next-line @typescript-eslint/naming-convention + _getItemData: (element: Element | dxElementWrapper) => unknown; +} + +interface DragBehaviorOptions { + getItemData: (itemElement: Element | dxElementWrapper, appointments: AppointmentsList) => unknown; + getItemSettings: ( + $itemElement: dxElementWrapper, + e?: Record, + ) => AppointmentViewModelPlain; + initialPosition?: Coordinates; + isSetCursorOffset?: boolean; + filter?: string; +} + // TODO: remove dragBehavior when old impl is removed const createDragBehaviorConfig = ( - container, - rootElement, - isDefaultDraggingMode, - dragBehavior, - enableDefaultDragging, - disableDefaultDragging, - getDroppableCell, - getDateTables, - removeDroppableCellClass, - getCellWidth, - options, -) => { - const state: any = { + container: dxElementWrapper, + rootElement: dxElementWrapper, + isDefaultDraggingMode: boolean, + dragBehavior: AppointmentDragBehavior, + enableDefaultDragging: () => void, + disableDefaultDragging: () => void, + getDroppableCell: () => dxElementWrapper, + getDateTables: () => dxElementWrapper, + removeDroppableCellClass: () => void, + getCellWidthCallback: () => number, + options: DragBehaviorOptions, +): { + container: dxElementWrapper; + dragTemplate: () => dxElementWrapper | undefined; + onDragStart: (e: AppointmentDraggingStartEvent) => void; + onDragMove: () => void; + onDragEnd: (e: AppointmentDraggingEndEvent) => void; + onDragCancel: (e: AppointmentDraggingRemoveEvent) => void; + cursorOffset: (() => TranslateVector) | undefined; + filter: string | undefined; +} => { + const state: { + dragElement: dxElementWrapper | undefined; + itemData: unknown; + } = { dragElement: undefined, itemData: undefined, }; - const isItemDisabled = () => { + const isItemDisabled = (): boolean => { const { itemData } = state; if (itemData) { - const getter: any = compileGetter('disabled'); + const getter = compileGetter('disabled') as (obj: unknown) => boolean; return getter(itemData); } return true; }; - const createDragAppointment = (itemData, settings, appointments) => { + const createDragAppointment = ( + itemData: unknown, + settings: AppointmentViewModelPlain, + appointments: AppointmentsList, + ): dxElementWrapper => { const appointmentIndex = appointments.option('items').length; const $item = appointments._renderItem(appointmentIndex, { - itemData, ...settings, + itemData, isCompact: false, virtual: false, sortedIndex: -1, @@ -3159,44 +3473,49 @@ const createDragBehaviorConfig = ( return $item; }; - const onDragStart = (e) => { + const onDragStart = (e: AppointmentDraggingStartEvent): void => { if (!isDefaultDraggingMode) { disableDefaultDragging(); } + if (!e.event) { + return; + } + const canceled = e.cancel; - const { event } = e; - const $itemElement = $(e.itemElement); - const appointments = e.component._appointments; + const $itemElement = $(e.itemElement as Element | null); + // @ts-expect-error + const appointments = (e.component)._appointments as AppointmentsList; - state.itemData = options.getItemData(e.itemElement, appointments); + state.itemData = options.getItemData(e.itemElement as Element, appointments); const settings = options.getItemSettings($itemElement, e); const { initialPosition } = options; if (!isItemDisabled()) { - event.data = event.data || {}; + e.event.data = e.event.data ?? {}; if (!canceled) { - if (!settings.isCompact) { + if (!('isCompact' in settings && settings.isCompact)) { dragBehavior.updateDragSource(state.itemData, settings); } state.dragElement = createDragAppointment(state.itemData, settings, appointments); - event.data.itemElement = state.dragElement; - event.data.initialPosition = initialPosition ?? locate($(state.dragElement)); - event.data.itemData = state.itemData; - event.data.itemSettings = settings; + e.event.data.itemElement = state.dragElement; + e.event.data.initialPosition = initialPosition + ?? locate($(state.dragElement)); + e.event.data.itemData = state.itemData; + e.event.data.itemSettings = settings; - dragBehavior.onDragStart(event.data); + dragBehavior.onDragStart(e.event.data); resetPosition($(state.dragElement)); } } }; - const getElementsFromPoint = () => { + const getElementsFromPoint = (): Element[] => { const appointmentWidth = getWidth(state.dragElement); - const cellWidth = getCellWidth(); + const cellWidth = getCellWidthCallback(); const isWideAppointment = appointmentWidth > cellWidth; const isNarrowAppointment = appointmentWidth <= DRAGGING_MOUSE_FAULT; const dragElementContainer = $(state.dragElement).parent().get(0); @@ -3205,14 +3524,22 @@ const createDragBehaviorConfig = ( const newY = boundingRect.top; if (isWideAppointment) { - return (domAdapter as any).elementsFromPoint(newX + DRAGGING_MOUSE_FAULT, newY + DRAGGING_MOUSE_FAULT, dragElementContainer); + return domAdapterExt.elementsFromPoint( + newX + DRAGGING_MOUSE_FAULT, + newY + DRAGGING_MOUSE_FAULT, + dragElementContainer, + ); } if (isNarrowAppointment) { - return (domAdapter as any).elementsFromPoint(newX, newY, dragElementContainer); + return domAdapterExt.elementsFromPoint(newX, newY, dragElementContainer); } - return (domAdapter as any).elementsFromPoint(newX + appointmentWidth / 2, newY + DRAGGING_MOUSE_FAULT, dragElementContainer); + return domAdapterExt.elementsFromPoint( + newX + appointmentWidth / 2, + newY + DRAGGING_MOUSE_FAULT, + dragElementContainer, + ); }; - const onDragMove = () => { + const onDragMove = (): void => { if (isDefaultDraggingMode) { return; } @@ -3235,7 +3562,7 @@ const createDragBehaviorConfig = ( }); if (droppableCell) { - if (!getDroppableCell().is(droppableCell)) { + if (!getDroppableCell().is(droppableCell as unknown as dxElementWrapper)) { removeDroppableCellClass(); } @@ -3245,7 +3572,7 @@ const createDragBehaviorConfig = ( } }; - const onDragEnd = (e) => { + const onDragEnd = (e: AppointmentDraggingEndEvent): void => { if (!isDefaultDraggingMode) { enableDefaultDragging(); } @@ -3258,17 +3585,17 @@ const createDragBehaviorConfig = ( removeDroppableCellClass(); }; - const onDragCancel = (e) => { + const onDragCancel = (e: AppointmentDraggingRemoveEvent): void => { if (!isDefaultDraggingMode) { enableDefaultDragging(); } removeDroppableCellClass(); - e.itemElement?.removeClass?.(APPOINTMENT_DRAG_SOURCE_CLASS); + $(e.itemElement as Element).removeClass(APPOINTMENT_DRAG_SOURCE_CLASS); }; const cursorOffset = options.isSetCursorOffset - ? () => { + ? (): TranslateVector => { const $dragElement = $(state.dragElement); return { x: getWidth($dragElement) / 2, @@ -3279,7 +3606,7 @@ const createDragBehaviorConfig = ( return { container, - dragTemplate: () => state.dragElement, + dragTemplate: (): dxElementWrapper | undefined => state.dragElement, onDragStart, onDragMove, onDragEnd, diff --git a/packages/devextreme/js/__internal/scheduler/workspaces/work_space_day.ts b/packages/devextreme/js/__internal/scheduler/workspaces/work_space_day.ts index c74216859863..e1ff9f58f224 100644 --- a/packages/devextreme/js/__internal/scheduler/workspaces/work_space_day.ts +++ b/packages/devextreme/js/__internal/scheduler/workspaces/work_space_day.ts @@ -14,7 +14,7 @@ class SchedulerWorkSpaceDay extends SchedulerWorkSpaceVertical { } renderRHeaderPanel(): void { - if (this.option('intervalCount') === 1) { + if (this.option().intervalCount === 1) { super.renderRHeaderPanel(false); } else { super.renderRHeaderPanel(true); diff --git a/packages/devextreme/js/__internal/scheduler/workspaces/work_space_grouped_strategy_vertical.ts b/packages/devextreme/js/__internal/scheduler/workspaces/work_space_grouped_strategy_vertical.ts index 2367a0663f0e..4955162edf91 100644 --- a/packages/devextreme/js/__internal/scheduler/workspaces/work_space_grouped_strategy_vertical.ts +++ b/packages/devextreme/js/__internal/scheduler/workspaces/work_space_grouped_strategy_vertical.ts @@ -1,4 +1,3 @@ -import type { DxElement } from '@js/core/element'; import type { dxElementWrapper } from '@js/core/renderer'; import { getBoundingRect } from '@js/core/utils/position'; import { calculateDayDuration, getVerticalGroupCountClass } from '@ts/scheduler/r1/utils/index'; @@ -86,7 +85,7 @@ class VerticalGroupedStrategy { return this.config.getTimePanelWidth() + this.config.getGroupTableWidth(); } - getGroupBoundsOffset(groupIndex: number, [$firstCell, $lastCell]: [DxElement, DxElement]) + getGroupBoundsOffset(groupIndex: number, [$firstCell, $lastCell]: [Element, Element]) : GroupBoundsOffset { return this.cache.memo(`groupBoundsOffset${groupIndex}`, () => { const startDayHour = this.config.startDayHour(); diff --git a/packages/devextreme/js/__internal/scheduler/workspaces/work_space_indicator.ts b/packages/devextreme/js/__internal/scheduler/workspaces/work_space_indicator.ts index f16304fb5f15..56e321f777d8 100644 --- a/packages/devextreme/js/__internal/scheduler/workspaces/work_space_indicator.ts +++ b/packages/devextreme/js/__internal/scheduler/workspaces/work_space_indicator.ts @@ -13,7 +13,7 @@ import { HEADER_CURRENT_TIME_CELL_CLASS } from '../classes'; import timezoneUtils from '../utils_time_zone'; import SchedulerWorkSpace, { type WorkspaceOptionsInternal, -} from './m_work_space'; +} from './work_space'; const toMs = dateUtils.dateToMilliseconds; @@ -23,8 +23,8 @@ class SchedulerWorkSpaceIndicator extends SchedulerWorkSpace { private indicatorInterval?: ReturnType; protected getToday(): Date { - const viewOffset = this.option('viewOffset'); - const today = getToday(this.option('indicatorTime'), this.timeZoneCalculator); + const { viewOffset, indicatorTime } = this.option(); + const today = getToday(indicatorTime, this.timeZoneCalculator); return dateUtilsTs.addOffsets(today, -viewOffset); } @@ -91,7 +91,7 @@ class SchedulerWorkSpaceIndicator extends SchedulerWorkSpace { } protected setIndicationUpdateInterval(): void { - if (!this.option('showCurrentTimeIndicator') || this.option('indicatorUpdateInterval') === 0) { + if (!this.option().showCurrentTimeIndicator || this.option().indicatorUpdateInterval === 0) { return; } @@ -100,7 +100,7 @@ class SchedulerWorkSpaceIndicator extends SchedulerWorkSpace { // eslint-disable-next-line no-restricted-globals this.indicatorInterval = setInterval(() => { this.renderCurrentDateTimeIndication(); - }, this.option('indicatorUpdateInterval')); + }, this.option().indicatorUpdateInterval); } private clearIndicatorUpdateInterval(): void { @@ -135,7 +135,7 @@ class SchedulerWorkSpaceIndicator extends SchedulerWorkSpace { const viewStartTime = this.getStartViewDate().getTime(); let timeDiff = today.getTime() - viewStartTime; - if (((this.option('skippedDays')) ?? []).length > 0) { + if (((this.option().skippedDays) ?? []).length > 0) { const skippedDaysDuration = this.getSkippedDaysCount( this.getStartViewDate(), Math.round(timeDiff / toMs('day')), diff --git a/packages/devextreme/js/__internal/scheduler/workspaces/work_space_month.ts b/packages/devextreme/js/__internal/scheduler/workspaces/work_space_month.ts index ecfd0b78bf23..057442ddf883 100644 --- a/packages/devextreme/js/__internal/scheduler/workspaces/work_space_month.ts +++ b/packages/devextreme/js/__internal/scheduler/workspaces/work_space_month.ts @@ -9,7 +9,7 @@ import { formatWeekday, monthUtils } from '@ts/scheduler/r1/utils/index'; import { utils } from '../utils'; import { VIEWS } from '../utils/options/constants_view'; -import type { ViewDateGenerationOptions } from './m_work_space'; +import type { ViewDateGenerationOptions } from './work_space'; import SchedulerWorkSpace from './work_space_indicator'; const MONTH_CLASS = 'dx-scheduler-work-space-month'; @@ -30,7 +30,7 @@ class SchedulerWorkSpaceMonth extends SchedulerWorkSpace { protected override getIntervalBetween(currentDate: Date): number { const firstViewDate = this.getStartViewDate(); const timeZoneOffset = dateUtils.getTimezonesDifference(firstViewDate, currentDate); - const startDayHour = this.option('startDayHour'); + const { startDayHour } = this.option(); return currentDate.getTime() - (firstViewDate.getTime() - startDayHour * 3600000) @@ -56,14 +56,18 @@ class SchedulerWorkSpaceMonth extends SchedulerWorkSpace { let averageWidth = 0; const cells = this.getCells().slice(0, DAYS_IN_WEEK); - cells.each((index, element) => { - averageWidth += hasWindow() ? getBoundingRect(element).width : 0; - }); + + cells.each( + (index: number, element: Element): boolean => { + averageWidth += hasWindow() ? getBoundingRect(element).width : 0; + return true; + }, + ); return cells.length === 0 ? 0 : averageWidth / DAYS_IN_WEEK; }); - return cellWidth as number; + return cellWidth; } protected override insertAllDayRowsIntoDateTable(): boolean { @@ -83,15 +87,17 @@ class SchedulerWorkSpaceMonth extends SchedulerWorkSpace { } protected override needCreateCrossScrolling(): boolean { - return this.option('crossScrollingEnabled') || this.isVerticalGroupedWorkSpace(); + return this.option().crossScrollingEnabled || this.isVerticalGroupedWorkSpace(); } protected override getViewStartByOptions(): Date { + const startDate = this.option().startDate ?? undefined; + return monthUtils.getViewStartByOptions( - this.option('startDate'), - this.option('currentDate'), - this.option('intervalCount'), - dateUtils.getFirstMonthDate(this.option('startDate')) as Date, + startDate, + this.option().currentDate, + this.option().intervalCount, + startDate ? dateUtils.getFirstMonthDate(startDate) as Date : undefined, ); } diff --git a/packages/devextreme/js/__internal/scheduler/workspaces/work_space_week.ts b/packages/devextreme/js/__internal/scheduler/workspaces/work_space_week.ts index 224bd9c9172c..c840b7ccaf37 100644 --- a/packages/devextreme/js/__internal/scheduler/workspaces/work_space_week.ts +++ b/packages/devextreme/js/__internal/scheduler/workspaces/work_space_week.ts @@ -9,7 +9,7 @@ const WEEK_CLASS = 'dx-scheduler-work-space-week'; const WORK_WEEK_CLASS = 'dx-scheduler-work-space-work-week'; class SchedulerWorkSpaceWeek extends SchedulerWorkSpaceVertical { get type(): ViewType { - return this.option('type') ?? VIEWS.WEEK; + return this.option().type ?? VIEWS.WEEK; } protected override getElementClass(): string { @@ -17,7 +17,7 @@ class SchedulerWorkSpaceWeek extends SchedulerWorkSpaceVertical { } protected override calculateViewStartDate(): Date { - return weekUtils.calculateViewStartDate(this.option('startDate') as Date, this.firstDayOfWeek()); + return weekUtils.calculateViewStartDate(this.option().startDate as Date, this.firstDayOfWeek()); } } diff --git a/packages/devextreme/testing/tests/DevExpress.ui.widgets.scheduler/workSpace.markup-0.tests.js b/packages/devextreme/testing/tests/DevExpress.ui.widgets.scheduler/workSpace.markup-0.tests.js index cf7aaf4e7190..45f731f4459e 100644 --- a/packages/devextreme/testing/tests/DevExpress.ui.widgets.scheduler/workSpace.markup-0.tests.js +++ b/packages/devextreme/testing/tests/DevExpress.ui.widgets.scheduler/workSpace.markup-0.tests.js @@ -1,5 +1,5 @@ import $ from 'jquery'; -import SchedulerWorkSpace from '__internal/scheduler/workspaces/m_work_space'; +import SchedulerWorkSpace from '__internal/scheduler/workspaces/work_space'; import SchedulerWorkSpaceHorizontalStrategy from '__internal/scheduler/workspaces/work_space_grouped_strategy_horizontal'; import '__internal/scheduler/m_scheduler';