UNPKG

devextreme

Version:

HTML5 JavaScript Component Suite for Responsive Web Development

1,249 lines (1,021 loc) • 41.3 kB
"use strict"; var $ = require("../../core/renderer"), Guid = require("../../core/guid"), registerComponent = require("../../core/component_registrator"), noop = require("../../core/utils/common").noop, typeUtils = require("../../core/utils/type"), extend = require("../../core/utils/extend").extend, Button = require("../button"), Editor = require("../editor/editor"), Swipeable = require("../../events/gesture/swipeable"), Navigator = require("./ui.calendar.navigator"), Views = require("./ui.calendar.views"), translator = require("../../animation/translator"), browser = require("../../core/utils/browser"), dateUtils = require("../../core/utils/date"), dateSerialization = require("../../core/utils/date_serialization"), devices = require("../../core/devices"), config = require("../../core/config"), fx = require("../../animation/fx"), windowUtils = require("../../core/utils/window"), messageLocalization = require("../../localization/message"), FunctionTemplate = require("../widget/function_template"); var CALENDAR_CLASS = "dx-calendar", CALENDAR_BODY_CLASS = "dx-calendar-body", CALENDAR_CELL_CLASS = "dx-calendar-cell", CALENDAR_FOOTER_CLASS = "dx-calendar-footer", CALENDAR_TODAY_BUTTON_CLASS = "dx-calendar-today-button", CALENDAR_HAS_FOOTER_CLASS = "dx-calendar-with-footer", CALENDAR_VIEWS_WRAPPER_CLASS = "dx-calendar-views-wrapper", CALENDAR_VIEW_CLASS = "dx-calendar-view", FOCUSED_STATE_CLASS = "dx-state-focused", ANIMATION_DURATION_SHOW_VIEW = 250, POP_ANIMATION_FROM = 0.6, POP_ANIMATION_TO = 1, CALENDAR_INPUT_STANDARD_PATTERN = "yyyy-MM-dd", CALENDAR_DATE_VALUE_KEY = "dxDateValueKey", LEVEL_COMPARE_MAP = { "month": 3, "year": 2, "decade": 1, "century": 0 }; var Calendar = Editor.inherit({ _activeStateUnit: "." + CALENDAR_CELL_CLASS, _getDefaultOptions: function _getDefaultOptions() { return extend(this.callBase(), { /** * @name dxCalendarOptions.hoverStateEnabled * @publicName hoverStateEnabled * @type boolean * @default true * @inheritdoc */ hoverStateEnabled: true, /** * @name dxCalendarOptions.activeStateEnabled * @publicName activeStateEnabled * @type boolean * @default true * @inheritdoc */ activeStateEnabled: true, /** * @name dxCalendarOptions.currentDate * @publicName currentDate * @type Date * @hidden * @default new Date() */ currentDate: new Date(), /** * @name dxCalendarOptions.value * @publicName value * @type Date|number|string * @default null */ value: null, /** * @name dxCalendarOptions.dateSerializationFormat * @publicName dateSerializationFormat * @type string * @default undefined */ dateSerializationFormat: undefined, /** * @name dxCalendarOptions.min * @publicName min * @type Date|number|string * @default new Date(1000, 0) */ min: new Date(1000, 0), /** * @name dxCalendarOptions.max * @publicName max * @type Date|number|string * @default new Date(3000, 0) */ max: new Date(3000, 0), /** * @name dxCalendarOptions.firstDayOfWeek * @publicName firstDayOfWeek * @type Enums.FirstDayOfWeek * @default undefined */ firstDayOfWeek: undefined, /** * @name dxCalendarOptions.zoomLevel * @publicName zoomLevel * @type Enums.CalendarZoomLevel * @default 'month' */ zoomLevel: "month", /** * @name dxCalendarOptions.maxZoomLevel * @publicName maxZoomLevel * @type Enums.CalendarZoomLevel * @default 'month' */ maxZoomLevel: "month", /** * @name dxCalendarOptions.minZoomLevel * @publicName minZoomLevel * @type Enums.CalendarZoomLevel * @default 'century' */ minZoomLevel: "century", /** * @name dxCalendarOptions.showTodayButton * @publicName showTodayButton * @type boolean * @default false */ showTodayButton: false, /** * @name dxCalendarOptions.cellTemplate * @publicName cellTemplate * @type template|function * @default "cell" * @type_function_param1 itemData:object * @type_function_param1_field1 date:Date * @type_function_param1_field2 view:string * @type_function_param1_field3 text:string * @type_function_param2 itemIndex:number * @type_function_param3 itemElement:dxElement * @type_function_return string|Node|jQuery */ cellTemplate: "cell", /** * @name dxCalendarOptions.disabledDates * @publicName disabledDates * @type Array<Date>|function(data) * @default null * @type_function_param1 data:object * @type_function_param1_field1 component:object * @type_function_param1_field2 date:Date * @type_function_param1_field3 view:string * @type_function_return boolean */ disabledDates: null, onCellClick: null, onContouredChanged: null, hasFocus: function hasFocus(element) { return element.hasClass(FOCUSED_STATE_CLASS); } /** * @name dxCalendarOptions.name * @publicName name * @type string * @hidden false * @inheritdoc */ /** * @name dxCalendarOptions.onContentReady * @publicName onContentReady * @hidden true * @action */ /** * @name dxCalendarCellTemplate * @publicName dxCalendarCellTemplate * @type object */ /** * @name dxCalendarCellTemplate.text * @publicName text * @type String */ /** * @name dxCalendarCellTemplate.date * @publicName date * @type Date */ /** * @name dxCalendarCellTemplate.view * @publicName view * @type String * @acceptValues 'month'|'year'|'decade'|'century' */ }); }, _defaultOptionsRules: function _defaultOptionsRules() { return this.callBase().concat([{ device: function device() { return devices.real().deviceType === "desktop" && !devices.isSimulator(); }, options: { /** * @name dxCalendarOptions.focusStateEnabled * @publicName focusStateEnabled * @type boolean * @default true @for desktop * @inheritdoc */ focusStateEnabled: true } }]); }, _supportedKeys: function _supportedKeys() { return extend(this.callBase(), { rightArrow: function rightArrow(e) { e.preventDefault(); if (e.ctrlKey) { this._waitRenderView(1); } else { this._moveCurrentDate(1 * this._getRtlCorrection()); } }, leftArrow: function leftArrow(e) { e.preventDefault(); if (e.ctrlKey) { this._waitRenderView(-1); } else { this._moveCurrentDate(-1 * this._getRtlCorrection()); } }, upArrow: function upArrow(e) { e.preventDefault(); if (e.ctrlKey) { this._navigateUp(); } else { if (fx.isAnimating(this._view.$element())) { return; } this._moveCurrentDate(-1 * this._view.option("colCount")); } }, downArrow: function downArrow(e) { e.preventDefault(); if (e.ctrlKey) { this._navigateDown(); } else { if (fx.isAnimating(this._view.$element())) { return; } this._moveCurrentDate(1 * this._view.option("colCount")); } }, home: function home(e) { e.preventDefault(); var zoomLevel = this.option("zoomLevel"); var currentDate = this.option("currentDate"); var min = this._dateOption("min"); var date = dateUtils.sameView(zoomLevel, currentDate, min) ? min : dateUtils.getViewFirstCellDate(zoomLevel, currentDate); this._moveToClosestAvailableDate(date, 1); }, end: function end(e) { e.preventDefault(); var zoomLevel = this.option("zoomLevel"); var currentDate = this.option("currentDate"); var max = this._dateOption("max"); var date = dateUtils.sameView(zoomLevel, currentDate, max) ? max : dateUtils.getViewLastCellDate(zoomLevel, currentDate); this._moveToClosestAvailableDate(date, -1); }, pageUp: function pageUp(e) { e.preventDefault(); this._waitRenderView(-1); }, pageDown: function pageDown(e) { e.preventDefault(); this._waitRenderView(1); }, tab: noop, enter: function enter(e) { if (!this._isMaxZoomLevel()) { this._navigateDown(); } else { var value = this._updateTimeComponent(this.option("currentDate")); this._dateValue(value, e); } } }); }, _getSerializationFormat: function _getSerializationFormat(optionName) { var value = this.option(optionName || "value"); if (this.option("dateSerializationFormat")) { return this.option("dateSerializationFormat"); } if (typeUtils.isNumeric(value)) { return "number"; } if (!typeUtils.isString(value)) { return; } return dateSerialization.getDateSerializationFormat(value); }, _convertToDate: function _convertToDate(value, optionName) { return dateSerialization.deserializeDate(value); }, _dateValue: function _dateValue(value, dxEvent) { if (dxEvent) this._saveValueChangeEvent(dxEvent); this._dateOption("value", value); }, _dateOption: function _dateOption(optionName, optionValue) { if (arguments.length === 1) { return this._convertToDate(this.option(optionName), optionName); } var serializationFormat = this._getSerializationFormat(optionName); this.option(optionName, dateSerialization.serializeDate(optionValue, serializationFormat)); }, _moveCurrentDate: function _moveCurrentDate(offset, baseDate) { var currentDate = baseDate || new Date(this.option("currentDate")), newDate = new Date(currentDate), maxDate = this.option("max"), zoomLevel = this.option("zoomLevel"); switch (zoomLevel) { case "month": newDate.setDate(currentDate.getDate() + offset); break; case "year": newDate.setMonth(currentDate.getMonth() + offset); break; case "decade": newDate.setFullYear(currentDate.getFullYear() + offset); break; case "century": newDate.setFullYear(currentDate.getFullYear() + 10 * offset); break; } var offsetCorrection = 2 * offset / Math.abs(offset); if (Math.abs(offset) > 1 && !dateUtils.sameView(zoomLevel, currentDate, newDate)) { if (zoomLevel === "decade") { newDate.setFullYear(currentDate.getFullYear() + offset - offsetCorrection); } if (zoomLevel === "century") { newDate.setFullYear(currentDate.getFullYear() + 10 * (offset - offsetCorrection)); } } if (this._view.isDateDisabled(newDate) && newDate <= new Date(maxDate)) { this._moveCurrentDate(offset, newDate); return; } this.option("currentDate", newDate); }, _moveToClosestAvailableDate: function _moveToClosestAvailableDate(baseDate, offset) { if (this._view.isDateDisabled(baseDate)) { this._moveCurrentDate(offset, baseDate); } else { this.option("currentDate", baseDate); } }, _init: function _init() { this.callBase(); this._correctZoomLevel(); this._initCurrentDate(); this._initActions(); }, _correctZoomLevel: function _correctZoomLevel() { var minZoomLevel = this.option("minZoomLevel"), maxZoomLevel = this.option("maxZoomLevel"), zoomLevel = this.option("zoomLevel"); 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: function _initCurrentDate() { var currentDate = this._getNormalizedDate(this._dateOption("value")) || this._getNormalizedDate(this.option("currentDate")); this.option("currentDate", currentDate); }, _getNormalizedDate: function _getNormalizedDate(date) { date = dateUtils.normalizeDate(date, this._getMinDate(), this._getMaxDate()); return typeUtils.isDefined(date) ? new Date(date) : date; }, _initActions: function _initActions() { this._cellClickAction = this._createActionByOption("onCellClick"); this._onContouredChanged = this._createActionByOption("onContouredChanged"); }, _initTemplates: function _initTemplates() { this.callBase(); this._defaultTemplates["cell"] = new FunctionTemplate(function (options) { var data = options.model; $(options.container).append($("<span>").text(data && data.text || String(data))); }, this); }, _updateCurrentDate: function _updateCurrentDate(date) { if (fx.isAnimating(this._$viewsWrapper)) { fx.stop(this._$viewsWrapper, true); } var min = this._getMinDate(), max = this._getMaxDate(); if (min > max) { this.option("currentDate", new Date()); return; } var normalizedDate = this._getNormalizedDate(date); if (date.getTime() !== normalizedDate.getTime()) { this.option("currentDate", new Date(normalizedDate)); return; } var offset = this._getViewsOffset(this._view.option("date"), normalizedDate); if (offset !== 0 && !this._isMaxZoomLevel() && this._isOtherViewCellClicked) { offset = 0; } if (this._view && offset !== 0 && !this._suppressNavigation) { this._navigate(offset, normalizedDate); } else { this._renderNavigator(); this._setViewContoured(normalizedDate); this._updateAriaId(normalizedDate); } }, _setViewContoured: function _setViewContoured(date) { if (this.option("hasFocus")(this._focusTarget())) { this._view.option("contouredDate", date); } }, _getMinDate: function _getMinDate() { if (this.min) { return this.min; } this.min = this._dateOption("min") || new Date(1000, 0); return this.min; }, _getMaxDate: function _getMaxDate() { if (this.max) { return this.max; } this.max = this._dateOption("max") || new Date(3000, 0); return this.max; }, _getViewsOffset: function _getViewsOffset(startDate, endDate) { var zoomLevel = this.option("zoomLevel"); if (zoomLevel === "month") { return this._getMonthsOffset(startDate, endDate); } var zoomCorrection; switch (zoomLevel) { case "century": zoomCorrection = 100; break; case "decade": zoomCorrection = 10; break; default: zoomCorrection = 1; break; } return parseInt(endDate.getFullYear() / zoomCorrection) - parseInt(startDate.getFullYear() / zoomCorrection); }, _getMonthsOffset: function _getMonthsOffset(startDate, endDate) { var yearOffset = endDate.getFullYear() - startDate.getFullYear(), monthOffset = endDate.getMonth() - startDate.getMonth(); return yearOffset * 12 + monthOffset; }, _waitRenderView: function _waitRenderView(offset) { if (this._alreadyViewRender) { return; } this._alreadyViewRender = true; var date = this._getDateByOffset(offset * this._getRtlCorrection()); this._moveToClosestAvailableDate(date, offset); setTimeout(function () { this._alreadyViewRender = false; }.bind(this)); }, _getRtlCorrection: function _getRtlCorrection() { return this.option("rtlEnabled") ? -1 : 1; }, _getDateByOffset: function _getDateByOffset(offset, date) { date = new Date(date || this.option("currentDate")); var currentDay = date.getDate(); var difference = dateUtils.getDifferenceInMonth(this.option("zoomLevel")) * offset; date.setDate(1); date.setMonth(date.getMonth() + difference); var lastDay = dateUtils.getLastMonthDate(date).getDate(); date.setDate(currentDay > lastDay ? lastDay : currentDay); return date; }, _focusTarget: function _focusTarget() { return this.$element(); }, _initMarkup: function _initMarkup() { this._renderSubmitElement(); this.callBase(); var $element = this.$element(); $element.addClass(CALENDAR_CLASS); this._renderBody(); $element.append(this.$body); this._renderViews(); this._renderNavigator(); $element.append(this._navigator.$element()); this._renderSwipeable(); this._renderFooter(); this.setAria({ "role": "listbox", "label": messageLocalization.format("dxCalendar-ariaWidgetName") }); this._updateAriaSelected(); this._updateAriaId(); if (this._view.isDateDisabled(this.option("currentDate"))) { this._moveCurrentDate(1); } }, _render: function _render() { this.callBase(); this._setViewContoured(this.option("currentDate")); }, _renderBody: function _renderBody() { if (!this._$viewsWrapper) { this.$body = $("<div>").addClass(CALENDAR_BODY_CLASS); this._$viewsWrapper = $("<div>").addClass(CALENDAR_VIEWS_WRAPPER_CLASS); this.$body.append(this._$viewsWrapper); } }, _renderViews: function _renderViews() { this.$element().addClass(CALENDAR_VIEW_CLASS + "-" + this.option("zoomLevel")); var currentDate = this.option("currentDate"); this._view = this._renderSpecificView(currentDate); this._view.option("_keyboardProcessor", this._viewKeyboardProcessor); if (windowUtils.hasWindow()) { var beforeDate = this._getDateByOffset(-1, currentDate); this._beforeView = this._isViewAvailable(beforeDate) ? this._renderSpecificView(beforeDate) : null; var afterDate = this._getDateByOffset(1, currentDate); afterDate.setDate(1); this._afterView = this._isViewAvailable(afterDate) ? this._renderSpecificView(afterDate) : null; } this._translateViews(); }, _renderSpecificView: function _renderSpecificView(date) { var specificView = Views[this.option("zoomLevel")], $view = $("<div>").appendTo(this._$viewsWrapper), config = this._viewConfig(date); return new specificView($view, config); }, _viewConfig: function _viewConfig(date) { var disabledDates = this.option("disabledDates"); disabledDates = typeUtils.isFunction(disabledDates) ? this._injectComponent(disabledDates.bind(this)) : disabledDates; return { date: date, min: this._getMinDate(), max: this._getMaxDate(), firstDayOfWeek: this.option("firstDayOfWeek"), value: this._dateOption("value"), rtl: this.option("rtlEnabled"), disabled: this.option("disabled") || config().designMode, tabIndex: undefined, focusStateEnabled: this.option("focusStateEnabled"), hoverStateEnabled: this.option("hoverStateEnabled"), disabledDates: disabledDates, onCellClick: this._cellClickHandler.bind(this), cellTemplate: this._getTemplateByOption("cellTemplate"), allowValueSelection: this._isMaxZoomLevel() }; }, _injectComponent: function _injectComponent(func) { var that = this; return function (params) { extend(params, { component: that }); return func(params); }; }, _isViewAvailable: function _isViewAvailable(date) { var zoomLevel = this.option("zoomLevel"); var min = dateUtils.getViewMinBoundaryDate(zoomLevel, this._getMinDate()); var max = dateUtils.getViewMaxBoundaryDate(zoomLevel, this._getMaxDate()); return dateUtils.dateInRange(date, min, max); }, _translateViews: function _translateViews() { translator.move(this._view.$element(), { left: 0, top: 0 }); this._beforeView && translator.move(this._beforeView.$element(), { left: this._getViewPosition(-1), top: 0 }); this._afterView && translator.move(this._afterView.$element(), { left: this._getViewPosition(1), top: 0 }); }, _getViewPosition: function _getViewPosition(coefficient) { var rtlCorrection = this.option("rtlEnabled") && !browser.msie ? -1 : 1; return coefficient * 100 * rtlCorrection + "%"; }, _cellClickHandler: function _cellClickHandler(e) { var zoomLevel = this.option("zoomLevel"), nextView = dateUtils.getViewDown(zoomLevel); var isMaxZoomLevel = this._isMaxZoomLevel(); if (nextView && !isMaxZoomLevel) { this._navigateDown(e.event.currentTarget); } else { var newValue = this._updateTimeComponent(e.value); this._dateValue(newValue, e.event); this._cellClickAction(e); } }, _updateTimeComponent: function _updateTimeComponent(date) { var result = new Date(date); var currentValue = this._dateOption("value"); if (currentValue) { result.setHours(currentValue.getHours()); result.setMinutes(currentValue.getMinutes()); result.setSeconds(currentValue.getSeconds()); result.setMilliseconds(currentValue.getMilliseconds()); } return result; }, _isMaxZoomLevel: function _isMaxZoomLevel() { return this.option("zoomLevel") === this.option("maxZoomLevel"); }, _navigateDown: function _navigateDown(cell) { var zoomLevel = this.option("zoomLevel"); if (this._isMaxZoomLevel()) { return; } var nextView = dateUtils.getViewDown(zoomLevel); if (!nextView) { return; } var newCurrentDate = this._view.option("contouredDate") || this._view.option("date"); if (cell) { newCurrentDate = $(cell).data(CALENDAR_DATE_VALUE_KEY); } this._isOtherViewCellClicked = true; this.option("currentDate", newCurrentDate); this.option("zoomLevel", nextView); this._isOtherViewCellClicked = false; this._renderNavigator(); this._animateShowView(); this._setViewContoured(this._getNormalizedDate(newCurrentDate)); }, _renderNavigator: function _renderNavigator() { if (!this._navigator) { this._navigator = new Navigator($("<div>"), this._navigatorConfig()); } this._navigator.option("text", this._view.getNavigatorCaption()); this._updateButtonsVisibility(); }, _navigatorConfig: function _navigatorConfig() { return { text: this._view.getNavigatorCaption(), onClick: this._navigatorClickHandler.bind(this), onCaptionClick: this._navigateUp.bind(this), rtlEnabled: this.option("rtlEnabled") }; }, _navigatorClickHandler: function _navigatorClickHandler(e) { var currentDate = this._getDateByOffset(e.direction, this.option("currentDate")); this._moveToClosestAvailableDate(currentDate, 1 * e.direction); this._updateNavigatorCaption(-e.direction * this._getRtlCorrection()); }, _navigateUp: function _navigateUp() { var zoomLevel = this.option("zoomLevel"), nextView = dateUtils.getViewUp(zoomLevel); if (!nextView || this._isMinZoomLevel(zoomLevel)) { return; } var contouredDate = this._view.option("contouredDate"); this.option("zoomLevel", nextView); this.option("currentDate", contouredDate || this._view.option("date")); this._renderNavigator(); this._animateShowView().done(function () { this._setViewContoured(contouredDate); }.bind(this)); }, _isMinZoomLevel: function _isMinZoomLevel(zoomLevel) { var min = this._getMinDate(), max = this._getMaxDate(); return dateUtils.sameView(zoomLevel, min, max) || this.option("minZoomLevel") === zoomLevel; }, _updateButtonsVisibility: function _updateButtonsVisibility() { this._navigator.toggleButton("next", !typeUtils.isDefined(this._getRequiredView("next"))); this._navigator.toggleButton("prev", !typeUtils.isDefined(this._getRequiredView("prev"))); }, _renderSwipeable: function _renderSwipeable() { if (!this._swipeable) { this._swipeable = this._createComponent(this.$element(), Swipeable, { onStart: this._swipeStartHandler.bind(this), onUpdated: this._swipeUpdateHandler.bind(this), onEnd: this._swipeEndHandler.bind(this), itemSizeFunc: this._viewWidth.bind(this) }); } }, _swipeStartHandler: function _swipeStartHandler(e) { fx.stop(this._$viewsWrapper, true); e.event.maxLeftOffset = this._getRequiredView("next") ? 1 : 0; e.event.maxRightOffset = this._getRequiredView("prev") ? 1 : 0; }, _getRequiredView: function _getRequiredView(name) { var view; var isRtl = this.option("rtlEnabled"); if (name === "next") { view = isRtl ? this._beforeView : this._afterView; } else if (name === "prev") { view = isRtl ? this._afterView : this._beforeView; } return view; }, _swipeUpdateHandler: function _swipeUpdateHandler(e) { var offset = e.event.offset; translator.move(this._$viewsWrapper, { left: offset * this._viewWidth(), top: 0 }); this._updateNavigatorCaption(offset); }, _swipeEndHandler: function _swipeEndHandler(e) { var targetOffset = e.event.targetOffset, moveOffset = !targetOffset ? 0 : targetOffset / Math.abs(targetOffset); if (moveOffset === 0) { this._animateWrapper(0, ANIMATION_DURATION_SHOW_VIEW); return; } var date = this._getDateByOffset(-moveOffset * this._getRtlCorrection()); if (this._isDateInInvalidRange(date)) { if (moveOffset >= 0) { date = new Date(this._getMinDate()); } else { date = new Date(this._getMaxDate()); } } this.option("currentDate", date); }, _viewWidth: function _viewWidth() { if (!this._viewWidthValue) { this._viewWidthValue = this.$element().width(); } return this._viewWidthValue; }, _updateNavigatorCaption: function _updateNavigatorCaption(offset) { offset *= this._getRtlCorrection(); var view = this._view; if (offset > 0.5 && this._beforeView) { view = this._beforeView; } else if (offset < -0.5 && this._afterView) { view = this._afterView; } this._navigator.option("text", view.getNavigatorCaption()); }, _isDateInInvalidRange: function _isDateInInvalidRange(date) { if (this._view.isBoundary(date)) { return; } var min = this._getMinDate(), max = this._getMaxDate(), normalizedDate = dateUtils.normalizeDate(date, min, max); return normalizedDate === min || normalizedDate === max; }, _renderFooter: function _renderFooter() { var showTodayButton = this.option("showTodayButton"); if (showTodayButton) { var $todayButton = this._createComponent($("<a>"), Button, { focusStateEnabled: false, text: messageLocalization.format("dxCalendar-todayButtonText"), onClick: function () { this._toTodayView(); }.bind(this), integrationOptions: {} }).$element().addClass(CALENDAR_TODAY_BUTTON_CLASS); this._$footer = $("<div>").addClass(CALENDAR_FOOTER_CLASS).append($todayButton); this.$element().append(this._$footer); } this.$element().toggleClass(CALENDAR_HAS_FOOTER_CLASS, showTodayButton); }, _renderSubmitElement: function _renderSubmitElement() { this._$submitElement = $("<input>").attr("type", "hidden").appendTo(this.$element()); this._setSubmitValue(this.option("value")); }, _setSubmitValue: function _setSubmitValue(value) { var dateValue = this._convertToDate(value); this._$submitElement.val(dateSerialization.serializeDate(dateValue, CALENDAR_INPUT_STANDARD_PATTERN)); }, _getSubmitElement: function _getSubmitElement() { return this._$submitElement; }, _animateShowView: function _animateShowView() { fx.stop(this._view.$element(), true); return this._popAnimationView(this._view, POP_ANIMATION_FROM, POP_ANIMATION_TO, ANIMATION_DURATION_SHOW_VIEW).promise(); }, _popAnimationView: function _popAnimationView(view, from, to, duration) { return fx.animate(view.$element(), { type: "pop", from: { scale: from, opacity: from }, to: { scale: to, opacity: to }, duration: duration }); }, _navigate: function _navigate(offset, value) { if (offset !== 0 && Math.abs(offset) !== 1 && this._isViewAvailable(value)) { var 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(); } var rtlCorrection = this._getRtlCorrection(), offsetSign = offset > 0 ? 1 : offset < 0 ? -1 : 0, endPosition = -rtlCorrection * offsetSign * this._viewWidth(); var viewsWrapperPosition = this._$viewsWrapper.position().left; if (viewsWrapperPosition !== endPosition) { if (this._preventViewChangeAnimation) { this._wrapperAnimationEndHandler(offset, value); } else { this._animateWrapper(endPosition, ANIMATION_DURATION_SHOW_VIEW).done(this._wrapperAnimationEndHandler.bind(this, offset, value)); } } }, _animateWrapper: function _animateWrapper(to, duration) { return fx.animate(this._$viewsWrapper, { type: "slide", from: { left: this._$viewsWrapper.position().left }, to: { left: to }, duration: duration }); }, _toTodayView: function _toTodayView() { var today = new Date(); if (this._isMaxZoomLevel()) { this._dateOption("value", today); return; } this._preventViewChangeAnimation = true; this.option("zoomLevel", this.option("maxZoomLevel")); this._dateOption("value", today); this._animateShowView(); this._preventViewChangeAnimation = false; }, _wrapperAnimationEndHandler: function _wrapperAnimationEndHandler(offset, newDate) { this._rearrangeViews(offset); this._translateViews(); this._resetLocation(); this._renderNavigator(); this._setViewContoured(newDate); this._updateAriaId(newDate); }, _rearrangeViews: function _rearrangeViews(offset) { if (offset === 0) { return; } var viewOffset, viewToCreateKey, viewToRemoveKey; if (offset < 0) { viewOffset = 1; viewToCreateKey = "_beforeView"; viewToRemoveKey = "_afterView"; } else { viewOffset = -1; viewToCreateKey = "_afterView"; viewToRemoveKey = "_beforeView"; } if (!this[viewToCreateKey]) { return; } var destinationDate = this[viewToCreateKey].option("date"); if (this[viewToRemoveKey]) { this[viewToRemoveKey].$element().remove(); } if (offset === viewOffset) { this[viewToRemoveKey] = this._view; } else { this[viewToRemoveKey] = this._renderSpecificView(this._getDateByOffset(viewOffset, destinationDate)); this._view.$element().remove(); } this._view = this[viewToCreateKey]; var dateByOffset = this._getDateByOffset(-viewOffset, destinationDate); this[viewToCreateKey] = this._isViewAvailable(dateByOffset) ? this._renderSpecificView(dateByOffset) : null; }, _resetLocation: function _resetLocation() { translator.move(this._$viewsWrapper, { left: 0, top: 0 }); }, _clean: function _clean() { this.callBase(); this._clearViewWidthCache(); delete this._$viewsWrapper; delete this._navigator; delete this._$footer; }, _clearViewWidthCache: function _clearViewWidthCache() { delete this._viewWidthValue; }, _disposeViews: function _disposeViews() { this._view.$element().remove(); this._beforeView && this._beforeView.$element().remove(); this._afterView && this._afterView.$element().remove(); delete this._view; delete this._beforeView; delete this._afterView; }, _refreshViews: function _refreshViews() { this._disposeViews(); this._renderViews(); }, _visibilityChanged: function _visibilityChanged() { this._translateViews(); }, _focusInHandler: function _focusInHandler() { this.callBase.apply(this, arguments); this._view.option("contouredDate", this.option("currentDate")); }, _focusOutHandler: function _focusOutHandler() { this.callBase.apply(this, arguments); this._view.option("contouredDate", null); }, _updateViewsValue: function _updateViewsValue(value) { var newValue = value ? new Date(value) : null; this._view.option("value", newValue); this._beforeView && this._beforeView.option("value", newValue); this._afterView && this._afterView.option("value", newValue); }, _updateAriaSelected: function _updateAriaSelected(value, previousValue) { value = value || this._dateOption("value"); var $prevSelectedCell = this._view._getCellByDate(previousValue); var $selectedCell = this._view._getCellByDate(value); this.setAria("selected", undefined, $prevSelectedCell); this.setAria("selected", true, $selectedCell); if (value && this.option("currentDate").getTime() === value.getTime()) { this._updateAriaId(value); } }, _updateAriaId: function _updateAriaId(value) { value = value || this.option("currentDate"); var ariaId = "dx-" + new Guid(); var $newCell = this._view._getCellByDate(value); this.setAria("id", ariaId, $newCell); this.setAria("activedescendant", ariaId); this._onContouredChanged(ariaId); }, _suppressingNavigation: function _suppressingNavigation(callback, args) { this._suppressNavigation = true; callback.apply(this, args); delete this._suppressNavigation; }, _optionChanged: function _optionChanged(args) { var value = args.value; var previousValue = args.previousValue; switch (args.name) { case "width": this.callBase(args); this._clearViewWidthCache(); break; case "min": case "max": this.min = undefined; this.max = undefined; this._suppressingNavigation(this._updateCurrentDate, [this.option("currentDate")]); this._refreshViews(); this._renderNavigator(); break; case "firstDayOfWeek": this._refreshViews(); this._updateButtonsVisibility(); break; case "currentDate": this.setAria("id", undefined, this._view._getCellByDate(previousValue)); this._updateCurrentDate(value); break; case "zoomLevel": this.$element().removeClass(CALENDAR_VIEW_CLASS + "-" + previousValue); this._correctZoomLevel(); this._refreshViews(); this._renderNavigator(); this._updateAriaId(); break; case "minZoomLevel": case "maxZoomLevel": this._correctZoomLevel(); this._updateButtonsVisibility(); break; case "value": value = this._convertToDate(value); previousValue = this._convertToDate(previousValue); this._updateAriaSelected(value, previousValue); this.option("currentDate", typeUtils.isDefined(value) ? new Date(value) : new Date()); this._updateViewsValue(value); this._setSubmitValue(value); this.callBase(args); break; case "disabled": this._view.option("disabled", value); this.callBase(args); break; case "onCellClick": this._view.option("onCellClick", value); break; case "onContouredChanged": this._onContouredChanged = this._createActionByOption("onContouredChanged"); break; case "disabledDates": case "dateSerializationFormat": case "cellTemplate": case "showTodayButton": this._invalidate(); break; case "hasFocus": break; default: this.callBase(args); } } }); registerComponent("dxCalendar", Calendar); module.exports = Calendar;