jspsych 7.2.1 → 7.3.0

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.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import "regenerator-runtime/runtime.js";
1
2
  import { JsPsych } from "./JsPsych";
2
3
  /**
3
4
  * Creates a new JsPsych instance using the provided options.
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- /*! *****************************************************************************
1
+ /******************************************************************************
2
2
  Copyright (c) Microsoft Corporation.
3
3
 
4
4
  Permission to use, copy, modify, and/or distribute this software for any
@@ -67,7 +67,7 @@ var autoBind = (self, {include, exclude} = {}) => {
67
67
  return self;
68
68
  };
69
69
 
70
- var version = "7.2.1";
70
+ var version = "7.3.0";
71
71
 
72
72
  class MigrationError extends Error {
73
73
  constructor(message = "The global `jsPsych` variable is no longer available in jsPsych v7.") {
@@ -839,8 +839,13 @@ class MediaAPI {
839
839
  this.img_cache = {};
840
840
  this.preloadMap = new Map();
841
841
  this.microphone_recorder = null;
842
+ this.camera_stream = null;
843
+ this.camera_recorder = null;
842
844
  }
843
845
  getVideoBuffer(videoID) {
846
+ if (videoID.startsWith("blob:")) {
847
+ this.video_buffers[videoID] = videoID;
848
+ }
844
849
  return this.video_buffers[videoID];
845
850
  }
846
851
  initAudio() {
@@ -1082,6 +1087,17 @@ class MediaAPI {
1082
1087
  getMicrophoneRecorder() {
1083
1088
  return this.microphone_recorder;
1084
1089
  }
1090
+ initializeCameraRecorder(stream, opts) {
1091
+ this.camera_stream = stream;
1092
+ const recorder = new MediaRecorder(stream, opts);
1093
+ this.camera_recorder = recorder;
1094
+ }
1095
+ getCameraStream() {
1096
+ return this.camera_stream;
1097
+ }
1098
+ getCameraRecorder() {
1099
+ return this.camera_recorder;
1100
+ }
1085
1101
  }
1086
1102
 
1087
1103
  class SimulationAPI {
@@ -1627,119 +1643,119 @@ words.wordList = wordList;
1627
1643
  var alea = {exports: {}};
1628
1644
 
1629
1645
  (function (module) {
1630
- // A port of an algorithm by Johannes Baagøe <baagoe@baagoe.com>, 2010
1631
- // http://baagoe.com/en/RandomMusings/javascript/
1632
- // https://github.com/nquinlan/better-random-numbers-for-javascript-mirror
1633
- // Original work is under MIT license -
1634
-
1635
- // Copyright (C) 2010 by Johannes Baagøe <baagoe@baagoe.org>
1636
- //
1637
- // Permission is hereby granted, free of charge, to any person obtaining a copy
1638
- // of this software and associated documentation files (the "Software"), to deal
1639
- // in the Software without restriction, including without limitation the rights
1640
- // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
1641
- // copies of the Software, and to permit persons to whom the Software is
1642
- // furnished to do so, subject to the following conditions:
1643
- //
1644
- // The above copyright notice and this permission notice shall be included in
1645
- // all copies or substantial portions of the Software.
1646
- //
1647
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1648
- // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1649
- // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
1650
- // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1651
- // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
1652
- // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
1653
- // THE SOFTWARE.
1654
-
1655
-
1656
-
1657
- (function(global, module, define) {
1658
-
1659
- function Alea(seed) {
1660
- var me = this, mash = Mash();
1661
-
1662
- me.next = function() {
1663
- var t = 2091639 * me.s0 + me.c * 2.3283064365386963e-10; // 2^-32
1664
- me.s0 = me.s1;
1665
- me.s1 = me.s2;
1666
- return me.s2 = t - (me.c = t | 0);
1667
- };
1668
-
1669
- // Apply the seeding algorithm from Baagoe.
1670
- me.c = 1;
1671
- me.s0 = mash(' ');
1672
- me.s1 = mash(' ');
1673
- me.s2 = mash(' ');
1674
- me.s0 -= mash(seed);
1675
- if (me.s0 < 0) { me.s0 += 1; }
1676
- me.s1 -= mash(seed);
1677
- if (me.s1 < 0) { me.s1 += 1; }
1678
- me.s2 -= mash(seed);
1679
- if (me.s2 < 0) { me.s2 += 1; }
1680
- mash = null;
1681
- }
1682
-
1683
- function copy(f, t) {
1684
- t.c = f.c;
1685
- t.s0 = f.s0;
1686
- t.s1 = f.s1;
1687
- t.s2 = f.s2;
1688
- return t;
1689
- }
1646
+ // A port of an algorithm by Johannes Baagøe <baagoe@baagoe.com>, 2010
1647
+ // http://baagoe.com/en/RandomMusings/javascript/
1648
+ // https://github.com/nquinlan/better-random-numbers-for-javascript-mirror
1649
+ // Original work is under MIT license -
1650
+
1651
+ // Copyright (C) 2010 by Johannes Baagøe <baagoe@baagoe.org>
1652
+ //
1653
+ // Permission is hereby granted, free of charge, to any person obtaining a copy
1654
+ // of this software and associated documentation files (the "Software"), to deal
1655
+ // in the Software without restriction, including without limitation the rights
1656
+ // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
1657
+ // copies of the Software, and to permit persons to whom the Software is
1658
+ // furnished to do so, subject to the following conditions:
1659
+ //
1660
+ // The above copyright notice and this permission notice shall be included in
1661
+ // all copies or substantial portions of the Software.
1662
+ //
1663
+ // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1664
+ // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1665
+ // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
1666
+ // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1667
+ // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
1668
+ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
1669
+ // THE SOFTWARE.
1670
+
1671
+
1672
+
1673
+ (function(global, module, define) {
1674
+
1675
+ function Alea(seed) {
1676
+ var me = this, mash = Mash();
1677
+
1678
+ me.next = function() {
1679
+ var t = 2091639 * me.s0 + me.c * 2.3283064365386963e-10; // 2^-32
1680
+ me.s0 = me.s1;
1681
+ me.s1 = me.s2;
1682
+ return me.s2 = t - (me.c = t | 0);
1683
+ };
1684
+
1685
+ // Apply the seeding algorithm from Baagoe.
1686
+ me.c = 1;
1687
+ me.s0 = mash(' ');
1688
+ me.s1 = mash(' ');
1689
+ me.s2 = mash(' ');
1690
+ me.s0 -= mash(seed);
1691
+ if (me.s0 < 0) { me.s0 += 1; }
1692
+ me.s1 -= mash(seed);
1693
+ if (me.s1 < 0) { me.s1 += 1; }
1694
+ me.s2 -= mash(seed);
1695
+ if (me.s2 < 0) { me.s2 += 1; }
1696
+ mash = null;
1697
+ }
1690
1698
 
1691
- function impl(seed, opts) {
1692
- var xg = new Alea(seed),
1693
- state = opts && opts.state,
1694
- prng = xg.next;
1695
- prng.int32 = function() { return (xg.next() * 0x100000000) | 0; };
1696
- prng.double = function() {
1697
- return prng() + (prng() * 0x200000 | 0) * 1.1102230246251565e-16; // 2^-53
1698
- };
1699
- prng.quick = prng;
1700
- if (state) {
1701
- if (typeof(state) == 'object') copy(state, xg);
1702
- prng.state = function() { return copy(xg, {}); };
1703
- }
1704
- return prng;
1705
- }
1699
+ function copy(f, t) {
1700
+ t.c = f.c;
1701
+ t.s0 = f.s0;
1702
+ t.s1 = f.s1;
1703
+ t.s2 = f.s2;
1704
+ return t;
1705
+ }
1706
1706
 
1707
- function Mash() {
1708
- var n = 0xefc8249d;
1709
-
1710
- var mash = function(data) {
1711
- data = String(data);
1712
- for (var i = 0; i < data.length; i++) {
1713
- n += data.charCodeAt(i);
1714
- var h = 0.02519603282416938 * n;
1715
- n = h >>> 0;
1716
- h -= n;
1717
- h *= n;
1718
- n = h >>> 0;
1719
- h -= n;
1720
- n += h * 0x100000000; // 2^32
1721
- }
1722
- return (n >>> 0) * 2.3283064365386963e-10; // 2^-32
1723
- };
1707
+ function impl(seed, opts) {
1708
+ var xg = new Alea(seed),
1709
+ state = opts && opts.state,
1710
+ prng = xg.next;
1711
+ prng.int32 = function() { return (xg.next() * 0x100000000) | 0; };
1712
+ prng.double = function() {
1713
+ return prng() + (prng() * 0x200000 | 0) * 1.1102230246251565e-16; // 2^-53
1714
+ };
1715
+ prng.quick = prng;
1716
+ if (state) {
1717
+ if (typeof(state) == 'object') copy(state, xg);
1718
+ prng.state = function() { return copy(xg, {}); };
1719
+ }
1720
+ return prng;
1721
+ }
1724
1722
 
1725
- return mash;
1726
- }
1723
+ function Mash() {
1724
+ var n = 0xefc8249d;
1725
+
1726
+ var mash = function(data) {
1727
+ data = String(data);
1728
+ for (var i = 0; i < data.length; i++) {
1729
+ n += data.charCodeAt(i);
1730
+ var h = 0.02519603282416938 * n;
1731
+ n = h >>> 0;
1732
+ h -= n;
1733
+ h *= n;
1734
+ n = h >>> 0;
1735
+ h -= n;
1736
+ n += h * 0x100000000; // 2^32
1737
+ }
1738
+ return (n >>> 0) * 2.3283064365386963e-10; // 2^-32
1739
+ };
1740
+
1741
+ return mash;
1742
+ }
1727
1743
 
1728
1744
 
1729
- if (module && module.exports) {
1730
- module.exports = impl;
1731
- } else if (define && define.amd) {
1732
- define(function() { return impl; });
1733
- } else {
1734
- this.alea = impl;
1735
- }
1745
+ if (module && module.exports) {
1746
+ module.exports = impl;
1747
+ } else if (define && define.amd) {
1748
+ define(function() { return impl; });
1749
+ } else {
1750
+ this.alea = impl;
1751
+ }
1736
1752
 
1737
- })(
1738
- commonjsGlobal,
1739
- module, // present in node.js
1740
- (typeof undefined) == 'function' // present with an AMD loader
1741
- );
1742
- }(alea));
1753
+ })(
1754
+ commonjsGlobal,
1755
+ module, // present in node.js
1756
+ (typeof undefined) == 'function' // present with an AMD loader
1757
+ );
1758
+ } (alea));
1743
1759
 
1744
1760
  var seedrandom = alea.exports;
1745
1761
 
@@ -2406,7 +2422,11 @@ class TimelineNode {
2406
2422
  // recursive downward search for active trial to extract timeline variable
2407
2423
  timelineVariable(variable_name) {
2408
2424
  if (typeof this.timeline_parameters == "undefined") {
2409
- return this.findTimelineVariable(variable_name);
2425
+ const val = this.findTimelineVariable(variable_name);
2426
+ if (typeof val === "undefined") {
2427
+ console.warn("Timeline variable " + variable_name + " not found.");
2428
+ }
2429
+ return val;
2410
2430
  }
2411
2431
  else {
2412
2432
  // if progress.current_location is -1, then the timeline variable is being evaluated
@@ -2421,7 +2441,11 @@ class TimelineNode {
2421
2441
  loc = loc - 1;
2422
2442
  }
2423
2443
  // now find the variable
2424
- return this.timeline_parameters.timeline[loc].timelineVariable(variable_name);
2444
+ const val = this.timeline_parameters.timeline[loc].timelineVariable(variable_name);
2445
+ if (typeof val === "undefined") {
2446
+ console.warn("Timeline variable " + variable_name + " not found.");
2447
+ }
2448
+ return val;
2425
2449
  }
2426
2450
  }
2427
2451
  // recursively get all the timeline variables for this trial
@@ -2699,6 +2723,7 @@ class JsPsych {
2699
2723
  return this.DOM_container;
2700
2724
  }
2701
2725
  finishTrial(data = {}) {
2726
+ var _a;
2702
2727
  if (this.current_trial_finished) {
2703
2728
  return;
2704
2729
  }
@@ -2711,7 +2736,7 @@ class JsPsych {
2711
2736
  // write the data from the trial
2712
2737
  this.data.write(data);
2713
2738
  // get back the data with all of the defaults in
2714
- const trial_data = this.data.get().filter({ trial_index: this.global_trial_index });
2739
+ const trial_data = this.data.getLastTrialData();
2715
2740
  // for trial-level callbacks, we just want to pass in a reference to the values
2716
2741
  // of the DataCollection, for easy access and editing.
2717
2742
  const trial_data_values = trial_data.values()[0];
@@ -2739,46 +2764,58 @@ class JsPsych {
2739
2764
  }
2740
2765
  }
2741
2766
  // handle extension callbacks
2742
- if (Array.isArray(current_trial.extensions)) {
2743
- for (const extension of current_trial.extensions) {
2744
- const ext_data_values = this.extensions[extension.type.info.name].on_finish(extension.params);
2745
- Object.assign(trial_data_values, ext_data_values);
2767
+ const extensionCallbackResults = ((_a = current_trial.extensions) !== null && _a !== void 0 ? _a : []).map((extension) => this.extensions[extension.type.info.name].on_finish(extension.params));
2768
+ const onExtensionCallbacksFinished = () => {
2769
+ // about to execute lots of callbacks, so switch context.
2770
+ this.internal.call_immediate = true;
2771
+ // handle callback at plugin level
2772
+ if (typeof current_trial.on_finish === "function") {
2773
+ current_trial.on_finish(trial_data_values);
2774
+ }
2775
+ // handle callback at whole-experiment level
2776
+ this.opts.on_trial_finish(trial_data_values);
2777
+ // after the above callbacks are complete, then the data should be finalized
2778
+ // for this trial. call the on_data_update handler, passing in the same
2779
+ // data object that just went through the trial's finish handlers.
2780
+ this.opts.on_data_update(trial_data_values);
2781
+ // done with callbacks
2782
+ this.internal.call_immediate = false;
2783
+ // wait for iti
2784
+ if (this.simulation_mode === "data-only") {
2785
+ this.nextTrial();
2746
2786
  }
2747
- }
2748
- // about to execute lots of callbacks, so switch context.
2749
- this.internal.call_immediate = true;
2750
- // handle callback at plugin level
2751
- if (typeof current_trial.on_finish === "function") {
2752
- current_trial.on_finish(trial_data_values);
2753
- }
2754
- // handle callback at whole-experiment level
2755
- this.opts.on_trial_finish(trial_data_values);
2756
- // after the above callbacks are complete, then the data should be finalized
2757
- // for this trial. call the on_data_update handler, passing in the same
2758
- // data object that just went through the trial's finish handlers.
2759
- this.opts.on_data_update(trial_data_values);
2760
- // done with callbacks
2761
- this.internal.call_immediate = false;
2762
- // wait for iti
2763
- if (this.simulation_mode === "data-only") {
2764
- this.nextTrial();
2765
- }
2766
- else if (typeof current_trial.post_trial_gap === null ||
2767
- typeof current_trial.post_trial_gap === "undefined") {
2768
- if (this.opts.default_iti > 0) {
2769
- setTimeout(this.nextTrial, this.opts.default_iti);
2787
+ else if (typeof current_trial.post_trial_gap === null ||
2788
+ typeof current_trial.post_trial_gap === "undefined") {
2789
+ if (this.opts.default_iti > 0) {
2790
+ setTimeout(this.nextTrial, this.opts.default_iti);
2791
+ }
2792
+ else {
2793
+ this.nextTrial();
2794
+ }
2770
2795
  }
2771
2796
  else {
2772
- this.nextTrial();
2797
+ if (current_trial.post_trial_gap > 0) {
2798
+ setTimeout(this.nextTrial, current_trial.post_trial_gap);
2799
+ }
2800
+ else {
2801
+ this.nextTrial();
2802
+ }
2773
2803
  }
2804
+ };
2805
+ // Strictly using Promise.resolve to turn all values into promises would be cleaner here, but it
2806
+ // would require user test code to make the event loop tick after every simulated key press even
2807
+ // if there are no async `on_finish` methods. Hence, in order to avoid a breaking change, we
2808
+ // only rely on the event loop if at least one `on_finish` method returns a promise.
2809
+ if (extensionCallbackResults.some((result) => typeof result.then === "function")) {
2810
+ Promise.all(extensionCallbackResults.map((result) => Promise.resolve(result).then((ext_data_values) => {
2811
+ Object.assign(trial_data_values, ext_data_values);
2812
+ }))).then(onExtensionCallbacksFinished);
2774
2813
  }
2775
2814
  else {
2776
- if (current_trial.post_trial_gap > 0) {
2777
- setTimeout(this.nextTrial, current_trial.post_trial_gap);
2778
- }
2779
- else {
2780
- this.nextTrial();
2815
+ for (const values of extensionCallbackResults) {
2816
+ Object.assign(trial_data_values, values);
2781
2817
  }
2818
+ onExtensionCallbacksFinished();
2782
2819
  }
2783
2820
  }
2784
2821
  endExperiment(end_message = "", data = {}) {
@@ -3066,16 +3103,16 @@ class JsPsych {
3066
3103
  }
3067
3104
  evaluateTimelineVariables(trial) {
3068
3105
  for (const key of Object.keys(trial)) {
3069
- // timeline variables on the root level
3070
3106
  if (typeof trial[key] === "object" &&
3071
3107
  trial[key] !== null &&
3072
3108
  typeof trial[key].timelineVariablePlaceholder !== "undefined") {
3073
- /*trial[key].toString().replace(/\s/g, "") ==
3074
- "function(){returntimeline.timelineVariable(varname);}"
3075
- )*/ trial[key] = trial[key].timelineVariableFunction();
3109
+ trial[key] = trial[key].timelineVariableFunction();
3076
3110
  }
3077
3111
  // timeline variables that are nested in objects
3078
- if (typeof trial[key] === "object" && trial[key] !== null) {
3112
+ if (typeof trial[key] === "object" &&
3113
+ trial[key] !== null &&
3114
+ key !== "timeline" &&
3115
+ key !== "timeline_variables") {
3079
3116
  this.evaluateTimelineVariables(trial[key]);
3080
3117
  }
3081
3118
  }
@@ -3118,9 +3155,11 @@ class JsPsych {
3118
3155
  else if (typeof obj === "object") {
3119
3156
  if (info === null || !info.nested) {
3120
3157
  for (const key of Object.keys(obj)) {
3121
- if (key === "type") {
3158
+ if (key === "type" || key === "timeline" || key === "timeline_variables") {
3122
3159
  // Ignore the object's `type` field because it contains a plugin and we do not want to
3123
- // call plugin functions
3160
+ // call plugin functions. Also ignore `timeline` and `timeline_variables` because they
3161
+ // are used in the `trials` parameter of the preload plugin and we don't want to actually
3162
+ // evaluate those in that context.
3124
3163
  continue;
3125
3164
  }
3126
3165
  obj[key] = this.replaceFunctionsWithValues(obj[key], null);
@@ -3250,6 +3289,7 @@ class JsPsych {
3250
3289
  }
3251
3290
  }
3252
3291
 
3292
+ // __rollup-babel-import-regenerator-runtime__
3253
3293
  // temporary patch for Safari
3254
3294
  if (typeof window !== "undefined" &&
3255
3295
  window.hasOwnProperty("webkitAudioContext") &&