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/dist/index.cjs CHANGED
@@ -71,7 +71,7 @@ var autoBind = (self, {include, exclude} = {}) => {
71
71
  return self;
72
72
  };
73
73
 
74
- var version = "7.3.2";
74
+ var version = "7.3.3";
75
75
 
76
76
  class MigrationError extends Error {
77
77
  constructor(message = "The global `jsPsych` variable is no longer available in jsPsych v7.") {
@@ -135,12 +135,45 @@ function deepCopy(obj) {
135
135
  else {
136
136
  return obj;
137
137
  }
138
+ }
139
+ /**
140
+ * Merges two objects, recursively.
141
+ * @param obj1 Object to merge
142
+ * @param obj2 Object to merge
143
+ */
144
+ function deepMerge(obj1, obj2) {
145
+ let merged = {};
146
+ for (const key in obj1) {
147
+ if (obj1.hasOwnProperty(key)) {
148
+ if (typeof obj1[key] === "object" && obj2.hasOwnProperty(key)) {
149
+ merged[key] = deepMerge(obj1[key], obj2[key]);
150
+ }
151
+ else {
152
+ merged[key] = obj1[key];
153
+ }
154
+ }
155
+ }
156
+ for (const key in obj2) {
157
+ if (obj2.hasOwnProperty(key)) {
158
+ if (!merged.hasOwnProperty(key)) {
159
+ merged[key] = obj2[key];
160
+ }
161
+ else if (typeof obj2[key] === "object") {
162
+ merged[key] = deepMerge(merged[key], obj2[key]);
163
+ }
164
+ else {
165
+ merged[key] = obj2[key];
166
+ }
167
+ }
168
+ }
169
+ return merged;
138
170
  }
139
171
 
140
172
  var utils = /*#__PURE__*/Object.freeze({
141
173
  __proto__: null,
142
174
  unique: unique,
143
- deepCopy: deepCopy
175
+ deepCopy: deepCopy,
176
+ deepMerge: deepMerge
144
177
  });
145
178
 
146
179
  class DataColumn {
@@ -1106,8 +1139,12 @@ class MediaAPI {
1106
1139
  }
1107
1140
 
1108
1141
  class SimulationAPI {
1142
+ constructor(getDisplayContainerElement, setJsPsychTimeout) {
1143
+ this.getDisplayContainerElement = getDisplayContainerElement;
1144
+ this.setJsPsychTimeout = setJsPsychTimeout;
1145
+ }
1109
1146
  dispatchEvent(event) {
1110
- document.body.dispatchEvent(event);
1147
+ this.getDisplayContainerElement().dispatchEvent(event);
1111
1148
  }
1112
1149
  /**
1113
1150
  * Dispatches a `keydown` event for the specified key
@@ -1130,7 +1167,7 @@ class SimulationAPI {
1130
1167
  */
1131
1168
  pressKey(key, delay = 0) {
1132
1169
  if (delay > 0) {
1133
- setTimeout(() => {
1170
+ this.setJsPsychTimeout(() => {
1134
1171
  this.keyDown(key);
1135
1172
  this.keyUp(key);
1136
1173
  }, delay);
@@ -1147,7 +1184,7 @@ class SimulationAPI {
1147
1184
  */
1148
1185
  clickTarget(target, delay = 0) {
1149
1186
  if (delay > 0) {
1150
- setTimeout(() => {
1187
+ this.setJsPsychTimeout(() => {
1151
1188
  target.dispatchEvent(new MouseEvent("mousedown", { bubbles: true }));
1152
1189
  target.dispatchEvent(new MouseEvent("mouseup", { bubbles: true }));
1153
1190
  target.dispatchEvent(new MouseEvent("click", { bubbles: true }));
@@ -1167,7 +1204,7 @@ class SimulationAPI {
1167
1204
  */
1168
1205
  fillTextInput(target, text, delay = 0) {
1169
1206
  if (delay > 0) {
1170
- setTimeout(() => {
1207
+ this.setJsPsychTimeout(() => {
1171
1208
  target.value = text;
1172
1209
  }, delay);
1173
1210
  }
@@ -1276,15 +1313,27 @@ class SimulationAPI {
1276
1313
  }
1277
1314
  }
1278
1315
 
1316
+ /**
1317
+ * A class that provides a wrapper around the global setTimeout and clearTimeout functions.
1318
+ */
1279
1319
  class TimeoutAPI {
1280
1320
  constructor() {
1281
1321
  this.timeout_handlers = [];
1282
1322
  }
1323
+ /**
1324
+ * Calls a function after a specified delay, in milliseconds.
1325
+ * @param callback The function to call after the delay.
1326
+ * @param delay The number of milliseconds to wait before calling the function.
1327
+ * @returns A handle that can be used to clear the timeout with clearTimeout.
1328
+ */
1283
1329
  setTimeout(callback, delay) {
1284
1330
  const handle = window.setTimeout(callback, delay);
1285
1331
  this.timeout_handlers.push(handle);
1286
1332
  return handle;
1287
1333
  }
1334
+ /**
1335
+ * Clears all timeouts that have been created with setTimeout.
1336
+ */
1288
1337
  clearAllTimeouts() {
1289
1338
  for (const handler of this.timeout_handlers) {
1290
1339
  clearTimeout(handler);
@@ -1295,13 +1344,12 @@ class TimeoutAPI {
1295
1344
 
1296
1345
  function createJointPluginAPIObject(jsPsych) {
1297
1346
  const settings = jsPsych.getInitSettings();
1298
- return Object.assign({}, ...[
1299
- new KeyboardListenerAPI(jsPsych.getDisplayContainerElement, settings.case_sensitive_responses, settings.minimum_valid_rt),
1300
- new TimeoutAPI(),
1301
- new MediaAPI(settings.use_webaudio, jsPsych.webaudio_context),
1302
- new HardwareAPI(),
1303
- new SimulationAPI(),
1304
- ].map((object) => autoBind(object)));
1347
+ const keyboardListenerAPI = autoBind(new KeyboardListenerAPI(jsPsych.getDisplayContainerElement, settings.case_sensitive_responses, settings.minimum_valid_rt));
1348
+ const timeoutAPI = autoBind(new TimeoutAPI());
1349
+ const mediaAPI = autoBind(new MediaAPI(settings.use_webaudio, jsPsych.webaudio_context));
1350
+ const hardwareAPI = autoBind(new HardwareAPI());
1351
+ const simulationAPI = autoBind(new SimulationAPI(jsPsych.getDisplayContainerElement, timeoutAPI.setTimeout));
1352
+ return Object.assign({}, ...[keyboardListenerAPI, timeoutAPI, mediaAPI, hardwareAPI, simulationAPI]);
1305
1353
  }
1306
1354
 
1307
1355
  var wordList = [
@@ -3056,13 +3104,14 @@ class JsPsych {
3056
3104
  }
3057
3105
  };
3058
3106
  let trial_complete;
3107
+ let trial_sim_opts;
3108
+ let trial_sim_opts_merged;
3059
3109
  if (!this.simulation_mode) {
3060
3110
  trial_complete = trial.type.trial(this.DOM_target, trial, load_callback);
3061
3111
  }
3062
3112
  if (this.simulation_mode) {
3063
3113
  // check if the trial supports simulation
3064
3114
  if (trial.type.simulate) {
3065
- let trial_sim_opts;
3066
3115
  if (!trial.simulation_options) {
3067
3116
  trial_sim_opts = this.simulation_options.default;
3068
3117
  }
@@ -3084,13 +3133,16 @@ class JsPsych {
3084
3133
  trial_sim_opts = trial.simulation_options;
3085
3134
  }
3086
3135
  }
3087
- trial_sim_opts = this.utils.deepCopy(trial_sim_opts);
3088
- trial_sim_opts = this.replaceFunctionsWithValues(trial_sim_opts, null);
3089
- if ((trial_sim_opts === null || trial_sim_opts === void 0 ? void 0 : trial_sim_opts.simulate) === false) {
3136
+ // merge in default options that aren't overriden by the trial's simulation_options
3137
+ // including nested parameters in the simulation_options
3138
+ trial_sim_opts_merged = this.utils.deepMerge(this.simulation_options.default, trial_sim_opts);
3139
+ trial_sim_opts_merged = this.utils.deepCopy(trial_sim_opts_merged);
3140
+ trial_sim_opts_merged = this.replaceFunctionsWithValues(trial_sim_opts_merged, null);
3141
+ if ((trial_sim_opts_merged === null || trial_sim_opts_merged === void 0 ? void 0 : trial_sim_opts_merged.simulate) === false) {
3090
3142
  trial_complete = trial.type.trial(this.DOM_target, trial, load_callback);
3091
3143
  }
3092
3144
  else {
3093
- trial_complete = trial.type.simulate(trial, (trial_sim_opts === null || trial_sim_opts === void 0 ? void 0 : trial_sim_opts.mode) || this.simulation_mode, trial_sim_opts, load_callback);
3145
+ 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);
3094
3146
  }
3095
3147
  }
3096
3148
  else {
@@ -3100,8 +3152,11 @@ class JsPsych {
3100
3152
  }
3101
3153
  // see if trial_complete is a Promise by looking for .then() function
3102
3154
  const is_promise = trial_complete && typeof trial_complete.then == "function";
3103
- // in simulation mode we let the simulate function call the load_callback always.
3104
- if (!is_promise && !this.simulation_mode) {
3155
+ // in simulation mode we let the simulate function call the load_callback always,
3156
+ // so we don't need to call it here. however, if we are in simulation mode but not simulating
3157
+ // this particular trial we need to call it.
3158
+ if (!is_promise &&
3159
+ (!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))) {
3105
3160
  load_callback();
3106
3161
  }
3107
3162
  // done with callbacks