mirror of
https://github.com/jspsych/jsPsych.git
synced 2025-05-10 11:10:54 +00:00
Merge pull request #2079 from bjoluc/preload
Implement `preload` flag for plugin parameters
This commit is contained in:
commit
5152f52977
@ -170,6 +170,13 @@ export class JsPsych {
|
||||
|
||||
document.documentElement.setAttribute("jspsych", "present");
|
||||
|
||||
// Register preloading for the plugins referenced in the timeline
|
||||
for (const [pluginName, parameters] of this.timeline.extractPreloadParameters()) {
|
||||
for (const [parameter, type] of Object.entries(parameters)) {
|
||||
this.pluginAPI.registerPreload(pluginName, parameter, type);
|
||||
}
|
||||
}
|
||||
|
||||
this.startExperiment();
|
||||
await this.finished;
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { JsPsych } from "./JsPsych";
|
||||
import { parameterType } from "./modules/plugins";
|
||||
import {
|
||||
repeat,
|
||||
sampleWithReplacement,
|
||||
@ -533,4 +534,54 @@ export class TimelineNode {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts a map that, for each of the timeline's (nested) plugins, maps the plugin name to an
|
||||
* object that maps media parameters to their corresponding `preload` type, if not prevented by a
|
||||
* `preload: false` flag in a parameter's description.
|
||||
*/
|
||||
extractPreloadParameters() {
|
||||
type PreloadType = "audio" | "image" | "video";
|
||||
const preloadMap = new Map<string, Record<string, PreloadType>>();
|
||||
|
||||
/** Maps parameter types to their corresponding preload type */
|
||||
const parameterTypeMap = new Map<number, PreloadType>([
|
||||
[parameterType.AUDIO, "audio"],
|
||||
[parameterType.IMAGE, "image"],
|
||||
[parameterType.VIDEO, "video"],
|
||||
]);
|
||||
|
||||
function recurseTimeline(node: TimelineNode) {
|
||||
const isTimeline = typeof node.timeline_parameters !== "undefined";
|
||||
|
||||
if (isTimeline) {
|
||||
for (const childNode of node.timeline_parameters.timeline) {
|
||||
recurseTimeline(childNode);
|
||||
}
|
||||
} else if (node.trial_parameters.type.info) {
|
||||
// node is a trial with type.info set
|
||||
|
||||
// Get the plugin name and parameters object from the info object
|
||||
const { name: pluginName, parameters } = node.trial_parameters.type.info;
|
||||
|
||||
if (!preloadMap.has(pluginName)) {
|
||||
preloadMap.set(
|
||||
pluginName,
|
||||
Object.fromEntries(
|
||||
Object.entries<any>(parameters)
|
||||
// Filter out parameter entries with media types and a non-false `preload` option
|
||||
.filter(
|
||||
([_name, { type, preload }]) => parameterTypeMap.has(type) && (preload ?? true)
|
||||
)
|
||||
// Map each entry's value to its preload type
|
||||
.map(([name, { type }]) => [name, parameterTypeMap.get(type)])
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
recurseTimeline(this);
|
||||
return preloadMap;
|
||||
}
|
||||
}
|
||||
|
@ -47,14 +47,15 @@ type ParameterTypeMap = {
|
||||
13: any; // TIMELINE
|
||||
};
|
||||
|
||||
interface ParameterInfo {
|
||||
export interface ParameterInfo {
|
||||
type: keyof ParameterTypeMap;
|
||||
array?: boolean;
|
||||
pretty_name?: string;
|
||||
default?: any;
|
||||
preload?: "image" | "video" | "audio";
|
||||
}
|
||||
|
||||
interface ParameterInfos {
|
||||
export interface ParameterInfos {
|
||||
[key: string]: ParameterInfo;
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
import htmlKeyboardResponse from "@jspsych/plugin-html-keyboard-response";
|
||||
|
||||
import { initJsPsych } from "../../src";
|
||||
import { initJsPsych, parameterType } from "../../src";
|
||||
import { TimelineNode } from "../../src/TimelineNode";
|
||||
import { pressKey, startTimeline } from "../utils";
|
||||
|
||||
describe("loop function", () => {
|
||||
@ -508,3 +509,89 @@ describe("add node to end of timeline", () => {
|
||||
pressKey("a");
|
||||
});
|
||||
});
|
||||
|
||||
describe("TimelineNode", () => {
|
||||
const createTimelineNode = (parameters) => new TimelineNode(initJsPsych(), parameters);
|
||||
|
||||
describe("extractPreloadParameters", () => {
|
||||
it("works for a single trial", () => {
|
||||
const preloadMap = createTimelineNode({
|
||||
type: {
|
||||
info: {
|
||||
name: "my-plugin",
|
||||
parameters: {
|
||||
one: { type: parameterType.IMAGE },
|
||||
two: { type: parameterType.VIDEO },
|
||||
three: { type: parameterType.AUDIO },
|
||||
four: { type: parameterType.IMAGE, preload: true },
|
||||
five: { type: parameterType.IMAGE, preload: false },
|
||||
six: {
|
||||
type: parameterType.STRING,
|
||||
// This is illegal! But it should still not be added
|
||||
preload: true,
|
||||
},
|
||||
seven: {},
|
||||
},
|
||||
},
|
||||
},
|
||||
}).extractPreloadParameters();
|
||||
|
||||
expect(preloadMap.get("my-plugin")).toEqual({
|
||||
one: "image",
|
||||
two: "video",
|
||||
three: "audio",
|
||||
four: "image",
|
||||
});
|
||||
});
|
||||
|
||||
it("works for a nested timeline", () => {
|
||||
const preloadMap = createTimelineNode({
|
||||
timeline: [
|
||||
{
|
||||
type: {
|
||||
info: {
|
||||
name: "plugin1",
|
||||
parameters: { one: { type: parameterType.STRING } },
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
type: {
|
||||
info: {
|
||||
name: "plugin2",
|
||||
parameters: { one: { type: parameterType.AUDIO } },
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
timeline: [
|
||||
{
|
||||
type: {
|
||||
info: {
|
||||
name: "plugin3",
|
||||
parameters: {
|
||||
one: { type: parameterType.VIDEO },
|
||||
two: { type: parameterType.IMAGE },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
}).extractPreloadParameters();
|
||||
|
||||
expect(preloadMap.get("plugin1")).toEqual({});
|
||||
expect(preloadMap.get("plugin2")).toEqual({ one: "audio" });
|
||||
expect(preloadMap.get("plugin3")).toEqual({ one: "video", two: "image" });
|
||||
});
|
||||
|
||||
it("ignores trials with a function type", () => {
|
||||
const preloadMap = createTimelineNode({
|
||||
type: () => ({ info: { name: "my-dynamic-trial-type" } }),
|
||||
}).extractPreloadParameters();
|
||||
|
||||
expect(preloadMap.size).toEqual(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user