diff --git a/src/gapfill-select.js b/src/gapfill-select.js new file mode 100644 index 0000000000000000000000000000000000000000..715af47ddda68af5e8eed6278efa8c608d57046b --- /dev/null +++ b/src/gapfill-select.js @@ -0,0 +1,69 @@ +/** + * Custom SurveyJS question type for a "fill-in-the-gaps" text, + * with a drop-down selection of choices for each + */ +export const gapfillSelectWidget = { + name: "gapfill-select", + title: "Gap-Fill Text (Select)", + /** + * This function should return true when the widget and all needed resources + * are loaded + */ + widgetIsLoaded: function () { + return true; + }, + /** + * This function should return true if the widget should be applied to the question */ + isFit: function (question) { + return question.getType() === this.name; + }, + init() { + //Register a new type using the empty question as the base. + Survey.Serializer.addClass(this.name, [], null, "empty"); + }, + /** Static HTML template rendered by SurveyJS */ + htmlTemplate: '<p id="gapfill-container"><template id="template-select"><select class="sd-input sd-dropdown inline-dropdown"><option selected/></select></template></p>', + /** + * Function called after the HTML template is rendered. This time we actually have the `question` object + * and the `el` element, to build the question according to the JSON + */ + afterRender: function (question, el) { + // The gap-fill text is made of segments, which are either plain pieces + // of text (strings) or "gaps" with a few options to select (string arrays). + // We append these to build the text, turning strings into <span>s and + // gaps into <select> dropdowns + let nbGaps = 0; + const segmentElems = new DocumentFragment(); // a bit faster than mutating the DOM all the time + const selectTemplate = document.getElementById("template-select").content.firstChild; + for (const segment of question.jsonObj.segments) { + let segmentElem; + if (typeof segment === 'string' || segment instanceof String) { + segmentElem = document.createElement("span"); + segmentElem.innerText = segment; + } else if (segment instanceof Array) { + // It's a gap + // Create the <select> element + segmentElem = selectTemplate.cloneNode(true); + segmentElem.setAttribute("data-index", nbGaps); // The node knows its index + // Create and append options + for (const opt of segment) { + let optionElem = document.createElement("option"); + optionElem.innerText = opt; + segmentElem.appendChild(optionElem); + } + // Add listener to update the question's value when the selector's value changes + segmentElem.addEventListener("change", (e) => { + // The select node knows its index, therefore is able to update the question value at the correct index + question.value[parseInt(e.target.getAttribute("data-index"))] = e.target.value; + }); + nbGaps++; + } + // Add segment + segmentElems.appendChild(segmentElem); + } + // Initialize question value array + question.value = new Array(nbGaps); + // Finally add everything to the DOM + el.appendChild(segmentElems); + }, +}; \ No newline at end of file diff --git a/src/index.html b/src/index.html new file mode 100644 index 0000000000000000000000000000000000000000..128b79302a21ed1a04001f9f96ecdf00602888c4 --- /dev/null +++ b/src/index.html @@ -0,0 +1,19 @@ +<!DOCTYPE html> +<html lang="en"> +<head> + <meta charset="UTF-8"> + <title>Survey-Quizgets example</title> + + <link rel="stylesheet" href="style.css"> + <!-- SurveyJS & dependencies--> + <script defer src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js" + type="text/javascript"></script> + <link href="https://unpkg.com/survey-jquery/defaultV2.min.css" rel="stylesheet" type="text/css"> + <script defer src="https://unpkg.com/survey-jquery/survey.jquery.min.js" type="text/javascript"></script> + + <script src="index.js" type="module"></script> +</head> +<body> +<div id="surveyContainer"></div> +</body> +</html> \ No newline at end of file diff --git a/src/index.js b/src/index.js new file mode 100644 index 0000000000000000000000000000000000000000..c4cf95d4c09844deef6c84d5267e2503664cd840 --- /dev/null +++ b/src/index.js @@ -0,0 +1,14 @@ +import {json} from "./json.js" +import {gapfillSelectWidget} from "./gapfill-select.js"; + +window.addEventListener('load', main) + +function main() { + // Register our custom question types + Survey.CustomWidgetCollection.Instance.add(gapfillSelectWidget, gapfillSelectWidget.name); + + let survey = new Survey.Model(json); + + // Inflate the survey in the page + $("#surveyContainer").Survey({model: survey}); +} diff --git a/src/json.js b/src/json.js new file mode 100644 index 0000000000000000000000000000000000000000..a1ed56016ae7637c9223f339892e11c7c165a013 --- /dev/null +++ b/src/json.js @@ -0,0 +1,42 @@ +export const json = { + elements: [ + { + type: "gapfill-select", + name: "pg20", + title: "The greatest song in the world", + segments: [ + "š¶\nWe're no strangers to ", + ["code", "love", "life"], + "\nYou ", + ["Node.js", "know the rules", "like apples"], + " and so do I", + "\nš¤ [...]", + "\nNever gonna ", + [ + "give you up", + "let you down", + "make you cry", + "say goodbye", + ], + "\nNever gonna ", + [ + "run around", + "tell a lie", + ], + " and ", + [ + "desert", + "hurt" + ], + " you" + ], + correctAnswer: [ + "love", + "know the rules", + "give you up", + "run around", + "desert" + ] + } + ] +}; \ No newline at end of file