UNPKG

devextreme

Version:

HTML5 JavaScript Component Suite for Responsive Web Development

709 lines (706 loc) • 27.4 kB
/** * DevExtreme (cjs/__internal/ui/date_box/m_date_box.base.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 _date = _interopRequireDefault(require("../../../common/core/localization/date")); var _message = _interopRequireDefault(require("../../../common/core/localization/message")); var _config = _interopRequireDefault(require("../../../core/config")); var _devices = _interopRequireDefault(require("../../../core/devices")); var _browser = _interopRequireDefault(require("../../../core/utils/browser")); var _date2 = _interopRequireDefault(require("../../../core/utils/date")); var _date_serialization = _interopRequireDefault(require("../../../core/utils/date_serialization")); var _dom = require("../../../core/utils/dom"); var _extend = require("../../../core/utils/extend"); var _iterator = require("../../../core/utils/iterator"); var _support = require("../../../core/utils/support"); var _type = require("../../../core/utils/type"); var _window = require("../../../core/utils/window"); var _m_drop_down_editor = _interopRequireDefault(require("../../ui/drop_down_editor/m_drop_down_editor")); var _m_date_boxStrategy = _interopRequireDefault(require("./m_date_box.strategy.calendar")); var _m_date_boxStrategy2 = _interopRequireDefault(require("./m_date_box.strategy.calendar_with_time")); var _m_date_boxStrategy3 = _interopRequireDefault(require("./m_date_box.strategy.date_view")); var _m_date_boxStrategy4 = _interopRequireDefault(require("./m_date_box.strategy.list")); var _m_date_boxStrategy5 = _interopRequireDefault(require("./m_date_box.strategy.native")); var _m_date_utils = _interopRequireDefault(require("./m_date_utils")); 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 window = (0, _window.getWindow)(); const DATEBOX_CLASS = "dx-datebox"; const DX_AUTO_WIDTH_CLASS = "dx-auto-width"; const DX_INVALID_BADGE_CLASS = "dx-show-invalid-badge"; const DX_CLEAR_BUTTON_CLASS = "dx-clear-button-area"; const DATEBOX_WRAPPER_CLASS = "dx-datebox-wrapper"; const DROPDOWNEDITOR_OVERLAY_CLASS = "dx-dropdowneditor-overlay"; const PICKER_TYPE = { calendar: "calendar", rollers: "rollers", list: "list", native: "native" }; const TYPE = { date: "date", datetime: "datetime", time: "time" }; const STRATEGY_NAME = { calendar: "Calendar", dateView: "DateView", native: "Native", calendarWithTime: "CalendarWithTime", list: "List" }; const STRATEGY_CLASSES = { Calendar: _m_date_boxStrategy.default, DateView: _m_date_boxStrategy3.default, Native: _m_date_boxStrategy5.default, CalendarWithTime: _m_date_boxStrategy2.default, List: _m_date_boxStrategy4.default }; class DateBox extends _m_drop_down_editor.default { _supportedKeys() { return _extends({}, super._supportedKeys(), this._strategy.supportedKeys()) } _renderButtonContainers() { super._renderButtonContainers.apply(this, arguments); this._strategy.customizeButtons() } _getDefaultOptions() { return _extends({}, super._getDefaultOptions(), { type: "date", showAnalogClock: true, value: null, displayFormat: null, interval: 30, disabledDates: null, pickerType: PICKER_TYPE.calendar, invalidDateMessage: _message.default.format("dxDateBox-validation-datetime"), dateOutOfRangeMessage: _message.default.format("validation-range"), applyButtonText: _message.default.format("OK"), adaptivityEnabled: false, calendarOptions: {}, useHiddenSubmitElement: true, _showValidationIcon: true }) } _defaultOptionsRules() { return super._defaultOptionsRules().concat([{ device: { platform: "ios" }, options: { "dropDownOptions.showTitle": true } }, { device: { platform: "android" }, options: { buttonsLocation: "bottom after" } }, { device() { const realDevice = _devices.default.real(); const { platform: platform } = realDevice; return "ios" === platform || "android" === platform }, options: { pickerType: PICKER_TYPE.native } }, { device: { platform: "generic", deviceType: "desktop" }, options: { buttonsLocation: "bottom after" } }]) } _initOptions(options) { this._userOptions = (0, _extend.extend)({}, options); super._initOptions(options); this._updatePickerOptions() } _updatePickerOptions() { let { pickerType: pickerType } = this.option(); const { type: type } = this.option(); if (pickerType === PICKER_TYPE.list && (type === TYPE.datetime || type === TYPE.date)) { pickerType = PICKER_TYPE.calendar } if (type === TYPE.time && pickerType === PICKER_TYPE.calendar) { pickerType = PICKER_TYPE.list } this._pickerType = pickerType; this._setShowDropDownButtonOption() } _setShowDropDownButtonOption() { const { platform: platform } = _devices.default.real(); const isMozillaOnAndroid = "android" === platform && _browser.default.mozilla; const isNativePickerType = this._isNativeType(); let showDropDownButton = "generic" !== platform || !isNativePickerType; if (isNativePickerType && isMozillaOnAndroid) { showDropDownButton = false } this.option({ showDropDownButton: showDropDownButton }) } _init() { this._initStrategy(); this.option((0, _extend.extend)({}, this._strategy.getDefaultOptions(), this._userOptions)); delete this._userOptions; super._init() } _toLowerCaseFirstLetter(string) { return string.charAt(0).toLowerCase() + string.substr(1) } _initStrategy() { const strategyName = this._getStrategyName(this._getFormatType()); const strategy = STRATEGY_CLASSES[strategyName]; if (!(this._strategy && this._strategy.NAME === strategyName)) { this._strategy = new strategy(this) } } _getFormatType() { const currentType = this.option("type"); const isTime = /h|m|s/g.test(currentType); const isDate = /d|M|Y/g.test(currentType); let type = ""; if (isDate) { type += TYPE.date } if (isTime) { type += TYPE.time } return type } _getStrategyName(type) { const pickerType = this._pickerType; if (pickerType === PICKER_TYPE.rollers) { return STRATEGY_NAME.dateView } if (pickerType === PICKER_TYPE.native) { return STRATEGY_NAME.native } if (type === TYPE.date) { return STRATEGY_NAME.calendar } if (type === TYPE.datetime) { return STRATEGY_NAME.calendarWithTime } return STRATEGY_NAME.list } _initMarkup() { this.$element().addClass("dx-datebox"); super._initMarkup(); this._refreshFormatClass(); this._refreshPickerTypeClass(); this._strategy.renderInputMinMax(this._input()) } _render() { super._render(); this._formatValidationIcon() } _renderDimensions() { super._renderDimensions(); this.$element().toggleClass("dx-auto-width", !this.option("width")); this._updatePopupWidth(); this._updatePopupHeight() } _dimensionChanged() { super._dimensionChanged(); this._updatePopupHeight() } _updatePopupHeight() { if (this._popup) { var _this$_strategy$_upda, _this$_strategy; null === (_this$_strategy$_upda = (_this$_strategy = this._strategy)._updatePopupHeight) || void 0 === _this$_strategy$_upda || _this$_strategy$_upda.call(_this$_strategy) } } _refreshFormatClass() { const $element = this.$element(); (0, _iterator.each)(TYPE, ((_, item) => { $element.removeClass(`dx-datebox-${item}`) })); const { type: type } = this.option(); $element.addClass(`dx-datebox-${type}`) } _refreshPickerTypeClass() { const $element = this.$element(); (0, _iterator.each)(PICKER_TYPE, ((_, item) => { $element.removeClass(`dx-datebox-${item}`) })); $element.addClass(`dx-datebox-${this._pickerType}`) } _formatValidationIcon() { if (!(0, _window.hasWindow)()) { return } const inputElement = this._input().get(0); const isRtlEnabled = this.option("rtlEnabled"); const clearButtonWidth = this._getClearButtonWidth(); const longestElementDimensions = this._getLongestElementDimensions(); const curWidth = parseFloat(window.getComputedStyle(inputElement).width) - clearButtonWidth; const shouldHideValidationIcon = longestElementDimensions.width > curWidth; const { style: style } = inputElement; const { _showValidationIcon: showValidationIcon } = this.option(); this.$element().toggleClass(DX_INVALID_BADGE_CLASS, !shouldHideValidationIcon && showValidationIcon); if (shouldHideValidationIcon) { if (void 0 === this._storedPadding) { this._storedPadding = isRtlEnabled ? longestElementDimensions.leftPadding : longestElementDimensions.rightPadding } isRtlEnabled ? style.paddingLeft = 0 : style.paddingRight = 0 } else { isRtlEnabled ? style.paddingLeft = `${this._storedPadding}px` : style.paddingRight = `${this._storedPadding}px` } } _getClearButtonWidth() { let clearButtonWidth = 0; if (this._isClearButtonVisible() && "" === this._input().val()) { const clearButtonElement = this.$element().find(`.${DX_CLEAR_BUTTON_CLASS}`).get(0); clearButtonWidth = parseFloat(window.getComputedStyle(clearButtonElement).width) } return clearButtonWidth } _getLongestElementDimensions() { const format = this._strategy.getDisplayFormat(this.option("displayFormat")); const longestValue = _date.default.format(_m_date_utils.default.getLongestDate(format, _date.default.getMonthNames(), _date.default.getDayNames()), format); const $input = this._input(); const inputElement = $input.get(0); const $longestValueElement = (0, _dom.createTextElementHiddenCopy)($input, longestValue); const isPaddingStored = void 0 !== this._storedPadding; const storedPadding = !isPaddingStored ? 0 : this._storedPadding; $longestValueElement.appendTo(this.$element()); const elementWidth = parseFloat(window.getComputedStyle($longestValueElement.get(0)).width); const rightPadding = parseFloat(window.getComputedStyle(inputElement).paddingRight); const leftPadding = parseFloat(window.getComputedStyle(inputElement).paddingLeft); const necessaryWidth = elementWidth + leftPadding + rightPadding + storedPadding; $longestValueElement.remove(); return { width: necessaryWidth, leftPadding: leftPadding, rightPadding: rightPadding } } _getKeyboardListeners() { var _this$_strategy2; return super._getKeyboardListeners().concat([null === (_this$_strategy2 = this._strategy) || void 0 === _this$_strategy2 ? void 0 : _this$_strategy2.getKeyboardListener()]) } _renderPopup() { var _this$_popup; super._renderPopup(); null === (_this$_popup = this._popup) || void 0 === _this$_popup || _this$_popup.$wrapper().addClass("dx-datebox-wrapper"); this._renderPopupWrapper() } _getPopupToolbarItems() { var _this$_strategy$_getP, _this$_strategy3; const defaultItems = super._getPopupToolbarItems(); return (null === (_this$_strategy$_getP = (_this$_strategy3 = this._strategy)._getPopupToolbarItems) || void 0 === _this$_strategy$_getP ? void 0 : _this$_strategy$_getP.call(_this$_strategy3, defaultItems)) ?? defaultItems } _popupConfig() { const popupConfig = super._popupConfig(); return _extends({}, this._strategy.popupConfig(popupConfig), { title: this._getPopupTitle(), dragEnabled: false }) } _renderPopupWrapper() { if (!this._popup) { return } const $element = this.$element(); const classPostfixes = (0, _extend.extend)({}, TYPE, PICKER_TYPE); (0, _iterator.each)(classPostfixes, ((_, item) => { $element.removeClass(`dx-datebox-wrapper-${item}`) })); const { type: type } = this.option(); this._popup.$wrapper().addClass(`dx-datebox-wrapper-${type}`).addClass(`dx-datebox-wrapper-${this._pickerType}`).addClass("dx-dropdowneditor-overlay") } _renderPopupContent() { super._renderPopupContent(); this._strategy.renderPopupContent() } _popupShowingHandler() { super._popupShowingHandler(); this._strategy.popupShowingHandler() } _popupShownHandler() { super._popupShownHandler(); this._strategy.renderOpenedState() } _popupHiddenHandler() { super._popupHiddenHandler(); this._strategy.renderOpenedState(); this._strategy.popupHiddenHandler() } _visibilityChanged(visible) { if (visible) { this._formatValidationIcon() } } _clearValueHandler(e) { this.option("text", ""); super._clearValueHandler(e) } _readOnlyPropValue() { if (this._pickerType === PICKER_TYPE.rollers) { return true } const { platform: platform } = _devices.default.real(); const isCustomValueDisabled = this._isNativeType() && ("ios" === platform || "android" === platform); if (isCustomValueDisabled) { const { readOnly: readOnly } = this.option(); return readOnly } return super._readOnlyPropValue() } _isClearButtonVisible() { return super._isClearButtonVisible() && !this._isNativeType() } _renderValue() { const value = this.dateOption("value"); this.option("text", this._getDisplayedText(value)); this._strategy.renderValue(); return super._renderValue() } _setSubmitValue() { const value = this.dateOption("value"); const { type: type, dateSerializationFormat: dateSerializationFormat } = this.option(); const submitFormat = _m_date_utils.default.SUBMIT_FORMATS_MAP[type]; const submitValue = dateSerializationFormat ? _date_serialization.default.serializeDate(value, dateSerializationFormat) : _m_date_utils.default.toStandardDateFormat(value, submitFormat); this._getSubmitElement().val(submitValue) } _getDisplayedText(value) { const { mode: mode } = this.option(); let displayedText; if ("text" === mode) { const displayFormat = this._strategy.getDisplayFormat(this.option("displayFormat")); displayedText = _date.default.format(value, displayFormat) } else { const format = this._getFormatByMode(mode); if (format) { displayedText = _date.default.format(value, format) } else { displayedText = _m_date_utils.default.toStandardDateFormat(value, mode) } } return displayedText } _getFormatByMode(mode) { return (0, _support.inputType)(mode) ? null : _m_date_utils.default.FORMATS_MAP[mode] } _valueChangeEventHandler(e) { const { text: text, type: type, validationError: validationError } = this.option(); const currentValue = this.dateOption("value"); if (text === this._getDisplayedText(currentValue)) { this._recallInternalValidation(currentValue, validationError); return } const parsedDate = this._getParsedDate(text); const value = currentValue ?? this._getDateByDefault(); const newValue = _m_date_utils.default.mergeDates(value, parsedDate, type); const date = parsedDate && "time" === type ? newValue : parsedDate; if (this._applyInternalValidation(date).isValid) { const displayedText = this._getDisplayedText(newValue); if (value && newValue && value.getTime() === newValue.getTime() && displayedText !== text) { this._renderValue() } else { this.dateValue(newValue, e) } } } _recallInternalValidation(value, validationError) { if (!validationError || validationError.editorSpecific) { this._applyInternalValidation(value); this._applyCustomValidation(value) } } _getDateByDefault() { return this._strategy.useCurrentDateByDefault() && this._strategy.getDefaultDate() } _getParsedDate(text) { const displayFormat = this._strategy.getDisplayFormat(this.option("displayFormat")); const parsedText = this._strategy.getParsedText(text, displayFormat); return parsedText ?? void 0 } _applyInternalValidation(value) { const text = this.option("text"); const hasText = !!text && null !== value; const isDate = !!value && (0, _type.isDate)(value) && !isNaN(value.getTime()); const isDateInRange = isDate && _date2.default.dateInRange(value, this.dateOption("min"), this.dateOption("max"), this.option("type")); const isValid = !hasText && !value || isDateInRange; let validationMessage = ""; const { invalidDateMessage: invalidDateMessage, dateOutOfRangeMessage: dateOutOfRangeMessage } = this.option(); if (!isDate) { validationMessage = invalidDateMessage } else if (!isDateInRange) { validationMessage = dateOutOfRangeMessage } this._updateInternalValidationState(isValid, validationMessage); return { isValid: isValid, isDate: isDate } } _updateInternalValidationState(isValid, validationMessage) { this.option({ isValid: isValid, validationError: isValid ? null : { editorSpecific: true, message: validationMessage } }) } _applyCustomValidation(value) { this.validationRequest.fire({ editor: this, value: this._serializeDate(value) }) } _isValueChanged(newValue) { const oldValue = this.dateOption("value"); const oldTime = oldValue && oldValue.getTime(); const newTime = newValue && newValue.getTime(); return oldTime !== newTime } _isTextChanged(newValue) { const oldText = this.option("text"); const newText = newValue && this._getDisplayedText(newValue) || ""; return oldText !== newText } _renderProps() { super._renderProps(); this._input().attr("autocomplete", "off") } _renderOpenedState() { if (!this._isNativeType()) { super._renderOpenedState() } if (this._strategy.isAdaptivityChanged()) { this._refreshStrategy() } } _getPopupTitle() { const { placeholder: placeholder } = this.option(); if (placeholder) { return placeholder } const { type: type } = this.option(); if (type === TYPE.time) { return _message.default.format("dxDateBox-simulatedDataPickerTitleTime") } if (type === TYPE.date || type === TYPE.datetime) { return _message.default.format("dxDateBox-simulatedDataPickerTitleDate") } return "" } _refreshStrategy() { this._strategy.dispose(); this._initStrategy(); this.option(this._strategy.getDefaultOptions()); this._refresh() } _applyButtonHandler(e) { const value = this._strategy.getValue(); this.dateValue(value, e.event); super._applyButtonHandler() } _dispose() { var _this$_strategy4; super._dispose(); null === (_this$_strategy4 = this._strategy) || void 0 === _this$_strategy4 || _this$_strategy4.dispose() } _isNativeType() { return this._pickerType === PICKER_TYPE.native } _updatePopupTitle() { var _this$_popup2; null === (_this$_popup2 = this._popup) || void 0 === _this$_popup2 || _this$_popup2.option("title", this._getPopupTitle()) } _optionChanged(args) { switch (args.name) { case "showClearButton": case "buttons": case "isValid": case "readOnly": super._optionChanged.apply(this, arguments); this._formatValidationIcon(); break; case "pickerType": this._updatePickerOptions(); this._refreshStrategy(); this._refreshPickerTypeClass(); this._invalidate(); break; case "type": this._updatePickerOptions(); this._refreshStrategy(); this._refreshFormatClass(); this._renderPopupWrapper(); this._formatValidationIcon(); this._updateValue(); break; case "placeholder": super._optionChanged.apply(this, arguments); this._updatePopupTitle(); break; case "min": case "max": { const isValid = this.option("isValid"); this._applyInternalValidation(this.dateOption("value")); if (!isValid) { this._applyCustomValidation(this.dateOption("value")) } this._invalidate(); break } case "dateSerializationFormat": case "interval": case "disabledDates": case "calendarOptions": this._invalidate(); break; case "displayFormat": this.option("text", this._getDisplayedText(this.dateOption("value"))); this._renderInputValue(); break; case "text": this._strategy.textChangedHandler(args.value); super._optionChanged.apply(this, arguments); break; case "showDropDownButton": this._formatValidationIcon(); super._optionChanged.apply(this, arguments); break; case "todayButtonText": this._setPopupOption("toolbarItems", this._getPopupToolbarItems()); break; case "invalidDateMessage": case "dateOutOfRangeMessage": case "adaptivityEnabled": case "showAnalogClock": case "_showValidationIcon": break; default: super._optionChanged.apply(this, arguments) } } _getSerializationFormat() { const value = this.option("value"); if (this.option("dateSerializationFormat") && (0, _config.default)().forceIsoDateParsing) { return this.option("dateSerializationFormat") } if ((0, _type.isNumeric)(value)) { return "number" } if (!(0, _type.isString)(value)) { return } return _date_serialization.default.getDateSerializationFormat(value) } _updateValue(value) { super._updateValue(); this._applyInternalValidation(value ?? this.dateOption("value")) } dateValue(value, dxEvent) { const isValueChanged = this._isValueChanged(value); if (isValueChanged && dxEvent) { this._saveValueChangeEvent(dxEvent) } if (!isValueChanged) { const { text: text } = this.option(); if (this._isTextChanged(value)) { this._updateValue(value) } else if ("" === text) { this._applyCustomValidation(value) } } return this.dateOption("value", value) } dateOption(optionName, value) { if (1 === arguments.length) { return _date_serialization.default.deserializeDate(this.option(optionName)) } this.option(optionName, this._serializeDate(value)) } _serializeDate(date) { const serializationFormat = this._getSerializationFormat(); return _date_serialization.default.serializeDate(date, serializationFormat) } _clearValue() { const value = this.option("value"); super._clearValue(); if (null === value) { this._applyCustomValidation(null) } } clear() { const value = this.option("value"); super.clear(); if (null === value) { this._applyInternalValidation(null) } } } var _default = exports.default = DateBox;