From 098d0ff8b0f2f79ddfab47b951b4ba4ed8eb6aeb Mon Sep 17 00:00:00 2001 From: Shaobin-Jiang Date: Sat, 6 Jan 2024 22:27:56 +0800 Subject: [PATCH 01/11] update package-lock.json --- package-lock.json | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/package-lock.json b/package-lock.json index 1db05357..1cdc7ef3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3095,6 +3095,10 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@jspsych-contrib/extension-countdown": { + "resolved": "packages/extension-countdown", + "link": true + }, "node_modules/@jspsych-contrib/extension-device-motion": { "resolved": "packages/extension-device-motion", "link": true @@ -16536,6 +16540,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "packages/extension-countdown": { + "version": "1.0.0", + "license": "MIT", + "devDependencies": { + "@jspsych/config": "^2.0.0", + "@jspsych/test-utils": "^1.0.0", + "jspsych": "^7.0.0" + }, + "peerDependencies": { + "jspsych": ">=7.0.0" + } + }, "packages/extension-device-motion": { "name": "@jspsych-contrib/extension-device-motion", "version": "1.0.0", @@ -19132,6 +19148,14 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "@jspsych-contrib/extension-countdown": { + "version": "file:packages/extension-countdown", + "requires": { + "@jspsych/config": "^2.0.0", + "@jspsych/test-utils": "^1.0.0", + "jspsych": "^7.0.0" + } + }, "@jspsych-contrib/extension-device-motion": { "version": "file:packages/extension-device-motion", "requires": { From 9d6ff402cc9acb94bbe07798d450f659ac5c6297 Mon Sep 17 00:00:00 2001 From: Shaobin-Jiang Date: Sat, 6 Jan 2024 22:29:07 +0800 Subject: [PATCH 02/11] set up package configuration --- packages/extension-countdown/jest.config.cjs | 1 + packages/extension-countdown/package.json | 45 +++++++++++++++++++ .../extension-countdown/rollup.config.mjs | 3 ++ packages/extension-countdown/tsconfig.json | 7 +++ 4 files changed, 56 insertions(+) create mode 100644 packages/extension-countdown/jest.config.cjs create mode 100644 packages/extension-countdown/package.json create mode 100644 packages/extension-countdown/rollup.config.mjs create mode 100644 packages/extension-countdown/tsconfig.json diff --git a/packages/extension-countdown/jest.config.cjs b/packages/extension-countdown/jest.config.cjs new file mode 100644 index 00000000..6ac19d5c --- /dev/null +++ b/packages/extension-countdown/jest.config.cjs @@ -0,0 +1 @@ +module.exports = require("@jspsych/config/jest").makePackageConfig(__dirname); diff --git a/packages/extension-countdown/package.json b/packages/extension-countdown/package.json new file mode 100644 index 00000000..2738e840 --- /dev/null +++ b/packages/extension-countdown/package.json @@ -0,0 +1,45 @@ +{ + "name": "@jspsych-contrib/extension-countdown", + "private": "true", + "version": "1.0.0", + "description": "jsPsych extension for adding a countdown for a trial", + "type": "module", + "main": "dist/index.cjs", + "exports": { + "import": "./dist/index.js", + "require": "./dist/index.cjs" + }, + "typings": "dist/index.d.ts", + "unpkg": "dist/index.browser.min.js", + "files": [ + "src", + "dist" + ], + "source": "src/index.ts", + "scripts": { + "test": "jest", + "test:watch": "npm test -- --watch", + "tsc": "tsc", + "build": "rollup --config", + "build:watch": "npm run build -- --watch" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/jspsych/jspsych-contrib.git", + "directory": "packages/extension-countdown" + }, + "author": "Shaobin Jiang", + "license": "MIT", + "bugs": { + "url": "https://github.com/jspsych/jspsych-contrib/issues" + }, + "homepage": "https://github.com/jspsych/jspsych-contrib/tree/main/packages/extension-countdown", + "peerDependencies": { + "jspsych": ">=7.0.0" + }, + "devDependencies": { + "@jspsych/config": "^2.0.0", + "@jspsych/test-utils": "^1.0.0", + "jspsych": "^7.0.0" + } +} diff --git a/packages/extension-countdown/rollup.config.mjs b/packages/extension-countdown/rollup.config.mjs new file mode 100644 index 00000000..3e4c87de --- /dev/null +++ b/packages/extension-countdown/rollup.config.mjs @@ -0,0 +1,3 @@ +import { makeRollupConfig } from "@jspsych/config/rollup"; + +export default makeRollupConfig("jsPsychExtensionCountdown"); diff --git a/packages/extension-countdown/tsconfig.json b/packages/extension-countdown/tsconfig.json new file mode 100644 index 00000000..3eabd0c2 --- /dev/null +++ b/packages/extension-countdown/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "@jspsych/config/tsconfig.contrib.json", + "compilerOptions": { + "baseUrl": "." + }, + "include": ["src"] +} From 1db81efa62fb101dc6bce3d2953f94212571c91f Mon Sep 17 00:00:00 2001 From: Shaobin-Jiang Date: Sat, 6 Jan 2024 22:29:41 +0800 Subject: [PATCH 03/11] extension core code --- packages/extension-countdown/src/index.ts | 87 +++++++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 packages/extension-countdown/src/index.ts diff --git a/packages/extension-countdown/src/index.ts b/packages/extension-countdown/src/index.ts new file mode 100644 index 00000000..1578938f --- /dev/null +++ b/packages/extension-countdown/src/index.ts @@ -0,0 +1,87 @@ +import { JsPsych, JsPsychExtension, JsPsychExtensionInfo } from "jspsych"; + +interface OnStartParameters { + format: (time: number) => string; + time: number; + update_time: number; +} + +/** + * **Extension-Countdown** + * + * jsPsych extension for adding a countdown for a trial + * + * @author Shaobin Jiang + */ +class CountdownExtension implements JsPsychExtension { + static info: JsPsychExtensionInfo = { + name: "countdown", + }; + + constructor(private jsPsych: JsPsych) {} + + private format: (time: number) => string; + private time: number; + private update_time: number; + + private countdown_element: HTMLElement; + private timer: number; + private last_recorded_time: number; + private time_elapsed: number = 0; + private is_running: boolean = true; + + initialize = (): Promise => { + return new Promise((resolve, _) => { + resolve(); + }); + }; + + on_start = ({ + format = (time: number) => String(Math.floor(time / 1000)), + time, + update_time = 50, + }: OnStartParameters): void => { + this.format = format; + this.time = time; + this.update_time = update_time; + + this.countdown_element = document.createElement("div"); + this.countdown_element.innerHTML = this.format(time); + this.countdown_element.className = "jspsych-extension-countdown"; + this.countdown_element.style.cssText = "font-size: 18px; position: fixed; top: 5%; right: 5%;"; + }; + + on_load = (): void => { + this.jsPsych.getDisplayContainerElement().appendChild(this.countdown_element); + this.last_recorded_time = performance.now(); + this.timer = window.setInterval(() => { + let now: number = performance.now(); + if (this.is_running) { + this.time_elapsed += now - this.last_recorded_time; + } + this.last_recorded_time = now; + let time_left = this.time - this.time_elapsed; + if (time_left <= 0) { + window.clearInterval(this.timer); + } else { + this.countdown_element.innerHTML = this.format(time_left); + } + }, this.update_time); + }; + + on_finish = () => { + window.clearInterval(this.timer); + this.countdown_element.remove(); + return {}; + }; + + pause = (): void => { + this.is_running = false; + }; + + resume = (): void => { + this.is_running = true; + }; +} + +export default CountdownExtension; From 5c74fff22861350d0642f19329c0c66d184f22ae Mon Sep 17 00:00:00 2001 From: Shaobin-Jiang Date: Sat, 6 Jan 2024 22:30:00 +0800 Subject: [PATCH 04/11] create test cases --- .../extension-countdown/src/index.spec.ts | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 packages/extension-countdown/src/index.spec.ts diff --git a/packages/extension-countdown/src/index.spec.ts b/packages/extension-countdown/src/index.spec.ts new file mode 100644 index 00000000..21430f8e --- /dev/null +++ b/packages/extension-countdown/src/index.spec.ts @@ -0,0 +1,21 @@ +import htmlButtonResponse from "@jspsych/plugin-html-button-response"; +import { initJsPsych } from "jspsych"; + +import CountdownExtension from "."; + +describe("Countdown Extension", () => { + it("should pass", () => { + const jsPsych = initJsPsych({ + extensions: [{ type: CountdownExtension }], + }); + + let trial = { + type: htmlButtonResponse, + stimulus: "Hello world", + choices: ["Foo", "Bar"], + extensions: [{ type: CountdownExtension, params: { time: 5000 } }], + }; + + jsPsych.run([trial]); + }); +}); From 67b811c71b8ba5813130639fddbab35e3c029c3d Mon Sep 17 00:00:00 2001 From: Shaobin-Jiang Date: Sat, 6 Jan 2024 22:30:15 +0800 Subject: [PATCH 05/11] create documentation --- .../docs/jspsych-countdown.md | 95 +++++++++++++++++++ 1 file changed, 95 insertions(+) create mode 100644 packages/extension-countdown/docs/jspsych-countdown.md diff --git a/packages/extension-countdown/docs/jspsych-countdown.md b/packages/extension-countdown/docs/jspsych-countdown.md new file mode 100644 index 00000000..c5a0a652 --- /dev/null +++ b/packages/extension-countdown/docs/jspsych-countdown.md @@ -0,0 +1,95 @@ +# countdown + +This extension adds a countdown for a trial. + +## Parameters + +### Initialization Parameters + +None + +### Trial Parameters + +Trial parameters can be set when adding the extension to a trial object. + +```javascript +let trial = { + type: jsPsych..., + extensions: [ + {type: jsPsychExtensionWebgazer, params: {...}} + ] +} +``` + +| Parameter | Type | Default Value | Description | +| --------- | ---- | ------------- | ----------- | +| time | number | undefined | Time in milliseconds of the countdown | +| update_time | number | 50 | How often to update the countdown display; in milliseconds | +| format | function | (time) => String(Math.floor(time / 1000)) | The displayed content of the countdown. Receives the current time left in milliseconds and returns a string for display. | + +## Data Generated + +None + +## Functions + +These functions below are provided to enable a better interaction with the countdown. Note that all of the functions below must be prefixed with `jsPsych.extensions.countdown` (e.g. `jsPsych.extensions.countdown.pause()`). + +### `pause()` + +Pauses the countdown. + +### `resume()` + +Resumes the countdown. + +## Example + +```javascript +let jsPsych = initJsPsych({ + extensions: [{ type: jsPsychExtensionCountdown }], +}); + +let trial = { + type: jsPsychHtmlKeyboardResponse, + stimulus: "Hello world", + extensions: [ + { + type: jsPsychExtensionCountdown, + params: { + time: 5000, + update_time: 20, + format: (time) => { + if (time < 3000) { + document.querySelector(".jspsych-extension-countdown").style.color = "red"; + } + + let time_in_seconds = time / 1000; + + let minutes = Math.floor(time_in_seconds / 60); + time_in_seconds -= minutes * 60; + + let seconds = Math.floor(time_in_seconds); + + let format_number = (number) => { + let temp_str = `0${number}`; + return temp_str.substring(temp_str.length - 2); + }; + + return `${format_number(minutes)}:${format_number(seconds)}`; + }, + }, + }, + ], + on_load: function () { + setTimeout(() => { + jsPsych.extensions.countdown.pause(); + setTimeout(() => { + jsPsych.extensions.countdown.resume(); + }, 2000); + }, 1000); + }, +}; + +jsPsych.run([trial]); +``` From 0eba45cab4205dfefd69bdbc081eeca05f17e7d0 Mon Sep 17 00:00:00 2001 From: Shaobin-Jiang Date: Sat, 6 Jan 2024 22:30:29 +0800 Subject: [PATCH 06/11] create examples --- .../extension-countdown/examples/example.html | 64 +++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 packages/extension-countdown/examples/example.html diff --git a/packages/extension-countdown/examples/example.html b/packages/extension-countdown/examples/example.html new file mode 100644 index 00000000..8f6d3eca --- /dev/null +++ b/packages/extension-countdown/examples/example.html @@ -0,0 +1,64 @@ + + + + + + Countdown Extension Example + + + + + + + + + From cd4177a8ecb7f3210e9c54e7921c56d60908c21e Mon Sep 17 00:00:00 2001 From: Shaobin-Jiang Date: Sat, 6 Jan 2024 22:30:40 +0800 Subject: [PATCH 07/11] create changeset --- .changeset/strange-baboons-protect.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/strange-baboons-protect.md diff --git a/.changeset/strange-baboons-protect.md b/.changeset/strange-baboons-protect.md new file mode 100644 index 00000000..6b64558a --- /dev/null +++ b/.changeset/strange-baboons-protect.md @@ -0,0 +1,5 @@ +--- +"@jspsych-contrib/extension-countdown": major +--- + +Added countdown extension. From 30e75d21bf233abe84468b6968221d54e9619d2e Mon Sep 17 00:00:00 2001 From: Shaobin-Jiang Date: Wed, 10 Jan 2024 14:42:13 +0800 Subject: [PATCH 08/11] update README --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 8d166a23..4a4a5a9b 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,7 @@ Plugin/Extension | Contributor | Description [audio-multi-response](https://github.com/jspsych/jspsych-contrib/blob/main/packages/plugin-audio-multi-response/README.md) | [Adam Richie-Halford](https://github.com/richford) | This plugin collects responses to an audio file using both button clicks and key presses. [audio-swipe-response](https://github.com/jspsych/jspsych-contrib/blob/main/packages/plugin-audio-swipe-response/README.md) | [Adam Richie-Halford](https://github.com/richford) | This plugin collects responses to an audio file using swipe gestures and keyboard responses. [corsi-blocks](https://github.com/jspsych/jspsych-contrib/blob/main/packages/plugin-corsi-blocks/README.md) | [Josh de Leeuw](https://github.com/jodeleeuw) | This plugin displays a configurable Corsi blocks task and records a series of click responses. +[countdown](https://github.com/jspsych/jspsych-contrib/blob/main/packages/extension-countdown/README.md) | [Shaobin Jiang](https://github.com/Shaobin-Jiang) | This extension adds a countdown during a trial. [gamepad](https://github.com/jspsych/jspsych-contrib/blob/main/packages/plugin-gamepad/README.md) | [Shaobin Jiang](https://github.com/Shaobin-Jiang) | This plugin allows one to use gamepads in a jsPsych experiment. [html-choice](https://github.com/jspsych/jspsych-contrib/blob/main/packages/plugin-html-choice/README.md) | [Younes Strittmatter](https://github.com/younesStrittmatter) | This plugin displays clickable html elements that can be used to present a choice. [html-multi-response](https://github.com/jspsych/jspsych-contrib/blob/main/packages/plugin-html-multi-response/README.md) | [Adam Richie-Halford](https://github.com/richford) | This plugin collects responses to an arbitrary HTML string using both button clicks and key presses. From 9e24b5cdcd0c69c5f353b5ab448c3c5c1aa097bd Mon Sep 17 00:00:00 2001 From: Shaobin-Jiang Date: Wed, 10 Jan 2024 14:42:35 +0800 Subject: [PATCH 09/11] update description in package.json --- packages/extension-countdown/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/extension-countdown/package.json b/packages/extension-countdown/package.json index 2738e840..24905b5b 100644 --- a/packages/extension-countdown/package.json +++ b/packages/extension-countdown/package.json @@ -2,7 +2,7 @@ "name": "@jspsych-contrib/extension-countdown", "private": "true", "version": "1.0.0", - "description": "jsPsych extension for adding a countdown for a trial", + "description": "jsPsych extension for adding a countdown during a trial", "type": "module", "main": "dist/index.cjs", "exports": { From b106ac31eceff307ad8daf04ad1d2309625fc45c Mon Sep 17 00:00:00 2001 From: Shaobin-Jiang Date: Wed, 10 Jan 2024 14:42:49 +0800 Subject: [PATCH 10/11] update doc --- packages/extension-countdown/docs/jspsych-countdown.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/extension-countdown/docs/jspsych-countdown.md b/packages/extension-countdown/docs/jspsych-countdown.md index c5a0a652..aa8a32ae 100644 --- a/packages/extension-countdown/docs/jspsych-countdown.md +++ b/packages/extension-countdown/docs/jspsych-countdown.md @@ -1,6 +1,6 @@ # countdown -This extension adds a countdown for a trial. +This extension adds a countdown during a trial. ## Parameters From 8a7f30d40752b8d221acfc2c4ddc2c7129a451ba Mon Sep 17 00:00:00 2001 From: Shaobin-Jiang Date: Thu, 11 Jan 2024 11:48:53 +0800 Subject: [PATCH 11/11] modify version and private flag in package.json --- packages/extension-countdown/package.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/extension-countdown/package.json b/packages/extension-countdown/package.json index 24905b5b..3016adb8 100644 --- a/packages/extension-countdown/package.json +++ b/packages/extension-countdown/package.json @@ -1,7 +1,6 @@ { "name": "@jspsych-contrib/extension-countdown", - "private": "true", - "version": "1.0.0", + "version": "0.0.1", "description": "jsPsych extension for adding a countdown during a trial", "type": "module", "main": "dist/index.cjs",