import { JsPsych, JsPsychPlugin, ParameterType, TrialType } from "jspsych"; import { version } from "../package.json"; const info = { name: "survey-html-form", version: version, parameters: { /** HTML formatted string containing all the input elements to display. Every element has to have its own distinctive name attribute. The
tag must not be included and is generated by the plugin. */ html: { type: ParameterType.HTML_STRING, default: null, }, /** HTML formatted string to display at the top of the page above all the questions. */ preamble: { type: ParameterType.HTML_STRING, default: null, }, /** The text that appears on the button to finish the trial. */ button_label: { type: ParameterType.STRING, default: "Continue", }, /** The HTML element ID of a form field to autofocus on. */ autofocus: { type: ParameterType.STRING, default: "", }, /** Retrieve the data as an array e.g. [{name: "INPUT_NAME", value: "INPUT_VALUE"}, ...] instead of an object e.g. {INPUT_NAME: INPUT_VALUE, ...}. */ dataAsArray: { type: ParameterType.BOOL, default: false, }, /** Setting this to true will enable browser auto-complete or auto-fill for the form. */ autocomplete: { type: ParameterType.BOOL, default: false, }, }, data: { /** An object containing the response for each input. The object will have a separate key (variable) for the response to each input, with each variable being named after its corresponding input element. Each response is a string containing whatever the participant answered for this particular input. This will be encoded as a JSON string when data is saved using the `.json()` or `.csv()` functions. */ response: { type: ParameterType.COMPLEX, nested: { identifier: { type: ParameterType.STRING, }, response: { type: ParameterType.STRING | ParameterType.INT | ParameterType.FLOAT | ParameterType.BOOL | ParameterType.OBJECT, }, }, }, /** The response time in milliseconds for the participant to make a response. */ rt: { type: ParameterType.INT, }, }, }; type Info = typeof info; /** * * The survey-html-form plugin displays a set of `` from a HTML string. The type of input can be freely * chosen, for a list of possible input types see the [MDN page on inputs](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input). * The participant provides answers to the input fields. * @author Jan Simson * @see {@link https://www.jspsych.org/latest/plugins/survey-html-form/ survey-html-form plugin documentation on jspsych.org} */ class SurveyHtmlFormPlugin implements JsPsychPlugin { static info = info; constructor(private jsPsych: JsPsych) {} trial(display_element: HTMLElement, trial: TrialType) { var html = ""; // show preamble text if (trial.preamble !== null) { html += '
' + trial.preamble + "
"; } // start form if (trial.autocomplete) { html += ''; } else { html += ''; } // add form HTML / input elements html += trial.html; // add submit button html += ''; html += ""; display_element.innerHTML = html; if (trial.autofocus !== "") { var focus_elements = display_element.querySelectorAll( "#" + trial.autofocus ); if (focus_elements.length === 0) { console.warn("No element found with id: " + trial.autofocus); } else if (focus_elements.length > 1) { console.warn('The id "' + trial.autofocus + '" is not unique so autofocus will not work.'); } else { focus_elements[0].focus(); } } display_element .querySelector("#jspsych-survey-html-form") .addEventListener("submit", (event) => { // don't submit form event.preventDefault(); // measure response time var endTime = performance.now(); var response_time = Math.round(endTime - startTime); var this_form = display_element.querySelector("#jspsych-survey-html-form"); var question_data = serializeArray(this_form); if (!trial.dataAsArray) { question_data = objectifyForm(question_data); } // save data var trialdata = { rt: response_time, response: question_data, }; // next trial this.jsPsych.finishTrial(trialdata); }); var startTime = performance.now(); /** * Serialize all form data into an array * @copyright (c) 2018 Chris Ferdinandi, MIT License, https://gomakethings.com * @param {Node} form The form to serialize * @return {String} The serialized form data */ function serializeArray(form) { // Setup our serialized data var serialized = []; // Loop through each field in the form for (var i = 0; i < form.elements.length; i++) { var field = form.elements[i]; // Don't serialize fields without a name, submits, buttons, file and reset inputs, and disabled fields if ( !field.name || field.disabled || field.type === "file" || field.type === "reset" || field.type === "submit" || field.type === "button" ) continue; // If a multi-select, get all selections if (field.type === "select-multiple") { for (var n = 0; n < field.options.length; n++) { if (!field.options[n].selected) continue; serialized.push({ name: field.name, value: field.options[n].value, }); } } // Convert field data to a query string else if ((field.type !== "checkbox" && field.type !== "radio") || field.checked) { serialized.push({ name: field.name, value: field.value, }); } } return serialized; } // from https://stackoverflow.com/questions/1184624/convert-form-data-to-javascript-object-with-jquery function objectifyForm(formArray) { //serialize data function var returnArray = {}; for (var i = 0; i < formArray.length; i++) { returnArray[formArray[i]["name"]] = formArray[i]["value"]; } return returnArray; } } } export default SurveyHtmlFormPlugin;