var jsPsychSurveyMultiChoice = (function (jspsych) { 'use strict'; const info = { name: "survey-multi-choice", parameters: { /** Array containing one or more objects with parameters for the question(s) that should be shown on the page. */ questions: { type: jspsych.ParameterType.COMPLEX, array: true, pretty_name: "Questions", nested: { /** Question prompt. */ prompt: { type: jspsych.ParameterType.HTML_STRING, pretty_name: "Prompt", default: undefined, }, /** Array of multiple choice options for this question. */ options: { type: jspsych.ParameterType.STRING, pretty_name: "Options", array: true, default: undefined, }, /** Whether or not a response to this question must be given in order to continue. */ required: { type: jspsych.ParameterType.BOOL, pretty_name: "Required", default: false, }, /** If true, then the question will be centered and options will be displayed horizontally. */ horizontal: { type: jspsych.ParameterType.BOOL, pretty_name: "Horizontal", default: false, }, /** Name of the question in the trial data. If no name is given, the questions are named Q0, Q1, etc. */ name: { type: jspsych.ParameterType.STRING, pretty_name: "Question Name", default: "", }, }, }, /** If true, the order of the questions in the 'questions' array will be randomized. */ randomize_question_order: { type: jspsych.ParameterType.BOOL, pretty_name: "Randomize Question Order", default: false, }, /** HTML-formatted string to display at top of the page above all of the questions. */ preamble: { type: jspsych.ParameterType.HTML_STRING, pretty_name: "Preamble", default: null, }, /** Label of the button to submit responses. */ button_label: { type: jspsych.ParameterType.STRING, pretty_name: "Button label", default: "Continue", }, /** Setting this to true will enable browser auto-complete or auto-fill for the form. */ autocomplete: { type: jspsych.ParameterType.BOOL, pretty_name: "Allow autocomplete", default: false, }, }, }; /** * **survey-multi-choice** * * jsPsych plugin for presenting multiple choice survey questions * * @author Shane Martin * @see {@link https://www.jspsych.org/plugins/jspsych-survey-multi-choice/ survey-multi-choice plugin documentation on jspsych.org} */ class SurveyMultiChoicePlugin { constructor(jsPsych) { this.jsPsych = jsPsych; } trial(display_element, trial) { var plugin_id_name = "jspsych-survey-multi-choice"; var html = ""; // inject CSS for trial html += '"; // show preamble text if (trial.preamble !== null) { html += '
' + trial.preamble + "
"; } // form element if (trial.autocomplete) { html += '
'; } else { html += ''; } // generate question order. this is randomized here as opposed to randomizing the order of trial.questions // so that the data are always associated with the same question regardless of order var question_order = []; for (var i = 0; i < trial.questions.length; i++) { question_order.push(i); } if (trial.randomize_question_order) { question_order = this.jsPsych.randomization.shuffle(question_order); } // add multiple-choice questions for (var i = 0; i < trial.questions.length; i++) { // get question based on question_order var question = trial.questions[question_order[i]]; var question_id = question_order[i]; // create question container var question_classes = ["jspsych-survey-multi-choice-question"]; if (question.horizontal) { question_classes.push("jspsych-survey-multi-choice-horizontal"); } html += '
'; // add question text html += '

' + question.prompt; if (question.required) { html += "*"; } html += "

"; // create option radio buttons for (var j = 0; j < question.options.length; j++) { // add label and question text var option_id_name = "jspsych-survey-multi-choice-option-" + question_id + "-" + j; var input_name = "jspsych-survey-multi-choice-response-" + question_id; var input_id = "jspsych-survey-multi-choice-response-" + question_id + "-" + j; var required_attr = question.required ? "required" : ""; // add radio button container html += '
'; html += '"; html += "
"; } html += "
"; } // add submit button html += '"; html += "
"; // render display_element.innerHTML = html; document.querySelector("form").addEventListener("submit", (event) => { event.preventDefault(); // measure response time var endTime = performance.now(); var response_time = Math.round(endTime - startTime); // create object to hold responses var question_data = {}; for (var i = 0; i < trial.questions.length; i++) { var match = display_element.querySelector("#jspsych-survey-multi-choice-" + i); var id = "Q" + i; var val; if (match.querySelector("input[type=radio]:checked") !== null) { val = match.querySelector("input[type=radio]:checked").value; } else { val = ""; } var obje = {}; var name = id; if (match.attributes["data-name"].value !== "") { name = match.attributes["data-name"].value; } obje[name] = val; Object.assign(question_data, obje); } // save data var trial_data = { rt: response_time, response: question_data, question_order: question_order, }; display_element.innerHTML = ""; // next trial this.jsPsych.finishTrial(trial_data); }); var startTime = performance.now(); } 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 question_data = {}; let rt = 1000; for (const q of trial.questions) { const name = q.name ? q.name : `Q${trial.questions.indexOf(q)}`; question_data[name] = this.jsPsych.randomization.sampleWithoutReplacement(q.options, 1)[0]; rt += this.jsPsych.randomization.sampleExGaussian(1500, 400, 1 / 200, true); } const default_data = { response: question_data, rt: rt, question_order: trial.randomize_question_order ? this.jsPsych.randomization.shuffle([...Array(trial.questions.length).keys()]) : [...Array(trial.questions.length).keys()], }; 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(); const answers = Object.entries(data.response); for (let i = 0; i < answers.length; i++) { this.jsPsych.pluginAPI.clickTarget(display_element.querySelector(`#jspsych-survey-multi-choice-response-${i}-${trial.questions[i].options.indexOf(answers[i][1])}`), ((data.rt - 1000) / answers.length) * (i + 1)); } this.jsPsych.pluginAPI.clickTarget(display_element.querySelector("#jspsych-survey-multi-choice-next"), data.rt); } } SurveyMultiChoicePlugin.info = info; return SurveyMultiChoicePlugin; })(jsPsychModule);