@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.
- package/dist/index.browser.js +22 -3
- package/dist/index.browser.js.map +1 -1
- package/dist/index.browser.min.js +2 -2
- package/dist/index.browser.min.js.map +1 -1
- package/dist/index.cjs +21 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +12 -0
- package/dist/index.js +21 -2
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/index.spec.ts +31 -0
- package/src/index.ts +23 -2
package/dist/index.browser.js
CHANGED
|
@@ -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
|
|
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.
|
|
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":"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"}
|
|
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
|
|
2
|
-
//# sourceMappingURL=https://unpkg.com/@jspsych/plugin-audio-button-response@1.
|
|
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
|
|
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);
|
package/dist/index.cjs.map
CHANGED
|
@@ -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
|
|
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":"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"}
|
|
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
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
|
|
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:
|
|
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
|
|