@jspsych/plugin-survey-multi-choice 2.0.1 → 2.1.0

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,7 +1,7 @@
1
1
  var jsPsychSurveyMultiChoice = (function (jspsych) {
2
2
  'use strict';
3
3
 
4
- var version = "2.0.1";
4
+ var version = "2.1.0";
5
5
 
6
6
  const info = {
7
7
  name: "survey-multi-choice",
@@ -92,8 +92,14 @@ var jsPsychSurveyMultiChoice = (function (jspsych) {
92
92
  type: jspsych.ParameterType.INT,
93
93
  array: true
94
94
  }
95
+ },
96
+ // prettier-ignore
97
+ citations: {
98
+ "apa": "de Leeuw, J. R., Gilbert, R. A., & Luchterhandt, B. (2023). jsPsych: Enabling an Open-Source Collaborative Ecosystem of Behavioral Experiments. Journal of Open Source Software, 8(85), 5351. https://doi.org/10.21105/joss.05351 ",
99
+ "bibtex": '@article{Leeuw2023jsPsych, author = {de Leeuw, Joshua R. and Gilbert, Rebecca A. and Luchterhandt, Bj{\\" o}rn}, journal = {Journal of Open Source Software}, doi = {10.21105/joss.05351}, issn = {2475-9066}, number = {85}, year = {2023}, month = {may 11}, pages = {5351}, publisher = {Open Journals}, title = {jsPsych: Enabling an {Open}-{Source} {Collaborative} {Ecosystem} of {Behavioral} {Experiments}}, url = {https://joss.theoj.org/papers/10.21105/joss.05351}, volume = {8}, } '
95
100
  }
96
101
  };
102
+ const plugin_id_name = "jspsych-survey-multi-choice";
97
103
  class SurveyMultiChoicePlugin {
98
104
  constructor(jsPsych) {
99
105
  this.jsPsych = jsPsych;
@@ -102,18 +108,24 @@ var jsPsychSurveyMultiChoice = (function (jspsych) {
102
108
  this.info = info;
103
109
  }
104
110
  trial(display_element, trial) {
105
- var plugin_id_name = "jspsych-survey-multi-choice";
111
+ const trial_form_id = `${plugin_id_name}_form`;
106
112
  var html = "";
107
- html += '<style id="jspsych-survey-multi-choice-css">';
108
- html += ".jspsych-survey-multi-choice-question { margin-top: 2em; margin-bottom: 2em; text-align: left; }.jspsych-survey-multi-choice-text span.required {color: darkred;}.jspsych-survey-multi-choice-horizontal .jspsych-survey-multi-choice-text { text-align: center;}.jspsych-survey-multi-choice-option { line-height: 2; }.jspsych-survey-multi-choice-horizontal .jspsych-survey-multi-choice-option { display: inline-block; margin-left: 1em; margin-right: 1em; vertical-align: top;}label.jspsych-survey-multi-choice-text input[type='radio'] {margin-right: 1em;}";
109
- html += "</style>";
113
+ html += `
114
+ <style id="${plugin_id_name}-css">
115
+ .${plugin_id_name}-question { margin-top: 2em; margin-bottom: 2em; text-align: left; }
116
+ .${plugin_id_name}-text span.required {color: darkred;}
117
+ .${plugin_id_name}-horizontal .${plugin_id_name}-text { text-align: center;}
118
+ .${plugin_id_name}-option { line-height: 2; }
119
+ .${plugin_id_name}-horizontal .${plugin_id_name}-option { display: inline-block; margin-left: 1em; margin-right: 1em; vertical-align: top;}
120
+ label.${plugin_id_name}-text input[type='radio'] {margin-right: 1em;}
121
+ </style>`;
110
122
  if (trial.preamble !== null) {
111
- html += '<div id="jspsych-survey-multi-choice-preamble" class="jspsych-survey-multi-choice-preamble">' + trial.preamble + "</div>";
123
+ html += `<div id="${plugin_id_name}-preamble" class="${plugin_id_name}-preamble">${trial.preamble}</div>`;
112
124
  }
113
125
  if (trial.autocomplete) {
114
- html += '<form id="jspsych-survey-multi-choice-form">';
126
+ html += `<form id="${trial_form_id}">`;
115
127
  } else {
116
- html += '<form id="jspsych-survey-multi-choice-form" autocomplete="off">';
128
+ html += `<form id="${trial_form_id}" autocomplete="off">`;
117
129
  }
118
130
  var question_order = [];
119
131
  for (var i = 0; i < trial.questions.length; i++) {
@@ -125,39 +137,42 @@ var jsPsychSurveyMultiChoice = (function (jspsych) {
125
137
  for (var i = 0; i < trial.questions.length; i++) {
126
138
  var question = trial.questions[question_order[i]];
127
139
  var question_id = question_order[i];
128
- var question_classes = ["jspsych-survey-multi-choice-question"];
140
+ var question_classes = [`${plugin_id_name}-question`];
129
141
  if (question.horizontal) {
130
- question_classes.push("jspsych-survey-multi-choice-horizontal");
142
+ question_classes.push(`${plugin_id_name}-horizontal`);
131
143
  }
132
- html += '<div id="jspsych-survey-multi-choice-' + question_id + '" class="' + question_classes.join(" ") + '" data-name="' + question.name + '">';
133
- html += '<p class="jspsych-survey-multi-choice-text survey-multi-choice">' + question.prompt;
144
+ html += `<div id="${plugin_id_name}-${question_id}" class="${question_classes.join(" ")}" data-name="${question.name}">`;
145
+ html += `<p class="${plugin_id_name}-text survey-multi-choice">${question.prompt}`;
134
146
  if (question.required) {
135
147
  html += "<span class='required'>*</span>";
136
148
  }
137
149
  html += "</p>";
138
150
  for (var j = 0; j < question.options.length; j++) {
139
- var option_id_name = "jspsych-survey-multi-choice-option-" + question_id + "-" + j;
140
- var input_name = "jspsych-survey-multi-choice-response-" + question_id;
141
- var input_id = "jspsych-survey-multi-choice-response-" + question_id + "-" + j;
151
+ var option_id_name = `${plugin_id_name}-option-${question_id}-${j}`;
152
+ var input_name = `${plugin_id_name}-response-${question_id}`;
153
+ var input_id = `${plugin_id_name}-response-${question_id}-${j}`;
142
154
  var required_attr = question.required ? "required" : "";
143
- html += '<div id="' + option_id_name + '" class="jspsych-survey-multi-choice-option">';
144
- html += '<label class="jspsych-survey-multi-choice-text" for="' + input_id + '">';
145
- html += '<input type="radio" name="' + input_name + '" id="' + input_id + '" value="' + question.options[j] + '" ' + required_attr + "></input>";
146
- html += question.options[j] + "</label>";
147
- html += "</div>";
155
+ html += `
156
+ <div id="${option_id_name}" class="${plugin_id_name}-option">
157
+ <label class="${plugin_id_name}-text" for="${input_id}">
158
+ <input type="radio" name="${input_name}" id="${input_id}" value="${question.options[j]}" ${required_attr} />
159
+ ${question.options[j]}
160
+ </label>
161
+ </div>`;
148
162
  }
149
163
  html += "</div>";
150
164
  }
151
- html += '<input type="submit" id="' + plugin_id_name + '-next" class="' + plugin_id_name + ' jspsych-btn"' + (trial.button_label ? ' value="' + trial.button_label + '"' : "") + "></input>";
165
+ html += `<input type="submit" id="${plugin_id_name}-next" class="${plugin_id_name} jspsych-btn"${trial.button_label ? ' value="' + trial.button_label + '"' : ""} />`;
152
166
  html += "</form>";
153
167
  display_element.innerHTML = html;
154
- document.querySelector("form").addEventListener("submit", (event) => {
168
+ const trial_form = display_element.querySelector(`#${trial_form_id}`);
169
+ trial_form.addEventListener("submit", (event) => {
155
170
  event.preventDefault();
156
171
  var endTime = performance.now();
157
172
  var response_time = Math.round(endTime - startTime);
158
173
  var question_data = {};
159
174
  for (var i2 = 0; i2 < trial.questions.length; i2++) {
160
- var match = display_element.querySelector("#jspsych-survey-multi-choice-" + i2);
175
+ var match = display_element.querySelector(`#${plugin_id_name}-${i2}`);
161
176
  var id = "Q" + i2;
162
177
  var val;
163
178
  if (match.querySelector("input[type=radio]:checked") !== null) {
@@ -221,7 +236,7 @@ var jsPsychSurveyMultiChoice = (function (jspsych) {
221
236
  for (let i = 0; i < answers.length; i++) {
222
237
  this.jsPsych.pluginAPI.clickTarget(
223
238
  display_element.querySelector(
224
- `#jspsych-survey-multi-choice-response-${i}-${trial.questions[i].options.indexOf(
239
+ `#${plugin_id_name}-response-${i}-${trial.questions[i].options.indexOf(
225
240
  answers[i][1]
226
241
  )}`
227
242
  ),
@@ -229,7 +244,7 @@ var jsPsychSurveyMultiChoice = (function (jspsych) {
229
244
  );
230
245
  }
231
246
  this.jsPsych.pluginAPI.clickTarget(
232
- display_element.querySelector("#jspsych-survey-multi-choice-next"),
247
+ display_element.querySelector(`#${plugin_id_name}-next`),
233
248
  data.rt
234
249
  );
235
250
  }
@@ -238,4 +253,4 @@ var jsPsychSurveyMultiChoice = (function (jspsych) {
238
253
  return SurveyMultiChoicePlugin;
239
254
 
240
255
  })(jsPsychModule);
241
- //# sourceMappingURL=https://unpkg.com/@jspsych/plugin-survey-multi-choice@2.0.1/dist/index.browser.js.map
256
+ //# sourceMappingURL=https://unpkg.com/@jspsych/plugin-survey-multi-choice@2.1.0/dist/index.browser.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.browser.js","sources":["../package.json","../src/index.ts"],"sourcesContent":["{\n \"name\": \"@jspsych/plugin-survey-multi-choice\",\n \"version\": \"2.0.1\",\n \"description\": \"a jspsych plugin for multiple choice survey questions\",\n \"type\": \"module\",\n \"main\": \"dist/index.cjs\",\n \"exports\": {\n \"import\": \"./dist/index.js\",\n \"require\": \"./dist/index.cjs\"\n },\n \"typings\": \"dist/index.d.ts\",\n \"unpkg\": \"dist/index.browser.min.js\",\n \"files\": [\n \"src\",\n \"dist\"\n ],\n \"source\": \"src/index.ts\",\n \"scripts\": {\n \"test\": \"jest\",\n \"test:watch\": \"npm test -- --watch\",\n \"tsc\": \"tsc\",\n \"build\": \"rollup --config\",\n \"build:watch\": \"npm run build -- --watch\"\n },\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/jspsych/jsPsych.git\",\n \"directory\": \"packages/plugin-survey-multi-choice\"\n },\n \"author\": \"Shane Martin\",\n \"license\": \"MIT\",\n \"bugs\": {\n \"url\": \"https://github.com/jspsych/jsPsych/issues\"\n },\n \"homepage\": \"https://www.jspsych.org/latest/plugins/survey-multi-choice\",\n \"peerDependencies\": {\n \"jspsych\": \">=7.1.0\"\n },\n \"devDependencies\": {\n \"@jspsych/config\": \"^3.1.1\",\n \"@jspsych/test-utils\": \"^1.2.0\"\n }\n}\n","import { JsPsych, JsPsychPlugin, ParameterType, TrialType } from \"jspsych\";\n\nimport { version } from \"../package.json\";\n\nconst info = <const>{\n name: \"survey-multi-choice\",\n version: version,\n parameters: {\n /**\n * An array of objects, each object represents a question that appears on the screen. Each object contains a prompt,\n * options, required, and horizontal parameter that will be applied to the question. See examples below for further\n * clarification.`prompt`: Type string, default value is *undefined*. The string is prompt/question that will be\n * associated with a group of options (radio buttons). All questions will get presented on the same page (trial).\n * `options`: Type array, defualt value is *undefined*. An array of strings. The array contains a set of options to\n * display for an individual question.`required`: Type boolean, default value is null. The boolean value indicates\n * if a question is required('true') or not ('false'), using the HTML5 `required` attribute. If this parameter is\n * undefined, the question will be optional. `horizontal`:Type boolean, default value is false. If true, then the\n * question is centered and the options are displayed horizontally. `name`: Name of the question. Used for storing\n * data. If left undefined then default names (`Q0`, `Q1`, `...`) will be used for the questions.\n */\n questions: {\n type: ParameterType.COMPLEX,\n array: true,\n nested: {\n /** Question prompt. */\n prompt: {\n type: ParameterType.HTML_STRING,\n default: undefined,\n },\n /** Array of multiple choice options for this question. */\n options: {\n type: ParameterType.STRING,\n array: true,\n default: undefined,\n },\n /** Whether or not a response to this question must be given in order to continue. */\n required: {\n type: ParameterType.BOOL,\n default: false,\n },\n /** If true, then the question will be centered and options will be displayed horizontally. */\n horizontal: {\n type: ParameterType.BOOL,\n default: false,\n },\n /** Name of the question in the trial data. If no name is given, the questions are named Q0, Q1, etc. */\n name: {\n type: ParameterType.STRING,\n default: \"\",\n },\n },\n },\n /**\n * If true, the display order of `questions` is randomly determined at the start of the trial. In the data object,\n * `Q0` will still refer to the first question in the array, regardless of where it was presented visually.\n */\n randomize_question_order: {\n type: ParameterType.BOOL,\n default: false,\n },\n /** HTML formatted string to display at the top of the page above all the questions. */\n preamble: {\n type: ParameterType.HTML_STRING,\n default: null,\n },\n /** Label of the button. */\n button_label: {\n type: ParameterType.STRING,\n default: \"Continue\",\n },\n /**\n * This determines whether or not all of the input elements on the page should allow autocomplete. Setting\n * this to true will enable autocomplete or auto-fill for the form.\n */\n autocomplete: {\n type: ParameterType.BOOL,\n default: false,\n },\n },\n data: {\n /** An object containing the response for each question. The object will have a separate key (variable) for each question, with the first question in the trial being recorded in `Q0`, the second in `Q1`, and so on. The responses are recorded as integers, representing the position selected on the likert scale for that question. If the `name` parameter is defined for the question, then the response object will use the value of `name` as the key for each question. This will be encoded as a JSON string when data is saved using the `.json()` or `.csv()` functions. */\n response: {\n type: ParameterType.OBJECT,\n },\n /** The response time in milliseconds for the participant to make a response. The time is measured from when the questions first appear on the screen until the participant's response(s) are submitted. */\n rt: {\n type: ParameterType.INT,\n },\n /** An array with the order of questions. For example `[2,0,1]` would indicate that the first question was `trial.questions[2]` (the third item in the `questions` parameter), the second question was `trial.questions[0]`, and the final question was `trial.questions[1]`. This will be encoded as a JSON string when data is saved using the `.json()` or `.csv()` functions. */\n question_order: {\n type: ParameterType.INT,\n array: true,\n },\n },\n};\n\ntype Info = typeof info;\n\n/**\n * **survey-multi-choice**\n *\n * The survey-multi-choice plugin displays a set of questions with multiple choice response fields. The participant selects a single answer.\n *\n * @author Shane Martin\n * @see {@link https://www.jspsych.org/latest/plugins/survey-multi-choice/ survey-multi-choice plugin documentation on jspsych.org}\n */\nclass SurveyMultiChoicePlugin implements JsPsychPlugin<Info> {\n static info = info;\n\n constructor(private jsPsych: JsPsych) {}\n\n trial(display_element: HTMLElement, trial: TrialType<Info>) {\n var plugin_id_name = \"jspsych-survey-multi-choice\";\n\n var html = \"\";\n\n // inject CSS for trial\n html += '<style id=\"jspsych-survey-multi-choice-css\">';\n html +=\n \".jspsych-survey-multi-choice-question { margin-top: 2em; margin-bottom: 2em; text-align: left; }\" +\n \".jspsych-survey-multi-choice-text span.required {color: darkred;}\" +\n \".jspsych-survey-multi-choice-horizontal .jspsych-survey-multi-choice-text { text-align: center;}\" +\n \".jspsych-survey-multi-choice-option { line-height: 2; }\" +\n \".jspsych-survey-multi-choice-horizontal .jspsych-survey-multi-choice-option { display: inline-block; margin-left: 1em; margin-right: 1em; vertical-align: top;}\" +\n \"label.jspsych-survey-multi-choice-text input[type='radio'] {margin-right: 1em;}\";\n html += \"</style>\";\n\n // show preamble text\n if (trial.preamble !== null) {\n html +=\n '<div id=\"jspsych-survey-multi-choice-preamble\" class=\"jspsych-survey-multi-choice-preamble\">' +\n trial.preamble +\n \"</div>\";\n }\n\n // form element\n if (trial.autocomplete) {\n html += '<form id=\"jspsych-survey-multi-choice-form\">';\n } else {\n html += '<form id=\"jspsych-survey-multi-choice-form\" autocomplete=\"off\">';\n }\n // generate question order. this is randomized here as opposed to randomizing the order of trial.questions\n // so that the data are always associated with the same question regardless of order\n var question_order = [];\n for (var i = 0; i < trial.questions.length; i++) {\n question_order.push(i);\n }\n if (trial.randomize_question_order) {\n question_order = this.jsPsych.randomization.shuffle(question_order);\n }\n\n // add multiple-choice questions\n for (var i = 0; i < trial.questions.length; i++) {\n // get question based on question_order\n var question = trial.questions[question_order[i]];\n var question_id = question_order[i];\n\n // create question container\n var question_classes = [\"jspsych-survey-multi-choice-question\"];\n if (question.horizontal) {\n question_classes.push(\"jspsych-survey-multi-choice-horizontal\");\n }\n\n html +=\n '<div id=\"jspsych-survey-multi-choice-' +\n question_id +\n '\" class=\"' +\n question_classes.join(\" \") +\n '\" data-name=\"' +\n question.name +\n '\">';\n\n // add question text\n html += '<p class=\"jspsych-survey-multi-choice-text survey-multi-choice\">' + question.prompt;\n if (question.required) {\n html += \"<span class='required'>*</span>\";\n }\n html += \"</p>\";\n\n // create option radio buttons\n for (var j = 0; j < question.options.length; j++) {\n // add label and question text\n var option_id_name = \"jspsych-survey-multi-choice-option-\" + question_id + \"-\" + j;\n var input_name = \"jspsych-survey-multi-choice-response-\" + question_id;\n var input_id = \"jspsych-survey-multi-choice-response-\" + question_id + \"-\" + j;\n\n var required_attr = question.required ? \"required\" : \"\";\n\n // add radio button container\n html += '<div id=\"' + option_id_name + '\" class=\"jspsych-survey-multi-choice-option\">';\n html += '<label class=\"jspsych-survey-multi-choice-text\" for=\"' + input_id + '\">';\n html +=\n '<input type=\"radio\" name=\"' +\n input_name +\n '\" id=\"' +\n input_id +\n '\" value=\"' +\n question.options[j] +\n '\" ' +\n required_attr +\n \"></input>\";\n html += question.options[j] + \"</label>\";\n html += \"</div>\";\n }\n\n html += \"</div>\";\n }\n\n // add submit button\n html +=\n '<input type=\"submit\" id=\"' +\n plugin_id_name +\n '-next\" class=\"' +\n plugin_id_name +\n ' jspsych-btn\"' +\n (trial.button_label ? ' value=\"' + trial.button_label + '\"' : \"\") +\n \"></input>\";\n html += \"</form>\";\n\n // render\n display_element.innerHTML = html;\n\n document.querySelector(\"form\").addEventListener(\"submit\", (event) => {\n event.preventDefault();\n // measure response time\n var endTime = performance.now();\n var response_time = Math.round(endTime - startTime);\n\n // create object to hold responses\n var question_data = {};\n for (var i = 0; i < trial.questions.length; i++) {\n var match = display_element.querySelector(\"#jspsych-survey-multi-choice-\" + i);\n var id = \"Q\" + i;\n var val: String;\n if (match.querySelector(\"input[type=radio]:checked\") !== null) {\n val = match.querySelector<HTMLInputElement>(\"input[type=radio]:checked\").value;\n } else {\n val = \"\";\n }\n var obje = {};\n var name = id;\n if (match.attributes[\"data-name\"].value !== \"\") {\n name = match.attributes[\"data-name\"].value;\n }\n obje[name] = val;\n Object.assign(question_data, obje);\n }\n // save data\n var trial_data = {\n rt: response_time,\n response: question_data,\n question_order: question_order,\n };\n\n // next trial\n this.jsPsych.finishTrial(trial_data);\n });\n\n var startTime = performance.now();\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 question_data = {};\n let rt = 1000;\n\n for (const q of trial.questions) {\n const name = q.name ? q.name : `Q${trial.questions.indexOf(q)}`;\n question_data[name] = this.jsPsych.randomization.sampleWithoutReplacement(q.options, 1)[0];\n rt += this.jsPsych.randomization.sampleExGaussian(1500, 400, 1 / 200, true);\n }\n\n const default_data = {\n response: question_data,\n rt: rt,\n question_order: trial.randomize_question_order\n ? this.jsPsych.randomization.shuffle([...Array(trial.questions.length).keys()])\n : [...Array(trial.questions.length).keys()],\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 this.trial(display_element, trial);\n load_callback();\n\n const answers = Object.entries(data.response);\n for (let i = 0; i < answers.length; i++) {\n this.jsPsych.pluginAPI.clickTarget(\n display_element.querySelector(\n `#jspsych-survey-multi-choice-response-${i}-${trial.questions[i].options.indexOf(\n answers[i][1]\n )}`\n ),\n ((data.rt - 1000) / answers.length) * (i + 1)\n );\n }\n\n this.jsPsych.pluginAPI.clickTarget(\n display_element.querySelector(\"#jspsych-survey-multi-choice-next\"),\n data.rt\n );\n }\n}\n\nexport default SurveyMultiChoicePlugin;\n"],"names":["ParameterType","i"],"mappings":"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"}
1
+ {"version":3,"file":"index.browser.js","sources":["../package.json","../src/index.ts"],"sourcesContent":["{\n \"name\": \"@jspsych/plugin-survey-multi-choice\",\n \"version\": \"2.1.0\",\n \"description\": \"a jspsych plugin for multiple choice survey questions\",\n \"type\": \"module\",\n \"main\": \"dist/index.cjs\",\n \"exports\": {\n \"import\": \"./dist/index.js\",\n \"require\": \"./dist/index.cjs\"\n },\n \"typings\": \"dist/index.d.ts\",\n \"unpkg\": \"dist/index.browser.min.js\",\n \"files\": [\n \"src\",\n \"dist\"\n ],\n \"source\": \"src/index.ts\",\n \"scripts\": {\n \"test\": \"jest\",\n \"test:watch\": \"npm test -- --watch\",\n \"tsc\": \"tsc\",\n \"build\": \"rollup --config\",\n \"build:watch\": \"npm run build -- --watch\"\n },\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/jspsych/jsPsych.git\",\n \"directory\": \"packages/plugin-survey-multi-choice\"\n },\n \"author\": \"Shane Martin\",\n \"license\": \"MIT\",\n \"bugs\": {\n \"url\": \"https://github.com/jspsych/jsPsych/issues\"\n },\n \"homepage\": \"https://www.jspsych.org/latest/plugins/survey-multi-choice\",\n \"peerDependencies\": {\n \"jspsych\": \">=7.1.0\"\n },\n \"devDependencies\": {\n \"@jspsych/config\": \"^3.2.0\",\n \"@jspsych/test-utils\": \"^1.2.0\"\n }\n}\n","import { JsPsych, JsPsychPlugin, ParameterType, TrialType } from \"jspsych\";\n\nimport { version } from \"../package.json\";\n\nconst info = <const>{\n name: \"survey-multi-choice\",\n version: version,\n parameters: {\n /**\n * An array of objects, each object represents a question that appears on the screen. Each object contains a prompt,\n * options, required, and horizontal parameter that will be applied to the question. See examples below for further\n * clarification.`prompt`: Type string, default value is *undefined*. The string is prompt/question that will be\n * associated with a group of options (radio buttons). All questions will get presented on the same page (trial).\n * `options`: Type array, defualt value is *undefined*. An array of strings. The array contains a set of options to\n * display for an individual question.`required`: Type boolean, default value is null. The boolean value indicates\n * if a question is required('true') or not ('false'), using the HTML5 `required` attribute. If this parameter is\n * undefined, the question will be optional. `horizontal`:Type boolean, default value is false. If true, then the\n * question is centered and the options are displayed horizontally. `name`: Name of the question. Used for storing\n * data. If left undefined then default names (`Q0`, `Q1`, `...`) will be used for the questions.\n */\n questions: {\n type: ParameterType.COMPLEX,\n array: true,\n nested: {\n /** Question prompt. */\n prompt: {\n type: ParameterType.HTML_STRING,\n default: undefined,\n },\n /** Array of multiple choice options for this question. */\n options: {\n type: ParameterType.STRING,\n array: true,\n default: undefined,\n },\n /** Whether or not a response to this question must be given in order to continue. */\n required: {\n type: ParameterType.BOOL,\n default: false,\n },\n /** If true, then the question will be centered and options will be displayed horizontally. */\n horizontal: {\n type: ParameterType.BOOL,\n default: false,\n },\n /** Name of the question in the trial data. If no name is given, the questions are named Q0, Q1, etc. */\n name: {\n type: ParameterType.STRING,\n default: \"\",\n },\n },\n },\n /**\n * If true, the display order of `questions` is randomly determined at the start of the trial. In the data object,\n * `Q0` will still refer to the first question in the array, regardless of where it was presented visually.\n */\n randomize_question_order: {\n type: ParameterType.BOOL,\n default: false,\n },\n /** HTML formatted string to display at the top of the page above all the questions. */\n preamble: {\n type: ParameterType.HTML_STRING,\n default: null,\n },\n /** Label of the button. */\n button_label: {\n type: ParameterType.STRING,\n default: \"Continue\",\n },\n /**\n * This determines whether or not all of the input elements on the page should allow autocomplete. Setting\n * this to true will enable autocomplete or auto-fill for the form.\n */\n autocomplete: {\n type: ParameterType.BOOL,\n default: false,\n },\n },\n data: {\n /** An object containing the response for each question. The object will have a separate key (variable) for each question, with the first question in the trial being recorded in `Q0`, the second in `Q1`, and so on. The responses are recorded as integers, representing the position selected on the likert scale for that question. If the `name` parameter is defined for the question, then the response object will use the value of `name` as the key for each question. This will be encoded as a JSON string when data is saved using the `.json()` or `.csv()` functions. */\n response: {\n type: ParameterType.OBJECT,\n },\n /** The response time in milliseconds for the participant to make a response. The time is measured from when the questions first appear on the screen until the participant's response(s) are submitted. */\n rt: {\n type: ParameterType.INT,\n },\n /** An array with the order of questions. For example `[2,0,1]` would indicate that the first question was `trial.questions[2]` (the third item in the `questions` parameter), the second question was `trial.questions[0]`, and the final question was `trial.questions[1]`. This will be encoded as a JSON string when data is saved using the `.json()` or `.csv()` functions. */\n question_order: {\n type: ParameterType.INT,\n array: true,\n },\n },\n // prettier-ignore\n citations: '__CITATIONS__',\n};\n\ntype Info = typeof info;\n\nconst plugin_id_name = \"jspsych-survey-multi-choice\";\n\n/**\n * **survey-multi-choice**\n *\n * The survey-multi-choice plugin displays a set of questions with multiple choice response fields. The participant selects a single answer.\n *\n * @author Shane Martin\n * @see {@link https://www.jspsych.org/latest/plugins/survey-multi-choice/ survey-multi-choice plugin documentation on jspsych.org}\n */\nclass SurveyMultiChoicePlugin implements JsPsychPlugin<Info> {\n static info = info;\n\n constructor(private jsPsych: JsPsych) { }\n\n trial(display_element: HTMLElement, trial: TrialType<Info>) {\n\n const trial_form_id = `${plugin_id_name}_form`;\n\n var html = \"\";\n\n // inject CSS for trial\n html += `\n <style id=\"${plugin_id_name}-css\">\n .${plugin_id_name}-question { margin-top: 2em; margin-bottom: 2em; text-align: left; }\n .${plugin_id_name}-text span.required {color: darkred;}\n .${plugin_id_name}-horizontal .${plugin_id_name}-text { text-align: center;}\n .${plugin_id_name}-option { line-height: 2; }\n .${plugin_id_name}-horizontal .${plugin_id_name}-option { display: inline-block; margin-left: 1em; margin-right: 1em; vertical-align: top;}\n label.${plugin_id_name}-text input[type='radio'] {margin-right: 1em;}\n </style>`;\n\n // show preamble text\n if (trial.preamble !== null) {\n html += `<div id=\"${plugin_id_name}-preamble\" class=\"${plugin_id_name}-preamble\">${trial.preamble}</div>`;\n }\n\n // form element\n if (trial.autocomplete) {\n html += `<form id=\"${trial_form_id}\">`;\n } else {\n html += `<form id=\"${trial_form_id}\" autocomplete=\"off\">`;\n }\n\n // generate question order. this is randomized here as opposed to randomizing the order of trial.questions\n // so that the data are always associated with the same question regardless of order\n var question_order = [];\n for (var i = 0; i < trial.questions.length; i++) {\n question_order.push(i);\n }\n if (trial.randomize_question_order) {\n question_order = this.jsPsych.randomization.shuffle(question_order);\n }\n\n // add multiple-choice questions\n for (var i = 0; i < trial.questions.length; i++) {\n // get question based on question_order\n var question = trial.questions[question_order[i]];\n var question_id = question_order[i];\n\n // create question container\n var question_classes = [`${plugin_id_name}-question`];\n if (question.horizontal) {\n question_classes.push(`${plugin_id_name}-horizontal`);\n }\n\n html += `<div id=\"${plugin_id_name}-${question_id}\" class=\"${question_classes.join(\" \")}\" data-name=\"${question.name}\">`;\n\n // add question text\n html += `<p class=\"${plugin_id_name}-text survey-multi-choice\">${question.prompt}`;\n if (question.required) {\n html += \"<span class='required'>*</span>\";\n }\n html += \"</p>\";\n\n // create option radio buttons\n for (var j = 0; j < question.options.length; j++) {\n // add label and question text\n var option_id_name = `${plugin_id_name}-option-${question_id}-${j}`;\n var input_name = `${plugin_id_name}-response-${question_id}`;\n var input_id = `${plugin_id_name}-response-${question_id}-${j}`;\n\n var required_attr = question.required ? \"required\" : \"\";\n\n // add radio button container\n html += `\n <div id=\"${option_id_name}\" class=\"${plugin_id_name}-option\">\n <label class=\"${plugin_id_name}-text\" for=\"${input_id}\">\n <input type=\"radio\" name=\"${input_name}\" id=\"${input_id}\" value=\"${question.options[j]}\" ${required_attr} />\n ${question.options[j]}\n </label>\n </div>`;\n }\n\n html += \"</div>\";\n }\n\n // add submit button\n html += `<input type=\"submit\" id=\"${plugin_id_name}-next\" class=\"${plugin_id_name} jspsych-btn\"${trial.button_label ? ' value=\"' + trial.button_label + '\"' : \"\"} />`;\n html += \"</form>\";\n\n // render\n display_element.innerHTML = html;\n\n const trial_form = display_element.querySelector<HTMLFormElement>(`#${trial_form_id}`);\n\n trial_form.addEventListener(\"submit\", (event) => {\n event.preventDefault();\n // measure response time\n var endTime = performance.now();\n var response_time = Math.round(endTime - startTime);\n\n // create object to hold responses\n var question_data = {};\n for (var i = 0; i < trial.questions.length; i++) {\n var match = display_element.querySelector(`#${plugin_id_name}-${i}`);\n var id = \"Q\" + i;\n var val: String;\n if (match.querySelector(\"input[type=radio]:checked\") !== null) {\n val = match.querySelector<HTMLInputElement>(\"input[type=radio]:checked\").value;\n } else {\n val = \"\";\n }\n var obje = {};\n var name = id;\n if (match.attributes[\"data-name\"].value !== \"\") {\n name = match.attributes[\"data-name\"].value;\n }\n obje[name] = val;\n Object.assign(question_data, obje);\n }\n // save data\n var trial_data = {\n rt: response_time,\n response: question_data,\n question_order: question_order,\n };\n\n // next trial\n this.jsPsych.finishTrial(trial_data);\n });\n\n var startTime = performance.now();\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 question_data = {};\n let rt = 1000;\n\n for (const q of trial.questions) {\n const name = q.name ? q.name : `Q${trial.questions.indexOf(q)}`;\n question_data[name] = this.jsPsych.randomization.sampleWithoutReplacement(q.options, 1)[0];\n rt += this.jsPsych.randomization.sampleExGaussian(1500, 400, 1 / 200, true);\n }\n\n const default_data = {\n response: question_data,\n rt: rt,\n question_order: trial.randomize_question_order\n ? this.jsPsych.randomization.shuffle([...Array(trial.questions.length).keys()])\n : [...Array(trial.questions.length).keys()],\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 this.trial(display_element, trial);\n load_callback();\n\n const answers = Object.entries(data.response);\n for (let i = 0; i < answers.length; i++) {\n this.jsPsych.pluginAPI.clickTarget(\n display_element.querySelector(\n `#${plugin_id_name}-response-${i}-${trial.questions[i].options.indexOf(\n answers[i][1]\n )}`\n ),\n ((data.rt - 1000) / answers.length) * (i + 1)\n );\n }\n\n this.jsPsych.pluginAPI.clickTarget(\n display_element.querySelector(`#${plugin_id_name}-next`),\n data.rt\n );\n }\n}\n\nexport default SurveyMultiChoicePlugin;\n"],"names":[],"mappings":";;;EAEE,IAAW,OAAA,GAAA,OAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IC6FA,SAAA,EAAA;EAAA;;KAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -1,2 +1,16 @@
1
- var jsPsychSurveyMultiChoice=function(a){"use strict";var P="2.0.1";const q={name:"survey-multi-choice",version:P,parameters:{questions:{type:a.ParameterType.COMPLEX,array:!0,nested:{prompt:{type:a.ParameterType.HTML_STRING,default:void 0},options:{type:a.ParameterType.STRING,array:!0,default:void 0},required:{type:a.ParameterType.BOOL,default:!1},horizontal:{type:a.ParameterType.BOOL,default:!1},name:{type:a.ParameterType.STRING,default:""}}},randomize_question_order:{type:a.ParameterType.BOOL,default:!1},preamble:{type:a.ParameterType.HTML_STRING,default:null},button_label:{type:a.ParameterType.STRING,default:"Continue"},autocomplete:{type:a.ParameterType.BOOL,default:!1}},data:{response:{type:a.ParameterType.OBJECT},rt:{type:a.ParameterType.INT},question_order:{type:a.ParameterType.INT,array:!0}}};class h{constructor(t){this.jsPsych=t}trial(t,i){var o="jspsych-survey-multi-choice",e="";e+='<style id="jspsych-survey-multi-choice-css">',e+=".jspsych-survey-multi-choice-question { margin-top: 2em; margin-bottom: 2em; text-align: left; }.jspsych-survey-multi-choice-text span.required {color: darkred;}.jspsych-survey-multi-choice-horizontal .jspsych-survey-multi-choice-text { text-align: center;}.jspsych-survey-multi-choice-option { line-height: 2; }.jspsych-survey-multi-choice-horizontal .jspsych-survey-multi-choice-option { display: inline-block; margin-left: 1em; margin-right: 1em; vertical-align: top;}label.jspsych-survey-multi-choice-text input[type='radio'] {margin-right: 1em;}",e+="</style>",i.preamble!==null&&(e+='<div id="jspsych-survey-multi-choice-preamble" class="jspsych-survey-multi-choice-preamble">'+i.preamble+"</div>"),i.autocomplete?e+='<form id="jspsych-survey-multi-choice-form">':e+='<form id="jspsych-survey-multi-choice-form" autocomplete="off">';for(var u=[],r=0;r<i.questions.length;r++)u.push(r);i.randomize_question_order&&(u=this.jsPsych.randomization.shuffle(u));for(var r=0;r<i.questions.length;r++){var s=i.questions[u[r]],n=u[r],p=["jspsych-survey-multi-choice-question"];s.horizontal&&p.push("jspsych-survey-multi-choice-horizontal"),e+='<div id="jspsych-survey-multi-choice-'+n+'" class="'+p.join(" ")+'" data-name="'+s.name+'">',e+='<p class="jspsych-survey-multi-choice-text survey-multi-choice">'+s.prompt,s.required&&(e+="<span class='required'>*</span>"),e+="</p>";for(var l=0;l<s.options.length;l++){var g="jspsych-survey-multi-choice-option-"+n+"-"+l,T="jspsych-survey-multi-choice-response-"+n,d="jspsych-survey-multi-choice-response-"+n+"-"+l,_=s.required?"required":"";e+='<div id="'+g+'" class="jspsych-survey-multi-choice-option">',e+='<label class="jspsych-survey-multi-choice-text" for="'+d+'">',e+='<input type="radio" name="'+T+'" id="'+d+'" value="'+s.options[l]+'" '+_+"></input>",e+=s.options[l]+"</label>",e+="</div>"}e+="</div>"}e+='<input type="submit" id="'+o+'-next" class="'+o+' jspsych-btn"'+(i.button_label?' value="'+i.button_label+'"':"")+"></input>",e+="</form>",t.innerHTML=e,document.querySelector("form").addEventListener("submit",S=>{S.preventDefault();for(var O=performance.now(),z=Math.round(O-b),v={},c=0;c<i.questions.length;c++){var y=t.querySelector("#jspsych-survey-multi-choice-"+c),x="Q"+c,m;y.querySelector("input[type=radio]:checked")!==null?m=y.querySelector("input[type=radio]:checked").value:m="";var f={},j=x;y.attributes["data-name"].value!==""&&(j=y.attributes["data-name"].value),f[j]=m,Object.assign(v,f)}var I={rt:z,response:v,question_order:u};this.jsPsych.finishTrial(I)});var b=performance.now()}simulate(t,i,o,e){i=="data-only"&&(e(),this.simulate_data_only(t,o)),i=="visual"&&this.simulate_visual(t,o,e)}create_simulation_data(t,i){const o={};let e=1e3;for(const s of t.questions){const n=s.name?s.name:`Q${t.questions.indexOf(s)}`;o[n]=this.jsPsych.randomization.sampleWithoutReplacement(s.options,1)[0],e+=this.jsPsych.randomization.sampleExGaussian(1500,400,.005,!0)}const u={response:o,rt:e,question_order:t.randomize_question_order?this.jsPsych.randomization.shuffle([...Array(t.questions.length).keys()]):[...Array(t.questions.length).keys()]},r=this.jsPsych.pluginAPI.mergeSimulationData(u,i);return this.jsPsych.pluginAPI.ensureSimulationDataConsistency(t,r),r}simulate_data_only(t,i){const o=this.create_simulation_data(t,i);this.jsPsych.finishTrial(o)}simulate_visual(t,i,o){const e=this.create_simulation_data(t,i),u=this.jsPsych.getDisplayElement();this.trial(u,t),o();const r=Object.entries(e.response);for(let s=0;s<r.length;s++)this.jsPsych.pluginAPI.clickTarget(u.querySelector(`#jspsych-survey-multi-choice-response-${s}-${t.questions[s].options.indexOf(r[s][1])}`),(e.rt-1e3)/r.length*(s+1));this.jsPsych.pluginAPI.clickTarget(u.querySelector("#jspsych-survey-multi-choice-next"),e.rt)}}return h.info=q,h}(jsPsychModule);
2
- //# sourceMappingURL=https://unpkg.com/@jspsych/plugin-survey-multi-choice@2.0.1/dist/index.browser.min.js.map
1
+ var jsPsychSurveyMultiChoice=function(n){"use strict";var b="2.1.0";const g={name:"survey-multi-choice",version:b,parameters:{questions:{type:n.ParameterType.COMPLEX,array:!0,nested:{prompt:{type:n.ParameterType.HTML_STRING,default:void 0},options:{type:n.ParameterType.STRING,array:!0,default:void 0},required:{type:n.ParameterType.BOOL,default:!1},horizontal:{type:n.ParameterType.BOOL,default:!1},name:{type:n.ParameterType.STRING,default:""}}},randomize_question_order:{type:n.ParameterType.BOOL,default:!1},preamble:{type:n.ParameterType.HTML_STRING,default:null},button_label:{type:n.ParameterType.STRING,default:"Continue"},autocomplete:{type:n.ParameterType.BOOL,default:!1}},data:{response:{type:n.ParameterType.OBJECT},rt:{type:n.ParameterType.INT},question_order:{type:n.ParameterType.INT,array:!0}},citations:{apa:"de Leeuw, J. R., Gilbert, R. A., & Luchterhandt, B. (2023). jsPsych: Enabling an Open-Source Collaborative Ecosystem of Behavioral Experiments. Journal of Open Source Software, 8(85), 5351. https://doi.org/10.21105/joss.05351 ",bibtex:'@article{Leeuw2023jsPsych, author = {de Leeuw, Joshua R. and Gilbert, Rebecca A. and Luchterhandt, Bj{\\" o}rn}, journal = {Journal of Open Source Software}, doi = {10.21105/joss.05351}, issn = {2475-9066}, number = {85}, year = {2023}, month = {may 11}, pages = {5351}, publisher = {Open Journals}, title = {jsPsych: Enabling an {Open}-{Source} {Collaborative} {Ecosystem} of {Behavioral} {Experiments}}, url = {https://joss.theoj.org/papers/10.21105/joss.05351}, volume = {8}, } '}},e="jspsych-survey-multi-choice";class h{constructor(a){this.jsPsych=a}trial(a,o){const s=`${e}_form`;var t="";t+=`
2
+ <style id="${e}-css">
3
+ .${e}-question { margin-top: 2em; margin-bottom: 2em; text-align: left; }
4
+ .${e}-text span.required {color: darkred;}
5
+ .${e}-horizontal .${e}-text { text-align: center;}
6
+ .${e}-option { line-height: 2; }
7
+ .${e}-horizontal .${e}-option { display: inline-block; margin-left: 1em; margin-right: 1em; vertical-align: top;}
8
+ label.${e}-text input[type='radio'] {margin-right: 1em;}
9
+ </style>`,o.preamble!==null&&(t+=`<div id="${e}-preamble" class="${e}-preamble">${o.preamble}</div>`),o.autocomplete?t+=`<form id="${s}">`:t+=`<form id="${s}" autocomplete="off">`;for(var l=[],i=0;i<o.questions.length;i++)l.push(i);o.randomize_question_order&&(l=this.jsPsych.randomization.shuffle(l));for(var i=0;i<o.questions.length;i++){var r=o.questions[l[i]],u=l[i],y=[`${e}-question`];r.horizontal&&y.push(`${e}-horizontal`),t+=`<div id="${e}-${u}" class="${y.join(" ")}" data-name="${r.name}">`,t+=`<p class="${e}-text survey-multi-choice">${r.prompt}`,r.required&&(t+="<span class='required'>*</span>"),t+="</p>";for(var p=0;p<r.options.length;p++){var q=`${e}-option-${u}-${p}`,T=`${e}-response-${u}`,$=`${e}-response-${u}-${p}`,_=r.required?"required":"";t+=`
10
+ <div id="${q}" class="${e}-option">
11
+ <label class="${e}-text" for="${$}">
12
+ <input type="radio" name="${T}" id="${$}" value="${r.options[p]}" ${_} />
13
+ ${r.options[p]}
14
+ </label>
15
+ </div>`}t+="</div>"}t+=`<input type="submit" id="${e}-next" class="${e} jspsych-btn"${o.button_label?' value="'+o.button_label+'"':""} />`,t+="</form>",a.innerHTML=t,a.querySelector(`#${s}`).addEventListener("submit",S=>{S.preventDefault();for(var j=performance.now(),x=Math.round(j-O),f={},m=0;m<o.questions.length;m++){var c=a.querySelector(`#${e}-${m}`),L="Q"+m,d;c.querySelector("input[type=radio]:checked")!==null?d=c.querySelector("input[type=radio]:checked").value:d="";var v={},P=L;c.attributes["data-name"].value!==""&&(P=c.attributes["data-name"].value),v[P]=d,Object.assign(f,v)}var z={rt:x,response:f,question_order:l};this.jsPsych.finishTrial(z)});var O=performance.now()}simulate(a,o,s,t){o=="data-only"&&(t(),this.simulate_data_only(a,s)),o=="visual"&&this.simulate_visual(a,s,t)}create_simulation_data(a,o){const s={};let t=1e3;for(const r of a.questions){const u=r.name?r.name:`Q${a.questions.indexOf(r)}`;s[u]=this.jsPsych.randomization.sampleWithoutReplacement(r.options,1)[0],t+=this.jsPsych.randomization.sampleExGaussian(1500,400,.005,!0)}const l={response:s,rt:t,question_order:a.randomize_question_order?this.jsPsych.randomization.shuffle([...Array(a.questions.length).keys()]):[...Array(a.questions.length).keys()]},i=this.jsPsych.pluginAPI.mergeSimulationData(l,o);return this.jsPsych.pluginAPI.ensureSimulationDataConsistency(a,i),i}simulate_data_only(a,o){const s=this.create_simulation_data(a,o);this.jsPsych.finishTrial(s)}simulate_visual(a,o,s){const t=this.create_simulation_data(a,o),l=this.jsPsych.getDisplayElement();this.trial(l,a),s();const i=Object.entries(t.response);for(let r=0;r<i.length;r++)this.jsPsych.pluginAPI.clickTarget(l.querySelector(`#${e}-response-${r}-${a.questions[r].options.indexOf(i[r][1])}`),(t.rt-1e3)/i.length*(r+1));this.jsPsych.pluginAPI.clickTarget(l.querySelector(`#${e}-next`),t.rt)}}return h.info=g,h}(jsPsychModule);
16
+ //# sourceMappingURL=https://unpkg.com/@jspsych/plugin-survey-multi-choice@2.1.0/dist/index.browser.min.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.browser.min.js","sources":["../package.json","../src/index.ts"],"sourcesContent":["{\n \"name\": \"@jspsych/plugin-survey-multi-choice\",\n \"version\": \"2.0.1\",\n \"description\": \"a jspsych plugin for multiple choice survey questions\",\n \"type\": \"module\",\n \"main\": \"dist/index.cjs\",\n \"exports\": {\n \"import\": \"./dist/index.js\",\n \"require\": \"./dist/index.cjs\"\n },\n \"typings\": \"dist/index.d.ts\",\n \"unpkg\": \"dist/index.browser.min.js\",\n \"files\": [\n \"src\",\n \"dist\"\n ],\n \"source\": \"src/index.ts\",\n \"scripts\": {\n \"test\": \"jest\",\n \"test:watch\": \"npm test -- --watch\",\n \"tsc\": \"tsc\",\n \"build\": \"rollup --config\",\n \"build:watch\": \"npm run build -- --watch\"\n },\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/jspsych/jsPsych.git\",\n \"directory\": \"packages/plugin-survey-multi-choice\"\n },\n \"author\": \"Shane Martin\",\n \"license\": \"MIT\",\n \"bugs\": {\n \"url\": \"https://github.com/jspsych/jsPsych/issues\"\n },\n \"homepage\": \"https://www.jspsych.org/latest/plugins/survey-multi-choice\",\n \"peerDependencies\": {\n \"jspsych\": \">=7.1.0\"\n },\n \"devDependencies\": {\n \"@jspsych/config\": \"^3.1.1\",\n \"@jspsych/test-utils\": \"^1.2.0\"\n }\n}\n","import { JsPsych, JsPsychPlugin, ParameterType, TrialType } from \"jspsych\";\n\nimport { version } from \"../package.json\";\n\nconst info = <const>{\n name: \"survey-multi-choice\",\n version: version,\n parameters: {\n /**\n * An array of objects, each object represents a question that appears on the screen. Each object contains a prompt,\n * options, required, and horizontal parameter that will be applied to the question. See examples below for further\n * clarification.`prompt`: Type string, default value is *undefined*. The string is prompt/question that will be\n * associated with a group of options (radio buttons). All questions will get presented on the same page (trial).\n * `options`: Type array, defualt value is *undefined*. An array of strings. The array contains a set of options to\n * display for an individual question.`required`: Type boolean, default value is null. The boolean value indicates\n * if a question is required('true') or not ('false'), using the HTML5 `required` attribute. If this parameter is\n * undefined, the question will be optional. `horizontal`:Type boolean, default value is false. If true, then the\n * question is centered and the options are displayed horizontally. `name`: Name of the question. Used for storing\n * data. If left undefined then default names (`Q0`, `Q1`, `...`) will be used for the questions.\n */\n questions: {\n type: ParameterType.COMPLEX,\n array: true,\n nested: {\n /** Question prompt. */\n prompt: {\n type: ParameterType.HTML_STRING,\n default: undefined,\n },\n /** Array of multiple choice options for this question. */\n options: {\n type: ParameterType.STRING,\n array: true,\n default: undefined,\n },\n /** Whether or not a response to this question must be given in order to continue. */\n required: {\n type: ParameterType.BOOL,\n default: false,\n },\n /** If true, then the question will be centered and options will be displayed horizontally. */\n horizontal: {\n type: ParameterType.BOOL,\n default: false,\n },\n /** Name of the question in the trial data. If no name is given, the questions are named Q0, Q1, etc. */\n name: {\n type: ParameterType.STRING,\n default: \"\",\n },\n },\n },\n /**\n * If true, the display order of `questions` is randomly determined at the start of the trial. In the data object,\n * `Q0` will still refer to the first question in the array, regardless of where it was presented visually.\n */\n randomize_question_order: {\n type: ParameterType.BOOL,\n default: false,\n },\n /** HTML formatted string to display at the top of the page above all the questions. */\n preamble: {\n type: ParameterType.HTML_STRING,\n default: null,\n },\n /** Label of the button. */\n button_label: {\n type: ParameterType.STRING,\n default: \"Continue\",\n },\n /**\n * This determines whether or not all of the input elements on the page should allow autocomplete. Setting\n * this to true will enable autocomplete or auto-fill for the form.\n */\n autocomplete: {\n type: ParameterType.BOOL,\n default: false,\n },\n },\n data: {\n /** An object containing the response for each question. The object will have a separate key (variable) for each question, with the first question in the trial being recorded in `Q0`, the second in `Q1`, and so on. The responses are recorded as integers, representing the position selected on the likert scale for that question. If the `name` parameter is defined for the question, then the response object will use the value of `name` as the key for each question. This will be encoded as a JSON string when data is saved using the `.json()` or `.csv()` functions. */\n response: {\n type: ParameterType.OBJECT,\n },\n /** The response time in milliseconds for the participant to make a response. The time is measured from when the questions first appear on the screen until the participant's response(s) are submitted. */\n rt: {\n type: ParameterType.INT,\n },\n /** An array with the order of questions. For example `[2,0,1]` would indicate that the first question was `trial.questions[2]` (the third item in the `questions` parameter), the second question was `trial.questions[0]`, and the final question was `trial.questions[1]`. This will be encoded as a JSON string when data is saved using the `.json()` or `.csv()` functions. */\n question_order: {\n type: ParameterType.INT,\n array: true,\n },\n },\n};\n\ntype Info = typeof info;\n\n/**\n * **survey-multi-choice**\n *\n * The survey-multi-choice plugin displays a set of questions with multiple choice response fields. The participant selects a single answer.\n *\n * @author Shane Martin\n * @see {@link https://www.jspsych.org/latest/plugins/survey-multi-choice/ survey-multi-choice plugin documentation on jspsych.org}\n */\nclass SurveyMultiChoicePlugin implements JsPsychPlugin<Info> {\n static info = info;\n\n constructor(private jsPsych: JsPsych) {}\n\n trial(display_element: HTMLElement, trial: TrialType<Info>) {\n var plugin_id_name = \"jspsych-survey-multi-choice\";\n\n var html = \"\";\n\n // inject CSS for trial\n html += '<style id=\"jspsych-survey-multi-choice-css\">';\n html +=\n \".jspsych-survey-multi-choice-question { margin-top: 2em; margin-bottom: 2em; text-align: left; }\" +\n \".jspsych-survey-multi-choice-text span.required {color: darkred;}\" +\n \".jspsych-survey-multi-choice-horizontal .jspsych-survey-multi-choice-text { text-align: center;}\" +\n \".jspsych-survey-multi-choice-option { line-height: 2; }\" +\n \".jspsych-survey-multi-choice-horizontal .jspsych-survey-multi-choice-option { display: inline-block; margin-left: 1em; margin-right: 1em; vertical-align: top;}\" +\n \"label.jspsych-survey-multi-choice-text input[type='radio'] {margin-right: 1em;}\";\n html += \"</style>\";\n\n // show preamble text\n if (trial.preamble !== null) {\n html +=\n '<div id=\"jspsych-survey-multi-choice-preamble\" class=\"jspsych-survey-multi-choice-preamble\">' +\n trial.preamble +\n \"</div>\";\n }\n\n // form element\n if (trial.autocomplete) {\n html += '<form id=\"jspsych-survey-multi-choice-form\">';\n } else {\n html += '<form id=\"jspsych-survey-multi-choice-form\" autocomplete=\"off\">';\n }\n // generate question order. this is randomized here as opposed to randomizing the order of trial.questions\n // so that the data are always associated with the same question regardless of order\n var question_order = [];\n for (var i = 0; i < trial.questions.length; i++) {\n question_order.push(i);\n }\n if (trial.randomize_question_order) {\n question_order = this.jsPsych.randomization.shuffle(question_order);\n }\n\n // add multiple-choice questions\n for (var i = 0; i < trial.questions.length; i++) {\n // get question based on question_order\n var question = trial.questions[question_order[i]];\n var question_id = question_order[i];\n\n // create question container\n var question_classes = [\"jspsych-survey-multi-choice-question\"];\n if (question.horizontal) {\n question_classes.push(\"jspsych-survey-multi-choice-horizontal\");\n }\n\n html +=\n '<div id=\"jspsych-survey-multi-choice-' +\n question_id +\n '\" class=\"' +\n question_classes.join(\" \") +\n '\" data-name=\"' +\n question.name +\n '\">';\n\n // add question text\n html += '<p class=\"jspsych-survey-multi-choice-text survey-multi-choice\">' + question.prompt;\n if (question.required) {\n html += \"<span class='required'>*</span>\";\n }\n html += \"</p>\";\n\n // create option radio buttons\n for (var j = 0; j < question.options.length; j++) {\n // add label and question text\n var option_id_name = \"jspsych-survey-multi-choice-option-\" + question_id + \"-\" + j;\n var input_name = \"jspsych-survey-multi-choice-response-\" + question_id;\n var input_id = \"jspsych-survey-multi-choice-response-\" + question_id + \"-\" + j;\n\n var required_attr = question.required ? \"required\" : \"\";\n\n // add radio button container\n html += '<div id=\"' + option_id_name + '\" class=\"jspsych-survey-multi-choice-option\">';\n html += '<label class=\"jspsych-survey-multi-choice-text\" for=\"' + input_id + '\">';\n html +=\n '<input type=\"radio\" name=\"' +\n input_name +\n '\" id=\"' +\n input_id +\n '\" value=\"' +\n question.options[j] +\n '\" ' +\n required_attr +\n \"></input>\";\n html += question.options[j] + \"</label>\";\n html += \"</div>\";\n }\n\n html += \"</div>\";\n }\n\n // add submit button\n html +=\n '<input type=\"submit\" id=\"' +\n plugin_id_name +\n '-next\" class=\"' +\n plugin_id_name +\n ' jspsych-btn\"' +\n (trial.button_label ? ' value=\"' + trial.button_label + '\"' : \"\") +\n \"></input>\";\n html += \"</form>\";\n\n // render\n display_element.innerHTML = html;\n\n document.querySelector(\"form\").addEventListener(\"submit\", (event) => {\n event.preventDefault();\n // measure response time\n var endTime = performance.now();\n var response_time = Math.round(endTime - startTime);\n\n // create object to hold responses\n var question_data = {};\n for (var i = 0; i < trial.questions.length; i++) {\n var match = display_element.querySelector(\"#jspsych-survey-multi-choice-\" + i);\n var id = \"Q\" + i;\n var val: String;\n if (match.querySelector(\"input[type=radio]:checked\") !== null) {\n val = match.querySelector<HTMLInputElement>(\"input[type=radio]:checked\").value;\n } else {\n val = \"\";\n }\n var obje = {};\n var name = id;\n if (match.attributes[\"data-name\"].value !== \"\") {\n name = match.attributes[\"data-name\"].value;\n }\n obje[name] = val;\n Object.assign(question_data, obje);\n }\n // save data\n var trial_data = {\n rt: response_time,\n response: question_data,\n question_order: question_order,\n };\n\n // next trial\n this.jsPsych.finishTrial(trial_data);\n });\n\n var startTime = performance.now();\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 question_data = {};\n let rt = 1000;\n\n for (const q of trial.questions) {\n const name = q.name ? q.name : `Q${trial.questions.indexOf(q)}`;\n question_data[name] = this.jsPsych.randomization.sampleWithoutReplacement(q.options, 1)[0];\n rt += this.jsPsych.randomization.sampleExGaussian(1500, 400, 1 / 200, true);\n }\n\n const default_data = {\n response: question_data,\n rt: rt,\n question_order: trial.randomize_question_order\n ? this.jsPsych.randomization.shuffle([...Array(trial.questions.length).keys()])\n : [...Array(trial.questions.length).keys()],\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 this.trial(display_element, trial);\n load_callback();\n\n const answers = Object.entries(data.response);\n for (let i = 0; i < answers.length; i++) {\n this.jsPsych.pluginAPI.clickTarget(\n display_element.querySelector(\n `#jspsych-survey-multi-choice-response-${i}-${trial.questions[i].options.indexOf(\n answers[i][1]\n )}`\n ),\n ((data.rt - 1000) / answers.length) * (i + 1)\n );\n }\n\n this.jsPsych.pluginAPI.clickTarget(\n display_element.querySelector(\"#jspsych-survey-multi-choice-next\"),\n data.rt\n );\n }\n}\n\nexport default SurveyMultiChoicePlugin;\n"],"names":["version","info","ParameterType","SurveyMultiChoicePlugin","jsPsych","display_element","trial","plugin_id_name","html","question_order","i","question","question_id","question_classes","j","option_id_name","input_name","input_id","required_attr","event","endTime","response_time","startTime","question_data","match","id","val","obje","name","trial_data","simulation_mode","simulation_options","load_callback","rt","q","default_data","data","answers"],"mappings":"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"}
1
+ {"version":3,"file":"index.browser.min.js","sources":["../package.json","../src/index.ts"],"sourcesContent":["{\n \"name\": \"@jspsych/plugin-survey-multi-choice\",\n \"version\": \"2.1.0\",\n \"description\": \"a jspsych plugin for multiple choice survey questions\",\n \"type\": \"module\",\n \"main\": \"dist/index.cjs\",\n \"exports\": {\n \"import\": \"./dist/index.js\",\n \"require\": \"./dist/index.cjs\"\n },\n \"typings\": \"dist/index.d.ts\",\n \"unpkg\": \"dist/index.browser.min.js\",\n \"files\": [\n \"src\",\n \"dist\"\n ],\n \"source\": \"src/index.ts\",\n \"scripts\": {\n \"test\": \"jest\",\n \"test:watch\": \"npm test -- --watch\",\n \"tsc\": \"tsc\",\n \"build\": \"rollup --config\",\n \"build:watch\": \"npm run build -- --watch\"\n },\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/jspsych/jsPsych.git\",\n \"directory\": \"packages/plugin-survey-multi-choice\"\n },\n \"author\": \"Shane Martin\",\n \"license\": \"MIT\",\n \"bugs\": {\n \"url\": \"https://github.com/jspsych/jsPsych/issues\"\n },\n \"homepage\": \"https://www.jspsych.org/latest/plugins/survey-multi-choice\",\n \"peerDependencies\": {\n \"jspsych\": \">=7.1.0\"\n },\n \"devDependencies\": {\n \"@jspsych/config\": \"^3.2.0\",\n \"@jspsych/test-utils\": \"^1.2.0\"\n }\n}\n","import { JsPsych, JsPsychPlugin, ParameterType, TrialType } from \"jspsych\";\n\nimport { version } from \"../package.json\";\n\nconst info = <const>{\n name: \"survey-multi-choice\",\n version: version,\n parameters: {\n /**\n * An array of objects, each object represents a question that appears on the screen. Each object contains a prompt,\n * options, required, and horizontal parameter that will be applied to the question. See examples below for further\n * clarification.`prompt`: Type string, default value is *undefined*. The string is prompt/question that will be\n * associated with a group of options (radio buttons). All questions will get presented on the same page (trial).\n * `options`: Type array, defualt value is *undefined*. An array of strings. The array contains a set of options to\n * display for an individual question.`required`: Type boolean, default value is null. The boolean value indicates\n * if a question is required('true') or not ('false'), using the HTML5 `required` attribute. If this parameter is\n * undefined, the question will be optional. `horizontal`:Type boolean, default value is false. If true, then the\n * question is centered and the options are displayed horizontally. `name`: Name of the question. Used for storing\n * data. If left undefined then default names (`Q0`, `Q1`, `...`) will be used for the questions.\n */\n questions: {\n type: ParameterType.COMPLEX,\n array: true,\n nested: {\n /** Question prompt. */\n prompt: {\n type: ParameterType.HTML_STRING,\n default: undefined,\n },\n /** Array of multiple choice options for this question. */\n options: {\n type: ParameterType.STRING,\n array: true,\n default: undefined,\n },\n /** Whether or not a response to this question must be given in order to continue. */\n required: {\n type: ParameterType.BOOL,\n default: false,\n },\n /** If true, then the question will be centered and options will be displayed horizontally. */\n horizontal: {\n type: ParameterType.BOOL,\n default: false,\n },\n /** Name of the question in the trial data. If no name is given, the questions are named Q0, Q1, etc. */\n name: {\n type: ParameterType.STRING,\n default: \"\",\n },\n },\n },\n /**\n * If true, the display order of `questions` is randomly determined at the start of the trial. In the data object,\n * `Q0` will still refer to the first question in the array, regardless of where it was presented visually.\n */\n randomize_question_order: {\n type: ParameterType.BOOL,\n default: false,\n },\n /** HTML formatted string to display at the top of the page above all the questions. */\n preamble: {\n type: ParameterType.HTML_STRING,\n default: null,\n },\n /** Label of the button. */\n button_label: {\n type: ParameterType.STRING,\n default: \"Continue\",\n },\n /**\n * This determines whether or not all of the input elements on the page should allow autocomplete. Setting\n * this to true will enable autocomplete or auto-fill for the form.\n */\n autocomplete: {\n type: ParameterType.BOOL,\n default: false,\n },\n },\n data: {\n /** An object containing the response for each question. The object will have a separate key (variable) for each question, with the first question in the trial being recorded in `Q0`, the second in `Q1`, and so on. The responses are recorded as integers, representing the position selected on the likert scale for that question. If the `name` parameter is defined for the question, then the response object will use the value of `name` as the key for each question. This will be encoded as a JSON string when data is saved using the `.json()` or `.csv()` functions. */\n response: {\n type: ParameterType.OBJECT,\n },\n /** The response time in milliseconds for the participant to make a response. The time is measured from when the questions first appear on the screen until the participant's response(s) are submitted. */\n rt: {\n type: ParameterType.INT,\n },\n /** An array with the order of questions. For example `[2,0,1]` would indicate that the first question was `trial.questions[2]` (the third item in the `questions` parameter), the second question was `trial.questions[0]`, and the final question was `trial.questions[1]`. This will be encoded as a JSON string when data is saved using the `.json()` or `.csv()` functions. */\n question_order: {\n type: ParameterType.INT,\n array: true,\n },\n },\n // prettier-ignore\n citations: '__CITATIONS__',\n};\n\ntype Info = typeof info;\n\nconst plugin_id_name = \"jspsych-survey-multi-choice\";\n\n/**\n * **survey-multi-choice**\n *\n * The survey-multi-choice plugin displays a set of questions with multiple choice response fields. The participant selects a single answer.\n *\n * @author Shane Martin\n * @see {@link https://www.jspsych.org/latest/plugins/survey-multi-choice/ survey-multi-choice plugin documentation on jspsych.org}\n */\nclass SurveyMultiChoicePlugin implements JsPsychPlugin<Info> {\n static info = info;\n\n constructor(private jsPsych: JsPsych) { }\n\n trial(display_element: HTMLElement, trial: TrialType<Info>) {\n\n const trial_form_id = `${plugin_id_name}_form`;\n\n var html = \"\";\n\n // inject CSS for trial\n html += `\n <style id=\"${plugin_id_name}-css\">\n .${plugin_id_name}-question { margin-top: 2em; margin-bottom: 2em; text-align: left; }\n .${plugin_id_name}-text span.required {color: darkred;}\n .${plugin_id_name}-horizontal .${plugin_id_name}-text { text-align: center;}\n .${plugin_id_name}-option { line-height: 2; }\n .${plugin_id_name}-horizontal .${plugin_id_name}-option { display: inline-block; margin-left: 1em; margin-right: 1em; vertical-align: top;}\n label.${plugin_id_name}-text input[type='radio'] {margin-right: 1em;}\n </style>`;\n\n // show preamble text\n if (trial.preamble !== null) {\n html += `<div id=\"${plugin_id_name}-preamble\" class=\"${plugin_id_name}-preamble\">${trial.preamble}</div>`;\n }\n\n // form element\n if (trial.autocomplete) {\n html += `<form id=\"${trial_form_id}\">`;\n } else {\n html += `<form id=\"${trial_form_id}\" autocomplete=\"off\">`;\n }\n\n // generate question order. this is randomized here as opposed to randomizing the order of trial.questions\n // so that the data are always associated with the same question regardless of order\n var question_order = [];\n for (var i = 0; i < trial.questions.length; i++) {\n question_order.push(i);\n }\n if (trial.randomize_question_order) {\n question_order = this.jsPsych.randomization.shuffle(question_order);\n }\n\n // add multiple-choice questions\n for (var i = 0; i < trial.questions.length; i++) {\n // get question based on question_order\n var question = trial.questions[question_order[i]];\n var question_id = question_order[i];\n\n // create question container\n var question_classes = [`${plugin_id_name}-question`];\n if (question.horizontal) {\n question_classes.push(`${plugin_id_name}-horizontal`);\n }\n\n html += `<div id=\"${plugin_id_name}-${question_id}\" class=\"${question_classes.join(\" \")}\" data-name=\"${question.name}\">`;\n\n // add question text\n html += `<p class=\"${plugin_id_name}-text survey-multi-choice\">${question.prompt}`;\n if (question.required) {\n html += \"<span class='required'>*</span>\";\n }\n html += \"</p>\";\n\n // create option radio buttons\n for (var j = 0; j < question.options.length; j++) {\n // add label and question text\n var option_id_name = `${plugin_id_name}-option-${question_id}-${j}`;\n var input_name = `${plugin_id_name}-response-${question_id}`;\n var input_id = `${plugin_id_name}-response-${question_id}-${j}`;\n\n var required_attr = question.required ? \"required\" : \"\";\n\n // add radio button container\n html += `\n <div id=\"${option_id_name}\" class=\"${plugin_id_name}-option\">\n <label class=\"${plugin_id_name}-text\" for=\"${input_id}\">\n <input type=\"radio\" name=\"${input_name}\" id=\"${input_id}\" value=\"${question.options[j]}\" ${required_attr} />\n ${question.options[j]}\n </label>\n </div>`;\n }\n\n html += \"</div>\";\n }\n\n // add submit button\n html += `<input type=\"submit\" id=\"${plugin_id_name}-next\" class=\"${plugin_id_name} jspsych-btn\"${trial.button_label ? ' value=\"' + trial.button_label + '\"' : \"\"} />`;\n html += \"</form>\";\n\n // render\n display_element.innerHTML = html;\n\n const trial_form = display_element.querySelector<HTMLFormElement>(`#${trial_form_id}`);\n\n trial_form.addEventListener(\"submit\", (event) => {\n event.preventDefault();\n // measure response time\n var endTime = performance.now();\n var response_time = Math.round(endTime - startTime);\n\n // create object to hold responses\n var question_data = {};\n for (var i = 0; i < trial.questions.length; i++) {\n var match = display_element.querySelector(`#${plugin_id_name}-${i}`);\n var id = \"Q\" + i;\n var val: String;\n if (match.querySelector(\"input[type=radio]:checked\") !== null) {\n val = match.querySelector<HTMLInputElement>(\"input[type=radio]:checked\").value;\n } else {\n val = \"\";\n }\n var obje = {};\n var name = id;\n if (match.attributes[\"data-name\"].value !== \"\") {\n name = match.attributes[\"data-name\"].value;\n }\n obje[name] = val;\n Object.assign(question_data, obje);\n }\n // save data\n var trial_data = {\n rt: response_time,\n response: question_data,\n question_order: question_order,\n };\n\n // next trial\n this.jsPsych.finishTrial(trial_data);\n });\n\n var startTime = performance.now();\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 question_data = {};\n let rt = 1000;\n\n for (const q of trial.questions) {\n const name = q.name ? q.name : `Q${trial.questions.indexOf(q)}`;\n question_data[name] = this.jsPsych.randomization.sampleWithoutReplacement(q.options, 1)[0];\n rt += this.jsPsych.randomization.sampleExGaussian(1500, 400, 1 / 200, true);\n }\n\n const default_data = {\n response: question_data,\n rt: rt,\n question_order: trial.randomize_question_order\n ? this.jsPsych.randomization.shuffle([...Array(trial.questions.length).keys()])\n : [...Array(trial.questions.length).keys()],\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 this.trial(display_element, trial);\n load_callback();\n\n const answers = Object.entries(data.response);\n for (let i = 0; i < answers.length; i++) {\n this.jsPsych.pluginAPI.clickTarget(\n display_element.querySelector(\n `#${plugin_id_name}-response-${i}-${trial.questions[i].options.indexOf(\n answers[i][1]\n )}`\n ),\n ((data.rt - 1000) / answers.length) * (i + 1)\n );\n }\n\n this.jsPsych.pluginAPI.clickTarget(\n display_element.querySelector(`#${plugin_id_name}-next`),\n data.rt\n );\n }\n}\n\nexport default SurveyMultiChoicePlugin;\n"],"names":["version"],"mappings":"sDAEEA,IAAAA,EAAW,+uBC6FA,UAAA,iuBAAe;;;;;;;;;;;;;;"}
package/dist/index.cjs CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  var jspsych = require('jspsych');
4
4
 
5
- var version = "2.0.1";
5
+ var version = "2.1.0";
6
6
 
7
7
  const info = {
8
8
  name: "survey-multi-choice",
@@ -93,8 +93,14 @@ const info = {
93
93
  type: jspsych.ParameterType.INT,
94
94
  array: true
95
95
  }
96
+ },
97
+ // prettier-ignore
98
+ citations: {
99
+ "apa": "de Leeuw, J. R., Gilbert, R. A., & Luchterhandt, B. (2023). jsPsych: Enabling an Open-Source Collaborative Ecosystem of Behavioral Experiments. Journal of Open Source Software, 8(85), 5351. https://doi.org/10.21105/joss.05351 ",
100
+ "bibtex": '@article{Leeuw2023jsPsych, author = {de Leeuw, Joshua R. and Gilbert, Rebecca A. and Luchterhandt, Bj{\\" o}rn}, journal = {Journal of Open Source Software}, doi = {10.21105/joss.05351}, issn = {2475-9066}, number = {85}, year = {2023}, month = {may 11}, pages = {5351}, publisher = {Open Journals}, title = {jsPsych: Enabling an {Open}-{Source} {Collaborative} {Ecosystem} of {Behavioral} {Experiments}}, url = {https://joss.theoj.org/papers/10.21105/joss.05351}, volume = {8}, } '
96
101
  }
97
102
  };
103
+ const plugin_id_name = "jspsych-survey-multi-choice";
98
104
  class SurveyMultiChoicePlugin {
99
105
  constructor(jsPsych) {
100
106
  this.jsPsych = jsPsych;
@@ -103,18 +109,24 @@ class SurveyMultiChoicePlugin {
103
109
  this.info = info;
104
110
  }
105
111
  trial(display_element, trial) {
106
- var plugin_id_name = "jspsych-survey-multi-choice";
112
+ const trial_form_id = `${plugin_id_name}_form`;
107
113
  var html = "";
108
- html += '<style id="jspsych-survey-multi-choice-css">';
109
- html += ".jspsych-survey-multi-choice-question { margin-top: 2em; margin-bottom: 2em; text-align: left; }.jspsych-survey-multi-choice-text span.required {color: darkred;}.jspsych-survey-multi-choice-horizontal .jspsych-survey-multi-choice-text { text-align: center;}.jspsych-survey-multi-choice-option { line-height: 2; }.jspsych-survey-multi-choice-horizontal .jspsych-survey-multi-choice-option { display: inline-block; margin-left: 1em; margin-right: 1em; vertical-align: top;}label.jspsych-survey-multi-choice-text input[type='radio'] {margin-right: 1em;}";
110
- html += "</style>";
114
+ html += `
115
+ <style id="${plugin_id_name}-css">
116
+ .${plugin_id_name}-question { margin-top: 2em; margin-bottom: 2em; text-align: left; }
117
+ .${plugin_id_name}-text span.required {color: darkred;}
118
+ .${plugin_id_name}-horizontal .${plugin_id_name}-text { text-align: center;}
119
+ .${plugin_id_name}-option { line-height: 2; }
120
+ .${plugin_id_name}-horizontal .${plugin_id_name}-option { display: inline-block; margin-left: 1em; margin-right: 1em; vertical-align: top;}
121
+ label.${plugin_id_name}-text input[type='radio'] {margin-right: 1em;}
122
+ </style>`;
111
123
  if (trial.preamble !== null) {
112
- html += '<div id="jspsych-survey-multi-choice-preamble" class="jspsych-survey-multi-choice-preamble">' + trial.preamble + "</div>";
124
+ html += `<div id="${plugin_id_name}-preamble" class="${plugin_id_name}-preamble">${trial.preamble}</div>`;
113
125
  }
114
126
  if (trial.autocomplete) {
115
- html += '<form id="jspsych-survey-multi-choice-form">';
127
+ html += `<form id="${trial_form_id}">`;
116
128
  } else {
117
- html += '<form id="jspsych-survey-multi-choice-form" autocomplete="off">';
129
+ html += `<form id="${trial_form_id}" autocomplete="off">`;
118
130
  }
119
131
  var question_order = [];
120
132
  for (var i = 0; i < trial.questions.length; i++) {
@@ -126,39 +138,42 @@ class SurveyMultiChoicePlugin {
126
138
  for (var i = 0; i < trial.questions.length; i++) {
127
139
  var question = trial.questions[question_order[i]];
128
140
  var question_id = question_order[i];
129
- var question_classes = ["jspsych-survey-multi-choice-question"];
141
+ var question_classes = [`${plugin_id_name}-question`];
130
142
  if (question.horizontal) {
131
- question_classes.push("jspsych-survey-multi-choice-horizontal");
143
+ question_classes.push(`${plugin_id_name}-horizontal`);
132
144
  }
133
- html += '<div id="jspsych-survey-multi-choice-' + question_id + '" class="' + question_classes.join(" ") + '" data-name="' + question.name + '">';
134
- html += '<p class="jspsych-survey-multi-choice-text survey-multi-choice">' + question.prompt;
145
+ html += `<div id="${plugin_id_name}-${question_id}" class="${question_classes.join(" ")}" data-name="${question.name}">`;
146
+ html += `<p class="${plugin_id_name}-text survey-multi-choice">${question.prompt}`;
135
147
  if (question.required) {
136
148
  html += "<span class='required'>*</span>";
137
149
  }
138
150
  html += "</p>";
139
151
  for (var j = 0; j < question.options.length; j++) {
140
- var option_id_name = "jspsych-survey-multi-choice-option-" + question_id + "-" + j;
141
- var input_name = "jspsych-survey-multi-choice-response-" + question_id;
142
- var input_id = "jspsych-survey-multi-choice-response-" + question_id + "-" + j;
152
+ var option_id_name = `${plugin_id_name}-option-${question_id}-${j}`;
153
+ var input_name = `${plugin_id_name}-response-${question_id}`;
154
+ var input_id = `${plugin_id_name}-response-${question_id}-${j}`;
143
155
  var required_attr = question.required ? "required" : "";
144
- html += '<div id="' + option_id_name + '" class="jspsych-survey-multi-choice-option">';
145
- html += '<label class="jspsych-survey-multi-choice-text" for="' + input_id + '">';
146
- html += '<input type="radio" name="' + input_name + '" id="' + input_id + '" value="' + question.options[j] + '" ' + required_attr + "></input>";
147
- html += question.options[j] + "</label>";
148
- html += "</div>";
156
+ html += `
157
+ <div id="${option_id_name}" class="${plugin_id_name}-option">
158
+ <label class="${plugin_id_name}-text" for="${input_id}">
159
+ <input type="radio" name="${input_name}" id="${input_id}" value="${question.options[j]}" ${required_attr} />
160
+ ${question.options[j]}
161
+ </label>
162
+ </div>`;
149
163
  }
150
164
  html += "</div>";
151
165
  }
152
- html += '<input type="submit" id="' + plugin_id_name + '-next" class="' + plugin_id_name + ' jspsych-btn"' + (trial.button_label ? ' value="' + trial.button_label + '"' : "") + "></input>";
166
+ html += `<input type="submit" id="${plugin_id_name}-next" class="${plugin_id_name} jspsych-btn"${trial.button_label ? ' value="' + trial.button_label + '"' : ""} />`;
153
167
  html += "</form>";
154
168
  display_element.innerHTML = html;
155
- document.querySelector("form").addEventListener("submit", (event) => {
169
+ const trial_form = display_element.querySelector(`#${trial_form_id}`);
170
+ trial_form.addEventListener("submit", (event) => {
156
171
  event.preventDefault();
157
172
  var endTime = performance.now();
158
173
  var response_time = Math.round(endTime - startTime);
159
174
  var question_data = {};
160
175
  for (var i2 = 0; i2 < trial.questions.length; i2++) {
161
- var match = display_element.querySelector("#jspsych-survey-multi-choice-" + i2);
176
+ var match = display_element.querySelector(`#${plugin_id_name}-${i2}`);
162
177
  var id = "Q" + i2;
163
178
  var val;
164
179
  if (match.querySelector("input[type=radio]:checked") !== null) {
@@ -222,7 +237,7 @@ class SurveyMultiChoicePlugin {
222
237
  for (let i = 0; i < answers.length; i++) {
223
238
  this.jsPsych.pluginAPI.clickTarget(
224
239
  display_element.querySelector(
225
- `#jspsych-survey-multi-choice-response-${i}-${trial.questions[i].options.indexOf(
240
+ `#${plugin_id_name}-response-${i}-${trial.questions[i].options.indexOf(
226
241
  answers[i][1]
227
242
  )}`
228
243
  ),
@@ -230,7 +245,7 @@ class SurveyMultiChoicePlugin {
230
245
  );
231
246
  }
232
247
  this.jsPsych.pluginAPI.clickTarget(
233
- display_element.querySelector("#jspsych-survey-multi-choice-next"),
248
+ display_element.querySelector(`#${plugin_id_name}-next`),
234
249
  data.rt
235
250
  );
236
251
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","sources":["../package.json","../src/index.ts"],"sourcesContent":["{\n \"name\": \"@jspsych/plugin-survey-multi-choice\",\n \"version\": \"2.0.1\",\n \"description\": \"a jspsych plugin for multiple choice survey questions\",\n \"type\": \"module\",\n \"main\": \"dist/index.cjs\",\n \"exports\": {\n \"import\": \"./dist/index.js\",\n \"require\": \"./dist/index.cjs\"\n },\n \"typings\": \"dist/index.d.ts\",\n \"unpkg\": \"dist/index.browser.min.js\",\n \"files\": [\n \"src\",\n \"dist\"\n ],\n \"source\": \"src/index.ts\",\n \"scripts\": {\n \"test\": \"jest\",\n \"test:watch\": \"npm test -- --watch\",\n \"tsc\": \"tsc\",\n \"build\": \"rollup --config\",\n \"build:watch\": \"npm run build -- --watch\"\n },\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/jspsych/jsPsych.git\",\n \"directory\": \"packages/plugin-survey-multi-choice\"\n },\n \"author\": \"Shane Martin\",\n \"license\": \"MIT\",\n \"bugs\": {\n \"url\": \"https://github.com/jspsych/jsPsych/issues\"\n },\n \"homepage\": \"https://www.jspsych.org/latest/plugins/survey-multi-choice\",\n \"peerDependencies\": {\n \"jspsych\": \">=7.1.0\"\n },\n \"devDependencies\": {\n \"@jspsych/config\": \"^3.1.1\",\n \"@jspsych/test-utils\": \"^1.2.0\"\n }\n}\n","import { JsPsych, JsPsychPlugin, ParameterType, TrialType } from \"jspsych\";\n\nimport { version } from \"../package.json\";\n\nconst info = <const>{\n name: \"survey-multi-choice\",\n version: version,\n parameters: {\n /**\n * An array of objects, each object represents a question that appears on the screen. Each object contains a prompt,\n * options, required, and horizontal parameter that will be applied to the question. See examples below for further\n * clarification.`prompt`: Type string, default value is *undefined*. The string is prompt/question that will be\n * associated with a group of options (radio buttons). All questions will get presented on the same page (trial).\n * `options`: Type array, defualt value is *undefined*. An array of strings. The array contains a set of options to\n * display for an individual question.`required`: Type boolean, default value is null. The boolean value indicates\n * if a question is required('true') or not ('false'), using the HTML5 `required` attribute. If this parameter is\n * undefined, the question will be optional. `horizontal`:Type boolean, default value is false. If true, then the\n * question is centered and the options are displayed horizontally. `name`: Name of the question. Used for storing\n * data. If left undefined then default names (`Q0`, `Q1`, `...`) will be used for the questions.\n */\n questions: {\n type: ParameterType.COMPLEX,\n array: true,\n nested: {\n /** Question prompt. */\n prompt: {\n type: ParameterType.HTML_STRING,\n default: undefined,\n },\n /** Array of multiple choice options for this question. */\n options: {\n type: ParameterType.STRING,\n array: true,\n default: undefined,\n },\n /** Whether or not a response to this question must be given in order to continue. */\n required: {\n type: ParameterType.BOOL,\n default: false,\n },\n /** If true, then the question will be centered and options will be displayed horizontally. */\n horizontal: {\n type: ParameterType.BOOL,\n default: false,\n },\n /** Name of the question in the trial data. If no name is given, the questions are named Q0, Q1, etc. */\n name: {\n type: ParameterType.STRING,\n default: \"\",\n },\n },\n },\n /**\n * If true, the display order of `questions` is randomly determined at the start of the trial. In the data object,\n * `Q0` will still refer to the first question in the array, regardless of where it was presented visually.\n */\n randomize_question_order: {\n type: ParameterType.BOOL,\n default: false,\n },\n /** HTML formatted string to display at the top of the page above all the questions. */\n preamble: {\n type: ParameterType.HTML_STRING,\n default: null,\n },\n /** Label of the button. */\n button_label: {\n type: ParameterType.STRING,\n default: \"Continue\",\n },\n /**\n * This determines whether or not all of the input elements on the page should allow autocomplete. Setting\n * this to true will enable autocomplete or auto-fill for the form.\n */\n autocomplete: {\n type: ParameterType.BOOL,\n default: false,\n },\n },\n data: {\n /** An object containing the response for each question. The object will have a separate key (variable) for each question, with the first question in the trial being recorded in `Q0`, the second in `Q1`, and so on. The responses are recorded as integers, representing the position selected on the likert scale for that question. If the `name` parameter is defined for the question, then the response object will use the value of `name` as the key for each question. This will be encoded as a JSON string when data is saved using the `.json()` or `.csv()` functions. */\n response: {\n type: ParameterType.OBJECT,\n },\n /** The response time in milliseconds for the participant to make a response. The time is measured from when the questions first appear on the screen until the participant's response(s) are submitted. */\n rt: {\n type: ParameterType.INT,\n },\n /** An array with the order of questions. For example `[2,0,1]` would indicate that the first question was `trial.questions[2]` (the third item in the `questions` parameter), the second question was `trial.questions[0]`, and the final question was `trial.questions[1]`. This will be encoded as a JSON string when data is saved using the `.json()` or `.csv()` functions. */\n question_order: {\n type: ParameterType.INT,\n array: true,\n },\n },\n};\n\ntype Info = typeof info;\n\n/**\n * **survey-multi-choice**\n *\n * The survey-multi-choice plugin displays a set of questions with multiple choice response fields. The participant selects a single answer.\n *\n * @author Shane Martin\n * @see {@link https://www.jspsych.org/latest/plugins/survey-multi-choice/ survey-multi-choice plugin documentation on jspsych.org}\n */\nclass SurveyMultiChoicePlugin implements JsPsychPlugin<Info> {\n static info = info;\n\n constructor(private jsPsych: JsPsych) {}\n\n trial(display_element: HTMLElement, trial: TrialType<Info>) {\n var plugin_id_name = \"jspsych-survey-multi-choice\";\n\n var html = \"\";\n\n // inject CSS for trial\n html += '<style id=\"jspsych-survey-multi-choice-css\">';\n html +=\n \".jspsych-survey-multi-choice-question { margin-top: 2em; margin-bottom: 2em; text-align: left; }\" +\n \".jspsych-survey-multi-choice-text span.required {color: darkred;}\" +\n \".jspsych-survey-multi-choice-horizontal .jspsych-survey-multi-choice-text { text-align: center;}\" +\n \".jspsych-survey-multi-choice-option { line-height: 2; }\" +\n \".jspsych-survey-multi-choice-horizontal .jspsych-survey-multi-choice-option { display: inline-block; margin-left: 1em; margin-right: 1em; vertical-align: top;}\" +\n \"label.jspsych-survey-multi-choice-text input[type='radio'] {margin-right: 1em;}\";\n html += \"</style>\";\n\n // show preamble text\n if (trial.preamble !== null) {\n html +=\n '<div id=\"jspsych-survey-multi-choice-preamble\" class=\"jspsych-survey-multi-choice-preamble\">' +\n trial.preamble +\n \"</div>\";\n }\n\n // form element\n if (trial.autocomplete) {\n html += '<form id=\"jspsych-survey-multi-choice-form\">';\n } else {\n html += '<form id=\"jspsych-survey-multi-choice-form\" autocomplete=\"off\">';\n }\n // generate question order. this is randomized here as opposed to randomizing the order of trial.questions\n // so that the data are always associated with the same question regardless of order\n var question_order = [];\n for (var i = 0; i < trial.questions.length; i++) {\n question_order.push(i);\n }\n if (trial.randomize_question_order) {\n question_order = this.jsPsych.randomization.shuffle(question_order);\n }\n\n // add multiple-choice questions\n for (var i = 0; i < trial.questions.length; i++) {\n // get question based on question_order\n var question = trial.questions[question_order[i]];\n var question_id = question_order[i];\n\n // create question container\n var question_classes = [\"jspsych-survey-multi-choice-question\"];\n if (question.horizontal) {\n question_classes.push(\"jspsych-survey-multi-choice-horizontal\");\n }\n\n html +=\n '<div id=\"jspsych-survey-multi-choice-' +\n question_id +\n '\" class=\"' +\n question_classes.join(\" \") +\n '\" data-name=\"' +\n question.name +\n '\">';\n\n // add question text\n html += '<p class=\"jspsych-survey-multi-choice-text survey-multi-choice\">' + question.prompt;\n if (question.required) {\n html += \"<span class='required'>*</span>\";\n }\n html += \"</p>\";\n\n // create option radio buttons\n for (var j = 0; j < question.options.length; j++) {\n // add label and question text\n var option_id_name = \"jspsych-survey-multi-choice-option-\" + question_id + \"-\" + j;\n var input_name = \"jspsych-survey-multi-choice-response-\" + question_id;\n var input_id = \"jspsych-survey-multi-choice-response-\" + question_id + \"-\" + j;\n\n var required_attr = question.required ? \"required\" : \"\";\n\n // add radio button container\n html += '<div id=\"' + option_id_name + '\" class=\"jspsych-survey-multi-choice-option\">';\n html += '<label class=\"jspsych-survey-multi-choice-text\" for=\"' + input_id + '\">';\n html +=\n '<input type=\"radio\" name=\"' +\n input_name +\n '\" id=\"' +\n input_id +\n '\" value=\"' +\n question.options[j] +\n '\" ' +\n required_attr +\n \"></input>\";\n html += question.options[j] + \"</label>\";\n html += \"</div>\";\n }\n\n html += \"</div>\";\n }\n\n // add submit button\n html +=\n '<input type=\"submit\" id=\"' +\n plugin_id_name +\n '-next\" class=\"' +\n plugin_id_name +\n ' jspsych-btn\"' +\n (trial.button_label ? ' value=\"' + trial.button_label + '\"' : \"\") +\n \"></input>\";\n html += \"</form>\";\n\n // render\n display_element.innerHTML = html;\n\n document.querySelector(\"form\").addEventListener(\"submit\", (event) => {\n event.preventDefault();\n // measure response time\n var endTime = performance.now();\n var response_time = Math.round(endTime - startTime);\n\n // create object to hold responses\n var question_data = {};\n for (var i = 0; i < trial.questions.length; i++) {\n var match = display_element.querySelector(\"#jspsych-survey-multi-choice-\" + i);\n var id = \"Q\" + i;\n var val: String;\n if (match.querySelector(\"input[type=radio]:checked\") !== null) {\n val = match.querySelector<HTMLInputElement>(\"input[type=radio]:checked\").value;\n } else {\n val = \"\";\n }\n var obje = {};\n var name = id;\n if (match.attributes[\"data-name\"].value !== \"\") {\n name = match.attributes[\"data-name\"].value;\n }\n obje[name] = val;\n Object.assign(question_data, obje);\n }\n // save data\n var trial_data = {\n rt: response_time,\n response: question_data,\n question_order: question_order,\n };\n\n // next trial\n this.jsPsych.finishTrial(trial_data);\n });\n\n var startTime = performance.now();\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 question_data = {};\n let rt = 1000;\n\n for (const q of trial.questions) {\n const name = q.name ? q.name : `Q${trial.questions.indexOf(q)}`;\n question_data[name] = this.jsPsych.randomization.sampleWithoutReplacement(q.options, 1)[0];\n rt += this.jsPsych.randomization.sampleExGaussian(1500, 400, 1 / 200, true);\n }\n\n const default_data = {\n response: question_data,\n rt: rt,\n question_order: trial.randomize_question_order\n ? this.jsPsych.randomization.shuffle([...Array(trial.questions.length).keys()])\n : [...Array(trial.questions.length).keys()],\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 this.trial(display_element, trial);\n load_callback();\n\n const answers = Object.entries(data.response);\n for (let i = 0; i < answers.length; i++) {\n this.jsPsych.pluginAPI.clickTarget(\n display_element.querySelector(\n `#jspsych-survey-multi-choice-response-${i}-${trial.questions[i].options.indexOf(\n answers[i][1]\n )}`\n ),\n ((data.rt - 1000) / answers.length) * (i + 1)\n );\n }\n\n this.jsPsych.pluginAPI.clickTarget(\n display_element.querySelector(\"#jspsych-survey-multi-choice-next\"),\n data.rt\n );\n }\n}\n\nexport default SurveyMultiChoicePlugin;\n"],"names":["ParameterType","i"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","sources":["../package.json","../src/index.ts"],"sourcesContent":["{\n \"name\": \"@jspsych/plugin-survey-multi-choice\",\n \"version\": \"2.1.0\",\n \"description\": \"a jspsych plugin for multiple choice survey questions\",\n \"type\": \"module\",\n \"main\": \"dist/index.cjs\",\n \"exports\": {\n \"import\": \"./dist/index.js\",\n \"require\": \"./dist/index.cjs\"\n },\n \"typings\": \"dist/index.d.ts\",\n \"unpkg\": \"dist/index.browser.min.js\",\n \"files\": [\n \"src\",\n \"dist\"\n ],\n \"source\": \"src/index.ts\",\n \"scripts\": {\n \"test\": \"jest\",\n \"test:watch\": \"npm test -- --watch\",\n \"tsc\": \"tsc\",\n \"build\": \"rollup --config\",\n \"build:watch\": \"npm run build -- --watch\"\n },\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/jspsych/jsPsych.git\",\n \"directory\": \"packages/plugin-survey-multi-choice\"\n },\n \"author\": \"Shane Martin\",\n \"license\": \"MIT\",\n \"bugs\": {\n \"url\": \"https://github.com/jspsych/jsPsych/issues\"\n },\n \"homepage\": \"https://www.jspsych.org/latest/plugins/survey-multi-choice\",\n \"peerDependencies\": {\n \"jspsych\": \">=7.1.0\"\n },\n \"devDependencies\": {\n \"@jspsych/config\": \"^3.2.0\",\n \"@jspsych/test-utils\": \"^1.2.0\"\n }\n}\n","import { JsPsych, JsPsychPlugin, ParameterType, TrialType } from \"jspsych\";\n\nimport { version } from \"../package.json\";\n\nconst info = <const>{\n name: \"survey-multi-choice\",\n version: version,\n parameters: {\n /**\n * An array of objects, each object represents a question that appears on the screen. Each object contains a prompt,\n * options, required, and horizontal parameter that will be applied to the question. See examples below for further\n * clarification.`prompt`: Type string, default value is *undefined*. The string is prompt/question that will be\n * associated with a group of options (radio buttons). All questions will get presented on the same page (trial).\n * `options`: Type array, defualt value is *undefined*. An array of strings. The array contains a set of options to\n * display for an individual question.`required`: Type boolean, default value is null. The boolean value indicates\n * if a question is required('true') or not ('false'), using the HTML5 `required` attribute. If this parameter is\n * undefined, the question will be optional. `horizontal`:Type boolean, default value is false. If true, then the\n * question is centered and the options are displayed horizontally. `name`: Name of the question. Used for storing\n * data. If left undefined then default names (`Q0`, `Q1`, `...`) will be used for the questions.\n */\n questions: {\n type: ParameterType.COMPLEX,\n array: true,\n nested: {\n /** Question prompt. */\n prompt: {\n type: ParameterType.HTML_STRING,\n default: undefined,\n },\n /** Array of multiple choice options for this question. */\n options: {\n type: ParameterType.STRING,\n array: true,\n default: undefined,\n },\n /** Whether or not a response to this question must be given in order to continue. */\n required: {\n type: ParameterType.BOOL,\n default: false,\n },\n /** If true, then the question will be centered and options will be displayed horizontally. */\n horizontal: {\n type: ParameterType.BOOL,\n default: false,\n },\n /** Name of the question in the trial data. If no name is given, the questions are named Q0, Q1, etc. */\n name: {\n type: ParameterType.STRING,\n default: \"\",\n },\n },\n },\n /**\n * If true, the display order of `questions` is randomly determined at the start of the trial. In the data object,\n * `Q0` will still refer to the first question in the array, regardless of where it was presented visually.\n */\n randomize_question_order: {\n type: ParameterType.BOOL,\n default: false,\n },\n /** HTML formatted string to display at the top of the page above all the questions. */\n preamble: {\n type: ParameterType.HTML_STRING,\n default: null,\n },\n /** Label of the button. */\n button_label: {\n type: ParameterType.STRING,\n default: \"Continue\",\n },\n /**\n * This determines whether or not all of the input elements on the page should allow autocomplete. Setting\n * this to true will enable autocomplete or auto-fill for the form.\n */\n autocomplete: {\n type: ParameterType.BOOL,\n default: false,\n },\n },\n data: {\n /** An object containing the response for each question. The object will have a separate key (variable) for each question, with the first question in the trial being recorded in `Q0`, the second in `Q1`, and so on. The responses are recorded as integers, representing the position selected on the likert scale for that question. If the `name` parameter is defined for the question, then the response object will use the value of `name` as the key for each question. This will be encoded as a JSON string when data is saved using the `.json()` or `.csv()` functions. */\n response: {\n type: ParameterType.OBJECT,\n },\n /** The response time in milliseconds for the participant to make a response. The time is measured from when the questions first appear on the screen until the participant's response(s) are submitted. */\n rt: {\n type: ParameterType.INT,\n },\n /** An array with the order of questions. For example `[2,0,1]` would indicate that the first question was `trial.questions[2]` (the third item in the `questions` parameter), the second question was `trial.questions[0]`, and the final question was `trial.questions[1]`. This will be encoded as a JSON string when data is saved using the `.json()` or `.csv()` functions. */\n question_order: {\n type: ParameterType.INT,\n array: true,\n },\n },\n // prettier-ignore\n citations: '__CITATIONS__',\n};\n\ntype Info = typeof info;\n\nconst plugin_id_name = \"jspsych-survey-multi-choice\";\n\n/**\n * **survey-multi-choice**\n *\n * The survey-multi-choice plugin displays a set of questions with multiple choice response fields. The participant selects a single answer.\n *\n * @author Shane Martin\n * @see {@link https://www.jspsych.org/latest/plugins/survey-multi-choice/ survey-multi-choice plugin documentation on jspsych.org}\n */\nclass SurveyMultiChoicePlugin implements JsPsychPlugin<Info> {\n static info = info;\n\n constructor(private jsPsych: JsPsych) { }\n\n trial(display_element: HTMLElement, trial: TrialType<Info>) {\n\n const trial_form_id = `${plugin_id_name}_form`;\n\n var html = \"\";\n\n // inject CSS for trial\n html += `\n <style id=\"${plugin_id_name}-css\">\n .${plugin_id_name}-question { margin-top: 2em; margin-bottom: 2em; text-align: left; }\n .${plugin_id_name}-text span.required {color: darkred;}\n .${plugin_id_name}-horizontal .${plugin_id_name}-text { text-align: center;}\n .${plugin_id_name}-option { line-height: 2; }\n .${plugin_id_name}-horizontal .${plugin_id_name}-option { display: inline-block; margin-left: 1em; margin-right: 1em; vertical-align: top;}\n label.${plugin_id_name}-text input[type='radio'] {margin-right: 1em;}\n </style>`;\n\n // show preamble text\n if (trial.preamble !== null) {\n html += `<div id=\"${plugin_id_name}-preamble\" class=\"${plugin_id_name}-preamble\">${trial.preamble}</div>`;\n }\n\n // form element\n if (trial.autocomplete) {\n html += `<form id=\"${trial_form_id}\">`;\n } else {\n html += `<form id=\"${trial_form_id}\" autocomplete=\"off\">`;\n }\n\n // generate question order. this is randomized here as opposed to randomizing the order of trial.questions\n // so that the data are always associated with the same question regardless of order\n var question_order = [];\n for (var i = 0; i < trial.questions.length; i++) {\n question_order.push(i);\n }\n if (trial.randomize_question_order) {\n question_order = this.jsPsych.randomization.shuffle(question_order);\n }\n\n // add multiple-choice questions\n for (var i = 0; i < trial.questions.length; i++) {\n // get question based on question_order\n var question = trial.questions[question_order[i]];\n var question_id = question_order[i];\n\n // create question container\n var question_classes = [`${plugin_id_name}-question`];\n if (question.horizontal) {\n question_classes.push(`${plugin_id_name}-horizontal`);\n }\n\n html += `<div id=\"${plugin_id_name}-${question_id}\" class=\"${question_classes.join(\" \")}\" data-name=\"${question.name}\">`;\n\n // add question text\n html += `<p class=\"${plugin_id_name}-text survey-multi-choice\">${question.prompt}`;\n if (question.required) {\n html += \"<span class='required'>*</span>\";\n }\n html += \"</p>\";\n\n // create option radio buttons\n for (var j = 0; j < question.options.length; j++) {\n // add label and question text\n var option_id_name = `${plugin_id_name}-option-${question_id}-${j}`;\n var input_name = `${plugin_id_name}-response-${question_id}`;\n var input_id = `${plugin_id_name}-response-${question_id}-${j}`;\n\n var required_attr = question.required ? \"required\" : \"\";\n\n // add radio button container\n html += `\n <div id=\"${option_id_name}\" class=\"${plugin_id_name}-option\">\n <label class=\"${plugin_id_name}-text\" for=\"${input_id}\">\n <input type=\"radio\" name=\"${input_name}\" id=\"${input_id}\" value=\"${question.options[j]}\" ${required_attr} />\n ${question.options[j]}\n </label>\n </div>`;\n }\n\n html += \"</div>\";\n }\n\n // add submit button\n html += `<input type=\"submit\" id=\"${plugin_id_name}-next\" class=\"${plugin_id_name} jspsych-btn\"${trial.button_label ? ' value=\"' + trial.button_label + '\"' : \"\"} />`;\n html += \"</form>\";\n\n // render\n display_element.innerHTML = html;\n\n const trial_form = display_element.querySelector<HTMLFormElement>(`#${trial_form_id}`);\n\n trial_form.addEventListener(\"submit\", (event) => {\n event.preventDefault();\n // measure response time\n var endTime = performance.now();\n var response_time = Math.round(endTime - startTime);\n\n // create object to hold responses\n var question_data = {};\n for (var i = 0; i < trial.questions.length; i++) {\n var match = display_element.querySelector(`#${plugin_id_name}-${i}`);\n var id = \"Q\" + i;\n var val: String;\n if (match.querySelector(\"input[type=radio]:checked\") !== null) {\n val = match.querySelector<HTMLInputElement>(\"input[type=radio]:checked\").value;\n } else {\n val = \"\";\n }\n var obje = {};\n var name = id;\n if (match.attributes[\"data-name\"].value !== \"\") {\n name = match.attributes[\"data-name\"].value;\n }\n obje[name] = val;\n Object.assign(question_data, obje);\n }\n // save data\n var trial_data = {\n rt: response_time,\n response: question_data,\n question_order: question_order,\n };\n\n // next trial\n this.jsPsych.finishTrial(trial_data);\n });\n\n var startTime = performance.now();\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 question_data = {};\n let rt = 1000;\n\n for (const q of trial.questions) {\n const name = q.name ? q.name : `Q${trial.questions.indexOf(q)}`;\n question_data[name] = this.jsPsych.randomization.sampleWithoutReplacement(q.options, 1)[0];\n rt += this.jsPsych.randomization.sampleExGaussian(1500, 400, 1 / 200, true);\n }\n\n const default_data = {\n response: question_data,\n rt: rt,\n question_order: trial.randomize_question_order\n ? this.jsPsych.randomization.shuffle([...Array(trial.questions.length).keys()])\n : [...Array(trial.questions.length).keys()],\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 this.trial(display_element, trial);\n load_callback();\n\n const answers = Object.entries(data.response);\n for (let i = 0; i < answers.length; i++) {\n this.jsPsych.pluginAPI.clickTarget(\n display_element.querySelector(\n `#${plugin_id_name}-response-${i}-${trial.questions[i].options.indexOf(\n answers[i][1]\n )}`\n ),\n ((data.rt - 1000) / answers.length) * (i + 1)\n );\n }\n\n this.jsPsych.pluginAPI.clickTarget(\n display_element.querySelector(`#${plugin_id_name}-next`),\n data.rt\n );\n }\n}\n\nexport default SurveyMultiChoicePlugin;\n"],"names":[],"mappings":";;;;AAEE,IAAW,OAAA,GAAA,OAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EC6FA,SAAA,EAAA;AAAA;;GAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
package/dist/index.d.ts CHANGED
@@ -90,6 +90,7 @@ declare const info: {
90
90
  readonly array: true;
91
91
  };
92
92
  };
93
+ readonly citations: "__CITATIONS__";
93
94
  };
94
95
  type Info = typeof info;
95
96
  /**
@@ -192,6 +193,7 @@ declare class SurveyMultiChoicePlugin implements JsPsychPlugin<Info> {
192
193
  readonly array: true;
193
194
  };
194
195
  };
196
+ readonly citations: "__CITATIONS__";
195
197
  };
196
198
  constructor(jsPsych: JsPsych);
197
199
  trial(display_element: HTMLElement, trial: TrialType<Info>): void;
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { ParameterType } from 'jspsych';
2
2
 
3
- var version = "2.0.1";
3
+ var version = "2.1.0";
4
4
 
5
5
  const info = {
6
6
  name: "survey-multi-choice",
@@ -91,8 +91,14 @@ const info = {
91
91
  type: ParameterType.INT,
92
92
  array: true
93
93
  }
94
+ },
95
+ // prettier-ignore
96
+ citations: {
97
+ "apa": "de Leeuw, J. R., Gilbert, R. A., & Luchterhandt, B. (2023). jsPsych: Enabling an Open-Source Collaborative Ecosystem of Behavioral Experiments. Journal of Open Source Software, 8(85), 5351. https://doi.org/10.21105/joss.05351 ",
98
+ "bibtex": '@article{Leeuw2023jsPsych, author = {de Leeuw, Joshua R. and Gilbert, Rebecca A. and Luchterhandt, Bj{\\" o}rn}, journal = {Journal of Open Source Software}, doi = {10.21105/joss.05351}, issn = {2475-9066}, number = {85}, year = {2023}, month = {may 11}, pages = {5351}, publisher = {Open Journals}, title = {jsPsych: Enabling an {Open}-{Source} {Collaborative} {Ecosystem} of {Behavioral} {Experiments}}, url = {https://joss.theoj.org/papers/10.21105/joss.05351}, volume = {8}, } '
94
99
  }
95
100
  };
101
+ const plugin_id_name = "jspsych-survey-multi-choice";
96
102
  class SurveyMultiChoicePlugin {
97
103
  constructor(jsPsych) {
98
104
  this.jsPsych = jsPsych;
@@ -101,18 +107,24 @@ class SurveyMultiChoicePlugin {
101
107
  this.info = info;
102
108
  }
103
109
  trial(display_element, trial) {
104
- var plugin_id_name = "jspsych-survey-multi-choice";
110
+ const trial_form_id = `${plugin_id_name}_form`;
105
111
  var html = "";
106
- html += '<style id="jspsych-survey-multi-choice-css">';
107
- html += ".jspsych-survey-multi-choice-question { margin-top: 2em; margin-bottom: 2em; text-align: left; }.jspsych-survey-multi-choice-text span.required {color: darkred;}.jspsych-survey-multi-choice-horizontal .jspsych-survey-multi-choice-text { text-align: center;}.jspsych-survey-multi-choice-option { line-height: 2; }.jspsych-survey-multi-choice-horizontal .jspsych-survey-multi-choice-option { display: inline-block; margin-left: 1em; margin-right: 1em; vertical-align: top;}label.jspsych-survey-multi-choice-text input[type='radio'] {margin-right: 1em;}";
108
- html += "</style>";
112
+ html += `
113
+ <style id="${plugin_id_name}-css">
114
+ .${plugin_id_name}-question { margin-top: 2em; margin-bottom: 2em; text-align: left; }
115
+ .${plugin_id_name}-text span.required {color: darkred;}
116
+ .${plugin_id_name}-horizontal .${plugin_id_name}-text { text-align: center;}
117
+ .${plugin_id_name}-option { line-height: 2; }
118
+ .${plugin_id_name}-horizontal .${plugin_id_name}-option { display: inline-block; margin-left: 1em; margin-right: 1em; vertical-align: top;}
119
+ label.${plugin_id_name}-text input[type='radio'] {margin-right: 1em;}
120
+ </style>`;
109
121
  if (trial.preamble !== null) {
110
- html += '<div id="jspsych-survey-multi-choice-preamble" class="jspsych-survey-multi-choice-preamble">' + trial.preamble + "</div>";
122
+ html += `<div id="${plugin_id_name}-preamble" class="${plugin_id_name}-preamble">${trial.preamble}</div>`;
111
123
  }
112
124
  if (trial.autocomplete) {
113
- html += '<form id="jspsych-survey-multi-choice-form">';
125
+ html += `<form id="${trial_form_id}">`;
114
126
  } else {
115
- html += '<form id="jspsych-survey-multi-choice-form" autocomplete="off">';
127
+ html += `<form id="${trial_form_id}" autocomplete="off">`;
116
128
  }
117
129
  var question_order = [];
118
130
  for (var i = 0; i < trial.questions.length; i++) {
@@ -124,39 +136,42 @@ class SurveyMultiChoicePlugin {
124
136
  for (var i = 0; i < trial.questions.length; i++) {
125
137
  var question = trial.questions[question_order[i]];
126
138
  var question_id = question_order[i];
127
- var question_classes = ["jspsych-survey-multi-choice-question"];
139
+ var question_classes = [`${plugin_id_name}-question`];
128
140
  if (question.horizontal) {
129
- question_classes.push("jspsych-survey-multi-choice-horizontal");
141
+ question_classes.push(`${plugin_id_name}-horizontal`);
130
142
  }
131
- html += '<div id="jspsych-survey-multi-choice-' + question_id + '" class="' + question_classes.join(" ") + '" data-name="' + question.name + '">';
132
- html += '<p class="jspsych-survey-multi-choice-text survey-multi-choice">' + question.prompt;
143
+ html += `<div id="${plugin_id_name}-${question_id}" class="${question_classes.join(" ")}" data-name="${question.name}">`;
144
+ html += `<p class="${plugin_id_name}-text survey-multi-choice">${question.prompt}`;
133
145
  if (question.required) {
134
146
  html += "<span class='required'>*</span>";
135
147
  }
136
148
  html += "</p>";
137
149
  for (var j = 0; j < question.options.length; j++) {
138
- var option_id_name = "jspsych-survey-multi-choice-option-" + question_id + "-" + j;
139
- var input_name = "jspsych-survey-multi-choice-response-" + question_id;
140
- var input_id = "jspsych-survey-multi-choice-response-" + question_id + "-" + j;
150
+ var option_id_name = `${plugin_id_name}-option-${question_id}-${j}`;
151
+ var input_name = `${plugin_id_name}-response-${question_id}`;
152
+ var input_id = `${plugin_id_name}-response-${question_id}-${j}`;
141
153
  var required_attr = question.required ? "required" : "";
142
- html += '<div id="' + option_id_name + '" class="jspsych-survey-multi-choice-option">';
143
- html += '<label class="jspsych-survey-multi-choice-text" for="' + input_id + '">';
144
- html += '<input type="radio" name="' + input_name + '" id="' + input_id + '" value="' + question.options[j] + '" ' + required_attr + "></input>";
145
- html += question.options[j] + "</label>";
146
- html += "</div>";
154
+ html += `
155
+ <div id="${option_id_name}" class="${plugin_id_name}-option">
156
+ <label class="${plugin_id_name}-text" for="${input_id}">
157
+ <input type="radio" name="${input_name}" id="${input_id}" value="${question.options[j]}" ${required_attr} />
158
+ ${question.options[j]}
159
+ </label>
160
+ </div>`;
147
161
  }
148
162
  html += "</div>";
149
163
  }
150
- html += '<input type="submit" id="' + plugin_id_name + '-next" class="' + plugin_id_name + ' jspsych-btn"' + (trial.button_label ? ' value="' + trial.button_label + '"' : "") + "></input>";
164
+ html += `<input type="submit" id="${plugin_id_name}-next" class="${plugin_id_name} jspsych-btn"${trial.button_label ? ' value="' + trial.button_label + '"' : ""} />`;
151
165
  html += "</form>";
152
166
  display_element.innerHTML = html;
153
- document.querySelector("form").addEventListener("submit", (event) => {
167
+ const trial_form = display_element.querySelector(`#${trial_form_id}`);
168
+ trial_form.addEventListener("submit", (event) => {
154
169
  event.preventDefault();
155
170
  var endTime = performance.now();
156
171
  var response_time = Math.round(endTime - startTime);
157
172
  var question_data = {};
158
173
  for (var i2 = 0; i2 < trial.questions.length; i2++) {
159
- var match = display_element.querySelector("#jspsych-survey-multi-choice-" + i2);
174
+ var match = display_element.querySelector(`#${plugin_id_name}-${i2}`);
160
175
  var id = "Q" + i2;
161
176
  var val;
162
177
  if (match.querySelector("input[type=radio]:checked") !== null) {
@@ -220,7 +235,7 @@ class SurveyMultiChoicePlugin {
220
235
  for (let i = 0; i < answers.length; i++) {
221
236
  this.jsPsych.pluginAPI.clickTarget(
222
237
  display_element.querySelector(
223
- `#jspsych-survey-multi-choice-response-${i}-${trial.questions[i].options.indexOf(
238
+ `#${plugin_id_name}-response-${i}-${trial.questions[i].options.indexOf(
224
239
  answers[i][1]
225
240
  )}`
226
241
  ),
@@ -228,7 +243,7 @@ class SurveyMultiChoicePlugin {
228
243
  );
229
244
  }
230
245
  this.jsPsych.pluginAPI.clickTarget(
231
- display_element.querySelector("#jspsych-survey-multi-choice-next"),
246
+ display_element.querySelector(`#${plugin_id_name}-next`),
232
247
  data.rt
233
248
  );
234
249
  }
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../package.json","../src/index.ts"],"sourcesContent":["{\n \"name\": \"@jspsych/plugin-survey-multi-choice\",\n \"version\": \"2.0.1\",\n \"description\": \"a jspsych plugin for multiple choice survey questions\",\n \"type\": \"module\",\n \"main\": \"dist/index.cjs\",\n \"exports\": {\n \"import\": \"./dist/index.js\",\n \"require\": \"./dist/index.cjs\"\n },\n \"typings\": \"dist/index.d.ts\",\n \"unpkg\": \"dist/index.browser.min.js\",\n \"files\": [\n \"src\",\n \"dist\"\n ],\n \"source\": \"src/index.ts\",\n \"scripts\": {\n \"test\": \"jest\",\n \"test:watch\": \"npm test -- --watch\",\n \"tsc\": \"tsc\",\n \"build\": \"rollup --config\",\n \"build:watch\": \"npm run build -- --watch\"\n },\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/jspsych/jsPsych.git\",\n \"directory\": \"packages/plugin-survey-multi-choice\"\n },\n \"author\": \"Shane Martin\",\n \"license\": \"MIT\",\n \"bugs\": {\n \"url\": \"https://github.com/jspsych/jsPsych/issues\"\n },\n \"homepage\": \"https://www.jspsych.org/latest/plugins/survey-multi-choice\",\n \"peerDependencies\": {\n \"jspsych\": \">=7.1.0\"\n },\n \"devDependencies\": {\n \"@jspsych/config\": \"^3.1.1\",\n \"@jspsych/test-utils\": \"^1.2.0\"\n }\n}\n","import { JsPsych, JsPsychPlugin, ParameterType, TrialType } from \"jspsych\";\n\nimport { version } from \"../package.json\";\n\nconst info = <const>{\n name: \"survey-multi-choice\",\n version: version,\n parameters: {\n /**\n * An array of objects, each object represents a question that appears on the screen. Each object contains a prompt,\n * options, required, and horizontal parameter that will be applied to the question. See examples below for further\n * clarification.`prompt`: Type string, default value is *undefined*. The string is prompt/question that will be\n * associated with a group of options (radio buttons). All questions will get presented on the same page (trial).\n * `options`: Type array, defualt value is *undefined*. An array of strings. The array contains a set of options to\n * display for an individual question.`required`: Type boolean, default value is null. The boolean value indicates\n * if a question is required('true') or not ('false'), using the HTML5 `required` attribute. If this parameter is\n * undefined, the question will be optional. `horizontal`:Type boolean, default value is false. If true, then the\n * question is centered and the options are displayed horizontally. `name`: Name of the question. Used for storing\n * data. If left undefined then default names (`Q0`, `Q1`, `...`) will be used for the questions.\n */\n questions: {\n type: ParameterType.COMPLEX,\n array: true,\n nested: {\n /** Question prompt. */\n prompt: {\n type: ParameterType.HTML_STRING,\n default: undefined,\n },\n /** Array of multiple choice options for this question. */\n options: {\n type: ParameterType.STRING,\n array: true,\n default: undefined,\n },\n /** Whether or not a response to this question must be given in order to continue. */\n required: {\n type: ParameterType.BOOL,\n default: false,\n },\n /** If true, then the question will be centered and options will be displayed horizontally. */\n horizontal: {\n type: ParameterType.BOOL,\n default: false,\n },\n /** Name of the question in the trial data. If no name is given, the questions are named Q0, Q1, etc. */\n name: {\n type: ParameterType.STRING,\n default: \"\",\n },\n },\n },\n /**\n * If true, the display order of `questions` is randomly determined at the start of the trial. In the data object,\n * `Q0` will still refer to the first question in the array, regardless of where it was presented visually.\n */\n randomize_question_order: {\n type: ParameterType.BOOL,\n default: false,\n },\n /** HTML formatted string to display at the top of the page above all the questions. */\n preamble: {\n type: ParameterType.HTML_STRING,\n default: null,\n },\n /** Label of the button. */\n button_label: {\n type: ParameterType.STRING,\n default: \"Continue\",\n },\n /**\n * This determines whether or not all of the input elements on the page should allow autocomplete. Setting\n * this to true will enable autocomplete or auto-fill for the form.\n */\n autocomplete: {\n type: ParameterType.BOOL,\n default: false,\n },\n },\n data: {\n /** An object containing the response for each question. The object will have a separate key (variable) for each question, with the first question in the trial being recorded in `Q0`, the second in `Q1`, and so on. The responses are recorded as integers, representing the position selected on the likert scale for that question. If the `name` parameter is defined for the question, then the response object will use the value of `name` as the key for each question. This will be encoded as a JSON string when data is saved using the `.json()` or `.csv()` functions. */\n response: {\n type: ParameterType.OBJECT,\n },\n /** The response time in milliseconds for the participant to make a response. The time is measured from when the questions first appear on the screen until the participant's response(s) are submitted. */\n rt: {\n type: ParameterType.INT,\n },\n /** An array with the order of questions. For example `[2,0,1]` would indicate that the first question was `trial.questions[2]` (the third item in the `questions` parameter), the second question was `trial.questions[0]`, and the final question was `trial.questions[1]`. This will be encoded as a JSON string when data is saved using the `.json()` or `.csv()` functions. */\n question_order: {\n type: ParameterType.INT,\n array: true,\n },\n },\n};\n\ntype Info = typeof info;\n\n/**\n * **survey-multi-choice**\n *\n * The survey-multi-choice plugin displays a set of questions with multiple choice response fields. The participant selects a single answer.\n *\n * @author Shane Martin\n * @see {@link https://www.jspsych.org/latest/plugins/survey-multi-choice/ survey-multi-choice plugin documentation on jspsych.org}\n */\nclass SurveyMultiChoicePlugin implements JsPsychPlugin<Info> {\n static info = info;\n\n constructor(private jsPsych: JsPsych) {}\n\n trial(display_element: HTMLElement, trial: TrialType<Info>) {\n var plugin_id_name = \"jspsych-survey-multi-choice\";\n\n var html = \"\";\n\n // inject CSS for trial\n html += '<style id=\"jspsych-survey-multi-choice-css\">';\n html +=\n \".jspsych-survey-multi-choice-question { margin-top: 2em; margin-bottom: 2em; text-align: left; }\" +\n \".jspsych-survey-multi-choice-text span.required {color: darkred;}\" +\n \".jspsych-survey-multi-choice-horizontal .jspsych-survey-multi-choice-text { text-align: center;}\" +\n \".jspsych-survey-multi-choice-option { line-height: 2; }\" +\n \".jspsych-survey-multi-choice-horizontal .jspsych-survey-multi-choice-option { display: inline-block; margin-left: 1em; margin-right: 1em; vertical-align: top;}\" +\n \"label.jspsych-survey-multi-choice-text input[type='radio'] {margin-right: 1em;}\";\n html += \"</style>\";\n\n // show preamble text\n if (trial.preamble !== null) {\n html +=\n '<div id=\"jspsych-survey-multi-choice-preamble\" class=\"jspsych-survey-multi-choice-preamble\">' +\n trial.preamble +\n \"</div>\";\n }\n\n // form element\n if (trial.autocomplete) {\n html += '<form id=\"jspsych-survey-multi-choice-form\">';\n } else {\n html += '<form id=\"jspsych-survey-multi-choice-form\" autocomplete=\"off\">';\n }\n // generate question order. this is randomized here as opposed to randomizing the order of trial.questions\n // so that the data are always associated with the same question regardless of order\n var question_order = [];\n for (var i = 0; i < trial.questions.length; i++) {\n question_order.push(i);\n }\n if (trial.randomize_question_order) {\n question_order = this.jsPsych.randomization.shuffle(question_order);\n }\n\n // add multiple-choice questions\n for (var i = 0; i < trial.questions.length; i++) {\n // get question based on question_order\n var question = trial.questions[question_order[i]];\n var question_id = question_order[i];\n\n // create question container\n var question_classes = [\"jspsych-survey-multi-choice-question\"];\n if (question.horizontal) {\n question_classes.push(\"jspsych-survey-multi-choice-horizontal\");\n }\n\n html +=\n '<div id=\"jspsych-survey-multi-choice-' +\n question_id +\n '\" class=\"' +\n question_classes.join(\" \") +\n '\" data-name=\"' +\n question.name +\n '\">';\n\n // add question text\n html += '<p class=\"jspsych-survey-multi-choice-text survey-multi-choice\">' + question.prompt;\n if (question.required) {\n html += \"<span class='required'>*</span>\";\n }\n html += \"</p>\";\n\n // create option radio buttons\n for (var j = 0; j < question.options.length; j++) {\n // add label and question text\n var option_id_name = \"jspsych-survey-multi-choice-option-\" + question_id + \"-\" + j;\n var input_name = \"jspsych-survey-multi-choice-response-\" + question_id;\n var input_id = \"jspsych-survey-multi-choice-response-\" + question_id + \"-\" + j;\n\n var required_attr = question.required ? \"required\" : \"\";\n\n // add radio button container\n html += '<div id=\"' + option_id_name + '\" class=\"jspsych-survey-multi-choice-option\">';\n html += '<label class=\"jspsych-survey-multi-choice-text\" for=\"' + input_id + '\">';\n html +=\n '<input type=\"radio\" name=\"' +\n input_name +\n '\" id=\"' +\n input_id +\n '\" value=\"' +\n question.options[j] +\n '\" ' +\n required_attr +\n \"></input>\";\n html += question.options[j] + \"</label>\";\n html += \"</div>\";\n }\n\n html += \"</div>\";\n }\n\n // add submit button\n html +=\n '<input type=\"submit\" id=\"' +\n plugin_id_name +\n '-next\" class=\"' +\n plugin_id_name +\n ' jspsych-btn\"' +\n (trial.button_label ? ' value=\"' + trial.button_label + '\"' : \"\") +\n \"></input>\";\n html += \"</form>\";\n\n // render\n display_element.innerHTML = html;\n\n document.querySelector(\"form\").addEventListener(\"submit\", (event) => {\n event.preventDefault();\n // measure response time\n var endTime = performance.now();\n var response_time = Math.round(endTime - startTime);\n\n // create object to hold responses\n var question_data = {};\n for (var i = 0; i < trial.questions.length; i++) {\n var match = display_element.querySelector(\"#jspsych-survey-multi-choice-\" + i);\n var id = \"Q\" + i;\n var val: String;\n if (match.querySelector(\"input[type=radio]:checked\") !== null) {\n val = match.querySelector<HTMLInputElement>(\"input[type=radio]:checked\").value;\n } else {\n val = \"\";\n }\n var obje = {};\n var name = id;\n if (match.attributes[\"data-name\"].value !== \"\") {\n name = match.attributes[\"data-name\"].value;\n }\n obje[name] = val;\n Object.assign(question_data, obje);\n }\n // save data\n var trial_data = {\n rt: response_time,\n response: question_data,\n question_order: question_order,\n };\n\n // next trial\n this.jsPsych.finishTrial(trial_data);\n });\n\n var startTime = performance.now();\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 question_data = {};\n let rt = 1000;\n\n for (const q of trial.questions) {\n const name = q.name ? q.name : `Q${trial.questions.indexOf(q)}`;\n question_data[name] = this.jsPsych.randomization.sampleWithoutReplacement(q.options, 1)[0];\n rt += this.jsPsych.randomization.sampleExGaussian(1500, 400, 1 / 200, true);\n }\n\n const default_data = {\n response: question_data,\n rt: rt,\n question_order: trial.randomize_question_order\n ? this.jsPsych.randomization.shuffle([...Array(trial.questions.length).keys()])\n : [...Array(trial.questions.length).keys()],\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 this.trial(display_element, trial);\n load_callback();\n\n const answers = Object.entries(data.response);\n for (let i = 0; i < answers.length; i++) {\n this.jsPsych.pluginAPI.clickTarget(\n display_element.querySelector(\n `#jspsych-survey-multi-choice-response-${i}-${trial.questions[i].options.indexOf(\n answers[i][1]\n )}`\n ),\n ((data.rt - 1000) / answers.length) * (i + 1)\n );\n }\n\n this.jsPsych.pluginAPI.clickTarget(\n display_element.querySelector(\"#jspsych-survey-multi-choice-next\"),\n data.rt\n );\n }\n}\n\nexport default SurveyMultiChoicePlugin;\n"],"names":["i"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../package.json","../src/index.ts"],"sourcesContent":["{\n \"name\": \"@jspsych/plugin-survey-multi-choice\",\n \"version\": \"2.1.0\",\n \"description\": \"a jspsych plugin for multiple choice survey questions\",\n \"type\": \"module\",\n \"main\": \"dist/index.cjs\",\n \"exports\": {\n \"import\": \"./dist/index.js\",\n \"require\": \"./dist/index.cjs\"\n },\n \"typings\": \"dist/index.d.ts\",\n \"unpkg\": \"dist/index.browser.min.js\",\n \"files\": [\n \"src\",\n \"dist\"\n ],\n \"source\": \"src/index.ts\",\n \"scripts\": {\n \"test\": \"jest\",\n \"test:watch\": \"npm test -- --watch\",\n \"tsc\": \"tsc\",\n \"build\": \"rollup --config\",\n \"build:watch\": \"npm run build -- --watch\"\n },\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/jspsych/jsPsych.git\",\n \"directory\": \"packages/plugin-survey-multi-choice\"\n },\n \"author\": \"Shane Martin\",\n \"license\": \"MIT\",\n \"bugs\": {\n \"url\": \"https://github.com/jspsych/jsPsych/issues\"\n },\n \"homepage\": \"https://www.jspsych.org/latest/plugins/survey-multi-choice\",\n \"peerDependencies\": {\n \"jspsych\": \">=7.1.0\"\n },\n \"devDependencies\": {\n \"@jspsych/config\": \"^3.2.0\",\n \"@jspsych/test-utils\": \"^1.2.0\"\n }\n}\n","import { JsPsych, JsPsychPlugin, ParameterType, TrialType } from \"jspsych\";\n\nimport { version } from \"../package.json\";\n\nconst info = <const>{\n name: \"survey-multi-choice\",\n version: version,\n parameters: {\n /**\n * An array of objects, each object represents a question that appears on the screen. Each object contains a prompt,\n * options, required, and horizontal parameter that will be applied to the question. See examples below for further\n * clarification.`prompt`: Type string, default value is *undefined*. The string is prompt/question that will be\n * associated with a group of options (radio buttons). All questions will get presented on the same page (trial).\n * `options`: Type array, defualt value is *undefined*. An array of strings. The array contains a set of options to\n * display for an individual question.`required`: Type boolean, default value is null. The boolean value indicates\n * if a question is required('true') or not ('false'), using the HTML5 `required` attribute. If this parameter is\n * undefined, the question will be optional. `horizontal`:Type boolean, default value is false. If true, then the\n * question is centered and the options are displayed horizontally. `name`: Name of the question. Used for storing\n * data. If left undefined then default names (`Q0`, `Q1`, `...`) will be used for the questions.\n */\n questions: {\n type: ParameterType.COMPLEX,\n array: true,\n nested: {\n /** Question prompt. */\n prompt: {\n type: ParameterType.HTML_STRING,\n default: undefined,\n },\n /** Array of multiple choice options for this question. */\n options: {\n type: ParameterType.STRING,\n array: true,\n default: undefined,\n },\n /** Whether or not a response to this question must be given in order to continue. */\n required: {\n type: ParameterType.BOOL,\n default: false,\n },\n /** If true, then the question will be centered and options will be displayed horizontally. */\n horizontal: {\n type: ParameterType.BOOL,\n default: false,\n },\n /** Name of the question in the trial data. If no name is given, the questions are named Q0, Q1, etc. */\n name: {\n type: ParameterType.STRING,\n default: \"\",\n },\n },\n },\n /**\n * If true, the display order of `questions` is randomly determined at the start of the trial. In the data object,\n * `Q0` will still refer to the first question in the array, regardless of where it was presented visually.\n */\n randomize_question_order: {\n type: ParameterType.BOOL,\n default: false,\n },\n /** HTML formatted string to display at the top of the page above all the questions. */\n preamble: {\n type: ParameterType.HTML_STRING,\n default: null,\n },\n /** Label of the button. */\n button_label: {\n type: ParameterType.STRING,\n default: \"Continue\",\n },\n /**\n * This determines whether or not all of the input elements on the page should allow autocomplete. Setting\n * this to true will enable autocomplete or auto-fill for the form.\n */\n autocomplete: {\n type: ParameterType.BOOL,\n default: false,\n },\n },\n data: {\n /** An object containing the response for each question. The object will have a separate key (variable) for each question, with the first question in the trial being recorded in `Q0`, the second in `Q1`, and so on. The responses are recorded as integers, representing the position selected on the likert scale for that question. If the `name` parameter is defined for the question, then the response object will use the value of `name` as the key for each question. This will be encoded as a JSON string when data is saved using the `.json()` or `.csv()` functions. */\n response: {\n type: ParameterType.OBJECT,\n },\n /** The response time in milliseconds for the participant to make a response. The time is measured from when the questions first appear on the screen until the participant's response(s) are submitted. */\n rt: {\n type: ParameterType.INT,\n },\n /** An array with the order of questions. For example `[2,0,1]` would indicate that the first question was `trial.questions[2]` (the third item in the `questions` parameter), the second question was `trial.questions[0]`, and the final question was `trial.questions[1]`. This will be encoded as a JSON string when data is saved using the `.json()` or `.csv()` functions. */\n question_order: {\n type: ParameterType.INT,\n array: true,\n },\n },\n // prettier-ignore\n citations: '__CITATIONS__',\n};\n\ntype Info = typeof info;\n\nconst plugin_id_name = \"jspsych-survey-multi-choice\";\n\n/**\n * **survey-multi-choice**\n *\n * The survey-multi-choice plugin displays a set of questions with multiple choice response fields. The participant selects a single answer.\n *\n * @author Shane Martin\n * @see {@link https://www.jspsych.org/latest/plugins/survey-multi-choice/ survey-multi-choice plugin documentation on jspsych.org}\n */\nclass SurveyMultiChoicePlugin implements JsPsychPlugin<Info> {\n static info = info;\n\n constructor(private jsPsych: JsPsych) { }\n\n trial(display_element: HTMLElement, trial: TrialType<Info>) {\n\n const trial_form_id = `${plugin_id_name}_form`;\n\n var html = \"\";\n\n // inject CSS for trial\n html += `\n <style id=\"${plugin_id_name}-css\">\n .${plugin_id_name}-question { margin-top: 2em; margin-bottom: 2em; text-align: left; }\n .${plugin_id_name}-text span.required {color: darkred;}\n .${plugin_id_name}-horizontal .${plugin_id_name}-text { text-align: center;}\n .${plugin_id_name}-option { line-height: 2; }\n .${plugin_id_name}-horizontal .${plugin_id_name}-option { display: inline-block; margin-left: 1em; margin-right: 1em; vertical-align: top;}\n label.${plugin_id_name}-text input[type='radio'] {margin-right: 1em;}\n </style>`;\n\n // show preamble text\n if (trial.preamble !== null) {\n html += `<div id=\"${plugin_id_name}-preamble\" class=\"${plugin_id_name}-preamble\">${trial.preamble}</div>`;\n }\n\n // form element\n if (trial.autocomplete) {\n html += `<form id=\"${trial_form_id}\">`;\n } else {\n html += `<form id=\"${trial_form_id}\" autocomplete=\"off\">`;\n }\n\n // generate question order. this is randomized here as opposed to randomizing the order of trial.questions\n // so that the data are always associated with the same question regardless of order\n var question_order = [];\n for (var i = 0; i < trial.questions.length; i++) {\n question_order.push(i);\n }\n if (trial.randomize_question_order) {\n question_order = this.jsPsych.randomization.shuffle(question_order);\n }\n\n // add multiple-choice questions\n for (var i = 0; i < trial.questions.length; i++) {\n // get question based on question_order\n var question = trial.questions[question_order[i]];\n var question_id = question_order[i];\n\n // create question container\n var question_classes = [`${plugin_id_name}-question`];\n if (question.horizontal) {\n question_classes.push(`${plugin_id_name}-horizontal`);\n }\n\n html += `<div id=\"${plugin_id_name}-${question_id}\" class=\"${question_classes.join(\" \")}\" data-name=\"${question.name}\">`;\n\n // add question text\n html += `<p class=\"${plugin_id_name}-text survey-multi-choice\">${question.prompt}`;\n if (question.required) {\n html += \"<span class='required'>*</span>\";\n }\n html += \"</p>\";\n\n // create option radio buttons\n for (var j = 0; j < question.options.length; j++) {\n // add label and question text\n var option_id_name = `${plugin_id_name}-option-${question_id}-${j}`;\n var input_name = `${plugin_id_name}-response-${question_id}`;\n var input_id = `${plugin_id_name}-response-${question_id}-${j}`;\n\n var required_attr = question.required ? \"required\" : \"\";\n\n // add radio button container\n html += `\n <div id=\"${option_id_name}\" class=\"${plugin_id_name}-option\">\n <label class=\"${plugin_id_name}-text\" for=\"${input_id}\">\n <input type=\"radio\" name=\"${input_name}\" id=\"${input_id}\" value=\"${question.options[j]}\" ${required_attr} />\n ${question.options[j]}\n </label>\n </div>`;\n }\n\n html += \"</div>\";\n }\n\n // add submit button\n html += `<input type=\"submit\" id=\"${plugin_id_name}-next\" class=\"${plugin_id_name} jspsych-btn\"${trial.button_label ? ' value=\"' + trial.button_label + '\"' : \"\"} />`;\n html += \"</form>\";\n\n // render\n display_element.innerHTML = html;\n\n const trial_form = display_element.querySelector<HTMLFormElement>(`#${trial_form_id}`);\n\n trial_form.addEventListener(\"submit\", (event) => {\n event.preventDefault();\n // measure response time\n var endTime = performance.now();\n var response_time = Math.round(endTime - startTime);\n\n // create object to hold responses\n var question_data = {};\n for (var i = 0; i < trial.questions.length; i++) {\n var match = display_element.querySelector(`#${plugin_id_name}-${i}`);\n var id = \"Q\" + i;\n var val: String;\n if (match.querySelector(\"input[type=radio]:checked\") !== null) {\n val = match.querySelector<HTMLInputElement>(\"input[type=radio]:checked\").value;\n } else {\n val = \"\";\n }\n var obje = {};\n var name = id;\n if (match.attributes[\"data-name\"].value !== \"\") {\n name = match.attributes[\"data-name\"].value;\n }\n obje[name] = val;\n Object.assign(question_data, obje);\n }\n // save data\n var trial_data = {\n rt: response_time,\n response: question_data,\n question_order: question_order,\n };\n\n // next trial\n this.jsPsych.finishTrial(trial_data);\n });\n\n var startTime = performance.now();\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 question_data = {};\n let rt = 1000;\n\n for (const q of trial.questions) {\n const name = q.name ? q.name : `Q${trial.questions.indexOf(q)}`;\n question_data[name] = this.jsPsych.randomization.sampleWithoutReplacement(q.options, 1)[0];\n rt += this.jsPsych.randomization.sampleExGaussian(1500, 400, 1 / 200, true);\n }\n\n const default_data = {\n response: question_data,\n rt: rt,\n question_order: trial.randomize_question_order\n ? this.jsPsych.randomization.shuffle([...Array(trial.questions.length).keys()])\n : [...Array(trial.questions.length).keys()],\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 this.trial(display_element, trial);\n load_callback();\n\n const answers = Object.entries(data.response);\n for (let i = 0; i < answers.length; i++) {\n this.jsPsych.pluginAPI.clickTarget(\n display_element.querySelector(\n `#${plugin_id_name}-response-${i}-${trial.questions[i].options.indexOf(\n answers[i][1]\n )}`\n ),\n ((data.rt - 1000) / answers.length) * (i + 1)\n );\n }\n\n this.jsPsych.pluginAPI.clickTarget(\n display_element.querySelector(`#${plugin_id_name}-next`),\n data.rt\n );\n }\n}\n\nexport default SurveyMultiChoicePlugin;\n"],"names":[],"mappings":";;AAEE,IAAW,OAAA,GAAA,OAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EC6FA,SAAA,EAAA;AAAA;;GAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jspsych/plugin-survey-multi-choice",
3
- "version": "2.0.1",
3
+ "version": "2.1.0",
4
4
  "description": "a jspsych plugin for multiple choice survey questions",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",
@@ -37,7 +37,7 @@
37
37
  "jspsych": ">=7.1.0"
38
38
  },
39
39
  "devDependencies": {
40
- "@jspsych/config": "^3.1.1",
40
+ "@jspsych/config": "^3.2.0",
41
41
  "@jspsych/test-utils": "^1.2.0"
42
42
  }
43
43
  }
package/src/index.spec.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import { clickTarget, simulateTimeline, startTimeline } from "@jspsych/test-utils";
2
2
 
3
+ import { initJsPsych } from "jspsych";
3
4
  import surveyMultiChoice from ".";
4
5
 
5
6
  jest.useFakeTimers();
@@ -10,6 +11,36 @@ const getInputElement = (choiceId: number, value: string) =>
10
11
  ) as HTMLInputElement;
11
12
 
12
13
  describe("survey-multi-choice plugin", () => {
14
+ test("properly ends when has sibling form", async () => {
15
+
16
+ const container = document.createElement('div')
17
+ const outerForm = document.createElement('form')
18
+ outerForm.id = 'outer_form'
19
+ container.appendChild(outerForm)
20
+ const innerDiv = document.createElement('div')
21
+ innerDiv.id = 'target_id';
22
+ container.appendChild(innerDiv);
23
+ document.body.appendChild(container)
24
+ const jsPsychInst = initJsPsych({ display_element: innerDiv })
25
+ const options = ["a", "b", "c"];
26
+
27
+ const { getData, expectFinished } = await startTimeline([
28
+ {
29
+ type: surveyMultiChoice,
30
+ questions: [
31
+ { prompt: "Q0", options },
32
+ { prompt: "Q1", options },
33
+ ]
34
+ },
35
+ ], jsPsychInst);
36
+
37
+ getInputElement(0, "a").checked = true;
38
+ await clickTarget(document.querySelector("#jspsych-survey-multi-choice-next"));
39
+ await expectFinished();
40
+
41
+ })
42
+
43
+
13
44
  test("data are logged with the right question when randomize order is true", async () => {
14
45
  var scale = ["a", "b", "c", "d", "e"];
15
46
  const { getData, expectFinished } = await startTimeline([
@@ -45,7 +76,7 @@ describe("survey-multi-choice plugin", () => {
45
76
  });
46
77
  });
47
78
 
48
- describe("survey-likert plugin simulation", () => {
79
+ describe("survey-multi-choice plugin simulation", () => {
49
80
  test("data-only mode works", async () => {
50
81
  const scale = ["a", "b", "c", "d", "e"];
51
82
  const { getData, expectFinished } = await simulateTimeline([
package/src/index.ts CHANGED
@@ -92,10 +92,14 @@ const info = <const>{
92
92
  array: true,
93
93
  },
94
94
  },
95
+ // prettier-ignore
96
+ citations: '__CITATIONS__',
95
97
  };
96
98
 
97
99
  type Info = typeof info;
98
100
 
101
+ const plugin_id_name = "jspsych-survey-multi-choice";
102
+
99
103
  /**
100
104
  * **survey-multi-choice**
101
105
  *
@@ -107,38 +111,37 @@ type Info = typeof info;
107
111
  class SurveyMultiChoicePlugin implements JsPsychPlugin<Info> {
108
112
  static info = info;
109
113
 
110
- constructor(private jsPsych: JsPsych) {}
114
+ constructor(private jsPsych: JsPsych) { }
111
115
 
112
116
  trial(display_element: HTMLElement, trial: TrialType<Info>) {
113
- var plugin_id_name = "jspsych-survey-multi-choice";
117
+
118
+ const trial_form_id = `${plugin_id_name}_form`;
114
119
 
115
120
  var html = "";
116
121
 
117
122
  // inject CSS for trial
118
- html += '<style id="jspsych-survey-multi-choice-css">';
119
- html +=
120
- ".jspsych-survey-multi-choice-question { margin-top: 2em; margin-bottom: 2em; text-align: left; }" +
121
- ".jspsych-survey-multi-choice-text span.required {color: darkred;}" +
122
- ".jspsych-survey-multi-choice-horizontal .jspsych-survey-multi-choice-text { text-align: center;}" +
123
- ".jspsych-survey-multi-choice-option { line-height: 2; }" +
124
- ".jspsych-survey-multi-choice-horizontal .jspsych-survey-multi-choice-option { display: inline-block; margin-left: 1em; margin-right: 1em; vertical-align: top;}" +
125
- "label.jspsych-survey-multi-choice-text input[type='radio'] {margin-right: 1em;}";
126
- html += "</style>";
123
+ html += `
124
+ <style id="${plugin_id_name}-css">
125
+ .${plugin_id_name}-question { margin-top: 2em; margin-bottom: 2em; text-align: left; }
126
+ .${plugin_id_name}-text span.required {color: darkred;}
127
+ .${plugin_id_name}-horizontal .${plugin_id_name}-text { text-align: center;}
128
+ .${plugin_id_name}-option { line-height: 2; }
129
+ .${plugin_id_name}-horizontal .${plugin_id_name}-option { display: inline-block; margin-left: 1em; margin-right: 1em; vertical-align: top;}
130
+ label.${plugin_id_name}-text input[type='radio'] {margin-right: 1em;}
131
+ </style>`;
127
132
 
128
133
  // show preamble text
129
134
  if (trial.preamble !== null) {
130
- html +=
131
- '<div id="jspsych-survey-multi-choice-preamble" class="jspsych-survey-multi-choice-preamble">' +
132
- trial.preamble +
133
- "</div>";
135
+ html += `<div id="${plugin_id_name}-preamble" class="${plugin_id_name}-preamble">${trial.preamble}</div>`;
134
136
  }
135
137
 
136
138
  // form element
137
139
  if (trial.autocomplete) {
138
- html += '<form id="jspsych-survey-multi-choice-form">';
140
+ html += `<form id="${trial_form_id}">`;
139
141
  } else {
140
- html += '<form id="jspsych-survey-multi-choice-form" autocomplete="off">';
142
+ html += `<form id="${trial_form_id}" autocomplete="off">`;
141
143
  }
144
+
142
145
  // generate question order. this is randomized here as opposed to randomizing the order of trial.questions
143
146
  // so that the data are always associated with the same question regardless of order
144
147
  var question_order = [];
@@ -156,22 +159,15 @@ class SurveyMultiChoicePlugin implements JsPsychPlugin<Info> {
156
159
  var question_id = question_order[i];
157
160
 
158
161
  // create question container
159
- var question_classes = ["jspsych-survey-multi-choice-question"];
162
+ var question_classes = [`${plugin_id_name}-question`];
160
163
  if (question.horizontal) {
161
- question_classes.push("jspsych-survey-multi-choice-horizontal");
164
+ question_classes.push(`${plugin_id_name}-horizontal`);
162
165
  }
163
166
 
164
- html +=
165
- '<div id="jspsych-survey-multi-choice-' +
166
- question_id +
167
- '" class="' +
168
- question_classes.join(" ") +
169
- '" data-name="' +
170
- question.name +
171
- '">';
167
+ html += `<div id="${plugin_id_name}-${question_id}" class="${question_classes.join(" ")}" data-name="${question.name}">`;
172
168
 
173
169
  // add question text
174
- html += '<p class="jspsych-survey-multi-choice-text survey-multi-choice">' + question.prompt;
170
+ html += `<p class="${plugin_id_name}-text survey-multi-choice">${question.prompt}`;
175
171
  if (question.required) {
176
172
  html += "<span class='required'>*</span>";
177
173
  }
@@ -180,47 +176,35 @@ class SurveyMultiChoicePlugin implements JsPsychPlugin<Info> {
180
176
  // create option radio buttons
181
177
  for (var j = 0; j < question.options.length; j++) {
182
178
  // add label and question text
183
- var option_id_name = "jspsych-survey-multi-choice-option-" + question_id + "-" + j;
184
- var input_name = "jspsych-survey-multi-choice-response-" + question_id;
185
- var input_id = "jspsych-survey-multi-choice-response-" + question_id + "-" + j;
179
+ var option_id_name = `${plugin_id_name}-option-${question_id}-${j}`;
180
+ var input_name = `${plugin_id_name}-response-${question_id}`;
181
+ var input_id = `${plugin_id_name}-response-${question_id}-${j}`;
186
182
 
187
183
  var required_attr = question.required ? "required" : "";
188
184
 
189
185
  // add radio button container
190
- html += '<div id="' + option_id_name + '" class="jspsych-survey-multi-choice-option">';
191
- html += '<label class="jspsych-survey-multi-choice-text" for="' + input_id + '">';
192
- html +=
193
- '<input type="radio" name="' +
194
- input_name +
195
- '" id="' +
196
- input_id +
197
- '" value="' +
198
- question.options[j] +
199
- '" ' +
200
- required_attr +
201
- "></input>";
202
- html += question.options[j] + "</label>";
203
- html += "</div>";
186
+ html += `
187
+ <div id="${option_id_name}" class="${plugin_id_name}-option">
188
+ <label class="${plugin_id_name}-text" for="${input_id}">
189
+ <input type="radio" name="${input_name}" id="${input_id}" value="${question.options[j]}" ${required_attr} />
190
+ ${question.options[j]}
191
+ </label>
192
+ </div>`;
204
193
  }
205
194
 
206
195
  html += "</div>";
207
196
  }
208
197
 
209
198
  // add submit button
210
- html +=
211
- '<input type="submit" id="' +
212
- plugin_id_name +
213
- '-next" class="' +
214
- plugin_id_name +
215
- ' jspsych-btn"' +
216
- (trial.button_label ? ' value="' + trial.button_label + '"' : "") +
217
- "></input>";
199
+ html += `<input type="submit" id="${plugin_id_name}-next" class="${plugin_id_name} jspsych-btn"${trial.button_label ? ' value="' + trial.button_label + '"' : ""} />`;
218
200
  html += "</form>";
219
201
 
220
202
  // render
221
203
  display_element.innerHTML = html;
222
204
 
223
- document.querySelector("form").addEventListener("submit", (event) => {
205
+ const trial_form = display_element.querySelector<HTMLFormElement>(`#${trial_form_id}`);
206
+
207
+ trial_form.addEventListener("submit", (event) => {
224
208
  event.preventDefault();
225
209
  // measure response time
226
210
  var endTime = performance.now();
@@ -229,7 +213,7 @@ class SurveyMultiChoicePlugin implements JsPsychPlugin<Info> {
229
213
  // create object to hold responses
230
214
  var question_data = {};
231
215
  for (var i = 0; i < trial.questions.length; i++) {
232
- var match = display_element.querySelector("#jspsych-survey-multi-choice-" + i);
216
+ var match = display_element.querySelector(`#${plugin_id_name}-${i}`);
233
217
  var id = "Q" + i;
234
218
  var val: String;
235
219
  if (match.querySelector("input[type=radio]:checked") !== null) {
@@ -317,7 +301,7 @@ class SurveyMultiChoicePlugin implements JsPsychPlugin<Info> {
317
301
  for (let i = 0; i < answers.length; i++) {
318
302
  this.jsPsych.pluginAPI.clickTarget(
319
303
  display_element.querySelector(
320
- `#jspsych-survey-multi-choice-response-${i}-${trial.questions[i].options.indexOf(
304
+ `#${plugin_id_name}-response-${i}-${trial.questions[i].options.indexOf(
321
305
  answers[i][1]
322
306
  )}`
323
307
  ),
@@ -326,7 +310,7 @@ class SurveyMultiChoicePlugin implements JsPsychPlugin<Info> {
326
310
  }
327
311
 
328
312
  this.jsPsych.pluginAPI.clickTarget(
329
- display_element.querySelector("#jspsych-survey-multi-choice-next"),
313
+ display_element.querySelector(`#${plugin_id_name}-next`),
330
314
  data.rt
331
315
  );
332
316
  }