UNPKG

ngx-mask

Version:
1,021 lines (1,017 loc) 123 kB
import * as i0 from '@angular/core'; import { InjectionToken, EventEmitter, inject, Injectable, ElementRef, Renderer2, makeEnvironmentProviders, input, output, signal, Directive, HostListener, Pipe } from '@angular/core'; import { DOCUMENT } from '@angular/common'; import { NG_VALUE_ACCESSOR, NG_VALIDATORS } from '@angular/forms'; var MaskExpression; (function (MaskExpression) { MaskExpression["SEPARATOR"] = "separator"; MaskExpression["PERCENT"] = "percent"; MaskExpression["IP"] = "IP"; MaskExpression["CPF_CNPJ"] = "CPF_CNPJ"; MaskExpression["MONTH"] = "M"; MaskExpression["MONTHS"] = "M0"; MaskExpression["MINUTE"] = "m"; MaskExpression["HOUR"] = "h"; MaskExpression["HOURS"] = "H"; MaskExpression["MINUTES"] = "m0"; MaskExpression["HOURS_HOUR"] = "Hh"; MaskExpression["SECONDS"] = "s0"; MaskExpression["HOURS_MINUTES_SECONDS"] = "Hh:m0:s0"; MaskExpression["EMAIL_MASK"] = "A*@A*.A*"; MaskExpression["HOURS_MINUTES"] = "Hh:m0"; MaskExpression["MINUTES_SECONDS"] = "m0:s0"; MaskExpression["DAYS_MONTHS_YEARS"] = "d0/M0/0000"; MaskExpression["DAYS_MONTHS"] = "d0/M0"; MaskExpression["DAYS"] = "d0"; MaskExpression["DAY"] = "d"; MaskExpression["SECOND"] = "s"; MaskExpression["LETTER_S"] = "S"; MaskExpression["DOT"] = "."; MaskExpression["COMMA"] = ","; MaskExpression["CURLY_BRACKETS_LEFT"] = "{"; MaskExpression["CURLY_BRACKETS_RIGHT"] = "}"; MaskExpression["MINUS"] = "-"; MaskExpression["OR"] = "||"; MaskExpression["HASH"] = "#"; MaskExpression["EMPTY_STRING"] = ""; MaskExpression["SYMBOL_STAR"] = "*"; MaskExpression["SYMBOL_QUESTION"] = "?"; MaskExpression["SLASH"] = "/"; MaskExpression["WHITE_SPACE"] = " "; MaskExpression["NUMBER_ZERO"] = "0"; MaskExpression["NUMBER_NINE"] = "9"; MaskExpression["BACKSPACE"] = "Backspace"; MaskExpression["DELETE"] = "Delete"; MaskExpression["ARROW_LEFT"] = "ArrowLeft"; MaskExpression["ARROW_UP"] = "ArrowUp"; MaskExpression["DOUBLE_ZERO"] = "00"; })(MaskExpression || (MaskExpression = {})); 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, showMaskTyped: false, instantPrefix: false, placeHolderCharacter: '_', dropSpecialCharacters: true, hiddenInput: false, shownMaskExpression: '', separatorLimit: '', allowNegativeNumbers: false, validation: true, 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 = [ MaskExpression.HOURS_MINUTES_SECONDS, MaskExpression.HOURS_MINUTES, MaskExpression.MINUTES_SECONDS, ]; const withoutValidation = [ MaskExpression.PERCENT, MaskExpression.HOURS_HOUR, MaskExpression.SECONDS, MaskExpression.MINUTES, MaskExpression.SEPARATOR, MaskExpression.DAYS_MONTHS_YEARS, MaskExpression.DAYS_MONTHS, MaskExpression.DAYS, MaskExpression.MONTHS, ]; class NgxMaskApplierService { _config = inject(NGX_MASK_CONFIG); dropSpecialCharacters = this._config.dropSpecialCharacters; hiddenInput = this._config.hiddenInput; clearIfNotMatch = this._config.clearIfNotMatch; specialCharacters = this._config.specialCharacters; patterns = this._config.patterns; prefix = this._config.prefix; suffix = this._config.suffix; thousandSeparator = this._config.thousandSeparator; decimalMarker = this._config.decimalMarker; customPattern; showMaskTyped = this._config.showMaskTyped; placeHolderCharacter = this._config.placeHolderCharacter; validation = this._config.validation; separatorLimit = this._config.separatorLimit; allowNegativeNumbers = this._config.allowNegativeNumbers; leadZeroDateTime = this._config.leadZeroDateTime; leadZero = this._config.leadZero; apm = this._config.apm; inputTransformFn = this._config.inputTransformFn; outputTransformFn = this._config.outputTransformFn; keepCharacterPositions = this._config.keepCharacterPositions; instantPrefix = this._config.instantPrefix; _shift = new Set(); plusOnePosition = false; maskExpression = ''; actualValue = ''; showKeepCharacterExp = ''; shownMaskExpression = ''; deletedSpecialCharacter = false; ipError; cpfCnpjError; applyMask(inputValue, maskExpression, position = 0, justPasted = false, backspaced = false, 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; let processedValue = inputValue; let processedPosition = position; if (processedValue.slice(0, this.prefix.length) === this.prefix) { processedValue = processedValue.slice(this.prefix.length, processedValue.length); } if (!!this.suffix && processedValue.length > 0) { processedValue = this.checkAndRemoveSuffix(processedValue); } if (processedValue === '(' && this.prefix) { processedValue = ''; } const inputArray = processedValue.toString().split(MaskExpression.EMPTY_STRING); if (this.allowNegativeNumbers && processedValue.slice(cursor, cursor + 1) === MaskExpression.MINUS) { result += processedValue.slice(cursor, cursor + 1); } if (maskExpression === MaskExpression.IP) { const valuesIP = processedValue.split(MaskExpression.DOT); this.ipError = this._validIP(valuesIP); maskExpression = '099.099.099.099'; } const arr = []; for (let i = 0; i < processedValue.length; i++) { if (processedValue[i]?.match('\\d')) { arr.push(processedValue[i] ?? MaskExpression.EMPTY_STRING); } } if (maskExpression === MaskExpression.CPF_CNPJ) { this.cpfCnpjError = arr.length !== 11 && arr.length !== 14; if (arr.length > 11) { maskExpression = '00.000.000/0000-00'; } else { maskExpression = '000.000.000-00'; } } if (maskExpression.startsWith(MaskExpression.PERCENT)) { if (processedValue.match('[a-z]|[A-Z]') || (processedValue.match(/[-!$%^&*()_+|~=`{}\[\]:";'<>?,\/.]/) && !backspaced)) { processedValue = this._stripToDecimal(processedValue); const precision = this.getPrecision(maskExpression); processedValue = this.checkInputPrecision(processedValue, precision, this.decimalMarker); } const decimalMarker = typeof this.decimalMarker === 'string' ? this.decimalMarker : MaskExpression.DOT; if (processedValue.indexOf(decimalMarker) > 0 && !this.percentage(processedValue.substring(0, processedValue.indexOf(decimalMarker)))) { let base = processedValue.substring(0, processedValue.indexOf(decimalMarker) - 1); if (this.allowNegativeNumbers && processedValue.slice(cursor, cursor + 1) === MaskExpression.MINUS && !backspaced) { base = processedValue.substring(0, processedValue.indexOf(decimalMarker)); } processedValue = `${base}${processedValue.substring(processedValue.indexOf(decimalMarker), processedValue.length)}`; } let value = ''; this.allowNegativeNumbers && processedValue.slice(cursor, cursor + 1) === MaskExpression.MINUS ? (value = `${MaskExpression.MINUS}${processedValue.slice(cursor + 1, cursor + processedValue.length)}`) : (value = processedValue); if (this.percentage(value)) { result = this._splitPercentZero(processedValue); } else { result = this._splitPercentZero(processedValue.substring(0, processedValue.length - 1)); } } else if (maskExpression.startsWith(MaskExpression.SEPARATOR)) { if (processedValue.match('[wа-яА-Я]') || processedValue.match('[ЁёА-я]') || processedValue.match('[a-z]|[A-Z]') || processedValue.match(/[-@#!$%\\^&*()_£¬'+|~=`{}\]:";<>.?/]/) || processedValue.match('[^A-Za-z0-9,]')) { processedValue = this._stripToDecimal(processedValue); } const precision = this.getPrecision(maskExpression); let decimalMarker = this.decimalMarker; if (Array.isArray(this.decimalMarker)) { if (this.actualValue.includes(this.decimalMarker[0]) || this.actualValue.includes(this.decimalMarker[1])) { decimalMarker = this.actualValue.includes(this.decimalMarker[0]) ? this.decimalMarker[0] : this.decimalMarker[1]; } else { decimalMarker = this.decimalMarker.find((dm) => dm !== this.thousandSeparator); } } if (backspaced) { const { decimalMarkerIndex, nonZeroIndex } = this._findFirstNonZeroAndDecimalIndex(processedValue, decimalMarker); const zeroIndexMinus = processedValue[0] === MaskExpression.MINUS; const zeroIndexNumberZero = processedValue[0] === MaskExpression.NUMBER_ZERO; const zeroIndexDecimalMarker = processedValue[0] === decimalMarker; const firstIndexDecimalMarker = processedValue[1] === decimalMarker; if ((zeroIndexDecimalMarker && !nonZeroIndex) || (zeroIndexMinus && firstIndexDecimalMarker && !nonZeroIndex) || (zeroIndexNumberZero && !decimalMarkerIndex && !nonZeroIndex)) { processedValue = MaskExpression.NUMBER_ZERO; } if (decimalMarkerIndex && nonZeroIndex && zeroIndexMinus && processedPosition === 1) { if (decimalMarkerIndex < nonZeroIndex || decimalMarkerIndex > nonZeroIndex) { processedValue = MaskExpression.MINUS + processedValue.slice(nonZeroIndex); } } if (!decimalMarkerIndex && nonZeroIndex && processedValue.length > nonZeroIndex) { processedValue = zeroIndexMinus ? MaskExpression.MINUS + processedValue.slice(nonZeroIndex) : processedValue.slice(nonZeroIndex); } if (decimalMarkerIndex && nonZeroIndex && processedPosition === 0) { if (decimalMarkerIndex < nonZeroIndex) { processedValue = processedValue.slice(decimalMarkerIndex - 1); } if (decimalMarkerIndex > nonZeroIndex) { processedValue = processedValue.slice(nonZeroIndex); } } } if (precision === 0) { processedValue = this.allowNegativeNumbers ? processedValue.length > 2 && processedValue[0] === MaskExpression.MINUS && processedValue[1] === MaskExpression.NUMBER_ZERO && processedValue[2] !== this.thousandSeparator && processedValue[2] !== MaskExpression.COMMA && processedValue[2] !== MaskExpression.DOT ? '-' + processedValue.slice(2, processedValue.length) : processedValue[0] === MaskExpression.NUMBER_ZERO && processedValue.length > 1 && processedValue[1] !== this.thousandSeparator && processedValue[1] !== MaskExpression.COMMA && processedValue[1] !== MaskExpression.DOT ? processedValue.slice(1, processedValue.length) : processedValue : processedValue.length > 1 && processedValue[0] === MaskExpression.NUMBER_ZERO && processedValue[1] !== this.thousandSeparator && processedValue[1] !== MaskExpression.COMMA && processedValue[1] !== MaskExpression.DOT ? processedValue.slice(1, processedValue.length) : processedValue; } else { if (processedValue[0] === decimalMarker && processedValue.length > 1 && !backspaced) { processedValue = MaskExpression.NUMBER_ZERO + processedValue.slice(0, processedValue.length + 1); this.plusOnePosition = true; } if (processedValue[0] === MaskExpression.NUMBER_ZERO && processedValue[1] !== decimalMarker && processedValue[1] !== this.thousandSeparator && !backspaced) { processedValue = processedValue.length > 1 ? processedValue.slice(0, 1) + decimalMarker + processedValue.slice(1, processedValue.length + 1) : processedValue; this.plusOnePosition = true; } if (this.allowNegativeNumbers && !backspaced && processedValue[0] === MaskExpression.MINUS && (processedValue[1] === decimalMarker || processedValue[1] === MaskExpression.NUMBER_ZERO)) { processedValue = processedValue[1] === decimalMarker && processedValue.length > 2 ? processedValue.slice(0, 1) + MaskExpression.NUMBER_ZERO + processedValue.slice(1, processedValue.length) : processedValue[1] === MaskExpression.NUMBER_ZERO && processedValue.length > 2 && processedValue[2] !== decimalMarker ? processedValue.slice(0, 2) + decimalMarker + processedValue.slice(2, processedValue.length) : processedValue; this.plusOnePosition = true; } } const thousandSeparatorCharEscaped = this._charToRegExpExpression(this.thousandSeparator); let invalidChars = '@#!$%^&*()_+|~=`{}\\[\\]:\\s,\\.";<>?\\/'.replace(thousandSeparatorCharEscaped, ''); 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 (processedValue.match(invalidCharRegexp)) { processedValue = processedValue.substring(0, processedValue.length - 1); } processedValue = this.checkInputPrecision(processedValue, precision, this.decimalMarker); const strForSep = processedValue.replace(new RegExp(thousandSeparatorCharEscaped, 'g'), ''); result = this._formatWithSeparators(strForSep, this.thousandSeparator, this.decimalMarker, precision); const commaShift = result.indexOf(MaskExpression.COMMA) - processedValue.indexOf(MaskExpression.COMMA); const shiftStep = result.length - processedValue.length; const backspacedDecimalMarkerWithSeparatorLimit = backspaced && result.length < inputValue.length && this.separatorLimit; if ((result[processedPosition - 1] === this.thousandSeparator || result[processedPosition - this.prefix.length]) && this.prefix && backspaced) { processedPosition = processedPosition - 1; } else if ((shiftStep > 0 && result[processedPosition] !== this.thousandSeparator) || backspacedDecimalMarkerWithSeparatorLimit) { backspaceShift = true; let _shift = 0; do { this._shift.add(processedPosition + _shift); _shift++; } while (_shift < shiftStep); } else if (result[processedPosition - 1] === this.thousandSeparator || shiftStep === -4 || shiftStep === -3 || result[processedPosition] === this.thousandSeparator) { this._shift.clear(); this._shift.add(processedPosition - 1); } else if ((commaShift !== 0 && processedPosition > 0 && !(result.indexOf(MaskExpression.COMMA) >= processedPosition && processedPosition > 3)) || (!(result.indexOf(MaskExpression.DOT) >= processedPosition && processedPosition > 3) && shiftStep <= 0)) { this._shift.clear(); backspaceShift = true; shift = shiftStep; processedPosition += shiftStep; this._shift.add(processedPosition); } 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] === MaskExpression.HOURS) { if (this.apm ? Number(inputSymbol) > 9 : Number(inputSymbol) > 2) { processedPosition = !this.leadZeroDateTime ? processedPosition + 1 : processedPosition; cursor += 1; this._shiftStep(cursor); i--; if (this.leadZeroDateTime) { result += '0'; } continue; } } if (maskExpression[cursor] === MaskExpression.HOUR) { if (this.apm ? (result.length === 1 && Number(result) > 1) || (result === '1' && Number(inputSymbol) > 2) || (processedValue.slice(cursor - 1, cursor).length === 1 && Number(processedValue.slice(cursor - 1, cursor)) > 2) || (processedValue.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)) { processedPosition = processedPosition + 1; cursor += 1; i--; continue; } } if (maskExpression[cursor] === MaskExpression.MINUTE || maskExpression[cursor] === MaskExpression.SECOND) { if (Number(inputSymbol) > 5) { processedPosition = !this.leadZeroDateTime ? processedPosition + 1 : processedPosition; cursor += 1; this._shiftStep(cursor); i--; if (this.leadZeroDateTime) { result += '0'; } continue; } } const daysCount = 31; const inputValueCursor = processedValue[cursor]; const inputValueCursorPlusOne = processedValue[cursor + 1]; const inputValueCursorPlusTwo = processedValue[cursor + 2]; const inputValueCursorMinusOne = processedValue[cursor - 1]; const inputValueCursorMinusTwo = processedValue[cursor - 2]; const inputValueSliceMinusThreeMinusOne = processedValue.slice(cursor - 3, cursor - 1); const inputValueSliceMinusOnePlusOne = processedValue.slice(cursor - 1, cursor + 1); const inputValueSliceCursorPlusTwo = processedValue.slice(cursor, cursor + 2); const inputValueSliceMinusTwoCursor = processedValue.slice(cursor - 2, cursor); if (maskExpression[cursor] === MaskExpression.DAY) { const maskStartWithMonth = maskExpression.slice(0, 2) === MaskExpression.MONTHS; const startWithMonthInput = maskExpression.slice(0, 2) === 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) && !backspaced))) { processedPosition = !this.leadZeroDateTime ? processedPosition + 1 : processedPosition; cursor += 1; this._shiftStep(cursor); i--; if (this.leadZeroDateTime) { result += '0'; } continue; } } if (maskExpression[cursor] === MaskExpression.MONTH) { const monthsCount = 12; const withoutDays = cursor === 0 && (Number(inputSymbol) > 2 || Number(inputValueSliceCursorPlusTwo) > monthsCount || (this.specialCharacters.includes(inputValueCursorPlusOne) && !backspaced)); 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)); const day2monthInput = Number(inputValueSliceMinusThreeMinusOne) <= daysCount && !this.specialCharacters.includes(inputValueSliceMinusThreeMinusOne) && this.specialCharacters.includes(inputValueCursorMinusOne) && (Number(inputValueSliceCursorPlusTwo) > monthsCount || this.specialCharacters.includes(inputValueCursorPlusOne)); const day2monthInputDot = (Number(inputValueSliceCursorPlusTwo) > monthsCount && cursor === 5) || (this.specialCharacters.includes(inputValueCursorPlusOne) && cursor === 5); const day1monthPaste = Number(inputValueSliceMinusThreeMinusOne) > daysCount && !this.specialCharacters.includes(inputValueSliceMinusThreeMinusOne) && !this.specialCharacters.includes(inputValueSliceMinusTwoCursor) && Number(inputValueSliceMinusTwoCursor) > monthsCount && maskExpression.includes('d0'); 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)) { processedPosition = !this.leadZeroDateTime ? processedPosition + 1 : processedPosition; cursor += 1; this._shiftStep(cursor); 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(cursor); i--; } else if (maskExpression[cursor] === MaskExpression.NUMBER_NINE && this.showMaskTyped) { this._shiftStep(cursor); } 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(MaskExpression.NUMBER_NINE + MaskExpression.SYMBOL_STAR) && maskExpression.includes(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[processedPosition - 1] && result.length + 1 === maskExpression.length && this.specialCharacters.indexOf(maskExpression[maskExpression.length - 1] ?? MaskExpression.EMPTY_STRING) !== -1) { result += maskExpression[maskExpression.length - 1]; } let newPosition = processedPosition + 1; while (this._shift.has(newPosition)) { shift++; newPosition++; } let actualShift = justPasted && !maskExpression.startsWith(MaskExpression.SEPARATOR) ? cursor : this._shift.has(processedPosition) ? 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.instantPrefix ? `${this.prefix}${result}` : `${result}`; } const isSpecialCharacterMaskFirstSymbol = processedValue.length === 1 && this.specialCharacters.includes(maskExpression[0]) && processedValue !== maskExpression[0]; if (!this._checkSymbolMask(processedValue, 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); } _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 (typeof precision === 'undefined') { return res + decimals; } else if (precision === 0) { return res; } return res + decimals.substring(0, precision + 1); }; 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; }; getPrecision = (maskExpression) => { const x = maskExpression.split(MaskExpression.DOT); if (x.length > 1) { return Number(x[x.length - 1]); } return Infinity; }; 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; }; checkInputPrecision = (inputValue, precision, decimalMarker) => { let processedInputValue = inputValue; let processedDecimalMarker = decimalMarker; if (precision < Infinity) { if (Array.isArray(processedDecimalMarker)) { const marker = processedDecimalMarker.find((dm) => dm !== this.thousandSeparator); processedDecimalMarker = marker ? marker : processedDecimalMarker[0]; } const precisionRegEx = new RegExp(this._charToRegExpExpression(processedDecimalMarker) + `\\d{${precision}}.*$`); const precisionMatch = processedInputValue.match(precisionRegEx); const precisionMatchLength = (precisionMatch && precisionMatch[0]?.length) ?? 0; if (precisionMatchLength - 1 > precision) { const diff = precisionMatchLength - 1 - precision; processedInputValue = processedInputValue.substring(0, processedInputValue.length - diff); } if (precision === 0 && this._compareOrIncludes(processedInputValue[processedInputValue.length - 1], processedDecimalMarker, this.thousandSeparator)) { processedInputValue = processedInputValue.substring(0, processedInputValue.length - 1); } } return processedInputValue; }; _stripToDecimal(str) { return str .split(MaskExpression.EMPTY_STRING) .filter((i, idx) => { const isDecimalMarker = typeof this.decimalMarker === 'string' ? i === this.decimalMarker : 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 (char) { const charsToEscape = '[\\^$.|?*+()'; return char === ' ' ? '\\s' : charsToEscape.indexOf(char) >= 0 ? `\\${char}` : char; } return char; } _shiftStep(cursor) { this._shift.add(cursor + 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}`; } } _findFirstNonZeroAndDecimalIndex(inputString, decimalMarker) { let decimalMarkerIndex = null; let nonZeroIndex = null; for (let i = 0; i < inputString.length; i++) { const char = inputString[i]; if (char === decimalMarker && decimalMarkerIndex === null) { decimalMarkerIndex = i; } if (char && char >= '1' && char <= '9' && nonZeroIndex === null) { nonZeroIndex = i; } if (decimalMarkerIndex !== null && nonZeroIndex !== null) { break; } } return { decimalMarkerIndex, nonZeroIndex, }; } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.4", ngImport: i0, type: NgxMaskApplierService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.0.4", ngImport: i0, type: NgxMaskApplierService }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.4", ngImport: i0, type: NgxMaskApplierService, decorators: [{ type: Injectable }] }); class NgxMaskService extends NgxMaskApplierService { isNumberValue = false; maskIsShown = ''; selStart = null; selEnd = null; maskChanged = false; maskExpressionArray = []; triggerOnMaskChange = false; previousValue = ''; currentValue = ''; writingValue = false; _emitValue = false; _start; _end; onChange = (_) => { }; _elementRef = inject(ElementRef, { optional: true }); document = inject(DOCUMENT); _config = inject(NGX_MASK_CONFIG); _renderer = inject(Renderer2, { optional: true }); applyMask(inputValue, maskExpression, position = 0, justPasted = false, backspaced = false, cb = () => { }) { if (!maskExpression) { return inputValue !== this.actualValue ? this.actualValue : inputValue; } this.maskIsShown = this.showMaskTyped ? this.showMaskInInput() : MaskExpression.EMPTY_STRING; if (this.maskExpression === MaskExpression.IP && this.showMaskTyped) { this.maskIsShown = this.showMaskInInput(inputValue || MaskExpression.HASH); } if (this.maskExpression === 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 = ''; let newPosition = position; if ((this.hiddenInput || (inputValue && inputValue.indexOf(MaskExpression.SYMBOL_STAR) >= 0)) && !this.writingValue) { let actualResult = inputValue && inputValue.length === 1 ? inputValue.split(MaskExpression.EMPTY_STRING) : this.actualValue.split(MaskExpression.EMPTY_STRING); if (backspaced) { actualResult = actualResult .slice(0, position) .concat(actualResult.slice(position + 1)); } if (this.showMaskTyped) { inputValue = this.removeMask(inputValue); actualResult = this.removeMask(actualResult.join('')).split(MaskExpression.EMPTY_STRING); } if (typeof this.selStart === 'object' && typeof this.selEnd === 'object') { this.selStart = Number(this.selStart); this.selEnd = Number(this.selEnd); } else { if (inputValue !== MaskExpression.EMPTY_STRING && actualResult.length) { if (typeof this.selStart === 'number' && typeof this.selEnd === 'number') { if (inputValue.length > actualResult.length) { actualResult.splice(this.selStart, 0, getSymbol); } else if (inputValue.length < actualResult.length) { if (actualResult.length - inputValue.length === 1) { if (backspaced) { actualResult.splice(this.selStart - 1, 1); } else { actualResult.splice(inputValue.length - 1, 1); } } else { actualResult.splice(this.selStart, this.selEnd - this.selStart); } } } } else { actualResult = []; } } if (this.showMaskTyped && !this.hiddenInput) { newInputValue = this.removeMask(inputValue); } if (this.actualValue.length) { if (actualResult.length < inputValue.length) { newInputValue = this.shiftTypedSymbols(actualResult.join(MaskExpression.EMPTY_STRING)); } else if (actualResult.length === inputValue.length) { newInputValue = actualResult.join(MaskExpression.EMPTY_STRING); } else { newInputValue = inputValue; } } else { newInputValue = inputValue; } } if (justPasted && (this.hiddenInput || !this.hiddenInput)) { newInputValue = inputValue; } if (backspaced && this.specialCharacters.indexOf(this.maskExpression[newPosition] ?? MaskExpression.EMPTY_STRING) !== -1 && this.showMaskTyped && !this.prefix) { newInputValue = this.currentValue; } if (this.deletedSpecialCharacter && newPosition) { if (this.specialCharacters.includes(this.actualValue.slice(newPosition, newPosition + 1))) { newPosition = newPosition + 1; } else if (maskExpression.slice(newPosition - 1, newPosition + 1) !== MaskExpression.MONTHS) { newPosition = newPosition - 2; } this.deletedSpecialCharacter = false; } if (this.showMaskTyped && this.placeHolderCharacter.length === 1 && !this.leadZeroDateTime) { newInputValue = this.removeMask(newInputValue); } if (this.maskChanged) { newInputValue = inputValue; } else { newInputValue = Boolean(newInputValue) && newInputValue.length ? newInputValue : inputValue; } if (this.showMaskTyped && this.keepC