jspsych
Version:
Behavioral experiments in a browser
995 lines (968 loc) • 39.2 kB
TypeScript
import { SetRequired, Class } from 'type-fest';
/**
* Parameter types for plugins
*/
declare enum ParameterType {
BOOL = 0,
STRING = 1,
INT = 2,
FLOAT = 3,
FUNCTION = 4,
KEY = 5,
KEYS = 6,
SELECT = 7,
HTML_STRING = 8,
IMAGE = 9,
AUDIO = 10,
VIDEO = 11,
OBJECT = 12,
COMPLEX = 13,
TIMELINE = 14
}
type ParameterTypeMap = {
[ParameterType.BOOL]: boolean;
[ParameterType.STRING]: string;
[ParameterType.INT]: number;
[ParameterType.FLOAT]: number;
[ParameterType.FUNCTION]: (...args: any[]) => any;
[ParameterType.KEY]: string;
[ParameterType.KEYS]: string[] | "ALL_KEYS" | "NO_KEYS";
[ParameterType.SELECT]: any;
[ParameterType.HTML_STRING]: string;
[ParameterType.IMAGE]: string;
[ParameterType.AUDIO]: string;
[ParameterType.VIDEO]: string;
[ParameterType.OBJECT]: object;
[ParameterType.COMPLEX]: any;
[ParameterType.TIMELINE]: any;
};
type PreloadParameterType = ParameterType.AUDIO | ParameterType.VIDEO | ParameterType.IMAGE;
type ParameterInfo = ({
type: Exclude<ParameterType, ParameterType.COMPLEX | PreloadParameterType>;
} | {
type: ParameterType.COMPLEX;
nested?: ParameterInfos;
} | {
type: PreloadParameterType;
preload?: boolean;
}) & {
array?: boolean;
pretty_name?: string;
default?: any;
};
type ParameterInfos = Record<string, ParameterInfo>;
type InferredParameter<I extends ParameterInfo> = I["array"] extends true ? Array<ParameterTypeMap[I["type"]]> : ParameterTypeMap[I["type"]];
type RequiredParameterNames<I extends ParameterInfos> = {
[K in keyof I]: I[K]["default"] extends undefined ? K : never;
}[keyof I];
type InferredParameters<I extends ParameterInfos> = SetRequired<{
[Property in keyof I]?: InferredParameter<I[Property]>;
}, RequiredParameterNames<I>>;
interface PluginInfo {
name: string;
version?: string;
parameters: ParameterInfos;
data?: ParameterInfos;
citations?: Record<string, string> | string;
}
interface JsPsychPlugin<I extends PluginInfo> {
trial(display_element: HTMLElement, trial: TrialType<I>, on_load?: () => void): void | Promise<TrialResult | void>;
simulate?(trial: TrialType<I>, simulation_mode: SimulationMode, simulation_options: SimulationOptions, on_load?: () => void): void | Promise<TrialResult | void>;
}
type TrialType<I extends PluginInfo> = InferredParameters<I["parameters"]> & TrialDescription;
interface JsPsychExtensionInfo {
name: string;
version?: string;
data?: ParameterInfos;
citations?: Record<string, string> | string;
}
interface JsPsychExtension {
/**
* Called once at the start of the experiment to initialize the extension
*/
initialize(params?: Record<string, any>): Promise<void>;
/**
* Called at the start of a trial, prior to invoking the plugin's trial method.
*/
on_start(params?: Record<string, any>): void;
/**
* Called during a trial, after the plugin makes initial changes to the DOM.
*/
on_load(params?: Record<string, any>): void;
/**
* Called at the end of the trial.
* @returns Data to append to the trial's data object.
*/
on_finish(params?: Record<string, any>): Record<string, any> | Promise<Record<string, any>>;
}
type GetParameterValueOptions = {
/**
* If true, and the retrieved parameter value is a function, invoke the function and return its
* return value (defaults to `true`)
*/
evaluateFunctions?: boolean;
/**
* Whether to fall back to parent timeline node parameters (defaults to `true`)
*/
recursive?: boolean;
/**
* Whether the timeline node should cache the parameter lookup result for successive lookups,
* including those of nested properties or array elements (defaults to `true`)
*/
cacheResult?: boolean;
/**
* A function that will be invoked with the original result of the parameter value lookup.
* Whatever it returns will subsequently be used instead of the original result. This allows to
* modify results before they are cached.
*/
replaceResult?: (originalResult: any) => any;
};
declare abstract class TimelineNode {
protected readonly dependencies: TimelineNodeDependencies;
abstract readonly description: TimelineDescription | TrialDescription | TimelineArray;
/**
* The globally unique trial index of this node. It is set when the node is run. Timeline nodes
* have the same trial index as their first trial.
*/
index?: number;
abstract readonly parent?: Timeline;
abstract run(): Promise<void>;
/**
* Returns a flat array of all currently available results of this node
*/
abstract getResults(): TrialResult[];
/**
* Recursively evaluates the given timeline variable, starting at the current timeline node.
* Returns the result, or `undefined` if the variable is neither specified in the timeline
* description of this node, nor in the description of any parent node.
*/
abstract evaluateTimelineVariable(variable: TimelineVariable): any;
/**
* Returns the most recent (child) TimelineNode. For trial nodes, this is always the trial node
* itself since trial nodes do not have child nodes. For timeline nodes, the return value is a
* Trial object most of the time, but it may also be a Timeline object when a timeline hasn't yet
* instantiated its children (e.g. during initial timeline callback functions).
*/
abstract getLatestNode(): TimelineNode;
/**
* Returns an active child timeline (or itself) that matches the given name, or `undefined` if no such child exists.
*/
abstract getActiveTimelineByName(name: string): Timeline | undefined;
protected status: TimelineNodeStatus;
constructor(dependencies: TimelineNodeDependencies);
getStatus(): TimelineNodeStatus;
private parameterValueCache;
/**
* Initializes the parameter value cache with `this.description`. To be called by subclass
* constructors after setting `this.description`.
*/
protected initializeParameterValueCache(): void;
/**
* Resets all cached parameter values in this timeline node and all of its parents. This is
* necessary to re-evaluate function parameters and timeline variables at each new trial.
*/
protected resetParameterValueCache(): void;
/**
* Retrieves a parameter value from the description of this timeline node, recursively falling
* back to the description of each parent timeline node unless `recursive` is set to `false`. If
* the parameter...
*
* * is a timeline variable, evaluates the variable and returns the result.
* * is not specified, returns `undefined`.
* * is a function and `evaluateFunctions` is not set to `false`, invokes the function and returns
* its return value
* * has previously been looked up, return the cached result of the previous lookup
*
* @param parameterPath The path of the respective parameter in the timeline node description. If
* the path is an array, nested object properties or array items will be looked up.
* @param options See {@link GetParameterValueOptions}
*/
getParameterValue(parameterPath: string | string[], options?: GetParameterValueOptions): any;
/**
* Retrieves and evaluates the `data` parameter. It is different from other parameters in that
* it's properties may be functions that have to be evaluated, and parent nodes' data parameter
* properties are merged into the result.
*/
getDataParameter(): Record<string, any> | undefined;
}
declare class Timeline extends TimelineNode {
readonly parent?: Timeline;
readonly children: TimelineNode[];
readonly description: TimelineDescription;
constructor(dependencies: TimelineNodeDependencies, description: TimelineDescription | TimelineArray, parent?: Timeline);
private currentChild?;
private shouldAbort;
run(): Promise<void>;
private onStart;
private onFinish;
pause(): void;
private resumePromise;
resume(): void;
/**
* If the timeline is running or paused, aborts the timeline after the current trial has completed
*/
abort(): void;
private instantiateChildNode;
private currentTimelineVariables;
private setCurrentTimelineVariablesByIndex;
/**
* If the timeline has timeline variables, returns the order of `timeline_variables` array indices
* to be used, according to the timeline's `sample` setting. If the timeline has no timeline
* variables, returns `[null]`.
*/
private generateTimelineVariableOrder;
/**
* Returns the current values of all timeline variables, including those from parent timelines
*/
getAllTimelineVariables(): Record<string, any>;
evaluateTimelineVariable(variable: TimelineVariable): any;
getResults(): TrialResult[];
/**
* Returns the naive progress of the timeline (as a fraction), without considering conditional or
* loop functions.
*/
getNaiveProgress(): number;
/**
* Recursively computes the naive number of trials in the timeline, without considering
* conditional or loop functions.
*/
getNaiveTrialCount(): any;
getLatestNode(): any;
getActiveTimelineByName(name: string): Timeline;
}
declare class Trial extends TimelineNode {
readonly description: TrialDescription;
readonly parent: Timeline;
readonly pluginClass: Class<JsPsychPlugin<any>>;
pluginInstance: JsPsychPlugin<any>;
trialObject?: TrialDescription;
index?: number;
private result;
private readonly pluginInfo;
constructor(dependencies: TimelineNodeDependencies, description: TrialDescription, parent: Timeline);
run(): Promise<void>;
private executeTrial;
private invokeTrialMethod;
/**
* Cleanup the trial by removing the display element and removing event listeners
*/
private cleanupTrial;
/**
* Add the CSS classes from the `css_classes` parameter to the display element
*/
private addCssClasses;
/**
* Removes the provided css classes from the display element
*/
private removeCssClasses;
private processResult;
/**
* Runs a callback function retrieved from a parameter value and returns its result.
*
* @param parameterName The name of the parameter to retrieve the callback function from.
* @param callbackParameters The parameters (if any) to be passed to the callback function
*/
private runParameterCallback;
private onStart;
private onLoad;
private onFinish;
evaluateTimelineVariable(variable: TimelineVariable): any;
getParameterValue(parameterPath: string | string[], options?: GetParameterValueOptions): any;
/**
* Retrieves and evaluates the `simulation_options` parameter, considering nested properties and
* global simulation options.
*/
getSimulationOptions(): SimulationOptions;
/**
* Returns the result object of this trial or `undefined` if the result is not yet known or the
* `record_data` trial parameter is `false`.
*/
getResult(): TrialResult;
getResults(): TrialResult[];
/**
* Checks that the parameters provided in the trial description align with the plugin's info
* object, resolves missing parameter values from the parent timeline, resolves timeline variable
* parameters, evaluates parameter functions if the expected parameter type is not `FUNCTION`, and
* sets default values for optional parameters.
*/
private processParameters;
getLatestNode(): this;
getActiveTimelineByName(name: string): Timeline | undefined;
}
/**
* Maintains a promise and offers a function to resolve it. Whenever the promise is resolved, it is
* replaced with a new one.
*/
declare class PromiseWrapper<ResolveType = void> {
constructor();
private promise;
private resolvePromise;
reset(): void;
get(): Promise<ResolveType>;
resolve(value: ResolveType): void;
}
declare class TimelineVariable {
readonly name: string;
constructor(name: string);
}
type Parameter<T> = T | (() => T) | TimelineVariable;
type TrialExtensionsConfiguration = Array<{
type: Class<JsPsychExtension>;
params?: Record<string, any>;
}>;
type SimulationMode = "visual" | "data-only";
type SimulationOptions = {
data?: Record<string, any>;
mode?: SimulationMode;
simulate?: boolean;
};
type SimulationOptionsParameter = Parameter<{
data?: Parameter<Record<string, Parameter<any>>>;
mode?: Parameter<SimulationMode>;
simulate?: Parameter<boolean>;
}>;
interface TrialDescription extends Record<string, any> {
type: Parameter<Class<JsPsychPlugin<any>>>;
/** https://www.jspsych.org/latest/overview/plugins/#the-post_trial_gap-iti-parameter */
post_trial_gap?: Parameter<number>;
/** https://www.jspsych.org/latest/overview/plugins/#the-save_trial_parameters-parameter */
save_trial_parameters?: Parameter<Record<string, boolean>>;
/**
* Whether to include the values of timeline variables under a `timeline_variables` key. Can be
* `true` to save the values of all timeline variables, or an array of timeline variable names to
* only save specific timeline variables. Defaults to `false`.
*/
save_timeline_variables?: Parameter<boolean | string[]>;
/** https://www.jspsych.org/latest/overview/style/#using-the-css_classes-trial-parameter */
css_classes?: Parameter<string | string[]>;
/** https://www.jspsych.org/latest/overview/simulation/#controlling-simulation-mode-with-simulation_options */
simulation_options?: SimulationOptionsParameter | string;
/** https://www.jspsych.org/latest/overview/extensions/ */
extensions?: Parameter<TrialExtensionsConfiguration>;
/**
* Whether to record the data of this trial. Defaults to `true`.
*/
record_data?: Parameter<boolean>;
/** https://www.jspsych.org/latest/overview/events/#on_start-trial */
on_start?: (trial: any) => void;
/** https://www.jspsych.org/latest/overview/events/#on_load */
on_load?: () => void;
/** https://www.jspsych.org/latest/overview/events/#on_finish-trial */
on_finish?: (data: any) => void;
}
/** https://www.jspsych.org/latest/overview/timeline/#sampling-methods */
type SampleOptions = {
type: "with-replacement";
size: number;
weights?: number[];
} | {
type: "without-replacement";
size: number;
} | {
type: "fixed-repetitions";
size: number;
} | {
type: "alternate-groups";
groups: number[][];
randomize_group_order?: boolean;
} | {
type: "custom";
fn: (ids: number[]) => number[];
};
type TimelineArray = Array<TimelineDescription | TrialDescription | TimelineArray>;
interface TimelineDescription extends Record<string, any> {
timeline: TimelineArray;
timeline_variables?: Record<string, any>[];
name?: string;
/** https://www.jspsych.org/latest/overview/timeline/#repeating-a-set-of-trials */
repetitions?: number;
/** https://www.jspsych.org/latest/overview/timeline/#looping-timelines */
loop_function?: (data: any) => boolean;
/** https://www.jspsych.org/latest/overview/timeline/#conditional-timelines */
conditional_function?: () => boolean;
/** https://www.jspsych.org/latest/overview/timeline/#random-orders-of-trials */
randomize_order?: boolean;
/** https://www.jspsych.org/latest/overview/timeline/#sampling-methods */
sample?: SampleOptions;
/** https://www.jspsych.org/latest/overview/events/#on_timeline_start */
on_timeline_start?: () => void;
/** https://www.jspsych.org/latest/overview/events/#on_timeline_finish */
on_timeline_finish?: () => void;
}
declare enum TimelineNodeStatus {
PENDING = 0,
RUNNING = 1,
PAUSED = 2,
COMPLETED = 3,
ABORTED = 4
}
/**
* Functions and options needed by `TimelineNode`s, provided by the `JsPsych` instance. This
* approach allows to keep the public `JsPsych` API slim and decouples the `JsPsych` and timeline
* node classes, simplifying unit testing.
*/
interface TimelineNodeDependencies {
/**
* Called at the start of a trial, prior to invoking the plugin's trial method.
*/
onTrialStart: (trial: Trial) => void;
/**
* Called when a trial's result data is available, before invoking `onTrialFinished()`.
*/
onTrialResultAvailable: (trial: Trial) => void;
/**
* Called after a trial has finished.
*/
onTrialFinished: (trial: Trial) => void;
/**
* Invoke `on_start` extension callbacks according to `extensionsConfiguration`
*/
runOnStartExtensionCallbacks(extensionsConfiguration: TrialExtensionsConfiguration): void;
/**
* Invoke `on_load` extension callbacks according to `extensionsConfiguration`
*/
runOnLoadExtensionCallbacks(extensionsConfiguration: TrialExtensionsConfiguration): void;
/**
* Invoke `on_finish` extension callbacks according to `extensionsConfiguration` and return a
* joint extensions result object
*/
runOnFinishExtensionCallbacks(extensionsConfiguration: TrialExtensionsConfiguration): Promise<Record<string, any>>;
/**
* Returns the simulation mode or `undefined`, if the experiment is not running in simulation
* mode.
*/
getSimulationMode(): SimulationMode | undefined;
/**
* Returns the global simulation options as passed to `jsPsych.simulate()`
*/
getGlobalSimulationOptions(): Record<string, SimulationOptionsParameter>;
/**
* Given a plugin class, create a new instance of it and return it.
*/
instantiatePlugin: <Info extends PluginInfo>(pluginClass: Class<JsPsychPlugin<Info>>) => JsPsychPlugin<Info>;
/**
* Return JsPsych's display element so it can be provided to plugins
*/
getDisplayElement: () => HTMLElement;
/**
* Return the default inter-trial interval as provided to `initJsPsych()`
*/
getDefaultIti: () => number;
/**
* A `PromiseWrapper` whose promise is resolved with result data whenever `jsPsych.finishTrial()`
* is called.
*/
finishTrialPromise: PromiseWrapper<TrialResult | void>;
/**
* Clear all of the timeouts
*/
clearAllTimeouts: () => void;
}
type TrialResult = Record<string, any>;
declare class DataColumn {
values: any[];
constructor(values?: any[]);
sum(): number;
mean(): number;
median(): any;
min(): any;
max(): any;
count(): number;
variance(): number;
sd(): number;
frequencies(): {};
all(eval_fn: any): boolean;
subset(eval_fn: any): DataColumn;
}
declare class DataCollection {
private trials;
constructor(data?: any[]);
push(new_data: any): this;
join(other_data_collection: DataCollection): this;
top(): DataCollection;
/**
* Queries the first n elements in a collection of trials.
*
* @param n A positive integer of elements to return. A value of
* n that is less than 1 will throw an error.
*
* @return First n objects of a collection of trials. If fewer than
* n trials are available, the trials.length elements will
* be returned.
*
*/
first(n?: number): DataCollection;
/**
* Queries the last n elements in a collection of trials.
*
* @param n A positive integer of elements to return. A value of
* n that is less than 1 will throw an error.
*
* @return Last n objects of a collection of trials. If fewer than
* n trials are available, the trials.length elements will
* be returned.
*
*/
last(n?: number): DataCollection;
values(): any[];
count(): number;
readOnly(): DataCollection;
addToAll(properties: any): this;
addToLast(properties: any): this;
filter(filters: any): DataCollection;
filterCustom(fn: any): DataCollection;
filterColumns(columns: Array<string>): DataCollection;
select(column: any): DataColumn;
ignore(columns: any): DataCollection;
uniqueNames(): any[];
csv(): string;
json(pretty?: boolean): string;
localSave(format: any, filename: any): void;
}
type InteractionEvent = "blur" | "focus" | "fullscreenenter" | "fullscreenexit";
interface InteractionRecord {
event: InteractionEvent;
trial: number;
time: number;
}
/**
* Functions and options needed by the `JsPsychData` module
*/
interface JsPsychDataDependencies {
/**
* Returns progress information for interaction records.
*/
getProgress: () => {
trial: number;
time: number;
};
onInteractionRecordAdded: (record: InteractionRecord) => void;
getDisplayElement: () => HTMLElement;
}
declare class JsPsychData {
private dependencies;
private results;
private resultToTrialMap;
/** Browser interaction event data */
private interactionRecords;
/** Data properties for all trials */
private dataProperties;
private query_string;
constructor(dependencies: JsPsychDataDependencies);
reset(): void;
get(): DataCollection;
getInteractionData(): DataCollection;
write(trial: Trial): void;
addProperties(properties: any): void;
addDataToLastTrial(data: any): void;
getLastTrialData(): DataCollection;
getLastTimelineData(): DataCollection;
displayData(format?: string): void;
urlVariables(): any;
getURLVariable(whichvar: any): any;
private addInteractionRecord;
private interactionListeners;
createInteractionListeners(): void;
removeInteractionListeners(): void;
}
type KeyboardListener = (e: KeyboardEvent) => void;
type ValidResponses = string[] | "ALL_KEYS" | "NO_KEYS";
interface GetKeyboardResponseOptions {
callback_function: any;
valid_responses?: ValidResponses;
rt_method?: "performance" | "audio";
persist?: boolean;
audio_context?: AudioContext;
audio_context_start_time?: number;
allow_held_key?: boolean;
minimum_valid_rt?: number;
}
declare class KeyboardListenerAPI {
private getRootElement;
private areResponsesCaseSensitive;
private minimumValidRt;
constructor(getRootElement: () => Element | undefined, areResponsesCaseSensitive?: boolean, minimumValidRt?: number);
private listeners;
private heldKeys;
private areRootListenersRegistered;
/**
* If not previously done and `this.getRootElement()` returns an element, adds the root key
* listeners to that element.
*/
private registerRootListeners;
private rootKeydownListener;
private toLowerCaseIfInsensitive;
private rootKeyupListener;
private isResponseValid;
getKeyboardResponse({ callback_function, valid_responses, rt_method, persist, audio_context, audio_context_start_time, allow_held_key, minimum_valid_rt, }: GetKeyboardResponseOptions): KeyboardListener;
cancelKeyboardResponse(listener: KeyboardListener): void;
cancelAllKeyboardResponses(): void;
compareKeys(key1: string | null, key2: string | null): boolean;
}
interface AudioPlayerOptions {
useWebAudio: boolean;
audioContext?: AudioContext;
}
interface AudioPlayerInterface {
load(): Promise<void>;
play(): void;
stop(): void;
addEventListener(eventName: string, callback: EventListenerOrEventListenerObject): void;
removeEventListener(eventName: string, callback: EventListenerOrEventListenerObject): void;
}
declare class AudioPlayer implements AudioPlayerInterface {
private audio;
private webAudioBuffer;
private audioContext;
private useWebAudio;
private src;
constructor(src: string, options?: AudioPlayerOptions);
load(): Promise<void>;
play(): void;
stop(): void;
addEventListener(eventName: string, callback: EventListenerOrEventListenerObject): void;
removeEventListener(eventName: string, callback: EventListenerOrEventListenerObject): void;
private getAudioSourceNode;
private preloadWebAudio;
private preloadHTMLAudio;
}
declare class MediaAPI {
useWebaudio: boolean;
constructor(useWebaudio: boolean);
private video_buffers;
getVideoBuffer(videoID: string): any;
private context;
private audio_buffers;
audioContext(): AudioContext;
getAudioPlayer(audioID: string): Promise<AudioPlayer>;
private preload_requests;
private img_cache;
preloadAudio(files: any, callback_complete?: () => void, callback_load?: (filepath: string) => void, callback_error?: (error: any) => void): void;
preloadImages(images: any, callback_complete?: () => void, callback_load?: (filepath: any) => void, callback_error?: (error_msg: any) => void): void;
preloadVideo(videos: any, callback_complete?: () => void, callback_load?: (filepath: any) => void, callback_error?: (error_msg: any) => void): void;
private preloadMap;
getAutoPreloadList(timeline_description: any[]): {
images: string[];
audio: string[];
video: string[];
};
cancelPreloads(): void;
private microphone_recorder;
initializeMicrophoneRecorder(stream: MediaStream): void;
getMicrophoneRecorder(): MediaRecorder;
private camera_stream;
private camera_recorder;
initializeCameraRecorder(stream: MediaStream, opts?: MediaRecorderOptions): void;
/** returns a compatible mimetype string, or null if none from the array are supported. */
private getCompatibleMimeType;
getCameraStream(): MediaStream;
getCameraRecorder(): MediaRecorder;
}
declare class SimulationAPI {
private getDisplayContainerElement;
private setJsPsychTimeout;
constructor(getDisplayContainerElement: () => HTMLElement, setJsPsychTimeout: (callback: () => void, delay: number) => number);
dispatchEvent(event: Event): void;
/**
* Dispatches a `keydown` event for the specified key
* @param key Character code (`.key` property) for the key to press.
*/
keyDown(key: string): void;
/**
* Dispatches a `keyup` event for the specified key
* @param key Character code (`.key` property) for the key to press.
*/
keyUp(key: string): void;
/**
* Dispatches a `keydown` and `keyup` event in sequence to simulate pressing a key.
* @param key Character code (`.key` property) for the key to press.
* @param delay Length of time to wait (ms) before executing action
*/
pressKey(key: string, delay?: number): void;
/**
* Dispatches `mousedown`, `mouseup`, and `click` events on the target element
* @param target The element to click
* @param delay Length of time to wait (ms) before executing action
*/
clickTarget(target: Element, delay?: number): void;
/**
* Sets the value of a target text input
* @param target A text input element to fill in
* @param text Text to input
* @param delay Length of time to wait (ms) before executing action
*/
fillTextInput(target: HTMLInputElement, text: string, delay?: number): void;
/**
* Picks a valid key from `choices`, taking into account jsPsych-specific
* identifiers like "NO_KEYS" and "ALL_KEYS".
* @param choices Which keys are valid.
* @returns A key selected at random from the valid keys.
*/
getValidKey(choices: "NO_KEYS" | "ALL_KEYS" | Array<string> | Array<Array<string>>): any;
mergeSimulationData(default_data: any, simulation_options: any): any;
ensureSimulationDataConsistency(trial: any, data: any): void;
}
/**
* A class that provides a wrapper around the global setTimeout and clearTimeout functions.
*/
declare class TimeoutAPI {
private timeout_handlers;
/**
* Calls a function after a specified delay, in milliseconds.
* @param callback The function to call after the delay.
* @param delay The number of milliseconds to wait before calling the function.
* @returns A handle that can be used to clear the timeout with clearTimeout.
*/
setTimeout(callback: () => void, delay: number): number;
/**
* Clears all timeouts that have been created with setTimeout.
*/
clearAllTimeouts(): void;
}
declare function createJointPluginAPIObject(jsPsych: JsPsych): KeyboardListenerAPI & TimeoutAPI & MediaAPI & SimulationAPI;
type PluginAPI = ReturnType<typeof createJointPluginAPIObject>;
/**
* Uses the `seedrandom` package to replace Math.random() with a seedable PRNG.
*
* @param seed An optional seed. If none is given, a random seed will be generated.
* @returns The seed value.
*/
declare function setSeed(seed?: string): string;
declare function repeat(array: any, repetitions: any, unpack?: boolean): any;
declare function shuffle<T>(array: Array<T>): T[];
declare function shuffleNoRepeats<T>(arr: Array<T>, equalityTest: (a: T, b: T) => boolean): T[];
declare function shuffleAlternateGroups<T extends any[]>(arr_groups: Array<T>, random_group_order?: boolean): any[];
declare function sampleWithoutReplacement<T>(arr: Array<T>, size: number): T[];
declare function sampleWithReplacement<T>(arr: Array<T>, size: number, weights?: number[]): any[];
declare function factorial(factors: Record<string, any>, repetitions?: number, unpack?: boolean): any;
declare function randomID(length?: number): string;
/**
* Generate a random integer from `lower` to `upper`, inclusive of both end points.
* @param lower The lowest value it is possible to generate
* @param upper The highest value it is possible to generate
* @returns A random integer
*/
declare function randomInt(lower: number, upper: number): number;
/**
* Generates a random sample from a Bernoulli distribution.
* @param p The probability of sampling 1.
* @returns 0, with probability 1-p, or 1, with probability p.
*/
declare function sampleBernoulli(p: number): 0 | 1;
declare function sampleNormal(mean: number, standard_deviation: number): number;
declare function sampleExponential(rate: number): number;
declare function sampleExGaussian(mean: number, standard_deviation: number, rate: number, positive?: boolean): number;
type RandomWordsOptions = {
min?: number;
max?: number;
exactly?: number;
maxLength?: number;
wordsPerString?: number;
seperator?: string;
formatter?: (word: string, index: number) => string;
join?: string;
};
type RandomWordsResult<T extends RandomWordsOptions> = T extends {
join: string;
} ? string : string[];
/**
* Generate one or more random words.
*
* This is a wrapper function for the {@link https://www.npmjs.com/package/random-words `random-words` npm package}.
*
* @param opts An object with optional properties `min`, `max`, `exactly`,
* `join`, `maxLength`, `wordsPerString`, `separator`, and `formatter`.
*
* @returns An array of words or a single string, depending on parameter choices.
*/
declare function randomWords<T extends RandomWordsOptions>(opts: T): RandomWordsResult<T>;
declare const randomization_factorial: typeof factorial;
declare const randomization_randomID: typeof randomID;
declare const randomization_randomInt: typeof randomInt;
declare const randomization_randomWords: typeof randomWords;
declare const randomization_repeat: typeof repeat;
declare const randomization_sampleBernoulli: typeof sampleBernoulli;
declare const randomization_sampleExGaussian: typeof sampleExGaussian;
declare const randomization_sampleExponential: typeof sampleExponential;
declare const randomization_sampleNormal: typeof sampleNormal;
declare const randomization_sampleWithReplacement: typeof sampleWithReplacement;
declare const randomization_sampleWithoutReplacement: typeof sampleWithoutReplacement;
declare const randomization_setSeed: typeof setSeed;
declare const randomization_shuffle: typeof shuffle;
declare const randomization_shuffleAlternateGroups: typeof shuffleAlternateGroups;
declare const randomization_shuffleNoRepeats: typeof shuffleNoRepeats;
declare namespace randomization {
export { randomization_factorial as factorial, randomization_randomID as randomID, randomization_randomInt as randomInt, randomization_randomWords as randomWords, randomization_repeat as repeat, randomization_sampleBernoulli as sampleBernoulli, randomization_sampleExGaussian as sampleExGaussian, randomization_sampleExponential as sampleExponential, randomization_sampleNormal as sampleNormal, randomization_sampleWithReplacement as sampleWithReplacement, randomization_sampleWithoutReplacement as sampleWithoutReplacement, randomization_setSeed as setSeed, randomization_shuffle as shuffle, randomization_shuffleAlternateGroups as shuffleAlternateGroups, randomization_shuffleNoRepeats as shuffleNoRepeats };
}
interface turkInformation {
/**
* Is the experiment being loaded in preview mode on Mechanical Turk?
*/
previewMode: boolean;
/**
* Is the experiment being loaded outside of the Mechanical Turk environment?
*/
outsideTurk: boolean;
/**
* The HIT ID.
*/
hitId: string;
/**
* The Assignment ID.
*/
assignmentId: string;
/**
* The worker ID.
*/
workerId: string;
/**
* URL for submission of the HIT.
*/
turkSubmitTo: string;
}
/**
* Gets information about the Mechanical Turk Environment, HIT, Assignment, and Worker
* by parsing the URL variables that Mechanical Turk generates.
* @returns An object containing information about the Mechanical Turk Environment, HIT, Assignment, and Worker.
*/
declare function turkInfo(): turkInformation;
/**
* Send data to Mechnical Turk for storage.
* @param data An object containing `key:value` pairs to send to Mechanical Turk. Values
* cannot contain nested objects, arrays, or functions.
* @returns Nothing
*/
declare function submitToTurk(data: any): void;
declare const turk_submitToTurk: typeof submitToTurk;
declare const turk_turkInfo: typeof turkInfo;
declare namespace turk {
export { turk_submitToTurk as submitToTurk, turk_turkInfo as turkInfo };
}
/**
* Finds all of the unique items in an array.
* @param arr The array to extract unique values from
* @returns An array with one copy of each unique item in `arr`
*/
declare function unique(arr: Array<any>): any[];
declare function deepCopy(obj: any): any;
/**
* Merges two objects, recursively.
* @param obj1 Object to merge
* @param obj2 Object to merge
*/
declare function deepMerge(obj1: any, obj2: any): any;
declare const utils_deepCopy: typeof deepCopy;
declare const utils_deepMerge: typeof deepMerge;
declare const utils_unique: typeof unique;
declare namespace utils {
export { utils_deepCopy as deepCopy, utils_deepMerge as deepMerge, utils_unique as unique };
}
/**
* Maintains a visual progress bar using HTML and CSS
*/
declare class ProgressBar {
private readonly containerElement;
private readonly message;
constructor(containerElement: HTMLDivElement, message: string | ((progress: number) => string));
private _progress;
private innerDiv;
private messageSpan;
/** Adds the progress bar HTML code into `this.containerElement` */
private setupElements;
/** Updates the progress bar according to `this.progress` */
private update;
/**
* The bar's current position as a number in the closed interval [0, 1]. Set this to update the
* progress bar accordingly.
*/
set progress(progress: number);
get progress(): number;
}
declare class JsPsych {
turk: typeof turk;
randomization: typeof randomization;
utils: typeof utils;
data: JsPsychData;
pluginAPI: PluginAPI;
version(): string;
private citation;
/** Options */
private options;
/** Experiment timeline */
private timeline?;
/** Target DOM element */
private displayContainerElement;
private displayElement;
/** Time that the experiment began */
private experimentStartTime;
/**
* Whether the page is retrieved directly via the `file://` protocol (true) or hosted on a web
* server (false)
*/
private isFileProtocolUsed;
/** The simulation mode (if the experiment is being simulated) */
private simulationMode?;
/** Simulation options passed in via `simulate()` */
private simulationOptions;
private extensionManager;
constructor(options?: any);
private endMessage?;
/**
* Starts an experiment using the provided timeline and returns a promise that is resolved when
* the experiment is finished.
*
* @param timeline The timeline to be run
*/
run(timeline: TimelineDescription | TimelineArray): Promise<void>;
simulate(timeline: any[], simulation_mode?: "data-only" | "visual", simulation_options?: {}): Promise<void>;
progressBar?: ProgressBar;
getProgress(): {
total_trials: any;
current_trial_global: any;
percent_complete: number;
};
getStartTime(): Date;
getTotalTime(): number;
getDisplayElement(): HTMLElement;
getDisplayContainerElement(): HTMLElement;
abortExperiment(endMessage?: string, data?: {}): void;
abortCurrentTimeline(): void;
/**
* Aborts a named timeline. The timeline must be currently running in order to abort it.
*
* @param name The name of the timeline to abort. Timelines can be given names by setting the `name` parameter in the description of the timeline.
*/
abortTimelineByName(name: string): void;
getCurrentTrial(): TrialDescription;
getInitSettings(): any;
timelineVariable(variableName: string): TimelineVariable;
evaluateTimelineVariable(variableName: string): any;
pauseExperiment(): void;
resumeExperiment(): void;
getSafeModeStatus(): boolean;
getTimeline(): TimelineArray;
/**
* Prints out a string containing citations for the jsPsych library and all input plugins/extensions in the specified format.
* If called without input, prints citation for jsPsych library.
*
* @param plugins The plugins/extensions to generate citations for. Always prints the citation for the jsPsych library at the top.
* @param format The desired output citation format. Currently supports "apa" and "bibtex".
* @returns String containing citations separated with newline character.
*/
getCitations(plugins?: Array<Class<JsPsychPlugin<any>> | Class<JsPsychExtension>>, format?: "apa" | "bibtex"): string;
get extensions(): Record<string, JsPsychExtension>;
private prepareDom;
private finishTrialPromise;
finishTrial(data?: TrialResult): void;
private timelineDependencies;
private extensionManagerDependencies;
private dataDependencies;
}
/**
* Creates a new JsPsych instance using the provided options.
*
* @param options The options to pass to the JsPsych constructor
* @returns A new JsPsych instance
*/
declare function initJsPsych(options?: any): JsPsych;
export { DataCollection, JsPsych, type JsPsychExtension, type JsPsychExtensionInfo, type JsPsychPlugin, ParameterType, type PluginInfo, type TrialType, initJsPsych };