diff --git a/src/dropdownListModel.ts b/src/dropdownListModel.ts index f2b86614f6..32fe682f84 100644 --- a/src/dropdownListModel.ts +++ b/src/dropdownListModel.ts @@ -6,6 +6,7 @@ import { ListModel } from "./list"; import { PopupModel } from "./popup"; import { Question } from "./question"; import { QuestionDropdownModel } from "./question_dropdown"; +import { SurveyModel } from "./survey"; import { CssClassBuilder } from "./utils/cssClassBuilder"; import { IsTouch } from "./utils/devices"; import { doKey2ClickBlur, doKey2ClickUp } from "./utils/utils"; @@ -386,10 +387,12 @@ export class DropdownListModel extends Base { if (event.keyCode === 13 && this.question.searchEnabled && !this.inputString && this.question instanceof QuestionDropdownModel && !this._markdownMode && this.question.value) { this._popupModel.isVisible = false; this.onClear(event); + (this.question.survey as SurveyModel).questionEditFinishCallback(this.question, event); } else { this.listModel.selectFocusedItem(); this.onFocus(event); + (this.question.survey as SurveyModel).questionEditFinishCallback(this.question, event); } event.preventDefault(); event.stopPropagation(); diff --git a/src/question_text.ts b/src/question_text.ts index cd54371d65..46f90ccf7c 100644 --- a/src/question_text.ts +++ b/src/question_text.ts @@ -8,6 +8,7 @@ import { CustomError } from "./error"; import { settings } from "./settings"; import { QuestionTextBase } from "./question_textbase"; import { ExpressionRunner } from "./conditions"; +import { SurveyModel } from "./survey"; /** * A class that describes the Text question type. @@ -429,6 +430,9 @@ export class QuestionTextModel extends QuestionTextBase { if(this.isInputTextUpdate) { this._isWaitingForEnter = event.keyCode === 229; } + if (event.keyCode === 13) { + (this.survey as SurveyModel).questionEditFinishCallback(this, event); + } } public onChange = (event: any): void => { if (event.target === document.activeElement) { diff --git a/src/settings.ts b/src/settings.ts index c2707c0bf4..9ac20009c5 100644 --- a/src/settings.ts +++ b/src/settings.ts @@ -8,6 +8,16 @@ * ``` */ export var settings = { + /** + * Specifies an action to perform when users press the Enter key within a survey. + * + * Possible values: + * + * - `"moveToNextEditor"` - Moves focus to the next editor. + * - `"loseFocus"` - Removes focus from the current editor. + * - `"default"` - Behaves as a standard `` element. + */ + enterKeyAction: "default" as "moveToNextEditor" | "loseFocus" | "default", /** * An object that configures string comparison. * diff --git a/src/survey.ts b/src/survey.ts index 660ed988bd..79ba2a30c3 100644 --- a/src/survey.ts +++ b/src/survey.ts @@ -6674,6 +6674,20 @@ export class SurveyModel extends SurveyElementCore return true; } + public questionEditFinishCallback(question: Question, event: any) { + if (settings.enterKeyAction == "loseFocus") event.target.blur(); + if (settings.enterKeyAction == "moveToNextEditor") { + const allQuestions = this.currentPage.questions; + const questionIndex = allQuestions.indexOf(question); + if (questionIndex > -1 && questionIndex < allQuestions.length - 1) { + allQuestions[questionIndex + 1].focus(); + } + else { + event.target.blur(); + } + } + } + public getElementWrapperComponentName(element: any, reason?: string): string { if (reason === "logo-image") { return "sv-logo-image"; diff --git a/testCafe/questions/text.js b/testCafe/questions/text.js index e9b46b9561..59b1a023f3 100644 --- a/testCafe/questions/text.js +++ b/testCafe/questions/text.js @@ -1,5 +1,5 @@ import { frameworks, url, initSurvey, getSurveyResult, getQuestionValue, getQuestionJson } from "../helper"; -import { Selector, fixture, test } from "testcafe"; +import { Selector, fixture, test, ClientFunction } from "testcafe"; // eslint-disable-next-line no-undef const assert = require("assert"); const title = "text"; diff --git a/testCafe/survey/focusQuestionEvent.ts b/testCafe/survey/focusQuestionEvent.ts index 0b2d7ff88e..7194a499a2 100644 --- a/testCafe/survey/focusQuestionEvent.ts +++ b/testCafe/survey/focusQuestionEvent.ts @@ -36,4 +36,79 @@ frameworks.forEach(async framework => { await t.click(Selector(".sv_qstn input").nth(1)); await t.expect(ClientFunction(() => window["raisedFocusEvent"])()).ok(); }); -}); \ No newline at end of file + + test("enterKeyAction", async (t) => { + const characterCounter = Selector(".sv-remaining-character-counter"); + + await initSurvey(framework, { + "logoPosition": "right", + "pages": [ + { + "name": "page1", + "elements": [ + { + "type": "text", + "name": "question1" + }, + { + "type": "dropdown", + "name": "question2", + "choices": ["item1", "item2"] + }, + { + "type": "text", + "name": "question3" + } + ] + }, + { + "name": "page2", + "elements": [ + { + "type": "text", + "name": "question4" + } + ] + } + ] + }); + + await ClientFunction(() => { + window["Survey"].settings.enterKeyAction = "loseFocus"; + })(); + + const q1Input = Selector("div[data-name=question1] input"); + const q2Input = Selector("div[data-name=question2] input"); + const q3Input = Selector("div[data-name=question3] input"); + const q4Input = Selector("div[data-name=question4] input"); + await t + .typeText(q1Input, "abc") + .expect(q1Input.focused).ok() + .pressKey("Enter") + .expect(q1Input.focused).notOk() + .typeText(q2Input, "it") + .expect(q2Input.focused).ok() + .pressKey("Enter") + .expect(q2Input.focused).notOk(); + + await ClientFunction(() => { + window["Survey"].settings.enterKeyAction = "moveToNextEditor"; + })(); + + await t + .typeText(q1Input, "abc") + .expect(q1Input.focused).ok() + .pressKey("Enter") + .typeText(q2Input, "it") + .expect(q2Input.focused).ok() + .pressKey("Enter") + .expect(q3Input.focused).ok() + .typeText(q3Input, "mnk") + .pressKey("Enter") + .expect(q3Input.focused).notOk(); + await ClientFunction(() => { + window["Survey"].settings.enterKeyAction = "default"; + })(); + }); + +});