From 22c1da9780bbda16882785e200f248d5cc8b1610 Mon Sep 17 00:00:00 2001 From: Becky Gilbert Date: Thu, 13 Nov 2025 13:17:34 -0800 Subject: [PATCH 1/8] add prompt param to image-hotspots and add to display --- packages/plugin-image-hotspots/src/index.ts | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/packages/plugin-image-hotspots/src/index.ts b/packages/plugin-image-hotspots/src/index.ts index 4962ad94..3ff652f3 100644 --- a/packages/plugin-image-hotspots/src/index.ts +++ b/packages/plugin-image-hotspots/src/index.ts @@ -26,6 +26,11 @@ const info = { type: ParameterType.STRING, default: "background-color: rgba(255, 255, 0, 0.3); border: 2px solid yellow;", }, + /** This string can contain HTML markup. Any content here will be displayed below the stimulus. The intention is that it can be used to provide a reminder about the action the participant is supposed to take (e.g., click on a specific area). */ + prompt: { + type: ParameterType.HTML_STRING, + default: null, + }, }, data: { /** The ID of the clicked hotspot region. */ @@ -68,12 +73,16 @@ class ImageHotspotsPlugin implements JsPsychPlugin { const start_time = performance.now(); // Create the HTML structure - const html = ` + let html = `
`; + // Add prompt if there is one + if (trial.prompt !== null) { + html += trial.prompt; + } display_element.innerHTML = html; From 77ceb32ed13ef1f8f8a0524b6cdb2f1f3c6e8c8a Mon Sep 17 00:00:00 2001 From: Becky Gilbert Date: Thu, 13 Nov 2025 13:18:39 -0800 Subject: [PATCH 2/8] add test for image-hotspots prompt param --- .../plugin-image-hotspots/src/index.spec.ts | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/packages/plugin-image-hotspots/src/index.spec.ts b/packages/plugin-image-hotspots/src/index.spec.ts index 312c9f43..0239402e 100644 --- a/packages/plugin-image-hotspots/src/index.spec.ts +++ b/packages/plugin-image-hotspots/src/index.spec.ts @@ -243,4 +243,27 @@ describe("jsPsychImageHotspots plugin", () => { const data = getData().values()[0]; expect(data.hotspot_clicked).toBeNull(); }); + + it("should show prompt if there is one", async () => { + const { expectFinished, getHTML, getData, displayElement } = await startTimeline([ + { + type: jsPsychImageHotspots, + stimulus: "test.jpg", + prompt: "

This is a prompt

", + hotspots: [ + { + id: "test_hotspot", + x: 50, + y: 50, + width: 100, + height: 100, + }, + ], + }, + ]); + + expect(getHTML()).toContain(` + +

This is a prompt

`); + }); }); From edc33e8c3b9ba2c58a0ac33be0c18df6b672863b Mon Sep 17 00:00:00 2001 From: Becky Gilbert Date: Thu, 13 Nov 2025 13:19:51 -0800 Subject: [PATCH 3/8] add prompt param to image-hotspots docs --- packages/plugin-image-hotspots/docs/plugin-image-hotspots.md | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/plugin-image-hotspots/docs/plugin-image-hotspots.md b/packages/plugin-image-hotspots/docs/plugin-image-hotspots.md index c9c7034c..4248e339 100644 --- a/packages/plugin-image-hotspots/docs/plugin-image-hotspots.md +++ b/packages/plugin-image-hotspots/docs/plugin-image-hotspots.md @@ -12,6 +12,7 @@ In addition to the [parameters available in all plugins](https://www.jspsych.org | hotspots | complex | [] | Array of hotspot regions. Each hotspot should have x, y, width, height, and id properties. | | trial_duration | int | null | How long to show the trial in milliseconds. If null, the trial will wait for a response. | | hotspot_highlight_css | string | "background-color: rgba(255, 255, 0, 0.3); border: 2px solid yellow;" | CSS string to style the hotspot highlight overlay that appears when clicking/touching a region. | +| prompt | string | null | This string can contain HTML markup. Any content here will be displayed below the stimulus. The intention is that it can be used to provide a reminder about the action the participant is supposed to take (e.g., click on a specific area). | ### Hotspot Object Properties From 28c350d18ea9c426f323cc107bd835e1ae94008f Mon Sep 17 00:00:00 2001 From: Becky Gilbert Date: Thu, 13 Nov 2025 13:21:02 -0800 Subject: [PATCH 4/8] add prompt and show_prompt_on_video_end params to video-hotspots --- packages/plugin-video-hotspots/src/index.ts | 29 ++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/packages/plugin-video-hotspots/src/index.ts b/packages/plugin-video-hotspots/src/index.ts index 2105cf27..d749d137 100644 --- a/packages/plugin-video-hotspots/src/index.ts +++ b/packages/plugin-video-hotspots/src/index.ts @@ -31,6 +31,16 @@ const info = { type: ParameterType.BOOL, default: true, }, + /** This string can contain HTML markup. Any content here will be displayed below the stimulus. The intention is that it can be used to provide a reminder about the action the participant is supposed to take (e.g., click on a specific area). */ + prompt: { + type: ParameterType.HTML_STRING, + default: null, + }, + /** Whether to wait until the video ends to display the prompt string (if there is one). If true (the default), the prompt will be shown when the video has ended. If false, the prompt is shown immediately. */ + show_prompt_on_video_end: { + type: ParameterType.BOOL, + default: true, + }, }, data: { /** The ID of the clicked hotspot region. */ @@ -77,7 +87,7 @@ class VideoHotspotsPlugin implements JsPsychPlugin { let video_end_time: number | null = null; // Create the HTML structure - const html = ` + let html = `
`; + // Add prompt if there is one + if (trial.prompt !== null) { + if (trial.show_prompt_on_video_end) { + // Add to the DOM and toggle visibility after video ends, rather than adding a new element later (which causes content position jump) + html += ``; + } else { + html += trial.prompt; + } + } display_element.innerHTML = html; @@ -258,6 +277,14 @@ class VideoHotspotsPlugin implements JsPsychPlugin { // Create hotspots now that video has ended createHotspots(); + // Add prompt if there is one and it should be shown when the video ends + if (trial.prompt !== null && trial.show_prompt_on_video_end) { + const prompt = display_element.querySelector( + "#jspsych-video-hotspots-prompt" + ) as HTMLSpanElement; + prompt.style.visibility = "visible"; + } + // Handle trial duration after video ends if (trial.trial_duration !== null) { this.jsPsych.pluginAPI.setTimeout(() => { From fd1c31ffcb2bd6c168170ae35270efd59afdbd25 Mon Sep 17 00:00:00 2001 From: Becky Gilbert Date: Thu, 13 Nov 2025 13:22:11 -0800 Subject: [PATCH 5/8] add tests for video-hotspots prompt and show_prompt_on_video_end params --- .../plugin-video-hotspots/src/index.spec.ts | 58 +++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/packages/plugin-video-hotspots/src/index.spec.ts b/packages/plugin-video-hotspots/src/index.spec.ts index 4f0280a9..93f461e4 100644 --- a/packages/plugin-video-hotspots/src/index.spec.ts +++ b/packages/plugin-video-hotspots/src/index.spec.ts @@ -235,4 +235,62 @@ describe("jsPsychVideoHotspots plugin", () => { expect(Number.isInteger(data.click_x)).toBe(true); expect(Number.isInteger(data.click_y)).toBe(true); }); + + it("should show prompt after video ends", async () => { + const { expectFinished, getHTML, getData, displayElement } = await startTimeline([ + { + type: jsPsychVideoHotspots, + stimulus: "test.mp4", + prompt: "

This is a prompt

", + hotspots: [ + { + id: "test_hotspot", + x: 50, + y: 50, + width: 100, + height: 100, + }, + ], + }, + ]); + + expect(getHTML()).toContain( + `