@jspsych/plugin-audio-button-response 1.2.0 → 2.0.1

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.
@@ -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 /** 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
+ {"version":3,"file":"index.browser.js","sources":["../../../node_modules/auto-bind/index.js","../src/index.ts"],"sourcesContent":["'use strict';\n\n// Gets all non-builtin properties up the prototype chain\nconst getAllProperties = object => {\n\tconst properties = new Set();\n\n\tdo {\n\t\tfor (const key of Reflect.ownKeys(object)) {\n\t\t\tproperties.add([object, key]);\n\t\t}\n\t} while ((object = Reflect.getPrototypeOf(object)) && object !== Object.prototype);\n\n\treturn properties;\n};\n\nmodule.exports = (self, {include, exclude} = {}) => {\n\tconst filter = key => {\n\t\tconst match = pattern => typeof pattern === 'string' ? key === pattern : pattern.test(key);\n\n\t\tif (include) {\n\t\t\treturn include.some(match);\n\t\t}\n\n\t\tif (exclude) {\n\t\t\treturn !exclude.some(match);\n\t\t}\n\n\t\treturn true;\n\t};\n\n\tfor (const [object, key] of getAllProperties(self.constructor.prototype)) {\n\t\tif (key === 'constructor' || !filter(key)) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst descriptor = Reflect.getOwnPropertyDescriptor(object, key);\n\t\tif (descriptor && typeof descriptor.value === 'function') {\n\t\t\tself[key] = self[key].bind(self);\n\t\t}\n\t}\n\n\treturn self;\n};\n","import autoBind from \"auto-bind\";\nimport { JsPsych, JsPsychPlugin, ParameterType, TrialType } from \"jspsych\";\n\nimport { AudioPlayerInterface } from \"../../jspsych/src/modules/plugin-api/AudioPlayer\";\nimport { version } from \"../package.json\";\n\nconst info = <const>{\n name: \"audio-button-response\",\n version: version,\n parameters: {\n /** Path to audio file to be played. */\n stimulus: {\n type: ParameterType.AUDIO,\n default: undefined,\n },\n /** Labels for the buttons. Each different string in the array will generate a different button. */\n choices: {\n type: ParameterType.STRING,\n default: undefined,\n array: true,\n },\n /**\n * A function that generates the HTML for each button in the `choices` array. The function gets the string\n * and index of the item in the `choices` array and should return valid HTML. If you want to use different\n * markup for each button, you can do that by using a conditional on either parameter. The default parameter\n * returns a button element with the text label of the choice.\n */\n button_html: {\n type: ParameterType.FUNCTION,\n default: function (choice: string, choice_index: number) {\n return `<button class=\"jspsych-btn\">${choice}</button>`;\n },\n },\n /** This string can contain HTML markup. Any content here will be displayed below the stimulus. The intention\n * is that it can be used to provide a reminder about the action the participant is supposed to take\n * (e.g., which key to press). */\n prompt: {\n type: ParameterType.HTML_STRING,\n default: null,\n },\n /** How long to wait for the participant to make a response before ending the trial in milliseconds. If the\n * participant fails to make a response before this timer is reached, the participant's response will be\n * recorded as null for the trial and the trial will end. If the value of this parameter is null, the trial\n * will wait for a response indefinitely */\n trial_duration: {\n type: ParameterType.INT,\n default: null,\n },\n /** Setting to `'grid'` will make the container element have the CSS property `display: grid` and enable the\n * use of `grid_rows` and `grid_columns`. Setting to `'flex'` will make the container element have the CSS\n * property `display: flex`. You can customize how the buttons are laid out by adding inline CSS in the `button_html` parameter.\n */\n button_layout: {\n type: ParameterType.STRING,\n default: \"grid\",\n },\n /** The number of rows in the button grid. Only applicable when `button_layout` is set to `'grid'`. If null, the\n * number of rows will be determined automatically based on the number of buttons and the number of columns.\n */\n grid_rows: {\n type: ParameterType.INT,\n default: 1,\n },\n /** The number of columns in the button grid. Only applicable when `button_layout` is set to `'grid'`.\n * If null, the number of columns will be determined automatically based on the number of buttons and the\n * number of rows.\n */\n grid_columns: {\n type: ParameterType.INT,\n default: null,\n },\n /** If true, then the trial will end whenever the participant makes a response (assuming they make their\n * response before the cutoff specified by the `trial_duration` parameter). If false, then the trial will\n * continue until the value for `trial_duration` is reached. You can set this parameter to `false` to force\n * the participant to listen to the stimulus for a fixed amount of time, even if they respond before the time is complete. */\n response_ends_trial: {\n type: ParameterType.BOOL,\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 default: false,\n },\n /**\n * If true, then responses are allowed while the audio is playing. If false, then the audio must finish\n * playing before the button choices are enabled and a response is accepted. Once the audio has played\n * all the way through, the buttons are enabled and a response is allowed (including while the audio is\n * being re-played via on-screen playback controls).\n */\n response_allowed_while_playing: {\n type: ParameterType.BOOL,\n default: true,\n },\n /** How long the button will delay enabling in milliseconds. If `response_allowed_while_playing` is `true`,\n * the timer will start immediately. If it is `false`, the timer will start at the end of the audio. */\n enable_button_after: {\n type: ParameterType.INT,\n default: 0,\n },\n },\n data: {\n /** The response time in milliseconds for the participant to make a response. The time is measured from\n * when the stimulus first began playing until the participant's response.*/\n rt: {\n type: ParameterType.INT,\n },\n /** Indicates which button the participant pressed. The first button in the `choices` array is 0, the second is 1, and so on. */\n response: {\n type: ParameterType.INT,\n },\n },\n};\n\ntype Info = typeof info;\n\n/**\n * If the browser supports it, audio files are played using the WebAudio API. This allows for reasonably precise \n * timing of the playback. The timing of responses generated is measured against the WebAudio specific clock, \n * improving the measurement of response times. If the browser does not support the WebAudio API, then the audio file is \n * played with HTML5 audio. \n\n * Audio files can be automatically preloaded by jsPsych using the [`preload` plugin](preload.md). However, if \n * you are using timeline variables or another dynamic method to specify the audio stimulus, you will need \n * to [manually preload](../overview/media-preloading.md#manual-preloading) the audio.\n\n * The trial can end when the participant responds, when the audio file has finished playing, or if the participant \n * has failed to respond within a fixed length of time. You can also prevent a button response from being made before the \n * audio has finished playing.\n * \n * @author Kristin Diep\n * @see {@link https://www.jspsych.org/latest/plugins/audio-button-response/ audio-button-response plugin documentation on jspsych.org}\n */\nclass AudioButtonResponsePlugin implements JsPsychPlugin<Info> {\n static info = info;\n private audio: AudioPlayerInterface;\n private params: TrialType<Info>;\n private buttonElements: HTMLElement[] = [];\n private display: HTMLElement;\n private response: { rt: number; button: number } = { rt: null, button: null };\n private context: AudioContext;\n private startTime: number;\n private trial_complete: (trial_data: { rt: number; stimulus: string; response: number }) => void;\n\n constructor(private jsPsych: JsPsych) {\n autoBind(this);\n }\n\n async trial(display_element: HTMLElement, trial: TrialType<Info>, on_load: () => void) {\n this.params = trial;\n this.display = display_element;\n // setup stimulus\n this.context = this.jsPsych.pluginAPI.audioContext();\n\n // load audio file\n this.audio = await this.jsPsych.pluginAPI.getAudioPlayer(trial.stimulus);\n\n // set up end event if trial needs it\n if (trial.trial_ends_after_audio) {\n this.audio.addEventListener(\"ended\", this.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\", this.enable_buttons);\n }\n\n // Display buttons\n const buttonGroupElement = document.createElement(\"div\");\n buttonGroupElement.id = \"jspsych-audio-button-response-btngroup\";\n if (trial.button_layout === \"grid\") {\n buttonGroupElement.classList.add(\"jspsych-btn-group-grid\");\n if (trial.grid_rows === null && trial.grid_columns === null) {\n throw new Error(\n \"You cannot set `grid_rows` to `null` without providing a value for `grid_columns`.\"\n );\n }\n const n_cols =\n trial.grid_columns === null\n ? Math.ceil(trial.choices.length / trial.grid_rows)\n : trial.grid_columns;\n const n_rows =\n trial.grid_rows === null\n ? Math.ceil(trial.choices.length / trial.grid_columns)\n : trial.grid_rows;\n buttonGroupElement.style.gridTemplateColumns = `repeat(${n_cols}, 1fr)`;\n buttonGroupElement.style.gridTemplateRows = `repeat(${n_rows}, 1fr)`;\n } else if (trial.button_layout === \"flex\") {\n buttonGroupElement.classList.add(\"jspsych-btn-group-flex\");\n }\n\n for (const [choiceIndex, choice] of trial.choices.entries()) {\n buttonGroupElement.insertAdjacentHTML(\"beforeend\", trial.button_html(choice, choiceIndex));\n const buttonElement = buttonGroupElement.lastChild as HTMLElement;\n buttonElement.dataset.choice = choiceIndex.toString();\n buttonElement.addEventListener(\"click\", () => {\n this.after_response(choiceIndex);\n });\n this.buttonElements.push(buttonElement);\n }\n\n display_element.appendChild(buttonGroupElement);\n\n // Show prompt if there is one\n if (trial.prompt !== null) {\n display_element.insertAdjacentHTML(\"beforeend\", trial.prompt);\n }\n\n if (trial.response_allowed_while_playing) {\n if (trial.enable_button_after > 0) {\n this.disable_buttons();\n this.enable_buttons();\n }\n } else {\n this.disable_buttons();\n }\n\n // end trial if time limit is set\n if (trial.trial_duration !== null) {\n this.jsPsych.pluginAPI.setTimeout(() => {\n this.end_trial();\n }, trial.trial_duration);\n }\n\n on_load();\n\n // start time\n this.startTime = performance.now();\n if (this.context !== null) {\n this.startTime = this.context.currentTime;\n }\n\n // start audio\n this.audio.play();\n\n return new Promise((resolve) => {\n // hold the .resolve() function from the Promise that ends the trial\n this.trial_complete = resolve;\n });\n }\n\n private disable_buttons = () => {\n for (const button of this.buttonElements) {\n button.setAttribute(\"disabled\", \"disabled\");\n }\n };\n\n private enable_buttons_without_delay = () => {\n for (const button of this.buttonElements) {\n button.removeAttribute(\"disabled\");\n }\n };\n\n private enable_buttons_with_delay = (delay: number) => {\n this.jsPsych.pluginAPI.setTimeout(this.enable_buttons_without_delay, delay);\n };\n\n private enable_buttons() {\n if (this.params.enable_button_after > 0) {\n this.enable_buttons_with_delay(this.params.enable_button_after);\n } else {\n this.enable_buttons_without_delay();\n }\n }\n\n // function to handle responses by the subject\n private after_response = (choice) => {\n // measure rt\n var endTime = performance.now();\n var rt = Math.round(endTime - this.startTime);\n if (this.context !== null) {\n endTime = this.context.currentTime;\n rt = Math.round((endTime - this.startTime) * 1000);\n }\n this.response.button = parseInt(choice);\n this.response.rt = rt;\n\n // disable all the buttons after a response\n this.disable_buttons();\n\n if (this.params.response_ends_trial) {\n this.end_trial();\n }\n };\n\n // method to end trial when it is time\n private end_trial = () => {\n // stop the audio file if it is playing\n this.audio.stop();\n\n // remove end event listeners if they exist\n this.audio.removeEventListener(\"ended\", this.end_trial);\n this.audio.removeEventListener(\"ended\", this.enable_buttons);\n\n // gather the data to store for the trial\n var trial_data = {\n rt: this.response.rt,\n stimulus: this.params.stimulus,\n response: this.response.button,\n };\n\n // move on to the next trial\n this.trial_complete(trial_data);\n };\n\n async 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(\n `#jspsych-audio-button-response-btngroup [data-choice=\"${data.response}\"]`\n ),\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":["version","ParameterType","autoBind"],"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 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
+ var jsPsychAudioButtonResponse=function(a){"use strict";function c(i){return i&&i.__esModule&&Object.prototype.hasOwnProperty.call(i,"default")?i.default:i}const _=i=>{const s=new Set;do for(const t of Reflect.ownKeys(i))s.add([i,t]);while((i=Reflect.getPrototypeOf(i))&&i!==Object.prototype);return s};var m=(i,{include:s,exclude:t}={})=>{const r=e=>{const n=o=>typeof o=="string"?e===o:o.test(e);return s?s.some(n):t?!t.some(n):!0};for(const[e,n]of _(i.constructor.prototype)){if(n==="constructor"||!r(n))continue;const o=Reflect.getOwnPropertyDescriptor(e,n);o&&typeof o.value=="function"&&(i[n]=i[n].bind(i))}return i},y=c(m),b={name:"@jspsych/plugin-audio-button-response",version:"2.0.1",description:"jsPsych plugin for playing an audio file and getting a button response",type:"module",main:"dist/index.cjs",exports:{import:"./dist/index.js",require:"./dist/index.cjs"},typings:"dist/index.d.ts",unpkg:"dist/index.browser.min.js",files:["src","dist"],source:"src/index.ts",scripts:{test:"jest","test:watch":"npm test -- --watch",tsc:"tsc",build:"rollup --config","build:watch":"npm run build -- --watch"},repository:{type:"git",url:"git+https://github.com/jspsych/jsPsych.git",directory:"packages/plugin-audio-button-response"},author:"Kristin Diep",license:"MIT",bugs:{url:"https://github.com/jspsych/jsPsych/issues"},homepage:"https://www.jspsych.org/latest/plugins/audio-button-response",peerDependencies:{jspsych:">=7.1.0"},devDependencies:{"@jspsych/config":"^3.0.0","@jspsych/test-utils":"^1.2.0"}},p=(i,s,t)=>new Promise((r,e)=>{var n=u=>{try{l(t.next(u))}catch(d){e(d)}},o=u=>{try{l(t.throw(u))}catch(d){e(d)}},l=u=>u.done?r(u.value):Promise.resolve(u.value).then(n,o);l((t=t.apply(i,s)).next())});const g={name:"audio-button-response",version:b.version,parameters:{stimulus:{type:a.ParameterType.AUDIO,default:void 0},choices:{type:a.ParameterType.STRING,default:void 0,array:!0},button_html:{type:a.ParameterType.FUNCTION,default:function(i,s){return`<button class="jspsych-btn">${i}</button>`}},prompt:{type:a.ParameterType.HTML_STRING,default:null},trial_duration:{type:a.ParameterType.INT,default:null},button_layout:{type:a.ParameterType.STRING,default:"grid"},grid_rows:{type:a.ParameterType.INT,default:1},grid_columns:{type:a.ParameterType.INT,default:null},response_ends_trial:{type:a.ParameterType.BOOL,default:!0},trial_ends_after_audio:{type:a.ParameterType.BOOL,default:!1},response_allowed_while_playing:{type:a.ParameterType.BOOL,default:!0},enable_button_after:{type:a.ParameterType.INT,default:0}},data:{rt:{type:a.ParameterType.INT},response:{type:a.ParameterType.INT}}};class h{constructor(s){this.jsPsych=s,this.buttonElements=[],this.response={rt:null,button:null},this.disable_buttons=()=>{for(const t of this.buttonElements)t.setAttribute("disabled","disabled")},this.enable_buttons_without_delay=()=>{for(const t of this.buttonElements)t.removeAttribute("disabled")},this.enable_buttons_with_delay=t=>{this.jsPsych.pluginAPI.setTimeout(this.enable_buttons_without_delay,t)},this.after_response=t=>{var r=performance.now(),e=Math.round(r-this.startTime);this.context!==null&&(r=this.context.currentTime,e=Math.round((r-this.startTime)*1e3)),this.response.button=parseInt(t),this.response.rt=e,this.disable_buttons(),this.params.response_ends_trial&&this.end_trial()},this.end_trial=()=>{this.audio.stop(),this.audio.removeEventListener("ended",this.end_trial),this.audio.removeEventListener("ended",this.enable_buttons);var t={rt:this.response.rt,stimulus:this.params.stimulus,response:this.response.button};this.trial_complete(t)},y(this)}trial(s,t,r){return p(this,null,function*(){this.params=t,this.display=s,this.context=this.jsPsych.pluginAPI.audioContext(),this.audio=yield this.jsPsych.pluginAPI.getAudioPlayer(t.stimulus),t.trial_ends_after_audio&&this.audio.addEventListener("ended",this.end_trial),!t.response_allowed_while_playing&&!t.trial_ends_after_audio&&this.audio.addEventListener("ended",this.enable_buttons);const e=document.createElement("div");if(e.id="jspsych-audio-button-response-btngroup",t.button_layout==="grid"){if(e.classList.add("jspsych-btn-group-grid"),t.grid_rows===null&&t.grid_columns===null)throw new Error("You cannot set `grid_rows` to `null` without providing a value for `grid_columns`.");const n=t.grid_columns===null?Math.ceil(t.choices.length/t.grid_rows):t.grid_columns,o=t.grid_rows===null?Math.ceil(t.choices.length/t.grid_columns):t.grid_rows;e.style.gridTemplateColumns=`repeat(${n}, 1fr)`,e.style.gridTemplateRows=`repeat(${o}, 1fr)`}else t.button_layout==="flex"&&e.classList.add("jspsych-btn-group-flex");for(const[n,o]of t.choices.entries()){e.insertAdjacentHTML("beforeend",t.button_html(o,n));const l=e.lastChild;l.dataset.choice=n.toString(),l.addEventListener("click",()=>{this.after_response(n)}),this.buttonElements.push(l)}return s.appendChild(e),t.prompt!==null&&s.insertAdjacentHTML("beforeend",t.prompt),t.response_allowed_while_playing?t.enable_button_after>0&&(this.disable_buttons(),this.enable_buttons()):this.disable_buttons(),t.trial_duration!==null&&this.jsPsych.pluginAPI.setTimeout(()=>{this.end_trial()},t.trial_duration),r(),this.startTime=performance.now(),this.context!==null&&(this.startTime=this.context.currentTime),this.audio.play(),new Promise(n=>{this.trial_complete=n})})}enable_buttons(){this.params.enable_button_after>0?this.enable_buttons_with_delay(this.params.enable_button_after):this.enable_buttons_without_delay()}simulate(s,t,r,e){return p(this,null,function*(){t=="data-only"&&(e(),this.simulate_data_only(s,r)),t=="visual"&&this.simulate_visual(s,r,e)})}create_simulation_data(s,t){const r={stimulus:s.stimulus,rt:this.jsPsych.randomization.sampleExGaussian(500,50,.006666666666666667,!0)+s.enable_button_after,response:this.jsPsych.randomization.randomInt(0,s.choices.length-1)},e=this.jsPsych.pluginAPI.mergeSimulationData(r,t);return this.jsPsych.pluginAPI.ensureSimulationDataConsistency(s,e),e}simulate_data_only(s,t){const r=this.create_simulation_data(s,t);this.jsPsych.finishTrial(r)}simulate_visual(s,t,r){const e=this.create_simulation_data(s,t),n=this.jsPsych.getDisplayElement(),o=()=>{e.rt!==null&&this.jsPsych.pluginAPI.clickTarget(n.querySelector(`#jspsych-audio-button-response-btngroup [data-choice="${e.response}"]`),e.rt)};this.trial(n,s,()=>{r(),s.response_allowed_while_playing?o():this.audio.addEventListener("ended",o)})}}return h.info=g,h}(jsPsychModule);
2
+ //# sourceMappingURL=https://unpkg.com/@jspsych/plugin-audio-button-response@2.0.1/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 /** 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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"}
1
+ {"version":3,"file":"index.browser.min.js","sources":["../../../node_modules/auto-bind/index.js","../src/index.ts"],"sourcesContent":["'use strict';\n\n// Gets all non-builtin properties up the prototype chain\nconst getAllProperties = object => {\n\tconst properties = new Set();\n\n\tdo {\n\t\tfor (const key of Reflect.ownKeys(object)) {\n\t\t\tproperties.add([object, key]);\n\t\t}\n\t} while ((object = Reflect.getPrototypeOf(object)) && object !== Object.prototype);\n\n\treturn properties;\n};\n\nmodule.exports = (self, {include, exclude} = {}) => {\n\tconst filter = key => {\n\t\tconst match = pattern => typeof pattern === 'string' ? key === pattern : pattern.test(key);\n\n\t\tif (include) {\n\t\t\treturn include.some(match);\n\t\t}\n\n\t\tif (exclude) {\n\t\t\treturn !exclude.some(match);\n\t\t}\n\n\t\treturn true;\n\t};\n\n\tfor (const [object, key] of getAllProperties(self.constructor.prototype)) {\n\t\tif (key === 'constructor' || !filter(key)) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst descriptor = Reflect.getOwnPropertyDescriptor(object, key);\n\t\tif (descriptor && typeof descriptor.value === 'function') {\n\t\t\tself[key] = self[key].bind(self);\n\t\t}\n\t}\n\n\treturn self;\n};\n","import autoBind from \"auto-bind\";\nimport { JsPsych, JsPsychPlugin, ParameterType, TrialType } from \"jspsych\";\n\nimport { AudioPlayerInterface } from \"../../jspsych/src/modules/plugin-api/AudioPlayer\";\nimport { version } from \"../package.json\";\n\nconst info = <const>{\n name: \"audio-button-response\",\n version: version,\n parameters: {\n /** Path to audio file to be played. */\n stimulus: {\n type: ParameterType.AUDIO,\n default: undefined,\n },\n /** Labels for the buttons. Each different string in the array will generate a different button. */\n choices: {\n type: ParameterType.STRING,\n default: undefined,\n array: true,\n },\n /**\n * A function that generates the HTML for each button in the `choices` array. The function gets the string\n * and index of the item in the `choices` array and should return valid HTML. If you want to use different\n * markup for each button, you can do that by using a conditional on either parameter. The default parameter\n * returns a button element with the text label of the choice.\n */\n button_html: {\n type: ParameterType.FUNCTION,\n default: function (choice: string, choice_index: number) {\n return `<button class=\"jspsych-btn\">${choice}</button>`;\n },\n },\n /** This string can contain HTML markup. Any content here will be displayed below the stimulus. The intention\n * is that it can be used to provide a reminder about the action the participant is supposed to take\n * (e.g., which key to press). */\n prompt: {\n type: ParameterType.HTML_STRING,\n default: null,\n },\n /** How long to wait for the participant to make a response before ending the trial in milliseconds. If the\n * participant fails to make a response before this timer is reached, the participant's response will be\n * recorded as null for the trial and the trial will end. If the value of this parameter is null, the trial\n * will wait for a response indefinitely */\n trial_duration: {\n type: ParameterType.INT,\n default: null,\n },\n /** Setting to `'grid'` will make the container element have the CSS property `display: grid` and enable the\n * use of `grid_rows` and `grid_columns`. Setting to `'flex'` will make the container element have the CSS\n * property `display: flex`. You can customize how the buttons are laid out by adding inline CSS in the `button_html` parameter.\n */\n button_layout: {\n type: ParameterType.STRING,\n default: \"grid\",\n },\n /** The number of rows in the button grid. Only applicable when `button_layout` is set to `'grid'`. If null, the\n * number of rows will be determined automatically based on the number of buttons and the number of columns.\n */\n grid_rows: {\n type: ParameterType.INT,\n default: 1,\n },\n /** The number of columns in the button grid. Only applicable when `button_layout` is set to `'grid'`.\n * If null, the number of columns will be determined automatically based on the number of buttons and the\n * number of rows.\n */\n grid_columns: {\n type: ParameterType.INT,\n default: null,\n },\n /** If true, then the trial will end whenever the participant makes a response (assuming they make their\n * response before the cutoff specified by the `trial_duration` parameter). If false, then the trial will\n * continue until the value for `trial_duration` is reached. You can set this parameter to `false` to force\n * the participant to listen to the stimulus for a fixed amount of time, even if they respond before the time is complete. */\n response_ends_trial: {\n type: ParameterType.BOOL,\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 default: false,\n },\n /**\n * If true, then responses are allowed while the audio is playing. If false, then the audio must finish\n * playing before the button choices are enabled and a response is accepted. Once the audio has played\n * all the way through, the buttons are enabled and a response is allowed (including while the audio is\n * being re-played via on-screen playback controls).\n */\n response_allowed_while_playing: {\n type: ParameterType.BOOL,\n default: true,\n },\n /** How long the button will delay enabling in milliseconds. If `response_allowed_while_playing` is `true`,\n * the timer will start immediately. If it is `false`, the timer will start at the end of the audio. */\n enable_button_after: {\n type: ParameterType.INT,\n default: 0,\n },\n },\n data: {\n /** The response time in milliseconds for the participant to make a response. The time is measured from\n * when the stimulus first began playing until the participant's response.*/\n rt: {\n type: ParameterType.INT,\n },\n /** Indicates which button the participant pressed. The first button in the `choices` array is 0, the second is 1, and so on. */\n response: {\n type: ParameterType.INT,\n },\n },\n};\n\ntype Info = typeof info;\n\n/**\n * If the browser supports it, audio files are played using the WebAudio API. This allows for reasonably precise \n * timing of the playback. The timing of responses generated is measured against the WebAudio specific clock, \n * improving the measurement of response times. If the browser does not support the WebAudio API, then the audio file is \n * played with HTML5 audio. \n\n * Audio files can be automatically preloaded by jsPsych using the [`preload` plugin](preload.md). However, if \n * you are using timeline variables or another dynamic method to specify the audio stimulus, you will need \n * to [manually preload](../overview/media-preloading.md#manual-preloading) the audio.\n\n * The trial can end when the participant responds, when the audio file has finished playing, or if the participant \n * has failed to respond within a fixed length of time. You can also prevent a button response from being made before the \n * audio has finished playing.\n * \n * @author Kristin Diep\n * @see {@link https://www.jspsych.org/latest/plugins/audio-button-response/ audio-button-response plugin documentation on jspsych.org}\n */\nclass AudioButtonResponsePlugin implements JsPsychPlugin<Info> {\n static info = info;\n private audio: AudioPlayerInterface;\n private params: TrialType<Info>;\n private buttonElements: HTMLElement[] = [];\n private display: HTMLElement;\n private response: { rt: number; button: number } = { rt: null, button: null };\n private context: AudioContext;\n private startTime: number;\n private trial_complete: (trial_data: { rt: number; stimulus: string; response: number }) => void;\n\n constructor(private jsPsych: JsPsych) {\n autoBind(this);\n }\n\n async trial(display_element: HTMLElement, trial: TrialType<Info>, on_load: () => void) {\n this.params = trial;\n this.display = display_element;\n // setup stimulus\n this.context = this.jsPsych.pluginAPI.audioContext();\n\n // load audio file\n this.audio = await this.jsPsych.pluginAPI.getAudioPlayer(trial.stimulus);\n\n // set up end event if trial needs it\n if (trial.trial_ends_after_audio) {\n this.audio.addEventListener(\"ended\", this.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\", this.enable_buttons);\n }\n\n // Display buttons\n const buttonGroupElement = document.createElement(\"div\");\n buttonGroupElement.id = \"jspsych-audio-button-response-btngroup\";\n if (trial.button_layout === \"grid\") {\n buttonGroupElement.classList.add(\"jspsych-btn-group-grid\");\n if (trial.grid_rows === null && trial.grid_columns === null) {\n throw new Error(\n \"You cannot set `grid_rows` to `null` without providing a value for `grid_columns`.\"\n );\n }\n const n_cols =\n trial.grid_columns === null\n ? Math.ceil(trial.choices.length / trial.grid_rows)\n : trial.grid_columns;\n const n_rows =\n trial.grid_rows === null\n ? Math.ceil(trial.choices.length / trial.grid_columns)\n : trial.grid_rows;\n buttonGroupElement.style.gridTemplateColumns = `repeat(${n_cols}, 1fr)`;\n buttonGroupElement.style.gridTemplateRows = `repeat(${n_rows}, 1fr)`;\n } else if (trial.button_layout === \"flex\") {\n buttonGroupElement.classList.add(\"jspsych-btn-group-flex\");\n }\n\n for (const [choiceIndex, choice] of trial.choices.entries()) {\n buttonGroupElement.insertAdjacentHTML(\"beforeend\", trial.button_html(choice, choiceIndex));\n const buttonElement = buttonGroupElement.lastChild as HTMLElement;\n buttonElement.dataset.choice = choiceIndex.toString();\n buttonElement.addEventListener(\"click\", () => {\n this.after_response(choiceIndex);\n });\n this.buttonElements.push(buttonElement);\n }\n\n display_element.appendChild(buttonGroupElement);\n\n // Show prompt if there is one\n if (trial.prompt !== null) {\n display_element.insertAdjacentHTML(\"beforeend\", trial.prompt);\n }\n\n if (trial.response_allowed_while_playing) {\n if (trial.enable_button_after > 0) {\n this.disable_buttons();\n this.enable_buttons();\n }\n } else {\n this.disable_buttons();\n }\n\n // end trial if time limit is set\n if (trial.trial_duration !== null) {\n this.jsPsych.pluginAPI.setTimeout(() => {\n this.end_trial();\n }, trial.trial_duration);\n }\n\n on_load();\n\n // start time\n this.startTime = performance.now();\n if (this.context !== null) {\n this.startTime = this.context.currentTime;\n }\n\n // start audio\n this.audio.play();\n\n return new Promise((resolve) => {\n // hold the .resolve() function from the Promise that ends the trial\n this.trial_complete = resolve;\n });\n }\n\n private disable_buttons = () => {\n for (const button of this.buttonElements) {\n button.setAttribute(\"disabled\", \"disabled\");\n }\n };\n\n private enable_buttons_without_delay = () => {\n for (const button of this.buttonElements) {\n button.removeAttribute(\"disabled\");\n }\n };\n\n private enable_buttons_with_delay = (delay: number) => {\n this.jsPsych.pluginAPI.setTimeout(this.enable_buttons_without_delay, delay);\n };\n\n private enable_buttons() {\n if (this.params.enable_button_after > 0) {\n this.enable_buttons_with_delay(this.params.enable_button_after);\n } else {\n this.enable_buttons_without_delay();\n }\n }\n\n // function to handle responses by the subject\n private after_response = (choice) => {\n // measure rt\n var endTime = performance.now();\n var rt = Math.round(endTime - this.startTime);\n if (this.context !== null) {\n endTime = this.context.currentTime;\n rt = Math.round((endTime - this.startTime) * 1000);\n }\n this.response.button = parseInt(choice);\n this.response.rt = rt;\n\n // disable all the buttons after a response\n this.disable_buttons();\n\n if (this.params.response_ends_trial) {\n this.end_trial();\n }\n };\n\n // method to end trial when it is time\n private end_trial = () => {\n // stop the audio file if it is playing\n this.audio.stop();\n\n // remove end event listeners if they exist\n this.audio.removeEventListener(\"ended\", this.end_trial);\n this.audio.removeEventListener(\"ended\", this.enable_buttons);\n\n // gather the data to store for the trial\n var trial_data = {\n rt: this.response.rt,\n stimulus: this.params.stimulus,\n response: this.response.button,\n };\n\n // move on to the next trial\n this.trial_complete(trial_data);\n };\n\n async 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(\n `#jspsych-audio-button-response-btngroup [data-choice=\"${data.response}\"]`\n ),\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":["getAllProperties","object","properties","key","autoBind","self","include","exclude","filter","match","pattern","descriptor","l","e","n","s","o","r","a","info","version","ParameterType","choice","choice_index","AudioButtonResponsePlugin","jsPsych","button","delay","endTime","rt","trial_data","display_element","trial","on_load","__async","buttonGroupElement","n_cols","n_rows","choiceIndex","buttonElement","resolve","simulation_mode","simulation_options","load_callback","default_data","data","respond"],"mappings":"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"}