UNPKG

devextreme

Version:

HTML5 JavaScript Component Suite for Responsive Web Development

594 lines (593 loc) • 22 kB
/** * DevExtreme (esm/ui/date_box/ui.date_box.mask.js) * Version: 21.1.4 * Build date: Mon Jun 21 2021 * * Copyright (c) 2012 - 2021 Developer Express Inc. ALL RIGHTS RESERVED * Read about DevExtreme licensing here: https://js.devexpress.com/Licensing/ */ import { addNamespace, normalizeKeyName, isCommandKeyPressed } from "../../events/utils/index"; import { isFunction, isString, isDate, isDefined } from "../../core/utils/type"; import { clipboardText } from "../../core/utils/dom"; import { extend } from "../../core/utils/extend"; import { fitIntoRange, inRange, sign } from "../../core/utils/math"; import eventsEngine from "../../events/core/events_engine"; import { getDatePartIndexByPosition, renderDateParts } from "./ui.date_box.mask.parts"; import dateLocalization from "../../localization/date"; import { getRegExpInfo } from "../../localization/ldml/date.parser"; import { getFormat } from "../../localization/ldml/date.format"; import DateBoxBase from "./ui.date_box.base"; import numberLocalization from "../../localization/number"; import devices from "../../core/devices"; import browser from "../../core/utils/browser"; var MASK_EVENT_NAMESPACE = "dateBoxMask"; var FORWARD = 1; var BACKWARD = -1; var DateBoxMask = DateBoxBase.inherit({ _supportedKeys(e) { var originalHandlers = this.callBase(e); var callOriginalHandler = e => { var originalHandler = originalHandlers[normalizeKeyName(e)]; return originalHandler && originalHandler.apply(this, [e]) }; var applyHandler = (e, maskHandler) => { if (this._shouldUseOriginalHandler(e)) { return callOriginalHandler.apply(this, [e]) } else { return maskHandler.apply(this, [e]) } }; return extend({}, originalHandlers, { del: e => applyHandler(e, event => { this._revertPart(FORWARD); this._isAllSelected() || event.preventDefault() }), backspace: e => applyHandler(e, event => { this._revertPart(BACKWARD); this._isAllSelected() || event.preventDefault() }), home: e => applyHandler(e, event => { this._selectFirstPart(); event.preventDefault() }), end: e => applyHandler(e, event => { this._selectLastPart(); event.preventDefault() }), escape: e => applyHandler(e, event => { this._revertChanges(event) }), enter: e => applyHandler(e, event => { this._enterHandler(event) }), leftArrow: e => applyHandler(e, event => { this._selectNextPart(BACKWARD); event.preventDefault() }), rightArrow: e => applyHandler(e, event => { this._selectNextPart(FORWARD); event.preventDefault() }), upArrow: e => applyHandler(e, event => { this._upDownArrowHandler(FORWARD); event.preventDefault() }), downArrow: e => applyHandler(e, event => { this._upDownArrowHandler(BACKWARD); event.preventDefault() }) }) }, _shouldUseOriginalHandler(e) { var isNotDeletingInCalendar = this.option("opened") && e && -1 === ["backspace", "del"].indexOf(normalizeKeyName(e)); return !this._useMaskBehavior() || isNotDeletingInCalendar || e && e.altKey }, _upDownArrowHandler(step) { this._setNewDateIfEmpty(); var originalValue = this._getActivePartValue(this._initialMaskValue); var currentValue = this._getActivePartValue(); var delta = currentValue - originalValue; this._loadMaskValue(this._initialMaskValue); this._partIncrease(delta + step, true) }, _getDefaultOptions() { return extend(this.callBase(), { useMaskBehavior: false, emptyDateValue: new Date(2e3, 0, 1, 0, 0, 0) }) }, _isSingleCharKey(_ref) { var { originalEvent: originalEvent, alt: alt } = _ref; var key = originalEvent.data || ("space" === normalizeKeyName(originalEvent) ? " " : originalEvent.key); return "string" === typeof key && 1 === key.length && !alt && !isCommandKeyPressed(originalEvent) }, _isSingleDigitKey(e) { var _e$originalEvent; var data = null === (_e$originalEvent = e.originalEvent) || void 0 === _e$originalEvent ? void 0 : _e$originalEvent.data; return 1 === (null === data || void 0 === data ? void 0 : data.length) && parseInt(data, 10) }, _useBeforeInputEvent: function() { var device = devices.real(); return device.android && device.version[0] > 4 }, _keyboardHandler(e) { var key = e.originalEvent.key; var result = this.callBase(e); if (!this._useMaskBehavior() || this._useBeforeInputEvent()) { return result } if (browser.chrome && "Process" === e.key && 0 === e.code.indexOf("Digit")) { key = e.code.replace("Digit", ""); this._processInputKey(key); this._maskInputHandler = () => { this._renderSelectedPart() } } else if (this._isSingleCharKey(e)) { this._processInputKey(key); e.originalEvent.preventDefault() } return result }, _maskBeforeInputHandler(e) { this._maskInputHandler = null; var { inputType: inputType } = e.originalEvent; if ("insertCompositionText" === inputType) { this._maskInputHandler = () => { this._renderSelectedPart() } } var isBackwardDeletion = "deleteContentBackward" === inputType; var isForwardDeletion = "deleteContentForward" === inputType; if (isBackwardDeletion || isForwardDeletion) { var direction = isBackwardDeletion ? BACKWARD : FORWARD; this._maskInputHandler = () => { this._revertPart(); this._selectNextPart(direction) } } if (!this._useMaskBehavior() || !this._isSingleCharKey(e)) { return } var key = e.originalEvent.data; this._processInputKey(key); e.preventDefault(); return true }, _keyPressHandler(e) { var { originalEvent: event } = e; if ("insertCompositionText" === (null === event || void 0 === event ? void 0 : event.inputType) && this._isSingleDigitKey(e)) { this._processInputKey(event.data); this._renderDisplayText(this._getDisplayedText(this._maskValue)); this._selectNextPart() } this.callBase(e); if (this._maskInputHandler) { this._maskInputHandler(); this._maskInputHandler = null } }, _processInputKey(key) { if (this._isAllSelected()) { this._activePartIndex = 0 } this._setNewDateIfEmpty(); if (isNaN(parseInt(key))) { this._searchString(key) } else { this._searchNumber(key) } }, _isAllSelected() { var caret = this._caret(); return caret.end - caret.start === this.option("text").length }, _getFormatPattern() { if (this._formatPattern) { return this._formatPattern } var format = this._strategy.getDisplayFormat(this.option("displayFormat")); var isLDMLPattern = isString(format) && !dateLocalization._getPatternByFormat(format); if (isLDMLPattern) { this._formatPattern = format } else { this._formatPattern = getFormat((function(value) { return dateLocalization.format(value, format) })) } return this._formatPattern }, _setNewDateIfEmpty() { if (!this._maskValue) { var value = "time" === this.option("type") ? new Date(null) : new Date; this._maskValue = value; this._initialMaskValue = value; this._renderDateParts() } }, _partLimitsReached(max) { var maxLimitLength = String(max).length; var formatLength = this._getActivePartProp("pattern").length; var isShortFormat = 1 === formatLength; var maxSearchLength = isShortFormat ? maxLimitLength : Math.min(formatLength, maxLimitLength); var isLengthExceeded = this._searchValue.length === maxSearchLength; var isValueOverflowed = parseInt(this._searchValue + "0") > max; return isLengthExceeded || isValueOverflowed }, _searchNumber(char) { var { max: max } = this._getActivePartLimits(); var maxLimitLength = String(max).length; this._searchValue = (this._searchValue + char).substr(-maxLimitLength); if (isNaN(this._searchValue)) { this._searchValue = char } this._setActivePartValue(this._searchValue); if (this._partLimitsReached(max)) { this._selectNextPart(FORWARD) } }, _searchString(char) { if (!isNaN(parseInt(this._getActivePartProp("text")))) { return } var limits = this._getActivePartProp("limits")(this._maskValue); var startString = this._searchValue + char.toLowerCase(); var endLimit = limits.max - limits.min; for (var i = 0; i <= endLimit; i++) { this._loadMaskValue(this._initialMaskValue); this._partIncrease(i + 1); if (0 === this._getActivePartProp("text").toLowerCase().indexOf(startString)) { this._searchValue = startString; return } } this._setNewDateIfEmpty(); if (this._searchValue) { this._clearSearchValue(); this._searchString(char) } }, _clearSearchValue() { this._searchValue = "" }, _revertPart: function(direction) { if (!this._isAllSelected()) { var actual = this._getActivePartValue(this.option("emptyDateValue")); this._setActivePartValue(actual); this._selectNextPart(direction) } this._clearSearchValue() }, _useMaskBehavior() { return this.option("useMaskBehavior") && "text" === this.option("mode") }, _prepareRegExpInfo() { this._regExpInfo = getRegExpInfo(this._getFormatPattern(), dateLocalization); var regExp = this._regExpInfo.regexp; var flags = regExp.flags; var convertedRegExp = numberLocalization.convertDigits(this._regExpInfo.regexp.source, false); this._regExpInfo.regexp = RegExp(convertedRegExp, flags) }, _initMaskState() { this._activePartIndex = 0; this._formatPattern = null; this._prepareRegExpInfo(); this._loadMaskValue() }, _renderMask() { this.callBase(); this._detachMaskEvents(); this._clearMaskState(); if (this._useMaskBehavior()) { this._attachMaskEvents(); this._initMaskState(); this._renderDateParts() } }, _renderDateParts() { if (!this._useMaskBehavior()) { return } var text = this.option("text") || this._getDisplayedText(this._maskValue); if (text) { this._dateParts = renderDateParts(text, this._regExpInfo); if (!this._input().is(":hidden")) { this._selectNextPart() } } }, _detachMaskEvents() { eventsEngine.off(this._input(), "." + MASK_EVENT_NAMESPACE) }, _attachMaskEvents() { eventsEngine.on(this._input(), addNamespace("dxclick", MASK_EVENT_NAMESPACE), this._maskClickHandler.bind(this)); eventsEngine.on(this._input(), addNamespace("paste", MASK_EVENT_NAMESPACE), this._maskPasteHandler.bind(this)); eventsEngine.on(this._input(), addNamespace("drop", MASK_EVENT_NAMESPACE), () => { this._renderSelectedPart() }); eventsEngine.on(this._input(), addNamespace("compositionend", MASK_EVENT_NAMESPACE), this._maskCompositionEndHandler.bind(this)); if (this._useBeforeInputEvent()) { eventsEngine.on(this._input(), addNamespace("beforeinput", MASK_EVENT_NAMESPACE), this._maskBeforeInputHandler.bind(this)) } }, _renderSelectedPart() { this._renderDisplayText(this._getDisplayedText(this._maskValue)); this._selectNextPart() }, _selectLastPart() { if (this.option("text")) { this._activePartIndex = this._dateParts.length; this._selectNextPart(BACKWARD) } }, _selectFirstPart() { if (this.option("text")) { this._activePartIndex = -1; this._selectNextPart(FORWARD) } }, _onMouseWheel(e) { if (this._useMaskBehavior()) { this._partIncrease(e.delta > 0 ? FORWARD : BACKWARD, e) } }, _selectNextPart() { var step = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : 0; if (!this.option("text") || this._disposed) { return } if (step) { this._initialMaskValue = new Date(this._maskValue) } var index = fitIntoRange(this._activePartIndex + step, 0, this._dateParts.length - 1); if (this._dateParts[index].isStub) { var isBoundaryIndex = 0 === index && step < 0 || index === this._dateParts.length - 1 && step > 0; if (!isBoundaryIndex) { this._selectNextPart(step >= 0 ? step + 1 : step - 1); return } else { index = this._activePartIndex } } if (this._activePartIndex !== index) { this._clearSearchValue() } this._activePartIndex = index; this._caret(this._getActivePartProp("caret")) }, _getRealLimitsPattern() { if ("d" === this._getActivePartProp("pattern")[0]) { return "dM" } }, _getActivePartLimits(lockOtherParts) { var limitFunction = this._getActivePartProp("limits"); return limitFunction(this._maskValue, lockOtherParts && this._getRealLimitsPattern()) }, _getActivePartValue(dateValue) { dateValue = dateValue || this._maskValue; var getter = this._getActivePartProp("getter"); return isFunction(getter) ? getter(dateValue) : dateValue[getter]() }, _addLeadingZeroes(value) { var zeroes = this._searchValue.match(/^0+/); var limits = this._getActivePartLimits(); var maxLimitLength = String(limits.max).length; return ((zeroes && zeroes[0] || "") + String(value)).substr(-maxLimitLength) }, _setActivePartValue(value, dateValue) { dateValue = dateValue || this._maskValue; var setter = this._getActivePartProp("setter"); var limits = this._getActivePartLimits(); value = inRange(value, limits.min, limits.max) ? value : value % 10; value = this._addLeadingZeroes(fitIntoRange(value, limits.min, limits.max)); isFunction(setter) ? setter(dateValue, value) : dateValue[setter](value); this._renderDisplayText(this._getDisplayedText(dateValue)); this._renderDateParts() }, _getActivePartProp(property) { if (!this._dateParts || !this._dateParts[this._activePartIndex]) { return } return this._dateParts[this._activePartIndex][property] }, _loadMaskValue() { var value = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : this.dateOption("value"); this._maskValue = value && new Date(value); this._initialMaskValue = value && new Date(value) }, _saveMaskValue() { var value = this._maskValue && new Date(this._maskValue); if (value && "date" === this.option("type")) { value.setHours(0, 0, 0, 0) } this._initialMaskValue = new Date(value); this.dateOption("value", value) }, _revertChanges() { this._loadMaskValue(); this._renderDisplayText(this._getDisplayedText(this._maskValue)); this._renderDateParts() }, _renderDisplayText(text) { this.callBase(text); if (this._useMaskBehavior()) { this.option("text", text) } }, _partIncrease(step, lockOtherParts) { this._setNewDateIfEmpty(); var { max: max, min: min } = this._getActivePartLimits(lockOtherParts); var limitDelta = max - min; if (1 === limitDelta) { limitDelta++ } var newValue = step + this._getActivePartValue(); if (newValue > max) { newValue = this._applyLimits(newValue, { limitBase: min, limitClosest: max, limitDelta: limitDelta }) } else if (newValue < min) { newValue = this._applyLimits(newValue, { limitBase: max, limitClosest: min, limitDelta: limitDelta }) } this._setActivePartValue(newValue) }, _applyLimits(newValue, _ref2) { var { limitBase: limitBase, limitClosest: limitClosest, limitDelta: limitDelta } = _ref2; var delta = (newValue - limitClosest) % limitDelta; return delta ? limitBase + delta - 1 * sign(delta) : limitClosest }, _maskClickHandler() { if (this.option("text")) { this._activePartIndex = getDatePartIndexByPosition(this._dateParts, this._caret().start); if (isDefined(this._activePartIndex)) { this._caret(this._getActivePartProp("caret")) } else { this._selectLastPart() } } }, _maskCompositionEndHandler(e) { if (browser.msie && this._isSingleDigitKey(e)) { var key = e.originalEvent.data; this._processInputKey(key) } else { this._input().val(this._getDisplayedText(this._maskValue)); this._selectNextPart(); this._maskInputHandler = () => { this._renderSelectedPart() } } }, _maskPasteHandler(e) { var newText = this._replaceSelectedText(this.option("text"), this._caret(), clipboardText(e)); var date = dateLocalization.parse(newText, this._getFormatPattern()); if (date && this._isDateValid(date)) { this._maskValue = date; this._renderDisplayText(this._getDisplayedText(this._maskValue)); this._renderDateParts(); this._selectNextPart() } e.preventDefault() }, _isDateValid: date => isDate(date) && !isNaN(date), _isValueDirty() { var value = this.dateOption("value"); return (this._maskValue && this._maskValue.getTime()) !== (value && value.getTime()) }, _fireChangeEvent() { this._clearSearchValue(); if (this._isValueDirty()) { eventsEngine.trigger(this._input(), "change") } }, _enterHandler(e) { this._fireChangeEvent(); this._selectNextPart(FORWARD); e.preventDefault() }, _focusOutHandler(e) { this.callBase(e); if (this._useMaskBehavior() && !e.isDefaultPrevented()) { this._fireChangeEvent(); this._selectFirstPart(e) } }, _valueChangeEventHandler(e) { var text = this.option("text"); if (this._useMaskBehavior()) { this._saveValueChangeEvent(e); if (!text) { this._maskValue = null } else if (null === this._maskValue) { this._loadMaskValue(text) } this._saveMaskValue() } else { this.callBase(e) } }, _optionChanged(args) { switch (args.name) { case "useMaskBehavior": this._renderMask(); break; case "displayFormat": case "mode": this.callBase(args); this._renderMask(); break; case "value": this._loadMaskValue(); this.callBase(args); this._renderDateParts(); break; case "emptyDateValue": break; default: this.callBase(args) } }, _clearMaskState() { this._clearSearchValue(); delete this._dateParts; delete this._activePartIndex; delete this._maskValue }, reset() { this.callBase(); this._clearMaskState(); this._activePartIndex = 0 }, _clean() { this.callBase(); this._detachMaskEvents(); this._clearMaskState() } }); export default DateBoxMask;