jspsych 7.3.2 → 7.3.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -3
- package/dist/index.browser.js +75 -20
- package/dist/index.browser.js.map +1 -1
- package/dist/index.browser.min.js +1 -1
- package/dist/index.browser.min.js.map +1 -1
- package/dist/index.cjs +75 -20
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +75 -20
- package/dist/index.js.map +1 -1
- package/dist/modules/plugin-api/SimulationAPI.d.ts +3 -0
- package/dist/modules/plugin-api/TimeoutAPI.d.ts +13 -1
- package/dist/modules/utils.d.ts +6 -0
- package/package.json +2 -2
- package/src/JsPsych.ts +21 -8
- package/src/modules/plugin-api/SimulationAPI.ts +9 -4
- package/src/modules/plugin-api/TimeoutAPI.ts +15 -3
- package/src/modules/plugin-api/index.ts +14 -11
- package/src/modules/utils.ts +31 -0
package/README.md
CHANGED
|
@@ -48,9 +48,15 @@ See the [contributing to jsPsych](https://www.jspsych.org/latest/developers/cont
|
|
|
48
48
|
|
|
49
49
|
## Citation
|
|
50
50
|
|
|
51
|
-
If you use this library in academic work,
|
|
51
|
+
If you use this library in academic work, the preferred citation is:
|
|
52
52
|
|
|
53
|
-
de Leeuw, J.R. (
|
|
53
|
+
de Leeuw, J.R., Gilbert, R.A., & Luchterhandt, B. (2023). jsPsych: Enabling an open-source collaborative ecosystem of behavioral experiments. *Journal of Open Source Software*, *8*(85), 5351, [https://joss.theoj.org/papers/10.21105/joss.05351](https://joss.theoj.org/papers/10.21105/joss.05351).
|
|
54
|
+
|
|
55
|
+
This paper is an updated description of jsPsych and includes all current core team members. It replaces the earlier paper that described jsPsych:
|
|
56
|
+
|
|
57
|
+
de Leeuw, J.R. (2015). jsPsych: A JavaScript library for creating behavioral experiments in a Web browser. *Behavior Research Methods*, _47_(1), 1-12. doi:[10.3758/s13428-014-0458-y](http://link.springer.com/article/10.3758%2Fs13428-014-0458-y)
|
|
58
|
+
|
|
59
|
+
Citations help us demonstrate that this library is used and valued, which allows us to continue working on it.
|
|
54
60
|
|
|
55
61
|
## Contributors
|
|
56
62
|
|
|
@@ -59,4 +65,4 @@ The project is currently managed by the core team of Josh de Leeuw ([@jodeleeuw]
|
|
|
59
65
|
|
|
60
66
|
jsPsych was created by [Josh de Leeuw](http://www.twitter.com/joshdeleeuw).
|
|
61
67
|
|
|
62
|
-
We're also grateful for the generous support from a [Mozilla Open Source Support award](https://www.mozilla.org/en-US/moss/), which funded development of the library from 2020-
|
|
68
|
+
We're also grateful for the generous support from a [Mozilla Open Source Support award](https://www.mozilla.org/en-US/moss/), which funded development of the library from 2020-2022.
|
package/dist/index.browser.js
CHANGED
|
@@ -70,7 +70,7 @@ var jsPsychModule = (function (exports) {
|
|
|
70
70
|
return self;
|
|
71
71
|
};
|
|
72
72
|
|
|
73
|
-
var version = "7.3.
|
|
73
|
+
var version = "7.3.3";
|
|
74
74
|
|
|
75
75
|
class MigrationError extends Error {
|
|
76
76
|
constructor(message = "The global `jsPsych` variable is no longer available in jsPsych v7.") {
|
|
@@ -134,12 +134,45 @@ var jsPsychModule = (function (exports) {
|
|
|
134
134
|
else {
|
|
135
135
|
return obj;
|
|
136
136
|
}
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Merges two objects, recursively.
|
|
140
|
+
* @param obj1 Object to merge
|
|
141
|
+
* @param obj2 Object to merge
|
|
142
|
+
*/
|
|
143
|
+
function deepMerge(obj1, obj2) {
|
|
144
|
+
let merged = {};
|
|
145
|
+
for (const key in obj1) {
|
|
146
|
+
if (obj1.hasOwnProperty(key)) {
|
|
147
|
+
if (typeof obj1[key] === "object" && obj2.hasOwnProperty(key)) {
|
|
148
|
+
merged[key] = deepMerge(obj1[key], obj2[key]);
|
|
149
|
+
}
|
|
150
|
+
else {
|
|
151
|
+
merged[key] = obj1[key];
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
for (const key in obj2) {
|
|
156
|
+
if (obj2.hasOwnProperty(key)) {
|
|
157
|
+
if (!merged.hasOwnProperty(key)) {
|
|
158
|
+
merged[key] = obj2[key];
|
|
159
|
+
}
|
|
160
|
+
else if (typeof obj2[key] === "object") {
|
|
161
|
+
merged[key] = deepMerge(merged[key], obj2[key]);
|
|
162
|
+
}
|
|
163
|
+
else {
|
|
164
|
+
merged[key] = obj2[key];
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
return merged;
|
|
137
169
|
}
|
|
138
170
|
|
|
139
171
|
var utils = /*#__PURE__*/Object.freeze({
|
|
140
172
|
__proto__: null,
|
|
141
173
|
unique: unique,
|
|
142
|
-
deepCopy: deepCopy
|
|
174
|
+
deepCopy: deepCopy,
|
|
175
|
+
deepMerge: deepMerge
|
|
143
176
|
});
|
|
144
177
|
|
|
145
178
|
class DataColumn {
|
|
@@ -1105,8 +1138,12 @@ var jsPsychModule = (function (exports) {
|
|
|
1105
1138
|
}
|
|
1106
1139
|
|
|
1107
1140
|
class SimulationAPI {
|
|
1141
|
+
constructor(getDisplayContainerElement, setJsPsychTimeout) {
|
|
1142
|
+
this.getDisplayContainerElement = getDisplayContainerElement;
|
|
1143
|
+
this.setJsPsychTimeout = setJsPsychTimeout;
|
|
1144
|
+
}
|
|
1108
1145
|
dispatchEvent(event) {
|
|
1109
|
-
|
|
1146
|
+
this.getDisplayContainerElement().dispatchEvent(event);
|
|
1110
1147
|
}
|
|
1111
1148
|
/**
|
|
1112
1149
|
* Dispatches a `keydown` event for the specified key
|
|
@@ -1129,7 +1166,7 @@ var jsPsychModule = (function (exports) {
|
|
|
1129
1166
|
*/
|
|
1130
1167
|
pressKey(key, delay = 0) {
|
|
1131
1168
|
if (delay > 0) {
|
|
1132
|
-
|
|
1169
|
+
this.setJsPsychTimeout(() => {
|
|
1133
1170
|
this.keyDown(key);
|
|
1134
1171
|
this.keyUp(key);
|
|
1135
1172
|
}, delay);
|
|
@@ -1146,7 +1183,7 @@ var jsPsychModule = (function (exports) {
|
|
|
1146
1183
|
*/
|
|
1147
1184
|
clickTarget(target, delay = 0) {
|
|
1148
1185
|
if (delay > 0) {
|
|
1149
|
-
|
|
1186
|
+
this.setJsPsychTimeout(() => {
|
|
1150
1187
|
target.dispatchEvent(new MouseEvent("mousedown", { bubbles: true }));
|
|
1151
1188
|
target.dispatchEvent(new MouseEvent("mouseup", { bubbles: true }));
|
|
1152
1189
|
target.dispatchEvent(new MouseEvent("click", { bubbles: true }));
|
|
@@ -1166,7 +1203,7 @@ var jsPsychModule = (function (exports) {
|
|
|
1166
1203
|
*/
|
|
1167
1204
|
fillTextInput(target, text, delay = 0) {
|
|
1168
1205
|
if (delay > 0) {
|
|
1169
|
-
|
|
1206
|
+
this.setJsPsychTimeout(() => {
|
|
1170
1207
|
target.value = text;
|
|
1171
1208
|
}, delay);
|
|
1172
1209
|
}
|
|
@@ -1275,15 +1312,27 @@ var jsPsychModule = (function (exports) {
|
|
|
1275
1312
|
}
|
|
1276
1313
|
}
|
|
1277
1314
|
|
|
1315
|
+
/**
|
|
1316
|
+
* A class that provides a wrapper around the global setTimeout and clearTimeout functions.
|
|
1317
|
+
*/
|
|
1278
1318
|
class TimeoutAPI {
|
|
1279
1319
|
constructor() {
|
|
1280
1320
|
this.timeout_handlers = [];
|
|
1281
1321
|
}
|
|
1322
|
+
/**
|
|
1323
|
+
* Calls a function after a specified delay, in milliseconds.
|
|
1324
|
+
* @param callback The function to call after the delay.
|
|
1325
|
+
* @param delay The number of milliseconds to wait before calling the function.
|
|
1326
|
+
* @returns A handle that can be used to clear the timeout with clearTimeout.
|
|
1327
|
+
*/
|
|
1282
1328
|
setTimeout(callback, delay) {
|
|
1283
1329
|
const handle = window.setTimeout(callback, delay);
|
|
1284
1330
|
this.timeout_handlers.push(handle);
|
|
1285
1331
|
return handle;
|
|
1286
1332
|
}
|
|
1333
|
+
/**
|
|
1334
|
+
* Clears all timeouts that have been created with setTimeout.
|
|
1335
|
+
*/
|
|
1287
1336
|
clearAllTimeouts() {
|
|
1288
1337
|
for (const handler of this.timeout_handlers) {
|
|
1289
1338
|
clearTimeout(handler);
|
|
@@ -1294,13 +1343,12 @@ var jsPsychModule = (function (exports) {
|
|
|
1294
1343
|
|
|
1295
1344
|
function createJointPluginAPIObject(jsPsych) {
|
|
1296
1345
|
const settings = jsPsych.getInitSettings();
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
].map((object) => autoBind(object)));
|
|
1346
|
+
const keyboardListenerAPI = autoBind(new KeyboardListenerAPI(jsPsych.getDisplayContainerElement, settings.case_sensitive_responses, settings.minimum_valid_rt));
|
|
1347
|
+
const timeoutAPI = autoBind(new TimeoutAPI());
|
|
1348
|
+
const mediaAPI = autoBind(new MediaAPI(settings.use_webaudio, jsPsych.webaudio_context));
|
|
1349
|
+
const hardwareAPI = autoBind(new HardwareAPI());
|
|
1350
|
+
const simulationAPI = autoBind(new SimulationAPI(jsPsych.getDisplayContainerElement, timeoutAPI.setTimeout));
|
|
1351
|
+
return Object.assign({}, ...[keyboardListenerAPI, timeoutAPI, mediaAPI, hardwareAPI, simulationAPI]);
|
|
1304
1352
|
}
|
|
1305
1353
|
|
|
1306
1354
|
var wordList = [
|
|
@@ -3055,13 +3103,14 @@ var jsPsychModule = (function (exports) {
|
|
|
3055
3103
|
}
|
|
3056
3104
|
};
|
|
3057
3105
|
let trial_complete;
|
|
3106
|
+
let trial_sim_opts;
|
|
3107
|
+
let trial_sim_opts_merged;
|
|
3058
3108
|
if (!this.simulation_mode) {
|
|
3059
3109
|
trial_complete = trial.type.trial(this.DOM_target, trial, load_callback);
|
|
3060
3110
|
}
|
|
3061
3111
|
if (this.simulation_mode) {
|
|
3062
3112
|
// check if the trial supports simulation
|
|
3063
3113
|
if (trial.type.simulate) {
|
|
3064
|
-
let trial_sim_opts;
|
|
3065
3114
|
if (!trial.simulation_options) {
|
|
3066
3115
|
trial_sim_opts = this.simulation_options.default;
|
|
3067
3116
|
}
|
|
@@ -3083,13 +3132,16 @@ var jsPsychModule = (function (exports) {
|
|
|
3083
3132
|
trial_sim_opts = trial.simulation_options;
|
|
3084
3133
|
}
|
|
3085
3134
|
}
|
|
3086
|
-
|
|
3087
|
-
|
|
3088
|
-
|
|
3135
|
+
// merge in default options that aren't overriden by the trial's simulation_options
|
|
3136
|
+
// including nested parameters in the simulation_options
|
|
3137
|
+
trial_sim_opts_merged = this.utils.deepMerge(this.simulation_options.default, trial_sim_opts);
|
|
3138
|
+
trial_sim_opts_merged = this.utils.deepCopy(trial_sim_opts_merged);
|
|
3139
|
+
trial_sim_opts_merged = this.replaceFunctionsWithValues(trial_sim_opts_merged, null);
|
|
3140
|
+
if ((trial_sim_opts_merged === null || trial_sim_opts_merged === void 0 ? void 0 : trial_sim_opts_merged.simulate) === false) {
|
|
3089
3141
|
trial_complete = trial.type.trial(this.DOM_target, trial, load_callback);
|
|
3090
3142
|
}
|
|
3091
3143
|
else {
|
|
3092
|
-
trial_complete = trial.type.simulate(trial, (
|
|
3144
|
+
trial_complete = trial.type.simulate(trial, (trial_sim_opts_merged === null || trial_sim_opts_merged === void 0 ? void 0 : trial_sim_opts_merged.mode) || this.simulation_mode, trial_sim_opts_merged, load_callback);
|
|
3093
3145
|
}
|
|
3094
3146
|
}
|
|
3095
3147
|
else {
|
|
@@ -3099,8 +3151,11 @@ var jsPsychModule = (function (exports) {
|
|
|
3099
3151
|
}
|
|
3100
3152
|
// see if trial_complete is a Promise by looking for .then() function
|
|
3101
3153
|
const is_promise = trial_complete && typeof trial_complete.then == "function";
|
|
3102
|
-
// in simulation mode we let the simulate function call the load_callback always
|
|
3103
|
-
|
|
3154
|
+
// in simulation mode we let the simulate function call the load_callback always,
|
|
3155
|
+
// so we don't need to call it here. however, if we are in simulation mode but not simulating
|
|
3156
|
+
// this particular trial we need to call it.
|
|
3157
|
+
if (!is_promise &&
|
|
3158
|
+
(!this.simulation_mode || (this.simulation_mode && (trial_sim_opts_merged === null || trial_sim_opts_merged === void 0 ? void 0 : trial_sim_opts_merged.simulate) === false))) {
|
|
3104
3159
|
load_callback();
|
|
3105
3160
|
}
|
|
3106
3161
|
// done with callbacks
|