From c050192ce442f6dd63c9815cf2e3d36ace30779d Mon Sep 17 00:00:00 2001 From: Andrii Kamaldinov <129040945+andriikamaldinov1@users.noreply.github.com> Date: Mon, 22 Jul 2024 14:46:17 +0300 Subject: [PATCH] feat(ref: no-ref): fix issue * feat(ref: no-ref): fix issue * feat(ref: no-ref): fix issue * feat(ref: no-ref): fix issue --- CHANGELOG.md | 7 +++ package.json | 2 +- projects/ngx-mask-lib/package.json | 2 +- .../src/lib/ngx-mask.directive.ts | 43 ++++++++++++++++--- .../ngx-mask-lib/src/test/add-prefix.spec.ts | 7 ++- .../ngx-mask-lib/src/test/cursor.cy-spec.ts | 22 ++++------ .../ngx-mask-lib/src/test/delete.cy-spec.ts | 4 +- .../ngx-mask-lib/src/test/dynamic.spec.ts | 36 ++++++++++++++++ 8 files changed, 97 insertions(+), 26 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 801d874b..dbceda1c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +# 17.1.8(2024-07-16) + +### Fix + +- Fix ([#1344](https://github.com/JsDaddy/ngx-mask/issues/1344)) +- Fix ([#1356](https://github.com/JsDaddy/ngx-mask/issues/1356)) + # 17.1.7(2024-07-18) ### Fix diff --git a/package.json b/package.json index ef66e2eb..bf18251d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ngx-mask", - "version": "17.1.7", + "version": "17.1.8", "description": "Awesome ngx mask", "license": "MIT", "engines": { diff --git a/projects/ngx-mask-lib/package.json b/projects/ngx-mask-lib/package.json index c2fcf93a..bf18c93a 100644 --- a/projects/ngx-mask-lib/package.json +++ b/projects/ngx-mask-lib/package.json @@ -1,6 +1,6 @@ { "name": "ngx-mask", - "version": "17.1.7", + "version": "17.1.8", "description": "awesome ngx mask", "keywords": [ "ng2-mask", diff --git a/projects/ngx-mask-lib/src/lib/ngx-mask.directive.ts b/projects/ngx-mask-lib/src/lib/ngx-mask.directive.ts index a03f34d6..0ed6da82 100644 --- a/projects/ngx-mask-lib/src/lib/ngx-mask.directive.ts +++ b/projects/ngx-mask-lib/src/lib/ngx-mask.directive.ts @@ -102,6 +102,8 @@ export class NgxMaskDirective implements ControlValueAccessor, OnChanges, Valida private _maskExpressionArray: string[] = []; + private _allowFewMaskChangeMask: boolean = false; + private _justPasted = false; private _isFocused = false; @@ -615,13 +617,19 @@ export class NgxMaskDirective implements ControlValueAccessor, OnChanges, Valida } // update position after applyValueChanges to prevent cursor on wrong position when it has an array of maskExpression if (this._maskExpressionArray.length) { - const isBackSpaceInSpecialCharactersPosition = - this._code === MaskExpression.BACKSPACE && - this.specialCharacters.includes( - el.value.slice(position, this._maskService.actualValue.length) + if (this._code === MaskExpression.BACKSPACE) { + const specialChartMinusOne = this.specialCharacters.includes( + this._maskService.actualValue.slice(position - 1, position) ); - if (isBackSpaceInSpecialCharactersPosition) { - position = position - 1; + const specialChartPlusOne = this.specialCharacters.includes( + this._maskService.actualValue.slice(position, position + 1) + ); + if (this._allowFewMaskChangeMask && !specialChartPlusOne) { + position = (el.selectionStart as number) + 1; + this._allowFewMaskChangeMask = false; + } else { + position = specialChartMinusOne ? position - 1 : position; + } } else { position = el.selectionStart === 1 @@ -1082,7 +1090,9 @@ export class NgxMaskDirective implements ControlValueAccessor, OnChanges, Valida .some((char) => this._maskService.specialCharacters.includes(char)); if ( - (specialChart && this._inputValue && !mask.includes(MaskExpression.LETTER_S)) || + (specialChart && + this._inputValue && + this._areAllCharactersInEachStringSame(this._maskExpressionArray)) || mask.includes(MaskExpression.CURLY_BRACKETS_LEFT) ) { const test = @@ -1097,6 +1107,10 @@ export class NgxMaskDirective implements ControlValueAccessor, OnChanges, Valida : mask; return test; } else { + if (this._code === MaskExpression.BACKSPACE) { + this._allowFewMaskChangeMask = true; + } + const expression = this._maskExpressionArray[this._maskExpressionArray.length - 1] ?? MaskExpression.EMPTY_STRING; @@ -1123,4 +1137,19 @@ export class NgxMaskDirective implements ControlValueAccessor, OnChanges, Valida } }); } + + private _areAllCharactersInEachStringSame(array: string[]): boolean { + const specialCharacters = this._maskService.specialCharacters; + function removeSpecialCharacters(str: string): string { + const regex = new RegExp(`[${specialCharacters.map((ch) => `\\${ch}`).join('')}]`, 'g'); + return str.replace(regex, ''); + } + + const processedArr = array.map(removeSpecialCharacters); + + return processedArr.every((str) => { + const uniqueCharacters = new Set(str); + return uniqueCharacters.size === 1; + }); + } } diff --git a/projects/ngx-mask-lib/src/test/add-prefix.spec.ts b/projects/ngx-mask-lib/src/test/add-prefix.spec.ts index e99eb10a..618a18e2 100644 --- a/projects/ngx-mask-lib/src/test/add-prefix.spec.ts +++ b/projects/ngx-mask-lib/src/test/add-prefix.spec.ts @@ -138,8 +138,11 @@ describe('Directive: Mask (Add prefix)', () => { component.dropSpecialCharacters = false; component.triggerOnMaskChange = true; component.form.setValue('KZ123123'); - equal('KZ123123', 'KZ123 123', fixture); - requestAnimationFrame(() => { + + fixture.whenStable().then(() => { + fixture.detectChanges(); + + equal('KZ123123', 'KZ123 123', fixture); expect(component.form.value).toBe('123123'); }); }); diff --git a/projects/ngx-mask-lib/src/test/cursor.cy-spec.ts b/projects/ngx-mask-lib/src/test/cursor.cy-spec.ts index 205fd2e7..e08e3be0 100644 --- a/projects/ngx-mask-lib/src/test/cursor.cy-spec.ts +++ b/projects/ngx-mask-lib/src/test/cursor.cy-spec.ts @@ -328,12 +328,11 @@ describe('Test Date Hh:m0', () => { imports: [CypressTestMaskModule], }); + cy.get('#masked').type('111111111111').should('have.value', '+11111111111'); cy.get('#masked') - .type('123 45678901') - - .should('have.value', '+1245678901') .type('{backspace}') - .should('have.prop', 'selectionStart', 13); + .should('have.value', '(111) 111-1111') + .should('have.prop', 'selectionStart', 14); }); it('dynamic mask after backspace should have right cursor position', () => { @@ -345,10 +344,11 @@ describe('Test Date Hh:m0', () => { }); cy.get('#masked') - .type('123 4') + .type('1234567890') - .should('have.value', '(123) 4') - .type('{backspace}'.repeat(2)) + .should('have.value', '(123) 456-7890') + .type('{leftArrow}'.repeat(7)) + .type('{backspace}') .should('have.prop', 'selectionStart', 5); }); @@ -360,11 +360,7 @@ describe('Test Date Hh:m0', () => { imports: [CypressTestMaskModule], }); - cy.get('#masked') - .type('123') - - .should('have.value', '(12) 3') - .type('{backspace}'.repeat(2)) - .should('have.prop', 'selectionStart', 4); + cy.get('#masked').type('111').should('have.value', '(11) 1'); + cy.get('#masked').type('{backspace}').should('have.prop', 'selectionStart', 4); }); }); diff --git a/projects/ngx-mask-lib/src/test/delete.cy-spec.ts b/projects/ngx-mask-lib/src/test/delete.cy-spec.ts index 39d9f168..ecd7e960 100644 --- a/projects/ngx-mask-lib/src/test/delete.cy-spec.ts +++ b/projects/ngx-mask-lib/src/test/delete.cy-spec.ts @@ -114,11 +114,11 @@ describe('Directive: Mask (Delete)', () => { .type('123') .should('have.value', '(12) 3') .type('{backspace}') - .should('have.prop', 'selectionStart', 5) + .should('have.prop', 'selectionStart', 4) .should('have.value', '(12) ') .type('{rightArrow}') .type('{backspace}') - .should('have.prop', 'selectionStart', 4); + .should('have.prop', 'selectionStart', 3); }); it('should return value from ctrl+V', () => { diff --git a/projects/ngx-mask-lib/src/test/dynamic.spec.ts b/projects/ngx-mask-lib/src/test/dynamic.spec.ts index cd2623d5..49b944b7 100644 --- a/projects/ngx-mask-lib/src/test/dynamic.spec.ts +++ b/projects/ngx-mask-lib/src/test/dynamic.spec.ts @@ -283,4 +283,40 @@ describe('Directive: Mask (Dynamic)', () => { equal('A5A 0A', 'A5A 0A', fixture); equal('A5A 0A9', 'A5A 0A9', fixture); }); + + it('should work with only S', () => { + component.mask = 'S.||S.S.||S.S.S.||S.S.S.S.||S.S.S.S.S.'; + equal('D', 'D.', fixture); + equal('D.D', 'D.D.', fixture); + equal('DDD', 'D.D.D.', fixture); + equal('DDDD', 'D.D.D.D.', fixture); + equal('DDDDD', 'D.D.D.D.D.', fixture); + }); + + it('should work with only A', () => { + component.mask = 'A.||A.A.||A.A.A.||A.A.A.A.||A.A.A.A.A.'; + equal('D', 'D.', fixture); + equal('D.D', 'D.D.', fixture); + equal('DDD', 'D.D.D.', fixture); + equal('DDDD', 'D.D.D.D.', fixture); + equal('DDDDD', 'D.D.D.D.D.', fixture); + }); + + it('should work with only U', () => { + component.mask = 'U.||U.U.||U.U.U.||U.U.U.U.||U.U.U.U.U.'; + equal('D', 'D.', fixture); + equal('D.D', 'D.D.', fixture); + equal('DDD', 'D.D.D.', fixture); + equal('DDDD', 'D.D.D.D.', fixture); + equal('DDDDD', 'D.D.D.D.D.', fixture); + }); + + it('should work with only L', () => { + component.mask = 'L.||L.L.||L.L.L.||L.L.L.L.||L.L.L.L.L.'; + equal('d', 'd.', fixture); + equal('d.d', 'd.d.', fixture); + equal('ddd', 'd.d.d.', fixture); + equal('dddd', 'd.d.d.d.', fixture); + equal('ddddd', 'd.d.d.d.d.', fixture); + }); });