diff --git a/packages/devextreme/js/__internal/core/utils/m_date.ts b/packages/devextreme/js/__internal/core/utils/m_date.ts index 5b252005804f..897db6958bf4 100644 --- a/packages/devextreme/js/__internal/core/utils/m_date.ts +++ b/packages/devextreme/js/__internal/core/utils/m_date.ts @@ -425,24 +425,26 @@ function getDateIntervalByString(intervalString) { return result; } -function sameDate(date1, date2) { +function sameDate(date1, date2): boolean { return sameMonthAndYear(date1, date2) && date1.getDate() === date2.getDate(); } -function sameMonthAndYear(date1, date2) { +function sameMonthAndYear(date1, date2): boolean { return sameYear(date1, date2) && date1.getMonth() === date2.getMonth(); } -function sameYear(date1, date2) { +function sameYear(date1, date2): boolean { return date1 && date2 && date1.getFullYear() === date2.getFullYear(); } -function sameHoursAndMinutes(date1, date2) { +function sameHoursAndMinutes(date1, date2): boolean { return date1 && date2 && date1.getHours() === date2.getHours() && date1.getMinutes() === date2.getMinutes(); } -const sameDecade = function (date1, date2) { - if (!isDefined(date1) || !isDefined(date2)) return; +const sameDecade = function (date1, date2): boolean { + if (!isDefined(date1) || !isDefined(date2)) { + return false; + } const startDecadeDate1 = date1.getFullYear() - date1.getFullYear() % 10; const startDecadeDate2 = date2.getFullYear() - date2.getFullYear() % 10; @@ -450,8 +452,10 @@ const sameDecade = function (date1, date2) { return date1 && date2 && startDecadeDate1 === startDecadeDate2; }; -const sameCentury = function (date1, date2) { - if (!isDefined(date1) || !isDefined(date2)) return; +const sameCentury = function (date1, date2): boolean { + if (!isDefined(date1) || !isDefined(date2)) { + return false; + } const startCenturyDate1 = date1.getFullYear() - date1.getFullYear() % 100; const startCenturyDate2 = date2.getFullYear() - date2.getFullYear() % 100; @@ -540,20 +544,27 @@ function getLastDateInYear(year) { function getDayWeekNumber(date, firstDayOfWeek) { let day = date.getDay() - firstDayOfWeek + 1; - if (day <= 0) { day += DAYS_IN_WEEK; } + if (day <= 0) { + day += DAYS_IN_WEEK; + } return day; } -function getWeekNumber(date, firstDayOfWeek, rule) { - const firstWeekDayInYear = getDayWeekNumber(getFirstDateInYear(date.getFullYear()), firstDayOfWeek); +function getWeekNumber(date, firstDayOfWeek, rule): number { + const firstWeekDayInYear = getDayWeekNumber( + getFirstDateInYear(date.getFullYear()), + firstDayOfWeek, + ); const lastWeekDayInYear = getDayWeekNumber(getLastDateInYear(date.getFullYear()), firstDayOfWeek); const daysInFirstWeek = DAYS_IN_WEEK - firstWeekDayInYear + 1; let weekNumber = Math.ceil((getDayNumber(date) - daysInFirstWeek) / 7); switch (rule) { case 'fullWeek': { - if (daysInFirstWeek === DAYS_IN_WEEK) { weekNumber++; } + if (daysInFirstWeek === DAYS_IN_WEEK) { + weekNumber += 1; + } if (weekNumber === 0) { const lastDateInPreviousYear = getLastDateInYear(date.getFullYear() - 1); return getWeekNumber(lastDateInPreviousYear, firstDayOfWeek, rule); @@ -561,20 +572,28 @@ function getWeekNumber(date, firstDayOfWeek, rule) { return weekNumber; } case 'firstDay': { - if (daysInFirstWeek > 0) { weekNumber++; } + if (daysInFirstWeek > 0) { + weekNumber += 1; + } const isSunday = firstWeekDayInYear === SUNDAY_WEEK_NUMBER || lastWeekDayInYear === SUNDAY_WEEK_NUMBER; - if ((weekNumber > USUAL_WEEK_COUNT_IN_YEAR && !isSunday) || weekNumber === 54) { weekNumber = 1; } + if ((weekNumber > USUAL_WEEK_COUNT_IN_YEAR && !isSunday) || weekNumber === 54) { + weekNumber = 1; + } return weekNumber; } case 'firstFourDays': { - if (daysInFirstWeek > 3) { weekNumber++; } + if (daysInFirstWeek > 3) { + weekNumber += 1; + } const isThursday = firstWeekDayInYear === THURSDAY_WEEK_NUMBER || lastWeekDayInYear === THURSDAY_WEEK_NUMBER; - if (weekNumber > USUAL_WEEK_COUNT_IN_YEAR && !isThursday) { weekNumber = 1; } + if (weekNumber > USUAL_WEEK_COUNT_IN_YEAR && !isThursday) { + weekNumber = 1; + } if (weekNumber === 0) { const lastDateInPreviousYear = getLastDateInYear(date.getFullYear() - 1); @@ -583,6 +602,7 @@ function getWeekNumber(date, firstDayOfWeek, rule) { return weekNumber; } default: + return weekNumber; break; } } @@ -699,7 +719,7 @@ const makeDate = function (date) { }; const getDatesOfInterval = function (startDate, endDate, step) { - const result: any[] = []; + const result: Date[] = []; let currentDate = new Date(startDate.getTime()); while (currentDate < endDate) { diff --git a/packages/devextreme/js/__internal/ui/calendar/m_calendar.base_view.ts b/packages/devextreme/js/__internal/ui/calendar/m_calendar.base_view.ts index 236aea3a4270..0541cc90ba95 100644 --- a/packages/devextreme/js/__internal/ui/calendar/m_calendar.base_view.ts +++ b/packages/devextreme/js/__internal/ui/calendar/m_calendar.base_view.ts @@ -1,19 +1,22 @@ +import type { template } from '@js/common'; import { name as clickEventName } from '@js/common/core/events/click'; import eventsEngine from '@js/common/core/events/core/events_engine'; import { start as hoverStartEventName } from '@js/common/core/events/hover'; import { addNamespace } from '@js/common/core/events/utils/index'; import dateLocalization from '@js/common/core/localization/date'; import messageLocalization from '@js/common/core/localization/message'; -import Class from '@js/core/class'; import domAdapter from '@js/core/dom_adapter'; import { getPublicElement } from '@js/core/element'; import { data as elementData } from '@js/core/element_data'; import type { dxElementWrapper } from '@js/core/renderer'; import $ from '@js/core/renderer'; -import { noop } from '@js/core/utils/common'; import coreDateUtils from '@js/core/utils/date'; import dateSerialization from '@js/core/utils/date_serialization'; -import type { CalendarSelectionMode, CalendarZoomLevel, DisabledDate } from '@js/ui/calendar'; +import type { DxEvent } from '@js/events'; +import type { + CalendarSelectionMode, CalendarZoomLevel, CellTemplateData, DisabledDate, +} from '@js/ui/calendar'; +import type { DefaultActionArgs } from '@ts/core/widget/component'; import type { OptionChanged } from '@ts/core/widget/types'; import type { WidgetProperties } from '@ts/core/widget/widget'; import Widget from '@ts/core/widget/widget'; @@ -57,11 +60,25 @@ const SELECTION_MODE = { range: 'range', }; +export interface CellEvent extends DefaultActionArgs { + event: DxEvent; + value: Date; +} + +export interface WeekNumberClickEvent extends DefaultActionArgs { + event: DxEvent; + rowDates: Date[]; +} + export interface BaseViewProperties extends WidgetProperties { date: Date; value?: Date | Date[]; + min?: Date; + + max?: Date; + contouredDate?: Date; _todayDate: () => Date; @@ -83,6 +100,14 @@ export interface BaseViewProperties extends WidgetProperties { range: Date[]; hoveredRange: Date[]; + + cellTemplate?: template | ( + (itemData: CellTemplateData, itemIndex: number, itemElement: Element) => dxElementWrapper + ); + + onCellClick?: (e: CellEvent) => void; + onCellHover?: (e: CellEvent) => void; + onWeekNumberClick?: (e: WeekNumberClickEvent) => void; } class BaseView< @@ -92,13 +117,13 @@ class BaseView< $body!: dxElementWrapper; - _disabledDatesHandler?: Date[] | ((data: DisabledDate) => boolean); + _disabledDatesHandler!: ((data: DisabledDate) => boolean); - _cellClickAction!: (e: Record) => void; + _cellClickAction!: (e: CellEvent) => void; - _cellHoverAction!: (e: Record) => void; + _cellHoverAction!: (e: CellEvent) => void; - _weekNumberCellClickAction!: (e: Record) => void; + _weekNumberCellClickAction!: (e: WeekNumberClickEvent) => void; _$rangeEndHoverCell!: dxElementWrapper; @@ -106,15 +131,14 @@ class BaseView< _$rangeEndDateCell!: dxElementWrapper; - _$rangeCells!: dxElementWrapper; + _$rangeCells!: dxElementWrapper[]; - _$hoveredRangeCells!: dxElementWrapper; + _$hoveredRangeCells!: dxElementWrapper[]; _$rangeStartHoverCell!: dxElementWrapper; - _$selectedCells!: dxElementWrapper; + _$selectedCells!: dxElementWrapper[]; - // eslint-disable-next-line class-methods-use-this _getViewName(): string { return 'base'; } @@ -154,7 +178,6 @@ class BaseView< this._updateTableAriaLabel(); } - // eslint-disable-next-line class-methods-use-this _getLocalizedWidgetName(): string { const localizedWidgetName = messageLocalization.format('dxCalendar-ariaWidgetName'); @@ -165,8 +188,8 @@ class BaseView< const { value } = this.option(); const localizedWidgetName = this._getLocalizedWidgetName(); - // @ts-expect-error - const formattedDate = dateLocalization.format(value, ARIA_LABEL_DATE_FORMAT); + const formattedDate = dateLocalization + .format(value as Date | undefined, ARIA_LABEL_DATE_FORMAT); // @ts-expect-error ts-error const selectedDatesText = messageLocalization.format('dxCalendar-selectedDate', formattedDate); @@ -179,8 +202,7 @@ class BaseView< const { value } = this.option(); const localizedWidgetName = this._getLocalizedWidgetName(); - // @ts-expect-error ts-error - const [startDate, endDate] = value; + const [startDate, endDate] = value as [Date, Date]; const formattedStartDate = dateLocalization.format(startDate, ARIA_LABEL_DATE_FORMAT); const formattedEndDate = dateLocalization.format(endDate, ARIA_LABEL_DATE_FORMAT); @@ -207,8 +229,8 @@ class BaseView< _getMultipleRangesText(): string { const { value } = this.option(); - // @ts-expect-error ts-error - const ranges = coreDateUtils.getRangesByDates(value.map((date) => new Date(date))); + const rangeValue = value as Date[]; + const ranges = coreDateUtils.getRangesByDates(rangeValue.map((date) => new Date(date))); if (ranges.length > 2) { // @ts-expect-error ts-error @@ -227,7 +249,7 @@ class BaseView< return result; } - _getRangeText(range) { + _getRangeText(range: [Date | undefined, Date | undefined]): string { const [startDate, endDate] = range; const formattedStartDate = dateLocalization.format(startDate, ARIA_LABEL_DATE_FORMAT); @@ -238,20 +260,18 @@ class BaseView< ? messageLocalization.format('dxCalendar-selectedMultipleDateRange', formattedStartDate, formattedEndDate) : formattedStartDate; - return selectedDatesText; + return `${selectedDatesText}`; } - // @ts-expect-error ts-error - _getTableAriaLabel() { + _getTableAriaLabel(): string { const { value, selectionMode } = this.option(); - const isValueEmpty = !value || Array.isArray(value) && !value.filter(Boolean).length; + const isValueEmpty = !value || (Array.isArray(value) && !value.filter(Boolean).length); if (isValueEmpty) { return this._getLocalizedWidgetName(); } - // eslint-disable-next-line default-case, @typescript-eslint/switch-exhaustiveness-check switch (selectionMode) { case SELECTION_MODE.single: return this._getSingleModeAriaLabel(); @@ -259,10 +279,12 @@ class BaseView< return this._getRangeModeAriaLabel(); case SELECTION_MODE.multiple: return this._getMultipleModeAriaLabel(); + default: + return this._getSingleModeAriaLabel(); } } - _updateTableAriaLabel() { + _updateTableAriaLabel(): void { const label = this._getTableAriaLabel(); this.setAria({ label }, this._$table); @@ -279,17 +301,17 @@ class BaseView< _renderBody(): void { this.$body = $('').appendTo(this._$table); - const rowData = { + const rowData: { cellDate: Date; prevCellDate: Date | null; row: HTMLElement | undefined } = { cellDate: this._getFirstCellData(), prevCellDate: null, + row: undefined, }; const { rowCount: rowsCount, colCount: colsCount } = this.option(); - for (let rowIndex = 0, rowCount = rowsCount; rowIndex < rowCount; rowIndex++) { - // @ts-expect-error ts-error + for (let rowIndex = 0, rowCount = rowsCount; rowIndex < rowCount; rowIndex += 1) { rowData.row = this._createRow(); - for (let colIndex = 0, colCount = colsCount; colIndex < colCount; colIndex++) { + for (let colIndex = 0, colCount = colsCount; colIndex < colCount; colIndex += 1) { this._renderCell(rowData, colIndex); } @@ -298,9 +320,10 @@ class BaseView< } // eslint-disable-next-line @typescript-eslint/no-unused-vars - _renderWeekNumberCell(rowData) {} + _renderWeekNumberCell(rowData?: unknown): void { + } - _createRow() { + _createRow(): HTMLElement { const row = domAdapter.createElement('tr'); this.setAria('role', 'row', $(row)); @@ -309,7 +332,7 @@ class BaseView< return row; } - _createCell(cellDate, cellIndex) { + _createCell(cellDate: Date, cellIndex: number): { cell: HTMLElement; $cell: dxElementWrapper } { const cell = domAdapter.createElement('td'); const $cell = $(cell); @@ -327,7 +350,10 @@ class BaseView< return { cell, $cell }; } - _renderCell(params, cellIndex) { + _renderCell( + params: { cellDate: Date; prevCellDate: Date | null; row: HTMLElement | undefined }, + cellIndex: number, + ): void { const { cellDate, prevCellDate, row } = params; // T425127 @@ -339,7 +365,7 @@ class BaseView< const { cell, $cell } = this._createCell(cellDate, cellIndex); - const cellTemplate = this.option('cellTemplate'); + const { cellTemplate } = this.option(); $(row).append(cell); @@ -347,14 +373,13 @@ class BaseView< // @ts-expect-error ts-error cellTemplate.render(this._prepareCellTemplateData(cellDate, cellIndex, $cell)); } else { - // @ts-expect-error ts-error cell.innerHTML = this._getCellText(cellDate); } params.cellDate = this._getNextCellData(cellDate); } - _getClassNameByDate(cellDate, cellIndex) { + _getClassNameByDate(cellDate: Date, cellIndex: number): string { let className = CALENDAR_CELL_CLASS; if (this._isTodayCell(cellDate)) { @@ -394,7 +419,11 @@ class BaseView< return className; } - _prepareCellTemplateData(cellDate, cellIndex, $cell) { + _prepareCellTemplateData(cellDate: Date, cellIndex: number, $cell: dxElementWrapper): { + model: CellTemplateData; + container: Element; + index: number; + } { const isDateCell = cellDate instanceof Date; const text = isDateCell ? this._getCellText(cellDate) : cellDate; const date = isDateCell ? cellDate : undefined; @@ -415,6 +444,7 @@ class BaseView< if (!$(e.currentTarget).hasClass(CALENDAR_EMPTY_CELL_CLASS)) { this._cellClickAction({ event: e, + // @ts-expect-error ts-error value: $(e.currentTarget).data(CALENDAR_DATE_VALUE_KEY), }); } @@ -426,14 +456,20 @@ class BaseView< if (selectionMode === SELECTION_MODE.range) { this._createCellHoverAction(); - eventsEngine.on(this._$table, CALENDAR_DXHOVERSTART_EVENT_NAME, NOT_WEEK_CELL_SELECTOR, (e) => { - if (!$(e.currentTarget).hasClass(CALENDAR_EMPTY_CELL_CLASS)) { - this._cellHoverAction({ - event: e, - value: $(e.currentTarget).data(CALENDAR_DATE_VALUE_KEY), - }); - } - }); + eventsEngine.on( + this._$table, + CALENDAR_DXHOVERSTART_EVENT_NAME, + NOT_WEEK_CELL_SELECTOR, + (e) => { + if (!$(e.currentTarget).hasClass(CALENDAR_EMPTY_CELL_CLASS)) { + this._cellHoverAction({ + event: e, + // @ts-expect-error ts-error + value: $(e.currentTarget).data(CALENDAR_DATE_VALUE_KEY), + }); + } + }, + ); } if (selectionMode !== SELECTION_MODE.single) { @@ -443,11 +479,15 @@ class BaseView< const $row = $(e.currentTarget).closest('tr'); const firstDateInRow = $row.find(`.${CALENDAR_CELL_CLASS}`).first().data(CALENDAR_DATE_VALUE_KEY); - const lastDateInRow = $row.find(`.${CALENDAR_CELL_CLASS}`).last().data(CALENDAR_DATE_VALUE_KEY); - const rowDates = [...coreDateUtils.getDatesOfInterval(firstDateInRow, lastDateInRow, DAY_INTERVAL), lastDateInRow]; + const lastDateInRow = $row.find(`.${CALENDAR_CELL_CLASS}`).last().data(CALENDAR_DATE_VALUE_KEY) ; + const rowDates = [ + ...coreDateUtils.getDatesOfInterval(firstDateInRow, lastDateInRow, DAY_INTERVAL), + lastDateInRow, + ]; this._weekNumberCellClickAction({ event: e, + // @ts-expect-error ts-error rowDates, }); }); @@ -455,99 +495,90 @@ class BaseView< } _createCellClickAction(): void { - // @ts-expect-error ts-error this._cellClickAction = this._createActionByOption('onCellClick'); } _createCellHoverAction(): void { - // @ts-expect-error ts-error this._cellHoverAction = this._createActionByOption('onCellHover'); } _createWeekNumberCellClickAction(): void { - // @ts-expect-error ts-error this._weekNumberCellClickAction = this._createActionByOption('onWeekNumberClick'); } _createDisabledDatesHandler(): void { const { disabledDates } = this.option(); - // @ts-expect-error ts-error + this._disabledDatesHandler = Array.isArray(disabledDates) ? this._getDefaultDisabledDatesHandler(disabledDates) - // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing - : disabledDates || noop; + : disabledDates ?? ((): boolean => false); } // eslint-disable-next-line @typescript-eslint/no-unused-vars - _getDefaultDisabledDatesHandler(disabledDates): (args) => void { - return noop; + _getDefaultDisabledDatesHandler(disabledDates: Date[]): (args) => boolean { + return () => false; } - // @ts-expect-error ts-error // eslint-disable-next-line @typescript-eslint/no-unused-vars - _isTodayCell(cellDate): boolean { - Class.abstract(); + _isTodayCell(cellDate: Date): boolean { + return false; } - // @ts-expect-error ts-error // eslint-disable-next-line @typescript-eslint/no-unused-vars - _isDateOutOfRange(cellDate): boolean { - Class.abstract(); + _isDateOutOfRange(cellDate: Date): boolean { + return false; } - isDateDisabled(cellDate): boolean { + isDateDisabled(cellDate: Date): boolean { const dateParts = { date: cellDate, view: this._getViewName(), }; - // @ts-expect-error ts-error - return this._disabledDatesHandler(dateParts); + + return this._disabledDatesHandler(dateParts as DisabledDate); } - // @ts-expect-error ts-error // eslint-disable-next-line @typescript-eslint/no-unused-vars - _isOtherView(cellDate): boolean { - Class.abstract(); + _isOtherView(cellDate: Date): boolean { + return false; } - // @ts-expect-error ts-error // eslint-disable-next-line @typescript-eslint/no-unused-vars - _isStartDayOfMonth(cellDate): boolean { - Class.abstract(); + _isStartDayOfMonth(cellDate: Date): boolean { + return false; } - // @ts-expect-error ts-error // eslint-disable-next-line @typescript-eslint/no-unused-vars - _isEndDayOfMonth(cellDate): boolean { - Class.abstract(); + _isEndDayOfMonth(cellDate: Date): boolean { + return false; } // eslint-disable-next-line @typescript-eslint/no-unused-vars - _getCellText(cellDate) { - Class.abstract(); + _getCellText(cellDate: Date): string { + return ''; } - _getFirstCellData() { - Class.abstract(); + _getFirstCellData(): Date { + return new Date(); } - // eslint-disable-next-line @typescript-eslint/no-unused-vars - _getNextCellData(date) { - Class.abstract(); + _getNextCellData(date: Date): Date { + return new Date(date); } - _renderContouredDate(contouredDate?) { - if (!this.option('focusStateEnabled')) { + _renderContouredDate(contouredDate?: Date | undefined): void { + const { focusStateEnabled } = this.option(); + if (!focusStateEnabled) { return; } - - contouredDate = contouredDate || this.option('contouredDate'); + const { contouredDate: currentContouredDate } = this.option(); + const newContouredDate = contouredDate ?? currentContouredDate; const $oldContouredCell = this._getContouredCell(); - const $newContouredCell = this._getCellByDate(contouredDate); + const $newContouredCell = this._getCellByDate(newContouredDate); $oldContouredCell.removeClass(CALENDAR_CONTOURED_DATE_CLASS); - if (contouredDate) { + if (newContouredDate) { $newContouredCell.addClass(CALENDAR_CONTOURED_DATE_CLASS); } } @@ -561,72 +592,73 @@ class BaseView< return; } - let value = this.option('value'); + let { value = [] } = this.option(); if (!Array.isArray(value)) { - // @ts-expect-error ts-error value = [value]; } this._updateSelectedClass(value); } - _updateSelectedClass(value): void { + _updateSelectedClass(value: Date[]): void { if (this._isRangeMode() && !this._isMonthView()) { return; } - // @ts-expect-error ts-error - this._$selectedCells?.forEach(($cell) => { $cell.removeClass(CALENDAR_SELECTED_DATE_CLASS); }); - this._$selectedCells = value.map((value) => this._getCellByDate(value)); - // @ts-expect-error ts-error + + this._$selectedCells?.forEach(($cell: dxElementWrapper) => { + $cell.removeClass(CALENDAR_SELECTED_DATE_CLASS); + }); + + this._$selectedCells = value.map((date: Date) => this._getCellByDate(date)); this._$selectedCells.forEach(($cell) => { $cell.addClass(CALENDAR_SELECTED_DATE_CLASS); }); } _renderRange(): void { - const { allowValueSelection, value, range } = this.option(); + const { allowValueSelection, value = [], range } = this.option(); if (!allowValueSelection || !this._isRangeMode() || !this._isMonthView()) { return; } - // @ts-expect-error ts-error + this._$rangeCells?.forEach(($cell) => { $cell.removeClass(CALENDAR_CELL_IN_RANGE_CLASS); }); - // @ts-expect-error ts-error - this._$hoveredRangeCells?.forEach(($cell) => { $cell.removeClass(CALENDAR_CELL_RANGE_HOVER_CLASS); }); + this._$hoveredRangeCells?.forEach(($cell) => { + $cell.removeClass(CALENDAR_CELL_RANGE_HOVER_CLASS); + }); this._$rangeStartHoverCell?.removeClass(CALENDAR_CELL_RANGE_HOVER_START_CLASS); this._$rangeEndHoverCell?.removeClass(CALENDAR_CELL_RANGE_HOVER_END_CLASS); this._$rangeStartDateCell?.removeClass(CALENDAR_RANGE_START_DATE_CLASS); this._$rangeEndDateCell?.removeClass(CALENDAR_RANGE_END_DATE_CLASS); - // @ts-expect-error ts-error - this._$rangeCells = range.map((value) => this._getCellByDate(value)); - // @ts-expect-error ts-error + + this._$rangeCells = range.map((date) => this._getCellByDate(date)); this._$rangeStartDateCell = this._getCellByDate(value[0]); - // @ts-expect-error ts-error this._$rangeEndDateCell = this._getCellByDate(value[1]); - // @ts-expect-error ts-error - this._$rangeCells.forEach(($cell) => { $cell.addClass(CALENDAR_CELL_IN_RANGE_CLASS); }); + this._$rangeCells.forEach(($cell) => { $cell.addClass(CALENDAR_CELL_IN_RANGE_CLASS); }); this._$rangeStartDateCell?.addClass(CALENDAR_RANGE_START_DATE_CLASS); this._$rangeEndDateCell?.addClass(CALENDAR_RANGE_END_DATE_CLASS); } - _renderHoveredRange() { + _renderHoveredRange(): void { const { allowValueSelection, hoveredRange } = this.option(); if (!allowValueSelection || !this._isRangeMode() || !this._isMonthView()) { return; } - // @ts-expect-error ts-error - this._$hoveredRangeCells?.forEach(($cell) => { $cell.removeClass(CALENDAR_CELL_RANGE_HOVER_CLASS); }); + + this._$hoveredRangeCells?.forEach(($cell) => { + $cell.removeClass(CALENDAR_CELL_RANGE_HOVER_CLASS); + }); this._$rangeStartHoverCell?.removeClass(CALENDAR_CELL_RANGE_HOVER_START_CLASS); this._$rangeEndHoverCell?.removeClass(CALENDAR_CELL_RANGE_HOVER_END_CLASS); - // @ts-expect-error ts-error + this._$hoveredRangeCells = hoveredRange - .map((value) => this._getCellByDate(value)); + .map((date) => this._getCellByDate(date)); this._$rangeStartHoverCell = this._getCellByDate(hoveredRange[0]); this._$rangeEndHoverCell = this._getCellByDate(hoveredRange[hoveredRange.length - 1]); - // @ts-expect-error ts-error + this._$hoveredRangeCells.forEach(($cell) => { $cell.addClass(CALENDAR_CELL_RANGE_HOVER_CLASS); }); @@ -651,13 +683,13 @@ class BaseView< return null; } - getCellAriaLabel(date) { + getCellAriaLabel(date: Date): string { const viewName = this._getViewName(); const isToday = this._isTodayCell(date); const format = this._getCurrentDateFormat(); const dateRangeText = format - ? dateLocalization.format(date, format) + ? `${dateLocalization.format(date, format)}` : this._getCellText(date); const ariaLabel = isToday @@ -668,23 +700,23 @@ class BaseView< } _getFirstAvailableDate(): Date { - let date = this.option('date'); - const min = this.option('min'); - // @ts-expect-error ts-error - date = coreDateUtils.getViewFirstCellDate(this._getViewName(), date); - // @ts-expect-error ts-error - return new Date(min && date < min ? min : date); + const { date, min } = this.option(); + const firstAvailableDate = coreDateUtils.getViewFirstCellDate( + this._getViewName(), + date, + ) ?? date; + + return new Date(min && firstAvailableDate < min ? min : firstAvailableDate); } - // @ts-expect-error ts-error // eslint-disable-next-line @typescript-eslint/no-unused-vars - _getCellByDate(contouredDate): dxElementWrapper { - Class.abstract(); + _getCellByDate(contouredDate: Date | undefined): dxElementWrapper { + return $(); } - // eslint-disable-next-line class-methods-use-this, @typescript-eslint/no-unused-vars - isBoundary(date?) { - Class.abstract(); + // eslint-disable-next-line @typescript-eslint/no-unused-vars + isBoundary(date?: Date): boolean { + return false; } _optionChanged(args: OptionChanged): void { @@ -701,7 +733,7 @@ class BaseView< this._renderHoveredRange(); break; case 'contouredDate': - this._renderContouredDate(value); + this._renderContouredDate(value as Date | undefined); break; case 'onCellClick': this._createCellClickAction(); diff --git a/packages/devextreme/js/__internal/ui/calendar/m_calendar.multiple.selection.strategy.ts b/packages/devextreme/js/__internal/ui/calendar/m_calendar.multiple.selection.strategy.ts index 61961bf0b882..491f87668d3e 100644 --- a/packages/devextreme/js/__internal/ui/calendar/m_calendar.multiple.selection.strategy.ts +++ b/packages/devextreme/js/__internal/ui/calendar/m_calendar.multiple.selection.strategy.ts @@ -1,23 +1,44 @@ +import type { DxEvent } from '@js/events'; + +import type Calendar from './m_calendar'; +import type { WeekNumberClickEvent } from './m_calendar.base_view'; import CalendarSelectionStrategy from './m_calendar.selection.strategy'; class CalendarMultiSelectionStrategy extends CalendarSelectionStrategy { - constructor(component) { + constructor(component: Calendar) { super(component); this.NAME = 'MultiSelection'; } - getViewOptions() { + dateOption(optionName: 'value'): (Date | null)[]; + dateOption(optionName: 'min' | 'max'): Date | null; + dateOption(optionName: 'min' | 'max' | 'value'): Date | null | (Date | null)[] { + if (optionName === 'value') { + return this.calendar._getDateOption('value') as Date[] | null; + } + return this.calendar._getDateOption(optionName); + } + + getViewOptions(): { + value: (Date | null)[]; + range: Date[]; + selectionMode: 'multiple'; + onWeekNumberClick?: ((e: WeekNumberClickEvent) => void) | null; + } { return { value: this.dateOption('value'), range: [], selectionMode: 'multiple', - onWeekNumberClick: this._shouldHandleWeekNumberClick() ? this._weekNumberClickHandler.bind(this) : null, + onWeekNumberClick: this._shouldHandleWeekNumberClick() + ? this._weekNumberClickHandler.bind(this) + : null, }; } - selectValue(selectedValue, e) { + selectValue(selectedValue: Date, e: DxEvent): void { const value = [...this.dateOption('value')]; - const alreadySelectedIndex = value.findIndex((date) => date?.toDateString() === selectedValue.toDateString()); + const alreadySelectedIndex = value + .findIndex((date) => date?.toDateString() === selectedValue.toDateString()); if (alreadySelectedIndex > -1) { value.splice(alreadySelectedIndex, 1); @@ -31,23 +52,25 @@ class CalendarMultiSelectionStrategy extends CalendarSelectionStrategy { this.dateValue(value, e); } - updateAriaSelected(value?, previousValue?) { - value ??= this.dateOption('value'); - previousValue ??= []; + updateAriaSelected(val?: (Date | null)[], previousVal?: (Date | null)[]): void { + const value = val ?? this.dateOption('value'); + const previousValue = previousVal ?? []; super.updateAriaSelected(value, previousValue); } - getDefaultCurrentDate() { - const dates = this.dateOption('value').filter(Boolean); + getDefaultCurrentDate(): Date | null { + const value = this.dateOption('value'); + const dates = value.filter((date) => date !== null); + return this._getLowestDateInArray(dates); } - restoreValue() { + restoreValue(): void { this.calendar.option('value', []); } - _weekNumberClickHandler({ rowDates, event }) { + _weekNumberClickHandler({ rowDates, event }: WeekNumberClickEvent): void { const selectedDates = rowDates.filter((date) => !this._isDateDisabled(date)); this.dateValue(selectedDates, event); diff --git a/packages/devextreme/js/__internal/ui/calendar/m_calendar.navigator.ts b/packages/devextreme/js/__internal/ui/calendar/m_calendar.navigator.ts index 11d486a7e460..df4ed75f69cb 100644 --- a/packages/devextreme/js/__internal/ui/calendar/m_calendar.navigator.ts +++ b/packages/devextreme/js/__internal/ui/calendar/m_calendar.navigator.ts @@ -17,7 +17,7 @@ const CALENDAR_NAVIGATOR_CAPTION_BUTTON_CLASS = 'dx-calendar-caption-button'; const BUTTON_TEXT_CLASS = 'dx-button-text'; export interface NavigatorOptions extends WidgetOptions { - onClick?: ((e: ClickEvent) => void); + onClick?: ((e: { direction: number; event: ClickEvent }) => void); onCaptionClick?: ((e: ClickEvent) => void); type?: ButtonType; stylingMode?: ButtonStyle; diff --git a/packages/devextreme/js/__internal/ui/calendar/m_calendar.range.selection.strategy.ts b/packages/devextreme/js/__internal/ui/calendar/m_calendar.range.selection.strategy.ts index b866abc2474e..97270adca7c4 100644 --- a/packages/devextreme/js/__internal/ui/calendar/m_calendar.range.selection.strategy.ts +++ b/packages/devextreme/js/__internal/ui/calendar/m_calendar.range.selection.strategy.ts @@ -1,16 +1,34 @@ import dateUtils from '@js/core/utils/date'; +import type { DxEvent } from '@js/events'; +import type Calendar from './m_calendar'; +import type { CellEvent, WeekNumberClickEvent } from './m_calendar.base_view'; import CalendarSelectionStrategy from './m_calendar.selection.strategy'; const DAY_INTERVAL = 86400000; class CalendarRangeSelectionStrategy extends CalendarSelectionStrategy { - constructor(component) { + constructor(component: Calendar) { super(component); this.NAME = 'RangeSelection'; } - getViewOptions() { + dateOption(optionName: 'value'): (Date | null)[]; + dateOption(optionName: 'min' | 'max'): Date | null; + dateOption(optionName: 'min' | 'max' | 'value'): Date | null | (Date | null)[] { + if (optionName === 'value') { + return this.calendar._getDateOption('value') as (Date | null)[] || null; + } + return this.calendar._getDateOption(optionName); + } + + getViewOptions(): { + value: (Date | null)[]; + range: Date[]; + selectionMode: 'range'; + onCellHover?: (e: CellEvent) => void; + onWeekNumberClick?: ((e: WeekNumberClickEvent) => void) | null; + } { const value = this._getValue(); const range = this._getDaysInRange(value[0], value[1]); @@ -19,27 +37,31 @@ class CalendarRangeSelectionStrategy extends CalendarSelectionStrategy { range, selectionMode: 'range', onCellHover: this._cellHoverHandler.bind(this), - onWeekNumberClick: this._shouldHandleWeekNumberClick() ? this._weekNumberClickHandler.bind(this) : null, + onWeekNumberClick: this._shouldHandleWeekNumberClick() + ? this._weekNumberClickHandler.bind(this) + : null, }; } - selectValue(selectedValue, e) { + selectValue(selectedValue: Date, e: DxEvent): void { const [startDate, endDate] = this._getValue(); this.skipNavigate(); this._updateCurrentDate(selectedValue); this._currentDateChanged = true; + const { allowChangeSelectionOrder, currentSelection } = this.calendar.option(); - if (this.calendar.option('_allowChangeSelectionOrder') === true) { + if (allowChangeSelectionOrder === true) { this.calendar._valueSelected = true; - - if (this.calendar.option('_currentSelection') === 'startDate') { - if (this.calendar._convertToDate(selectedValue) > this.calendar._convertToDate(endDate)) { + const convertedSelectedValue = this.calendar._convertToDate(selectedValue) as Date; + if (currentSelection === 'startDate') { + if (convertedSelectedValue > (this.calendar._convertToDate(endDate) ?? new Date(0))) { this.dateValue([selectedValue, null], e); } else { this.dateValue([selectedValue, endDate], e); } - } else if (this.calendar._convertToDate(selectedValue) >= this.calendar._convertToDate(startDate)) { + } else if (convertedSelectedValue + >= (this.calendar._convertToDate(startDate) ?? new Date(0))) { this.dateValue([startDate, selectedValue], e); } else { this.dateValue([selectedValue, null], e); @@ -47,49 +69,52 @@ class CalendarRangeSelectionStrategy extends CalendarSelectionStrategy { } else if (!startDate || endDate) { this.dateValue([selectedValue, null], e); } else { - this.dateValue(startDate < selectedValue ? [startDate, selectedValue] : [selectedValue, startDate], e); + this.dateValue( + startDate < selectedValue + ? [startDate, selectedValue] + : [selectedValue, startDate], + e, + ); } } - updateAriaSelected(value?, previousValue?) { - value ??= this._getValue(); - previousValue ??= []; - + updateAriaSelected(val?: (Date | null)[] | null, previousVal?: (Date | null)[] | null): void { + const value = val ?? this._getValue(); + const previousValue = previousVal ?? []; super.updateAriaSelected(value, previousValue); } - processValueChanged(value, previousValue) { + processValueChanged(value: (Date | null)[], previousValue: (Date | null)[]): void { super.processValueChanged(value, previousValue); const range = this._getRange(); this._updateViewsOption('range', range); } - getDefaultCurrentDate() { - // eslint-disable-next-line @typescript-eslint/naming-convention - const { _allowChangeSelectionOrder, _currentSelection } = this.calendar.option(); + getDefaultCurrentDate(): Date | null { + const { allowChangeSelectionOrder, currentSelection } = this.calendar.option(); const value = this.dateOption('value'); - if (_allowChangeSelectionOrder) { - if (_currentSelection === 'startDate' && value[0]) { + if (allowChangeSelectionOrder) { + if (currentSelection === 'startDate' && value[0]) { return value[0]; } - if (_currentSelection === 'endDate' && value[1]) { + if (currentSelection === 'endDate' && value[1]) { return value[1]; } } - const dates = value.filter((value) => value); + const dates = value.filter((date) => date !== null); return this._getLowestDateInArray(dates); } - restoreValue() { + restoreValue(): void { this.calendar.option('value', [null, null]); } - _getValue() { + _getValue(): (Date | null)[] { const value = this.dateOption('value'); if (!value.length) { @@ -105,53 +130,60 @@ class CalendarRangeSelectionStrategy extends CalendarSelectionStrategy { return [startDate, endDate]; } - _getRange() { + _getRange(): Date[] { const [startDate, endDate] = this._getValue(); return this._getDaysInRange(startDate, endDate); } - _getDaysInRange(startDate, endDate) { + _getDaysInRange(startDate: Date | null, endDate: Date | null): Date[] { if (!startDate || !endDate) { return []; } const { currentDate, viewsCount } = this.calendar.option(); const isAdditionalViewDate = this.calendar._isAdditionalViewDate(currentDate); - const firstDateInViews = dateUtils.getFirstMonthDate(currentDate, isAdditionalViewDate ? -2 : -1); - const lastDateInViews = dateUtils.getLastMonthDate(currentDate, isAdditionalViewDate ? 1 : viewsCount); - - // @ts-expect-error - const rangeStartDate = new Date(Math.max(firstDateInViews, startDate)); - // @ts-expect-error - const rangeEndDate = new Date(Math.min(lastDateInViews, endDate)); - - return [...dateUtils.getDatesOfInterval(rangeStartDate, rangeEndDate, DAY_INTERVAL), rangeEndDate]; + const firstDateInViews = dateUtils.getFirstMonthDate( + currentDate, + isAdditionalViewDate ? -2 : -1, + ) as Date; + const lastDateInViews = dateUtils.getLastMonthDate( + currentDate, + isAdditionalViewDate ? 1 : viewsCount, + ) as Date; + + const rangeStartDate = new Date(Math.max(firstDateInViews.getTime(), startDate.getTime())); + const rangeEndDate = new Date(Math.min(lastDateInViews.getTime(), endDate.getTime())); + + return [ + ...dateUtils.getDatesOfInterval(rangeStartDate, rangeEndDate, DAY_INTERVAL), + rangeEndDate, + ]; } - _cellHoverHandler(e) { + _cellHoverHandler(e: CellEvent): void { const isMaxZoomLevel = this._isMaxZoomLevel(); const [startDate, endDate] = this._getValue(); - // eslint-disable-next-line @typescript-eslint/naming-convention - const { _allowChangeSelectionOrder, _currentSelection } = this.calendar.option(); + + const { allowChangeSelectionOrder, currentSelection } = this.calendar.option(); if (isMaxZoomLevel) { - const skipHoveredRange = _allowChangeSelectionOrder && _currentSelection === 'startDate'; + const skipHoveredRange = allowChangeSelectionOrder && currentSelection === 'startDate'; if (startDate && !endDate && !skipHoveredRange) { if (e.value > startDate) { this._updateViewsOption('hoveredRange', this._getDaysInRange(startDate, e.value)); return; } - } else if (!startDate && endDate && !(_allowChangeSelectionOrder && _currentSelection === 'endDate')) { + } else if (!startDate && endDate && !(allowChangeSelectionOrder && currentSelection === 'endDate')) { if (e.value < endDate) { this._updateViewsOption('hoveredRange', this._getDaysInRange(e.value, endDate)); return; } } else if (startDate && endDate) { - if (_currentSelection === 'startDate' && e.value < startDate) { + if (currentSelection === 'startDate' && e.value < startDate) { this._updateViewsOption('hoveredRange', this._getDaysInRange(e.value, startDate)); return; - } if (_currentSelection === 'endDate' && e.value > endDate) { + } if (currentSelection === 'endDate' && e.value > endDate) { this._updateViewsOption('hoveredRange', this._getDaysInRange(endDate, e.value)); return; } @@ -161,9 +193,11 @@ class CalendarRangeSelectionStrategy extends CalendarSelectionStrategy { } } - _weekNumberClickHandler({ rowDates, event }) { + _weekNumberClickHandler({ rowDates, event }: WeekNumberClickEvent): void { const selectedDates = rowDates.filter((date) => !this._isDateDisabled(date)); - const value = selectedDates.length ? [selectedDates[0], selectedDates[selectedDates.length - 1]] : [null, null]; + const value = selectedDates.length + ? [selectedDates[0], selectedDates[selectedDates.length - 1]] + : [null, null]; this.dateValue(value, event); } diff --git a/packages/devextreme/js/__internal/ui/calendar/m_calendar.selection.strategy.ts b/packages/devextreme/js/__internal/ui/calendar/m_calendar.selection.strategy.ts index de434e828e48..ccf00ffba9f0 100644 --- a/packages/devextreme/js/__internal/ui/calendar/m_calendar.selection.strategy.ts +++ b/packages/devextreme/js/__internal/ui/calendar/m_calendar.selection.strategy.ts @@ -1,48 +1,54 @@ +import type { DateLike } from '@js/common'; import dateUtils from '@js/core/utils/date'; import { isDefined } from '@js/core/utils/type'; +import type { DxEvent } from '@js/events'; + +import type Calendar from './m_calendar'; class CalendarSelectionStrategy { - public NAME?: string; + public NAME!: string; - public calendar; + public calendar!: Calendar; public _currentDateChanged?: boolean; - constructor(component) { + constructor(component: Calendar) { this.calendar = component; } - dateOption(optionName) { - return this.calendar._getDateOption(optionName); - } - - dateValue(value, e) { + dateValue(value: Date | null | (Date | null)[], e: DxEvent): void { this.calendar._dateValue(value, e); } - skipNavigate() { + skipNavigate(): void { this.calendar._skipNavigate = true; } - updateAriaSelected(value, previousValue) { + updateAriaSelected(value: (Date | null)[], previousValue: (Date | null)[]): void { this.calendar._updateAriaSelected(value, previousValue); + const { currentDate = new Date() } = this.calendar.option(); - if (value[0] && this.calendar.option('currentDate').getTime() === value[0].getTime()) { + if (value[0] && currentDate.getTime() === value[0].getTime()) { this.calendar._updateAriaId(value[0]); } } - processValueChanged(value, previousValue) { + processValueChanged( + val: Date | null | (Date | null)[], + previousVal: Date | null | (Date | null)[], + ): void { + let value = val; + let previousValue = previousVal; if (isDefined(value) && !Array.isArray(value)) { value = [value]; } if (isDefined(previousValue) && !Array.isArray(previousValue)) { previousValue = [previousValue]; } - value = value?.map((item) => this._convertToDate(item)) || []; - previousValue = previousValue?.map((item) => this._convertToDate(item)) || []; + value = value?.map((item) => this._convertToDate(item)) ?? []; + previousValue = previousValue?.map((item) => this._convertToDate(item)) ?? []; - this._updateViewsValue(value); + this._updateViewsValue(value.filter((item): item is Date => item !== null)); this.updateAriaSelected(value, previousValue); if (!this._currentDateChanged) { @@ -51,7 +57,7 @@ class CalendarSelectionStrategy { this._currentDateChanged = false; } - _isDateDisabled(date) { + _isDateDisabled(date: Date): boolean { const min = this.calendar._getDateOption('min'); const max = this.calendar._getDateOption('max'); const isLessThanMin = isDefined(min) && date < min && !dateUtils.sameDate(min, date); @@ -60,37 +66,38 @@ class CalendarSelectionStrategy { return this.calendar._view.isDateDisabled(date) || isLessThanMin || isBiggerThanMax; } - // @ts-expect-error - _getLowestDateInArray(dates) { + _getLowestDateInArray(dates: (Date | null)[]): Date | null { if (dates.length) { - return new Date(Math.min(...dates)); + return new Date(Math.min(...dates.map((date) => date?.getTime() ?? Infinity))); } + + return null; } - _convertToDate(value) { + _convertToDate(value: DateLike): Date | null { return this.calendar._convertToDate(value); } - _isMaxZoomLevel() { + _isMaxZoomLevel(): boolean { return this.calendar._isMaxZoomLevel(); } - _updateViewsOption(optionName, optionValue) { + _updateViewsOption(optionName: string, optionValue: Date | Date[]): void { this.calendar._updateViewsOption(optionName, optionValue); } - _updateViewsValue(value) { + _updateViewsValue(value: Date | Date[]): void { this._updateViewsOption('value', value); } - _updateCurrentDate(value) { + _updateCurrentDate(value: Date | null): void { this.calendar.option('currentDate', value ?? new Date()); } - _shouldHandleWeekNumberClick() { + _shouldHandleWeekNumberClick(): boolean { const { selectionMode, selectWeekOnClick } = this.calendar.option(); - return selectWeekOnClick && selectionMode !== 'single'; + return selectWeekOnClick === true && selectionMode !== 'single'; } } diff --git a/packages/devextreme/js/__internal/ui/calendar/m_calendar.single.selection.strategy.ts b/packages/devextreme/js/__internal/ui/calendar/m_calendar.single.selection.strategy.ts index 73196c216cad..09c8bc75b870 100644 --- a/packages/devextreme/js/__internal/ui/calendar/m_calendar.single.selection.strategy.ts +++ b/packages/devextreme/js/__internal/ui/calendar/m_calendar.single.selection.strategy.ts @@ -1,46 +1,56 @@ +import type { DxEvent } from '@js/events'; + +import type Calendar from './m_calendar'; import CalendarSelectionStrategy from './m_calendar.selection.strategy'; class CalendarSingleSelectionStrategy extends CalendarSelectionStrategy { - constructor(component) { + constructor(component: Calendar) { super(component); this.NAME = 'SingleSelection'; } - getViewOptions() { + dateOption(optionName: 'min' | 'max' | 'value'): Date | null { + if (optionName === 'value') { + return this.calendar._getDateOption('value') as Date | null; + } + return this.calendar._getDateOption(optionName); + } + + getViewOptions(): { + value: Date | undefined; + range: Date[]; + selectionMode: 'single'; + } { + const value = this.dateOption('value') ?? undefined; + return { - value: this.dateOption('value'), + value, range: [], selectionMode: 'single', }; } - selectValue(selectedValue, e) { + selectValue(selectedValue: Date, e: DxEvent): void { this.skipNavigate(); this.dateValue(selectedValue, e); } - updateAriaSelected(value?, previousValue?) { - value ??= [this.dateOption('value')]; - previousValue ??= []; + updateAriaSelected(val?: (Date | null)[], previousVal?: (Date | null)[]): void { + const value = val ?? [this.dateOption('value')]; + const previousValue = previousVal ?? []; super.updateAriaSelected(value, previousValue); } - getDefaultCurrentDate() { - const date = this.dateOption('value'); - - if (date === '') { - return new Date(); - } - - return date; + getDefaultCurrentDate(): Date | null { + return this.dateOption('value'); } restoreValue(): void { this.calendar.option('value', null); } - _updateViewsValue(value) { + _updateViewsValue(value: Date[]): void { this._updateViewsOption('value', value[0]); } } diff --git a/packages/devextreme/js/__internal/ui/calendar/m_calendar.ts b/packages/devextreme/js/__internal/ui/calendar/m_calendar.ts index 6b23a99a34ed..6cacf4a87676 100644 --- a/packages/devextreme/js/__internal/ui/calendar/m_calendar.ts +++ b/packages/devextreme/js/__internal/ui/calendar/m_calendar.ts @@ -1,4 +1,3 @@ -import type { AnimationConfig } from '@js/common/core/animation'; import { fx } from '@js/common/core/animation'; import { move } from '@js/common/core/animation/translator'; import eventsEngine from '@js/common/core/events/core/events_engine'; @@ -37,7 +36,7 @@ import type { SwipeEndEvent, SwipeStartEvent, SwipeUpdateEvent } from '@ts/event import Button from '@ts/ui/button/wrapper'; import Editor from '@ts/ui/editor/editor'; -import type { BaseViewProperties } from './m_calendar.base_view'; +import type { BaseViewProperties, CellEvent } from './m_calendar.base_view'; import CalendarMultipleSelectionStrategy from './m_calendar.multiple.selection.strategy'; import type { NavigatorOptions } from './m_calendar.navigator'; import Navigator from './m_calendar.navigator'; @@ -96,9 +95,13 @@ export interface CalendarProperties extends Properties { todayButtonText?: string; - _rangeMin?: Date; - _rangeMax?: Date; + rangeMin?: Date; + rangeMax?: Date; + allowChangeSelectionOrder?: boolean; + currentSelection?: 'startDate' | 'endDate'; _todayDate: () => Date; + onCellClick?: (e: CellEvent) => void; + onContouredChanged?: (e: { activeElement: string }) => void; } class Calendar< @@ -112,9 +115,9 @@ class Calendar< _skipNavigate?: boolean; - _onContouredChanged?: (arg) => void; + _onContouredChanged?: (activeElement: string) => void; - _cellClickAction?: (e) => void; + _cellClickAction?: (e: CellEvent) => void; _view!: MonthView | YearView | DecadeView | CenturyView; @@ -138,7 +141,7 @@ class Calendar< _alreadyViewRender?: boolean; - _waitRenderViewTimeout?: ReturnType; + _waitRenderViewTimeout?: NodeJS.Timeout; _$footer?: dxElementWrapper; @@ -150,6 +153,8 @@ class Calendar< _isOtherViewCellClicked?: boolean; + _valueSelected?: boolean; + _getDefaultOptions(): TProperties { return { ...super._getDefaultOptions(), @@ -217,7 +222,7 @@ class Calendar< if (isCommandKeyPressed(e)) { this._navigateUp(); } else { - if (fx.isAnimating(this._view.$element())) { + if (fx.isAnimating(this._view.$element().get(0))) { return; } this._moveCurrentDateByOffset(-1 * this._view.option('colCount')); @@ -228,7 +233,7 @@ class Calendar< if (isCommandKeyPressed(e)) { this._navigateDown(); } else { - if (fx.isAnimating(this._view.$element())) { + if (fx.isAnimating(this._view.$element().get(0))) { return; } this._moveCurrentDateByOffset(1 * this._view.option('colCount')); @@ -307,14 +312,16 @@ class Calendar< return undefined; } + // eslint-disable-next-line @typescript-eslint/no-unsafe-return return dateSerialization.getDateSerializationFormat(value); } - _convertToDate(value): Date | null { + _convertToDate(value: DateLike | undefined): Date | null { + // eslint-disable-next-line @typescript-eslint/no-unsafe-return return dateSerialization.deserializeDate(value); } - _dateValue(value: Date | Date[], event: DxEvent): void { + _dateValue(value: Date | null | (Date | null)[], event: DxEvent): void { if (event) { if (event.type === 'keydown') { const cellElement = this._view._getContouredCell().get(0); @@ -336,6 +343,7 @@ class Calendar< ): void { const serializationFormat = this._getSerializationFormat(optionName); const serializedValue = this._isArrayValue(optionName, optionValue) + // eslint-disable-next-line @typescript-eslint/no-unsafe-return ? optionValue.map((value) => dateSerialization.serializeDate(value, serializationFormat)) : dateSerialization.serializeDate(optionValue, serializationFormat); @@ -345,15 +353,15 @@ class Calendar< _getDateOption(optionName: 'value'): Date | null | (Date | null)[]; _getDateOption(optionName: 'min' | 'max'): Date | null; _getDateOption(optionName: 'value' | 'min' | 'max'): Date | null | (Date | null)[] { - const { value } = this.option(); - - if (!this._isArrayValue(optionName, value)) { - const { [optionName]: optionValue } = this.option(); - + let { [optionName]: optionValue } = this.option(); + if (!this._isArrayValue(optionName, optionValue)) { + if (optionValue === '') { + optionValue = null; + } return this._convertToDate(optionValue); } - const valueArray = value ?? []; + const valueArray = optionValue ?? []; return valueArray.map((item) => this._convertToDate(item)); } @@ -599,21 +607,22 @@ class Calendar< _initCurrentDate(): void { const { currentDate = new Date() } = this.option(); - const date = this._getNormalizedDate(this._selectionStrategy.getDefaultCurrentDate()) + const defaultCurrentDate = this._selectionStrategy.getDefaultCurrentDate(); + const date = (defaultCurrentDate ? this._getNormalizedDate(defaultCurrentDate) : null) ?? this._getNormalizedDate(currentDate); this.option('currentDate', date); } - _getNormalizedDate(date: Date): Date { + _getNormalizedDate(date: Date): Date; + _getNormalizedDate(date: null): null; + _getNormalizedDate(date: Date | null): Date | null { const normalizedDate = dateUtils.normalizeDate(date, this._getMinDate(), this._getMaxDate()); return isDefined(normalizedDate) ? this._getDate(normalizedDate) : date; } - _initActions() { - // @ts-expect-error ts-error + _initActions(): void { this._cellClickAction = this._createActionByOption('onCellClick'); - // @ts-expect-error ts-error this._onContouredChanged = this._createActionByOption('onContouredChanged'); } @@ -701,7 +710,7 @@ class Calendar< } _getMinDate(): Date { - const { _rangeMin: rangeMin } = this.option(); + const { rangeMin } = this.option(); if (rangeMin) { return rangeMin; } @@ -715,7 +724,7 @@ class Calendar< } _getMaxDate(): Date { - const { _rangeMax: rangeMax } = this.option(); + const { rangeMax } = this.option(); if (rangeMax) { return rangeMax; } @@ -771,6 +780,7 @@ class Calendar< this._moveToClosestAvailableDate(date); + // eslint-disable-next-line no-restricted-globals this._waitRenderViewTimeout = setTimeout(() => { this._alreadyViewRender = false; }); @@ -1008,7 +1018,7 @@ class Calendar< return `${coefficient * 100 * rtlCorrection}%`; } - _cellClickHandler(e: { event: DxEvent; value: Date }): void { + _cellClickHandler(e: CellEvent): void { const zoomLevel = this.option('zoomLevel'); const nextView = dateUtils.getViewDown(zoomLevel); @@ -1098,7 +1108,7 @@ class Calendar< }; } - _navigatorClickHandler(e): void { + _navigatorClickHandler(e: { direction: number; event: ClickEvent }): void { const { currentDate, viewsCount } = this.option(); let offset = e.direction; @@ -1165,8 +1175,7 @@ class Calendar< } _swipeStartHandler(event: SwipeStartEvent): void { - // @ts-expect-error ts-error - fx.stop(this._$viewsWrapper, true); + fx.stop(this._$viewsWrapper.get(0), true); const { viewsCount } = this.option(); this._toggleGestureCoverCursor('grabbing'); @@ -1209,6 +1218,7 @@ class Calendar< && (rtlEnabled ? moveOffset === -1 : moveOffset === 1); if (moveOffset === 0) { + // eslint-disable-next-line @typescript-eslint/no-floating-promises this._animateWrapper(0, ANIMATION_DURATION_SHOW_VIEW); return; } @@ -1324,10 +1334,15 @@ class Calendar< .appendTo(this.$element()); const { value } = this.option(); + this._setSubmitValue(value); } - _setSubmitValue(value): void { + _setSubmitValue(value: DateLike | DateLike[] | undefined): void { + if (this._isArrayValue('value', value)) { + return; + } + const dateValue = this._convertToDate(value); this._getSubmitElement() .val(dateSerialization.serializeDate(dateValue, CALENDAR_INPUT_STANDARD_PATTERN)); @@ -1338,8 +1353,8 @@ class Calendar< } _animateShowView(): void { - // @ts-expect-error ts-error - fx.stop(this._view.$element(), true); + fx.stop(this._view.$element().get(0), true); + // eslint-disable-next-line @typescript-eslint/no-floating-promises this._popAnimationView( this._view, POP_ANIMATION_FROM, @@ -1350,8 +1365,8 @@ class Calendar< const { viewsCount } = this.option(); if (viewsCount > 1) { - // @ts-expect-error ts-error - fx.stop(this._additionalView.$element(), true); + fx.stop(this._additionalView.$element().get(0), true); + // eslint-disable-next-line @typescript-eslint/no-floating-promises this._popAnimationView( this._additionalView, POP_ANIMATION_FROM, @@ -1363,12 +1378,11 @@ class Calendar< _popAnimationView( view: MonthView | YearView | DecadeView | CenturyView, - from: AnimationConfig['from'], - to: AnimationConfig['to'], + from: number, + to: number, duration: number, ): Promise { - // @ts-expect-error ts-error - return fx.animate(view.$element(), { + return fx.animate(view.$element().get(0), { type: 'pop', from: { scale: from, @@ -1414,9 +1428,8 @@ class Calendar< } } - _animateWrapper(to: AnimationConfig['to'], duration: number): Promise { - // @ts-expect-error ts-error - return fx.animate(this._$viewsWrapper, { + _animateWrapper(to: number, duration: number): Promise { + return fx.animate(this._$viewsWrapper.get(0), { type: 'slide', // @ts-expect-error ts-error from: { left: this._$viewsWrapper.position().left }, @@ -1429,10 +1442,11 @@ class Calendar< return new Date(value); } - _toTodayView(args: ClickEvent): void { + _toTodayView(args: DxEvent): void { const today = new Date(); if (this._isMaxZoomLevel()) { + // @ts-expect-error ts-error this._selectionStrategy.selectValue(today, args.event); return; } @@ -1440,6 +1454,7 @@ class Calendar< this._preventViewChangeAnimation = true; this.option('zoomLevel', this.option('maxZoomLevel')); + // @ts-expect-error this._selectionStrategy.selectValue(today, args.event); this._animateShowView(); @@ -1463,11 +1478,11 @@ class Calendar< } const { viewsCount } = this.option(); - let viewOffset; - let viewToCreateKey; - let viewToRemoveKey; - let viewBeforeCreateKey; - let viewAfterRemoveKey; + let viewOffset = -1; + let viewToCreateKey = '_afterView'; + let viewToRemoveKey = '_beforeView'; + let viewBeforeCreateKey = viewsCount === 1 ? '_view' : '_additionalView'; + let viewAfterRemoveKey = '_view'; if (offset < 0) { viewOffset = 1; @@ -1475,12 +1490,6 @@ class Calendar< viewToRemoveKey = '_afterView'; viewBeforeCreateKey = '_view'; viewAfterRemoveKey = viewsCount === 1 ? '_view' : '_additionalView'; - } else { - viewOffset = -1; - viewToCreateKey = '_afterView'; - viewToRemoveKey = '_beforeView'; - viewBeforeCreateKey = viewsCount === 1 ? '_view' : '_additionalView'; - viewAfterRemoveKey = '_view'; } if (!this[viewToCreateKey]) { @@ -1599,21 +1608,21 @@ class Calendar< _setViewsMinOption(min: Date): void { this._restoreViewsMinMaxOptions(); - this.option('_rangeMin', this._convertToDate(min)); + this.option('rangeMin', this._convertToDate(min)); this._updateViewsOption('min', this._getMinDate()); } _setViewsMaxOption(max: Date): void { this._restoreViewsMinMaxOptions(); - this.option('_rangeMax', this._convertToDate(max)); + this.option('rangeMax', this._convertToDate(max)); this._updateViewsOption('max', this._getMaxDate()); } _restoreViewsMinMaxOptions(): void { this._resetActiveState(); this.option({ - _rangeMin: null, - _rangeMax: null, + rangeMin: null, + rangeMax: null, }); this._updateViewsOption('min', this._getMinDate()); @@ -1634,23 +1643,38 @@ class Calendar< this.setAria('label', localizedNextButtonLabel, this._navigator._nextButton.$element()); } - _updateAriaSelected(value: Date[], previousValue: Date[]): void { - previousValue.forEach((item) => { + _updateAriaSelected( + value: (Date | null)[] | null, + previousValue: (Date | null)[] | null, + ): void { + previousValue?.forEach((item) => { + if (!item) { + return; + } this.setAria('selected', false, this._view._getCellByDate(item)); }); - value.forEach((item) => { + value?.forEach((item) => { + if (!item) { + return; + } this.setAria('selected', true, this._view._getCellByDate(item)); }); const { viewsCount } = this.option(); if (viewsCount > 1) { - previousValue.forEach((item) => { + previousValue?.forEach((item) => { + if (!item) { + return; + } this.setAria('selected', false, this._additionalView._getCellByDate(item)); }); - value.forEach((item) => { + value?.forEach((item) => { + if (!item) { + return; + } this.setAria('selected', true, this._additionalView._getCellByDate(item)); }); } @@ -1710,7 +1734,7 @@ class Calendar< this._invalidate(); break; case 'currentDate': - this.setAria('id', undefined, this._view._getCellByDate(previousValue)); + this.setAria('id', undefined, this._view._getCellByDate(previousValue as Date)); this._updateCurrentDate(value as Date); break; case 'zoomLevel': @@ -1731,10 +1755,12 @@ class Calendar< const isSameValue = dateUtils.sameDatesArrays(value, previousValue); if (!isSameValue) { - this._selectionStrategy.processValueChanged(value, previousValue); + this._selectionStrategy.processValueChanged( + value as (Date | null)[], + previousValue as (Date | null)[], + ); } - - this._setSubmitValue(value); + this._setSubmitValue(value as DateLike | DateLike[] | undefined); super._optionChanged(args); break; } @@ -1746,7 +1772,6 @@ class Calendar< this._view.option('onCellClick', value); break; case 'onContouredChanged': - // @ts-expect-error ts-error this._onContouredChanged = this._createActionByOption('onContouredChanged'); break; case 'disabledDates': diff --git a/packages/devextreme/js/__internal/ui/calendar/m_calendar.views.ts b/packages/devextreme/js/__internal/ui/calendar/m_calendar.views.ts index 337d5f807f26..d85d53ba03e6 100644 --- a/packages/devextreme/js/__internal/ui/calendar/m_calendar.views.ts +++ b/packages/devextreme/js/__internal/ui/calendar/m_calendar.views.ts @@ -1,5 +1,4 @@ /* eslint-disable max-classes-per-file */ -import type { template } from '@js/common'; import dateLocalization from '@js/common/core/localization/date'; import domAdapter from '@js/core/dom_adapter'; import type { dxElementWrapper } from '@js/core/renderer'; @@ -7,7 +6,7 @@ import $ from '@js/core/renderer'; import dateUtils from '@js/core/utils/date'; import dateSerialization from '@js/core/utils/date_serialization'; import type { - CalendarSelectionMode, CellTemplateData, FirstDayOfWeek, WeekNumberRule, + CalendarSelectionMode, FirstDayOfWeek, WeekNumberRule, } from '@js/ui/calendar'; import type { BaseViewProperties } from './m_calendar.base_view'; @@ -28,10 +27,6 @@ export interface MonthViewProperties extends BaseViewProperties { selectionMode?: CalendarSelectionMode; selectWeekOnClick?: boolean; - - cellTemplate?: template | ( - (itemData: CellTemplateData, itemIndex: number, itemElement: Element) => dxElementWrapper - ); } export class MonthView extends BaseView { @@ -73,7 +68,7 @@ export class MonthView extends BaseView { const { colCount: columnsCount, showWeekNumbers } = this.option(); - for (let colIndex = 0, colCount = columnsCount; colIndex < colCount; colIndex++) { + for (let colIndex = 0, colCount = columnsCount; colIndex < colCount; colIndex += 1) { this._renderHeaderCell(colIndex, $headerRow); } @@ -82,8 +77,8 @@ export class MonthView extends BaseView { } } - _renderHeaderCell(cellIndex, $headerRow): void { - const { firstDayOfWeek } = this.option(); + _renderHeaderCell(cellIndex: number, $headerRow: dxElementWrapper): void { + const { firstDayOfWeek = 0 } = this.option(); const { full: fullCaption, @@ -100,7 +95,7 @@ export class MonthView extends BaseView { $headerRow.append($cell); } - _renderWeekHeaderCell($headerRow): void { + _renderWeekHeaderCell($headerRow: dxElementWrapper): void { const $weekNumberHeaderCell = $('') // @ts-expect-error ts-error .attr({ @@ -112,7 +107,7 @@ export class MonthView extends BaseView { $headerRow.prepend($weekNumberHeaderCell); } - _renderWeekNumberCell(rowData): void { + _renderWeekNumberCell(rowData: { cellDate: Date; prevCellDate: Date; row: HTMLElement }): void { const { showWeekNumbers, cellTemplate, @@ -139,7 +134,7 @@ export class MonthView extends BaseView { // @ts-expect-error ts-error cellTemplate.render(this._prepareCellTemplateData(weekNumber, -1, $cell)); } else { - cell.innerHTML = weekNumber; + cell.innerHTML = `${weekNumber}`; } rowData.row.prepend(cell); @@ -150,11 +145,15 @@ export class MonthView extends BaseView { }, $cell); } - _getWeekNumber(date) { - const { weekNumberRule, firstDayOfWeek } = this.option(); + _getWeekNumber(date: Date): number { + const { weekNumberRule = 'auto', firstDayOfWeek } = this.option(); if (weekNumberRule === 'auto') { - return dateUtils.getWeekNumber(date, firstDayOfWeek, firstDayOfWeek === 1 ? 'firstFourDays' : 'firstDay'); + return dateUtils.getWeekNumber( + date, + firstDayOfWeek, + firstDayOfWeek === 1 ? 'firstFourDays' : 'firstDay', + ); } return dateUtils.getWeekNumber(date, firstDayOfWeek, weekNumberRule); @@ -163,42 +162,41 @@ export class MonthView extends BaseView { getNavigatorCaption(): string { const { date } = this.option(); - // @ts-expect-error ts-error - return dateLocalization.format(date, 'monthandyear'); + return `${dateLocalization.format(date, 'monthandyear')}`; } - _isTodayCell(cellDate): boolean { + _isTodayCell(cellDate: Date): boolean { const { _todayDate: today } = this.option(); return dateUtils.sameDate(cellDate, today()); } - _isDateOutOfRange(cellDate) { + _isDateOutOfRange(cellDate: Date): boolean { const minDate = this.option('min'); const maxDate = this.option('max'); return !dateUtils.dateInRange(cellDate, minDate, maxDate, 'date'); } - _isOtherView(cellDate): boolean { + _isOtherView(cellDate: Date): boolean { const { date } = this.option(); return cellDate.getMonth() !== date.getMonth(); } - _isStartDayOfMonth(cellDate) { + _isStartDayOfMonth(cellDate: Date): boolean { return dateUtils.sameDate(cellDate, dateUtils.getFirstMonthDate(this.option('date'))); } - _isEndDayOfMonth(cellDate) { + _isEndDayOfMonth(cellDate: Date): boolean { return dateUtils.sameDate(cellDate, dateUtils.getLastMonthDate(this.option('date'))); } - _getCellText(cellDate) { - return dateLocalization.format(cellDate, 'd'); + _getCellText(cellDate: Date): string { + return `${dateLocalization.format(cellDate, 'd')}`; } - _getDayCaption(day) { + _getDayCaption(day: number): { full: string; abbreviated: string } { const { colCount: daysInWeek } = this.option(); const dayIndex = day % daysInWeek; @@ -208,11 +206,9 @@ export class MonthView extends BaseView { }; } - _getFirstCellData() { - const { firstDayOfWeek } = this.option(); - - const firstDay = dateUtils.getFirstMonthDate(this.option('date')); - // @ts-expect-error ts-error + _getFirstCellData(): Date { + const { firstDayOfWeek = 0, date } = this.option(); + const firstDay = dateUtils.getFirstMonthDate(date) as Date; let firstMonthDayOffset = firstDayOfWeek - firstDay.getDay(); const { colCount: daysInWeek } = this.option(); @@ -220,39 +216,34 @@ export class MonthView extends BaseView { firstMonthDayOffset -= daysInWeek; } - // @ts-expect-error ts-error firstDay.setDate(firstDay.getDate() + firstMonthDayOffset); return firstDay; } - _getNextCellData(date?) { - date = new Date(date); - date.setDate(date.getDate() + 1); - return date; + _getNextCellData(date: Date): Date { + const newDate = new Date(date); + newDate.setDate(newDate.getDate() + 1); + + return newDate; } - _getCellByDate(date) { + _getCellByDate(date: Date): dxElementWrapper { return this._$table.find(`td[data-value='${dateSerialization.serializeDate(date, dateUtils.getShortDateFormat())}']`); } - isBoundary(date) { + isBoundary(date: Date): boolean { return dateUtils.sameMonthAndYear(date, this.option('min')) || dateUtils.sameMonthAndYear(date, this.option('max')); } - _getDefaultDisabledDatesHandler(disabledDates) { - // @ts-expect-error - return function (args) { - const isDisabledDate = disabledDates.some((item) => dateUtils.sameDate(item, args.date)); - - if (isDisabledDate) { - return true; - } - }; + _getDefaultDisabledDatesHandler( + disabledDates: Date[], + ): (args: { date: Date }) => boolean { + return (args) => disabledDates.some((item) => dateUtils.sameDate(item, args.date)); } } export class YearView extends BaseView { - _getViewName() { + _getViewName(): string { return 'year'; } @@ -260,30 +251,29 @@ export class YearView extends BaseView { return 'monthandyear'; } - _isTodayCell(cellDate) { + _isTodayCell(cellDate: Date): boolean { const { _todayDate: today } = this.option(); return dateUtils.sameMonthAndYear(cellDate, today()); } - _isDateOutOfRange(cellDate) { + _isDateOutOfRange(cellDate: Date): boolean { return !dateUtils.dateInRange(cellDate, dateUtils.getFirstMonthDate(this.option('min')), dateUtils.getLastMonthDate(this.option('max'))); } - _isOtherView() { + _isOtherView(): boolean { return false; } - _isStartDayOfMonth() { + _isStartDayOfMonth(): boolean { return false; } - _isEndDayOfMonth() { + _isEndDayOfMonth(): boolean { return false; } - // eslint-disable-next-line class-methods-use-this - _getCellText(cellDate): string { + _getCellText(cellDate: Date): string { return dateLocalization.getMonthNames('abbreviated')[cellDate.getMonth()]; } @@ -297,13 +287,14 @@ export class YearView extends BaseView { return data; } - _getNextCellData(date) { - date = new Date(date); - date.setMonth(date.getMonth() + 1); - return date; + _getNextCellData(date: Date): Date { + const newDate = new Date(date); + newDate.setMonth(newDate.getMonth() + 1); + + return newDate; } - _getCellByDate(date) { + _getCellByDate(date: Date): dxElementWrapper { const foundDate = new Date(date); foundDate.setDate(1); @@ -316,59 +307,59 @@ export class YearView extends BaseView { return `${dateLocalization.format(date, 'yyyy')}`; } - isBoundary(date) { + isBoundary(date: Date): boolean { return dateUtils.sameYear(date, this.option('min')) || dateUtils.sameYear(date, this.option('max')); } - _renderWeekNumberCell() {} + _renderWeekNumberCell(): void {} } export class DecadeView extends BaseView { - _getViewName() { + _getViewName(): string { return 'decade'; } - _isTodayCell(cellDate) { + _isTodayCell(cellDate: Date): boolean { const { _todayDate: today } = this.option(); return dateUtils.sameYear(cellDate, today()); } - _isDateOutOfRange(cellDate): boolean { - const min = this.option('min'); - const max = this.option('max'); - // @ts-expect-error ts-error + _isDateOutOfRange(cellDate: Date): boolean { + const { min, max } = this.option(); + return !dateUtils.dateInRange(cellDate.getFullYear(), min?.getFullYear(), max?.getFullYear()); } - _isOtherView(cellDate) { + _isOtherView(cellDate: Date): boolean { const date = new Date(cellDate); date.setMonth(1); return !dateUtils.sameDecade(date, this.option('date')); } - _isStartDayOfMonth() { + _isStartDayOfMonth(): boolean { return false; } - _isEndDayOfMonth() { + _isEndDayOfMonth(): boolean { return false; } - _getCellText(cellDate) { - return dateLocalization.format(cellDate, 'yyyy'); + _getCellText(cellDate: Date): string { + return `${dateLocalization.format(cellDate, 'yyyy')}`; } - _getFirstCellData() { + _getFirstCellData(): Date { const year = dateUtils.getFirstYearInDecade(this.option('date')) - 1; return dateUtils.createDateWithFullYear(year, 0, 1); } - _getNextCellData(date): Date { - date = new Date(date); - date.setFullYear(date.getFullYear() + 1); - return date; + _getNextCellData(date: Date): Date { + const newDate = new Date(date); + newDate.setFullYear(newDate.getFullYear() + 1); + + return newDate; } getNavigatorCaption(): string { @@ -383,11 +374,11 @@ export class DecadeView extends BaseView { return `${dateLocalization.format(startDate, 'yyyy')}-${dateLocalization.format(endDate, 'yyyy')}`; } - _isValueOnCurrentView(currentDate, value) { + _isValueOnCurrentView(currentDate: Date, value: Date): boolean { return dateUtils.sameDecade(currentDate, value); } - _getCellByDate(date) { + _getCellByDate(date: Date): dxElementWrapper { const foundDate = new Date(date); foundDate.setDate(1); foundDate.setMonth(0); @@ -395,25 +386,25 @@ export class DecadeView extends BaseView { return this._$table.find(`td[data-value='${dateSerialization.serializeDate(foundDate, dateUtils.getShortDateFormat())}']`); } - isBoundary(date) { + isBoundary(date: Date): boolean { return dateUtils.sameDecade(date, this.option('min')) || dateUtils.sameDecade(date, this.option('max')); } - _renderWeekNumberCell() {} + _renderWeekNumberCell(): void {} } export class CenturyView extends BaseView { - _getViewName() { + _getViewName(): string { return 'century'; } - _isTodayCell(cellDate) { + _isTodayCell(cellDate: Date): boolean { const { _todayDate: today } = this.option(); return dateUtils.sameDecade(cellDate, today()); } - _isDateOutOfRange(cellDate) { + _isDateOutOfRange(cellDate: Date): boolean { const decade = dateUtils.getFirstYearInDecade(cellDate); const minDecade = dateUtils.getFirstYearInDecade(this.option('min')); const maxDecade = dateUtils.getFirstYearInDecade(this.option('max')); @@ -421,22 +412,22 @@ export class CenturyView extends BaseView { return !dateUtils.dateInRange(decade, minDecade, maxDecade); } - _isOtherView(cellDate) { + _isOtherView(cellDate: Date): boolean { const date = new Date(cellDate); date.setMonth(1); return !dateUtils.sameCentury(date, this.option('date')); } - _isStartDayOfMonth() { + _isStartDayOfMonth(): boolean { return false; } - _isEndDayOfMonth() { + _isEndDayOfMonth(): boolean { return false; } - _getCellText(cellDate): string { + _getCellText(cellDate: Date): string { const startDate = dateLocalization.format(cellDate, 'yyyy'); const endDate = new Date(cellDate); @@ -445,18 +436,19 @@ export class CenturyView extends BaseView { return `${startDate} - ${dateLocalization.format(endDate, 'yyyy')}`; } - _getFirstCellData() { + _getFirstCellData(): Date { const decade = dateUtils.getFirstDecadeInCentury(this.option('date')) - 10; return dateUtils.createDateWithFullYear(decade, 0, 1); } - _getNextCellData(date) { - date = new Date(date); - date.setFullYear(date.getFullYear() + 10); - return date; + _getNextCellData(date: Date): Date { + const newDate = new Date(date); + newDate.setFullYear(newDate.getFullYear() + 10); + + return newDate; } - _getCellByDate(date) { + _getCellByDate(date: Date): dxElementWrapper { const foundDate = new Date(date); foundDate.setDate(1); foundDate.setMonth(0); @@ -477,7 +469,7 @@ export class CenturyView extends BaseView { return `${dateLocalization.format(startDate, 'yyyy')}-${dateLocalization.format(endDate, 'yyyy')}`; } - isBoundary(date) { + isBoundary(date: Date): boolean { return dateUtils.sameCentury(date, this.option('min')) || dateUtils.sameCentury(date, this.option('max')); } diff --git a/packages/devextreme/js/__internal/ui/date_range_box/m_date_range_box.ts b/packages/devextreme/js/__internal/ui/date_range_box/m_date_range_box.ts index f0eecbaca3fa..87ccccac5fc4 100644 --- a/packages/devextreme/js/__internal/ui/date_range_box/m_date_range_box.ts +++ b/packages/devextreme/js/__internal/ui/date_range_box/m_date_range_box.ts @@ -149,7 +149,7 @@ class DateRangeBox extends Editor { value: [null, null], valueChangeEvent: 'change', _internalValidationErrors: [], - _currentSelection: 'startDate', + currentSelection: 'startDate', }); } @@ -1061,7 +1061,7 @@ class DateRangeBox extends Editor { break; } - case '_currentSelection': + case 'currentSelection': break; default: // @ts-expect-error diff --git a/packages/devextreme/js/__internal/ui/date_range_box/m_multiselect_date_box.ts b/packages/devextreme/js/__internal/ui/date_range_box/m_multiselect_date_box.ts index ba789d13cdbb..de786de86282 100644 --- a/packages/devextreme/js/__internal/ui/date_range_box/m_multiselect_date_box.ts +++ b/packages/devextreme/js/__internal/ui/date_range_box/m_multiselect_date_box.ts @@ -159,10 +159,10 @@ class MultiselectDateBox extends TypedDateBox { const dateRangeBox = this._getDateRangeBox(); const [startDateInput, endDateInput] = dateRangeBox.field(); if ($(target).is($(startDateInput))) { - dateRangeBox.option('_currentSelection', 'startDate'); + dateRangeBox.option('currentSelection', 'startDate'); } if ($(target).is($(endDateInput))) { - dateRangeBox.option('_currentSelection', 'endDate'); + dateRangeBox.option('currentSelection', 'endDate'); } if (!dateRangeBox.getStartDateBox().getStrategy().getWidget()) { @@ -181,7 +181,7 @@ class MultiselectDateBox extends TypedDateBox { calendar.option('currentDate', startDate); } this.getStrategy().setActiveStartDateBox(); - calendar.option('_currentSelection', 'startDate'); + calendar.option('currentSelection', 'startDate'); if (dateRangeBox.option('disableOutOfRangeSelection')) { // @ts-expect-error @@ -203,7 +203,7 @@ class MultiselectDateBox extends TypedDateBox { calendar.option('currentDate', endDate); } dateRangeBox.getStartDateBox().getStrategy().setActiveEndDateBox(); - calendar.option('_currentSelection', 'endDate'); + calendar.option('currentSelection', 'endDate'); if (dateRangeBox.option('disableOutOfRangeSelection')) { // @ts-expect-error diff --git a/packages/devextreme/js/__internal/ui/date_range_box/strategy/m_rangeCalendar.ts b/packages/devextreme/js/__internal/ui/date_range_box/strategy/m_rangeCalendar.ts index 47475137df67..179a411b42c1 100644 --- a/packages/devextreme/js/__internal/ui/date_range_box/strategy/m_rangeCalendar.ts +++ b/packages/devextreme/js/__internal/ui/date_range_box/strategy/m_rangeCalendar.ts @@ -133,8 +133,8 @@ class RangeCalendarStrategy extends CalendarStrategy { value, selectionMode: 'range', viewsCount: multiView ? 2 : 1, - _allowChangeSelectionOrder: true, - _currentSelection: this.getCurrentSelection(), + allowChangeSelectionOrder: true, + currentSelection: this.getCurrentSelection(), }); } @@ -234,11 +234,11 @@ class RangeCalendarStrategy extends CalendarStrategy { } getCurrentSelection() { - return this.getDateRangeBox().option('_currentSelection'); + return this.getDateRangeBox().option('currentSelection'); } _getCalendarCurrentSelection() { - return this.getWidget().option('_currentSelection'); + return this.getWidget().option('currentSelection'); } _closeDropDownByEnter(): boolean { diff --git a/packages/devextreme/js/ui/calendar.d.ts b/packages/devextreme/js/ui/calendar.d.ts index 4d710412e16a..068c55287281 100644 --- a/packages/devextreme/js/ui/calendar.d.ts +++ b/packages/devextreme/js/ui/calendar.d.ts @@ -78,7 +78,7 @@ export type ValueChangedEvent = NativeEventInfo { - QUnit.test(`Click by cell should change startDate value if _allowChangeSelectionOrder is true and _currentSelection is startDate, initial value: ${JSON.stringify(value)}`, function(assert) { + QUnit.test(`Click by cell should change startDate value if allowChangeSelectionOrder is true and currentSelection is startDate, initial value: ${JSON.stringify(value)}`, function(assert) { this.reinit({ value, selectionMode: 'range', - _allowChangeSelectionOrder: true, - _currentSelection: 'startDate', + allowChangeSelectionOrder: true, + currentSelection: 'startDate', }); let $startDateCell = $(this.calendar.$element()).find(`.${CALENDAR_CELL_CLASS}`).eq(20); @@ -2444,12 +2444,12 @@ QUnit.module('Options', { assert.deepEqual(this.calendar.option('value'), [startCellDate, value[1]]); }); - QUnit.test(`Click by cell should change startDate value and reselect endDate if _allowChangeSelectionOrder is true and _currentSelection is startDate, startDate > endDate, initial value: ${JSON.stringify(value)}`, function(assert) { + QUnit.test(`Click by cell should change startDate value and reselect endDate if allowChangeSelectionOrder is true and currentSelection is startDate, startDate > endDate, initial value: ${JSON.stringify(value)}`, function(assert) { this.reinit({ value, selectionMode: 'range', - _allowChangeSelectionOrder: true, - _currentSelection: 'startDate', + allowChangeSelectionOrder: true, + currentSelection: 'startDate', }); const $startDateCell = $(this.calendar.$element()).find(`.${CALENDAR_CELL_CLASS}`).eq(30); @@ -2459,12 +2459,12 @@ QUnit.module('Options', { assert.deepEqual(this.calendar.option('value'), [startCellDate, null]); }); - QUnit.test(`Click by cell should change endDate value and reselect startDate if _allowChangeSelectionOrder is true and _currentSelection is endDate, endDate < startDate, initial value: ${JSON.stringify(value)}`, function(assert) { + QUnit.test(`Click by cell should change endDate value and reselect startDate if allowChangeSelectionOrder is true and currentSelection is endDate, endDate < startDate, initial value: ${JSON.stringify(value)}`, function(assert) { this.reinit({ value, selectionMode: 'range', - _allowChangeSelectionOrder: true, - _currentSelection: 'endDate', + allowChangeSelectionOrder: true, + currentSelection: 'endDate', }); const $endCellDate = $(this.calendar.$element()).find(`.${CALENDAR_CELL_CLASS}`).eq(7); @@ -2474,12 +2474,12 @@ QUnit.module('Options', { assert.deepEqual(this.calendar.option('value'), endCellDate < value[0] ? [endCellDate, null] : [null, endCellDate]); }); - QUnit.test(`Click by cell should change endDate value if _allowChangeSelectionOrder is true and _currentSelection is endDate, initial value: ${JSON.stringify(value)}`, function(assert) { + QUnit.test(`Click by cell should change endDate value if allowChangeSelectionOrder is true and currentSelection is endDate, initial value: ${JSON.stringify(value)}`, function(assert) { this.reinit({ value, selectionMode: 'range', - _allowChangeSelectionOrder: true, - _currentSelection: 'endDate', + allowChangeSelectionOrder: true, + currentSelection: 'endDate', }); let $endDateCell = $(this.calendar.$element()).find(`.${CALENDAR_CELL_CLASS}`).eq(25); @@ -2495,12 +2495,12 @@ QUnit.module('Options', { assert.deepEqual(this.calendar.option('value'), [value[0], endCellDate]); }); - QUnit.test(`Click by cell should change endDate then startDate value if _allowChangeSelectionOrder is true and _currentSelection is endDate then startDate, initial value: ${JSON.stringify(value)}`, function(assert) { + QUnit.test(`Click by cell should change endDate then startDate value if allowChangeSelectionOrder is true and currentSelection is endDate then startDate, initial value: ${JSON.stringify(value)}`, function(assert) { this.reinit({ value, selectionMode: 'range', - _allowChangeSelectionOrder: true, - _currentSelection: 'endDate', + allowChangeSelectionOrder: true, + currentSelection: 'endDate', }); const $endDateCell = $(this.calendar.$element()).find(`.${CALENDAR_CELL_CLASS}`).eq(30); @@ -2509,7 +2509,7 @@ QUnit.module('Options', { assert.deepEqual(this.calendar.option('value'), [value[0], endCellDate]); - this.calendar.option('_currentSelection', 'startDate'); + this.calendar.option('currentSelection', 'startDate'); const $startDateCell = $(this.calendar.$element()).find(`.${CALENDAR_CELL_CLASS}`).eq(10); const startCellDate = dataUtils.data($startDateCell.get(0), CALENDAR_DATE_VALUE_KEY); @@ -2519,12 +2519,12 @@ QUnit.module('Options', { }); }); - QUnit.test('Range should not be displayed on cell hover if only startDate is defined and _allowChangeSelectionOrder is true and _currentSelection is startDate', function(assert) { + QUnit.test('Range should not be displayed on cell hover if only startDate is defined and allowChangeSelectionOrder is true and currentSelection is startDate', function(assert) { this.reinit({ value: ['2023/04/01', null], selectionMode: 'range', - _allowChangeSelectionOrder: true, - _currentSelection: 'startDate', + allowChangeSelectionOrder: true, + currentSelection: 'startDate', }); const $cellToHover = $(this.calendar.$element()).find(`.${CALENDAR_CELL_CLASS}`).eq(20); diff --git a/packages/devextreme/ts/dx.all.d.ts b/packages/devextreme/ts/dx.all.d.ts index 3f1c02220775..6db48f96b739 100644 --- a/packages/devextreme/ts/dx.all.d.ts +++ b/packages/devextreme/ts/dx.all.d.ts @@ -9806,7 +9806,7 @@ declare module DevExpress.ui { export type CalendarSelectionMode = 'single' | 'multiple' | 'range'; export type CalendarZoomLevel = 'century' | 'decade' | 'month' | 'year'; export type CellTemplateData = { - readonly date: Date; + readonly date?: Date; readonly view: string; readonly text?: string; };