UNPKG

ngx-mask

Version:
952 lines (949 loc) 125 kB
import * as i0 from '@angular/core'; import { InjectionToken, EventEmitter, inject, Injectable, ElementRef, Renderer2, makeEnvironmentProviders, Directive, Input, Output, HostListener, Pipe } from '@angular/core'; import { DOCUMENT } from '@angular/common'; import { NG_VALUE_ACCESSOR, NG_VALIDATORS } from '@angular/forms'; const NGX_MASK_CONFIG = new InjectionToken('ngx-mask config'); const NEW_CONFIG = new InjectionToken('new ngx-mask config'); const INITIAL_CONFIG = new InjectionToken('initial ngx-mask config'); const initialConfig = { suffix: '', prefix: '', thousandSeparator: ' ', decimalMarker: ['.', ','], clearIfNotMatch: false, showTemplate: false, showMaskTyped: false, placeHolderCharacter: '_', dropSpecialCharacters: true, hiddenInput: undefined, shownMaskExpression: '', separatorLimit: '', allowNegativeNumbers: false, validation: true, // eslint-disable-next-line @typescript-eslint/quotes specialCharacters: ['-', '/', '(', ')', '.', ':', ' ', '+', ',', '@', '[', ']', '"', "'"], leadZeroDateTime: false, apm: false, leadZero: false, keepCharacterPositions: false, triggerOnMaskChange: false, inputTransformFn: (value) => value, outputTransformFn: (value) => value, maskFilled: new EventEmitter(), patterns: { '0': { pattern: new RegExp('\\d'), }, '9': { pattern: new RegExp('\\d'), optional: true, }, X: { pattern: new RegExp('\\d'), symbol: '*', }, A: { pattern: new RegExp('[a-zA-Z0-9]'), }, S: { pattern: new RegExp('[a-zA-Z]'), }, U: { pattern: new RegExp('[A-Z]'), }, L: { pattern: new RegExp('[a-z]'), }, d: { pattern: new RegExp('\\d'), }, m: { pattern: new RegExp('\\d'), }, M: { pattern: new RegExp('\\d'), }, H: { pattern: new RegExp('\\d'), }, h: { pattern: new RegExp('\\d'), }, s: { pattern: new RegExp('\\d'), }, }, }; const timeMasks = [ "Hh:m0:s0" /* MaskExpression.HOURS_MINUTES_SECONDS */, "Hh:m0" /* MaskExpression.HOURS_MINUTES */, "m0:s0" /* MaskExpression.MINUTES_SECONDS */, ]; const withoutValidation = [ "percent" /* MaskExpression.PERCENT */, "Hh" /* MaskExpression.HOURS_HOUR */, "s0" /* MaskExpression.SECONDS */, "m0" /* MaskExpression.MINUTES */, "separator" /* MaskExpression.SEPARATOR */, "d0/M0/0000" /* MaskExpression.DAYS_MONTHS_YEARS */, "d0/M0" /* MaskExpression.DAYS_MONTHS */, "d0" /* MaskExpression.DAYS */, "M0" /* MaskExpression.MONTHS */, ]; class NgxMaskApplierService { constructor() { this._config = inject(NGX_MASK_CONFIG); this.dropSpecialCharacters = this._config.dropSpecialCharacters; this.hiddenInput = this._config.hiddenInput; this.clearIfNotMatch = this._config.clearIfNotMatch; this.specialCharacters = this._config.specialCharacters; this.patterns = this._config.patterns; this.prefix = this._config.prefix; this.suffix = this._config.suffix; this.thousandSeparator = this._config.thousandSeparator; this.decimalMarker = this._config.decimalMarker; this.showMaskTyped = this._config.showMaskTyped; this.placeHolderCharacter = this._config.placeHolderCharacter; this.validation = this._config.validation; this.separatorLimit = this._config.separatorLimit; this.allowNegativeNumbers = this._config.allowNegativeNumbers; this.leadZeroDateTime = this._config.leadZeroDateTime; this.leadZero = this._config.leadZero; this.apm = this._config.apm; this.inputTransformFn = this._config.inputTransformFn; this.outputTransformFn = this._config.outputTransformFn; this.keepCharacterPositions = this._config.keepCharacterPositions; this._shift = new Set(); this.plusOnePosition = false; this.maskExpression = ''; this.actualValue = ''; this.showKeepCharacterExp = ''; this.shownMaskExpression = ''; this.deletedSpecialCharacter = false; this._formatWithSeparators = (str, thousandSeparatorChar, decimalChars, precision) => { let x = []; let decimalChar = ''; if (Array.isArray(decimalChars)) { const regExp = new RegExp(decimalChars.map((v) => ('[\\^$.|?*+()'.indexOf(v) >= 0 ? `\\${v}` : v)).join('|')); x = str.split(regExp); decimalChar = str.match(regExp)?.[0] ?? "" /* MaskExpression.EMPTY_STRING */; } else { x = str.split(decimalChars); decimalChar = decimalChars; } const decimals = x.length > 1 ? `${decimalChar}${x[1]}` : "" /* MaskExpression.EMPTY_STRING */; let res = x[0] ?? "" /* MaskExpression.EMPTY_STRING */; const separatorLimit = this.separatorLimit.replace(/\s/g, "" /* MaskExpression.EMPTY_STRING */); if (separatorLimit && +separatorLimit) { if (res[0] === "-" /* MaskExpression.MINUS */) { res = `-${res.slice(1, res.length).slice(0, separatorLimit.length)}`; } else { res = res.slice(0, separatorLimit.length); } } const rgx = /(\d+)(\d{3})/; while (thousandSeparatorChar && rgx.test(res)) { res = res.replace(rgx, '$1' + thousandSeparatorChar + '$2'); } if (precision === undefined) { return res + decimals; } else if (precision === 0) { return res; } return res + decimals.substring(0, precision + 1); }; this.percentage = (str) => { const sanitizedStr = str.replace(',', '.'); const value = Number(this.allowNegativeNumbers && str.includes("-" /* MaskExpression.MINUS */) ? sanitizedStr.slice(1, str.length) : sanitizedStr); return !isNaN(value) && value >= 0 && value <= 100; }; this.getPrecision = (maskExpression) => { const x = maskExpression.split("." /* MaskExpression.DOT */); if (x.length > 1) { return Number(x[x.length - 1]); } return Infinity; }; this.checkAndRemoveSuffix = (inputValue) => { for (let i = this.suffix?.length - 1; i >= 0; i--) { const substr = this.suffix.substring(i, this.suffix?.length); if (inputValue.includes(substr) && i !== this.suffix?.length - 1 && (i - 1 < 0 || !inputValue.includes(this.suffix.substring(i - 1, this.suffix?.length)))) { return inputValue.replace(substr, "" /* MaskExpression.EMPTY_STRING */); } } return inputValue; }; this.checkInputPrecision = (inputValue, precision, decimalMarker) => { if (precision < Infinity) { // TODO need think about decimalMarker if (Array.isArray(decimalMarker)) { const marker = decimalMarker.find((dm) => dm !== this.thousandSeparator); // eslint-disable-next-line no-param-reassign decimalMarker = marker ? marker : decimalMarker[0]; } const precisionRegEx = new RegExp(this._charToRegExpExpression(decimalMarker) + `\\d{${precision}}.*$`); const precisionMatch = inputValue.match(precisionRegEx); const precisionMatchLength = (precisionMatch && precisionMatch[0]?.length) ?? 0; if (precisionMatchLength - 1 > precision) { const diff = precisionMatchLength - 1 - precision; // eslint-disable-next-line no-param-reassign inputValue = inputValue.substring(0, inputValue.length - diff); } if (precision === 0 && this._compareOrIncludes(inputValue[inputValue.length - 1], decimalMarker, this.thousandSeparator)) { // eslint-disable-next-line no-param-reassign inputValue = inputValue.substring(0, inputValue.length - 1); } } return inputValue; }; } applyMaskWithPattern(inputValue, maskAndPattern) { const [mask, customPattern] = maskAndPattern; this.customPattern = customPattern; return this.applyMask(inputValue, mask); } applyMask(inputValue, maskExpression, position = 0, justPasted = false, backspaced = false, // eslint-disable-next-line @typescript-eslint/no-explicit-any cb = () => { }) { if (!maskExpression || typeof inputValue !== 'string') { return "" /* MaskExpression.EMPTY_STRING */; } let cursor = 0; let result = ''; let multi = false; let backspaceShift = false; let shift = 1; let stepBack = false; if (inputValue.slice(0, this.prefix.length) === this.prefix) { // eslint-disable-next-line no-param-reassign inputValue = inputValue.slice(this.prefix.length, inputValue.length); } if (!!this.suffix && inputValue?.length > 0) { // eslint-disable-next-line no-param-reassign inputValue = this.checkAndRemoveSuffix(inputValue); } if (inputValue === '(' && this.prefix) { // eslint-disable-next-line no-param-reassign inputValue = ''; } const inputArray = inputValue.toString().split("" /* MaskExpression.EMPTY_STRING */); if (this.allowNegativeNumbers && inputValue.slice(cursor, cursor + 1) === "-" /* MaskExpression.MINUS */) { result += inputValue.slice(cursor, cursor + 1); } if (maskExpression === "IP" /* MaskExpression.IP */) { const valuesIP = inputValue.split("." /* MaskExpression.DOT */); this.ipError = this._validIP(valuesIP); // eslint-disable-next-line no-param-reassign maskExpression = '099.099.099.099'; } const arr = []; for (let i = 0; i < inputValue.length; i++) { if (inputValue[i]?.match('\\d')) { arr.push(inputValue[i] ?? "" /* MaskExpression.EMPTY_STRING */); } } if (maskExpression === "CPF_CNPJ" /* MaskExpression.CPF_CNPJ */) { this.cpfCnpjError = arr.length !== 11 && arr.length !== 14; if (arr.length > 11) { // eslint-disable-next-line no-param-reassign maskExpression = '00.000.000/0000-00'; } else { // eslint-disable-next-line no-param-reassign maskExpression = '000.000.000-00'; } } if (maskExpression.startsWith("percent" /* MaskExpression.PERCENT */)) { if (inputValue.match('[a-z]|[A-Z]') || // eslint-disable-next-line no-useless-escape (inputValue.match(/[-!$%^&*()_+|~=`{}\[\]:";'<>?,\/.]/) && !backspaced)) { // eslint-disable-next-line no-param-reassign inputValue = this._stripToDecimal(inputValue); const precision = this.getPrecision(maskExpression); // eslint-disable-next-line no-param-reassign inputValue = this.checkInputPrecision(inputValue, precision, this.decimalMarker); } const decimalMarker = typeof this.decimalMarker === 'string' ? this.decimalMarker : "." /* MaskExpression.DOT */; if (inputValue.indexOf(decimalMarker) > 0 && !this.percentage(inputValue.substring(0, inputValue.indexOf(decimalMarker)))) { let base = inputValue.substring(0, inputValue.indexOf(decimalMarker) - 1); if (this.allowNegativeNumbers && inputValue.slice(cursor, cursor + 1) === "-" /* MaskExpression.MINUS */ && !backspaced) { base = inputValue.substring(0, inputValue.indexOf(decimalMarker)); } // eslint-disable-next-line no-param-reassign inputValue = `${base}${inputValue.substring(inputValue.indexOf(decimalMarker), inputValue.length)}`; } let value = ''; this.allowNegativeNumbers && inputValue.slice(cursor, cursor + 1) === "-" /* MaskExpression.MINUS */ ? (value = `${"-" /* MaskExpression.MINUS */}${inputValue.slice(cursor + 1, cursor + inputValue.length)}`) : (value = inputValue); if (this.percentage(value)) { result = this._splitPercentZero(inputValue); } else { result = this._splitPercentZero(inputValue.substring(0, inputValue.length - 1)); } } else if (maskExpression.startsWith("separator" /* MaskExpression.SEPARATOR */)) { if (inputValue.match('[wа-яА-Я]') || inputValue.match('[ЁёА-я]') || inputValue.match('[a-z]|[A-Z]') || inputValue.match(/[-@#!$%\\^&*()_£¬'+|~=`{}\]:";<>.?/]/) || inputValue.match('[^A-Za-z0-9,]')) { // eslint-disable-next-line no-param-reassign inputValue = this._stripToDecimal(inputValue); } const precision = this.getPrecision(maskExpression); const decimalMarker = Array.isArray(this.decimalMarker) ? "." /* MaskExpression.DOT */ : this.decimalMarker; if (precision === 0) { // eslint-disable-next-line no-param-reassign inputValue = this.allowNegativeNumbers ? inputValue.length > 2 && inputValue[0] === "-" /* MaskExpression.MINUS */ && inputValue[1] === "0" /* MaskExpression.NUMBER_ZERO */ && inputValue[2] !== this.thousandSeparator && inputValue[2] !== "," /* MaskExpression.COMMA */ && inputValue[2] !== "." /* MaskExpression.DOT */ ? '-' + inputValue.slice(2, inputValue.length) : inputValue[0] === "0" /* MaskExpression.NUMBER_ZERO */ && inputValue.length > 1 && inputValue[1] !== this.thousandSeparator && inputValue[1] !== "," /* MaskExpression.COMMA */ && inputValue[1] !== "." /* MaskExpression.DOT */ ? inputValue.slice(1, inputValue.length) : inputValue : inputValue.length > 1 && inputValue[0] === "0" /* MaskExpression.NUMBER_ZERO */ && inputValue[1] !== this.thousandSeparator && inputValue[1] !== "," /* MaskExpression.COMMA */ && inputValue[1] !== "." /* MaskExpression.DOT */ ? inputValue.slice(1, inputValue.length) : inputValue; } else { if (inputValue[0] === decimalMarker && inputValue.length > 1) { // eslint-disable-next-line no-param-reassign inputValue = "0" /* MaskExpression.NUMBER_ZERO */ + inputValue.slice(0, inputValue.length + 1); this.plusOnePosition = true; } if (inputValue[0] === "0" /* MaskExpression.NUMBER_ZERO */ && inputValue[1] !== decimalMarker && inputValue[1] !== this.thousandSeparator) { // eslint-disable-next-line no-param-reassign inputValue = inputValue.length > 1 ? inputValue.slice(0, 1) + decimalMarker + inputValue.slice(1, inputValue.length + 1) : inputValue; this.plusOnePosition = true; } if (this.allowNegativeNumbers && inputValue[0] === "-" /* MaskExpression.MINUS */ && (inputValue[1] === decimalMarker || inputValue[1] === "0" /* MaskExpression.NUMBER_ZERO */)) { // eslint-disable-next-line no-param-reassign inputValue = inputValue[1] === decimalMarker && inputValue.length > 2 ? inputValue.slice(0, 1) + "0" /* MaskExpression.NUMBER_ZERO */ + inputValue.slice(1, inputValue.length) : inputValue[1] === "0" /* MaskExpression.NUMBER_ZERO */ && inputValue.length > 2 && inputValue[2] !== decimalMarker ? inputValue.slice(0, 2) + decimalMarker + inputValue.slice(2, inputValue.length) : inputValue; this.plusOnePosition = true; } } if (backspaced) { const inputValueAfterZero = inputValue.slice(this._findFirstNonZeroDigitIndex(inputValue), inputValue.length); const positionOfZeroOrDecimalMarker = inputValue[position] === "0" /* MaskExpression.NUMBER_ZERO */ || inputValue[position] === decimalMarker; const zeroIndexNumberZero = inputValue[0] === "0" /* MaskExpression.NUMBER_ZERO */; const zeroIndexMinus = inputValue[0] === "-" /* MaskExpression.MINUS */; const zeroIndexThousand = inputValue[0] === this.thousandSeparator; const firstIndexDecimalMarker = inputValue[1] === decimalMarker; const firstIndexNumberZero = inputValue[1] === "0" /* MaskExpression.NUMBER_ZERO */; const secondIndexDecimalMarker = inputValue[2] === decimalMarker; if (zeroIndexNumberZero && firstIndexDecimalMarker && positionOfZeroOrDecimalMarker && position < 2) { // eslint-disable-next-line no-param-reassign inputValue = inputValueAfterZero; } if (zeroIndexMinus && firstIndexNumberZero && secondIndexDecimalMarker && positionOfZeroOrDecimalMarker && position < 3) { // eslint-disable-next-line no-param-reassign inputValue = "-" /* MaskExpression.MINUS */ + inputValueAfterZero; } if (inputValueAfterZero !== "-" /* MaskExpression.MINUS */ && ((position === 0 && (zeroIndexNumberZero || zeroIndexThousand)) || (this.allowNegativeNumbers && position === 1 && zeroIndexMinus && !firstIndexNumberZero))) { // eslint-disable-next-line no-param-reassign inputValue = zeroIndexMinus ? "-" /* MaskExpression.MINUS */ + inputValueAfterZero : inputValueAfterZero; } } // TODO: we had different rexexps here for the different cases... but tests dont seam to bother - check this // separator: no COMMA, dot-sep: no SPACE, COMMA OK, comma-sep: no SPACE, COMMA OK const thousandSeparatorCharEscaped = this._charToRegExpExpression(this.thousandSeparator); let invalidChars = '@#!$%^&*()_+|~=`{}\\[\\]:\\s,\\.";<>?\\/'.replace(thousandSeparatorCharEscaped, ''); //.replace(decimalMarkerEscaped, ''); if (Array.isArray(this.decimalMarker)) { for (const marker of this.decimalMarker) { invalidChars = invalidChars.replace(this._charToRegExpExpression(marker), "" /* MaskExpression.EMPTY_STRING */); } } else { invalidChars = invalidChars.replace(this._charToRegExpExpression(this.decimalMarker), ''); } const invalidCharRegexp = new RegExp('[' + invalidChars + ']'); if (inputValue.match(invalidCharRegexp)) { // eslint-disable-next-line no-param-reassign inputValue = inputValue.substring(0, inputValue.length - 1); } // eslint-disable-next-line no-param-reassign inputValue = this.checkInputPrecision(inputValue, precision, this.decimalMarker); const strForSep = inputValue.replace(new RegExp(thousandSeparatorCharEscaped, 'g'), ''); result = this._formatWithSeparators(strForSep, this.thousandSeparator, this.decimalMarker, precision); const commaShift = result.indexOf("," /* MaskExpression.COMMA */) - inputValue.indexOf("," /* MaskExpression.COMMA */); const shiftStep = result.length - inputValue.length; if (result[position - 1] === this.thousandSeparator && this.prefix && backspaced) { // eslint-disable-next-line no-param-reassign position = position - 1; } else if (shiftStep > 0 && result[position] !== this.thousandSeparator) { backspaceShift = true; let _shift = 0; do { this._shift.add(position + _shift); _shift++; } while (_shift < shiftStep); } else if (result[position - 1] === this.decimalMarker || shiftStep === -4 || shiftStep === -3 || result[position] === this.thousandSeparator) { this._shift.clear(); this._shift.add(position - 1); } else if ((commaShift !== 0 && position > 0 && !(result.indexOf("," /* MaskExpression.COMMA */) >= position && position > 3)) || (!(result.indexOf("." /* MaskExpression.DOT */) >= position && position > 3) && shiftStep <= 0)) { this._shift.clear(); backspaceShift = true; shift = shiftStep; // eslint-disable-next-line no-param-reassign position += shiftStep; this._shift.add(position); } else { this._shift.clear(); } } else { for (let i = 0, inputSymbol = inputArray[0]; i < inputArray.length; i++, inputSymbol = inputArray[i] ?? "" /* MaskExpression.EMPTY_STRING */) { if (cursor === maskExpression.length) { break; } const symbolStarInPattern = "*" /* MaskExpression.SYMBOL_STAR */ in this.patterns; if (this._checkSymbolMask(inputSymbol, maskExpression[cursor] ?? "" /* MaskExpression.EMPTY_STRING */) && maskExpression[cursor + 1] === "?" /* MaskExpression.SYMBOL_QUESTION */) { result += inputSymbol; cursor += 2; } else if (maskExpression[cursor + 1] === "*" /* MaskExpression.SYMBOL_STAR */ && multi && this._checkSymbolMask(inputSymbol, maskExpression[cursor + 2] ?? "" /* MaskExpression.EMPTY_STRING */)) { result += inputSymbol; cursor += 3; multi = false; } else if (this._checkSymbolMask(inputSymbol, maskExpression[cursor] ?? "" /* MaskExpression.EMPTY_STRING */) && maskExpression[cursor + 1] === "*" /* MaskExpression.SYMBOL_STAR */ && !symbolStarInPattern) { result += inputSymbol; multi = true; } else if (maskExpression[cursor + 1] === "?" /* MaskExpression.SYMBOL_QUESTION */ && this._checkSymbolMask(inputSymbol, maskExpression[cursor + 2] ?? "" /* MaskExpression.EMPTY_STRING */)) { result += inputSymbol; cursor += 3; } else if (this._checkSymbolMask(inputSymbol, maskExpression[cursor] ?? "" /* MaskExpression.EMPTY_STRING */)) { if (maskExpression[cursor] === "H" /* MaskExpression.HOURS */) { if (this.apm ? Number(inputSymbol) > 9 : Number(inputSymbol) > 2) { // eslint-disable-next-line no-param-reassign position = !this.leadZeroDateTime ? position + 1 : position; cursor += 1; this._shiftStep(maskExpression, cursor, inputArray.length); i--; if (this.leadZeroDateTime) { result += '0'; } continue; } } if (maskExpression[cursor] === "h" /* MaskExpression.HOUR */) { if (this.apm ? (result.length === 1 && Number(result) > 1) || (result === '1' && Number(inputSymbol) > 2) || (inputValue.slice(cursor - 1, cursor).length === 1 && Number(inputValue.slice(cursor - 1, cursor)) > 2) || (inputValue.slice(cursor - 1, cursor) === '1' && Number(inputSymbol) > 2) : (result === '2' && Number(inputSymbol) > 3) || ((result.slice(cursor - 2, cursor) === '2' || result.slice(cursor - 3, cursor) === '2' || result.slice(cursor - 4, cursor) === '2' || result.slice(cursor - 1, cursor) === '2') && Number(inputSymbol) > 3 && cursor > 10)) { // eslint-disable-next-line no-param-reassign position = position + 1; cursor += 1; i--; continue; } } if (maskExpression[cursor] === "m" /* MaskExpression.MINUTE */ || maskExpression[cursor] === "s" /* MaskExpression.SECOND */) { if (Number(inputSymbol) > 5) { // eslint-disable-next-line no-param-reassign position = !this.leadZeroDateTime ? position + 1 : position; cursor += 1; this._shiftStep(maskExpression, cursor, inputArray.length); i--; if (this.leadZeroDateTime) { result += '0'; } continue; } } const daysCount = 31; const inputValueCursor = inputValue[cursor]; const inputValueCursorPlusOne = inputValue[cursor + 1]; const inputValueCursorPlusTwo = inputValue[cursor + 2]; const inputValueCursorMinusOne = inputValue[cursor - 1]; const inputValueCursorMinusTwo = inputValue[cursor - 2]; const inputValueSliceMinusThreeMinusOne = inputValue.slice(cursor - 3, cursor - 1); const inputValueSliceMinusOnePlusOne = inputValue.slice(cursor - 1, cursor + 1); const inputValueSliceCursorPlusTwo = inputValue.slice(cursor, cursor + 2); const inputValueSliceMinusTwoCursor = inputValue.slice(cursor - 2, cursor); if (maskExpression[cursor] === "d" /* MaskExpression.DAY */) { const maskStartWithMonth = maskExpression.slice(0, 2) === "M0" /* MaskExpression.MONTHS */; const startWithMonthInput = maskExpression.slice(0, 2) === "M0" /* MaskExpression.MONTHS */ && this.specialCharacters.includes(inputValueCursorMinusTwo); if ((Number(inputSymbol) > 3 && this.leadZeroDateTime) || (!maskStartWithMonth && (Number(inputValueSliceCursorPlusTwo) > daysCount || Number(inputValueSliceMinusOnePlusOne) > daysCount || this.specialCharacters.includes(inputValueCursorPlusOne))) || (startWithMonthInput ? Number(inputValueSliceMinusOnePlusOne) > daysCount || (!this.specialCharacters.includes(inputValueCursor) && this.specialCharacters.includes(inputValueCursorPlusTwo)) || this.specialCharacters.includes(inputValueCursor) : Number(inputValueSliceCursorPlusTwo) > daysCount || this.specialCharacters.includes(inputValueCursorPlusOne))) { // eslint-disable-next-line no-param-reassign position = !this.leadZeroDateTime ? position + 1 : position; cursor += 1; this._shiftStep(maskExpression, cursor, inputArray.length); i--; if (this.leadZeroDateTime) { result += '0'; } continue; } } if (maskExpression[cursor] === "M" /* MaskExpression.MONTH */) { const monthsCount = 12; // mask without day const withoutDays = cursor === 0 && (Number(inputSymbol) > 2 || Number(inputValueSliceCursorPlusTwo) > monthsCount || (this.specialCharacters.includes(inputValueCursorPlusOne) && !backspaced)); // day<10 && month<12 for input const specialChart = maskExpression.slice(cursor + 2, cursor + 3); const day1monthInput = inputValueSliceMinusThreeMinusOne.includes(specialChart) && maskExpression.includes('d0') && ((this.specialCharacters.includes(inputValueCursorMinusTwo) && Number(inputValueSliceMinusOnePlusOne) > monthsCount && !this.specialCharacters.includes(inputValueCursor)) || this.specialCharacters.includes(inputValueCursor)); // month<12 && day<10 for input const day2monthInput = Number(inputValueSliceMinusThreeMinusOne) <= daysCount && !this.specialCharacters.includes(inputValueSliceMinusThreeMinusOne) && this.specialCharacters.includes(inputValueCursorMinusOne) && (Number(inputValueSliceCursorPlusTwo) > monthsCount || this.specialCharacters.includes(inputValueCursorPlusOne)); // cursor === 5 && without days const day2monthInputDot = (Number(inputValueSliceCursorPlusTwo) > monthsCount && cursor === 5) || (this.specialCharacters.includes(inputValueCursorPlusOne) && cursor === 5); // // day<10 && month<12 for paste whole data const day1monthPaste = Number(inputValueSliceMinusThreeMinusOne) > daysCount && !this.specialCharacters.includes(inputValueSliceMinusThreeMinusOne) && !this.specialCharacters.includes(inputValueSliceMinusTwoCursor) && Number(inputValueSliceMinusTwoCursor) > monthsCount && maskExpression.includes('d0'); // 10<day<31 && month<12 for paste whole data const day2monthPaste = Number(inputValueSliceMinusThreeMinusOne) <= daysCount && !this.specialCharacters.includes(inputValueSliceMinusThreeMinusOne) && !this.specialCharacters.includes(inputValueCursorMinusOne) && Number(inputValueSliceMinusOnePlusOne) > monthsCount; if ((Number(inputSymbol) > 1 && this.leadZeroDateTime) || withoutDays || day1monthInput || day2monthPaste || day1monthPaste || day2monthInput || (day2monthInputDot && !this.leadZeroDateTime)) { // eslint-disable-next-line no-param-reassign position = !this.leadZeroDateTime ? position + 1 : position; cursor += 1; this._shiftStep(maskExpression, cursor, inputArray.length); i--; if (this.leadZeroDateTime) { result += '0'; } continue; } } result += inputSymbol; cursor++; } else if (this.specialCharacters.includes(inputSymbol) && maskExpression[cursor] === inputSymbol) { result += inputSymbol; cursor++; } else if (this.specialCharacters.indexOf(maskExpression[cursor] ?? "" /* MaskExpression.EMPTY_STRING */) !== -1) { result += maskExpression[cursor]; cursor++; this._shiftStep(maskExpression, cursor, inputArray.length); i--; } else if (maskExpression[cursor] === "9" /* MaskExpression.NUMBER_NINE */ && this.showMaskTyped) { this._shiftStep(maskExpression, cursor, inputArray.length); } else if (this.patterns[maskExpression[cursor] ?? "" /* MaskExpression.EMPTY_STRING */] && this.patterns[maskExpression[cursor] ?? "" /* MaskExpression.EMPTY_STRING */]?.optional) { if (!!inputArray[cursor] && maskExpression !== '099.099.099.099' && maskExpression !== '000.000.000-00' && maskExpression !== '00.000.000/0000-00' && !maskExpression.match(/^9+\.0+$/) && !this.patterns[maskExpression[cursor] ?? "" /* MaskExpression.EMPTY_STRING */] ?.optional) { result += inputArray[cursor]; } if (maskExpression.includes("9" /* MaskExpression.NUMBER_NINE */ + "*" /* MaskExpression.SYMBOL_STAR */) && maskExpression.includes("0" /* MaskExpression.NUMBER_ZERO */ + "*" /* MaskExpression.SYMBOL_STAR */)) { cursor++; } cursor++; i--; } else if (this.maskExpression[cursor + 1] === "*" /* MaskExpression.SYMBOL_STAR */ && this._findSpecialChar(this.maskExpression[cursor + 2] ?? "" /* MaskExpression.EMPTY_STRING */) && this._findSpecialChar(inputSymbol) === this.maskExpression[cursor + 2] && multi) { cursor += 3; result += inputSymbol; } else if (this.maskExpression[cursor + 1] === "?" /* MaskExpression.SYMBOL_QUESTION */ && this._findSpecialChar(this.maskExpression[cursor + 2] ?? "" /* MaskExpression.EMPTY_STRING */) && this._findSpecialChar(inputSymbol) === this.maskExpression[cursor + 2] && multi) { cursor += 3; result += inputSymbol; } else if (this.showMaskTyped && this.specialCharacters.indexOf(inputSymbol) < 0 && inputSymbol !== this.placeHolderCharacter && this.placeHolderCharacter.length === 1) { stepBack = true; } } } if (result.length + 1 === maskExpression.length && this.specialCharacters.indexOf(maskExpression[maskExpression.length - 1] ?? "" /* MaskExpression.EMPTY_STRING */) !== -1) { result += maskExpression[maskExpression.length - 1]; } let newPosition = position + 1; while (this._shift.has(newPosition)) { shift++; newPosition++; } let actualShift = justPasted && !maskExpression.startsWith("separator" /* MaskExpression.SEPARATOR */) ? cursor : this._shift.has(position) ? shift : 0; if (stepBack) { actualShift--; } cb(actualShift, backspaceShift); if (shift < 0) { this._shift.clear(); } let onlySpecial = false; if (backspaced) { onlySpecial = inputArray.every((char) => this.specialCharacters.includes(char)); } let res = `${this.prefix}${onlySpecial ? "" /* MaskExpression.EMPTY_STRING */ : result}${this.showMaskTyped ? '' : this.suffix}`; if (result.length === 0) { res = !this.dropSpecialCharacters ? `${this.prefix}${result}` : `${result}`; } const isSpecialCharacterMaskFirstSymbol = inputValue.length === 1 && this.specialCharacters.includes(maskExpression[0]) && inputValue !== maskExpression[0]; if (!this._checkSymbolMask(inputValue, maskExpression[1]) && isSpecialCharacterMaskFirstSymbol) { return ''; } if (result.includes("-" /* MaskExpression.MINUS */) && this.prefix && this.allowNegativeNumbers) { if (backspaced && result === "-" /* MaskExpression.MINUS */) { return ''; } res = `${"-" /* MaskExpression.MINUS */}${this.prefix}${result .split("-" /* MaskExpression.MINUS */) .join("" /* MaskExpression.EMPTY_STRING */)}${this.suffix}`; } return res; } _findDropSpecialChar(inputSymbol) { if (Array.isArray(this.dropSpecialCharacters)) { return this.dropSpecialCharacters.find((val) => val === inputSymbol); } return this._findSpecialChar(inputSymbol); } _findSpecialChar(inputSymbol) { return this.specialCharacters.find((val) => val === inputSymbol); } _checkSymbolMask(inputSymbol, maskSymbol) { this.patterns = this.customPattern ? this.customPattern : this.patterns; return ((this.patterns[maskSymbol]?.pattern && this.patterns[maskSymbol]?.pattern.test(inputSymbol)) ?? false); } _stripToDecimal(str) { return str .split("" /* MaskExpression.EMPTY_STRING */) .filter((i, idx) => { const isDecimalMarker = typeof this.decimalMarker === 'string' ? i === this.decimalMarker : // TODO (inepipenko) use utility type this.decimalMarker.includes(i); return (i.match('^-?\\d') || i === this.thousandSeparator || isDecimalMarker || (i === "-" /* MaskExpression.MINUS */ && idx === 0 && this.allowNegativeNumbers)); }) .join("" /* MaskExpression.EMPTY_STRING */); } _charToRegExpExpression(char) { // if (Array.isArray(char)) { // return char.map((v) => ('[\\^$.|?*+()'.indexOf(v) >= 0 ? `\\${v}` : v)).join('|'); // } if (char) { const charsToEscape = '[\\^$.|?*+()'; return char === ' ' ? '\\s' : charsToEscape.indexOf(char) >= 0 ? `\\${char}` : char; } return char; } _shiftStep(maskExpression, cursor, inputLength) { const shiftStep = /[*?]/g.test(maskExpression.slice(0, cursor)) ? inputLength : cursor; this._shift.add(shiftStep + this.prefix.length || 0); } _compareOrIncludes(value, comparedValue, excludedValue) { return Array.isArray(comparedValue) ? comparedValue.filter((v) => v !== excludedValue).includes(value) : value === comparedValue; } _validIP(valuesIP) { return !(valuesIP.length === 4 && !valuesIP.some((value, index) => { if (valuesIP.length !== index + 1) { return value === "" /* MaskExpression.EMPTY_STRING */ || Number(value) > 255; } return value === "" /* MaskExpression.EMPTY_STRING */ || Number(value.substring(0, 3)) > 255; })); } _splitPercentZero(value) { if (value === "-" /* MaskExpression.MINUS */ && this.allowNegativeNumbers) { return value; } const decimalIndex = typeof this.decimalMarker === 'string' ? value.indexOf(this.decimalMarker) : value.indexOf("." /* MaskExpression.DOT */); const emptyOrMinus = this.allowNegativeNumbers && value.includes("-" /* MaskExpression.MINUS */) ? '-' : ''; if (decimalIndex === -1) { const parsedValue = parseInt(emptyOrMinus ? value.slice(1, value.length) : value, 10); return isNaN(parsedValue) ? "" /* MaskExpression.EMPTY_STRING */ : `${emptyOrMinus}${parsedValue}`; } else { const integerPart = parseInt(value.replace('-', '').substring(0, decimalIndex), 10); const decimalPart = value.substring(decimalIndex + 1); const integerString = isNaN(integerPart) ? '' : integerPart.toString(); const decimal = typeof this.decimalMarker === 'string' ? this.decimalMarker : "." /* MaskExpression.DOT */; return integerString === "" /* MaskExpression.EMPTY_STRING */ ? "" /* MaskExpression.EMPTY_STRING */ : `${emptyOrMinus}${integerString}${decimal}${decimalPart}`; } } _findFirstNonZeroDigitIndex(inputString) { for (let i = 0; i < inputString.length; i++) { const char = inputString[i]; if (char && char >= '1' && char <= '9') { return i; } } return -1; } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.8", ngImport: i0, type: NgxMaskApplierService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); } static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.8", ngImport: i0, type: NgxMaskApplierService }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.8", ngImport: i0, type: NgxMaskApplierService, decorators: [{ type: Injectable }] }); class NgxMaskService extends NgxMaskApplierService { constructor() { super(...arguments); this.isNumberValue = false; this.maskIsShown = ''; this.selStart = null; this.selEnd = null; /** * Whether we are currently in writeValue function, in this case when applying the mask we don't want to trigger onChange function, * since writeValue should be a one way only process of writing the DOM value based on the Angular model value. */ this.writingValue = false; this.maskChanged = false; this._maskExpressionArray = []; this.triggerOnMaskChange = false; this._previousValue = ''; this._currentValue = ''; this._emitValue = false; // eslint-disable-next-line @typescript-eslint/no-explicit-any this.onChange = (_) => { }; this._elementRef = inject(ElementRef, { optional: true }); this.document = inject(DOCUMENT); this._config = inject(NGX_MASK_CONFIG); this._renderer = inject(Renderer2, { optional: true }); } applyMask(inputValue, maskExpression, position = 0, justPasted = false, backspaced = false, // eslint-disable-next-line @typescript-eslint/no-explicit-any cb = () => { }) { if (!maskExpression) { return inputValue !== this.actualValue ? this.actualValue : inputValue; } this.maskIsShown = this.showMaskTyped ? this.showMaskInInput() : "" /* MaskExpression.EMPTY_STRING */; if (this.maskExpression === "IP" /* MaskExpression.IP */ && this.showMaskTyped) { this.maskIsShown = this.showMaskInInput(inputValue || "#" /* MaskExpression.HASH */); } if (this.maskExpression === "CPF_CNPJ" /* MaskExpression.CPF_CNPJ */ && this.showMaskTyped) { this.maskIsShown = this.showMaskInInput(inputValue || "#" /* MaskExpression.HASH */); } if (!inputValue && this.showMaskTyped) { this.formControlResult(this.prefix); return `${this.prefix}${this.maskIsShown}${this.suffix}`; } const getSymbol = !!inputValue && typeof this.selStart === 'number' ? inputValue[this.selStart] ?? "" /* MaskExpression.EMPTY_STRING */ : "" /* MaskExpression.EMPTY_STRING */; let newInputValue = ''; if (this.hiddenInput !== undefined && !this.writingValue) { let actualResult = inputValue && inputValue.length === 1 ? inputValue.split("" /* MaskExpression.EMPTY_STRING */) : this.actualValue.split("" /* MaskExpression.EMPTY_STRING */); // eslint-disable @typescript-eslint/no-unused-expressions if (typeof this.selStart === 'object' && typeof this.selEnd === 'object') { this.selStart = Number(this.selStart); this.selEnd = Number(this.selEnd); } else { inputValue !== "" /* MaskExpression.EMPTY_STRING */ && actualResult.length ? typeof this.selStart === 'number' && typeof this.selEnd === 'number' ? inputValue.length > actualResult.length ? actualResult.splice(this.selStart, 0, getSymbol) : inputValue.length < actualResult.length ? actualResult.length - inputValue.length === 1 ? backspaced ? actualResult.splice(this.selStart - 1, 1) : actualResult.splice(inputValue.length - 1, 1) : actualResult.splice(this.selStart, this.selEnd - this.selStart) : null : null : (actualResult = []); } if (this.showMaskTyped) { if (!this.hiddenInput) { // eslint-disable-next-line no-param-reassign inputValue = this.removeMask(inputValue); } } // eslint-enable @typescript-eslint/no-unused-expressions newInputValue = this.actualValue.length && actualResult.length <= inputValue.length ? this.shiftTypedSymbols(actualResult.join("" /* MaskExpression.EMPTY_STRING */)) : inputValue; } if (justPasted && (this.hiddenInput || !this.hiddenInput)) { newInputValue = inputValue; } if (backspaced && this.specialCharacters.indexOf(this.maskExpression[position] ?? "" /* MaskExpression.EMPTY_STRING */) !== -1 && this.showMaskTyped && !this.prefix) { newInputValue = this._currentValue; } if (this.deletedSpecialCharacter && position) { if (this.specialCharacters.includes(this.actualValue.slice(position, position + 1))) { // eslint-disable-next-line no-param-reassign position = position + 1; } else if (maskExpression.slice(position - 1, position + 1) !== "M0" /* MaskExpression.MONTHS */) { // eslint-disable-next-line no-param-reassign position = position - 2; } this.delete