UNPKG

devextreme

Version:

JavaScript/TypeScript Component Suite for Responsive Web Development

623 lines (621 loc) • 28.1 kB
/** * DevExtreme (cjs/__internal/scheduler/workspaces/view_model/view_data_generator.js) * Version: 26.1.4 * Build date: Fri Jul 24 2026 * * Copyright (c) 2012 - 2026 Developer Express Inc. ALL RIGHTS RESERVED * Read about DevExtreme licensing here: https://js.devexpress.com/Licensing/ */ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ViewDataGenerator = void 0; var _date = _interopRequireDefault(require("../../../../core/utils/date")); var _date2 = require("../../../core/utils/date"); var _constants = require("../../constants"); var _index = require("../../r1/utils/index"); var _constants_view = require("../../utils/options/constants_view"); var _group_utils = require("../../utils/resource_manager/group_utils"); var _skipped_days = require("../../utils/skipped_days"); var _utils_time_zone = _interopRequireDefault(require("../../utils_time_zone")); function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e } } const toMs = _date.default.dateToMilliseconds; class ViewDataGenerator { constructor(viewType) { this.viewType = viewType; this.tableAllDay = false; this.hiddenInterval = 0; this.skippedDays = [] } get daysInInterval() { const isWeekLikeView = [_constants_view.VIEWS.WEEK, _constants_view.VIEWS.TIMELINE_WEEK, _constants_view.VIEWS.WORK_WEEK, _constants_view.VIEWS.TIMELINE_WORK_WEEK].includes(this.viewType); return isWeekLikeView ? 7 - this.skippedDays.length : 1 } usesMonthDayLayout() { return false } getVisibleDaysOfWeek(firstDayOfWeek) { return (0, _skipped_days.getVisibleDaysOfWeek)(firstDayOfWeek, this.skippedDays) } getSkippedDaysAnchorDay(firstDayOfWeekOption, startViewDate) { return this.getFirstDayOfWeek(firstDayOfWeekOption ?? 0) } getVisibleDayOffset(rowIndex, columnIndex, anchorDay, cellCountInDay) { const rotated = this.getVisibleDaysOfWeek(anchorDay); const visibleCount = rotated.length; if (0 === visibleCount) { return 0 } if (this.usesMonthDayLayout()) { const targetDayOfWeek = rotated[columnIndex]; const naiveDayOffset = rowIndex * visibleCount + columnIndex; const actualDayOffset = 7 * rowIndex + (targetDayOfWeek - anchorDay + 7) % 7; return actualDayOffset - naiveDayOffset } const dayIndex = (0, _index.isHorizontalView)(this.viewType) ? Math.floor(columnIndex / cellCountInDay) : columnIndex; const week = Math.floor(dayIndex / visibleCount); const idxInWeek = dayIndex % visibleCount; const targetDayOfWeek = rotated[idxInWeek]; const naiveDayOffset = dayIndex; const actualDayOffset = 7 * week + (targetDayOfWeek - anchorDay + 7) % 7; return actualDayOffset - naiveDayOffset } isDateSkipped(date) { return (0, _skipped_days.isDateSkipped)(date, this.skippedDays) } calculateStartViewDate(options) { return new Date } getStartViewDate(options) { return this.calculateStartViewDate(options) } getCompleteViewDataMap(options) { const { getResourceManager: getResourceManager, isGroupedByDate: isGroupedByDate, isHorizontalGrouping: isHorizontalGrouping, isVerticalGrouping: isVerticalGrouping, intervalCount: intervalCount, currentDate: currentDate, viewType: viewType, startDayHour: startDayHour, endDayHour: endDayHour, hoursInterval: hoursInterval } = options; this.skippedDays = options.skippedDays ?? this.skippedDays; this.setVisibilityDates(options); this.setHiddenInterval(startDayHour, endDayHour, hoursInterval); const groupsList = (0, _group_utils.getAllGroupValues)(getResourceManager().groupsLeafs); const cellCountInGroupRow = this.getCellCount({ intervalCount: intervalCount, currentDate: currentDate, viewType: viewType, startDayHour: startDayHour, endDayHour: endDayHour, hoursInterval: hoursInterval }); const rowCountInGroup = this.getRowCount({ intervalCount: intervalCount, currentDate: currentDate, viewType: viewType, hoursInterval: hoursInterval, startDayHour: startDayHour, endDayHour: endDayHour }); let viewDataMap = []; const allDayPanelData = this.generateAllDayPanelData(options, rowCountInGroup, cellCountInGroupRow); const viewCellsData = this.generateViewCellsData(options, rowCountInGroup, cellCountInGroupRow); if (allDayPanelData) { viewDataMap.push(allDayPanelData) } viewDataMap.push(...viewCellsData); if (isHorizontalGrouping && !isGroupedByDate) { viewDataMap = this.transformViewDataMapForHorizontalGrouping(viewDataMap, groupsList) } if (isVerticalGrouping) { viewDataMap = this.transformViewDataMapForVerticalGrouping(viewDataMap, groupsList) } if (isGroupedByDate) { viewDataMap = this.transformViewDataMapForGroupingByDate(viewDataMap, groupsList) } return this.addKeysToCells(viewDataMap) } transformViewDataMapForHorizontalGrouping(viewDataMap, groupsList) { const result = viewDataMap.map(row => row.slice()); groupsList.slice(1).forEach((groups, index) => { const groupIndex = index + 1; viewDataMap.forEach((row, rowIndex) => { const nextGroupRow = row.map(cellData => Object.assign({}, cellData, { groups: groups, groupIndex: groupIndex })); result[rowIndex].push(...nextGroupRow) }) }); return result } transformViewDataMapForVerticalGrouping(viewDataMap, groupsList) { const result = viewDataMap.map(row => row.slice()); groupsList.slice(1).forEach((groups, index) => { const groupIndex = index + 1; const nextGroupMap = viewDataMap.map(cellsRow => { const nextRow = cellsRow.map(cellData => Object.assign({}, cellData, { groupIndex: groupIndex, groups: groups })); return nextRow }); result.push(...nextGroupMap) }); return result } transformViewDataMapForGroupingByDate(viewDataMap, groupsList) { const correctedGroupList = groupsList.slice(1); const correctedGroupCount = correctedGroupList.length; const result = viewDataMap.map(cellsRow => { const groupedByDateCellsRow = cellsRow.reduce((currentRow, cell) => { const rowWithCurrentCell = [...currentRow, Object.assign({}, cell, { isFirstGroupCell: true, isLastGroupCell: 0 === correctedGroupCount }), ...correctedGroupList.map((groups, index) => Object.assign({}, cell, { groups: groups, groupIndex: index + 1, isFirstGroupCell: false, isLastGroupCell: index === correctedGroupCount - 1 }))]; return rowWithCurrentCell }, []); return groupedByDateCellsRow }); return result } addKeysToCells(viewDataMap) { const totalColumnCount = viewDataMap[0].length; const { currentViewDataMap: result } = viewDataMap.reduce((_ref, row, rowIndex) => { let { allDayPanelsCount: allDayPanelsCount, currentViewDataMap: currentViewDataMap } = _ref; const isAllDay = row[0].allDay; const keyBase = (rowIndex - allDayPanelsCount) * totalColumnCount; const currentAllDayPanelsCount = isAllDay ? allDayPanelsCount + 1 : allDayPanelsCount; currentViewDataMap.push(row.map((cell, columnIndex) => Object.assign({}, cell, { key: keyBase + columnIndex }))); return { allDayPanelsCount: currentAllDayPanelsCount, currentViewDataMap: currentViewDataMap } }, { allDayPanelsCount: 0, currentViewDataMap: [] }); return result } generateViewDataMap(completeViewDataMap, options) { const { rowCount: rowCount, startCellIndex: startCellIndex, startRowIndex: startRowIndex, cellCount: cellCount, isVerticalGrouping: isVerticalGrouping, isAllDayPanelVisible: isAllDayPanelVisible } = options; const sliceCells = (row, rowIndex, startIndex, count) => { const sliceToIndex = void 0 !== count ? startIndex + count : void 0; return row.slice(startIndex, sliceToIndex).map((cellData, columnIndex) => ({ cellData: cellData, position: { rowIndex: rowIndex, columnIndex: columnIndex } })) }; let correctedStartRowIndex = startRowIndex; let allDayPanelMap = []; if (this.isStandaloneAllDayPanel(isVerticalGrouping, isAllDayPanelVisible)) { correctedStartRowIndex += 1; allDayPanelMap = sliceCells(completeViewDataMap[0], 0, startCellIndex, cellCount) } const displayedRowCount = (0, _index.getDisplayedRowCount)(rowCount, completeViewDataMap); const dateTableMap = completeViewDataMap.slice(correctedStartRowIndex, correctedStartRowIndex + displayedRowCount).map((row, rowIndex) => sliceCells(row, rowIndex, startCellIndex, cellCount)); return { allDayPanelMap: allDayPanelMap, dateTableMap: dateTableMap } } isStandaloneAllDayPanel(isVerticalGrouping, isAllDayPanelVisible) { return !isVerticalGrouping && isAllDayPanelVisible } getViewDataFromMap(completeViewDataMap, viewDataMap, options) { const { topVirtualRowHeight: topVirtualRowHeight, bottomVirtualRowHeight: bottomVirtualRowHeight, leftVirtualCellWidth: leftVirtualCellWidth, rightVirtualCellWidth: rightVirtualCellWidth, cellCount: cellCount, rowCount: rowCount, startRowIndex: startRowIndex, startCellIndex: startCellIndex, isProvideVirtualCellsWidth: isProvideVirtualCellsWidth, isGroupedAllDayPanel: isGroupedAllDayPanel, isVerticalGrouping: isVerticalGrouping, isAllDayPanelVisible: isAllDayPanelVisible } = options; const { allDayPanelMap: allDayPanelMap, dateTableMap: dateTableMap } = viewDataMap; const { groupedData: groupedData } = dateTableMap.reduce((_ref2, cellsRow) => { let { previousGroupIndex: previousGroupIndex, groupedData: currentGroupedData } = _ref2; const cellDataRow = cellsRow.map(_ref3 => { let { cellData: cellData } = _ref3; return cellData }); const firstCell = cellDataRow[0]; const isAllDayRow = firstCell.allDay; const currentGroupIndex = firstCell.groupIndex; if (currentGroupIndex !== previousGroupIndex) { currentGroupedData.push({ dateTable: [], isGroupedAllDayPanel: (0, _index.getIsGroupedAllDayPanel)(Boolean(isAllDayRow), isVerticalGrouping), groupIndex: currentGroupIndex, key: (0, _index.getKeyByGroup)(currentGroupIndex, isVerticalGrouping) }) } if (isAllDayRow) { currentGroupedData[currentGroupedData.length - 1].allDayPanel = cellDataRow } else { currentGroupedData[currentGroupedData.length - 1].dateTable.push({ cells: cellDataRow, key: (cellDataRow[0].key ?? 0) - startCellIndex }) } return { groupedData: currentGroupedData, previousGroupIndex: currentGroupIndex } }, { previousGroupIndex: -1, groupedData: [] }); if (this.isStandaloneAllDayPanel(isVerticalGrouping, isAllDayPanelVisible)) { groupedData[0].allDayPanel = allDayPanelMap.map(_ref4 => { let { cellData: cellData } = _ref4; return cellData }) } const totalCellCount = (0, _index.getTotalCellCountByCompleteData)(completeViewDataMap); const totalRowCount = (0, _index.getTotalRowCountByCompleteData)(completeViewDataMap); const displayedCellCount = (0, _index.getDisplayedCellCount)(cellCount, completeViewDataMap); const displayedRowCount = (0, _index.getDisplayedRowCount)(rowCount, completeViewDataMap); return { groupedData: groupedData, topVirtualRowHeight: topVirtualRowHeight, bottomVirtualRowHeight: bottomVirtualRowHeight, leftVirtualCellWidth: isProvideVirtualCellsWidth ? leftVirtualCellWidth : void 0, rightVirtualCellWidth: isProvideVirtualCellsWidth ? rightVirtualCellWidth : void 0, isGroupedAllDayPanel: isGroupedAllDayPanel, leftVirtualCellCount: startCellIndex, rightVirtualCellCount: void 0 === cellCount ? 0 : totalCellCount - startCellIndex - displayedCellCount, topVirtualRowCount: startRowIndex, bottomVirtualRowCount: totalRowCount - startRowIndex - displayedRowCount } } generateViewCellsData(options, rowCount, cellCountInGroupRow) { const viewCellsData = []; for (let rowIndex = 0; rowIndex < rowCount; rowIndex += 1) { viewCellsData.push(this.generateCellsRow(options, false, rowIndex, rowCount, cellCountInGroupRow)) } return viewCellsData } generateAllDayPanelData(options, rowCount, columnCount) { if (!options.isAllDayPanelVisible) { return null } return this.generateCellsRow(options, true, 0, rowCount, columnCount) } generateCellsRow(options, allDay, rowIndex, rowCount, columnCount) { const cellsRow = []; for (let columnIndex = 0; columnIndex < columnCount; columnIndex += 1) { const cellDataValue = this.getCellData(rowIndex, columnIndex, options, allDay); const index = rowIndex * columnCount + columnIndex; const isFirstGroupCell = this.isFirstGroupCell(rowIndex, columnIndex, options, rowCount, columnCount); const isLastGroupCell = this.isLastGroupCell(rowIndex, columnIndex, options, rowCount, columnCount); cellsRow.push(Object.assign({}, cellDataValue, { index: index, isFirstGroupCell: isFirstGroupCell, isLastGroupCell: isLastGroupCell })) } return cellsRow } getCellData(rowIndex, columnIndex, options, allDay) { return allDay ? this.prepareAllDayCellData(options, rowIndex, columnIndex) : this.prepareCellData(options, rowIndex, columnIndex) } prepareCellData(options, rowIndex, columnIndex) { const { getResourceManager: getResourceManager } = options; const groupsList = (0, _group_utils.getAllGroupValues)(getResourceManager().groupsLeafs); const startDate = this.getDateByCellIndices(options, rowIndex, columnIndex); const endDate = this.calculateEndDate(startDate, options.interval, options.endDayHour); const data = { startDate: startDate, endDate: endDate, allDay: this.tableAllDay, groupIndex: 0 }; if (groupsList.length > 0) { data.groups = groupsList[0] } return data } prepareAllDayCellData(options, rowIndex, columnIndex) { const data = this.prepareCellData(Object.assign({}, options, { viewOffset: 0 }), rowIndex, columnIndex); const { viewOffset: viewOffset } = options; const startDate = _date.default.trimTime(data.startDate); const shiftedStartDate = _date2.dateUtilsTs.addOffsets(startDate, viewOffset); return Object.assign({}, data, { startDate: shiftedStartDate, endDate: shiftedStartDate, allDay: true }) } getDateByCellIndices(options, rowIndex, columnIndex) { const { startViewDate: startViewDate } = options; const { startDayHour: startDayHour, endDayHour: endDayHour, hoursInterval: hoursInterval, interval: interval, firstDayOfWeek: firstDayOfWeek, viewOffset: viewOffset } = options; const cellCountInDay = this.getCellCountInDay(startDayHour, endDayHour, hoursInterval); const columnCountBase = this.getCellCount(options); const rowCountBase = this.getRowCount(options); const cellIndex = this.calculateCellIndex(rowIndex, columnIndex, rowCountBase, columnCountBase); const millisecondsOffset = this.getMillisecondsOffset(cellIndex, interval, cellCountInDay); let offsetByCount = 0; if (this.skippedDays.length > 0) { offsetByCount = this.getVisibleDayOffset(rowIndex, columnIndex, this.getSkippedDaysAnchorDay(firstDayOfWeek, startViewDate), cellCountInDay) * toMs("day") } const isStartViewDateDuringDST = startViewDate.getHours() !== Math.floor(startDayHour); let startViewDateTime = startViewDate.getTime(); let currentDate = new Date(startViewDateTime + millisecondsOffset + offsetByCount + viewOffset); const isMidnightDSTViewStart = _utils_time_zone.default.isLocalTimeMidnightDST(startViewDate); const isMidnightDST = _utils_time_zone.default.isLocalTimeMidnightDST(currentDate); if (!isMidnightDSTViewStart && !isMidnightDST) { if (isStartViewDateDuringDST) { const dateWithCorrectHours = (0, _index.getStartViewDateWithoutDST)(startViewDate, startDayHour); startViewDateTime = dateWithCorrectHours.getTime() - toMs("day"); currentDate = new Date(startViewDateTime + millisecondsOffset + offsetByCount + viewOffset) } else { const timeZoneDifference = _date.default.getTimezonesDifference(startViewDate, currentDate); currentDate.setTime(currentDate.getTime() + timeZoneDifference) } } else { currentDate = new Date(currentDate.getFullYear(), currentDate.getMonth(), currentDate.getDate(), currentDate.getHours(), currentDate.getMinutes()) } return currentDate } getMillisecondsOffset(cellIndex, interval, cellCountInDay) { const dayIndex = Math.floor(cellIndex / cellCountInDay); const realHiddenInterval = dayIndex * this.hiddenInterval; return interval * cellIndex + realHiddenInterval } calculateEndDate(startDate, interval, endDayHour) { return _utils_time_zone.default.addOffsetsWithoutDST(startDate, Math.round(interval)) } calculateCellIndex(rowIndex, columnIndex, rowCount, columnCountBase) { return (0, _index.calculateCellIndex)(rowIndex, columnIndex, rowCount, columnCountBase) } generateGroupedDataMap(viewDataMap) { const { allDayPanelMap: allDayPanelMap, dateTableMap: dateTableMap } = viewDataMap; const { previousGroupedDataMap: dateTableGroupedMap } = dateTableMap.reduce((previousOptions, cellsRow) => { const { previousGroupedDataMap: previousGroupedDataMap, previousRowIndex: previousRowIndex, previousGroupIndex: previousGroupIndex } = previousOptions; const { groupIndex: currentGroupIndex } = cellsRow[0].cellData; const currentRowIndex = currentGroupIndex === previousGroupIndex ? previousRowIndex + 1 : 0; cellsRow.forEach(cell => { const { groupIndex: groupIndex } = cell.cellData; if (void 0 !== groupIndex) { if (!previousGroupedDataMap[groupIndex]) { previousGroupedDataMap[groupIndex] = [] } if (!previousGroupedDataMap[groupIndex][currentRowIndex]) { previousGroupedDataMap[groupIndex][currentRowIndex] = [] } previousGroupedDataMap[groupIndex][currentRowIndex].push(cell) } }); return { previousGroupedDataMap: previousGroupedDataMap, previousRowIndex: currentRowIndex, previousGroupIndex: currentGroupIndex } }, { previousGroupedDataMap: [], previousRowIndex: -1, previousGroupIndex: -1 }); const allDayPanelGroupedMap = []; null === allDayPanelMap || void 0 === allDayPanelMap || allDayPanelMap.forEach(cell => { const { groupIndex: groupIndex } = cell.cellData; if (void 0 !== groupIndex) { if (!allDayPanelGroupedMap[groupIndex]) { allDayPanelGroupedMap[groupIndex] = [] } allDayPanelGroupedMap[groupIndex].push(cell) } }); return { allDayPanelGroupedMap: allDayPanelGroupedMap, dateTableGroupedMap: dateTableGroupedMap } } isFirstGroupCell(rowIndex, columnIndex, options, rowCount, columnCount) { const { groupOrientation: groupOrientation, getResourceManager: getResourceManager, isGroupedByDate: isGroupedByDate } = options; const groupCount = getResourceManager().groupCount(); if (isGroupedByDate) { return columnIndex % groupCount === 0 } if (groupOrientation === _constants.HORIZONTAL_GROUP_ORIENTATION) { return columnIndex % columnCount === 0 } return rowIndex % rowCount === 0 } isLastGroupCell(rowIndex, columnIndex, options, rowCount, columnCount) { const { groupOrientation: groupOrientation, getResourceManager: getResourceManager, isGroupedByDate: isGroupedByDate } = options; const groupCount = getResourceManager().groupCount(); if (isGroupedByDate) { return (columnIndex + 1) % groupCount === 0 } if (groupOrientation === _constants.HORIZONTAL_GROUP_ORIENTATION) { return (columnIndex + 1) % columnCount === 0 } return (rowIndex + 1) % rowCount === 0 } markSelectedAndFocusedCells(viewDataMap, renderOptions) { const { selectedCells: selectedCells, focusedCell: focusedCell } = renderOptions; if (!selectedCells && !focusedCell) { return viewDataMap } const { allDayPanelMap: allDayPanelMap, dateTableMap: dateTableMap } = viewDataMap; const nextDateTableMap = dateTableMap.map(row => this.markSelectedAndFocusedCellsInRow(row, selectedCells, focusedCell)); const nextAllDayMap = this.markSelectedAndFocusedCellsInRow(allDayPanelMap, selectedCells, focusedCell); return { allDayPanelMap: nextAllDayMap, dateTableMap: nextDateTableMap } } markSelectedAndFocusedCellsInRow(dataRow, selectedCells, focusedCell) { return dataRow.map(cell => { const { index: index, groupIndex: groupIndex, allDay: allDay, startDate: startDate } = cell.cellData; const indexInSelectedCells = (null === selectedCells || void 0 === selectedCells ? void 0 : selectedCells.findIndex(_ref5 => { let { index: selectedCellIndex, groupIndex: selectedCellGroupIndex, allDay: selectedCellAllDay, startDate: selectedCellStartDate } = _ref5; const groupIndexMatch = groupIndex === selectedCellGroupIndex; const cellIndexMatch = index === selectedCellIndex || void 0 === selectedCellIndex && startDate.getTime() === selectedCellStartDate.getTime(); const allDayMatch = Boolean(allDay) === Boolean(selectedCellAllDay); return groupIndexMatch && cellIndexMatch && allDayMatch })) ?? -1; const focusedCellData = null === focusedCell || void 0 === focusedCell ? void 0 : focusedCell.cellData; const isFocused = (null === focusedCellData || void 0 === focusedCellData ? void 0 : focusedCellData.index) === index && (null === focusedCellData || void 0 === focusedCellData ? void 0 : focusedCellData.groupIndex) === groupIndex && (null === focusedCellData || void 0 === focusedCellData ? void 0 : focusedCellData.allDay) === allDay; if (!isFocused && -1 === indexInSelectedCells) { return cell } return Object.assign({}, cell, { cellData: Object.assign({}, cell.cellData, { isSelected: indexInSelectedCells > -1, isFocused: isFocused }) }) }) } getInterval(hoursInterval) { return hoursInterval * toMs("hour") } _getIntervalDuration(intervalCount) { return toMs("day") * intervalCount } setVisibilityDates(options) {} getCellCountInDay(startDayHour, endDayHour, hoursInterval) { const result = (0, _index.calculateDayDuration)(startDayHour, endDayHour) / hoursInterval; return Math.ceil(result) } getCellCount(options) { const { intervalCount: intervalCount, viewType: viewType, startDayHour: startDayHour, endDayHour: endDayHour, hoursInterval: hoursInterval } = options; const cellCountInDay = this.getCellCountInDay(startDayHour, endDayHour, hoursInterval); const columnCountInDay = (0, _index.isHorizontalView)(viewType) ? cellCountInDay : 1; return this.daysInInterval * intervalCount * columnCountInDay } getRowCount(options) { const { viewType: viewType, startDayHour: startDayHour, endDayHour: endDayHour, hoursInterval: hoursInterval } = options; const cellCountInDay = this.getCellCountInDay(startDayHour, endDayHour, hoursInterval); const rowCountInDay = !(0, _index.isHorizontalView)(viewType) ? cellCountInDay : 1; return rowCountInDay } setHiddenInterval(startDayHour, endDayHour, hoursInterval) { this.hiddenInterval = toMs("day") - this.getVisibleDayDuration(startDayHour, endDayHour, hoursInterval) } getVisibleDayDuration(startDayHour, endDayHour, hoursInterval) { const cellCountInDay = this.getCellCountInDay(startDayHour, endDayHour, hoursInterval); return hoursInterval * cellCountInDay * toMs("hour") } getFirstDayOfWeek(firstDayOfWeekOption) { return firstDayOfWeekOption } } exports.ViewDataGenerator = ViewDataGenerator;