Skip to content

Commit

Permalink
work for #4842
Browse files Browse the repository at this point in the history
  • Loading branch information
OlgaLarina committed Dec 1, 2023
1 parent 1dabc93 commit 5d019a0
Show file tree
Hide file tree
Showing 8 changed files with 274 additions and 115 deletions.
20 changes: 13 additions & 7 deletions src/mask/mask.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,26 @@
import { processValueWithPattern, getMaskedValueByPattern, getUnmaskedValueByPattern } from "./mask_utils";
import { IMaskedValue } from "./mask_utils";

export class InputMaskBase {
private _prevSelectionStart: number;
constructor(private input: HTMLInputElement, private mask: string) {
protected _prevSelectionStart: number;
constructor(protected input: HTMLInputElement, protected mask: any) {
this.applyValue(mask);
this.addInputEventListener();
}

applyValue(mask: string) {
protected getMaskedValue(mask: any, option?: any): string {
return this.input.value;
}
protected processMaskedValue(mask: any, option?: any): IMaskedValue {
return { text: this.input.value, cursorPosition: this.input.selectionStart };
}
applyValue(mask: any) {
if(!!this.input) {
this.input.value = getMaskedValueByPattern(getUnmaskedValueByPattern(this.input.value, mask, false), mask);
this.input.value = this.getMaskedValue(mask);
}
}
updateMaskedString(mask: string): void {
protected updateMaskedString(mask: any): void {
if(!!this.input) {
const result = processValueWithPattern(this.input.value, mask, this._prevSelectionStart, this.input.selectionStart);
const result = this.processMaskedValue(mask);
this.input.value = result.text;
this.input.setSelectionRange(result.cursorPosition, result.cursorPosition);
}
Expand Down
86 changes: 86 additions & 0 deletions src/mask/mask_pattern.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import { InputMaskBase } from "./mask";
import { IMaskedValue, settings, syntacticAnalysisMask } from "./mask_utils";

export function getMaskedValueByPattern(str: string, pattern: string, matchWholeMask = true): string {
let result = "";
let strIndex = 0;

const parsedMask = syntacticAnalysisMask(pattern);
for(let maskIndex = 0; maskIndex < parsedMask.length; maskIndex++) {
if(parsedMask[maskIndex].type === "regex") {
const currentDefinition = settings.definitions[parsedMask[maskIndex].value];
if(strIndex < str.length && str[strIndex].match(currentDefinition)) {
result += str[strIndex];
} else if(matchWholeMask) {
result += settings.placeholderChar;
} else {
break;
}
strIndex++;
} else if(parsedMask[maskIndex].type === "const") {
result += parsedMask[maskIndex].value;
if(parsedMask[maskIndex].value === str[strIndex]) {
strIndex++;
}
}
}
return result;
}

export function getUnmaskedValueByPattern(str: string, pattern: string, matchWholeMask: boolean): string {
let result = "";
if(!str) return result;

const parsedMask = syntacticAnalysisMask(pattern);
for(let index = 0; index < parsedMask.length; index++) {
if(parsedMask[index].type === "regex") {
const currentDefinition = settings.definitions[parsedMask[index].value];
if(!!str[index] && str[index].match(currentDefinition)) {
result += str[index];
} else if(matchWholeMask) {
result = "";
break;
} else {
break;
}
}
}
return result;
}

export function processValueWithPattern(str: string, pattern: string, prevСursorPosition: number, currentCursorPosition: number): IMaskedValue {
let result = "";
if(!str) return <IMaskedValue>{ text: result, cursorPosition: currentCursorPosition };
let leftPartResult = "";
let rigthPartResult = "";
let centerPart = "";
let newCursorPosition = currentCursorPosition;

const leftPartRange = Math.min(prevСursorPosition, currentCursorPosition, pattern.length - 1);
leftPartResult = getUnmaskedValueByPattern(str.substring(0, leftPartRange), pattern.substring(0, leftPartRange), false);
rigthPartResult = getUnmaskedValueByPattern(str.substring(currentCursorPosition), pattern.substring(prevСursorPosition), false);
if(currentCursorPosition > prevСursorPosition) {
centerPart = getUnmaskedValueByPattern(str.substring(leftPartRange, currentCursorPosition), pattern.substring(leftPartRange), false);
newCursorPosition = getMaskedValueByPattern(leftPartResult + centerPart, pattern, false).length;

}
result = getMaskedValueByPattern(leftPartResult + centerPart + rigthPartResult, pattern);
return <IMaskedValue>{ text: result, cursorPosition: newCursorPosition };
}

export class InputMaskPattern extends InputMaskBase {
protected getMaskedValue(mask: string, option?: any): string {
return getMaskedValueByPattern(getUnmaskedValueByPattern(this.input.value, mask, false), mask);
}
protected processMaskedValue(mask: string): IMaskedValue {
return processValueWithPattern(this.input.value, mask, this._prevSelectionStart, this.input.selectionStart);
}

protected updateMaskedString(mask: string, option?: any): void {
if(!!this.input) {
const result = this.processMaskedValue(mask);
this.input.value = result.text;
this.input.setSelectionRange(result.cursorPosition, result.cursorPosition);
}
}
}
157 changes: 51 additions & 106 deletions src/mask/mask_utils.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
interface IMaskedValue {
export interface IMaskedValue {
text: string;
cursorPosition: number;
}

export var settings = {
placeholderChar: "_",
escapedChar: "\\",
numberOptions: {
decimal: ".",
thousands: ",",
precision: 2,
allowNegative: true,
align: "right"
},
definitions: <{ [key: string]: RegExp }>{
"9": /[0-9]/,
"a": /[a-zA-Z]/,
Expand All @@ -15,12 +22,14 @@ export var settings = {

interface IMaskLiteral {
type: "const" | "regex";
repeat?: boolean;
value: any;
}

export function syntacticAnalysisMask(mask: string): Array<IMaskLiteral> {
const result: Array<IMaskLiteral> = [];
let prevChartIsEscaped = false;
let prevChart;
const definitionsKeys = Object.keys(settings.definitions);

for(let index = 0; index < mask.length; index++) {
Expand All @@ -30,118 +39,54 @@ export function syntacticAnalysisMask(mask: string): Array<IMaskLiteral> {
} else if(prevChartIsEscaped) {
prevChartIsEscaped = false;
result.push({ type: "const", value: currentChar });
} else if(currentChar === "+") {
result[result.length - 1].repeat = true;
} else {
result.push({ type: definitionsKeys.indexOf(currentChar) !== -1 ? "regex" : "const", value: currentChar });
}
prevChart = currentChar;
}

return result;
}

export function getMaskedValueByPatternOld(str: string, pattern: string, matchWholeMask = true): string {
let result = "";
let strIndex = 0;
for(let maskIndex = 0; maskIndex < pattern.length; maskIndex++) {
const currentDefinition = settings.definitions[pattern[maskIndex]];
if(currentDefinition) {
if(strIndex < str.length && str[strIndex].match(currentDefinition)) {
result += str[strIndex];
} else if(matchWholeMask) {
result += settings.placeholderChar;
} else {
break;
}
strIndex++;
} else {
result += pattern[maskIndex];
}
}
return result;
}
// export function getMaskedValueByPatternOld(str: string, pattern: string, matchWholeMask = true): string {
// let result = "";
// let strIndex = 0;
// for(let maskIndex = 0; maskIndex < pattern.length; maskIndex++) {
// const currentDefinition = settings.definitions[pattern[maskIndex]];
// if(currentDefinition) {
// if(strIndex < str.length && str[strIndex].match(currentDefinition)) {
// result += str[strIndex];
// } else if(matchWholeMask) {
// result += settings.placeholderChar;
// } else {
// break;
// }
// strIndex++;
// } else {
// result += pattern[maskIndex];
// }
// }
// return result;
// }

export function getMaskedValueByPattern(str: string, pattern: string, matchWholeMask = true): string {
let result = "";
let strIndex = 0;
// export function getUnmaskedValueByPatternOld(str: string, pattern: string, matchWholeMask: boolean): string {
// let result = "";
// if(!str) return result;

const parsedMask = syntacticAnalysisMask(pattern);
for(let maskIndex = 0; maskIndex < parsedMask.length; maskIndex++) {
if(parsedMask[maskIndex].type === "regex") {
const currentDefinition = settings.definitions[parsedMask[maskIndex].value];
if(strIndex < str.length && str[strIndex].match(currentDefinition)) {
result += str[strIndex];
} else if(matchWholeMask) {
result += settings.placeholderChar;
} else {
break;
}
strIndex++;
} else if(parsedMask[maskIndex].type === "const") {
result += parsedMask[maskIndex].value;
if(parsedMask[maskIndex].value === str[strIndex]) {
strIndex++;
}
}
}
return result;
}

export function getUnmaskedValueByPattern(str: string, pattern: string, matchWholeMask: boolean): string {
let result = "";
if(!str) return result;

const parsedMask = syntacticAnalysisMask(pattern);
for(let index = 0; index < parsedMask.length; index++) {
if(parsedMask[index].type === "regex") {
const currentDefinition = settings.definitions[parsedMask[index].value];
if(!!str[index] && str[index].match(currentDefinition)) {
result += str[index];
} else if(matchWholeMask) {
result = "";
break;
} else {
break;
}
}
}
return result;
}

export function getUnmaskedValueByPatternOld(str: string, pattern: string, matchWholeMask: boolean): string {
let result = "";
if(!str) return result;

for(let index = 0; index < pattern.length; index++) {
const currentDefinition = settings.definitions[pattern[index]];
if(currentDefinition) {
if(!!str[index] && str[index].match(currentDefinition)) {
result += str[index];
} else if(matchWholeMask) {
result = "";
break;
} else {
break;
}
}
}
return result;
}

export function processValueWithPattern(str: string, pattern: string, prevСursorPosition: number, currentCursorPosition: number): IMaskedValue {
let result = "";
if(!str) return <IMaskedValue>{ text: result, cursorPosition: currentCursorPosition };
let leftPartResult = "";
let rigthPartResult = "";
let centerPart = "";
let newCursorPosition = currentCursorPosition;

const leftPartRange = Math.min(prevСursorPosition, currentCursorPosition, pattern.length - 1);
leftPartResult = getUnmaskedValueByPattern(str.substring(0, leftPartRange), pattern.substring(0, leftPartRange), false);
rigthPartResult = getUnmaskedValueByPattern(str.substring(currentCursorPosition), pattern.substring(prevСursorPosition), false);
if(currentCursorPosition > prevСursorPosition) {
centerPart = getUnmaskedValueByPattern(str.substring(leftPartRange, currentCursorPosition), pattern.substring(leftPartRange), false);
newCursorPosition = getMaskedValueByPattern(leftPartResult + centerPart, pattern, false).length;

}
result = getMaskedValueByPattern(leftPartResult + centerPart + rigthPartResult, pattern);
return <IMaskedValue>{ text: result, cursorPosition: newCursorPosition };
}
// for(let index = 0; index < pattern.length; index++) {
// const currentDefinition = settings.definitions[pattern[index]];
// if(currentDefinition) {
// if(!!str[index] && str[index].match(currentDefinition)) {
// result += str[index];
// } else if(matchWholeMask) {
// result = "";
// break;
// } else {
// break;
// }
// }
// }
// return result;
// }
68 changes: 68 additions & 0 deletions src/mask/number_mask.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import { InputMaskBase } from "./mask";
import { IMaskedValue, settings, syntacticAnalysisMask } from "./mask_utils";

interface INumberMaskOption {
mask?: string;
align?: "left" | "right";
allowNegative?: boolean;
decimal?: string;
precision?: number;
thousands?: string;
}
interface INumericalСomposition {
integralPart: number;
fractionalPart?: number;
}

export function parseNumber(str: any): INumericalСomposition {
const result: INumericalСomposition = { integralPart: 0, fractionalPart: 0 };
const input = str.toString();

const parts = input.trim().split(".");
if(parts.length >= 2) {
result.integralPart = parseInt(parts[0].trim());
result.fractionalPart = parseInt(parts[1].trim());
} else if(parts.length == 1) {
result.integralPart = parseInt(parts[0].trim());
} else {
result.integralPart = parseInt(input.trim());
}

return result;
}

export function getNumberMaskedValue(str: string | number, mask: string, option?: INumberMaskOption) {
const decimalSeparator = option?.decimal || settings.numberOptions.decimal;
const parsedMask = syntacticAnalysisMask(mask);

const input = str.toString();
const parsedNumber = parseNumber(input);

let result = "";
let maskIndex = 0;

for(let index = 0; index < parsedNumber.integralPart.toString().length; index++) {

}
return result;
}

export function getNumberUnmaskedValue(str: string, mask: string, option?: INumberMaskOption) {
return str;
}

export class InputMaskNumber extends InputMaskBase {

constructor(input: HTMLInputElement, mask?: INumberMaskOption) {
super(input, mask);
}

protected getMaskedValue(mask: string, option: INumberMaskOption): string {
return getNumberMaskedValue(getNumberUnmaskedValue(this.input.value, mask, option), mask, option);
}

protected processMaskedValue(mask: string): IMaskedValue {
// return processValueWithPattern(this.input.value, mask, this._prevSelectionStart, this.input.selectionStart);
return { text: this.input.value, cursorPosition: this.input.selectionStart };
}
}
Loading

0 comments on commit 5d019a0

Please sign in to comment.