var jsPsychIatHtml = (function (jspsych) { 'use strict'; const info = { name: "iat-html", parameters: { /** The HTML string to be displayed. */ stimulus: { type: jspsych.ParameterType.HTML_STRING, pretty_name: "Stimulus", default: undefined, }, /** Key press that is associated with the left category label.*/ left_category_key: { type: jspsych.ParameterType.KEY, pretty_name: "Left category key", default: "e", }, /** Key press that is associated with the right category label. */ right_category_key: { type: jspsych.ParameterType.KEY, pretty_name: "Right category key", default: "i", }, /** The label that is associated with the stimulus. Aligned to the left side of page */ left_category_label: { type: jspsych.ParameterType.STRING, pretty_name: "Left category label", array: true, default: ["left"], }, /** The label that is associated with the stimulus. Aligned to the right side of the page. */ right_category_label: { type: jspsych.ParameterType.STRING, pretty_name: "Right category label", array: true, default: ["right"], }, /** Array containing the key(s) that allow the user to advance to the next trial if their key press was incorrect. */ key_to_move_forward: { type: jspsych.ParameterType.KEYS, pretty_name: "Key to move forward", default: "ALL_KEYS", }, /** If true, then html when wrong will be displayed when user makes an incorrect key press. */ display_feedback: { type: jspsych.ParameterType.BOOL, pretty_name: "Display feedback", default: false, }, /** The HTML to display when a user presses the wrong key. */ html_when_wrong: { type: jspsych.ParameterType.HTML_STRING, pretty_name: "HTML when wrong", default: 'X', }, /** Instructions shown at the bottom of the page. */ bottom_instructions: { type: jspsych.ParameterType.HTML_STRING, pretty_name: "Bottom instructions", default: "

If you press the wrong key, a red X will appear. Press any key to continue.

", }, /** If true, in order to advance to the next trial after a wrong key press the user will be forced to press the correct key. */ force_correct_key_press: { type: jspsych.ParameterType.BOOL, pretty_name: "Force correct key press", default: false, }, /** Stimulus will be associated with either "left" or "right". */ stim_key_association: { type: jspsych.ParameterType.SELECT, pretty_name: "Stimulus key association", options: ["left", "right"], default: undefined, }, /** If true, trial will end when user makes a response. */ response_ends_trial: { type: jspsych.ParameterType.BOOL, pretty_name: "Response ends trial", default: true, }, /** How long to show the trial. */ trial_duration: { type: jspsych.ParameterType.INT, pretty_name: "Trial duration", default: null, }, }, }; /** * **iat-html** * * jsPsych plugin for running an IAT (Implicit Association Test) with an HTML-formatted stimulus * * @author Kristin Diep * @see {@link https://www.jspsych.org/plugins/jspsych-iat-html/ iat-html plugin documentation on jspsych.org} */ class IatHtmlPlugin { constructor(jsPsych) { this.jsPsych = jsPsych; } trial(display_element, trial) { var html_str = ""; html_str += "

" + trial.stimulus + "

"; html_str += "
"; if (trial.left_category_label.length == 1) { html_str += "

Press " + trial.left_category_key + " for:
" + trial.left_category_label[0].bold() + "

"; } else { html_str += "

Press " + trial.left_category_key + " for:
" + trial.left_category_label[0].bold() + "
" + "or
" + trial.left_category_label[1].bold() + "

"; } html_str += "
"; if (trial.right_category_label.length == 1) { html_str += "

Press " + trial.right_category_key + " for:
" + trial.right_category_label[0].bold() + "

"; } else { html_str += "

Press " + trial.right_category_key + " for:
" + trial.right_category_label[0].bold() + "
" + "or
" + trial.right_category_label[1].bold() + "

"; } html_str += "
"; if (trial.display_feedback === true) { html_str += ""; html_str += "
" + trial.bottom_instructions + "
"; } else { html_str += "
" + trial.bottom_instructions + "
"; } html_str += "
"; display_element.innerHTML = html_str; // store response var response = { rt: null, key: null, correct: false, }; // function to end trial when it is time const end_trial = () => { // kill any remaining setTimeout handlers this.jsPsych.pluginAPI.clearAllTimeouts(); // kill keyboard listeners if (typeof keyboardListener !== "undefined") { this.jsPsych.pluginAPI.cancelKeyboardResponse(keyboardListener); } // gather the data to store for the trial var trial_data = { rt: response.rt, stimulus: trial.stimulus, response: response.key, correct: response.correct, }; // clears the display display_element.innerHTML = ""; // move on to the next trial this.jsPsych.finishTrial(trial_data); }; var leftKeyCode = trial.left_category_key; var rightKeyCode = trial.right_category_key; // function to handle responses by the subject const after_response = (info) => { var wImg = document.getElementById("wrongImgContainer"); // after a valid response, the stimulus will have the CSS class 'responded' // which can be used to provide visual feedback that a response was recorded display_element.querySelector("#jspsych-iat-stim").className += " responded"; // only record the first response if (response.key == null) { response.key = info.key; response.rt = info.rt; } if (trial.stim_key_association == "right") { if (response.rt !== null && this.jsPsych.pluginAPI.compareKeys(response.key, rightKeyCode)) { response.correct = true; if (trial.response_ends_trial) { end_trial(); } } else { response.correct = false; if (!trial.response_ends_trial && trial.display_feedback == true) { wImg.style.visibility = "visible"; } if (trial.response_ends_trial && trial.display_feedback == true) { wImg.style.visibility = "visible"; if (trial.force_correct_key_press) { this.jsPsych.pluginAPI.getKeyboardResponse({ callback_function: end_trial, valid_responses: [trial.right_category_key], }); } else { this.jsPsych.pluginAPI.getKeyboardResponse({ callback_function: end_trial, valid_responses: trial.key_to_move_forward, }); } } else if (trial.response_ends_trial && trial.display_feedback != true) { end_trial(); } else if (!trial.response_ends_trial && trial.display_feedback != true) ; } } else if (trial.stim_key_association == "left") { if (response.rt !== null && this.jsPsych.pluginAPI.compareKeys(response.key, leftKeyCode)) { response.correct = true; if (trial.response_ends_trial) { end_trial(); } } else { response.correct = false; if (!trial.response_ends_trial && trial.display_feedback == true) { wImg.style.visibility = "visible"; } if (trial.response_ends_trial && trial.display_feedback == true) { wImg.style.visibility = "visible"; if (trial.force_correct_key_press) { this.jsPsych.pluginAPI.getKeyboardResponse({ callback_function: end_trial, valid_responses: [trial.left_category_key], }); } else { this.jsPsych.pluginAPI.getKeyboardResponse({ callback_function: end_trial, valid_responses: trial.key_to_move_forward, }); } } else if (trial.response_ends_trial && trial.display_feedback != true) { end_trial(); } else if (!trial.response_ends_trial && trial.display_feedback != true) ; } } }; // start the response listener if (trial.left_category_key != "NO_KEYS" && trial.right_category_key != "NO_KEYS") { var keyboardListener = this.jsPsych.pluginAPI.getKeyboardResponse({ callback_function: after_response, valid_responses: [trial.left_category_key, trial.right_category_key], rt_method: "performance", persist: false, allow_held_key: false, }); } // end trial if time limit is set if (trial.trial_duration !== null && trial.response_ends_trial != true) { this.jsPsych.pluginAPI.setTimeout(() => { end_trial(); }, trial.trial_duration); } } simulate(trial, simulation_mode, simulation_options, load_callback) { if (simulation_mode == "data-only") { load_callback(); this.simulate_data_only(trial, simulation_options); } if (simulation_mode == "visual") { this.simulate_visual(trial, simulation_options, load_callback); } } create_simulation_data(trial, simulation_options) { const key = this.jsPsych.pluginAPI.getValidKey([ trial.left_category_key, trial.right_category_key, ]); const correct = trial.stim_key_association == "left" ? key == trial.left_category_key : key == trial.right_category_key; const default_data = { stimulus: trial.stimulus, response: key, rt: this.jsPsych.randomization.sampleExGaussian(500, 50, 1 / 150, true), correct: correct, }; const data = this.jsPsych.pluginAPI.mergeSimulationData(default_data, simulation_options); this.jsPsych.pluginAPI.ensureSimulationDataConsistency(trial, data); return data; } simulate_data_only(trial, simulation_options) { const data = this.create_simulation_data(trial, simulation_options); this.jsPsych.finishTrial(data); } simulate_visual(trial, simulation_options, load_callback) { const data = this.create_simulation_data(trial, simulation_options); const display_element = this.jsPsych.getDisplayElement(); this.trial(display_element, trial); load_callback(); if (data.response !== null) { this.jsPsych.pluginAPI.pressKey(data.response, data.rt); } const cont_rt = data.rt == null ? trial.trial_duration : data.rt; if (trial.force_correct_key_press) { if (!data.correct) { this.jsPsych.pluginAPI.pressKey(trial.stim_key_association == "left" ? trial.left_category_key : trial.right_category_key, cont_rt + this.jsPsych.randomization.sampleExGaussian(500, 50, 1 / 150, true)); } } else { this.jsPsych.pluginAPI.pressKey(this.jsPsych.pluginAPI.getValidKey(trial.key_to_move_forward), cont_rt + this.jsPsych.randomization.sampleExGaussian(500, 50, 1 / 150, true)); } } } IatHtmlPlugin.info = info; return IatHtmlPlugin; })(jsPsychModule);