From 16ef614018438967e58b5871b5028bb4ef07fdf1 Mon Sep 17 00:00:00 2001 From: jadeddelta <101148768+jadeddelta@users.noreply.github.com> Date: Wed, 19 Oct 2022 23:37:35 -0400 Subject: [PATCH 1/7] autofocus + case sensitivity --- examples/jspsych-cloze.html | 8 ++++++++ packages/plugin-cloze/src/index.spec.ts | 15 ++++++++++++++ packages/plugin-cloze/src/index.ts | 27 +++++++++++++++++-------- 3 files changed, 42 insertions(+), 8 deletions(-) diff --git a/examples/jspsych-cloze.html b/examples/jspsych-cloze.html index d32859b9f6..aebc1982a1 100644 --- a/examples/jspsych-cloze.html +++ b/examples/jspsych-cloze.html @@ -22,6 +22,14 @@ text: 'The %% is the largest terrestrial mammal. It lives in both %% and %%.' }); + // an example that allows the user to input a solution that doesn't require case sensitivity + timeline.push({ + type: jsPsychCloze, + text: 'The %CASE% is closed.', + check_answers: true, + case_sensitivity: false, + }) + // another example with checking if all the blanks are filled in timeline.push({ type: jsPsychCloze, diff --git a/packages/plugin-cloze/src/index.spec.ts b/packages/plugin-cloze/src/index.spec.ts index 3c383818f5..30307fc558 100644 --- a/packages/plugin-cloze/src/index.spec.ts +++ b/packages/plugin-cloze/src/index.spec.ts @@ -73,6 +73,21 @@ describe("cloze", () => { await expectFinished(); }); + test("ends trial on button click when answers are checked and correct without case sensitivity", async () => { + const { expectFinished } = await startTimeline([ + { + type: cloze, + text: "This is a %cloze% text.", + check_answers: true, + case_sensitivity: false, + }, + ]); + + getInputElementById("input0").value = "CLOZE"; + clickTarget(document.querySelector("#finish_cloze_button")); + await expectFinished(); + }); + test("ends trial on button click when all answers are checked for completion and are complete", async () => { const { expectFinished } = await startTimeline([ { diff --git a/packages/plugin-cloze/src/index.ts b/packages/plugin-cloze/src/index.ts index 71d538cf2f..9ad952a0f7 100644 --- a/packages/plugin-cloze/src/index.ts +++ b/packages/plugin-cloze/src/index.ts @@ -27,6 +27,12 @@ const info = { pretty_name: "Allow blanks", default: true, }, + /** Boolean value indicating if the solutions checker must be case sensitive. */ + case_sensitivity: { + type: ParameterType.BOOL, + pretty_name: "Case sensitivity", + default: true, + }, /** Function called if either the check_answers is set to TRUE or the allow_blanks is set to FALSE and there is a discrepancy between the set answers and the answers provide or if all input fields aren't filled out, respectively. */ mistake_fn: { type: ParameterType.FUNCTION, @@ -55,7 +61,7 @@ class ClozePlugin implements JsPsychPlugin { var html = '
'; // odd elements are text, even elements are the blanks var elements = trial.text.split("%"); - const solutions = this.getSolutions(trial.text); + const solutions = this.getSolutions(trial.text, trial.case_sensitivity); let solution_counter = 0; for (var i = 0; i < elements.length; i++) { @@ -78,7 +84,9 @@ class ClozePlugin implements JsPsychPlugin { for (var i = 0; i < solutions.length; i++) { var field = document.getElementById("input" + i) as HTMLInputElement; - answers.push(field.value.trim()); + answers.push( + trial.case_sensitivity ? field.value.trim() : field.value.toLowerCase().trim() + ); if (trial.check_answers) { if (answers[i] !== solutions[i]) { @@ -112,15 +120,18 @@ class ClozePlugin implements JsPsychPlugin { trial.button_text + ""; display_element.querySelector("#finish_cloze_button").addEventListener("click", check); + + (display_element.querySelector("#input0") as HTMLElement).focus(); } - private getSolutions(text: string) { + private getSolutions(text: string, case_sensitive: boolean) { const solutions = []; const elements = text.split("%"); - for (let i = 0; i < elements.length; i++) { - if (i % 2 == 1) { - solutions.push(elements[i].trim()); - } + + for (let i = 1; i < elements.length; i += 2) { + solutions.push( + case_sensitive ? elements[i].trim() : elements[i].toLowerCase().trim() + ); } return solutions; @@ -142,7 +153,7 @@ class ClozePlugin implements JsPsychPlugin { } private create_simulation_data(trial: TrialType, simulation_options) { - const solutions = this.getSolutions(trial.text); + const solutions = this.getSolutions(trial.text, trial.case_sensitivity); const responses = []; for (const word of solutions) { if (word == "") { From 10ca06ce14b3b982fb45e1660010b3e7db2a09a9 Mon Sep 17 00:00:00 2001 From: jadeddelta <101148768+jadeddelta@users.noreply.github.com> Date: Thu, 20 Oct 2022 00:11:38 -0400 Subject: [PATCH 2/7] added multiple answer checking --- examples/jspsych-cloze.html | 4 ++-- packages/plugin-cloze/src/index.spec.ts | 1 + packages/plugin-cloze/src/index.ts | 10 +++++----- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/examples/jspsych-cloze.html b/examples/jspsych-cloze.html index aebc1982a1..ef8d67fa13 100644 --- a/examples/jspsych-cloze.html +++ b/examples/jspsych-cloze.html @@ -22,10 +22,10 @@ text: 'The %% is the largest terrestrial mammal. It lives in both %% and %%.' }); - // an example that allows the user to input a solution that doesn't require case sensitivity + // an example that allows the user to input a solution that doesn't require case sensitivity, and allows multiple responses timeline.push({ type: jsPsychCloze, - text: 'The %CASE% is closed.', + text: 'The %CASE/door/EyE% is closed.', check_answers: true, case_sensitivity: false, }) diff --git a/packages/plugin-cloze/src/index.spec.ts b/packages/plugin-cloze/src/index.spec.ts index 30307fc558..38c4eca6f8 100644 --- a/packages/plugin-cloze/src/index.spec.ts +++ b/packages/plugin-cloze/src/index.spec.ts @@ -218,6 +218,7 @@ describe("cloze", () => { }); describe("cloze simulation", () => { + //TODO: bro why is this not working (wraps this in array but not the next one) test("data-only mode works", async () => { const { getData, expectFinished } = await simulateTimeline([ { diff --git a/packages/plugin-cloze/src/index.ts b/packages/plugin-cloze/src/index.ts index 9ad952a0f7..46be9869f8 100644 --- a/packages/plugin-cloze/src/index.ts +++ b/packages/plugin-cloze/src/index.ts @@ -3,7 +3,7 @@ import { JsPsych, JsPsychPlugin, ParameterType, TrialType } from "jspsych"; const info = { name: "cloze", parameters: { - /** The cloze text to be displayed. Blanks are indicated by %% signs and automatically replaced by input fields. If there is a correct answer you want the system to check against, it must be typed between the two percentage signs (i.e. %solution%). */ + /** The cloze text to be displayed. Blanks are indicated by %% signs and automatically replaced by input fields. If there is a correct answer you want the system to check against, it must be typed between the two percentage signs (i.e. %solution%). For multiple answers, type them with a slash (i.e. %1/2/3%). */ text: { type: ParameterType.HTML_STRING, pretty_name: "Cloze text", @@ -89,7 +89,7 @@ class ClozePlugin implements JsPsychPlugin { ); if (trial.check_answers) { - if (answers[i] !== solutions[i]) { + if (!solutions[i].includes(answers[i])) { field.style.color = "red"; answers_correct = false; } else { @@ -125,12 +125,12 @@ class ClozePlugin implements JsPsychPlugin { } private getSolutions(text: string, case_sensitive: boolean) { - const solutions = []; + const solutions: String[][] = []; const elements = text.split("%"); for (let i = 1; i < elements.length; i += 2) { solutions.push( - case_sensitive ? elements[i].trim() : elements[i].toLowerCase().trim() + case_sensitive ? elements[i].trim().split("/") : elements[i].toLowerCase().trim().split("/") ); } @@ -156,7 +156,7 @@ class ClozePlugin implements JsPsychPlugin { const solutions = this.getSolutions(trial.text, trial.case_sensitivity); const responses = []; for (const word of solutions) { - if (word == "") { + if (word.includes("")) { responses.push(this.jsPsych.randomization.randomWords({ exactly: 1 })); } else { responses.push(word); From d2be99fc47f86071fc8e91f052133734bc793da6 Mon Sep 17 00:00:00 2001 From: jadeddelta <101148768+jadeddelta@users.noreply.github.com> Date: Mon, 24 Oct 2022 23:35:09 -0400 Subject: [PATCH 3/7] simulation bugfix --- packages/plugin-cloze/src/index.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/plugin-cloze/src/index.ts b/packages/plugin-cloze/src/index.ts index 46be9869f8..13a91cb747 100644 --- a/packages/plugin-cloze/src/index.ts +++ b/packages/plugin-cloze/src/index.ts @@ -155,11 +155,13 @@ class ClozePlugin implements JsPsychPlugin { private create_simulation_data(trial: TrialType, simulation_options) { const solutions = this.getSolutions(trial.text, trial.case_sensitivity); const responses = []; - for (const word of solutions) { - if (word.includes("")) { + for (const wordList of solutions) { + if (wordList.includes("")) { responses.push(this.jsPsych.randomization.randomWords({ exactly: 1 })); } else { - responses.push(word); + for (const word of wordList) { + responses.push(word); + } } } From 3f91e52900989020a9c650999f37d883554a2dcf Mon Sep 17 00:00:00 2001 From: jadeddelta <101148768+jadeddelta@users.noreply.github.com> Date: Mon, 31 Oct 2022 21:52:38 -0400 Subject: [PATCH 4/7] simulation bugfix pt. 2 + docs --- docs/plugins/cloze.md | 3 ++- packages/plugin-cloze/src/index.spec.ts | 1 - packages/plugin-cloze/src/index.ts | 10 ++++++---- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/docs/plugins/cloze.md b/docs/plugins/cloze.md index 4ee5a51f74..1a1a9dff57 100644 --- a/docs/plugins/cloze.md +++ b/docs/plugins/cloze.md @@ -10,10 +10,11 @@ In addition to the [parameters available in all plugins](../overview/plugins.md# | Parameter | Type | Default Value | Description | | ------------- | -------- | ------------------ | ---------------------------------------- | -| text | string | *undefined* | The cloze text to be displayed. Blanks are indicated by %% signs and automatically replaced by input fields. If there is a correct answer you want the system to check against, it must be typed between the two percentage signs (i.e. % correct solution %). | +| text | string | *undefined* | The cloze text to be displayed. Blanks are indicated by %% signs and automatically replaced by input fields. If there is a correct answer you want the system to check against, it must be typed between the two percentage signs (i.e. % correct solution %). To input multiple correct answers, add a / between each answer (i.e. %correct/alsocorrect%). | | button_text | string | OK | Text of the button participants have to press for finishing the cloze test. | | check_answers | boolean | false | Boolean value indicating if the answers given by participants should be compared against a correct solution given in the text (between % signs) after the button was clicked. If ```true```, answers are checked and in case of differences, the ```mistake_fn``` is called. In this case, the trial does not automatically finish. If ```false```, no checks are performed and the trial automatically ends when clicking the button. | | allow_blanks | boolean | true | Boolean value indicating if the answers given by participants should be checked for completion after the button was clicked. If ```true```, answers are not checked for completion and blank answers are allowed. The trial will then automatically finish upon the clicking the button. If ```false```, answers are checked for completion, and in case there are some fields with missing answers, the ```mistake_fn``` is called. In this case, the trial does not automatically finish. | +| case_sensitivity | boolean | true | Boolean value indicating if the answers given by participants should also be checked to have the right case along with correctness. If set to ```false```, case is disregarded and participants may type in whatever case they please. | | mistake_fn | function | ```function(){}``` | Function called if ```check_answers``` is set to ```true``` and there is a difference between the participant's answers and the correct solution provided in the text, or if ```allow_blanks``` is set to ```false``` and there is at least one field with a blank answer. | ## Data Generated diff --git a/packages/plugin-cloze/src/index.spec.ts b/packages/plugin-cloze/src/index.spec.ts index 38c4eca6f8..30307fc558 100644 --- a/packages/plugin-cloze/src/index.spec.ts +++ b/packages/plugin-cloze/src/index.spec.ts @@ -218,7 +218,6 @@ describe("cloze", () => { }); describe("cloze simulation", () => { - //TODO: bro why is this not working (wraps this in array but not the next one) test("data-only mode works", async () => { const { getData, expectFinished } = await simulateTimeline([ { diff --git a/packages/plugin-cloze/src/index.ts b/packages/plugin-cloze/src/index.ts index 13a91cb747..3b9241ac62 100644 --- a/packages/plugin-cloze/src/index.ts +++ b/packages/plugin-cloze/src/index.ts @@ -159,9 +159,7 @@ class ClozePlugin implements JsPsychPlugin { if (wordList.includes("")) { responses.push(this.jsPsych.randomization.randomWords({ exactly: 1 })); } else { - for (const word of wordList) { - responses.push(word); - } + responses.push(wordList); } } @@ -179,6 +177,8 @@ class ClozePlugin implements JsPsychPlugin { private simulate_data_only(trial: TrialType, simulation_options) { const data = this.create_simulation_data(trial, simulation_options); + data.response = data.response[0]; + this.jsPsych.finishTrial(data); } @@ -193,7 +193,9 @@ class ClozePlugin implements JsPsychPlugin { const inputs = display_element.querySelectorAll('input[type="text"]'); let rt = this.jsPsych.randomization.sampleExGaussian(750, 200, 0.01, true); for (let i = 0; i < data.response.length; i++) { - this.jsPsych.pluginAPI.fillTextInput(inputs[i] as HTMLInputElement, data.response[i], rt); + let res = data.response[i][Math.floor(Math.random() * data.response[i].length)]; + + this.jsPsych.pluginAPI.fillTextInput(inputs[i] as HTMLInputElement, res, rt); rt += this.jsPsych.randomization.sampleExGaussian(750, 200, 0.01, true); } this.jsPsych.pluginAPI.clickTarget(display_element.querySelector("#finish_cloze_button"), rt); From 703b724376ec66c09967ac6e1bb87ecce6b33b74 Mon Sep 17 00:00:00 2001 From: jadeddelta <101148768+jadeddelta@users.noreply.github.com> Date: Mon, 31 Oct 2022 21:56:44 -0400 Subject: [PATCH 5/7] changeset --- .changeset/spotty-mails-cheat.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/spotty-mails-cheat.md diff --git a/.changeset/spotty-mails-cheat.md b/.changeset/spotty-mails-cheat.md new file mode 100644 index 0000000000..3bf24ee0c1 --- /dev/null +++ b/.changeset/spotty-mails-cheat.md @@ -0,0 +1,5 @@ +--- +"@jspsych/plugin-cloze": minor +--- + +adds support for multiple correct answers and case sensitivity From 0d5e3ea5f6b26c0bc75505eaca83cf5abca679c4 Mon Sep 17 00:00:00 2001 From: jade <101148768+jadeddelta@users.noreply.github.com> Date: Mon, 4 Nov 2024 14:43:55 -0500 Subject: [PATCH 6/7] fix simulation data and tests --- packages/plugin-cloze/src/index.spec.ts | 24 ++++++++++++ packages/plugin-cloze/src/index.ts | 51 +++++++++++++++++-------- 2 files changed, 59 insertions(+), 16 deletions(-) diff --git a/packages/plugin-cloze/src/index.spec.ts b/packages/plugin-cloze/src/index.spec.ts index 52b1c4c88f..ec92cdb412 100644 --- a/packages/plugin-cloze/src/index.spec.ts +++ b/packages/plugin-cloze/src/index.spec.ts @@ -8,6 +8,11 @@ const getInputElementById = (id: string) => document.getElementById(id) as HTMLI const clickFinishButton = () => clickTarget(document.querySelector("#finish_cloze_button")); +// reset DOM +beforeEach(() => { + document.body.innerHTML = ""; +}); + describe("cloze", () => { test("displays cloze", async () => { const { getHTML, expectFinished } = await startTimeline([ @@ -200,6 +205,25 @@ describe("cloze", () => { await expectFinished(); }); + test.skip("calls mistake function on button click when answers are checked and do not belong to a multiple answer blank", async () => { + const mistakeFn = jest.fn(); + + const { expectFinished } = await startTimeline([ + { + type: cloze, + text: "This is a %cloze/jspsych% text.", + check_answers: true, + mistake_fn: mistakeFn, + }, + ]); + + getInputElementById("input0").value = "not fitting in answer"; + await clickFinishButton(); + expect(mistakeFn).toHaveBeenCalled(); + + await expectFinished(); + }); + test("response data is stored as an array", async () => { const { getData, expectFinished } = await startTimeline([ { diff --git a/packages/plugin-cloze/src/index.ts b/packages/plugin-cloze/src/index.ts index bc2b50005a..9c4aa073a9 100644 --- a/packages/plugin-cloze/src/index.ts +++ b/packages/plugin-cloze/src/index.ts @@ -6,7 +6,12 @@ const info = { name: "cloze", version: version, parameters: { - /** The cloze text to be displayed. Blanks are indicated by %% signs and automatically replaced by input fields. If there is a correct answer you want the system to check against, it must be typed between the two percentage signs (i.e. % correct solution %). */ + /** + * The cloze text to be displayed. Blanks are indicated by %% signs and automatically replaced by + * input fields. If there is a correct answer you want the system to check against, it must be typed + * between the two percentage signs (i.e. % correct solution %). If you would like to input multiple + * solutions, type a slash between each responses (i.e. %1/2/3%). + */ text: { type: ParameterType.HTML_STRING, default: undefined, @@ -16,12 +21,25 @@ const info = { type: ParameterType.STRING, default: "OK", }, - /** Boolean value indicating if the answers given by participants should be compared against a correct solution given in the text (between % signs) after the button was clicked. If ```true```, answers are checked and in case of differences, the ```mistake_fn``` is called. In this case, the trial does not automatically finish. If ```false```, no checks are performed and the trial automatically ends when clicking the button. */ + /** + * Boolean value indicating if the answers given by participants should be compared + * against a correct solution given in `text` after the submit button was clicked. + * If ```true```, answers are checked and in case of differences, the ```mistake_fn``` + * is called. In this case, the trial does not automatically finish. If ```false```, + * no checks are performed and the trial ends when clicking the submit button. + */ check_answers: { type: ParameterType.BOOL, default: false, }, - /** Boolean value indicating if the answers given by participants should be checked for completion after the button was clicked. If ```true```, answers are not checked for completion and blank answers are allowed. The trial will then automatically finish upon the clicking the button. If ```false```, answers are checked for completion, and in case there are some fields with missing answers, the ```mistake_fn``` is called. In this case, the trial does not automatically finish. */ + /** + * Boolean value indicating if the answers given by participants should be checked for + * completion after the button was clicked. If ```true```, answers are not checked for + * completion and blank answers are allowed. The trial will then automatically finish + * upon the clicking the button. If ```false```, answers are checked for completion, + * and in case there are some fields with missing answers, the ```mistake_fn``` is called. + * In this case, the trial does not automatically finish. + */ allow_blanks: { type: ParameterType.BOOL, default: true, @@ -32,14 +50,18 @@ const info = { pretty_name: "Case sensitivity", default: true, }, - /** Function called if either the check_answers is set to TRUE or the allow_blanks is set to FALSE and there is a discrepancy between the set answers and the answers provide or if all input fields aren't filled out, respectively. */ + /** + * Function called if either `check_answers` is `true` or `allow_blanks` is `false` + * and there is a discrepancy between the set answers and the answers provided, or + * if all input fields aren't filled out, respectively. + */ mistake_fn: { type: ParameterType.FUNCTION, default: () => {}, }, }, data: { - /** Answers the partcipant gave. */ + /** Answers the participant gave. */ response: { type: ParameterType.STRING, array: true, @@ -81,7 +103,7 @@ class ClozePlugin implements JsPsychPlugin { display_element.innerHTML = html; const check = () => { - var answers: String[] = []; + var answers: string[] = []; var answers_correct = true; var answers_filled = true; @@ -126,8 +148,8 @@ class ClozePlugin implements JsPsychPlugin { (display_element.querySelector("#input0") as HTMLElement).focus(); } - private getSolutions(text: string, case_sensitive: boolean) { - const solutions: String[][] = []; + private getSolutions(text: string, case_sensitive: boolean): string[][] { + const solutions: string[][] = []; const elements = text.split("%"); for (let i = 1; i < elements.length; i += 2) { @@ -156,12 +178,13 @@ class ClozePlugin implements JsPsychPlugin { private create_simulation_data(trial: TrialType, simulation_options) { const solutions = this.getSolutions(trial.text, trial.case_sensitivity); - const responses = []; + const responses: string[] = []; for (const wordList of solutions) { if (wordList.includes("")) { - responses.push(this.jsPsych.randomization.randomWords({ exactly: 1 })); + var word = this.jsPsych.randomization.randomWords({ exactly: 1 }); + responses.push(word[0]); } else { - responses.push(wordList); + responses.push(wordList[Math.floor(Math.random() * wordList.length)]); } } @@ -179,8 +202,6 @@ class ClozePlugin implements JsPsychPlugin { private simulate_data_only(trial: TrialType, simulation_options) { const data = this.create_simulation_data(trial, simulation_options); - data.response = data.response[0]; - this.jsPsych.finishTrial(data); } @@ -195,9 +216,7 @@ class ClozePlugin implements JsPsychPlugin { const inputs = display_element.querySelectorAll('input[type="text"]'); let rt = this.jsPsych.randomization.sampleExGaussian(750, 200, 0.01, true); for (let i = 0; i < data.response.length; i++) { - let res = data.response[i][Math.floor(Math.random() * data.response[i].length)]; - - this.jsPsych.pluginAPI.fillTextInput(inputs[i] as HTMLInputElement, res, rt); + this.jsPsych.pluginAPI.fillTextInput(inputs[i] as HTMLInputElement, data.response[i], rt); rt += this.jsPsych.randomization.sampleExGaussian(750, 200, 0.01, true); } this.jsPsych.pluginAPI.clickTarget(display_element.querySelector("#finish_cloze_button"), rt); From 7d19525db91452c65ce3a8b40be35fca2e99346e Mon Sep 17 00:00:00 2001 From: jade <101148768+jadeddelta@users.noreply.github.com> Date: Sun, 1 Dec 2024 23:55:50 -0500 Subject: [PATCH 7/7] parameterize autofocus, fix last test --- .changeset/spotty-mails-cheat.md | 2 +- docs/plugins/cloze.md | 1 + packages/plugin-cloze/src/index.spec.ts | 9 +++------ packages/plugin-cloze/src/index.ts | 11 ++++++++++- 4 files changed, 15 insertions(+), 8 deletions(-) diff --git a/.changeset/spotty-mails-cheat.md b/.changeset/spotty-mails-cheat.md index 3bf24ee0c1..399ac45b5b 100644 --- a/.changeset/spotty-mails-cheat.md +++ b/.changeset/spotty-mails-cheat.md @@ -2,4 +2,4 @@ "@jspsych/plugin-cloze": minor --- -adds support for multiple correct answers and case sensitivity +adds support for multiple correct answers, case sensitivity, and autofocus. diff --git a/docs/plugins/cloze.md b/docs/plugins/cloze.md index f7b869f44d..4830e18134 100644 --- a/docs/plugins/cloze.md +++ b/docs/plugins/cloze.md @@ -16,6 +16,7 @@ In addition to the [parameters available in all plugins](../overview/plugins.md# | allow_blanks | boolean | true | Boolean value indicating if the answers given by participants should be checked for completion after the button was clicked. If ```true```, answers are not checked for completion and blank answers are allowed. The trial will then automatically finish upon the clicking the button. If ```false```, answers are checked for completion, and in case there are some fields with missing answers, the ```mistake_fn``` is called. In this case, the trial does not automatically finish. | | case_sensitivity | boolean | true | Boolean value indicating if the answers given by participants should also be checked to have the right case along with correctness. If set to ```false```, case is disregarded and participants may type in whatever case they please. | | mistake_fn | function | ```function(){}``` | Function called if ```check_answers``` is set to ```true``` and there is a difference between the participant's answers and the correct solution provided in the text, or if ```allow_blanks``` is set to ```false``` and there is at least one field with a blank answer. | +| autofocus | boolean | true | Boolean value indicating if the first input field should be focused when the trial starts. Enabled by default, but may be disabled especially if participants are using screen readers. | ## Data Generated diff --git a/packages/plugin-cloze/src/index.spec.ts b/packages/plugin-cloze/src/index.spec.ts index ec92cdb412..045373af89 100644 --- a/packages/plugin-cloze/src/index.spec.ts +++ b/packages/plugin-cloze/src/index.spec.ts @@ -8,11 +8,6 @@ const getInputElementById = (id: string) => document.getElementById(id) as HTMLI const clickFinishButton = () => clickTarget(document.querySelector("#finish_cloze_button")); -// reset DOM -beforeEach(() => { - document.body.innerHTML = ""; -}); - describe("cloze", () => { test("displays cloze", async () => { const { getHTML, expectFinished } = await startTimeline([ @@ -205,7 +200,7 @@ describe("cloze", () => { await expectFinished(); }); - test.skip("calls mistake function on button click when answers are checked and do not belong to a multiple answer blank", async () => { + test("calls mistake function on button click when answers are checked and do not belong to a multiple answer blank", async () => { const mistakeFn = jest.fn(); const { expectFinished } = await startTimeline([ @@ -221,6 +216,8 @@ describe("cloze", () => { await clickFinishButton(); expect(mistakeFn).toHaveBeenCalled(); + getInputElementById("input0").value = "cloze"; + await clickFinishButton(); await expectFinished(); }); diff --git a/packages/plugin-cloze/src/index.ts b/packages/plugin-cloze/src/index.ts index 9c4aa073a9..85de2d24a5 100644 --- a/packages/plugin-cloze/src/index.ts +++ b/packages/plugin-cloze/src/index.ts @@ -59,6 +59,14 @@ const info = { type: ParameterType.FUNCTION, default: () => {}, }, + /** + * Boolean value indicating if the first input field should be focused when the trial starts. + * Enabled by default, but may be disabled especially if participants are using screen readers. + */ + autofocus: { + type: ParameterType.BOOL, + default: true, + } }, data: { /** Answers the participant gave. */ @@ -145,7 +153,8 @@ class ClozePlugin implements JsPsychPlugin { ""; display_element.querySelector("#finish_cloze_button").addEventListener("click", check); - (display_element.querySelector("#input0") as HTMLElement).focus(); + if (trial.autofocus) + (display_element.querySelector("#input0") as HTMLElement).focus(); } private getSolutions(text: string, case_sensitive: boolean): string[][] {