@jspsych/plugin-audio-button-response 1.1.3 → 1.2.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.
@@ -69,6 +69,12 @@ var jsPsychAudioButtonResponse = (function (jspsych) {
69
69
  pretty_name: "Response allowed while playing",
70
70
  default: true,
71
71
  },
72
+ /** The delay of enabling button */
73
+ enable_button_after: {
74
+ type: jspsych.ParameterType.INT,
75
+ pretty_name: "Enable button after",
76
+ default: 0,
77
+ },
72
78
  },
73
79
  };
74
80
  /**
@@ -161,6 +167,7 @@ var jsPsychAudioButtonResponse = (function (jspsych) {
161
167
  }
162
168
  display_element.innerHTML = html;
163
169
  if (trial.response_allowed_while_playing) {
170
+ disable_buttons();
164
171
  enable_buttons();
165
172
  }
166
173
  else {
@@ -227,6 +234,9 @@ var jsPsychAudioButtonResponse = (function (jspsych) {
227
234
  this.jsPsych.finishTrial(trial_data);
228
235
  trial_complete();
229
236
  };
237
+ const enable_buttons_with_delay = (delay) => {
238
+ this.jsPsych.pluginAPI.setTimeout(enable_buttons_without_delay, delay);
239
+ };
230
240
  function button_response(e) {
231
241
  var choice = e.currentTarget.getAttribute("data-choice"); // don't use dataset for jsdom compatibility
232
242
  after_response(choice);
@@ -241,7 +251,7 @@ var jsPsychAudioButtonResponse = (function (jspsych) {
241
251
  btns[i].removeEventListener("click", button_response);
242
252
  }
243
253
  }
244
- function enable_buttons() {
254
+ function enable_buttons_without_delay() {
245
255
  var btns = document.querySelectorAll(".jspsych-audio-button-response-button");
246
256
  for (var i = 0; i < btns.length; i++) {
247
257
  var btn_el = btns[i].querySelector("button");
@@ -251,6 +261,14 @@ var jsPsychAudioButtonResponse = (function (jspsych) {
251
261
  btns[i].addEventListener("click", button_response);
252
262
  }
253
263
  }
264
+ function enable_buttons() {
265
+ if (trial.enable_button_after > 0) {
266
+ enable_buttons_with_delay(trial.enable_button_after);
267
+ }
268
+ else {
269
+ enable_buttons_without_delay();
270
+ }
271
+ }
254
272
  return new Promise((resolve) => {
255
273
  trial_complete = resolve;
256
274
  });
@@ -267,7 +285,8 @@ var jsPsychAudioButtonResponse = (function (jspsych) {
267
285
  create_simulation_data(trial, simulation_options) {
268
286
  const default_data = {
269
287
  stimulus: trial.stimulus,
270
- rt: this.jsPsych.randomization.sampleExGaussian(500, 50, 1 / 150, true),
288
+ rt: this.jsPsych.randomization.sampleExGaussian(500, 50, 1 / 150, true) +
289
+ trial.enable_button_after,
271
290
  response: this.jsPsych.randomization.randomInt(0, trial.choices.length - 1),
272
291
  };
273
292
  const data = this.jsPsych.pluginAPI.mergeSimulationData(default_data, simulation_options);
@@ -302,4 +321,4 @@ var jsPsychAudioButtonResponse = (function (jspsych) {
302
321
  return AudioButtonResponsePlugin;
303
322
 
304
323
  })(jsPsychModule);
305
- //# sourceMappingURL=https://unpkg.com/@jspsych/plugin-audio-button-response@1.1.3/dist/index.browser.js.map
324
+ //# sourceMappingURL=https://unpkg.com/@jspsych/plugin-audio-button-response@1.2.0/dist/index.browser.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.browser.js","sources":["../src/index.ts"],"sourcesContent":["import { JsPsych, JsPsychPlugin, ParameterType, TrialType } from \"jspsych\";\n\nconst info = <const>{\n name: \"audio-button-response\",\n parameters: {\n /** The audio to be played. */\n stimulus: {\n type: ParameterType.AUDIO,\n pretty_name: \"Stimulus\",\n default: undefined,\n },\n /** Array containing the label(s) for the button(s). */\n choices: {\n type: ParameterType.STRING,\n pretty_name: \"Choices\",\n default: undefined,\n array: true,\n },\n /** The HTML for creating button. Can create own style. Use the \"%choice%\" string to indicate where the label from the choices parameter should be inserted. */\n button_html: {\n type: ParameterType.HTML_STRING,\n pretty_name: \"Button HTML\",\n default: '<button class=\"jspsych-btn\">%choice%</button>',\n array: true,\n },\n /** Any content here will be displayed below the stimulus. */\n prompt: {\n type: ParameterType.HTML_STRING,\n pretty_name: \"Prompt\",\n default: null,\n },\n /** The maximum duration to wait for a response. */\n trial_duration: {\n type: ParameterType.INT,\n pretty_name: \"Trial duration\",\n default: null,\n },\n /** Vertical margin of button. */\n margin_vertical: {\n type: ParameterType.STRING,\n pretty_name: \"Margin vertical\",\n default: \"0px\",\n },\n /** Horizontal margin of button. */\n margin_horizontal: {\n type: ParameterType.STRING,\n pretty_name: \"Margin horizontal\",\n default: \"8px\",\n },\n /** If true, the trial will end when user makes a response. */\n response_ends_trial: {\n type: ParameterType.BOOL,\n pretty_name: \"Response ends trial\",\n default: true,\n },\n /** If true, then the trial will end as soon as the audio file finishes playing. */\n trial_ends_after_audio: {\n type: ParameterType.BOOL,\n pretty_name: \"Trial ends after audio\",\n default: false,\n },\n /**\n * If true, then responses are allowed while the audio is playing.\n * If false, then the audio must finish playing before a response is accepted.\n */\n response_allowed_while_playing: {\n type: ParameterType.BOOL,\n pretty_name: \"Response allowed while playing\",\n default: true,\n },\n },\n};\n\ntype Info = typeof info;\n\n/**\n * **audio-button-response**\n *\n * jsPsych plugin for playing an audio file and getting a button response\n *\n * @author Kristin Diep\n * @see {@link https://www.jspsych.org/plugins/jspsych-audio-button-response/ audio-button-response plugin documentation on jspsych.org}\n */\nclass AudioButtonResponsePlugin implements JsPsychPlugin<Info> {\n static info = info;\n private audio;\n\n constructor(private jsPsych: JsPsych) {}\n\n trial(display_element: HTMLElement, trial: TrialType<Info>, on_load: () => void) {\n // hold the .resolve() function from the Promise that ends the trial\n let trial_complete;\n\n // setup stimulus\n var context = this.jsPsych.pluginAPI.audioContext();\n\n // store response\n var response = {\n rt: null,\n button: null,\n };\n\n // record webaudio context start time\n var startTime;\n\n // load audio file\n this.jsPsych.pluginAPI\n .getAudioBuffer(trial.stimulus)\n .then((buffer) => {\n if (context !== null) {\n this.audio = context.createBufferSource();\n this.audio.buffer = buffer;\n this.audio.connect(context.destination);\n } else {\n this.audio = buffer;\n this.audio.currentTime = 0;\n }\n setupTrial();\n })\n .catch((err) => {\n console.error(\n `Failed to load audio file \"${trial.stimulus}\". Try checking the file path. We recommend using the preload plugin to load audio files.`\n );\n console.error(err);\n });\n\n const setupTrial = () => {\n // set up end event if trial needs it\n if (trial.trial_ends_after_audio) {\n this.audio.addEventListener(\"ended\", end_trial);\n }\n\n // enable buttons after audio ends if necessary\n if (!trial.response_allowed_while_playing && !trial.trial_ends_after_audio) {\n this.audio.addEventListener(\"ended\", enable_buttons);\n }\n\n //display buttons\n var buttons = [];\n if (Array.isArray(trial.button_html)) {\n if (trial.button_html.length == trial.choices.length) {\n buttons = trial.button_html;\n } else {\n console.error(\n \"Error in audio-button-response plugin. The length of the button_html array does not equal the length of the choices array\"\n );\n }\n } else {\n for (var i = 0; i < trial.choices.length; i++) {\n buttons.push(trial.button_html);\n }\n }\n\n var html = '<div id=\"jspsych-audio-button-response-btngroup\">';\n for (var i = 0; i < trial.choices.length; i++) {\n var str = buttons[i].replace(/%choice%/g, trial.choices[i]);\n html +=\n '<div class=\"jspsych-audio-button-response-button\" style=\"cursor: pointer; display: inline-block; margin:' +\n trial.margin_vertical +\n \" \" +\n trial.margin_horizontal +\n '\" id=\"jspsych-audio-button-response-button-' +\n i +\n '\" data-choice=\"' +\n i +\n '\">' +\n str +\n \"</div>\";\n }\n html += \"</div>\";\n\n //show prompt if there is one\n if (trial.prompt !== null) {\n html += trial.prompt;\n }\n\n display_element.innerHTML = html;\n\n if (trial.response_allowed_while_playing) {\n enable_buttons();\n } else {\n disable_buttons();\n }\n\n // start time\n startTime = performance.now();\n\n // start audio\n if (context !== null) {\n startTime = context.currentTime;\n this.audio.start(startTime);\n } else {\n this.audio.play();\n }\n\n // end trial if time limit is set\n if (trial.trial_duration !== null) {\n this.jsPsych.pluginAPI.setTimeout(() => {\n end_trial();\n }, trial.trial_duration);\n }\n\n on_load();\n };\n\n // function to handle responses by the subject\n function after_response(choice) {\n // measure rt\n var endTime = performance.now();\n var rt = Math.round(endTime - startTime);\n if (context !== null) {\n endTime = context.currentTime;\n rt = Math.round((endTime - startTime) * 1000);\n }\n response.button = parseInt(choice);\n response.rt = rt;\n\n // disable all the buttons after a response\n disable_buttons();\n\n if (trial.response_ends_trial) {\n end_trial();\n }\n }\n\n // function to end trial when it is time\n const end_trial = () => {\n // kill any remaining setTimeout handlers\n this.jsPsych.pluginAPI.clearAllTimeouts();\n\n // stop the audio file if it is playing\n // remove end event listeners if they exist\n if (context !== null) {\n this.audio.stop();\n } else {\n this.audio.pause();\n }\n\n this.audio.removeEventListener(\"ended\", end_trial);\n this.audio.removeEventListener(\"ended\", enable_buttons);\n\n // gather the data to store for the trial\n var trial_data = {\n rt: response.rt,\n stimulus: trial.stimulus,\n response: response.button,\n };\n\n // clear the display\n display_element.innerHTML = \"\";\n\n // move on to the next trial\n this.jsPsych.finishTrial(trial_data);\n\n trial_complete();\n };\n\n function button_response(e) {\n var choice = e.currentTarget.getAttribute(\"data-choice\"); // don't use dataset for jsdom compatibility\n after_response(choice);\n }\n\n function disable_buttons() {\n var btns = document.querySelectorAll(\".jspsych-audio-button-response-button\");\n for (var i = 0; i < btns.length; i++) {\n var btn_el = btns[i].querySelector(\"button\");\n if (btn_el) {\n btn_el.disabled = true;\n }\n btns[i].removeEventListener(\"click\", button_response);\n }\n }\n\n function enable_buttons() {\n var btns = document.querySelectorAll(\".jspsych-audio-button-response-button\");\n for (var i = 0; i < btns.length; i++) {\n var btn_el = btns[i].querySelector(\"button\");\n if (btn_el) {\n btn_el.disabled = false;\n }\n btns[i].addEventListener(\"click\", button_response);\n }\n }\n\n return new Promise((resolve) => {\n trial_complete = resolve;\n });\n }\n\n simulate(\n trial: TrialType<Info>,\n simulation_mode,\n simulation_options: any,\n load_callback: () => void\n ) {\n if (simulation_mode == \"data-only\") {\n load_callback();\n this.simulate_data_only(trial, simulation_options);\n }\n if (simulation_mode == \"visual\") {\n this.simulate_visual(trial, simulation_options, load_callback);\n }\n }\n\n private create_simulation_data(trial: TrialType<Info>, simulation_options) {\n const default_data = {\n stimulus: trial.stimulus,\n rt: this.jsPsych.randomization.sampleExGaussian(500, 50, 1 / 150, true),\n response: this.jsPsych.randomization.randomInt(0, trial.choices.length - 1),\n };\n\n const data = this.jsPsych.pluginAPI.mergeSimulationData(default_data, simulation_options);\n\n this.jsPsych.pluginAPI.ensureSimulationDataConsistency(trial, data);\n\n return data;\n }\n\n private simulate_data_only(trial: TrialType<Info>, simulation_options) {\n const data = this.create_simulation_data(trial, simulation_options);\n\n this.jsPsych.finishTrial(data);\n }\n\n private simulate_visual(trial: TrialType<Info>, simulation_options, load_callback: () => void) {\n const data = this.create_simulation_data(trial, simulation_options);\n\n const display_element = this.jsPsych.getDisplayElement();\n\n const respond = () => {\n if (data.rt !== null) {\n this.jsPsych.pluginAPI.clickTarget(\n display_element.querySelector(`div[data-choice=\"${data.response}\"] button`),\n data.rt\n );\n }\n };\n\n this.trial(display_element, trial, () => {\n load_callback();\n if (!trial.response_allowed_while_playing) {\n this.audio.addEventListener(\"ended\", respond);\n } else {\n respond();\n }\n });\n }\n}\n\nexport default AudioButtonResponsePlugin;\n"],"names":["ParameterType"],"mappings":";;;EAEA,MAAM,IAAI,GAAU;EAClB,IAAA,IAAI,EAAE,uBAAuB;EAC7B,IAAA,UAAU,EAAE;;EAEV,QAAA,QAAQ,EAAE;cACR,IAAI,EAAEA,qBAAa,CAAC,KAAK;EACzB,YAAA,WAAW,EAAE,UAAU;EACvB,YAAA,OAAO,EAAE,SAAS;EACnB,SAAA;;EAED,QAAA,OAAO,EAAE;cACP,IAAI,EAAEA,qBAAa,CAAC,MAAM;EAC1B,YAAA,WAAW,EAAE,SAAS;EACtB,YAAA,OAAO,EAAE,SAAS;EAClB,YAAA,KAAK,EAAE,IAAI;EACZ,SAAA;;EAED,QAAA,WAAW,EAAE;cACX,IAAI,EAAEA,qBAAa,CAAC,WAAW;EAC/B,YAAA,WAAW,EAAE,aAAa;EAC1B,YAAA,OAAO,EAAE,+CAA+C;EACxD,YAAA,KAAK,EAAE,IAAI;EACZ,SAAA;;EAED,QAAA,MAAM,EAAE;cACN,IAAI,EAAEA,qBAAa,CAAC,WAAW;EAC/B,YAAA,WAAW,EAAE,QAAQ;EACrB,YAAA,OAAO,EAAE,IAAI;EACd,SAAA;;EAED,QAAA,cAAc,EAAE;cACd,IAAI,EAAEA,qBAAa,CAAC,GAAG;EACvB,YAAA,WAAW,EAAE,gBAAgB;EAC7B,YAAA,OAAO,EAAE,IAAI;EACd,SAAA;;EAED,QAAA,eAAe,EAAE;cACf,IAAI,EAAEA,qBAAa,CAAC,MAAM;EAC1B,YAAA,WAAW,EAAE,iBAAiB;EAC9B,YAAA,OAAO,EAAE,KAAK;EACf,SAAA;;EAED,QAAA,iBAAiB,EAAE;cACjB,IAAI,EAAEA,qBAAa,CAAC,MAAM;EAC1B,YAAA,WAAW,EAAE,mBAAmB;EAChC,YAAA,OAAO,EAAE,KAAK;EACf,SAAA;;EAED,QAAA,mBAAmB,EAAE;cACnB,IAAI,EAAEA,qBAAa,CAAC,IAAI;EACxB,YAAA,WAAW,EAAE,qBAAqB;EAClC,YAAA,OAAO,EAAE,IAAI;EACd,SAAA;;EAED,QAAA,sBAAsB,EAAE;cACtB,IAAI,EAAEA,qBAAa,CAAC,IAAI;EACxB,YAAA,WAAW,EAAE,wBAAwB;EACrC,YAAA,OAAO,EAAE,KAAK;EACf,SAAA;EACD;;;EAGG;EACH,QAAA,8BAA8B,EAAE;cAC9B,IAAI,EAAEA,qBAAa,CAAC,IAAI;EACxB,YAAA,WAAW,EAAE,gCAAgC;EAC7C,YAAA,OAAO,EAAE,IAAI;EACd,SAAA;EACF,KAAA;GACF,CAAC;EAIF;;;;;;;EAOG;EACH,MAAM,yBAAyB,CAAA;EAI7B,IAAA,WAAA,CAAoB,OAAgB,EAAA;UAAhB,IAAO,CAAA,OAAA,GAAP,OAAO,CAAS;OAAI;EAExC,IAAA,KAAK,CAAC,eAA4B,EAAE,KAAsB,EAAE,OAAmB,EAAA;;EAE7E,QAAA,IAAI,cAAc,CAAC;;UAGnB,IAAI,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,YAAY,EAAE,CAAC;;EAGpD,QAAA,IAAI,QAAQ,GAAG;EACb,YAAA,EAAE,EAAE,IAAI;EACR,YAAA,MAAM,EAAE,IAAI;WACb,CAAC;;EAGF,QAAA,IAAI,SAAS,CAAC;;UAGd,IAAI,CAAC,OAAO,CAAC,SAAS;EACnB,aAAA,cAAc,CAAC,KAAK,CAAC,QAAQ,CAAC;EAC9B,aAAA,IAAI,CAAC,CAAC,MAAM,KAAI;cACf,IAAI,OAAO,KAAK,IAAI,EAAE;EACpB,gBAAA,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC,kBAAkB,EAAE,CAAC;EAC1C,gBAAA,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC;kBAC3B,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;EACzC,aAAA;EAAM,iBAAA;EACL,gBAAA,IAAI,CAAC,KAAK,GAAG,MAAM,CAAC;EACpB,gBAAA,IAAI,CAAC,KAAK,CAAC,WAAW,GAAG,CAAC,CAAC;EAC5B,aAAA;EACD,YAAA,UAAU,EAAE,CAAC;EACf,SAAC,CAAC;EACD,aAAA,KAAK,CAAC,CAAC,GAAG,KAAI;cACb,OAAO,CAAC,KAAK,CACX,CAAA,2BAAA,EAA8B,KAAK,CAAC,QAAQ,CAA2F,yFAAA,CAAA,CACxI,CAAC;EACF,YAAA,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;EACrB,SAAC,CAAC,CAAC;UAEL,MAAM,UAAU,GAAG,MAAK;;cAEtB,IAAI,KAAK,CAAC,sBAAsB,EAAE;kBAChC,IAAI,CAAC,KAAK,CAAC,gBAAgB,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;EACjD,aAAA;;cAGD,IAAI,CAAC,KAAK,CAAC,8BAA8B,IAAI,CAAC,KAAK,CAAC,sBAAsB,EAAE;kBAC1E,IAAI,CAAC,KAAK,CAAC,gBAAgB,CAAC,OAAO,EAAE,cAAc,CAAC,CAAC;EACtD,aAAA;;cAGD,IAAI,OAAO,GAAG,EAAE,CAAC;cACjB,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,WAAW,CAAC,EAAE;kBACpC,IAAI,KAAK,CAAC,WAAW,CAAC,MAAM,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,EAAE;EACpD,oBAAA,OAAO,GAAG,KAAK,CAAC,WAAW,CAAC;EAC7B,iBAAA;EAAM,qBAAA;EACL,oBAAA,OAAO,CAAC,KAAK,CACX,2HAA2H,CAC5H,CAAC;EACH,iBAAA;EACF,aAAA;EAAM,iBAAA;EACL,gBAAA,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;EAC7C,oBAAA,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;EACjC,iBAAA;EACF,aAAA;cAED,IAAI,IAAI,GAAG,mDAAmD,CAAC;EAC/D,YAAA,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;EAC7C,gBAAA,IAAI,GAAG,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,WAAW,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;kBAC5D,IAAI;sBACF,0GAA0G;EAC1G,wBAAA,KAAK,CAAC,eAAe;0BACrB,GAAG;EACH,wBAAA,KAAK,CAAC,iBAAiB;0BACvB,6CAA6C;0BAC7C,CAAC;0BACD,iBAAiB;0BACjB,CAAC;0BACD,IAAI;0BACJ,GAAG;EACH,wBAAA,QAAQ,CAAC;EACZ,aAAA;cACD,IAAI,IAAI,QAAQ,CAAC;;EAGjB,YAAA,IAAI,KAAK,CAAC,MAAM,KAAK,IAAI,EAAE;EACzB,gBAAA,IAAI,IAAI,KAAK,CAAC,MAAM,CAAC;EACtB,aAAA;EAED,YAAA,eAAe,CAAC,SAAS,GAAG,IAAI,CAAC;cAEjC,IAAI,KAAK,CAAC,8BAA8B,EAAE;EACxC,gBAAA,cAAc,EAAE,CAAC;EAClB,aAAA;EAAM,iBAAA;EACL,gBAAA,eAAe,EAAE,CAAC;EACnB,aAAA;;EAGD,YAAA,SAAS,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;;cAG9B,IAAI,OAAO,KAAK,IAAI,EAAE;EACpB,gBAAA,SAAS,GAAG,OAAO,CAAC,WAAW,CAAC;EAChC,gBAAA,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;EAC7B,aAAA;EAAM,iBAAA;EACL,gBAAA,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;EACnB,aAAA;;EAGD,YAAA,IAAI,KAAK,CAAC,cAAc,KAAK,IAAI,EAAE;kBACjC,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,UAAU,CAAC,MAAK;EACrC,oBAAA,SAAS,EAAE,CAAC;EACd,iBAAC,EAAE,KAAK,CAAC,cAAc,CAAC,CAAC;EAC1B,aAAA;EAED,YAAA,OAAO,EAAE,CAAC;EACZ,SAAC,CAAC;;UAGF,SAAS,cAAc,CAAC,MAAM,EAAA;;EAE5B,YAAA,IAAI,OAAO,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;cAChC,IAAI,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,GAAG,SAAS,CAAC,CAAC;cACzC,IAAI,OAAO,KAAK,IAAI,EAAE;EACpB,gBAAA,OAAO,GAAG,OAAO,CAAC,WAAW,CAAC;EAC9B,gBAAA,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,OAAO,GAAG,SAAS,IAAI,IAAI,CAAC,CAAC;EAC/C,aAAA;EACD,YAAA,QAAQ,CAAC,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC;EACnC,YAAA,QAAQ,CAAC,EAAE,GAAG,EAAE,CAAC;;EAGjB,YAAA,eAAe,EAAE,CAAC;cAElB,IAAI,KAAK,CAAC,mBAAmB,EAAE;EAC7B,gBAAA,SAAS,EAAE,CAAC;EACb,aAAA;WACF;;UAGD,MAAM,SAAS,GAAG,MAAK;;EAErB,YAAA,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,gBAAgB,EAAE,CAAC;;;cAI1C,IAAI,OAAO,KAAK,IAAI,EAAE;EACpB,gBAAA,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;EACnB,aAAA;EAAM,iBAAA;EACL,gBAAA,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;EACpB,aAAA;cAED,IAAI,CAAC,KAAK,CAAC,mBAAmB,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;cACnD,IAAI,CAAC,KAAK,CAAC,mBAAmB,CAAC,OAAO,EAAE,cAAc,CAAC,CAAC;;EAGxD,YAAA,IAAI,UAAU,GAAG;kBACf,EAAE,EAAE,QAAQ,CAAC,EAAE;kBACf,QAAQ,EAAE,KAAK,CAAC,QAAQ;kBACxB,QAAQ,EAAE,QAAQ,CAAC,MAAM;eAC1B,CAAC;;EAGF,YAAA,eAAe,CAAC,SAAS,GAAG,EAAE,CAAC;;EAG/B,YAAA,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC;EAErC,YAAA,cAAc,EAAE,CAAC;EACnB,SAAC,CAAC;UAEF,SAAS,eAAe,CAAC,CAAC,EAAA;EACxB,YAAA,IAAI,MAAM,GAAG,CAAC,CAAC,aAAa,CAAC,YAAY,CAAC,aAAa,CAAC,CAAC;cACzD,cAAc,CAAC,MAAM,CAAC,CAAC;WACxB;EAED,QAAA,SAAS,eAAe,GAAA;cACtB,IAAI,IAAI,GAAG,QAAQ,CAAC,gBAAgB,CAAC,uCAAuC,CAAC,CAAC;EAC9E,YAAA,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;kBACpC,IAAI,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;EAC7C,gBAAA,IAAI,MAAM,EAAE;EACV,oBAAA,MAAM,CAAC,QAAQ,GAAG,IAAI,CAAC;EACxB,iBAAA;kBACD,IAAI,CAAC,CAAC,CAAC,CAAC,mBAAmB,CAAC,OAAO,EAAE,eAAe,CAAC,CAAC;EACvD,aAAA;WACF;EAED,QAAA,SAAS,cAAc,GAAA;cACrB,IAAI,IAAI,GAAG,QAAQ,CAAC,gBAAgB,CAAC,uCAAuC,CAAC,CAAC;EAC9E,YAAA,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;kBACpC,IAAI,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;EAC7C,gBAAA,IAAI,MAAM,EAAE;EACV,oBAAA,MAAM,CAAC,QAAQ,GAAG,KAAK,CAAC;EACzB,iBAAA;kBACD,IAAI,CAAC,CAAC,CAAC,CAAC,gBAAgB,CAAC,OAAO,EAAE,eAAe,CAAC,CAAC;EACpD,aAAA;WACF;EAED,QAAA,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,KAAI;cAC7B,cAAc,GAAG,OAAO,CAAC;EAC3B,SAAC,CAAC,CAAC;OACJ;EAED,IAAA,QAAQ,CACN,KAAsB,EACtB,eAAe,EACf,kBAAuB,EACvB,aAAyB,EAAA;UAEzB,IAAI,eAAe,IAAI,WAAW,EAAE;EAClC,YAAA,aAAa,EAAE,CAAC;EAChB,YAAA,IAAI,CAAC,kBAAkB,CAAC,KAAK,EAAE,kBAAkB,CAAC,CAAC;EACpD,SAAA;UACD,IAAI,eAAe,IAAI,QAAQ,EAAE;cAC/B,IAAI,CAAC,eAAe,CAAC,KAAK,EAAE,kBAAkB,EAAE,aAAa,CAAC,CAAC;EAChE,SAAA;OACF;MAEO,sBAAsB,CAAC,KAAsB,EAAE,kBAAkB,EAAA;EACvE,QAAA,MAAM,YAAY,GAAG;cACnB,QAAQ,EAAE,KAAK,CAAC,QAAQ;EACxB,YAAA,EAAE,EAAE,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,gBAAgB,CAAC,GAAG,EAAE,EAAE,EAAE,CAAC,GAAG,GAAG,EAAE,IAAI,CAAC;EACvE,YAAA,QAAQ,EAAE,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,EAAE,KAAK,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC;WAC5E,CAAC;EAEF,QAAA,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,mBAAmB,CAAC,YAAY,EAAE,kBAAkB,CAAC,CAAC;UAE1F,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,+BAA+B,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;EAEpE,QAAA,OAAO,IAAI,CAAC;OACb;MAEO,kBAAkB,CAAC,KAAsB,EAAE,kBAAkB,EAAA;UACnE,MAAM,IAAI,GAAG,IAAI,CAAC,sBAAsB,CAAC,KAAK,EAAE,kBAAkB,CAAC,CAAC;EAEpE,QAAA,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;OAChC;EAEO,IAAA,eAAe,CAAC,KAAsB,EAAE,kBAAkB,EAAE,aAAyB,EAAA;UAC3F,MAAM,IAAI,GAAG,IAAI,CAAC,sBAAsB,CAAC,KAAK,EAAE,kBAAkB,CAAC,CAAC;UAEpE,MAAM,eAAe,GAAG,IAAI,CAAC,OAAO,CAAC,iBAAiB,EAAE,CAAC;UAEzD,MAAM,OAAO,GAAG,MAAK;EACnB,YAAA,IAAI,IAAI,CAAC,EAAE,KAAK,IAAI,EAAE;kBACpB,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,WAAW,CAChC,eAAe,CAAC,aAAa,CAAC,oBAAoB,IAAI,CAAC,QAAQ,CAAW,SAAA,CAAA,CAAC,EAC3E,IAAI,CAAC,EAAE,CACR,CAAC;EACH,aAAA;EACH,SAAC,CAAC;UAEF,IAAI,CAAC,KAAK,CAAC,eAAe,EAAE,KAAK,EAAE,MAAK;EACtC,YAAA,aAAa,EAAE,CAAC;EAChB,YAAA,IAAI,CAAC,KAAK,CAAC,8BAA8B,EAAE;kBACzC,IAAI,CAAC,KAAK,CAAC,gBAAgB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;EAC/C,aAAA;EAAM,iBAAA;EACL,gBAAA,OAAO,EAAE,CAAC;EACX,aAAA;EACH,SAAC,CAAC,CAAC;OACJ;;EAtQM,yBAAI,CAAA,IAAA,GAAG,IAAI;;;;;;;;"}
1
+ {"version":3,"file":"index.browser.js","sources":["../src/index.ts"],"sourcesContent":["import { JsPsych, JsPsychPlugin, ParameterType, TrialType } from \"jspsych\";\n\nconst info = <const>{\n name: \"audio-button-response\",\n parameters: {\n /** The audio to be played. */\n stimulus: {\n type: ParameterType.AUDIO,\n pretty_name: \"Stimulus\",\n default: undefined,\n },\n /** Array containing the label(s) for the button(s). */\n choices: {\n type: ParameterType.STRING,\n pretty_name: \"Choices\",\n default: undefined,\n array: true,\n },\n /** The HTML for creating button. Can create own style. Use the \"%choice%\" string to indicate where the label from the choices parameter should be inserted. */\n button_html: {\n type: ParameterType.HTML_STRING,\n pretty_name: \"Button HTML\",\n default: '<button class=\"jspsych-btn\">%choice%</button>',\n array: true,\n },\n /** Any content here will be displayed below the stimulus. */\n prompt: {\n type: ParameterType.HTML_STRING,\n pretty_name: \"Prompt\",\n default: null,\n },\n /** The maximum duration to wait for a response. */\n trial_duration: {\n type: ParameterType.INT,\n pretty_name: \"Trial duration\",\n default: null,\n },\n /** Vertical margin of button. */\n margin_vertical: {\n type: ParameterType.STRING,\n pretty_name: \"Margin vertical\",\n default: \"0px\",\n },\n /** Horizontal margin of button. */\n margin_horizontal: {\n type: ParameterType.STRING,\n pretty_name: \"Margin horizontal\",\n default: \"8px\",\n },\n /** If true, the trial will end when user makes a response. */\n response_ends_trial: {\n type: ParameterType.BOOL,\n pretty_name: \"Response ends trial\",\n default: true,\n },\n /** If true, then the trial will end as soon as the audio file finishes playing. */\n trial_ends_after_audio: {\n type: ParameterType.BOOL,\n pretty_name: \"Trial ends after audio\",\n default: false,\n },\n /**\n * If true, then responses are allowed while the audio is playing.\n * If false, then the audio must finish playing before a response is accepted.\n */\n response_allowed_while_playing: {\n type: ParameterType.BOOL,\n pretty_name: \"Response allowed while playing\",\n default: true,\n },\n /** The delay of enabling button */\n enable_button_after: {\n type: ParameterType.INT,\n pretty_name: \"Enable button after\",\n default: 0,\n },\n },\n};\n\ntype Info = typeof info;\n\n/**\n * **audio-button-response**\n *\n * jsPsych plugin for playing an audio file and getting a button response\n *\n * @author Kristin Diep\n * @see {@link https://www.jspsych.org/plugins/jspsych-audio-button-response/ audio-button-response plugin documentation on jspsych.org}\n */\nclass AudioButtonResponsePlugin implements JsPsychPlugin<Info> {\n static info = info;\n private audio;\n\n constructor(private jsPsych: JsPsych) {}\n\n trial(display_element: HTMLElement, trial: TrialType<Info>, on_load: () => void) {\n // hold the .resolve() function from the Promise that ends the trial\n let trial_complete;\n\n // setup stimulus\n var context = this.jsPsych.pluginAPI.audioContext();\n\n // store response\n var response = {\n rt: null,\n button: null,\n };\n\n // record webaudio context start time\n var startTime;\n\n // load audio file\n this.jsPsych.pluginAPI\n .getAudioBuffer(trial.stimulus)\n .then((buffer) => {\n if (context !== null) {\n this.audio = context.createBufferSource();\n this.audio.buffer = buffer;\n this.audio.connect(context.destination);\n } else {\n this.audio = buffer;\n this.audio.currentTime = 0;\n }\n setupTrial();\n })\n .catch((err) => {\n console.error(\n `Failed to load audio file \"${trial.stimulus}\". Try checking the file path. We recommend using the preload plugin to load audio files.`\n );\n console.error(err);\n });\n\n const setupTrial = () => {\n // set up end event if trial needs it\n if (trial.trial_ends_after_audio) {\n this.audio.addEventListener(\"ended\", end_trial);\n }\n\n // enable buttons after audio ends if necessary\n if (!trial.response_allowed_while_playing && !trial.trial_ends_after_audio) {\n this.audio.addEventListener(\"ended\", enable_buttons);\n }\n\n //display buttons\n var buttons = [];\n if (Array.isArray(trial.button_html)) {\n if (trial.button_html.length == trial.choices.length) {\n buttons = trial.button_html;\n } else {\n console.error(\n \"Error in audio-button-response plugin. The length of the button_html array does not equal the length of the choices array\"\n );\n }\n } else {\n for (var i = 0; i < trial.choices.length; i++) {\n buttons.push(trial.button_html);\n }\n }\n\n var html = '<div id=\"jspsych-audio-button-response-btngroup\">';\n for (var i = 0; i < trial.choices.length; i++) {\n var str = buttons[i].replace(/%choice%/g, trial.choices[i]);\n html +=\n '<div class=\"jspsych-audio-button-response-button\" style=\"cursor: pointer; display: inline-block; margin:' +\n trial.margin_vertical +\n \" \" +\n trial.margin_horizontal +\n '\" id=\"jspsych-audio-button-response-button-' +\n i +\n '\" data-choice=\"' +\n i +\n '\">' +\n str +\n \"</div>\";\n }\n html += \"</div>\";\n\n //show prompt if there is one\n if (trial.prompt !== null) {\n html += trial.prompt;\n }\n\n display_element.innerHTML = html;\n\n if (trial.response_allowed_while_playing) {\n disable_buttons();\n enable_buttons();\n } else {\n disable_buttons();\n }\n\n // start time\n startTime = performance.now();\n\n // start audio\n if (context !== null) {\n startTime = context.currentTime;\n this.audio.start(startTime);\n } else {\n this.audio.play();\n }\n\n // end trial if time limit is set\n if (trial.trial_duration !== null) {\n this.jsPsych.pluginAPI.setTimeout(() => {\n end_trial();\n }, trial.trial_duration);\n }\n\n on_load();\n };\n\n // function to handle responses by the subject\n function after_response(choice) {\n // measure rt\n var endTime = performance.now();\n var rt = Math.round(endTime - startTime);\n if (context !== null) {\n endTime = context.currentTime;\n rt = Math.round((endTime - startTime) * 1000);\n }\n response.button = parseInt(choice);\n response.rt = rt;\n\n // disable all the buttons after a response\n disable_buttons();\n\n if (trial.response_ends_trial) {\n end_trial();\n }\n }\n\n // function to end trial when it is time\n const end_trial = () => {\n // kill any remaining setTimeout handlers\n this.jsPsych.pluginAPI.clearAllTimeouts();\n\n // stop the audio file if it is playing\n // remove end event listeners if they exist\n if (context !== null) {\n this.audio.stop();\n } else {\n this.audio.pause();\n }\n\n this.audio.removeEventListener(\"ended\", end_trial);\n this.audio.removeEventListener(\"ended\", enable_buttons);\n\n // gather the data to store for the trial\n var trial_data = {\n rt: response.rt,\n stimulus: trial.stimulus,\n response: response.button,\n };\n\n // clear the display\n display_element.innerHTML = \"\";\n\n // move on to the next trial\n this.jsPsych.finishTrial(trial_data);\n\n trial_complete();\n };\n\n const enable_buttons_with_delay = (delay: number) => {\n this.jsPsych.pluginAPI.setTimeout(enable_buttons_without_delay, delay);\n };\n\n function button_response(e) {\n var choice = e.currentTarget.getAttribute(\"data-choice\"); // don't use dataset for jsdom compatibility\n after_response(choice);\n }\n\n function disable_buttons() {\n var btns = document.querySelectorAll(\".jspsych-audio-button-response-button\");\n for (var i = 0; i < btns.length; i++) {\n var btn_el = btns[i].querySelector(\"button\");\n if (btn_el) {\n btn_el.disabled = true;\n }\n btns[i].removeEventListener(\"click\", button_response);\n }\n }\n\n function enable_buttons_without_delay() {\n var btns = document.querySelectorAll(\".jspsych-audio-button-response-button\");\n for (var i = 0; i < btns.length; i++) {\n var btn_el = btns[i].querySelector(\"button\");\n if (btn_el) {\n btn_el.disabled = false;\n }\n btns[i].addEventListener(\"click\", button_response);\n }\n }\n\n function enable_buttons() {\n if (trial.enable_button_after > 0) {\n enable_buttons_with_delay(trial.enable_button_after);\n } else {\n enable_buttons_without_delay();\n }\n }\n\n return new Promise((resolve) => {\n trial_complete = resolve;\n });\n }\n\n simulate(\n trial: TrialType<Info>,\n simulation_mode,\n simulation_options: any,\n load_callback: () => void\n ) {\n if (simulation_mode == \"data-only\") {\n load_callback();\n this.simulate_data_only(trial, simulation_options);\n }\n if (simulation_mode == \"visual\") {\n this.simulate_visual(trial, simulation_options, load_callback);\n }\n }\n\n private create_simulation_data(trial: TrialType<Info>, simulation_options) {\n const default_data = {\n stimulus: trial.stimulus,\n rt:\n this.jsPsych.randomization.sampleExGaussian(500, 50, 1 / 150, true) +\n trial.enable_button_after,\n response: this.jsPsych.randomization.randomInt(0, trial.choices.length - 1),\n };\n\n const data = this.jsPsych.pluginAPI.mergeSimulationData(default_data, simulation_options);\n\n this.jsPsych.pluginAPI.ensureSimulationDataConsistency(trial, data);\n\n return data;\n }\n\n private simulate_data_only(trial: TrialType<Info>, simulation_options) {\n const data = this.create_simulation_data(trial, simulation_options);\n\n this.jsPsych.finishTrial(data);\n }\n\n private simulate_visual(trial: TrialType<Info>, simulation_options, load_callback: () => void) {\n const data = this.create_simulation_data(trial, simulation_options);\n\n const display_element = this.jsPsych.getDisplayElement();\n\n const respond = () => {\n if (data.rt !== null) {\n this.jsPsych.pluginAPI.clickTarget(\n display_element.querySelector(`div[data-choice=\"${data.response}\"] button`),\n data.rt\n );\n }\n };\n\n this.trial(display_element, trial, () => {\n load_callback();\n if (!trial.response_allowed_while_playing) {\n this.audio.addEventListener(\"ended\", respond);\n } else {\n respond();\n }\n });\n }\n}\n\nexport default AudioButtonResponsePlugin;\n"],"names":["ParameterType"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- var jsPsychAudioButtonResponse=function(e){"use strict";function t(e,t){for(var n=0;n<t.length;n++){var r=t[n];r.enumerable=r.enumerable||!1,r.configurable=!0,"value"in r&&(r.writable=!0),Object.defineProperty(e,(a=r.key,i=void 0,"symbol"==typeof(i=function(e,t){if("object"!=typeof e||null===e)return e;var n=e[Symbol.toPrimitive];if(void 0!==n){var r=n.call(e,t||"default");if("object"!=typeof r)return r;throw new TypeError("@@toPrimitive must return a primitive value.")}return("string"===t?String:Number)(e)}(a,"string"))?i:String(i)),r)}var a,i}var n={name:"audio-button-response",parameters:{stimulus:{type:e.ParameterType.AUDIO,pretty_name:"Stimulus",default:void 0},choices:{type:e.ParameterType.STRING,pretty_name:"Choices",default:void 0,array:!0},button_html:{type:e.ParameterType.HTML_STRING,pretty_name:"Button HTML",default:'<button class="jspsych-btn">%choice%</button>',array:!0},prompt:{type:e.ParameterType.HTML_STRING,pretty_name:"Prompt",default:null},trial_duration:{type:e.ParameterType.INT,pretty_name:"Trial duration",default:null},margin_vertical:{type:e.ParameterType.STRING,pretty_name:"Margin vertical",default:"0px"},margin_horizontal:{type:e.ParameterType.STRING,pretty_name:"Margin horizontal",default:"8px"},response_ends_trial:{type:e.ParameterType.BOOL,pretty_name:"Response ends trial",default:!0},trial_ends_after_audio:{type:e.ParameterType.BOOL,pretty_name:"Trial ends after audio",default:!1},response_allowed_while_playing:{type:e.ParameterType.BOOL,pretty_name:"Response allowed while playing",default:!0}}},r=function(){function e(t){!function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}(this,e),this.jsPsych=t}var n,r,a;return n=e,(r=[{key:"trial",value:function(e,t,n){var r,a,i=this,o=this.jsPsych.pluginAPI.audioContext(),u={rt:null,button:null};this.jsPsych.pluginAPI.getAudioBuffer(t.stimulus).then((function(e){null!==o?(i.audio=o.createBufferSource(),i.audio.buffer=e,i.audio.connect(o.destination)):(i.audio=e,i.audio.currentTime=0),s()})).catch((function(e){console.error('Failed to load audio file "'.concat(t.stimulus,'". Try checking the file path. We recommend using the preload plugin to load audio files.')),console.error(e)}));var s=function(){t.trial_ends_after_audio&&i.audio.addEventListener("ended",l),t.response_allowed_while_playing||t.trial_ends_after_audio||i.audio.addEventListener("ended",p);var r=[];if(Array.isArray(t.button_html))t.button_html.length==t.choices.length?r=t.button_html:console.error("Error in audio-button-response plugin. The length of the button_html array does not equal the length of the choices array");else for(var u=0;u<t.choices.length;u++)r.push(t.button_html);var s='<div id="jspsych-audio-button-response-btngroup">';for(u=0;u<t.choices.length;u++){var c=r[u].replace(/%choice%/g,t.choices[u]);s+='<div class="jspsych-audio-button-response-button" style="cursor: pointer; display: inline-block; margin:'+t.margin_vertical+" "+t.margin_horizontal+'" id="jspsych-audio-button-response-button-'+u+'" data-choice="'+u+'">'+c+"</div>"}s+="</div>",null!==t.prompt&&(s+=t.prompt),e.innerHTML=s,t.response_allowed_while_playing?p():d(),a=performance.now(),null!==o?(a=o.currentTime,i.audio.start(a)):i.audio.play(),null!==t.trial_duration&&i.jsPsych.pluginAPI.setTimeout((function(){l()}),t.trial_duration),n()},l=function n(){i.jsPsych.pluginAPI.clearAllTimeouts(),null!==o?i.audio.stop():i.audio.pause(),i.audio.removeEventListener("ended",n),i.audio.removeEventListener("ended",p);var a={rt:u.rt,stimulus:t.stimulus,response:u.button};e.innerHTML="",i.jsPsych.finishTrial(a),r()};function c(e){!function(e){var n=performance.now(),r=Math.round(n-a);null!==o&&(n=o.currentTime,r=Math.round(1e3*(n-a))),u.button=parseInt(e),u.rt=r,d(),t.response_ends_trial&&l()}(e.currentTarget.getAttribute("data-choice"))}function d(){for(var e=document.querySelectorAll(".jspsych-audio-button-response-button"),t=0;t<e.length;t++){var n=e[t].querySelector("button");n&&(n.disabled=!0),e[t].removeEventListener("click",c)}}function p(){for(var e=document.querySelectorAll(".jspsych-audio-button-response-button"),t=0;t<e.length;t++){var n=e[t].querySelector("button");n&&(n.disabled=!1),e[t].addEventListener("click",c)}}return new Promise((function(e){r=e}))}},{key:"simulate",value:function(e,t,n,r){"data-only"==t&&(r(),this.simulate_data_only(e,n)),"visual"==t&&this.simulate_visual(e,n,r)}},{key:"create_simulation_data",value:function(e,t){var n={stimulus:e.stimulus,rt:this.jsPsych.randomization.sampleExGaussian(500,50,1/150,!0),response:this.jsPsych.randomization.randomInt(0,e.choices.length-1)},r=this.jsPsych.pluginAPI.mergeSimulationData(n,t);return this.jsPsych.pluginAPI.ensureSimulationDataConsistency(e,r),r}},{key:"simulate_data_only",value:function(e,t){var n=this.create_simulation_data(e,t);this.jsPsych.finishTrial(n)}},{key:"simulate_visual",value:function(e,t,n){var r=this,a=this.create_simulation_data(e,t),i=this.jsPsych.getDisplayElement(),o=function(){null!==a.rt&&r.jsPsych.pluginAPI.clickTarget(i.querySelector('div[data-choice="'.concat(a.response,'"] button')),a.rt)};this.trial(i,e,(function(){n(),e.response_allowed_while_playing?o():r.audio.addEventListener("ended",o)}))}}])&&t(n.prototype,r),a&&t(n,a),Object.defineProperty(n,"prototype",{writable:!1}),e}();return r.info=n,r}(jsPsychModule);
2
- //# sourceMappingURL=https://unpkg.com/@jspsych/plugin-audio-button-response@1.1.3/dist/index.browser.min.js.map
1
+ var jsPsychAudioButtonResponse=function(e){"use strict";function t(e,t){for(var n=0;n<t.length;n++){var a=t[n];a.enumerable=a.enumerable||!1,a.configurable=!0,"value"in a&&(a.writable=!0),Object.defineProperty(e,(r=a.key,i=void 0,"symbol"==typeof(i=function(e,t){if("object"!=typeof e||null===e)return e;var n=e[Symbol.toPrimitive];if(void 0!==n){var a=n.call(e,t||"default");if("object"!=typeof a)return a;throw new TypeError("@@toPrimitive must return a primitive value.")}return("string"===t?String:Number)(e)}(r,"string"))?i:String(i)),a)}var r,i}var n={name:"audio-button-response",parameters:{stimulus:{type:e.ParameterType.AUDIO,pretty_name:"Stimulus",default:void 0},choices:{type:e.ParameterType.STRING,pretty_name:"Choices",default:void 0,array:!0},button_html:{type:e.ParameterType.HTML_STRING,pretty_name:"Button HTML",default:'<button class="jspsych-btn">%choice%</button>',array:!0},prompt:{type:e.ParameterType.HTML_STRING,pretty_name:"Prompt",default:null},trial_duration:{type:e.ParameterType.INT,pretty_name:"Trial duration",default:null},margin_vertical:{type:e.ParameterType.STRING,pretty_name:"Margin vertical",default:"0px"},margin_horizontal:{type:e.ParameterType.STRING,pretty_name:"Margin horizontal",default:"8px"},response_ends_trial:{type:e.ParameterType.BOOL,pretty_name:"Response ends trial",default:!0},trial_ends_after_audio:{type:e.ParameterType.BOOL,pretty_name:"Trial ends after audio",default:!1},response_allowed_while_playing:{type:e.ParameterType.BOOL,pretty_name:"Response allowed while playing",default:!0},enable_button_after:{type:e.ParameterType.INT,pretty_name:"Enable button after",default:0}}},a=function(){function e(t){!function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}(this,e),this.jsPsych=t}var n,a,r;return n=e,(a=[{key:"trial",value:function(e,t,n){var a,r,i=this,o=this.jsPsych.pluginAPI.audioContext(),u={rt:null,button:null};this.jsPsych.pluginAPI.getAudioBuffer(t.stimulus).then((function(e){null!==o?(i.audio=o.createBufferSource(),i.audio.buffer=e,i.audio.connect(o.destination)):(i.audio=e,i.audio.currentTime=0),s()})).catch((function(e){console.error('Failed to load audio file "'.concat(t.stimulus,'". Try checking the file path. We recommend using the preload plugin to load audio files.')),console.error(e)}));var s=function(){t.trial_ends_after_audio&&i.audio.addEventListener("ended",l),t.response_allowed_while_playing||t.trial_ends_after_audio||i.audio.addEventListener("ended",h);var a=[];if(Array.isArray(t.button_html))t.button_html.length==t.choices.length?a=t.button_html:console.error("Error in audio-button-response plugin. The length of the button_html array does not equal the length of the choices array");else for(var u=0;u<t.choices.length;u++)a.push(t.button_html);var s='<div id="jspsych-audio-button-response-btngroup">';for(u=0;u<t.choices.length;u++){var c=a[u].replace(/%choice%/g,t.choices[u]);s+='<div class="jspsych-audio-button-response-button" style="cursor: pointer; display: inline-block; margin:'+t.margin_vertical+" "+t.margin_horizontal+'" id="jspsych-audio-button-response-button-'+u+'" data-choice="'+u+'">'+c+"</div>"}s+="</div>",null!==t.prompt&&(s+=t.prompt),e.innerHTML=s,t.response_allowed_while_playing?(p(),h()):p(),r=performance.now(),null!==o?(r=o.currentTime,i.audio.start(r)):i.audio.play(),null!==t.trial_duration&&i.jsPsych.pluginAPI.setTimeout((function(){l()}),t.trial_duration),n()},l=function n(){i.jsPsych.pluginAPI.clearAllTimeouts(),null!==o?i.audio.stop():i.audio.pause(),i.audio.removeEventListener("ended",n),i.audio.removeEventListener("ended",h);var r={rt:u.rt,stimulus:t.stimulus,response:u.button};e.innerHTML="",i.jsPsych.finishTrial(r),a()},c=function(e){i.jsPsych.pluginAPI.setTimeout(y,e)};function d(e){!function(e){var n=performance.now(),a=Math.round(n-r);null!==o&&(n=o.currentTime,a=Math.round(1e3*(n-r))),u.button=parseInt(e),u.rt=a,p(),t.response_ends_trial&&l()}(e.currentTarget.getAttribute("data-choice"))}function p(){for(var e=document.querySelectorAll(".jspsych-audio-button-response-button"),t=0;t<e.length;t++){var n=e[t].querySelector("button");n&&(n.disabled=!0),e[t].removeEventListener("click",d)}}function y(){for(var e=document.querySelectorAll(".jspsych-audio-button-response-button"),t=0;t<e.length;t++){var n=e[t].querySelector("button");n&&(n.disabled=!1),e[t].addEventListener("click",d)}}function h(){t.enable_button_after>0?c(t.enable_button_after):y()}return new Promise((function(e){a=e}))}},{key:"simulate",value:function(e,t,n,a){"data-only"==t&&(a(),this.simulate_data_only(e,n)),"visual"==t&&this.simulate_visual(e,n,a)}},{key:"create_simulation_data",value:function(e,t){var n={stimulus:e.stimulus,rt:this.jsPsych.randomization.sampleExGaussian(500,50,1/150,!0)+e.enable_button_after,response:this.jsPsych.randomization.randomInt(0,e.choices.length-1)},a=this.jsPsych.pluginAPI.mergeSimulationData(n,t);return this.jsPsych.pluginAPI.ensureSimulationDataConsistency(e,a),a}},{key:"simulate_data_only",value:function(e,t){var n=this.create_simulation_data(e,t);this.jsPsych.finishTrial(n)}},{key:"simulate_visual",value:function(e,t,n){var a=this,r=this.create_simulation_data(e,t),i=this.jsPsych.getDisplayElement(),o=function(){null!==r.rt&&a.jsPsych.pluginAPI.clickTarget(i.querySelector('div[data-choice="'.concat(r.response,'"] button')),r.rt)};this.trial(i,e,(function(){n(),e.response_allowed_while_playing?o():a.audio.addEventListener("ended",o)}))}}])&&t(n.prototype,a),r&&t(n,r),Object.defineProperty(n,"prototype",{writable:!1}),e}();return a.info=n,a}(jsPsychModule);
2
+ //# sourceMappingURL=https://unpkg.com/@jspsych/plugin-audio-button-response@1.2.0/dist/index.browser.min.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.browser.min.js","sources":["../src/index.ts"],"sourcesContent":["import { JsPsych, JsPsychPlugin, ParameterType, TrialType } from \"jspsych\";\n\nconst info = <const>{\n name: \"audio-button-response\",\n parameters: {\n /** The audio to be played. */\n stimulus: {\n type: ParameterType.AUDIO,\n pretty_name: \"Stimulus\",\n default: undefined,\n },\n /** Array containing the label(s) for the button(s). */\n choices: {\n type: ParameterType.STRING,\n pretty_name: \"Choices\",\n default: undefined,\n array: true,\n },\n /** The HTML for creating button. Can create own style. Use the \"%choice%\" string to indicate where the label from the choices parameter should be inserted. */\n button_html: {\n type: ParameterType.HTML_STRING,\n pretty_name: \"Button HTML\",\n default: '<button class=\"jspsych-btn\">%choice%</button>',\n array: true,\n },\n /** Any content here will be displayed below the stimulus. */\n prompt: {\n type: ParameterType.HTML_STRING,\n pretty_name: \"Prompt\",\n default: null,\n },\n /** The maximum duration to wait for a response. */\n trial_duration: {\n type: ParameterType.INT,\n pretty_name: \"Trial duration\",\n default: null,\n },\n /** Vertical margin of button. */\n margin_vertical: {\n type: ParameterType.STRING,\n pretty_name: \"Margin vertical\",\n default: \"0px\",\n },\n /** Horizontal margin of button. */\n margin_horizontal: {\n type: ParameterType.STRING,\n pretty_name: \"Margin horizontal\",\n default: \"8px\",\n },\n /** If true, the trial will end when user makes a response. */\n response_ends_trial: {\n type: ParameterType.BOOL,\n pretty_name: \"Response ends trial\",\n default: true,\n },\n /** If true, then the trial will end as soon as the audio file finishes playing. */\n trial_ends_after_audio: {\n type: ParameterType.BOOL,\n pretty_name: \"Trial ends after audio\",\n default: false,\n },\n /**\n * If true, then responses are allowed while the audio is playing.\n * If false, then the audio must finish playing before a response is accepted.\n */\n response_allowed_while_playing: {\n type: ParameterType.BOOL,\n pretty_name: \"Response allowed while playing\",\n default: true,\n },\n },\n};\n\ntype Info = typeof info;\n\n/**\n * **audio-button-response**\n *\n * jsPsych plugin for playing an audio file and getting a button response\n *\n * @author Kristin Diep\n * @see {@link https://www.jspsych.org/plugins/jspsych-audio-button-response/ audio-button-response plugin documentation on jspsych.org}\n */\nclass AudioButtonResponsePlugin implements JsPsychPlugin<Info> {\n static info = info;\n private audio;\n\n constructor(private jsPsych: JsPsych) {}\n\n trial(display_element: HTMLElement, trial: TrialType<Info>, on_load: () => void) {\n // hold the .resolve() function from the Promise that ends the trial\n let trial_complete;\n\n // setup stimulus\n var context = this.jsPsych.pluginAPI.audioContext();\n\n // store response\n var response = {\n rt: null,\n button: null,\n };\n\n // record webaudio context start time\n var startTime;\n\n // load audio file\n this.jsPsych.pluginAPI\n .getAudioBuffer(trial.stimulus)\n .then((buffer) => {\n if (context !== null) {\n this.audio = context.createBufferSource();\n this.audio.buffer = buffer;\n this.audio.connect(context.destination);\n } else {\n this.audio = buffer;\n this.audio.currentTime = 0;\n }\n setupTrial();\n })\n .catch((err) => {\n console.error(\n `Failed to load audio file \"${trial.stimulus}\". Try checking the file path. We recommend using the preload plugin to load audio files.`\n );\n console.error(err);\n });\n\n const setupTrial = () => {\n // set up end event if trial needs it\n if (trial.trial_ends_after_audio) {\n this.audio.addEventListener(\"ended\", end_trial);\n }\n\n // enable buttons after audio ends if necessary\n if (!trial.response_allowed_while_playing && !trial.trial_ends_after_audio) {\n this.audio.addEventListener(\"ended\", enable_buttons);\n }\n\n //display buttons\n var buttons = [];\n if (Array.isArray(trial.button_html)) {\n if (trial.button_html.length == trial.choices.length) {\n buttons = trial.button_html;\n } else {\n console.error(\n \"Error in audio-button-response plugin. The length of the button_html array does not equal the length of the choices array\"\n );\n }\n } else {\n for (var i = 0; i < trial.choices.length; i++) {\n buttons.push(trial.button_html);\n }\n }\n\n var html = '<div id=\"jspsych-audio-button-response-btngroup\">';\n for (var i = 0; i < trial.choices.length; i++) {\n var str = buttons[i].replace(/%choice%/g, trial.choices[i]);\n html +=\n '<div class=\"jspsych-audio-button-response-button\" style=\"cursor: pointer; display: inline-block; margin:' +\n trial.margin_vertical +\n \" \" +\n trial.margin_horizontal +\n '\" id=\"jspsych-audio-button-response-button-' +\n i +\n '\" data-choice=\"' +\n i +\n '\">' +\n str +\n \"</div>\";\n }\n html += \"</div>\";\n\n //show prompt if there is one\n if (trial.prompt !== null) {\n html += trial.prompt;\n }\n\n display_element.innerHTML = html;\n\n if (trial.response_allowed_while_playing) {\n enable_buttons();\n } else {\n disable_buttons();\n }\n\n // start time\n startTime = performance.now();\n\n // start audio\n if (context !== null) {\n startTime = context.currentTime;\n this.audio.start(startTime);\n } else {\n this.audio.play();\n }\n\n // end trial if time limit is set\n if (trial.trial_duration !== null) {\n this.jsPsych.pluginAPI.setTimeout(() => {\n end_trial();\n }, trial.trial_duration);\n }\n\n on_load();\n };\n\n // function to handle responses by the subject\n function after_response(choice) {\n // measure rt\n var endTime = performance.now();\n var rt = Math.round(endTime - startTime);\n if (context !== null) {\n endTime = context.currentTime;\n rt = Math.round((endTime - startTime) * 1000);\n }\n response.button = parseInt(choice);\n response.rt = rt;\n\n // disable all the buttons after a response\n disable_buttons();\n\n if (trial.response_ends_trial) {\n end_trial();\n }\n }\n\n // function to end trial when it is time\n const end_trial = () => {\n // kill any remaining setTimeout handlers\n this.jsPsych.pluginAPI.clearAllTimeouts();\n\n // stop the audio file if it is playing\n // remove end event listeners if they exist\n if (context !== null) {\n this.audio.stop();\n } else {\n this.audio.pause();\n }\n\n this.audio.removeEventListener(\"ended\", end_trial);\n this.audio.removeEventListener(\"ended\", enable_buttons);\n\n // gather the data to store for the trial\n var trial_data = {\n rt: response.rt,\n stimulus: trial.stimulus,\n response: response.button,\n };\n\n // clear the display\n display_element.innerHTML = \"\";\n\n // move on to the next trial\n this.jsPsych.finishTrial(trial_data);\n\n trial_complete();\n };\n\n function button_response(e) {\n var choice = e.currentTarget.getAttribute(\"data-choice\"); // don't use dataset for jsdom compatibility\n after_response(choice);\n }\n\n function disable_buttons() {\n var btns = document.querySelectorAll(\".jspsych-audio-button-response-button\");\n for (var i = 0; i < btns.length; i++) {\n var btn_el = btns[i].querySelector(\"button\");\n if (btn_el) {\n btn_el.disabled = true;\n }\n btns[i].removeEventListener(\"click\", button_response);\n }\n }\n\n function enable_buttons() {\n var btns = document.querySelectorAll(\".jspsych-audio-button-response-button\");\n for (var i = 0; i < btns.length; i++) {\n var btn_el = btns[i].querySelector(\"button\");\n if (btn_el) {\n btn_el.disabled = false;\n }\n btns[i].addEventListener(\"click\", button_response);\n }\n }\n\n return new Promise((resolve) => {\n trial_complete = resolve;\n });\n }\n\n simulate(\n trial: TrialType<Info>,\n simulation_mode,\n simulation_options: any,\n load_callback: () => void\n ) {\n if (simulation_mode == \"data-only\") {\n load_callback();\n this.simulate_data_only(trial, simulation_options);\n }\n if (simulation_mode == \"visual\") {\n this.simulate_visual(trial, simulation_options, load_callback);\n }\n }\n\n private create_simulation_data(trial: TrialType<Info>, simulation_options) {\n const default_data = {\n stimulus: trial.stimulus,\n rt: this.jsPsych.randomization.sampleExGaussian(500, 50, 1 / 150, true),\n response: this.jsPsych.randomization.randomInt(0, trial.choices.length - 1),\n };\n\n const data = this.jsPsych.pluginAPI.mergeSimulationData(default_data, simulation_options);\n\n this.jsPsych.pluginAPI.ensureSimulationDataConsistency(trial, data);\n\n return data;\n }\n\n private simulate_data_only(trial: TrialType<Info>, simulation_options) {\n const data = this.create_simulation_data(trial, simulation_options);\n\n this.jsPsych.finishTrial(data);\n }\n\n private simulate_visual(trial: TrialType<Info>, simulation_options, load_callback: () => void) {\n const data = this.create_simulation_data(trial, simulation_options);\n\n const display_element = this.jsPsych.getDisplayElement();\n\n const respond = () => {\n if (data.rt !== null) {\n this.jsPsych.pluginAPI.clickTarget(\n display_element.querySelector(`div[data-choice=\"${data.response}\"] button`),\n data.rt\n );\n }\n };\n\n this.trial(display_element, trial, () => {\n load_callback();\n if (!trial.response_allowed_while_playing) {\n this.audio.addEventListener(\"ended\", respond);\n } else {\n respond();\n }\n });\n }\n}\n\nexport default AudioButtonResponsePlugin;\n"],"names":["info","name","parameters","stimulus","type","ParameterType","AUDIO","pretty_name","default","undefined","choices","STRING","array","button_html","HTML_STRING","prompt","trial_duration","INT","margin_vertical","margin_horizontal","response_ends_trial","BOOL","trial_ends_after_audio","response_allowed_while_playing","AudioButtonResponsePlugin","jsPsych","_classCallCheck","this","key","value","display_element","trial","on_load","trial_complete","startTime","_this","context","pluginAPI","audioContext","response","rt","button","getAudioBuffer","then","buffer","audio","createBufferSource","connect","destination","currentTime","setupTrial","err","console","error","concat","addEventListener","end_trial","enable_buttons","buttons","Array","isArray","length","i","push","html","str","replace","innerHTML","disable_buttons","performance","now","start","play","setTimeout","clearAllTimeouts","stop","pause","removeEventListener","trial_data","finishTrial","button_response","e","choice","endTime","Math","round","parseInt","after_response","currentTarget","getAttribute","btns","document","querySelectorAll","btn_el","querySelector","disabled","Promise","resolve","simulation_mode","simulation_options","load_callback","simulate_data_only","simulate_visual","default_data","randomization","sampleExGaussian","randomInt","data","mergeSimulationData","ensureSimulationDataConsistency","create_simulation_data","_this2","getDisplayElement","respond","clickTarget"],"mappings":"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"}
1
+ {"version":3,"file":"index.browser.min.js","sources":["../src/index.ts"],"sourcesContent":["import { JsPsych, JsPsychPlugin, ParameterType, TrialType } from \"jspsych\";\n\nconst info = <const>{\n name: \"audio-button-response\",\n parameters: {\n /** The audio to be played. */\n stimulus: {\n type: ParameterType.AUDIO,\n pretty_name: \"Stimulus\",\n default: undefined,\n },\n /** Array containing the label(s) for the button(s). */\n choices: {\n type: ParameterType.STRING,\n pretty_name: \"Choices\",\n default: undefined,\n array: true,\n },\n /** The HTML for creating button. Can create own style. Use the \"%choice%\" string to indicate where the label from the choices parameter should be inserted. */\n button_html: {\n type: ParameterType.HTML_STRING,\n pretty_name: \"Button HTML\",\n default: '<button class=\"jspsych-btn\">%choice%</button>',\n array: true,\n },\n /** Any content here will be displayed below the stimulus. */\n prompt: {\n type: ParameterType.HTML_STRING,\n pretty_name: \"Prompt\",\n default: null,\n },\n /** The maximum duration to wait for a response. */\n trial_duration: {\n type: ParameterType.INT,\n pretty_name: \"Trial duration\",\n default: null,\n },\n /** Vertical margin of button. */\n margin_vertical: {\n type: ParameterType.STRING,\n pretty_name: \"Margin vertical\",\n default: \"0px\",\n },\n /** Horizontal margin of button. */\n margin_horizontal: {\n type: ParameterType.STRING,\n pretty_name: \"Margin horizontal\",\n default: \"8px\",\n },\n /** If true, the trial will end when user makes a response. */\n response_ends_trial: {\n type: ParameterType.BOOL,\n pretty_name: \"Response ends trial\",\n default: true,\n },\n /** If true, then the trial will end as soon as the audio file finishes playing. */\n trial_ends_after_audio: {\n type: ParameterType.BOOL,\n pretty_name: \"Trial ends after audio\",\n default: false,\n },\n /**\n * If true, then responses are allowed while the audio is playing.\n * If false, then the audio must finish playing before a response is accepted.\n */\n response_allowed_while_playing: {\n type: ParameterType.BOOL,\n pretty_name: \"Response allowed while playing\",\n default: true,\n },\n /** The delay of enabling button */\n enable_button_after: {\n type: ParameterType.INT,\n pretty_name: \"Enable button after\",\n default: 0,\n },\n },\n};\n\ntype Info = typeof info;\n\n/**\n * **audio-button-response**\n *\n * jsPsych plugin for playing an audio file and getting a button response\n *\n * @author Kristin Diep\n * @see {@link https://www.jspsych.org/plugins/jspsych-audio-button-response/ audio-button-response plugin documentation on jspsych.org}\n */\nclass AudioButtonResponsePlugin implements JsPsychPlugin<Info> {\n static info = info;\n private audio;\n\n constructor(private jsPsych: JsPsych) {}\n\n trial(display_element: HTMLElement, trial: TrialType<Info>, on_load: () => void) {\n // hold the .resolve() function from the Promise that ends the trial\n let trial_complete;\n\n // setup stimulus\n var context = this.jsPsych.pluginAPI.audioContext();\n\n // store response\n var response = {\n rt: null,\n button: null,\n };\n\n // record webaudio context start time\n var startTime;\n\n // load audio file\n this.jsPsych.pluginAPI\n .getAudioBuffer(trial.stimulus)\n .then((buffer) => {\n if (context !== null) {\n this.audio = context.createBufferSource();\n this.audio.buffer = buffer;\n this.audio.connect(context.destination);\n } else {\n this.audio = buffer;\n this.audio.currentTime = 0;\n }\n setupTrial();\n })\n .catch((err) => {\n console.error(\n `Failed to load audio file \"${trial.stimulus}\". Try checking the file path. We recommend using the preload plugin to load audio files.`\n );\n console.error(err);\n });\n\n const setupTrial = () => {\n // set up end event if trial needs it\n if (trial.trial_ends_after_audio) {\n this.audio.addEventListener(\"ended\", end_trial);\n }\n\n // enable buttons after audio ends if necessary\n if (!trial.response_allowed_while_playing && !trial.trial_ends_after_audio) {\n this.audio.addEventListener(\"ended\", enable_buttons);\n }\n\n //display buttons\n var buttons = [];\n if (Array.isArray(trial.button_html)) {\n if (trial.button_html.length == trial.choices.length) {\n buttons = trial.button_html;\n } else {\n console.error(\n \"Error in audio-button-response plugin. The length of the button_html array does not equal the length of the choices array\"\n );\n }\n } else {\n for (var i = 0; i < trial.choices.length; i++) {\n buttons.push(trial.button_html);\n }\n }\n\n var html = '<div id=\"jspsych-audio-button-response-btngroup\">';\n for (var i = 0; i < trial.choices.length; i++) {\n var str = buttons[i].replace(/%choice%/g, trial.choices[i]);\n html +=\n '<div class=\"jspsych-audio-button-response-button\" style=\"cursor: pointer; display: inline-block; margin:' +\n trial.margin_vertical +\n \" \" +\n trial.margin_horizontal +\n '\" id=\"jspsych-audio-button-response-button-' +\n i +\n '\" data-choice=\"' +\n i +\n '\">' +\n str +\n \"</div>\";\n }\n html += \"</div>\";\n\n //show prompt if there is one\n if (trial.prompt !== null) {\n html += trial.prompt;\n }\n\n display_element.innerHTML = html;\n\n if (trial.response_allowed_while_playing) {\n disable_buttons();\n enable_buttons();\n } else {\n disable_buttons();\n }\n\n // start time\n startTime = performance.now();\n\n // start audio\n if (context !== null) {\n startTime = context.currentTime;\n this.audio.start(startTime);\n } else {\n this.audio.play();\n }\n\n // end trial if time limit is set\n if (trial.trial_duration !== null) {\n this.jsPsych.pluginAPI.setTimeout(() => {\n end_trial();\n }, trial.trial_duration);\n }\n\n on_load();\n };\n\n // function to handle responses by the subject\n function after_response(choice) {\n // measure rt\n var endTime = performance.now();\n var rt = Math.round(endTime - startTime);\n if (context !== null) {\n endTime = context.currentTime;\n rt = Math.round((endTime - startTime) * 1000);\n }\n response.button = parseInt(choice);\n response.rt = rt;\n\n // disable all the buttons after a response\n disable_buttons();\n\n if (trial.response_ends_trial) {\n end_trial();\n }\n }\n\n // function to end trial when it is time\n const end_trial = () => {\n // kill any remaining setTimeout handlers\n this.jsPsych.pluginAPI.clearAllTimeouts();\n\n // stop the audio file if it is playing\n // remove end event listeners if they exist\n if (context !== null) {\n this.audio.stop();\n } else {\n this.audio.pause();\n }\n\n this.audio.removeEventListener(\"ended\", end_trial);\n this.audio.removeEventListener(\"ended\", enable_buttons);\n\n // gather the data to store for the trial\n var trial_data = {\n rt: response.rt,\n stimulus: trial.stimulus,\n response: response.button,\n };\n\n // clear the display\n display_element.innerHTML = \"\";\n\n // move on to the next trial\n this.jsPsych.finishTrial(trial_data);\n\n trial_complete();\n };\n\n const enable_buttons_with_delay = (delay: number) => {\n this.jsPsych.pluginAPI.setTimeout(enable_buttons_without_delay, delay);\n };\n\n function button_response(e) {\n var choice = e.currentTarget.getAttribute(\"data-choice\"); // don't use dataset for jsdom compatibility\n after_response(choice);\n }\n\n function disable_buttons() {\n var btns = document.querySelectorAll(\".jspsych-audio-button-response-button\");\n for (var i = 0; i < btns.length; i++) {\n var btn_el = btns[i].querySelector(\"button\");\n if (btn_el) {\n btn_el.disabled = true;\n }\n btns[i].removeEventListener(\"click\", button_response);\n }\n }\n\n function enable_buttons_without_delay() {\n var btns = document.querySelectorAll(\".jspsych-audio-button-response-button\");\n for (var i = 0; i < btns.length; i++) {\n var btn_el = btns[i].querySelector(\"button\");\n if (btn_el) {\n btn_el.disabled = false;\n }\n btns[i].addEventListener(\"click\", button_response);\n }\n }\n\n function enable_buttons() {\n if (trial.enable_button_after > 0) {\n enable_buttons_with_delay(trial.enable_button_after);\n } else {\n enable_buttons_without_delay();\n }\n }\n\n return new Promise((resolve) => {\n trial_complete = resolve;\n });\n }\n\n simulate(\n trial: TrialType<Info>,\n simulation_mode,\n simulation_options: any,\n load_callback: () => void\n ) {\n if (simulation_mode == \"data-only\") {\n load_callback();\n this.simulate_data_only(trial, simulation_options);\n }\n if (simulation_mode == \"visual\") {\n this.simulate_visual(trial, simulation_options, load_callback);\n }\n }\n\n private create_simulation_data(trial: TrialType<Info>, simulation_options) {\n const default_data = {\n stimulus: trial.stimulus,\n rt:\n this.jsPsych.randomization.sampleExGaussian(500, 50, 1 / 150, true) +\n trial.enable_button_after,\n response: this.jsPsych.randomization.randomInt(0, trial.choices.length - 1),\n };\n\n const data = this.jsPsych.pluginAPI.mergeSimulationData(default_data, simulation_options);\n\n this.jsPsych.pluginAPI.ensureSimulationDataConsistency(trial, data);\n\n return data;\n }\n\n private simulate_data_only(trial: TrialType<Info>, simulation_options) {\n const data = this.create_simulation_data(trial, simulation_options);\n\n this.jsPsych.finishTrial(data);\n }\n\n private simulate_visual(trial: TrialType<Info>, simulation_options, load_callback: () => void) {\n const data = this.create_simulation_data(trial, simulation_options);\n\n const display_element = this.jsPsych.getDisplayElement();\n\n const respond = () => {\n if (data.rt !== null) {\n this.jsPsych.pluginAPI.clickTarget(\n display_element.querySelector(`div[data-choice=\"${data.response}\"] button`),\n data.rt\n );\n }\n };\n\n this.trial(display_element, trial, () => {\n load_callback();\n if (!trial.response_allowed_while_playing) {\n this.audio.addEventListener(\"ended\", respond);\n } else {\n respond();\n }\n });\n }\n}\n\nexport default AudioButtonResponsePlugin;\n"],"names":["info","name","parameters","stimulus","type","ParameterType","AUDIO","pretty_name","default","undefined","choices","STRING","array","button_html","HTML_STRING","prompt","trial_duration","INT","margin_vertical","margin_horizontal","response_ends_trial","BOOL","trial_ends_after_audio","response_allowed_while_playing","enable_button_after","AudioButtonResponsePlugin","jsPsych","_classCallCheck","this","key","value","display_element","trial","on_load","trial_complete","startTime","_this","context","pluginAPI","audioContext","response","rt","button","getAudioBuffer","then","buffer","audio","createBufferSource","connect","destination","currentTime","setupTrial","err","console","error","concat","addEventListener","end_trial","enable_buttons","buttons","Array","isArray","length","i","push","html","str","replace","innerHTML","disable_buttons","performance","now","start","play","setTimeout","clearAllTimeouts","stop","pause","removeEventListener","trial_data","finishTrial","enable_buttons_with_delay","delay","enable_buttons_without_delay","button_response","e","choice","endTime","Math","round","parseInt","after_response","currentTarget","getAttribute","btns","document","querySelectorAll","btn_el","querySelector","disabled","Promise","resolve","simulation_mode","simulation_options","load_callback","simulate_data_only","simulate_visual","default_data","randomization","sampleExGaussian","randomInt","data","mergeSimulationData","ensureSimulationDataConsistency","create_simulation_data","_this2","getDisplayElement","respond","clickTarget"],"mappings":"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"}
package/dist/index.cjs CHANGED
@@ -70,6 +70,12 @@ const info = {
70
70
  pretty_name: "Response allowed while playing",
71
71
  default: true,
72
72
  },
73
+ /** The delay of enabling button */
74
+ enable_button_after: {
75
+ type: jspsych.ParameterType.INT,
76
+ pretty_name: "Enable button after",
77
+ default: 0,
78
+ },
73
79
  },
74
80
  };
75
81
  /**
@@ -162,6 +168,7 @@ class AudioButtonResponsePlugin {
162
168
  }
163
169
  display_element.innerHTML = html;
164
170
  if (trial.response_allowed_while_playing) {
171
+ disable_buttons();
165
172
  enable_buttons();
166
173
  }
167
174
  else {
@@ -228,6 +235,9 @@ class AudioButtonResponsePlugin {
228
235
  this.jsPsych.finishTrial(trial_data);
229
236
  trial_complete();
230
237
  };
238
+ const enable_buttons_with_delay = (delay) => {
239
+ this.jsPsych.pluginAPI.setTimeout(enable_buttons_without_delay, delay);
240
+ };
231
241
  function button_response(e) {
232
242
  var choice = e.currentTarget.getAttribute("data-choice"); // don't use dataset for jsdom compatibility
233
243
  after_response(choice);
@@ -242,7 +252,7 @@ class AudioButtonResponsePlugin {
242
252
  btns[i].removeEventListener("click", button_response);
243
253
  }
244
254
  }
245
- function enable_buttons() {
255
+ function enable_buttons_without_delay() {
246
256
  var btns = document.querySelectorAll(".jspsych-audio-button-response-button");
247
257
  for (var i = 0; i < btns.length; i++) {
248
258
  var btn_el = btns[i].querySelector("button");
@@ -252,6 +262,14 @@ class AudioButtonResponsePlugin {
252
262
  btns[i].addEventListener("click", button_response);
253
263
  }
254
264
  }
265
+ function enable_buttons() {
266
+ if (trial.enable_button_after > 0) {
267
+ enable_buttons_with_delay(trial.enable_button_after);
268
+ }
269
+ else {
270
+ enable_buttons_without_delay();
271
+ }
272
+ }
255
273
  return new Promise((resolve) => {
256
274
  trial_complete = resolve;
257
275
  });
@@ -268,7 +286,8 @@ class AudioButtonResponsePlugin {
268
286
  create_simulation_data(trial, simulation_options) {
269
287
  const default_data = {
270
288
  stimulus: trial.stimulus,
271
- rt: this.jsPsych.randomization.sampleExGaussian(500, 50, 1 / 150, true),
289
+ rt: this.jsPsych.randomization.sampleExGaussian(500, 50, 1 / 150, true) +
290
+ trial.enable_button_after,
272
291
  response: this.jsPsych.randomization.randomInt(0, trial.choices.length - 1),
273
292
  };
274
293
  const data = this.jsPsych.pluginAPI.mergeSimulationData(default_data, simulation_options);
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","sources":["../src/index.ts"],"sourcesContent":["import { JsPsych, JsPsychPlugin, ParameterType, TrialType } from \"jspsych\";\n\nconst info = <const>{\n name: \"audio-button-response\",\n parameters: {\n /** The audio to be played. */\n stimulus: {\n type: ParameterType.AUDIO,\n pretty_name: \"Stimulus\",\n default: undefined,\n },\n /** Array containing the label(s) for the button(s). */\n choices: {\n type: ParameterType.STRING,\n pretty_name: \"Choices\",\n default: undefined,\n array: true,\n },\n /** The HTML for creating button. Can create own style. Use the \"%choice%\" string to indicate where the label from the choices parameter should be inserted. */\n button_html: {\n type: ParameterType.HTML_STRING,\n pretty_name: \"Button HTML\",\n default: '<button class=\"jspsych-btn\">%choice%</button>',\n array: true,\n },\n /** Any content here will be displayed below the stimulus. */\n prompt: {\n type: ParameterType.HTML_STRING,\n pretty_name: \"Prompt\",\n default: null,\n },\n /** The maximum duration to wait for a response. */\n trial_duration: {\n type: ParameterType.INT,\n pretty_name: \"Trial duration\",\n default: null,\n },\n /** Vertical margin of button. */\n margin_vertical: {\n type: ParameterType.STRING,\n pretty_name: \"Margin vertical\",\n default: \"0px\",\n },\n /** Horizontal margin of button. */\n margin_horizontal: {\n type: ParameterType.STRING,\n pretty_name: \"Margin horizontal\",\n default: \"8px\",\n },\n /** If true, the trial will end when user makes a response. */\n response_ends_trial: {\n type: ParameterType.BOOL,\n pretty_name: \"Response ends trial\",\n default: true,\n },\n /** If true, then the trial will end as soon as the audio file finishes playing. */\n trial_ends_after_audio: {\n type: ParameterType.BOOL,\n pretty_name: \"Trial ends after audio\",\n default: false,\n },\n /**\n * If true, then responses are allowed while the audio is playing.\n * If false, then the audio must finish playing before a response is accepted.\n */\n response_allowed_while_playing: {\n type: ParameterType.BOOL,\n pretty_name: \"Response allowed while playing\",\n default: true,\n },\n },\n};\n\ntype Info = typeof info;\n\n/**\n * **audio-button-response**\n *\n * jsPsych plugin for playing an audio file and getting a button response\n *\n * @author Kristin Diep\n * @see {@link https://www.jspsych.org/plugins/jspsych-audio-button-response/ audio-button-response plugin documentation on jspsych.org}\n */\nclass AudioButtonResponsePlugin implements JsPsychPlugin<Info> {\n static info = info;\n private audio;\n\n constructor(private jsPsych: JsPsych) {}\n\n trial(display_element: HTMLElement, trial: TrialType<Info>, on_load: () => void) {\n // hold the .resolve() function from the Promise that ends the trial\n let trial_complete;\n\n // setup stimulus\n var context = this.jsPsych.pluginAPI.audioContext();\n\n // store response\n var response = {\n rt: null,\n button: null,\n };\n\n // record webaudio context start time\n var startTime;\n\n // load audio file\n this.jsPsych.pluginAPI\n .getAudioBuffer(trial.stimulus)\n .then((buffer) => {\n if (context !== null) {\n this.audio = context.createBufferSource();\n this.audio.buffer = buffer;\n this.audio.connect(context.destination);\n } else {\n this.audio = buffer;\n this.audio.currentTime = 0;\n }\n setupTrial();\n })\n .catch((err) => {\n console.error(\n `Failed to load audio file \"${trial.stimulus}\". Try checking the file path. We recommend using the preload plugin to load audio files.`\n );\n console.error(err);\n });\n\n const setupTrial = () => {\n // set up end event if trial needs it\n if (trial.trial_ends_after_audio) {\n this.audio.addEventListener(\"ended\", end_trial);\n }\n\n // enable buttons after audio ends if necessary\n if (!trial.response_allowed_while_playing && !trial.trial_ends_after_audio) {\n this.audio.addEventListener(\"ended\", enable_buttons);\n }\n\n //display buttons\n var buttons = [];\n if (Array.isArray(trial.button_html)) {\n if (trial.button_html.length == trial.choices.length) {\n buttons = trial.button_html;\n } else {\n console.error(\n \"Error in audio-button-response plugin. The length of the button_html array does not equal the length of the choices array\"\n );\n }\n } else {\n for (var i = 0; i < trial.choices.length; i++) {\n buttons.push(trial.button_html);\n }\n }\n\n var html = '<div id=\"jspsych-audio-button-response-btngroup\">';\n for (var i = 0; i < trial.choices.length; i++) {\n var str = buttons[i].replace(/%choice%/g, trial.choices[i]);\n html +=\n '<div class=\"jspsych-audio-button-response-button\" style=\"cursor: pointer; display: inline-block; margin:' +\n trial.margin_vertical +\n \" \" +\n trial.margin_horizontal +\n '\" id=\"jspsych-audio-button-response-button-' +\n i +\n '\" data-choice=\"' +\n i +\n '\">' +\n str +\n \"</div>\";\n }\n html += \"</div>\";\n\n //show prompt if there is one\n if (trial.prompt !== null) {\n html += trial.prompt;\n }\n\n display_element.innerHTML = html;\n\n if (trial.response_allowed_while_playing) {\n enable_buttons();\n } else {\n disable_buttons();\n }\n\n // start time\n startTime = performance.now();\n\n // start audio\n if (context !== null) {\n startTime = context.currentTime;\n this.audio.start(startTime);\n } else {\n this.audio.play();\n }\n\n // end trial if time limit is set\n if (trial.trial_duration !== null) {\n this.jsPsych.pluginAPI.setTimeout(() => {\n end_trial();\n }, trial.trial_duration);\n }\n\n on_load();\n };\n\n // function to handle responses by the subject\n function after_response(choice) {\n // measure rt\n var endTime = performance.now();\n var rt = Math.round(endTime - startTime);\n if (context !== null) {\n endTime = context.currentTime;\n rt = Math.round((endTime - startTime) * 1000);\n }\n response.button = parseInt(choice);\n response.rt = rt;\n\n // disable all the buttons after a response\n disable_buttons();\n\n if (trial.response_ends_trial) {\n end_trial();\n }\n }\n\n // function to end trial when it is time\n const end_trial = () => {\n // kill any remaining setTimeout handlers\n this.jsPsych.pluginAPI.clearAllTimeouts();\n\n // stop the audio file if it is playing\n // remove end event listeners if they exist\n if (context !== null) {\n this.audio.stop();\n } else {\n this.audio.pause();\n }\n\n this.audio.removeEventListener(\"ended\", end_trial);\n this.audio.removeEventListener(\"ended\", enable_buttons);\n\n // gather the data to store for the trial\n var trial_data = {\n rt: response.rt,\n stimulus: trial.stimulus,\n response: response.button,\n };\n\n // clear the display\n display_element.innerHTML = \"\";\n\n // move on to the next trial\n this.jsPsych.finishTrial(trial_data);\n\n trial_complete();\n };\n\n function button_response(e) {\n var choice = e.currentTarget.getAttribute(\"data-choice\"); // don't use dataset for jsdom compatibility\n after_response(choice);\n }\n\n function disable_buttons() {\n var btns = document.querySelectorAll(\".jspsych-audio-button-response-button\");\n for (var i = 0; i < btns.length; i++) {\n var btn_el = btns[i].querySelector(\"button\");\n if (btn_el) {\n btn_el.disabled = true;\n }\n btns[i].removeEventListener(\"click\", button_response);\n }\n }\n\n function enable_buttons() {\n var btns = document.querySelectorAll(\".jspsych-audio-button-response-button\");\n for (var i = 0; i < btns.length; i++) {\n var btn_el = btns[i].querySelector(\"button\");\n if (btn_el) {\n btn_el.disabled = false;\n }\n btns[i].addEventListener(\"click\", button_response);\n }\n }\n\n return new Promise((resolve) => {\n trial_complete = resolve;\n });\n }\n\n simulate(\n trial: TrialType<Info>,\n simulation_mode,\n simulation_options: any,\n load_callback: () => void\n ) {\n if (simulation_mode == \"data-only\") {\n load_callback();\n this.simulate_data_only(trial, simulation_options);\n }\n if (simulation_mode == \"visual\") {\n this.simulate_visual(trial, simulation_options, load_callback);\n }\n }\n\n private create_simulation_data(trial: TrialType<Info>, simulation_options) {\n const default_data = {\n stimulus: trial.stimulus,\n rt: this.jsPsych.randomization.sampleExGaussian(500, 50, 1 / 150, true),\n response: this.jsPsych.randomization.randomInt(0, trial.choices.length - 1),\n };\n\n const data = this.jsPsych.pluginAPI.mergeSimulationData(default_data, simulation_options);\n\n this.jsPsych.pluginAPI.ensureSimulationDataConsistency(trial, data);\n\n return data;\n }\n\n private simulate_data_only(trial: TrialType<Info>, simulation_options) {\n const data = this.create_simulation_data(trial, simulation_options);\n\n this.jsPsych.finishTrial(data);\n }\n\n private simulate_visual(trial: TrialType<Info>, simulation_options, load_callback: () => void) {\n const data = this.create_simulation_data(trial, simulation_options);\n\n const display_element = this.jsPsych.getDisplayElement();\n\n const respond = () => {\n if (data.rt !== null) {\n this.jsPsych.pluginAPI.clickTarget(\n display_element.querySelector(`div[data-choice=\"${data.response}\"] button`),\n data.rt\n );\n }\n };\n\n this.trial(display_element, trial, () => {\n load_callback();\n if (!trial.response_allowed_while_playing) {\n this.audio.addEventListener(\"ended\", respond);\n } else {\n respond();\n }\n });\n }\n}\n\nexport default AudioButtonResponsePlugin;\n"],"names":["ParameterType"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","sources":["../src/index.ts"],"sourcesContent":["import { JsPsych, JsPsychPlugin, ParameterType, TrialType } from \"jspsych\";\n\nconst info = <const>{\n name: \"audio-button-response\",\n parameters: {\n /** The audio to be played. */\n stimulus: {\n type: ParameterType.AUDIO,\n pretty_name: \"Stimulus\",\n default: undefined,\n },\n /** Array containing the label(s) for the button(s). */\n choices: {\n type: ParameterType.STRING,\n pretty_name: \"Choices\",\n default: undefined,\n array: true,\n },\n /** The HTML for creating button. Can create own style. Use the \"%choice%\" string to indicate where the label from the choices parameter should be inserted. */\n button_html: {\n type: ParameterType.HTML_STRING,\n pretty_name: \"Button HTML\",\n default: '<button class=\"jspsych-btn\">%choice%</button>',\n array: true,\n },\n /** Any content here will be displayed below the stimulus. */\n prompt: {\n type: ParameterType.HTML_STRING,\n pretty_name: \"Prompt\",\n default: null,\n },\n /** The maximum duration to wait for a response. */\n trial_duration: {\n type: ParameterType.INT,\n pretty_name: \"Trial duration\",\n default: null,\n },\n /** Vertical margin of button. */\n margin_vertical: {\n type: ParameterType.STRING,\n pretty_name: \"Margin vertical\",\n default: \"0px\",\n },\n /** Horizontal margin of button. */\n margin_horizontal: {\n type: ParameterType.STRING,\n pretty_name: \"Margin horizontal\",\n default: \"8px\",\n },\n /** If true, the trial will end when user makes a response. */\n response_ends_trial: {\n type: ParameterType.BOOL,\n pretty_name: \"Response ends trial\",\n default: true,\n },\n /** If true, then the trial will end as soon as the audio file finishes playing. */\n trial_ends_after_audio: {\n type: ParameterType.BOOL,\n pretty_name: \"Trial ends after audio\",\n default: false,\n },\n /**\n * If true, then responses are allowed while the audio is playing.\n * If false, then the audio must finish playing before a response is accepted.\n */\n response_allowed_while_playing: {\n type: ParameterType.BOOL,\n pretty_name: \"Response allowed while playing\",\n default: true,\n },\n /** The delay of enabling button */\n enable_button_after: {\n type: ParameterType.INT,\n pretty_name: \"Enable button after\",\n default: 0,\n },\n },\n};\n\ntype Info = typeof info;\n\n/**\n * **audio-button-response**\n *\n * jsPsych plugin for playing an audio file and getting a button response\n *\n * @author Kristin Diep\n * @see {@link https://www.jspsych.org/plugins/jspsych-audio-button-response/ audio-button-response plugin documentation on jspsych.org}\n */\nclass AudioButtonResponsePlugin implements JsPsychPlugin<Info> {\n static info = info;\n private audio;\n\n constructor(private jsPsych: JsPsych) {}\n\n trial(display_element: HTMLElement, trial: TrialType<Info>, on_load: () => void) {\n // hold the .resolve() function from the Promise that ends the trial\n let trial_complete;\n\n // setup stimulus\n var context = this.jsPsych.pluginAPI.audioContext();\n\n // store response\n var response = {\n rt: null,\n button: null,\n };\n\n // record webaudio context start time\n var startTime;\n\n // load audio file\n this.jsPsych.pluginAPI\n .getAudioBuffer(trial.stimulus)\n .then((buffer) => {\n if (context !== null) {\n this.audio = context.createBufferSource();\n this.audio.buffer = buffer;\n this.audio.connect(context.destination);\n } else {\n this.audio = buffer;\n this.audio.currentTime = 0;\n }\n setupTrial();\n })\n .catch((err) => {\n console.error(\n `Failed to load audio file \"${trial.stimulus}\". Try checking the file path. We recommend using the preload plugin to load audio files.`\n );\n console.error(err);\n });\n\n const setupTrial = () => {\n // set up end event if trial needs it\n if (trial.trial_ends_after_audio) {\n this.audio.addEventListener(\"ended\", end_trial);\n }\n\n // enable buttons after audio ends if necessary\n if (!trial.response_allowed_while_playing && !trial.trial_ends_after_audio) {\n this.audio.addEventListener(\"ended\", enable_buttons);\n }\n\n //display buttons\n var buttons = [];\n if (Array.isArray(trial.button_html)) {\n if (trial.button_html.length == trial.choices.length) {\n buttons = trial.button_html;\n } else {\n console.error(\n \"Error in audio-button-response plugin. The length of the button_html array does not equal the length of the choices array\"\n );\n }\n } else {\n for (var i = 0; i < trial.choices.length; i++) {\n buttons.push(trial.button_html);\n }\n }\n\n var html = '<div id=\"jspsych-audio-button-response-btngroup\">';\n for (var i = 0; i < trial.choices.length; i++) {\n var str = buttons[i].replace(/%choice%/g, trial.choices[i]);\n html +=\n '<div class=\"jspsych-audio-button-response-button\" style=\"cursor: pointer; display: inline-block; margin:' +\n trial.margin_vertical +\n \" \" +\n trial.margin_horizontal +\n '\" id=\"jspsych-audio-button-response-button-' +\n i +\n '\" data-choice=\"' +\n i +\n '\">' +\n str +\n \"</div>\";\n }\n html += \"</div>\";\n\n //show prompt if there is one\n if (trial.prompt !== null) {\n html += trial.prompt;\n }\n\n display_element.innerHTML = html;\n\n if (trial.response_allowed_while_playing) {\n disable_buttons();\n enable_buttons();\n } else {\n disable_buttons();\n }\n\n // start time\n startTime = performance.now();\n\n // start audio\n if (context !== null) {\n startTime = context.currentTime;\n this.audio.start(startTime);\n } else {\n this.audio.play();\n }\n\n // end trial if time limit is set\n if (trial.trial_duration !== null) {\n this.jsPsych.pluginAPI.setTimeout(() => {\n end_trial();\n }, trial.trial_duration);\n }\n\n on_load();\n };\n\n // function to handle responses by the subject\n function after_response(choice) {\n // measure rt\n var endTime = performance.now();\n var rt = Math.round(endTime - startTime);\n if (context !== null) {\n endTime = context.currentTime;\n rt = Math.round((endTime - startTime) * 1000);\n }\n response.button = parseInt(choice);\n response.rt = rt;\n\n // disable all the buttons after a response\n disable_buttons();\n\n if (trial.response_ends_trial) {\n end_trial();\n }\n }\n\n // function to end trial when it is time\n const end_trial = () => {\n // kill any remaining setTimeout handlers\n this.jsPsych.pluginAPI.clearAllTimeouts();\n\n // stop the audio file if it is playing\n // remove end event listeners if they exist\n if (context !== null) {\n this.audio.stop();\n } else {\n this.audio.pause();\n }\n\n this.audio.removeEventListener(\"ended\", end_trial);\n this.audio.removeEventListener(\"ended\", enable_buttons);\n\n // gather the data to store for the trial\n var trial_data = {\n rt: response.rt,\n stimulus: trial.stimulus,\n response: response.button,\n };\n\n // clear the display\n display_element.innerHTML = \"\";\n\n // move on to the next trial\n this.jsPsych.finishTrial(trial_data);\n\n trial_complete();\n };\n\n const enable_buttons_with_delay = (delay: number) => {\n this.jsPsych.pluginAPI.setTimeout(enable_buttons_without_delay, delay);\n };\n\n function button_response(e) {\n var choice = e.currentTarget.getAttribute(\"data-choice\"); // don't use dataset for jsdom compatibility\n after_response(choice);\n }\n\n function disable_buttons() {\n var btns = document.querySelectorAll(\".jspsych-audio-button-response-button\");\n for (var i = 0; i < btns.length; i++) {\n var btn_el = btns[i].querySelector(\"button\");\n if (btn_el) {\n btn_el.disabled = true;\n }\n btns[i].removeEventListener(\"click\", button_response);\n }\n }\n\n function enable_buttons_without_delay() {\n var btns = document.querySelectorAll(\".jspsych-audio-button-response-button\");\n for (var i = 0; i < btns.length; i++) {\n var btn_el = btns[i].querySelector(\"button\");\n if (btn_el) {\n btn_el.disabled = false;\n }\n btns[i].addEventListener(\"click\", button_response);\n }\n }\n\n function enable_buttons() {\n if (trial.enable_button_after > 0) {\n enable_buttons_with_delay(trial.enable_button_after);\n } else {\n enable_buttons_without_delay();\n }\n }\n\n return new Promise((resolve) => {\n trial_complete = resolve;\n });\n }\n\n simulate(\n trial: TrialType<Info>,\n simulation_mode,\n simulation_options: any,\n load_callback: () => void\n ) {\n if (simulation_mode == \"data-only\") {\n load_callback();\n this.simulate_data_only(trial, simulation_options);\n }\n if (simulation_mode == \"visual\") {\n this.simulate_visual(trial, simulation_options, load_callback);\n }\n }\n\n private create_simulation_data(trial: TrialType<Info>, simulation_options) {\n const default_data = {\n stimulus: trial.stimulus,\n rt:\n this.jsPsych.randomization.sampleExGaussian(500, 50, 1 / 150, true) +\n trial.enable_button_after,\n response: this.jsPsych.randomization.randomInt(0, trial.choices.length - 1),\n };\n\n const data = this.jsPsych.pluginAPI.mergeSimulationData(default_data, simulation_options);\n\n this.jsPsych.pluginAPI.ensureSimulationDataConsistency(trial, data);\n\n return data;\n }\n\n private simulate_data_only(trial: TrialType<Info>, simulation_options) {\n const data = this.create_simulation_data(trial, simulation_options);\n\n this.jsPsych.finishTrial(data);\n }\n\n private simulate_visual(trial: TrialType<Info>, simulation_options, load_callback: () => void) {\n const data = this.create_simulation_data(trial, simulation_options);\n\n const display_element = this.jsPsych.getDisplayElement();\n\n const respond = () => {\n if (data.rt !== null) {\n this.jsPsych.pluginAPI.clickTarget(\n display_element.querySelector(`div[data-choice=\"${data.response}\"] button`),\n data.rt\n );\n }\n };\n\n this.trial(display_element, trial, () => {\n load_callback();\n if (!trial.response_allowed_while_playing) {\n this.audio.addEventListener(\"ended\", respond);\n } else {\n respond();\n }\n });\n }\n}\n\nexport default AudioButtonResponsePlugin;\n"],"names":["ParameterType"],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -67,6 +67,12 @@ declare const info: {
67
67
  readonly pretty_name: "Response allowed while playing";
68
68
  readonly default: true;
69
69
  };
70
+ /** The delay of enabling button */
71
+ readonly enable_button_after: {
72
+ readonly type: ParameterType.INT;
73
+ readonly pretty_name: "Enable button after";
74
+ readonly default: 0;
75
+ };
70
76
  };
71
77
  };
72
78
  type Info = typeof info;
@@ -148,6 +154,12 @@ declare class AudioButtonResponsePlugin implements JsPsychPlugin<Info> {
148
154
  readonly pretty_name: "Response allowed while playing";
149
155
  readonly default: true;
150
156
  };
157
+ /** The delay of enabling button */
158
+ readonly enable_button_after: {
159
+ readonly type: ParameterType.INT;
160
+ readonly pretty_name: "Enable button after";
161
+ readonly default: 0;
162
+ };
151
163
  };
152
164
  };
153
165
  private audio;
package/dist/index.js CHANGED
@@ -68,6 +68,12 @@ const info = {
68
68
  pretty_name: "Response allowed while playing",
69
69
  default: true,
70
70
  },
71
+ /** The delay of enabling button */
72
+ enable_button_after: {
73
+ type: ParameterType.INT,
74
+ pretty_name: "Enable button after",
75
+ default: 0,
76
+ },
71
77
  },
72
78
  };
73
79
  /**
@@ -160,6 +166,7 @@ class AudioButtonResponsePlugin {
160
166
  }
161
167
  display_element.innerHTML = html;
162
168
  if (trial.response_allowed_while_playing) {
169
+ disable_buttons();
163
170
  enable_buttons();
164
171
  }
165
172
  else {
@@ -226,6 +233,9 @@ class AudioButtonResponsePlugin {
226
233
  this.jsPsych.finishTrial(trial_data);
227
234
  trial_complete();
228
235
  };
236
+ const enable_buttons_with_delay = (delay) => {
237
+ this.jsPsych.pluginAPI.setTimeout(enable_buttons_without_delay, delay);
238
+ };
229
239
  function button_response(e) {
230
240
  var choice = e.currentTarget.getAttribute("data-choice"); // don't use dataset for jsdom compatibility
231
241
  after_response(choice);
@@ -240,7 +250,7 @@ class AudioButtonResponsePlugin {
240
250
  btns[i].removeEventListener("click", button_response);
241
251
  }
242
252
  }
243
- function enable_buttons() {
253
+ function enable_buttons_without_delay() {
244
254
  var btns = document.querySelectorAll(".jspsych-audio-button-response-button");
245
255
  for (var i = 0; i < btns.length; i++) {
246
256
  var btn_el = btns[i].querySelector("button");
@@ -250,6 +260,14 @@ class AudioButtonResponsePlugin {
250
260
  btns[i].addEventListener("click", button_response);
251
261
  }
252
262
  }
263
+ function enable_buttons() {
264
+ if (trial.enable_button_after > 0) {
265
+ enable_buttons_with_delay(trial.enable_button_after);
266
+ }
267
+ else {
268
+ enable_buttons_without_delay();
269
+ }
270
+ }
253
271
  return new Promise((resolve) => {
254
272
  trial_complete = resolve;
255
273
  });
@@ -266,7 +284,8 @@ class AudioButtonResponsePlugin {
266
284
  create_simulation_data(trial, simulation_options) {
267
285
  const default_data = {
268
286
  stimulus: trial.stimulus,
269
- rt: this.jsPsych.randomization.sampleExGaussian(500, 50, 1 / 150, true),
287
+ rt: this.jsPsych.randomization.sampleExGaussian(500, 50, 1 / 150, true) +
288
+ trial.enable_button_after,
270
289
  response: this.jsPsych.randomization.randomInt(0, trial.choices.length - 1),
271
290
  };
272
291
  const data = this.jsPsych.pluginAPI.mergeSimulationData(default_data, simulation_options);
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../src/index.ts"],"sourcesContent":["import { JsPsych, JsPsychPlugin, ParameterType, TrialType } from \"jspsych\";\n\nconst info = <const>{\n name: \"audio-button-response\",\n parameters: {\n /** The audio to be played. */\n stimulus: {\n type: ParameterType.AUDIO,\n pretty_name: \"Stimulus\",\n default: undefined,\n },\n /** Array containing the label(s) for the button(s). */\n choices: {\n type: ParameterType.STRING,\n pretty_name: \"Choices\",\n default: undefined,\n array: true,\n },\n /** The HTML for creating button. Can create own style. Use the \"%choice%\" string to indicate where the label from the choices parameter should be inserted. */\n button_html: {\n type: ParameterType.HTML_STRING,\n pretty_name: \"Button HTML\",\n default: '<button class=\"jspsych-btn\">%choice%</button>',\n array: true,\n },\n /** Any content here will be displayed below the stimulus. */\n prompt: {\n type: ParameterType.HTML_STRING,\n pretty_name: \"Prompt\",\n default: null,\n },\n /** The maximum duration to wait for a response. */\n trial_duration: {\n type: ParameterType.INT,\n pretty_name: \"Trial duration\",\n default: null,\n },\n /** Vertical margin of button. */\n margin_vertical: {\n type: ParameterType.STRING,\n pretty_name: \"Margin vertical\",\n default: \"0px\",\n },\n /** Horizontal margin of button. */\n margin_horizontal: {\n type: ParameterType.STRING,\n pretty_name: \"Margin horizontal\",\n default: \"8px\",\n },\n /** If true, the trial will end when user makes a response. */\n response_ends_trial: {\n type: ParameterType.BOOL,\n pretty_name: \"Response ends trial\",\n default: true,\n },\n /** If true, then the trial will end as soon as the audio file finishes playing. */\n trial_ends_after_audio: {\n type: ParameterType.BOOL,\n pretty_name: \"Trial ends after audio\",\n default: false,\n },\n /**\n * If true, then responses are allowed while the audio is playing.\n * If false, then the audio must finish playing before a response is accepted.\n */\n response_allowed_while_playing: {\n type: ParameterType.BOOL,\n pretty_name: \"Response allowed while playing\",\n default: true,\n },\n },\n};\n\ntype Info = typeof info;\n\n/**\n * **audio-button-response**\n *\n * jsPsych plugin for playing an audio file and getting a button response\n *\n * @author Kristin Diep\n * @see {@link https://www.jspsych.org/plugins/jspsych-audio-button-response/ audio-button-response plugin documentation on jspsych.org}\n */\nclass AudioButtonResponsePlugin implements JsPsychPlugin<Info> {\n static info = info;\n private audio;\n\n constructor(private jsPsych: JsPsych) {}\n\n trial(display_element: HTMLElement, trial: TrialType<Info>, on_load: () => void) {\n // hold the .resolve() function from the Promise that ends the trial\n let trial_complete;\n\n // setup stimulus\n var context = this.jsPsych.pluginAPI.audioContext();\n\n // store response\n var response = {\n rt: null,\n button: null,\n };\n\n // record webaudio context start time\n var startTime;\n\n // load audio file\n this.jsPsych.pluginAPI\n .getAudioBuffer(trial.stimulus)\n .then((buffer) => {\n if (context !== null) {\n this.audio = context.createBufferSource();\n this.audio.buffer = buffer;\n this.audio.connect(context.destination);\n } else {\n this.audio = buffer;\n this.audio.currentTime = 0;\n }\n setupTrial();\n })\n .catch((err) => {\n console.error(\n `Failed to load audio file \"${trial.stimulus}\". Try checking the file path. We recommend using the preload plugin to load audio files.`\n );\n console.error(err);\n });\n\n const setupTrial = () => {\n // set up end event if trial needs it\n if (trial.trial_ends_after_audio) {\n this.audio.addEventListener(\"ended\", end_trial);\n }\n\n // enable buttons after audio ends if necessary\n if (!trial.response_allowed_while_playing && !trial.trial_ends_after_audio) {\n this.audio.addEventListener(\"ended\", enable_buttons);\n }\n\n //display buttons\n var buttons = [];\n if (Array.isArray(trial.button_html)) {\n if (trial.button_html.length == trial.choices.length) {\n buttons = trial.button_html;\n } else {\n console.error(\n \"Error in audio-button-response plugin. The length of the button_html array does not equal the length of the choices array\"\n );\n }\n } else {\n for (var i = 0; i < trial.choices.length; i++) {\n buttons.push(trial.button_html);\n }\n }\n\n var html = '<div id=\"jspsych-audio-button-response-btngroup\">';\n for (var i = 0; i < trial.choices.length; i++) {\n var str = buttons[i].replace(/%choice%/g, trial.choices[i]);\n html +=\n '<div class=\"jspsych-audio-button-response-button\" style=\"cursor: pointer; display: inline-block; margin:' +\n trial.margin_vertical +\n \" \" +\n trial.margin_horizontal +\n '\" id=\"jspsych-audio-button-response-button-' +\n i +\n '\" data-choice=\"' +\n i +\n '\">' +\n str +\n \"</div>\";\n }\n html += \"</div>\";\n\n //show prompt if there is one\n if (trial.prompt !== null) {\n html += trial.prompt;\n }\n\n display_element.innerHTML = html;\n\n if (trial.response_allowed_while_playing) {\n enable_buttons();\n } else {\n disable_buttons();\n }\n\n // start time\n startTime = performance.now();\n\n // start audio\n if (context !== null) {\n startTime = context.currentTime;\n this.audio.start(startTime);\n } else {\n this.audio.play();\n }\n\n // end trial if time limit is set\n if (trial.trial_duration !== null) {\n this.jsPsych.pluginAPI.setTimeout(() => {\n end_trial();\n }, trial.trial_duration);\n }\n\n on_load();\n };\n\n // function to handle responses by the subject\n function after_response(choice) {\n // measure rt\n var endTime = performance.now();\n var rt = Math.round(endTime - startTime);\n if (context !== null) {\n endTime = context.currentTime;\n rt = Math.round((endTime - startTime) * 1000);\n }\n response.button = parseInt(choice);\n response.rt = rt;\n\n // disable all the buttons after a response\n disable_buttons();\n\n if (trial.response_ends_trial) {\n end_trial();\n }\n }\n\n // function to end trial when it is time\n const end_trial = () => {\n // kill any remaining setTimeout handlers\n this.jsPsych.pluginAPI.clearAllTimeouts();\n\n // stop the audio file if it is playing\n // remove end event listeners if they exist\n if (context !== null) {\n this.audio.stop();\n } else {\n this.audio.pause();\n }\n\n this.audio.removeEventListener(\"ended\", end_trial);\n this.audio.removeEventListener(\"ended\", enable_buttons);\n\n // gather the data to store for the trial\n var trial_data = {\n rt: response.rt,\n stimulus: trial.stimulus,\n response: response.button,\n };\n\n // clear the display\n display_element.innerHTML = \"\";\n\n // move on to the next trial\n this.jsPsych.finishTrial(trial_data);\n\n trial_complete();\n };\n\n function button_response(e) {\n var choice = e.currentTarget.getAttribute(\"data-choice\"); // don't use dataset for jsdom compatibility\n after_response(choice);\n }\n\n function disable_buttons() {\n var btns = document.querySelectorAll(\".jspsych-audio-button-response-button\");\n for (var i = 0; i < btns.length; i++) {\n var btn_el = btns[i].querySelector(\"button\");\n if (btn_el) {\n btn_el.disabled = true;\n }\n btns[i].removeEventListener(\"click\", button_response);\n }\n }\n\n function enable_buttons() {\n var btns = document.querySelectorAll(\".jspsych-audio-button-response-button\");\n for (var i = 0; i < btns.length; i++) {\n var btn_el = btns[i].querySelector(\"button\");\n if (btn_el) {\n btn_el.disabled = false;\n }\n btns[i].addEventListener(\"click\", button_response);\n }\n }\n\n return new Promise((resolve) => {\n trial_complete = resolve;\n });\n }\n\n simulate(\n trial: TrialType<Info>,\n simulation_mode,\n simulation_options: any,\n load_callback: () => void\n ) {\n if (simulation_mode == \"data-only\") {\n load_callback();\n this.simulate_data_only(trial, simulation_options);\n }\n if (simulation_mode == \"visual\") {\n this.simulate_visual(trial, simulation_options, load_callback);\n }\n }\n\n private create_simulation_data(trial: TrialType<Info>, simulation_options) {\n const default_data = {\n stimulus: trial.stimulus,\n rt: this.jsPsych.randomization.sampleExGaussian(500, 50, 1 / 150, true),\n response: this.jsPsych.randomization.randomInt(0, trial.choices.length - 1),\n };\n\n const data = this.jsPsych.pluginAPI.mergeSimulationData(default_data, simulation_options);\n\n this.jsPsych.pluginAPI.ensureSimulationDataConsistency(trial, data);\n\n return data;\n }\n\n private simulate_data_only(trial: TrialType<Info>, simulation_options) {\n const data = this.create_simulation_data(trial, simulation_options);\n\n this.jsPsych.finishTrial(data);\n }\n\n private simulate_visual(trial: TrialType<Info>, simulation_options, load_callback: () => void) {\n const data = this.create_simulation_data(trial, simulation_options);\n\n const display_element = this.jsPsych.getDisplayElement();\n\n const respond = () => {\n if (data.rt !== null) {\n this.jsPsych.pluginAPI.clickTarget(\n display_element.querySelector(`div[data-choice=\"${data.response}\"] button`),\n data.rt\n );\n }\n };\n\n this.trial(display_element, trial, () => {\n load_callback();\n if (!trial.response_allowed_while_playing) {\n this.audio.addEventListener(\"ended\", respond);\n } else {\n respond();\n }\n });\n }\n}\n\nexport default AudioButtonResponsePlugin;\n"],"names":[],"mappings":";;AAEA,MAAM,IAAI,GAAU;AAClB,IAAA,IAAI,EAAE,uBAAuB;AAC7B,IAAA,UAAU,EAAE;;AAEV,QAAA,QAAQ,EAAE;YACR,IAAI,EAAE,aAAa,CAAC,KAAK;AACzB,YAAA,WAAW,EAAE,UAAU;AACvB,YAAA,OAAO,EAAE,SAAS;AACnB,SAAA;;AAED,QAAA,OAAO,EAAE;YACP,IAAI,EAAE,aAAa,CAAC,MAAM;AAC1B,YAAA,WAAW,EAAE,SAAS;AACtB,YAAA,OAAO,EAAE,SAAS;AAClB,YAAA,KAAK,EAAE,IAAI;AACZ,SAAA;;AAED,QAAA,WAAW,EAAE;YACX,IAAI,EAAE,aAAa,CAAC,WAAW;AAC/B,YAAA,WAAW,EAAE,aAAa;AAC1B,YAAA,OAAO,EAAE,+CAA+C;AACxD,YAAA,KAAK,EAAE,IAAI;AACZ,SAAA;;AAED,QAAA,MAAM,EAAE;YACN,IAAI,EAAE,aAAa,CAAC,WAAW;AAC/B,YAAA,WAAW,EAAE,QAAQ;AACrB,YAAA,OAAO,EAAE,IAAI;AACd,SAAA;;AAED,QAAA,cAAc,EAAE;YACd,IAAI,EAAE,aAAa,CAAC,GAAG;AACvB,YAAA,WAAW,EAAE,gBAAgB;AAC7B,YAAA,OAAO,EAAE,IAAI;AACd,SAAA;;AAED,QAAA,eAAe,EAAE;YACf,IAAI,EAAE,aAAa,CAAC,MAAM;AAC1B,YAAA,WAAW,EAAE,iBAAiB;AAC9B,YAAA,OAAO,EAAE,KAAK;AACf,SAAA;;AAED,QAAA,iBAAiB,EAAE;YACjB,IAAI,EAAE,aAAa,CAAC,MAAM;AAC1B,YAAA,WAAW,EAAE,mBAAmB;AAChC,YAAA,OAAO,EAAE,KAAK;AACf,SAAA;;AAED,QAAA,mBAAmB,EAAE;YACnB,IAAI,EAAE,aAAa,CAAC,IAAI;AACxB,YAAA,WAAW,EAAE,qBAAqB;AAClC,YAAA,OAAO,EAAE,IAAI;AACd,SAAA;;AAED,QAAA,sBAAsB,EAAE;YACtB,IAAI,EAAE,aAAa,CAAC,IAAI;AACxB,YAAA,WAAW,EAAE,wBAAwB;AACrC,YAAA,OAAO,EAAE,KAAK;AACf,SAAA;AACD;;;AAGG;AACH,QAAA,8BAA8B,EAAE;YAC9B,IAAI,EAAE,aAAa,CAAC,IAAI;AACxB,YAAA,WAAW,EAAE,gCAAgC;AAC7C,YAAA,OAAO,EAAE,IAAI;AACd,SAAA;AACF,KAAA;CACF,CAAC;AAIF;;;;;;;AAOG;AACH,MAAM,yBAAyB,CAAA;AAI7B,IAAA,WAAA,CAAoB,OAAgB,EAAA;QAAhB,IAAO,CAAA,OAAA,GAAP,OAAO,CAAS;KAAI;AAExC,IAAA,KAAK,CAAC,eAA4B,EAAE,KAAsB,EAAE,OAAmB,EAAA;;AAE7E,QAAA,IAAI,cAAc,CAAC;;QAGnB,IAAI,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,YAAY,EAAE,CAAC;;AAGpD,QAAA,IAAI,QAAQ,GAAG;AACb,YAAA,EAAE,EAAE,IAAI;AACR,YAAA,MAAM,EAAE,IAAI;SACb,CAAC;;AAGF,QAAA,IAAI,SAAS,CAAC;;QAGd,IAAI,CAAC,OAAO,CAAC,SAAS;AACnB,aAAA,cAAc,CAAC,KAAK,CAAC,QAAQ,CAAC;AAC9B,aAAA,IAAI,CAAC,CAAC,MAAM,KAAI;YACf,IAAI,OAAO,KAAK,IAAI,EAAE;AACpB,gBAAA,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC,kBAAkB,EAAE,CAAC;AAC1C,gBAAA,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC;gBAC3B,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;AACzC,aAAA;AAAM,iBAAA;AACL,gBAAA,IAAI,CAAC,KAAK,GAAG,MAAM,CAAC;AACpB,gBAAA,IAAI,CAAC,KAAK,CAAC,WAAW,GAAG,CAAC,CAAC;AAC5B,aAAA;AACD,YAAA,UAAU,EAAE,CAAC;AACf,SAAC,CAAC;AACD,aAAA,KAAK,CAAC,CAAC,GAAG,KAAI;YACb,OAAO,CAAC,KAAK,CACX,CAAA,2BAAA,EAA8B,KAAK,CAAC,QAAQ,CAA2F,yFAAA,CAAA,CACxI,CAAC;AACF,YAAA,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;AACrB,SAAC,CAAC,CAAC;QAEL,MAAM,UAAU,GAAG,MAAK;;YAEtB,IAAI,KAAK,CAAC,sBAAsB,EAAE;gBAChC,IAAI,CAAC,KAAK,CAAC,gBAAgB,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;AACjD,aAAA;;YAGD,IAAI,CAAC,KAAK,CAAC,8BAA8B,IAAI,CAAC,KAAK,CAAC,sBAAsB,EAAE;gBAC1E,IAAI,CAAC,KAAK,CAAC,gBAAgB,CAAC,OAAO,EAAE,cAAc,CAAC,CAAC;AACtD,aAAA;;YAGD,IAAI,OAAO,GAAG,EAAE,CAAC;YACjB,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,WAAW,CAAC,EAAE;gBACpC,IAAI,KAAK,CAAC,WAAW,CAAC,MAAM,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,EAAE;AACpD,oBAAA,OAAO,GAAG,KAAK,CAAC,WAAW,CAAC;AAC7B,iBAAA;AAAM,qBAAA;AACL,oBAAA,OAAO,CAAC,KAAK,CACX,2HAA2H,CAC5H,CAAC;AACH,iBAAA;AACF,aAAA;AAAM,iBAAA;AACL,gBAAA,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;AAC7C,oBAAA,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;AACjC,iBAAA;AACF,aAAA;YAED,IAAI,IAAI,GAAG,mDAAmD,CAAC;AAC/D,YAAA,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;AAC7C,gBAAA,IAAI,GAAG,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,WAAW,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;gBAC5D,IAAI;oBACF,0GAA0G;AAC1G,wBAAA,KAAK,CAAC,eAAe;wBACrB,GAAG;AACH,wBAAA,KAAK,CAAC,iBAAiB;wBACvB,6CAA6C;wBAC7C,CAAC;wBACD,iBAAiB;wBACjB,CAAC;wBACD,IAAI;wBACJ,GAAG;AACH,wBAAA,QAAQ,CAAC;AACZ,aAAA;YACD,IAAI,IAAI,QAAQ,CAAC;;AAGjB,YAAA,IAAI,KAAK,CAAC,MAAM,KAAK,IAAI,EAAE;AACzB,gBAAA,IAAI,IAAI,KAAK,CAAC,MAAM,CAAC;AACtB,aAAA;AAED,YAAA,eAAe,CAAC,SAAS,GAAG,IAAI,CAAC;YAEjC,IAAI,KAAK,CAAC,8BAA8B,EAAE;AACxC,gBAAA,cAAc,EAAE,CAAC;AAClB,aAAA;AAAM,iBAAA;AACL,gBAAA,eAAe,EAAE,CAAC;AACnB,aAAA;;AAGD,YAAA,SAAS,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;;YAG9B,IAAI,OAAO,KAAK,IAAI,EAAE;AACpB,gBAAA,SAAS,GAAG,OAAO,CAAC,WAAW,CAAC;AAChC,gBAAA,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;AAC7B,aAAA;AAAM,iBAAA;AACL,gBAAA,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;AACnB,aAAA;;AAGD,YAAA,IAAI,KAAK,CAAC,cAAc,KAAK,IAAI,EAAE;gBACjC,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,UAAU,CAAC,MAAK;AACrC,oBAAA,SAAS,EAAE,CAAC;AACd,iBAAC,EAAE,KAAK,CAAC,cAAc,CAAC,CAAC;AAC1B,aAAA;AAED,YAAA,OAAO,EAAE,CAAC;AACZ,SAAC,CAAC;;QAGF,SAAS,cAAc,CAAC,MAAM,EAAA;;AAE5B,YAAA,IAAI,OAAO,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;YAChC,IAAI,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,GAAG,SAAS,CAAC,CAAC;YACzC,IAAI,OAAO,KAAK,IAAI,EAAE;AACpB,gBAAA,OAAO,GAAG,OAAO,CAAC,WAAW,CAAC;AAC9B,gBAAA,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,OAAO,GAAG,SAAS,IAAI,IAAI,CAAC,CAAC;AAC/C,aAAA;AACD,YAAA,QAAQ,CAAC,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC;AACnC,YAAA,QAAQ,CAAC,EAAE,GAAG,EAAE,CAAC;;AAGjB,YAAA,eAAe,EAAE,CAAC;YAElB,IAAI,KAAK,CAAC,mBAAmB,EAAE;AAC7B,gBAAA,SAAS,EAAE,CAAC;AACb,aAAA;SACF;;QAGD,MAAM,SAAS,GAAG,MAAK;;AAErB,YAAA,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,gBAAgB,EAAE,CAAC;;;YAI1C,IAAI,OAAO,KAAK,IAAI,EAAE;AACpB,gBAAA,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;AACnB,aAAA;AAAM,iBAAA;AACL,gBAAA,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;AACpB,aAAA;YAED,IAAI,CAAC,KAAK,CAAC,mBAAmB,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;YACnD,IAAI,CAAC,KAAK,CAAC,mBAAmB,CAAC,OAAO,EAAE,cAAc,CAAC,CAAC;;AAGxD,YAAA,IAAI,UAAU,GAAG;gBACf,EAAE,EAAE,QAAQ,CAAC,EAAE;gBACf,QAAQ,EAAE,KAAK,CAAC,QAAQ;gBACxB,QAAQ,EAAE,QAAQ,CAAC,MAAM;aAC1B,CAAC;;AAGF,YAAA,eAAe,CAAC,SAAS,GAAG,EAAE,CAAC;;AAG/B,YAAA,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC;AAErC,YAAA,cAAc,EAAE,CAAC;AACnB,SAAC,CAAC;QAEF,SAAS,eAAe,CAAC,CAAC,EAAA;AACxB,YAAA,IAAI,MAAM,GAAG,CAAC,CAAC,aAAa,CAAC,YAAY,CAAC,aAAa,CAAC,CAAC;YACzD,cAAc,CAAC,MAAM,CAAC,CAAC;SACxB;AAED,QAAA,SAAS,eAAe,GAAA;YACtB,IAAI,IAAI,GAAG,QAAQ,CAAC,gBAAgB,CAAC,uCAAuC,CAAC,CAAC;AAC9E,YAAA,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;gBACpC,IAAI,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;AAC7C,gBAAA,IAAI,MAAM,EAAE;AACV,oBAAA,MAAM,CAAC,QAAQ,GAAG,IAAI,CAAC;AACxB,iBAAA;gBACD,IAAI,CAAC,CAAC,CAAC,CAAC,mBAAmB,CAAC,OAAO,EAAE,eAAe,CAAC,CAAC;AACvD,aAAA;SACF;AAED,QAAA,SAAS,cAAc,GAAA;YACrB,IAAI,IAAI,GAAG,QAAQ,CAAC,gBAAgB,CAAC,uCAAuC,CAAC,CAAC;AAC9E,YAAA,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;gBACpC,IAAI,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;AAC7C,gBAAA,IAAI,MAAM,EAAE;AACV,oBAAA,MAAM,CAAC,QAAQ,GAAG,KAAK,CAAC;AACzB,iBAAA;gBACD,IAAI,CAAC,CAAC,CAAC,CAAC,gBAAgB,CAAC,OAAO,EAAE,eAAe,CAAC,CAAC;AACpD,aAAA;SACF;AAED,QAAA,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,KAAI;YAC7B,cAAc,GAAG,OAAO,CAAC;AAC3B,SAAC,CAAC,CAAC;KACJ;AAED,IAAA,QAAQ,CACN,KAAsB,EACtB,eAAe,EACf,kBAAuB,EACvB,aAAyB,EAAA;QAEzB,IAAI,eAAe,IAAI,WAAW,EAAE;AAClC,YAAA,aAAa,EAAE,CAAC;AAChB,YAAA,IAAI,CAAC,kBAAkB,CAAC,KAAK,EAAE,kBAAkB,CAAC,CAAC;AACpD,SAAA;QACD,IAAI,eAAe,IAAI,QAAQ,EAAE;YAC/B,IAAI,CAAC,eAAe,CAAC,KAAK,EAAE,kBAAkB,EAAE,aAAa,CAAC,CAAC;AAChE,SAAA;KACF;IAEO,sBAAsB,CAAC,KAAsB,EAAE,kBAAkB,EAAA;AACvE,QAAA,MAAM,YAAY,GAAG;YACnB,QAAQ,EAAE,KAAK,CAAC,QAAQ;AACxB,YAAA,EAAE,EAAE,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,gBAAgB,CAAC,GAAG,EAAE,EAAE,EAAE,CAAC,GAAG,GAAG,EAAE,IAAI,CAAC;AACvE,YAAA,QAAQ,EAAE,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,EAAE,KAAK,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC;SAC5E,CAAC;AAEF,QAAA,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,mBAAmB,CAAC,YAAY,EAAE,kBAAkB,CAAC,CAAC;QAE1F,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,+BAA+B,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;AAEpE,QAAA,OAAO,IAAI,CAAC;KACb;IAEO,kBAAkB,CAAC,KAAsB,EAAE,kBAAkB,EAAA;QACnE,MAAM,IAAI,GAAG,IAAI,CAAC,sBAAsB,CAAC,KAAK,EAAE,kBAAkB,CAAC,CAAC;AAEpE,QAAA,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;KAChC;AAEO,IAAA,eAAe,CAAC,KAAsB,EAAE,kBAAkB,EAAE,aAAyB,EAAA;QAC3F,MAAM,IAAI,GAAG,IAAI,CAAC,sBAAsB,CAAC,KAAK,EAAE,kBAAkB,CAAC,CAAC;QAEpE,MAAM,eAAe,GAAG,IAAI,CAAC,OAAO,CAAC,iBAAiB,EAAE,CAAC;QAEzD,MAAM,OAAO,GAAG,MAAK;AACnB,YAAA,IAAI,IAAI,CAAC,EAAE,KAAK,IAAI,EAAE;gBACpB,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,WAAW,CAChC,eAAe,CAAC,aAAa,CAAC,oBAAoB,IAAI,CAAC,QAAQ,CAAW,SAAA,CAAA,CAAC,EAC3E,IAAI,CAAC,EAAE,CACR,CAAC;AACH,aAAA;AACH,SAAC,CAAC;QAEF,IAAI,CAAC,KAAK,CAAC,eAAe,EAAE,KAAK,EAAE,MAAK;AACtC,YAAA,aAAa,EAAE,CAAC;AAChB,YAAA,IAAI,CAAC,KAAK,CAAC,8BAA8B,EAAE;gBACzC,IAAI,CAAC,KAAK,CAAC,gBAAgB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;AAC/C,aAAA;AAAM,iBAAA;AACL,gBAAA,OAAO,EAAE,CAAC;AACX,aAAA;AACH,SAAC,CAAC,CAAC;KACJ;;AAtQM,yBAAI,CAAA,IAAA,GAAG,IAAI;;;;"}
1
+ {"version":3,"file":"index.js","sources":["../src/index.ts"],"sourcesContent":["import { JsPsych, JsPsychPlugin, ParameterType, TrialType } from \"jspsych\";\n\nconst info = <const>{\n name: \"audio-button-response\",\n parameters: {\n /** The audio to be played. */\n stimulus: {\n type: ParameterType.AUDIO,\n pretty_name: \"Stimulus\",\n default: undefined,\n },\n /** Array containing the label(s) for the button(s). */\n choices: {\n type: ParameterType.STRING,\n pretty_name: \"Choices\",\n default: undefined,\n array: true,\n },\n /** The HTML for creating button. Can create own style. Use the \"%choice%\" string to indicate where the label from the choices parameter should be inserted. */\n button_html: {\n type: ParameterType.HTML_STRING,\n pretty_name: \"Button HTML\",\n default: '<button class=\"jspsych-btn\">%choice%</button>',\n array: true,\n },\n /** Any content here will be displayed below the stimulus. */\n prompt: {\n type: ParameterType.HTML_STRING,\n pretty_name: \"Prompt\",\n default: null,\n },\n /** The maximum duration to wait for a response. */\n trial_duration: {\n type: ParameterType.INT,\n pretty_name: \"Trial duration\",\n default: null,\n },\n /** Vertical margin of button. */\n margin_vertical: {\n type: ParameterType.STRING,\n pretty_name: \"Margin vertical\",\n default: \"0px\",\n },\n /** Horizontal margin of button. */\n margin_horizontal: {\n type: ParameterType.STRING,\n pretty_name: \"Margin horizontal\",\n default: \"8px\",\n },\n /** If true, the trial will end when user makes a response. */\n response_ends_trial: {\n type: ParameterType.BOOL,\n pretty_name: \"Response ends trial\",\n default: true,\n },\n /** If true, then the trial will end as soon as the audio file finishes playing. */\n trial_ends_after_audio: {\n type: ParameterType.BOOL,\n pretty_name: \"Trial ends after audio\",\n default: false,\n },\n /**\n * If true, then responses are allowed while the audio is playing.\n * If false, then the audio must finish playing before a response is accepted.\n */\n response_allowed_while_playing: {\n type: ParameterType.BOOL,\n pretty_name: \"Response allowed while playing\",\n default: true,\n },\n /** The delay of enabling button */\n enable_button_after: {\n type: ParameterType.INT,\n pretty_name: \"Enable button after\",\n default: 0,\n },\n },\n};\n\ntype Info = typeof info;\n\n/**\n * **audio-button-response**\n *\n * jsPsych plugin for playing an audio file and getting a button response\n *\n * @author Kristin Diep\n * @see {@link https://www.jspsych.org/plugins/jspsych-audio-button-response/ audio-button-response plugin documentation on jspsych.org}\n */\nclass AudioButtonResponsePlugin implements JsPsychPlugin<Info> {\n static info = info;\n private audio;\n\n constructor(private jsPsych: JsPsych) {}\n\n trial(display_element: HTMLElement, trial: TrialType<Info>, on_load: () => void) {\n // hold the .resolve() function from the Promise that ends the trial\n let trial_complete;\n\n // setup stimulus\n var context = this.jsPsych.pluginAPI.audioContext();\n\n // store response\n var response = {\n rt: null,\n button: null,\n };\n\n // record webaudio context start time\n var startTime;\n\n // load audio file\n this.jsPsych.pluginAPI\n .getAudioBuffer(trial.stimulus)\n .then((buffer) => {\n if (context !== null) {\n this.audio = context.createBufferSource();\n this.audio.buffer = buffer;\n this.audio.connect(context.destination);\n } else {\n this.audio = buffer;\n this.audio.currentTime = 0;\n }\n setupTrial();\n })\n .catch((err) => {\n console.error(\n `Failed to load audio file \"${trial.stimulus}\". Try checking the file path. We recommend using the preload plugin to load audio files.`\n );\n console.error(err);\n });\n\n const setupTrial = () => {\n // set up end event if trial needs it\n if (trial.trial_ends_after_audio) {\n this.audio.addEventListener(\"ended\", end_trial);\n }\n\n // enable buttons after audio ends if necessary\n if (!trial.response_allowed_while_playing && !trial.trial_ends_after_audio) {\n this.audio.addEventListener(\"ended\", enable_buttons);\n }\n\n //display buttons\n var buttons = [];\n if (Array.isArray(trial.button_html)) {\n if (trial.button_html.length == trial.choices.length) {\n buttons = trial.button_html;\n } else {\n console.error(\n \"Error in audio-button-response plugin. The length of the button_html array does not equal the length of the choices array\"\n );\n }\n } else {\n for (var i = 0; i < trial.choices.length; i++) {\n buttons.push(trial.button_html);\n }\n }\n\n var html = '<div id=\"jspsych-audio-button-response-btngroup\">';\n for (var i = 0; i < trial.choices.length; i++) {\n var str = buttons[i].replace(/%choice%/g, trial.choices[i]);\n html +=\n '<div class=\"jspsych-audio-button-response-button\" style=\"cursor: pointer; display: inline-block; margin:' +\n trial.margin_vertical +\n \" \" +\n trial.margin_horizontal +\n '\" id=\"jspsych-audio-button-response-button-' +\n i +\n '\" data-choice=\"' +\n i +\n '\">' +\n str +\n \"</div>\";\n }\n html += \"</div>\";\n\n //show prompt if there is one\n if (trial.prompt !== null) {\n html += trial.prompt;\n }\n\n display_element.innerHTML = html;\n\n if (trial.response_allowed_while_playing) {\n disable_buttons();\n enable_buttons();\n } else {\n disable_buttons();\n }\n\n // start time\n startTime = performance.now();\n\n // start audio\n if (context !== null) {\n startTime = context.currentTime;\n this.audio.start(startTime);\n } else {\n this.audio.play();\n }\n\n // end trial if time limit is set\n if (trial.trial_duration !== null) {\n this.jsPsych.pluginAPI.setTimeout(() => {\n end_trial();\n }, trial.trial_duration);\n }\n\n on_load();\n };\n\n // function to handle responses by the subject\n function after_response(choice) {\n // measure rt\n var endTime = performance.now();\n var rt = Math.round(endTime - startTime);\n if (context !== null) {\n endTime = context.currentTime;\n rt = Math.round((endTime - startTime) * 1000);\n }\n response.button = parseInt(choice);\n response.rt = rt;\n\n // disable all the buttons after a response\n disable_buttons();\n\n if (trial.response_ends_trial) {\n end_trial();\n }\n }\n\n // function to end trial when it is time\n const end_trial = () => {\n // kill any remaining setTimeout handlers\n this.jsPsych.pluginAPI.clearAllTimeouts();\n\n // stop the audio file if it is playing\n // remove end event listeners if they exist\n if (context !== null) {\n this.audio.stop();\n } else {\n this.audio.pause();\n }\n\n this.audio.removeEventListener(\"ended\", end_trial);\n this.audio.removeEventListener(\"ended\", enable_buttons);\n\n // gather the data to store for the trial\n var trial_data = {\n rt: response.rt,\n stimulus: trial.stimulus,\n response: response.button,\n };\n\n // clear the display\n display_element.innerHTML = \"\";\n\n // move on to the next trial\n this.jsPsych.finishTrial(trial_data);\n\n trial_complete();\n };\n\n const enable_buttons_with_delay = (delay: number) => {\n this.jsPsych.pluginAPI.setTimeout(enable_buttons_without_delay, delay);\n };\n\n function button_response(e) {\n var choice = e.currentTarget.getAttribute(\"data-choice\"); // don't use dataset for jsdom compatibility\n after_response(choice);\n }\n\n function disable_buttons() {\n var btns = document.querySelectorAll(\".jspsych-audio-button-response-button\");\n for (var i = 0; i < btns.length; i++) {\n var btn_el = btns[i].querySelector(\"button\");\n if (btn_el) {\n btn_el.disabled = true;\n }\n btns[i].removeEventListener(\"click\", button_response);\n }\n }\n\n function enable_buttons_without_delay() {\n var btns = document.querySelectorAll(\".jspsych-audio-button-response-button\");\n for (var i = 0; i < btns.length; i++) {\n var btn_el = btns[i].querySelector(\"button\");\n if (btn_el) {\n btn_el.disabled = false;\n }\n btns[i].addEventListener(\"click\", button_response);\n }\n }\n\n function enable_buttons() {\n if (trial.enable_button_after > 0) {\n enable_buttons_with_delay(trial.enable_button_after);\n } else {\n enable_buttons_without_delay();\n }\n }\n\n return new Promise((resolve) => {\n trial_complete = resolve;\n });\n }\n\n simulate(\n trial: TrialType<Info>,\n simulation_mode,\n simulation_options: any,\n load_callback: () => void\n ) {\n if (simulation_mode == \"data-only\") {\n load_callback();\n this.simulate_data_only(trial, simulation_options);\n }\n if (simulation_mode == \"visual\") {\n this.simulate_visual(trial, simulation_options, load_callback);\n }\n }\n\n private create_simulation_data(trial: TrialType<Info>, simulation_options) {\n const default_data = {\n stimulus: trial.stimulus,\n rt:\n this.jsPsych.randomization.sampleExGaussian(500, 50, 1 / 150, true) +\n trial.enable_button_after,\n response: this.jsPsych.randomization.randomInt(0, trial.choices.length - 1),\n };\n\n const data = this.jsPsych.pluginAPI.mergeSimulationData(default_data, simulation_options);\n\n this.jsPsych.pluginAPI.ensureSimulationDataConsistency(trial, data);\n\n return data;\n }\n\n private simulate_data_only(trial: TrialType<Info>, simulation_options) {\n const data = this.create_simulation_data(trial, simulation_options);\n\n this.jsPsych.finishTrial(data);\n }\n\n private simulate_visual(trial: TrialType<Info>, simulation_options, load_callback: () => void) {\n const data = this.create_simulation_data(trial, simulation_options);\n\n const display_element = this.jsPsych.getDisplayElement();\n\n const respond = () => {\n if (data.rt !== null) {\n this.jsPsych.pluginAPI.clickTarget(\n display_element.querySelector(`div[data-choice=\"${data.response}\"] button`),\n data.rt\n );\n }\n };\n\n this.trial(display_element, trial, () => {\n load_callback();\n if (!trial.response_allowed_while_playing) {\n this.audio.addEventListener(\"ended\", respond);\n } else {\n respond();\n }\n });\n }\n}\n\nexport default AudioButtonResponsePlugin;\n"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jspsych/plugin-audio-button-response",
3
- "version": "1.1.3",
3
+ "version": "1.2.0",
4
4
  "description": "jsPsych plugin for playing an audio file and getting a button response",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",
package/src/index.spec.ts CHANGED
@@ -32,6 +32,37 @@ describe.skip("audio-button-response", () => {
32
32
 
33
33
  await finished;
34
34
  });
35
+
36
+ test("enable buttons during audio playback", async () => {
37
+ const timeline = [
38
+ {
39
+ type: audioButtonResponse,
40
+ stimulus: "mymp3.mp3",
41
+ prompt: "foo",
42
+ choices: ["choice1"],
43
+ response_allowed_while_playing: true,
44
+ enable_button_after: 500,
45
+ },
46
+ ];
47
+
48
+ const jsPsych = initJsPsych({
49
+ use_webaudio: false,
50
+ });
51
+
52
+ const { getHTML, finished } = await startTimeline(timeline, jsPsych);
53
+
54
+ const btns = document.querySelectorAll(".jspsych-html-button-response-button button");
55
+
56
+ for (let i = 0; i < btns.length; i++) {
57
+ expect(btns[i].getAttribute("disabled")).toBe(true);
58
+ }
59
+
60
+ jest.advanceTimersByTime(500);
61
+
62
+ for (let i = 0; i < btns.length; i++) {
63
+ expect(btns[i].hasAttribute("disabled")).toBe(false);
64
+ }
65
+ });
35
66
  });
36
67
 
37
68
  describe("audio-button-response simulation", () => {
package/src/index.ts CHANGED
@@ -68,6 +68,12 @@ const info = <const>{
68
68
  pretty_name: "Response allowed while playing",
69
69
  default: true,
70
70
  },
71
+ /** The delay of enabling button */
72
+ enable_button_after: {
73
+ type: ParameterType.INT,
74
+ pretty_name: "Enable button after",
75
+ default: 0,
76
+ },
71
77
  },
72
78
  };
73
79
 
@@ -177,6 +183,7 @@ class AudioButtonResponsePlugin implements JsPsychPlugin<Info> {
177
183
  display_element.innerHTML = html;
178
184
 
179
185
  if (trial.response_allowed_while_playing) {
186
+ disable_buttons();
180
187
  enable_buttons();
181
188
  } else {
182
189
  disable_buttons();
@@ -255,6 +262,10 @@ class AudioButtonResponsePlugin implements JsPsychPlugin<Info> {
255
262
  trial_complete();
256
263
  };
257
264
 
265
+ const enable_buttons_with_delay = (delay: number) => {
266
+ this.jsPsych.pluginAPI.setTimeout(enable_buttons_without_delay, delay);
267
+ };
268
+
258
269
  function button_response(e) {
259
270
  var choice = e.currentTarget.getAttribute("data-choice"); // don't use dataset for jsdom compatibility
260
271
  after_response(choice);
@@ -271,7 +282,7 @@ class AudioButtonResponsePlugin implements JsPsychPlugin<Info> {
271
282
  }
272
283
  }
273
284
 
274
- function enable_buttons() {
285
+ function enable_buttons_without_delay() {
275
286
  var btns = document.querySelectorAll(".jspsych-audio-button-response-button");
276
287
  for (var i = 0; i < btns.length; i++) {
277
288
  var btn_el = btns[i].querySelector("button");
@@ -282,6 +293,14 @@ class AudioButtonResponsePlugin implements JsPsychPlugin<Info> {
282
293
  }
283
294
  }
284
295
 
296
+ function enable_buttons() {
297
+ if (trial.enable_button_after > 0) {
298
+ enable_buttons_with_delay(trial.enable_button_after);
299
+ } else {
300
+ enable_buttons_without_delay();
301
+ }
302
+ }
303
+
285
304
  return new Promise((resolve) => {
286
305
  trial_complete = resolve;
287
306
  });
@@ -305,7 +324,9 @@ class AudioButtonResponsePlugin implements JsPsychPlugin<Info> {
305
324
  private create_simulation_data(trial: TrialType<Info>, simulation_options) {
306
325
  const default_data = {
307
326
  stimulus: trial.stimulus,
308
- rt: this.jsPsych.randomization.sampleExGaussian(500, 50, 1 / 150, true),
327
+ rt:
328
+ this.jsPsych.randomization.sampleExGaussian(500, 50, 1 / 150, true) +
329
+ trial.enable_button_after,
309
330
  response: this.jsPsych.randomization.randomInt(0, trial.choices.length - 1),
310
331
  };
311
332