Skip to content

Commit 1dea42d

Browse files
committed
refactor(mask): Addressed PR comments
1 parent 87b80c1 commit 1dea42d

File tree

3 files changed

+56
-49
lines changed

3 files changed

+56
-49
lines changed

projects/igniteui-angular/src/lib/directives/mask/mask-parsing.service.ts

Lines changed: 17 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,15 @@ import { Injectable } from '@angular/core';
44
const FLAGS = new Set('aACL09#&?');
55
const REGEX = new Map([
66
['C', /(?!^$)/u], // Non-empty
7-
['&', /[^\p{Separator}]/u], // Whitespace
7+
['&', /[^\p{Separator}]/u], // Non-whitespace
88
['a', /[\p{Letter}\d\p{Separator}]/u], // Alphanumeric & whitespace
99
['A', /[\p{Letter}\d]/u], // Alphanumeric
1010
['?', /[\p{Letter}\p{Separator}]/u], // Alpha & whitespace
1111
['L', /\p{Letter}/u], // Alpha
1212
['0', /\d/], // Numeric
1313
['9', /[\d\p{Separator}]/u], // Numeric & whitespace
1414
['#', /[\d\-+]/], // Numeric and sign
15-
]);
15+
]);
1616

1717
/** @hidden */
1818
export interface MaskOptions {
@@ -40,17 +40,17 @@ export function parseMask(format: string): ParsedMask {
4040
let mask = format;
4141

4242
for (let i = 0, j = 0; i < format.length; i++, j++) {
43-
const [current, next] = [format.charAt(i), format.charAt(i + 1)];
44-
45-
if (current === '\\' && FLAGS.has(next)) {
46-
mask = replaceCharAt(mask, j, '');
47-
literals.set(j, next);
48-
i++;
49-
} else {
50-
if (!FLAGS.has(current)) {
51-
literals.set(j, current);
43+
const [current, next] = [format.charAt(i), format.charAt(i + 1)];
44+
45+
if (current === '\\' && FLAGS.has(next)) {
46+
mask = replaceCharAt(mask, j, '');
47+
literals.set(j, next);
48+
i++;
49+
} else {
50+
if (!FLAGS.has(current)) {
51+
literals.set(j, current);
52+
}
5253
}
53-
}
5454
}
5555

5656
return { literals, mask };
@@ -62,7 +62,6 @@ export function parseMask(format: string): ParsedMask {
6262
})
6363
export class MaskParsingService {
6464

65-
6665
public applyMask(inputVal: string, maskOptions: MaskOptions, pos: number = 0): string {
6766
let outputVal = '';
6867
let value = '';
@@ -80,7 +79,7 @@ export class MaskParsingService {
8079
}
8180

8281
literals.forEach((val: string, key: number) => {
83-
outputVal = this.replaceCharAt(outputVal, key, val);
82+
outputVal = replaceCharAt(outputVal, key, val);
8483
});
8584

8685
if (!value) {
@@ -104,16 +103,15 @@ export class MaskParsingService {
104103

105104
for (const nonLiteralValue of nonLiteralValues) {
106105
const char = nonLiteralValue;
107-
outputVal = this.replaceCharAt(outputVal, nonLiteralIndices[pos++], char);
106+
outputVal = replaceCharAt(outputVal, nonLiteralIndices[pos++], char);
108107
}
109108

110109
return outputVal;
111110
}
112111

113112
public parseValueFromMask(maskedValue: string, maskOptions: MaskOptions): string {
114113
let outputVal = '';
115-
const literals: Map<number, string> = this.getMaskLiterals(maskOptions.format);
116-
const literalValues: string[] = Array.from(literals.values());
114+
const literalValues: string[] = Array.from(parseMask(maskOptions.format).literals.values());
117115

118116
for (const val of maskedValue) {
119117
if (literalValues.indexOf(val) === -1) {
@@ -154,7 +152,7 @@ export class MaskParsingService {
154152
cursor = i + 1;
155153
char = chars.shift();
156154
}
157-
maskedValue = this.replaceCharAt(maskedValue, i, char);
155+
maskedValue = replaceCharAt(maskedValue, i, char);
158156
}
159157

160158
if (value.length <= 1) {
@@ -174,18 +172,7 @@ export class MaskParsingService {
174172
}
175173
}
176174

177-
return { value: maskedValue, end: cursor};
178-
}
179-
180-
public replaceCharAt(strValue: string, index: number, char: string): string {
181-
if (strValue !== undefined) {
182-
return strValue.substring(0, index) + char + strValue.substring(index + 1);
183-
}
184-
}
185-
186-
public getMaskLiterals(mask: string): Map<number, string> {
187-
return parseMask(mask).literals;
188-
175+
return { value: maskedValue, end: cursor };
189176
}
190177

191178
/** Validates only non literal positions. */

projects/igniteui-angular/src/lib/directives/mask/mask.directive.spec.ts

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,15 +63,35 @@ describe('igxMask', () => {
6363
fixture.detectChanges();
6464

6565
const { input, maskDirective } = fixture.componentInstance;
66-
;
66+
6767
maskDirective.mask = '+\\9 000 000';
6868
fixture.detectChanges();
6969

7070
input.nativeElement.dispatchEvent(new Event('focus'));
7171
fixture.detectChanges();
7272

7373
expect(input.nativeElement.value).toEqual('+9 ___ ___');
74-
})
74+
});
75+
76+
it('Escaped mask - advanced escaped patterns with input', () => {
77+
const fixture = TestBed.createComponent(DefMaskComponent);
78+
fixture.detectChanges();
79+
80+
const { input, maskDirective } = fixture.componentInstance;
81+
maskDirective.mask = '\\C\\C CCCC - \\0\\00 - X\\9\\9';
82+
fixture.detectChanges();
83+
84+
input.nativeElement.dispatchEvent(new Event('focus'));
85+
fixture.detectChanges();
86+
87+
expect(input.nativeElement.value).toEqual('CC ____ - 00_ - X99');
88+
89+
input.nativeElement.value = 'abcdefgh';
90+
input.nativeElement.dispatchEvent(new Event('input'));
91+
fixture.detectChanges();
92+
93+
expect(input.nativeElement.value).toEqual('CC abcd - 00_ - X99');
94+
});
7595

7696
it('Mask rules - digit (0-9) or a space', fakeAsync(() => {
7797
const fixture = TestBed.createComponent(DigitSpaceMaskComponent);

projects/igniteui-angular/src/lib/directives/mask/mask.directive.ts

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -212,27 +212,27 @@ export class IgxMaskDirective implements OnInit, AfterViewChecked, ControlValueA
212212
// After the compositionend event Chromium triggers input events of type 'deleteContentBackward' and
213213
// we need to adjust the start and end indexes to include mask literals
214214
if (event.inputType === 'deleteContentBackward' && this._key !== this.platform.KEYMAP.BACKSPACE) {
215-
const isInputComplete = this._compositionStartIndex === 0 && this._end === this.mask.length;
216-
let numberOfMaskLiterals = 0;
217-
const literalPos = this.maskParser.getMaskLiterals(this.maskOptions.format).keys();
218-
for (const index of literalPos) {
219-
if (index >= this._compositionStartIndex && index <= this._end) {
220-
numberOfMaskLiterals++;
221-
}
215+
const isInputComplete = this._compositionStartIndex === 0 && this._end === this.mask.length;
216+
let numberOfMaskLiterals = 0;
217+
const literalPos = parseMask(this.maskOptions.format).literals.keys();
218+
for (const index of literalPos) {
219+
if (index >= this._compositionStartIndex && index <= this._end) {
220+
numberOfMaskLiterals++;
222221
}
223-
this.inputValue = isInputComplete ?
222+
}
223+
this.inputValue = isInputComplete ?
224224
this.inputValue.substring(0, this.selectionEnd - numberOfMaskLiterals) + this.inputValue.substring(this.selectionEnd)
225225
: this._compositionValue?.substring(0, this._compositionStartIndex) || this.inputValue;
226226

227-
if (this._compositionValue) {
228-
this._start = this.selectionStart;
229-
this._end = this.selectionEnd;
230-
this.nativeElement.selectionStart = isInputComplete ? this._start - numberOfMaskLiterals : this._compositionStartIndex;
231-
this.nativeElement.selectionEnd = this._end - numberOfMaskLiterals;
232-
this.nativeElement.selectionEnd = this._end;
233-
this._start = this.selectionStart;
234-
this._end = this.selectionEnd;
235-
}
227+
if (this._compositionValue) {
228+
this._start = this.selectionStart;
229+
this._end = this.selectionEnd;
230+
this.nativeElement.selectionStart = isInputComplete ? this._start - numberOfMaskLiterals : this._compositionStartIndex;
231+
this.nativeElement.selectionEnd = this._end - numberOfMaskLiterals;
232+
this.nativeElement.selectionEnd = this._end;
233+
this._start = this.selectionStart;
234+
this._end = this.selectionEnd;
235+
}
236236
}
237237

238238
if (this._hasDropAction) {

0 commit comments

Comments
 (0)