diff --git a/functionalTests/questions/input_mask.ts b/functionalTests/questions/input_mask.ts index 8bcba1c926..42363832b1 100644 --- a/functionalTests/questions/input_mask.ts +++ b/functionalTests/questions/input_mask.ts @@ -105,6 +105,37 @@ frameworks.forEach((framework) => { .expect(Selector("input").value).eql(emptyValue); }); + test("mask and maxlength", async (t) => { + await initSurvey(framework, { + focusFirstQuestionAutomatic: true, + "pages": [ + { + "name": "page1", + "elements": [ + { + "type": "text", + "name": "question1", + "maskType": "numeric", + "maxLength": 2 + } + ] + } + ] + }); + + await t + .expect(Selector("input").value).eql("") + + .pressKey("1") + .expect(Selector("input").value).eql("1") + + .pressKey("2") + .expect(Selector("input").value).eql("12") + + .pressKey("3") + .expect(Selector("input").value).eql("12"); + }); + test("Test mask in western timezone", async (t) => { if (framework === "vue") return; const oldTimeZone = await getTimeZone(); diff --git a/packages/survey-core/src/mask/input_element_adapter.ts b/packages/survey-core/src/mask/input_element_adapter.ts index caa2fda1e3..74d4b7a944 100644 --- a/packages/survey-core/src/mask/input_element_adapter.ts +++ b/packages/survey-core/src/mask/input_element_adapter.ts @@ -4,12 +4,18 @@ import { ITextInputParams } from "./mask_utils"; export class InputElementAdapter { private prevUnmaskedValue: string = undefined; + private setInputValue(value: string) { + if (this.inputElement.maxLength >= 0 && this.inputElement.maxLength < value.length) { + value = value.slice(0, this.inputElement.maxLength); + } + this.inputElement.value = value; + } constructor(private inputMaskInstance: InputMaskBase, private inputElement: HTMLInputElement, value?: any) { let _value: any = value; if (_value === null || _value === undefined) { _value = ""; } - this.inputElement.value = inputMaskInstance.getMaskedValue(_value); + this.setInputValue(inputMaskInstance.getMaskedValue(_value)); this.prevUnmaskedValue = _value; inputMaskInstance.onPropertyChanged.add(this.inputMaskInstancePropertyChangedHandler); @@ -19,7 +25,7 @@ export class InputElementAdapter { inputMaskInstancePropertyChangedHandler = (sender: any, options: any) => { if (options.name !== "saveMaskedValue") { const maskedValue = this.inputMaskInstance.getMaskedValue(this.prevUnmaskedValue); - this.inputElement.value = maskedValue; + this.setInputValue(maskedValue); } } @@ -32,7 +38,7 @@ export class InputElementAdapter { beforeInputHandler = (event: any) => { const args = this.createArgs(event); const result = this.inputMaskInstance.processInput(args); - this.inputElement.value = result.value; + this.setInputValue(result.value); this.inputElement.setSelectionRange(result.caretPosition, result.caretPosition); if (!result.cancelPreventDefault) { event.preventDefault(); @@ -41,7 +47,7 @@ export class InputElementAdapter { changeHandler = (event: any) => { const result = this.inputMaskInstance.processInput({ prevValue: "", insertedChars: event.target.value, selectionStart: 0, selectionEnd: 0 }); - this.inputElement.value = result.value; + this.setInputValue(result.value); } public createArgs(event: any): ITextInputParams {