UNPKG

devextreme

Version:

HTML5 JavaScript Component Suite for Responsive Web Development

129 lines (127 loc) 5.32 kB
/** * DevExtreme (esm/__internal/ui/number_box/m_number_box.caret.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/ */ import number from "../../../common/core/localization/number"; import { escapeRegExp } from "../../../core/utils/common"; import { fitIntoRange } from "../../../core/utils/math"; import { getNthOccurrence, getRealSeparatorIndex, splitByIndex } from "./m_utils"; export const getCaretBoundaries = function(text, format) { if ("string" === typeof format) { const signParts = format.split(";"); const sign = number.getSign(text, format); signParts[1] = signParts[1] || `-${signParts[0]}`; format = signParts[sign < 0 ? 1 : 0]; const mockEscapedStubs = str => str.replace(/'([^']*)'/g, (str => str.split("").map((() => " ")).join("").substr(2))); format = mockEscapedStubs(format); const prefixStubLength = /^[^#0.,]*/.exec(format)[0].length; const postfixStubLength = /[^#0.,]*$/.exec(format)[0].length; return { start: prefixStubLength, end: text.length - postfixStubLength } } return { start: 0, end: text.length } }; const _getDigitCountBeforeIndex = function(index, text) { const decimalSeparator = number.getDecimalSeparator(); const regExp = new RegExp(`[^0-9${escapeRegExp(decimalSeparator)}]`, "g"); const textBeforePosition = text.slice(0, index); return textBeforePosition.replace(regExp, "").length }; const _reverseText = function(text) { return text.split("").reverse().join("") }; const _getDigitPositionByIndex = function(digitIndex, text) { if (!digitIndex) { return -1 } const regExp = /[0-9]/g; let counter = 1; let index = null; let result = regExp.exec(text); while (result) { index = result.index; if (counter >= digitIndex) { return index } counter++; result = regExp.exec(text) } return null === index ? text.length : index }; const _trimNonNumericCharsFromEnd = function(text) { return text.replace(/[^0-9e]+$/, "") }; export const getCaretWithOffset = function(caret, offset) { if (void 0 === caret.start) { caret = { start: caret, end: caret } } return { start: caret.start + offset, end: caret.end + offset } }; export const getCaretAfterFormat = function(text, formatted, caret, format) { caret = getCaretWithOffset(caret, 0); const point = number.getDecimalSeparator(); const isSeparatorBasedText = isSeparatorBasedString(text); const realSeparatorOccurrenceIndex = getRealSeparatorIndex(format).occurrence; const pointPosition = isSeparatorBasedText ? 0 : getNthOccurrence(text, point, realSeparatorOccurrenceIndex); const newPointPosition = getNthOccurrence(formatted, point, realSeparatorOccurrenceIndex); const textParts = splitByIndex(text, pointPosition); const formattedParts = splitByIndex(formatted, newPointPosition); const isCaretOnFloat = -1 !== pointPosition && caret.start > pointPosition; if (isCaretOnFloat) { const relativeIndex = caret.start - pointPosition - 1; const digitsBefore = _getDigitCountBeforeIndex(relativeIndex, textParts[1]); const newPosition = formattedParts[1] ? newPointPosition + 1 + _getDigitPositionByIndex(digitsBefore, formattedParts[1]) + 1 : formatted.length; return getCaretInBoundaries(newPosition, formatted, format) } const formattedIntPart = _trimNonNumericCharsFromEnd(formattedParts[0]); const positionFromEnd = textParts[0].length - caret.start; const digitsFromEnd = _getDigitCountBeforeIndex(positionFromEnd, _reverseText(textParts[0])); const newPositionFromEnd = _getDigitPositionByIndex(digitsFromEnd, _reverseText(formattedIntPart)); const newPositionFromBegin = formattedIntPart.length - (newPositionFromEnd + 1); return getCaretInBoundaries(newPositionFromBegin, formatted, format) }; function isSeparatorBasedString(text) { return 1 === text.length && !!text.match(/^[,.][0-9]*$/g) } export const isCaretInBoundaries = function(caret, text, format) { caret = getCaretWithOffset(caret, 0); const boundaries = getCaretInBoundaries(caret, text, format); return caret.start >= boundaries.start && caret.end <= boundaries.end }; export function getCaretInBoundaries(caret, text, format) { caret = getCaretWithOffset(caret, 0); const boundaries = getCaretBoundaries(text, format); const adjustedCaret = { start: fitIntoRange(caret.start, boundaries.start, boundaries.end), end: fitIntoRange(caret.end, boundaries.start, boundaries.end) }; return adjustedCaret } export const getCaretOffset = function(previousText, newText, format) { const previousBoundaries = getCaretBoundaries(previousText, format); const newBoundaries = getCaretBoundaries(newText, format); return newBoundaries.start - previousBoundaries.start };