UNPKG

devextreme

Version:

HTML5 JavaScript Component Suite for Responsive Web Development

1,196 lines (1,194 loc) • 55.7 kB
/** * DevExtreme (cjs/__internal/ui/calendar/m_calendar.js) * Version: 24.2.6 * Build date: Mon Mar 17 2025 * * Copyright (c) 2012 - 2025 Developer Express Inc. ALL RIGHTS RESERVED * Read about DevExtreme licensing here: https://js.devexpress.com/Licensing/ */ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _animation = require("../../../common/core/animation"); var _translator = require("../../../common/core/animation/translator"); var _events_engine = _interopRequireDefault(require("../../../common/core/events/core/events_engine")); var _swipeable = _interopRequireDefault(require("../../../common/core/events/gesture/swipeable")); var _hover = require("../../../common/core/events/hover"); var _index = require("../../../common/core/events/utils/index"); var _date = _interopRequireDefault(require("../../../common/core/localization/date")); var _message = _interopRequireDefault(require("../../../common/core/localization/message")); var _component_registrator = _interopRequireDefault(require("../../../core/component_registrator")); var _devices = _interopRequireDefault(require("../../../core/devices")); var _guid = _interopRequireDefault(require("../../../core/guid")); var _renderer = _interopRequireDefault(require("../../../core/renderer")); var _function_template = require("../../../core/templates/function_template"); var _date2 = _interopRequireDefault(require("../../../core/utils/date")); var _date_serialization = _interopRequireDefault(require("../../../core/utils/date_serialization")); var _extend = require("../../../core/utils/extend"); var _math = require("../../../core/utils/math"); var _size = require("../../../core/utils/size"); var _type = require("../../../core/utils/type"); var _window = require("../../../core/utils/window"); var _button = _interopRequireDefault(require("../../../ui/button")); var _themes = require("../../../ui/themes"); var _editor = _interopRequireDefault(require("../../ui/editor/editor")); var _m_calendarMultipleSelection = _interopRequireDefault(require("./m_calendar.multiple.selection.strategy")); var _m_calendar = _interopRequireDefault(require("./m_calendar.navigator")); var _m_calendarRangeSelection = _interopRequireDefault(require("./m_calendar.range.selection.strategy")); var _m_calendarSingleSelection = _interopRequireDefault(require("./m_calendar.single.selection.strategy")); var _m_calendar2 = _interopRequireDefault(require("./m_calendar.views")); function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e } } function _extends() { return _extends = Object.assign ? Object.assign.bind() : function(n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) { ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]) } } return n }, _extends.apply(null, arguments) } const CALENDAR_CLASS = "dx-calendar"; const CALENDAR_BODY_CLASS = "dx-calendar-body"; const CALENDAR_CELL_CLASS = "dx-calendar-cell"; const CALENDAR_FOOTER_CLASS = "dx-calendar-footer"; const CALENDAR_TODAY_BUTTON_CLASS = "dx-calendar-today-button"; const CALENDAR_HAS_FOOTER_CLASS = "dx-calendar-with-footer"; const CALENDAR_VIEWS_WRAPPER_CLASS = "dx-calendar-views-wrapper"; const CALENDAR_VIEW_CLASS = "dx-calendar-view"; const CALENDAR_MULTIVIEW_CLASS = "dx-calendar-multiview"; const CALENDAR_RANGE_CLASS = "dx-calendar-range"; const GESTURE_COVER_CLASS = "dx-gesture-cover"; const ANIMATION_DURATION_SHOW_VIEW = 250; const POP_ANIMATION_FROM = .6; const POP_ANIMATION_TO = 1; const CALENDAR_INPUT_STANDARD_PATTERN = "yyyy-MM-dd"; const CALENDAR_DATE_VALUE_KEY = "dxDateValueKey"; const CALENDAR_DXHOVEREND_EVENT_NAME = (0, _index.addNamespace)(_hover.end, "dxCalendar"); const LEVEL_COMPARE_MAP = { month: 3, year: 2, decade: 1, century: 0 }; const ZOOM_LEVEL = { MONTH: "month", YEAR: "year", DECADE: "decade", CENTURY: "century" }; const SELECTION_STRATEGIES = { SingleSelection: _m_calendarSingleSelection.default, MultipleSelection: _m_calendarMultipleSelection.default, RangeSelection: _m_calendarRangeSelection.default }; class Calendar extends _editor.default { _getDefaultOptions() { return _extends({}, super._getDefaultOptions(), { hoverStateEnabled: true, activeStateEnabled: true, currentDate: new Date, value: null, min: new Date(1e3, 0), max: new Date(3e3, 0), viewsCount: 1, zoomLevel: ZOOM_LEVEL.MONTH, maxZoomLevel: ZOOM_LEVEL.MONTH, minZoomLevel: ZOOM_LEVEL.CENTURY, selectionMode: "single", selectWeekOnClick: true, showTodayButton: false, showWeekNumbers: false, weekNumberRule: "auto", cellTemplate: "cell", disabledDates: null, onCellClick: null, onContouredChanged: null, skipFocusCheck: false, _todayDate: () => new Date }) } _defaultOptionsRules() { return super._defaultOptionsRules().concat([{ device: () => "desktop" === _devices.default.real().deviceType && !_devices.default.isSimulator(), options: { focusStateEnabled: true } }]) } _supportedKeys() { return _extends({}, super._supportedKeys(), { rightArrow(e) { e.preventDefault(); if ((0, _index.isCommandKeyPressed)(e)) { this._waitRenderView(1) } else { this._moveCurrentDateByOffset(1 * this._getRtlCorrection()) } }, leftArrow(e) { e.preventDefault(); if ((0, _index.isCommandKeyPressed)(e)) { this._waitRenderView(-1) } else { this._moveCurrentDateByOffset(-1 * this._getRtlCorrection()) } }, upArrow(e) { e.preventDefault(); if ((0, _index.isCommandKeyPressed)(e)) { this._navigateUp() } else { if (_animation.fx.isAnimating(this._view.$element())) { return } this._moveCurrentDateByOffset(-1 * this._view.option("colCount")) } }, downArrow(e) { e.preventDefault(); if ((0, _index.isCommandKeyPressed)(e)) { this._navigateDown() } else { if (_animation.fx.isAnimating(this._view.$element())) { return } this._moveCurrentDateByOffset(1 * this._view.option("colCount")) } }, home(e) { e.preventDefault(); const zoomLevel = this.option("zoomLevel"); const currentDate = this.option("currentDate"); const min = this._dateOption("min"); if (this._view.isDateDisabled(currentDate)) { return } const date = _date2.default.sameView(zoomLevel, currentDate, min) ? min : _date2.default.getViewFirstCellDate(zoomLevel, currentDate); this._moveToClosestAvailableDate(date) }, end(e) { e.preventDefault(); const zoomLevel = this.option("zoomLevel"); const currentDate = this.option("currentDate"); const max = this._dateOption("max"); if (this._view.isDateDisabled(currentDate)) { return } const date = _date2.default.sameView(zoomLevel, currentDate, max) ? max : _date2.default.getViewLastCellDate(zoomLevel, currentDate); this._moveToClosestAvailableDate(date) }, pageUp(e) { e.preventDefault(); this._waitRenderView(-1 * this._getRtlCorrection()) }, pageDown(e) { e.preventDefault(); this._waitRenderView(1 * this._getRtlCorrection()) }, tab() {}, enter: this._enterKeyHandler }) } _enterKeyHandler(e) { if (!this._isMaxZoomLevel()) { this._navigateDown() } else if (!this._view.isDateDisabled(this.option("currentDate"))) { const value = this._updateTimeComponent(this.option("currentDate")); this._selectionStrategy.selectValue(value, e) } } _getSerializationFormat(optionName) { const value = this.option(optionName || "value"); if (this.option("dateSerializationFormat")) { return this.option("dateSerializationFormat") } if ((0, _type.isNumeric)(value)) { return "number" } if (!(0, _type.isString)(value)) { return } return _date_serialization.default.getDateSerializationFormat(value) } _convertToDate(value) { return _date_serialization.default.deserializeDate(value) } _dateValue(value, event) { if (event) { if ("keydown" === event.type) { const cellElement = this._view._getContouredCell().get(0); event.target = cellElement } this._saveValueChangeEvent(event) } this._dateOption("value", value) } _dateOption(optionName, optionValue) { const isArray = "value" === optionName && !this._isSingleMode(); const value = this.option("value"); if (1 === arguments.length) { return isArray ? (value ?? []).map((value => this._convertToDate(value))) : this._convertToDate(this.option(optionName)) } const serializationFormat = this._getSerializationFormat(optionName); const serializedValue = isArray ? (null === optionValue || void 0 === optionValue ? void 0 : optionValue.map((value => _date_serialization.default.serializeDate(value, serializationFormat)))) || [] : _date_serialization.default.serializeDate(optionValue, serializationFormat); this.option(optionName, serializedValue) } _isSingleMode() { const { selectionMode: selectionMode } = this.option(); return "single" === selectionMode } _shiftDate(zoomLevel, date, offset, reverse) { switch (zoomLevel) { case ZOOM_LEVEL.MONTH: date.setDate(date.getDate() + offset * reverse); break; case ZOOM_LEVEL.YEAR: date.setMonth(date.getMonth() + offset * reverse); break; case ZOOM_LEVEL.DECADE: date.setFullYear(date.getFullYear() + offset * reverse); break; case ZOOM_LEVEL.CENTURY: date.setFullYear(date.getFullYear() + 10 * offset * reverse) } } _moveCurrentDateByOffset(offset) { const baseDate = this.option("currentDate"); let currentDate = new Date(baseDate); const zoomLevel = this.option("zoomLevel"); this._shiftDate(zoomLevel, currentDate, offset, 1); const maxDate = this._getMaxDate(); const minDate = this._getMinDate(); let isDateForwardInNeighborView = this._areDatesInNeighborView(zoomLevel, currentDate, baseDate); let isDateForwardInRange = (0, _math.inRange)(currentDate, minDate, maxDate) && isDateForwardInNeighborView; const dateForward = new Date(currentDate); while (isDateForwardInRange) { if (!this._view.isDateDisabled(dateForward)) { currentDate = dateForward; break } this._shiftDate(zoomLevel, dateForward, offset, 1); isDateForwardInNeighborView = this._areDatesInNeighborView(zoomLevel, dateForward, baseDate); isDateForwardInRange = (0, _math.inRange)(dateForward, minDate, maxDate) && isDateForwardInNeighborView } if (this._view.isDateDisabled(baseDate) || this._view.isDateDisabled(currentDate)) { const direction = offset > 0 ? 1 : -1; const isViewDisabled = 1 === direction ? this._isNextViewDisabled() : this._isPrevViewDisabled(); if (!isViewDisabled) { this._waitRenderView(direction) } else { this._moveToClosestAvailableDate(currentDate) } } else { this._skipNavigate = true; this.option("currentDate", currentDate) } } _isNextViewDisabled() { return this._navigator._nextButton.option("disabled") } _isPrevViewDisabled() { return this._navigator._prevButton.option("disabled") } _areDatesInSameView(zoomLevel, date1, date2) { switch (zoomLevel) { case ZOOM_LEVEL.MONTH: return date1.getMonth() === date2.getMonth(); case ZOOM_LEVEL.YEAR: return date1.getYear() === date2.getYear(); case ZOOM_LEVEL.DECADE: return parseInt(date1.getYear() / 10) === parseInt(date2.getYear() / 10); case ZOOM_LEVEL.CENTURY: return parseInt(date1.getYear() / 100) === parseInt(date2.getYear() / 100) } } _areDatesInNeighborView(zoomLevel, date1, date2) { switch (zoomLevel) { case ZOOM_LEVEL.MONTH: return ((a, b) => { const abs = Math.abs(a - b); return Math.min(abs, 12 - abs) })(date1.getMonth(), date2.getMonth()) <= 1; case ZOOM_LEVEL.YEAR: return Math.abs(date1.getYear() - date2.getYear()) <= 1; case ZOOM_LEVEL.DECADE: return Math.abs(date1.getYear() - date2.getYear()) <= 10; case ZOOM_LEVEL.CENTURY: return Math.abs(date1.getYear() - date2.getYear()) <= 100 } } _moveToClosestAvailableDate() { let baseDate = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : this.option("currentDate"); let currentDate = new Date(baseDate); const zoomLevel = this.option("zoomLevel"); const isCurrentDateAvailable = !this._isDateNotAvailable(currentDate); let isDateForwardAvailable = isCurrentDateAvailable; let isDateBackwardAvailable = isCurrentDateAvailable; let isDateForwardInStartView; let isDateBackwardInStartView; const dateForward = new Date(currentDate); const dateBackward = new Date(currentDate); do { if (isDateForwardAvailable) { currentDate = dateForward; break } if (isDateBackwardAvailable) { currentDate = dateBackward; break } this._shiftDate(zoomLevel, dateForward, 1, 1); this._shiftDate(zoomLevel, dateBackward, 1, -1); isDateForwardInStartView = this._areDatesInSameView(zoomLevel, dateForward, baseDate); isDateBackwardInStartView = this._areDatesInSameView(zoomLevel, dateBackward, baseDate); isDateForwardAvailable = isDateForwardInStartView && !this._isDateNotAvailable(dateForward); isDateBackwardAvailable = isDateBackwardInStartView && !this._isDateNotAvailable(dateBackward) } while (isDateForwardInStartView || isDateBackwardInStartView); this.option("currentDate", currentDate) } _isDateNotAvailable(date) { const maxDate = this._getMaxDate(); const minDate = this._getMinDate(); return !(0, _math.inRange)(date, minDate, maxDate) || this._view.isDateDisabled(date) } _init() { super._init(); this._activeStateUnit = ".dx-calendar-cell"; this._initSelectionStrategy(); this._correctZoomLevel(); this._initCurrentDate(); this._initActions() } _initSelectionStrategy() { const strategyName = this._getSelectionStrategyName(); const strategy = SELECTION_STRATEGIES[strategyName]; if (!this._selectionStrategy || this._selectionStrategy.NAME !== strategyName) { this._selectionStrategy = new strategy(this) } } _refreshSelectionStrategy() { this._initSelectionStrategy(); this._selectionStrategy.restoreValue(); this._refresh() } _getSelectionStrategyName() { const { selectionMode: selectionMode } = this.option(); switch (selectionMode) { case "multiple": return "MultipleSelection"; case "range": return "RangeSelection"; default: return "SingleSelection" } } _correctZoomLevel() { const { minZoomLevel: minZoomLevel, maxZoomLevel: maxZoomLevel, zoomLevel: zoomLevel } = this.option(); if (LEVEL_COMPARE_MAP[maxZoomLevel] < LEVEL_COMPARE_MAP[minZoomLevel]) { return } if (LEVEL_COMPARE_MAP[zoomLevel] > LEVEL_COMPARE_MAP[maxZoomLevel]) { this.option("zoomLevel", maxZoomLevel) } else if (LEVEL_COMPARE_MAP[zoomLevel] < LEVEL_COMPARE_MAP[minZoomLevel]) { this.option("zoomLevel", minZoomLevel) } } _initCurrentDate() { const currentDate = this._getNormalizedDate(this._selectionStrategy.getDefaultCurrentDate()) ?? this._getNormalizedDate(this.option("currentDate")); this.option("currentDate", currentDate) } _getNormalizedDate(date) { date = _date2.default.normalizeDate(date, this._getMinDate(), this._getMaxDate()); return (0, _type.isDefined)(date) ? this._getDate(date) : date } _initActions() { this._cellClickAction = this._createActionByOption("onCellClick"); this._onContouredChanged = this._createActionByOption("onContouredChanged") } _initTemplates() { this._templateManager.addDefaultTemplates({ cell: new _function_template.FunctionTemplate((options => { const data = options.model; (0, _renderer.default)(options.container).append((0, _renderer.default)("<span>").text(data && data.text || String(data))) })) }); super._initTemplates() } _updateCurrentDate(date) { if (_animation.fx.isAnimating(this._$viewsWrapper)) { _animation.fx.stop(this._$viewsWrapper, true) } const min = this._getMinDate(); const max = this._getMaxDate(); if (min > max) { this.option("currentDate", new Date); return } const normalizedDate = this._getNormalizedDate(date); if (date.getTime() !== normalizedDate.getTime()) { this.option("currentDate", new Date(normalizedDate)); return } let offset = this._getViewsOffset(this._view.option("date"), normalizedDate); if (0 !== offset && !this._isMaxZoomLevel() && this._isOtherViewCellClicked) { offset = 0 } if (this._view && 0 !== offset && !this._suppressNavigation) { if (this._additionalView) { if (offset > 2 || offset < -1) { this._refreshViews(); this._setViewContoured(normalizedDate); this._updateAriaId(normalizedDate); this._renderNavigator() } else if (1 === offset && this._skipNavigate) { this._setViewContoured(normalizedDate); this._updateAriaId(normalizedDate) } else { this._navigate(offset, normalizedDate) } } else { this._navigate(offset, normalizedDate) } } else { this._renderNavigator(); this._setViewContoured(normalizedDate); this._updateAriaId(normalizedDate) } this._skipNavigate = false } _isAdditionalViewDate(date) { if (!this._additionalView) { return false } return date >= this._additionalView._getFirstAvailableDate() } _getActiveView(date) { return this._isAdditionalViewDate(date) ? this._additionalView : this._view } _setViewContoured(date) { if (this.option("skipFocusCheck") || (0, _renderer.default)(this._$viewsWrapper).is(":focus")) { var _this$_additionalView; this._view.option("contouredDate", null); null === (_this$_additionalView = this._additionalView) || void 0 === _this$_additionalView || _this$_additionalView.option("contouredDate", null); const view = this._isAdditionalViewDate(date) ? this._additionalView : this._view; view.option("contouredDate", date) } } _getMinDate() { const _rangeMin = this.option("_rangeMin"); if (_rangeMin) { return _rangeMin } if (this.min) { return this.min } this.min = this._dateOption("min") || new Date(1e3, 0); return this.min } _getMaxDate() { const _rangeMax = this.option("_rangeMax"); if (_rangeMax) { return _rangeMax } if (this.max) { return this.max } this.max = this._dateOption("max") || new Date(3e3, 0); return this.max } _getViewsOffset(startDate, endDate) { const { zoomLevel: zoomLevel } = this.option(); if (zoomLevel === ZOOM_LEVEL.MONTH) { return this._getMonthsOffset(startDate, endDate) } let zoomCorrection; switch (zoomLevel) { case ZOOM_LEVEL.CENTURY: zoomCorrection = 100; break; case ZOOM_LEVEL.DECADE: zoomCorrection = 10; break; default: zoomCorrection = 1 } return parseInt(endDate.getFullYear() / zoomCorrection) - parseInt(startDate.getFullYear() / zoomCorrection) } _getMonthsOffset(startDate, endDate) { const yearOffset = endDate.getFullYear() - startDate.getFullYear(); const monthOffset = endDate.getMonth() - startDate.getMonth(); return 12 * yearOffset + monthOffset } _waitRenderView(offset) { if (this._alreadyViewRender) { return } this._alreadyViewRender = true; const date = this._getDateByOffset(offset * this._getRtlCorrection()); this._moveToClosestAvailableDate(date); this._waitRenderViewTimeout = setTimeout((() => { this._alreadyViewRender = false })) } _getRtlCorrection() { return this.option("rtlEnabled") ? -1 : 1 } _getDateByOffset(offset, date) { date = this._getDate(date ?? this.option("currentDate")); const currentDay = date.getDate(); const difference = _date2.default.getDifferenceInMonth(this.option("zoomLevel")) * offset; date.setDate(1); date.setMonth(date.getMonth() + difference); const lastDay = _date2.default.getLastMonthDate(date).getDate(); date.setDate(currentDay > lastDay ? lastDay : currentDay); return date } _focusTarget() { return this._$viewsWrapper } _focusEventTarget() { return this.$element() } _initMarkup() { this._renderSubmitElement(); const $element = this.$element(); $element.addClass("dx-calendar"); const { selectionMode: selectionMode } = this.option(); $element.toggleClass("dx-calendar-range", "range" === selectionMode); this._renderBody(); $element.append(this.$body); this._renderViews(); this._renderNavigator(); super._initMarkup(); this._renderEvents(); $element.prepend(this._navigator.$element()); this._renderSwipeable(); this._renderFooter(); this._selectionStrategy.updateAriaSelected(); this._updateAriaId(); this._updateNavigatorLabels(); this.setAria("role", "application"); this._updateAriaLabelAndRole(); this._moveToClosestAvailableDate() } _render() { super._render(); this._setViewContoured(this.option("currentDate")) } _renderBody() { if (!this._$viewsWrapper) { this.$body = (0, _renderer.default)("<div>").addClass("dx-calendar-body"); this._$viewsWrapper = (0, _renderer.default)("<div>").addClass("dx-calendar-views-wrapper"); this.$body.append(this._$viewsWrapper) } } _updateAriaLabelAndRole() { const readOnly = this.option("readOnly"); const $element = this.$element(); const aria = { role: readOnly ? "group" : void 0, label: readOnly ? _message.default.format("dxCalendar-readOnlyLabel") : void 0 }; this.setAria(aria, $element) } _setAriaReadonly() {} _getKeyboardListeners() { return super._getKeyboardListeners().concat([this._view]) } _renderViews() { const { zoomLevel: zoomLevel } = this.option(); this.$element().addClass(`dx-calendar-view-${zoomLevel}`); const { currentDate: currentDate, viewsCount: viewsCount } = this.option(); this.$element().toggleClass("dx-calendar-multiview", viewsCount > 1); this._view = this._renderSpecificView(currentDate); if ((0, _window.hasWindow)()) { const beforeDate = this._getDateByOffset(-1, currentDate); this._beforeView = this._isViewAvailable(beforeDate) ? this._renderSpecificView(beforeDate) : null; const afterDate = this._getDateByOffset(viewsCount, currentDate); afterDate.setDate(1); this._afterView = this._isViewAvailable(afterDate) ? this._renderSpecificView(afterDate) : null } if (viewsCount > 1) { this._additionalView = this._renderSpecificView(this._getDateByOffset(1, currentDate)) } this._translateViews() } _renderSpecificView(date) { const { zoomLevel: zoomLevel } = this.option(); const specificView = _m_calendar2.default[zoomLevel]; const $view = (0, _renderer.default)("<div>").appendTo(this._$viewsWrapper); const config = this._viewConfig(date); const view = this._createComponent($view, specificView, config); return view } _viewConfig(date) { let disabledDates = this.option("disabledDates"); disabledDates = (0, _type.isFunction)(disabledDates) ? this._injectComponent(disabledDates.bind(this)) : disabledDates; return _extends({}, this._selectionStrategy.getViewOptions(), { date: date, min: this._getMinDate(), max: this._getMaxDate(), firstDayOfWeek: this.option("firstDayOfWeek") ?? _date.default.firstDayOfWeekIndex(), showWeekNumbers: this.option("showWeekNumbers"), selectWeekOnClick: this.option("selectWeekOnClick"), weekNumberRule: this.option("weekNumberRule"), zoomLevel: this.option("zoomLevel"), tabIndex: void 0, focusStateEnabled: this.option("focusStateEnabled"), hoverStateEnabled: this.option("hoverStateEnabled"), disabledDates: disabledDates, onCellClick: this._cellClickHandler.bind(this), cellTemplate: this._getTemplateByOption("cellTemplate"), allowValueSelection: this._isMaxZoomLevel(), _todayDate: this.option("_todayDate") }) } _renderEvents() { _events_engine.default.off(this._$viewsWrapper, CALENDAR_DXHOVEREND_EVENT_NAME); const { selectionMode: selectionMode } = this.option(); if ("range" === selectionMode) { _events_engine.default.on(this._$viewsWrapper, CALENDAR_DXHOVEREND_EVENT_NAME, null, (() => { this._updateViewsOption("hoveredRange", []) })) } } _injectComponent(func) { const that = this; return function(params) { (0, _extend.extend)(params, { component: that }); return func(params) } } _isViewAvailable(date) { const zoomLevel = this.option("zoomLevel"); const min = _date2.default.getViewMinBoundaryDate(zoomLevel, this._getMinDate()); const max = _date2.default.getViewMaxBoundaryDate(zoomLevel, this._getMaxDate()); return _date2.default.dateInRange(date, min, max) } _translateViews() { const { viewsCount: viewsCount } = this.option(); (0, _translator.move)(this._view.$element(), { left: 0, top: 0 }); this._moveViewElement(this._beforeView, -1); this._moveViewElement(this._afterView, viewsCount); this._moveViewElement(this._additionalView, 1) } _moveViewElement(view, coefficient) { view && (0, _translator.move)(view.$element(), { left: this._getViewPosition(coefficient), top: 0 }) } _getViewPosition(coefficient) { const rtlCorrection = this.option("rtlEnabled") ? -1 : 1; return 100 * coefficient * rtlCorrection + "%" } _cellClickHandler(e) { const zoomLevel = this.option("zoomLevel"); const nextView = _date2.default.getViewDown(zoomLevel); const isMaxZoomLevel = this._isMaxZoomLevel(); if (nextView && !isMaxZoomLevel) { this._navigateDown(e.event.currentTarget) } else { var _this$_cellClickActio; const newValue = this._updateTimeComponent(e.value); this._selectionStrategy.selectValue(newValue, e.event); null === (_this$_cellClickActio = this._cellClickAction) || void 0 === _this$_cellClickActio || _this$_cellClickActio.call(this, e) } } _updateTimeComponent(date) { const result = new Date(date); const currentValue = this._dateOption("value"); if (currentValue && this._isSingleMode()) { result.setHours(currentValue.getHours()); result.setMinutes(currentValue.getMinutes()); result.setSeconds(currentValue.getSeconds()); result.setMilliseconds(currentValue.getMilliseconds()) } return result } _isMaxZoomLevel() { return this.option("zoomLevel") === this.option("maxZoomLevel") } _navigateDown(cell) { const zoomLevel = this.option("zoomLevel"); if (this._isMaxZoomLevel()) { return } const nextView = _date2.default.getViewDown(zoomLevel); if (!nextView) { return } let newCurrentDate = this._view.option("contouredDate") || this._view.option("date"); if (cell) { newCurrentDate = (0, _renderer.default)(cell).data("dxDateValueKey") } this._isOtherViewCellClicked = true; this.option("currentDate", newCurrentDate); this.option("zoomLevel", nextView); this._isOtherViewCellClicked = false; this._renderNavigator(); this._animateShowView(); this._moveToClosestAvailableDate(); this._setViewContoured(this._getNormalizedDate(this.option("currentDate"))) } _renderNavigator() { if (!this._navigator) { this._navigator = new _m_calendar.default((0, _renderer.default)("<div>"), this._navigatorConfig()) } this._navigator.option("text", this._getViewsCaption(this._view, this._additionalView)); this._updateButtonsVisibility() } _navigatorConfig() { const { focusStateEnabled: focusStateEnabled, rtlEnabled: rtlEnabled } = this.option(); return { text: this._getViewsCaption(this._view, this._additionalView), onClick: this._navigatorClickHandler.bind(this), onCaptionClick: this._navigateUp.bind(this), focusStateEnabled: focusStateEnabled, rtlEnabled: rtlEnabled, tabIndex: void 0 } } _navigatorClickHandler(e) { const { currentDate: currentDate, viewsCount: viewsCount } = this.option(); let offset = e.direction; if (viewsCount > 1) { const additionalViewActive = this._isAdditionalViewDate(currentDate); const shouldDoubleOffset = additionalViewActive && offset < 0 || !additionalViewActive && offset > 0; if (shouldDoubleOffset) { offset *= 2 } } const newCurrentDate = this._getDateByOffset(offset, currentDate); this._moveToClosestAvailableDate(newCurrentDate) } _navigateUp() { const zoomLevel = this.option("zoomLevel"); const nextView = _date2.default.getViewUp(zoomLevel); if (!nextView || this._isMinZoomLevel(zoomLevel)) { return } this.option("zoomLevel", nextView); this._renderNavigator(); this._animateShowView(); this._moveToClosestAvailableDate(); this._setViewContoured(this._getNormalizedDate(this.option("currentDate"))) } _isMinZoomLevel(zoomLevel) { const min = this._getMinDate(); const max = this._getMaxDate(); return _date2.default.sameView(zoomLevel, min, max) || this.option("minZoomLevel") === zoomLevel } _updateButtonsVisibility() { this._navigator.toggleButton("next", !(0, _type.isDefined)(this._afterView)); this._navigator.toggleButton("prev", !(0, _type.isDefined)(this._beforeView)) } _renderSwipeable() { if (!this._swipeable) { this._swipeable = this._createComponent(this.$element(), _swipeable.default, { onStart: this._swipeStartHandler.bind(this), onUpdated: this._swipeUpdateHandler.bind(this), onEnd: this._swipeEndHandler.bind(this), itemSizeFunc: this._viewWidth.bind(this) }) } } _swipeStartHandler(e) { _animation.fx.stop(this._$viewsWrapper, true); const { viewsCount: viewsCount } = this.option(); this._toggleGestureCoverCursor("grabbing"); e.event.maxLeftOffset = this._getRequiredView("next") ? 1 / viewsCount : 0; e.event.maxRightOffset = this._getRequiredView("prev") ? 1 / viewsCount : 0 } _toggleGestureCoverCursor(cursor) { (0, _renderer.default)(".dx-gesture-cover").css("cursor", cursor) } _getRequiredView(name) { let view; const isRtl = this.option("rtlEnabled"); if ("next" === name) { view = isRtl ? this._beforeView : this._afterView } else if ("prev" === name) { view = isRtl ? this._afterView : this._beforeView } return view } _swipeUpdateHandler(e) { const { offset: offset } = e.event; (0, _translator.move)(this._$viewsWrapper, { left: offset * this._viewWidth(), top: 0 }); this._updateNavigatorCaption(offset) } _swipeEndHandler(e) { this._toggleGestureCoverCursor("auto"); const { currentDate: currentDate, rtlEnabled: rtlEnabled } = this.option(); const { targetOffset: targetOffset } = e.event; const moveOffset = !targetOffset ? 0 : targetOffset / Math.abs(targetOffset); const isAdditionalViewActive = this._isAdditionalViewDate(currentDate); const shouldDoubleOffset = isAdditionalViewActive && (rtlEnabled ? -1 === moveOffset : 1 === moveOffset); if (0 === moveOffset) { this._animateWrapper(0, 250); return } const offset = -moveOffset * this._getRtlCorrection() * (shouldDoubleOffset ? 2 : 1); let date = this._getDateByOffset(offset); if (this._isDateInInvalidRange(date)) { if (moveOffset >= 0) { date = new Date(this._getMinDate()) } else { date = new Date(this._getMaxDate()) } } this.option("currentDate", date) } _viewWidth() { if (!this._viewWidthValue) { const { viewsCount: viewsCount } = this.option(); this._viewWidthValue = (0, _size.getWidth)(this.$element()) / viewsCount } return this._viewWidthValue } _updateNavigatorCaption(offset) { offset *= this._getRtlCorrection(); const { viewsCount: viewsCount } = this.option(); const isMultiView = viewsCount > 1; let view; let additionalView; if (offset > .5 && this._beforeView) { view = this._beforeView; additionalView = isMultiView && this._view } else if (offset < -.5 && this._afterView) { view = isMultiView ? this._additionalView : this._afterView; additionalView = isMultiView ? this._afterView : null } else { view = this._view; additionalView = isMultiView ? this._additionalView : null } this._navigator.option("text", this._getViewsCaption(view, additionalView)) } _getViewsCaption(view, additionalView) { let caption = view.getNavigatorCaption(); const { viewsCount: viewsCount } = this.option(); if (viewsCount > 1 && additionalView) { const additionalViewCaption = additionalView.getNavigatorCaption(); caption = `${caption} - ${additionalViewCaption}` } return caption } _isDateInInvalidRange(date) { if (this._view.isBoundary(date)) { return } const min = this._getMinDate(); const max = this._getMaxDate(); const normalizedDate = _date2.default.normalizeDate(date, min, max); return normalizedDate === min || normalizedDate === max } _renderFooter() { const showTodayButton = this.option("showTodayButton"); if (showTodayButton) { const $todayButton = this._createComponent((0, _renderer.default)("<div>"), _button.default, { focusStateEnabled: this.option("focusStateEnabled"), text: _message.default.format("dxCalendar-todayButtonText"), onClick: args => { this._toTodayView(args) }, type: (0, _themes.isFluent)() ? "normal" : "default", stylingMode: (0, _themes.isFluent)() ? "outlined" : "text", integrationOptions: {} }).$element().addClass("dx-calendar-today-button"); this._$footer = (0, _renderer.default)("<div>").addClass("dx-calendar-footer").append($todayButton); this.$element().append(this._$footer) } this.$element().toggleClass("dx-calendar-with-footer", showTodayButton) } _renderSubmitElement() { this._$submitElement = (0, _renderer.default)("<input>").attr("type", "hidden").appendTo(this.$element()); this._setSubmitValue(this.option("value")) } _setSubmitValue(value) { const dateValue = this._convertToDate(value); this._getSubmitElement().val(_date_serialization.default.serializeDate(dateValue, "yyyy-MM-dd")) } _getSubmitElement() { return this._$submitElement } _animateShowView() { _animation.fx.stop(this._view.$element(), true); this._popAnimationView(this._view, .6, 1, 250); const { viewsCount: viewsCount } = this.option(); if (viewsCount > 1) { _animation.fx.stop(this._additionalView.$element(), true); this._popAnimationView(this._additionalView, .6, 1, 250) } } _popAnimationView(view, from, to, duration) { return _animation.fx.animate(view.$element(), { type: "pop", from: { scale: from, opacity: from }, to: { scale: to, opacity: to }, duration: duration }) } _navigate(offset, value) { if (0 !== offset && 1 !== Math.abs(offset) && this._isViewAvailable(value)) { const newView = this._renderSpecificView(value); if (offset > 0) { this._afterView && this._afterView.$element().remove(); this._afterView = newView } else { this._beforeView && this._beforeView.$element().remove(); this._beforeView = newView } this._translateViews() } const rtlCorrection = this._getRtlCorrection(); const offsetSign = offset > 0 ? 1 : offset < 0 ? -1 : 0; const endPosition = -rtlCorrection * offsetSign * this._viewWidth(); const viewsWrapperPosition = this._$viewsWrapper.position().left; if (viewsWrapperPosition !== endPosition) { if (this._preventViewChangeAnimation) { this._wrapperAnimationEndHandler(offset, value) } else { this._animateWrapper(endPosition, 250).done(this._wrapperAnimationEndHandler.bind(this, offset, value)) } } } _animateWrapper(to, duration) { return _animation.fx.animate(this._$viewsWrapper, { type: "slide", from: { left: this._$viewsWrapper.position().left }, to: { left: to }, duration: duration }) } _getDate(value) { return new Date(value) } _toTodayView(args) { const today = new Date; if (this._isMaxZoomLevel()) { this._selectionStrategy.selectValue(today, args.event); return } this._preventViewChangeAnimation = true; this.option("zoomLevel", this.option("maxZoomLevel")); this._selectionStrategy.selectValue(today, args.event); this._animateShowView(); this._preventViewChangeAnimation = false } _wrapperAnimationEndHandler(offset, newDate) { this._rearrangeViews(offset); this._translateViews(); this._resetLocation(); this._renderNavigator(); this._setViewContoured(newDate); this._updateAriaId(newDate); this._selectionStrategy.updateAriaSelected() } _rearrangeViews(offset) { var _this$viewToRemoveKey; if (0 === offset) { return } const { viewsCount: viewsCount } = this.option(); let viewOffset; let viewToCreateKey; let viewToRemoveKey; let viewBeforeCreateKey; let viewAfterRemoveKey; if (offset < 0) { viewOffset = 1; viewToCreateKey = "_beforeView"; viewToRemoveKey = "_afterView"; viewBeforeCreateKey = "_view"; viewAfterRemoveKey = 1 === viewsCount ? "_view" : "_additionalView" } else { viewOffset = -1; viewToCreateKey = "_afterView"; viewToRemoveKey = "_beforeView"; viewBeforeCreateKey = 1 === viewsCount ? "_view" : "_additionalView"; viewAfterRemoveKey = "_view" } if (!this[viewToCreateKey]) { return } const destinationDate = this[viewToCreateKey].option("date"); null === (_this$viewToRemoveKey = this[viewToRemoveKey]) || void 0 === _this$viewToRemoveKey || _this$viewToRemoveKey.$element().remove(); this[viewToRemoveKey] = this._renderSpecificView(this._getDateByOffset(viewOffset * viewsCount, destinationDate)); this[viewAfterRemoveKey].$element().remove(); if (1 === viewsCount) { this[viewAfterRemoveKey] = this[viewToCreateKey] } else { this[viewAfterRemoveKey] = this[viewBeforeCreateKey]; this[viewBeforeCreateKey] = this[viewToCreateKey] } const dateByOffset = this._getDateByOffset(-viewOffset, destinationDate); this[viewToCreateKey] = this._isViewAvailable(dateByOffset) ? this._renderSpecificView(dateByOffset) : null } _resetLocation() { (0, _translator.move)(this._$viewsWrapper, { left: 0, top: 0 }) } _clean() { super._clean(); this._clearViewWidthCache(); delete this._$viewsWrapper; delete this._navigator; delete this._$footer } _clearViewWidthCache() { delete this._viewWidthValue } _disposeViews() { var _this$_beforeView, _this$_additionalView2, _this$_afterView; this._view.$element().remove(); null === (_this$_beforeView = this._beforeView) || void 0 === _this$_beforeView || _this$_beforeView.$element().remove(); null === (_this$_additionalView2 = this._additionalView) || void 0 === _this$_additionalView2 || _this$_additionalView2.$element().remove(); null === (_this$_afterView = this._afterView) || void 0 === _this$_afterView || _this$_afterView.$element().remove(); delete this._view; delete this._additionalView; delete this._beforeView; delete this._afterView; delete this._skipNavigate } _dispose() { clearTimeout(this._waitRenderViewTimeout); super._dispose() } _refreshViews() { this._resetActiveState(); this._disposeViews(); this._renderViews() } _visibilityChanged() { this._translateViews() } _shouldSkipFocusEvent(event) { const { target: target, relatedTarget: relatedTarget } = event; return (0, _renderer.default)(target).parents(".dx-calendar").length && (0, _renderer.default)(relatedTarget).parents(".dx-calendar").length } _focusInHandler(event) { if ((0, _renderer.default)(event.target).is(this._$viewsWrapper)) { this._setViewContoured(this.option("currentDate")) } if (this._shouldSkipFocusEvent(event)) { return } super._focusInHandler.apply(this, arguments); this._toggleFocusClass(true, this.$element()) } _focusOutHandler(event) { if ((0, _renderer.default)(event.target).is(this._$viewsWrapper)) { var _this$_additionalView3; this._view.option("contouredDate", null); null === (_this$_additionalView3 = this._additionalView) || void 0 === _this$_additionalView3 || _this$_additionalView3.option("contouredDate", null) } if (this._shouldSkipFocusEvent(event)) { return } super._focusOutHandler.apply(this, arguments); this._toggleFocusClass(false, this.$element()) } _updateViewsOption(optionName, newValue) { var _this$_additionalView4, _this$_beforeView2, _this$_afterView2; this._view.option(optionName, newValue); null === (_this$_additionalView4 = this._additionalView) || void 0 === _this$_additionalView4 || _this$_additionalView4.option(optionName, newValue); null === (_this$_beforeView2 = this._beforeView) || void 0 === _this$_beforeView2 || _this$_beforeView2.option(optionName, newValue); null === (_this$_afterView2 = this._afterView) || void 0 === _this$_afterView2 || _this$_afterView2.option(optionName, newValue) } _setViewsMinOption(min) { this._restoreViewsMinMaxOptions(); this.option("_rangeMin", this._convertToDate(min)); this._updateViewsOption("min", this._getMinDate()) } _setViewsMaxOption(max) { this._restoreViewsMinMaxOptions(); this.option("_rangeMax", this._convertToDate(max)); this._updateViewsOption("max", this._getMaxDate()) } _restoreViewsMinMaxOptions() { this._resetActiveState(); this.option({ _rangeMin: null, _rangeMax: null }); this._updateViewsOption("min", this._getM