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.js CHANGED
@@ -67,7 +67,7 @@ var autoBind = (self, {include, exclude} = {}) => {
67
67
  return self;
68
68
  };
69
69
 
70
- var version = "7.3.2";
70
+ var version = "7.3.3";
71
71
 
72
72
  class MigrationError extends Error {
73
73
  constructor(message = "The global `jsPsych` variable is no longer available in jsPsych v7.") {
@@ -131,12 +131,45 @@ function deepCopy(obj) {
131
131
  else {
132
132
  return obj;
133
133
  }
134
+ }
135
+ /**
136
+ * Merges two objects, recursively.
137
+ * @param obj1 Object to merge
138
+ * @param obj2 Object to merge
139
+ */
140
+ function deepMerge(obj1, obj2) {
141
+ let merged = {};
142
+ for (const key in obj1) {
143
+ if (obj1.hasOwnProperty(key)) {
144
+ if (typeof obj1[key] === "object" && obj2.hasOwnProperty(key)) {
145
+ merged[key] = deepMerge(obj1[key], obj2[key]);
146
+ }
147
+ else {
148
+ merged[key] = obj1[key];
149
+ }
150
+ }
151
+ }
152
+ for (const key in obj2) {
153
+ if (obj2.hasOwnProperty(key)) {
154
+ if (!merged.hasOwnProperty(key)) {
155
+ merged[key] = obj2[key];
156
+ }
157
+ else if (typeof obj2[key] === "object") {
158
+ merged[key] = deepMerge(merged[key], obj2[key]);
159
+ }
160
+ else {
161
+ merged[key] = obj2[key];
162
+ }
163
+ }
164
+ }
165
+ return merged;
134
166
  }
135
167
 
136
168
  var utils = /*#__PURE__*/Object.freeze({
137
169
  __proto__: null,
138
170
  unique: unique,
139
- deepCopy: deepCopy
171
+ deepCopy: deepCopy,
172
+ deepMerge: deepMerge
140
173
  });
141
174
 
142
175
  class DataColumn {
@@ -1102,8 +1135,12 @@ class MediaAPI {
1102
1135
  }
1103
1136
 
1104
1137
  class SimulationAPI {
1138
+ constructor(getDisplayContainerElement, setJsPsychTimeout) {
1139
+ this.getDisplayContainerElement = getDisplayContainerElement;
1140
+ this.setJsPsychTimeout = setJsPsychTimeout;
1141
+ }
1105
1142
  dispatchEvent(event) {
1106
- document.body.dispatchEvent(event);
1143
+ this.getDisplayContainerElement().dispatchEvent(event);
1107
1144
  }
1108
1145
  /**
1109
1146
  * Dispatches a `keydown` event for the specified key
@@ -1126,7 +1163,7 @@ class SimulationAPI {
1126
1163
  */
1127
1164
  pressKey(key, delay = 0) {
1128
1165
  if (delay > 0) {
1129
- setTimeout(() => {
1166
+ this.setJsPsychTimeout(() => {
1130
1167
  this.keyDown(key);
1131
1168
  this.keyUp(key);
1132
1169
  }, delay);
@@ -1143,7 +1180,7 @@ class SimulationAPI {
1143
1180
  */
1144
1181
  clickTarget(target, delay = 0) {
1145
1182
  if (delay > 0) {
1146
- setTimeout(() => {
1183
+ this.setJsPsychTimeout(() => {
1147
1184
  target.dispatchEvent(new MouseEvent("mousedown", { bubbles: true }));
1148
1185
  target.dispatchEvent(new MouseEvent("mouseup", { bubbles: true }));
1149
1186
  target.dispatchEvent(new MouseEvent("click", { bubbles: true }));
@@ -1163,7 +1200,7 @@ class SimulationAPI {
1163
1200
  */
1164
1201
  fillTextInput(target, text, delay = 0) {
1165
1202
  if (delay > 0) {
1166
- setTimeout(() => {
1203
+ this.setJsPsychTimeout(() => {
1167
1204
  target.value = text;
1168
1205
  }, delay);
1169
1206
  }
@@ -1272,15 +1309,27 @@ class SimulationAPI {
1272
1309
  }
1273
1310
  }
1274
1311
 
1312
+ /**
1313
+ * A class that provides a wrapper around the global setTimeout and clearTimeout functions.
1314
+ */
1275
1315
  class TimeoutAPI {
1276
1316
  constructor() {
1277
1317
  this.timeout_handlers = [];
1278
1318
  }
1319
+ /**
1320
+ * Calls a function after a specified delay, in milliseconds.
1321
+ * @param callback The function to call after the delay.
1322
+ * @param delay The number of milliseconds to wait before calling the function.
1323
+ * @returns A handle that can be used to clear the timeout with clearTimeout.
1324
+ */
1279
1325
  setTimeout(callback, delay) {
1280
1326
  const handle = window.setTimeout(callback, delay);
1281
1327
  this.timeout_handlers.push(handle);
1282
1328
  return handle;
1283
1329
  }
1330
+ /**
1331
+ * Clears all timeouts that have been created with setTimeout.
1332
+ */
1284
1333
  clearAllTimeouts() {
1285
1334
  for (const handler of this.timeout_handlers) {
1286
1335
  clearTimeout(handler);
@@ -1291,13 +1340,12 @@ class TimeoutAPI {
1291
1340
 
1292
1341
  function createJointPluginAPIObject(jsPsych) {
1293
1342
  const settings = jsPsych.getInitSettings();
1294
- return Object.assign({}, ...[
1295
- new KeyboardListenerAPI(jsPsych.getDisplayContainerElement, settings.case_sensitive_responses, settings.minimum_valid_rt),
1296
- new TimeoutAPI(),
1297
- new MediaAPI(settings.use_webaudio, jsPsych.webaudio_context),
1298
- new HardwareAPI(),
1299
- new SimulationAPI(),
1300
- ].map((object) => autoBind(object)));
1343
+ const keyboardListenerAPI = autoBind(new KeyboardListenerAPI(jsPsych.getDisplayContainerElement, settings.case_sensitive_responses, settings.minimum_valid_rt));
1344
+ const timeoutAPI = autoBind(new TimeoutAPI());
1345
+ const mediaAPI = autoBind(new MediaAPI(settings.use_webaudio, jsPsych.webaudio_context));
1346
+ const hardwareAPI = autoBind(new HardwareAPI());
1347
+ const simulationAPI = autoBind(new SimulationAPI(jsPsych.getDisplayContainerElement, timeoutAPI.setTimeout));
1348
+ return Object.assign({}, ...[keyboardListenerAPI, timeoutAPI, mediaAPI, hardwareAPI, simulationAPI]);
1301
1349
  }
1302
1350
 
1303
1351
  var wordList = [
@@ -3052,13 +3100,14 @@ class JsPsych {
3052
3100
  }
3053
3101
  };
3054
3102
  let trial_complete;
3103
+ let trial_sim_opts;
3104
+ let trial_sim_opts_merged;
3055
3105
  if (!this.simulation_mode) {
3056
3106
  trial_complete = trial.type.trial(this.DOM_target, trial, load_callback);
3057
3107
  }
3058
3108
  if (this.simulation_mode) {
3059
3109
  // check if the trial supports simulation
3060
3110
  if (trial.type.simulate) {
3061
- let trial_sim_opts;
3062
3111
  if (!trial.simulation_options) {
3063
3112
  trial_sim_opts = this.simulation_options.default;
3064
3113
  }
@@ -3080,13 +3129,16 @@ class JsPsych {
3080
3129
  trial_sim_opts = trial.simulation_options;
3081
3130
  }
3082
3131
  }
3083
- trial_sim_opts = this.utils.deepCopy(trial_sim_opts);
3084
- trial_sim_opts = this.replaceFunctionsWithValues(trial_sim_opts, null);
3085
- if ((trial_sim_opts === null || trial_sim_opts === void 0 ? void 0 : trial_sim_opts.simulate) === false) {
3132
+ // merge in default options that aren't overriden by the trial's simulation_options
3133
+ // including nested parameters in the simulation_options
3134
+ trial_sim_opts_merged = this.utils.deepMerge(this.simulation_options.default, trial_sim_opts);
3135
+ trial_sim_opts_merged = this.utils.deepCopy(trial_sim_opts_merged);
3136
+ trial_sim_opts_merged = this.replaceFunctionsWithValues(trial_sim_opts_merged, null);
3137
+ if ((trial_sim_opts_merged === null || trial_sim_opts_merged === void 0 ? void 0 : trial_sim_opts_merged.simulate) === false) {
3086
3138
  trial_complete = trial.type.trial(this.DOM_target, trial, load_callback);
3087
3139
  }
3088
3140
  else {
3089
- 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);
3141
+ 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);
3090
3142
  }
3091
3143
  }
3092
3144
  else {
@@ -3096,8 +3148,11 @@ class JsPsych {
3096
3148
  }
3097
3149
  // see if trial_complete is a Promise by looking for .then() function
3098
3150
  const is_promise = trial_complete && typeof trial_complete.then == "function";
3099
- // in simulation mode we let the simulate function call the load_callback always.
3100
- if (!is_promise && !this.simulation_mode) {
3151
+ // in simulation mode we let the simulate function call the load_callback always,
3152
+ // so we don't need to call it here. however, if we are in simulation mode but not simulating
3153
+ // this particular trial we need to call it.
3154
+ if (!is_promise &&
3155
+ (!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))) {
3101
3156
  load_callback();
3102
3157
  }
3103
3158
  // done with callbacks