diff --git a/CHANGELOG.md b/CHANGELOG.md index ee4dcd6b..5a2a825b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +# 17.1.4(2024-07-16) + +### Fix + +- Fix ([#1389](https://github.com/JsDaddy/ngx-mask/issues/1389)) + # 17.1.3(2024-07-16) ### Fix diff --git a/package.json b/package.json index 8f0bf700..91c4eb9c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ngx-mask", - "version": "17.1.3", + "version": "17.1.4", "description": "Awesome ngx mask", "license": "MIT", "engines": { diff --git a/projects/ngx-mask-lib/package.json b/projects/ngx-mask-lib/package.json index 0e348689..f0b75121 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.3", + "version": "17.1.4", "description": "awesome ngx mask", "keywords": [ "ng2-mask", diff --git a/projects/ngx-mask-lib/src/lib/ngx-mask-applier.service.ts b/projects/ngx-mask-lib/src/lib/ngx-mask-applier.service.ts index ec382b5a..31feab2b 100644 --- a/projects/ngx-mask-lib/src/lib/ngx-mask-applier.service.ts +++ b/projects/ngx-mask-lib/src/lib/ngx-mask-applier.service.ts @@ -266,24 +266,50 @@ export class NgxMaskApplierService { } if (backspaced) { + const inputValueAfterZero = inputValue.slice( + this._findFirstNonZeroDigitIndex(inputValue), + inputValue.length + ); + const positionOfZeroOrDecimalMarker = + inputValue[position] === MaskExpression.NUMBER_ZERO || + inputValue[position] === decimalMarker; + const zeroIndexNumberZero = inputValue[0] === MaskExpression.NUMBER_ZERO; + const zeroIndexMinus = inputValue[0] === MaskExpression.MINUS; + const firstIndexDecimalMarker = inputValue[1] === decimalMarker; + const firstIndexNumberZero = inputValue[1] === MaskExpression.NUMBER_ZERO; + const secondIndexDecimalMarker = inputValue[2] === decimalMarker; + if ( - inputValue[0] === MaskExpression.NUMBER_ZERO && - inputValue[1] === this.decimalMarker && - (inputValue[position] === MaskExpression.NUMBER_ZERO || - inputValue[position] === this.decimalMarker) + zeroIndexNumberZero && + firstIndexDecimalMarker && + positionOfZeroOrDecimalMarker && + position < 2 ) { // eslint-disable-next-line no-param-reassign - inputValue = inputValue.slice(2, inputValue.length); + inputValue = inputValueAfterZero; } if ( - inputValue[0] === MaskExpression.MINUS && - inputValue[1] === MaskExpression.NUMBER_ZERO && - inputValue[2] === this.decimalMarker && - (inputValue[position] === MaskExpression.NUMBER_ZERO || - inputValue[position] === this.decimalMarker) + zeroIndexMinus && + firstIndexNumberZero && + secondIndexDecimalMarker && + positionOfZeroOrDecimalMarker && + position < 3 ) { // eslint-disable-next-line no-param-reassign - inputValue = MaskExpression.MINUS + inputValue.slice(3, inputValue.length); + inputValue = MaskExpression.MINUS + inputValueAfterZero; + } + if ( + inputValueAfterZero !== MaskExpression.MINUS && + ((position === 0 && !zeroIndexNumberZero) || + (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 @@ -961,4 +987,14 @@ export class NgxMaskApplierService { : `${emptyOrMinus}${integerString}${decimal}${decimalPart}`; } } + + private _findFirstNonZeroDigitIndex(inputString: string): number { + for (let i = 0; i < inputString.length; i++) { + const char = inputString[i]; + if (char && char >= '1' && char <= '9') { + return i; + } + } + return -1; + } } 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 90ee2560..d05307fe 100644 --- a/projects/ngx-mask-lib/src/test/delete.cy-spec.ts +++ b/projects/ngx-mask-lib/src/test/delete.cy-spec.ts @@ -375,4 +375,180 @@ describe('Directive: Mask (Delete)', () => { .type('{backspace}'.repeat(8)) .should('have.value', '__:__:____'); }); + + it('should correct work after backspace separator.6 decimalMarker . thousandSeparator ,', () => { + cy.mount(CypressTestMaskComponent, { + componentProperties: { + mask: 'separator.6', + decimalMarker: '.', + thousandSeparator: ',', + }, + imports: [CypressTestMaskModule], + }); + + cy.get('#masked') + .type('0.000001') + .should('have.value', '0.000001') + .type('{leftArrow}'.repeat(2)) + .type('{backspace}') + .should('have.value', '0.00001') + .type('{leftArrow}'.repeat(2)) + .type('{backspace}') + .should('have.value', '0.0001') + .type('{backspace}') + .should('have.value', '1'); + }); + + it('should correct work after backspace separator.2 decimalMarker . thousandSeparator ,', () => { + cy.mount(CypressTestMaskComponent, { + componentProperties: { + mask: 'separator.2', + decimalMarker: '.', + thousandSeparator: ',', + }, + imports: [CypressTestMaskModule], + }); + + cy.get('#masked') + .type('0.01') + .should('have.value', '0.01') + .type('{leftArrow}') + .type('{backspace}') + .should('have.value', '0.1') + .type('{leftArrow}') + .type('{backspace}') + .should('have.value', '1'); + }); + + it('should correct work after backspace separator.2 decimalMarker . thousandSeparator , allowNegative', () => { + cy.mount(CypressTestMaskComponent, { + componentProperties: { + mask: 'separator.2', + decimalMarker: '.', + thousandSeparator: ',', + allowNegativeNumbers: true, + }, + imports: [CypressTestMaskModule], + }); + + cy.get('#masked') + .type('-0.01') + .should('have.value', '-0.01') + .type('{leftArrow}') + .type('{backspace}') + .should('have.value', '-0.1') + .type('{leftArrow}') + .type('{backspace}') + .should('have.value', '-1'); + }); + + it('should correct work after backspace separator.3 decimalMarker . thousandSeparator , allowNegative', () => { + cy.mount(CypressTestMaskComponent, { + componentProperties: { + mask: 'separator.3', + decimalMarker: '.', + thousandSeparator: ',', + allowNegativeNumbers: true, + }, + imports: [CypressTestMaskModule], + }); + + cy.get('#masked') + .type('-0.014') + .should('have.value', '-0.014') + .type('{leftArrow}'.repeat(2)) + .type('{backspace}') + .should('have.value', '-0.14') + .type('{leftArrow}'.repeat(2)) + .type('{backspace}') + .should('have.value', '-14'); + }); + + it('should correct work after backspace separator.3 leadZero allowNegative', () => { + cy.mount(CypressTestMaskComponent, { + componentProperties: { + mask: 'separator.3', + allowNegativeNumbers: true, + leadZero: true, + }, + imports: [CypressTestMaskModule], + }); + + cy.get('#masked') + .type('-0.1') + .should('have.value', '-0.1') + .type('{leftArrow}'.repeat(2)) + .type('{backspace}') + .should('have.value', '-1') + .type('{backspace}') + .should('have.value', '-'); + }); + + it('should correct work after backspace separator', () => { + cy.mount(CypressTestMaskComponent, { + componentProperties: { + mask: 'separator', + }, + imports: [CypressTestMaskModule], + }); + + cy.get('#masked') + .type('0.33') + .should('have.value', '0.33') + .type('{leftArrow}'.repeat(2)) + .type('{backspace}') + .should('have.value', '33'); + }); + + it('should correct work after backspace separator leadZero', () => { + cy.mount(CypressTestMaskComponent, { + componentProperties: { + mask: 'separator', + leadZero: true, + }, + imports: [CypressTestMaskModule], + }); + + cy.get('#masked') + .type('0.33') + .should('have.value', '0.33') + .type('{leftArrow}'.repeat(2)) + .type('{backspace}') + .should('have.value', '33'); + }); + + it('should correct work after backspace separator allowNegativeNumbers', () => { + cy.mount(CypressTestMaskComponent, { + componentProperties: { + mask: 'separator', + allowNegativeNumbers: true, + }, + imports: [CypressTestMaskModule], + }); + + cy.get('#masked') + .type('-0.33') + .should('have.value', '-0.33') + .type('{leftArrow}'.repeat(2)) + .type('{backspace}') + .should('have.value', '-33'); + }); + + it('should correct work after backspace separator leadZero', () => { + cy.mount(CypressTestMaskComponent, { + componentProperties: { + mask: 'separator', + leadZero: true, + allowNegativeNumbers: true, + }, + imports: [CypressTestMaskModule], + }); + + cy.get('#masked') + .type('-0.33') + .should('have.value', '-0.33') + .type('{leftArrow}'.repeat(2)) + .type('{backspace}') + .should('have.value', '-33'); + }); }); diff --git a/projects/ngx-mask-lib/src/test/utils/cypress-test-component.component.ts b/projects/ngx-mask-lib/src/test/utils/cypress-test-component.component.ts index 5c228f92..5a81b095 100644 --- a/projects/ngx-mask-lib/src/test/utils/cypress-test-component.component.ts +++ b/projects/ngx-mask-lib/src/test/utils/cypress-test-component.component.ts @@ -14,6 +14,7 @@ import { IConfig, NGX_MASK_CONFIG } from 'ngx-mask'; [suffix]="suffix" [leadZero]="leadZero" [showMaskTyped]="showMaskTyped" + [allowNegativeNumbers]="allowNegativeNumbers" [decimalMarker]="decimalMarker" [thousandSeparator]="thousandSeparator" [shownMaskExpression]="shownMaskExpression" @@ -37,6 +38,8 @@ export class CypressTestMaskComponent { @Input() public hiddenInput = false; + @Input() public allowNegativeNumbers = false; + @Input() public prefix = ''; @Input() public suffix = '';