diff --git a/examples/end-active-node.html b/examples/abort-current-timeline.html similarity index 96% rename from examples/end-active-node.html rename to examples/abort-current-timeline.html index eb271b4c..953e0d6a 100644 --- a/examples/end-active-node.html +++ b/examples/abort-current-timeline.html @@ -5,7 +5,7 @@ - + diff --git a/examples/end-experiment.html b/examples/abort-experiment.html similarity index 90% rename from examples/end-experiment.html rename to examples/abort-experiment.html index df01ae3d..9927a7a9 100644 --- a/examples/end-experiment.html +++ b/examples/abort-experiment.html @@ -4,7 +4,7 @@ - + diff --git a/packages/jspsych/core-changes.md b/packages/jspsych/core-changes.md index 0503c446..807aa41d 100644 --- a/packages/jspsych/core-changes.md +++ b/packages/jspsych/core-changes.md @@ -10,3 +10,4 @@ A growing list of implemented 8.0 changes so we don't loose track - Drop `jsPsych.data.getDataByTimelineNode()` since nodes have no IDs anymore - Trial results do no longer have the `internal_node_id` property - `save_trial_parameters` can only be used to remove parameters that are specified in the plugin info +- `endExperiment()` and `endCurrentTimeline()` => `abortExperiment()` and `abortCurrentTimeline()` diff --git a/packages/jspsych/src/JsPsych.ts b/packages/jspsych/src/JsPsych.ts index f21ae9a4..27c26a81 100644 --- a/packages/jspsych/src/JsPsych.ts +++ b/packages/jspsych/src/JsPsych.ts @@ -176,7 +176,7 @@ export class JsPsych { getProgress() { return { total_trials: this.timeline?.getNaiveTrialCount(), - current_trial_global: 0, // TODO This used to be `this.global_trial_index` – is a global trial index still needed / does it make sense and, if so, how should it be maintained? + current_trial_global: this.timeline?.getLatestNode().index ?? 0, percent_complete: this.timeline?.getNaiveProgress() * 100, }; } @@ -200,8 +200,7 @@ export class JsPsych { return this.domContainer; } - // TODO Should this be called `abortExperiment()`? - endExperiment(endMessage?: string, data = {}) { + abortExperiment(endMessage?: string, data = {}) { this.endMessage = endMessage; this.timeline.abort(); this.pluginAPI.cancelAllKeyboardResponses(); @@ -209,9 +208,14 @@ export class JsPsych { this.finishTrial(data); } - // TODO Is there a legit use case for this "global" function that cannot be achieved with callback functions in trial/timeline descriptions? - endCurrentTimeline() { - // this.timeline.endActiveNode(); + abortCurrentTimeline() { + let currentTimeline = this.timeline?.getLatestNode(); + if (currentTimeline instanceof Trial) { + currentTimeline = currentTimeline.parent; + } + if (currentTimeline instanceof Timeline) { + currentTimeline.abort(); + } } getCurrentTrial() { @@ -254,7 +258,7 @@ export class JsPsych { } getTimeline() { - return this.timeline?.description; + return this.timeline?.description.timeline; } get extensions() { diff --git a/packages/jspsych/tests/core/endexperiment.test.ts b/packages/jspsych/tests/core/abortexperiment.test.ts similarity index 93% rename from packages/jspsych/tests/core/endexperiment.test.ts rename to packages/jspsych/tests/core/abortexperiment.test.ts index 45edc29d..abb086c7 100644 --- a/packages/jspsych/tests/core/endexperiment.test.ts +++ b/packages/jspsych/tests/core/abortexperiment.test.ts @@ -11,7 +11,7 @@ test("works on basic timeline", async () => { type: htmlKeyboardResponse, stimulus: "trial 1", on_finish: () => { - jsPsych.endExperiment("the end"); + jsPsych.abortExperiment("the end"); }, }, { @@ -35,7 +35,7 @@ test("works with looping timeline (#541)", async () => { { timeline: [{ type: htmlKeyboardResponse, stimulus: "trial 1" }], loop_function: () => { - jsPsych.endExperiment("the end"); + jsPsych.abortExperiment("the end"); }, }, ], @@ -64,7 +64,7 @@ test("if on_finish returns a Promise, wait for resolve before showing end messag type: htmlKeyboardResponse, stimulus: "foo", on_finish: () => { - jsPsych.endExperiment("done"); + jsPsych.abortExperiment("done"); }, }, { diff --git a/packages/jspsych/tests/core/simulation-mode.test.ts b/packages/jspsych/tests/core/simulation-mode.test.ts index cceebee3..ec4d4c3a 100644 --- a/packages/jspsych/tests/core/simulation-mode.test.ts +++ b/packages/jspsych/tests/core/simulation-mode.test.ts @@ -1,7 +1,7 @@ import htmlKeyboardResponse from "@jspsych/plugin-html-keyboard-response"; import { clickTarget, pressKey, simulateTimeline } from "@jspsych/test-utils"; -import { JsPsych, JsPsychPlugin, ParameterType, TrialType, initJsPsych } from "../../src"; +import { JsPsych, ParameterType, initJsPsych } from "../../src"; jest.useFakeTimers(); @@ -306,7 +306,7 @@ describe("data simulation mode", () => { expect(getData().values()[2].rt).toBe(200); }); - test("endExperiment() works in simulation mode", async () => { + test("abortExperiment() works in simulation mode", async () => { const jsPsych = initJsPsych(); const timeline = [ @@ -314,7 +314,7 @@ describe("data simulation mode", () => { type: htmlKeyboardResponse, stimulus: "foo", on_finish: () => { - jsPsych.endExperiment("done"); + jsPsych.abortExperiment("done"); }, }, { diff --git a/packages/jspsych/tests/core/timelines.test.ts b/packages/jspsych/tests/core/timelines.test.ts index f60a309c..cdb3e847 100644 --- a/packages/jspsych/tests/core/timelines.test.ts +++ b/packages/jspsych/tests/core/timelines.test.ts @@ -378,8 +378,7 @@ describe("conditional function", () => { }); }); -// TODO Do we need `endCurrentTimeline`? -describe.skip("endCurrentTimeline", () => { +describe("endCurrentTimeline", () => { test("stops the current timeline, skipping to the end after the trial completes", async () => { const jsPsych = initJsPsych(); const { getHTML } = await startTimeline( @@ -390,7 +389,7 @@ describe.skip("endCurrentTimeline", () => { type: htmlKeyboardResponse, stimulus: "foo", on_finish: () => { - jsPsych.endCurrentTimeline(); + jsPsych.abortCurrentTimeline(); }, }, { @@ -425,7 +424,7 @@ describe.skip("endCurrentTimeline", () => { type: htmlKeyboardResponse, stimulus: "foo", on_finish: () => { - jsPsych.endCurrentTimeline(); + jsPsych.abortCurrentTimeline(); }, }, { @@ -485,29 +484,3 @@ describe("nested timelines", () => { await pressKey("a"); }); }); - -// TODO Should we have such a function? -// describe("add node to end of timeline", () => { -// test("adds node to end of timeline", async () => { -// const jsPsych = initJsPsych(); -// const { getHTML } = await startTimeline( -// [ -// { -// type: htmlKeyboardResponse, -// stimulus: "foo", -// on_start: () => { -// jsPsych.addNodeToEndOfTimeline({ -// timeline: [{ type: htmlKeyboardResponse, stimulus: "bar" }], -// }); -// }, -// }, -// ], -// jsPsych -// ); - -// expect(getHTML()).toMatch("foo"); -// await pressKey("a"); -// expect(getHTML()).toMatch("bar"); -// await pressKey("a"); -// }); -// }); diff --git a/packages/plugin-browser-check/src/index.ts b/packages/plugin-browser-check/src/index.ts index 912cc189..4fb0b7db 100644 --- a/packages/plugin-browser-check/src/index.ts +++ b/packages/plugin-browser-check/src/index.ts @@ -373,7 +373,7 @@ class BrowserCheckPlugin implements JsPsychPlugin { const trial_data = { ...Object.fromEntries(feature_data) }; - this.jsPsych.endExperiment(this.t.exclusion_message(trial_data), trial_data); + this.jsPsych.abortExperiment(this.t.exclusion_message(trial_data), trial_data); } simulate( @@ -429,7 +429,7 @@ class BrowserCheckPlugin implements JsPsychPlugin { if (trial.inclusion_function(data)) { this.jsPsych.finishTrial(data); } else { - this.jsPsych.endExperiment(trial.exclusion_message(data), data); + this.jsPsych.abortExperiment(trial.exclusion_message(data), data); } }); }