mirror of
https://github.com/jspsych/jsPsych.git
synced 2025-05-10 11:10:54 +00:00
211 lines
6.8 KiB
TypeScript
211 lines
6.8 KiB
TypeScript
import { JsPsych, JsPsychPlugin, ParameterType, TrialType } from "jspsych";
|
|
|
|
import { version } from "../package.json";
|
|
|
|
const info = <const>{
|
|
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 <form> 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 `<inputs>` 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<Info> {
|
|
static info = info;
|
|
|
|
constructor(private jsPsych: JsPsych) {}
|
|
|
|
trial(display_element: HTMLElement, trial: TrialType<Info>) {
|
|
var html = "";
|
|
// show preamble text
|
|
if (trial.preamble !== null) {
|
|
html +=
|
|
'<div id="jspsych-survey-html-form-preamble" class="jspsych-survey-html-form-preamble">' +
|
|
trial.preamble +
|
|
"</div>";
|
|
}
|
|
// start form
|
|
if (trial.autocomplete) {
|
|
html += '<form id="jspsych-survey-html-form">';
|
|
} else {
|
|
html += '<form id="jspsych-survey-html-form" autocomplete="off">';
|
|
}
|
|
|
|
// add form HTML / input elements
|
|
html += trial.html;
|
|
|
|
// add submit button
|
|
html +=
|
|
'<input type="submit" id="jspsych-survey-html-form-next" class="jspsych-btn jspsych-survey-html-form" value="' +
|
|
trial.button_label +
|
|
'"></input>';
|
|
|
|
html += "</form>";
|
|
display_element.innerHTML = html;
|
|
|
|
if (trial.autofocus !== "") {
|
|
var focus_elements = display_element.querySelectorAll<HTMLInputElement>(
|
|
"#" + 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 = <any>{};
|
|
for (var i = 0; i < formArray.length; i++) {
|
|
returnArray[formArray[i]["name"]] = formArray[i]["value"];
|
|
}
|
|
return returnArray;
|
|
}
|
|
}
|
|
}
|
|
|
|
export default SurveyHtmlFormPlugin;
|