diff --git a/backend/src/services/learning-objects/processing/gift/gift-processor.ts b/backend/src/services/learning-objects/processing/gift/gift-processor.ts
index 8d548f56..d6fe5adb 100644
--- a/backend/src/services/learning-objects/processing/gift/gift-processor.ts
+++ b/backend/src/services/learning-objects/processing/gift/gift-processor.ts
@@ -38,7 +38,7 @@ class GiftProcessor extends StringProcessor {
let html = "
\n";
let i = 1;
for (const question of quizQuestions) {
- html += `
\n`;
+ html += `
\n`;
html += ' ' + this.renderQuestion(question, i).replaceAll(/\n(.+)/g, '\n $1'); // Replace for indentation.
html += `
\n`;
i++;
diff --git a/frontend/src/views/learning-paths/LearningObjectView.vue b/frontend/src/views/learning-paths/LearningObjectView.vue
index 25fd5672..a80f2625 100644
--- a/frontend/src/views/learning-paths/LearningObjectView.vue
+++ b/frontend/src/views/learning-paths/LearningObjectView.vue
@@ -3,6 +3,8 @@
import type { UseQueryReturnType } from "@tanstack/vue-query";
import { useLearningObjectHTMLQuery } from "@/queries/learning-objects.ts";
import UsingQueryResult from "@/components/UsingQueryResult.vue";
+ import {nextTick, onMounted, reactive, watch} from "vue";
+ import {getGiftAdapterForType} from "@/views/learning-paths/gift-adapters/gift-adapters.ts";
const props = defineProps<{ hruid: string; language: Language; version: number }>();
@@ -11,6 +13,49 @@
() => props.language,
() => props.version,
);
+
+ const currentAnswer = reactive([]);
+
+ function forEachQuestion(
+ doAction: (questionIndex: number, questionName: string, questionType: string, questionElement: Element) => void
+ ) {
+ const questions = document.querySelectorAll(".gift-question");
+ questions.forEach(question => {
+ const name = question.id.match(/gift-q(\d+)/)?.[1]
+ const questionType = question.classList.values()
+ .find(it => it.startsWith("gift-question-type"))
+ .match(/gift-question-type-([^ ]*)/)?.[1];
+
+ if (!name || isNaN(parseInt(name)) || !questionType) return;
+
+ const index = parseInt(name) - 1;
+
+ doAction(index, name, questionType, question);
+ });
+ }
+
+ function attachQuestionListeners() {
+ forEachQuestion((index, name, type, element) => {
+ getGiftAdapterForType(type)?.installListener(
+ element, (newAnswer) => currentAnswer[index] = newAnswer
+ );
+ });
+ }
+
+ function setAnswers(answers: (object | string | number)[]) {
+ forEachQuestion((index, name, type, element) => {
+ getGiftAdapterForType(type)?.setAnswer(element, answers[index]);
+ });
+ currentAnswer.fill(answers);
+ }
+
+ onMounted(() => nextTick(() => attachQuestionListeners()));
+
+ watch(learningObjectHtmlQueryResult.data, async () => {
+ await nextTick();
+ attachQuestionListeners();
+ setAnswers([1]);
+ });
@@ -22,6 +67,7 @@
class="learning-object-container"
v-html="learningPathHtml.data.body.innerHTML"
>
+ {{ currentAnswer }}
diff --git a/frontend/src/views/learning-paths/gift-adapters/essay-question-adapter.ts b/frontend/src/views/learning-paths/gift-adapters/essay-question-adapter.ts
new file mode 100644
index 00000000..eb49027c
--- /dev/null
+++ b/frontend/src/views/learning-paths/gift-adapters/essay-question-adapter.ts
@@ -0,0 +1,13 @@
+export const essayQuestionAdapter: GiftAdapter = {
+ questionType: "Essay",
+
+ installListener(questionElement: Element, answerUpdateCallback: (newAnswer: string | number | object) => void): void {
+ const textArea = questionElement.querySelector('textarea')!;
+ textArea.addEventListener('input', () => answerUpdateCallback(textArea.value));
+ },
+
+ setAnswer(questionElement: Element, answer: string | number | object): void {
+ const textArea = questionElement.querySelector('textarea')!;
+ textArea.value = String(answer);
+ }
+}
diff --git a/frontend/src/views/learning-paths/gift-adapters/gift-adapter.d.ts b/frontend/src/views/learning-paths/gift-adapters/gift-adapter.d.ts
new file mode 100644
index 00000000..b93234d9
--- /dev/null
+++ b/frontend/src/views/learning-paths/gift-adapters/gift-adapter.d.ts
@@ -0,0 +1,5 @@
+interface GiftAdapter {
+ questionType: string;
+ installListener(questionElement: Element, answerUpdateCallback: (newAnswer: string | number | object) => void): void;
+ setAnswer(questionElement: Element, answer: string | number | object): void;
+}
diff --git a/frontend/src/views/learning-paths/gift-adapters/gift-adapters.ts b/frontend/src/views/learning-paths/gift-adapters/gift-adapters.ts
new file mode 100644
index 00000000..d4a49ef2
--- /dev/null
+++ b/frontend/src/views/learning-paths/gift-adapters/gift-adapters.ts
@@ -0,0 +1,8 @@
+import {multipleChoiceQuestionAdapter} from "@/views/learning-paths/gift-adapters/multiple-choice-question-adapter.ts";
+import {essayQuestionAdapter} from "@/views/learning-paths/gift-adapters/essay-question-adapter.ts";
+
+export const giftAdapters = [multipleChoiceQuestionAdapter, essayQuestionAdapter];
+
+export function getGiftAdapterForType(questionType: string): GiftAdapter | undefined {
+ return giftAdapters.find(it => it.questionType === questionType);
+}
diff --git a/frontend/src/views/learning-paths/gift-adapters/multiple-choice-question-adapter.ts b/frontend/src/views/learning-paths/gift-adapters/multiple-choice-question-adapter.ts
new file mode 100644
index 00000000..3898cb97
--- /dev/null
+++ b/frontend/src/views/learning-paths/gift-adapters/multiple-choice-question-adapter.ts
@@ -0,0 +1,26 @@
+export const multipleChoiceQuestionAdapter: GiftAdapter = {
+ questionType: "MC",
+
+ installListener(questionElement: Element, answerUpdateCallback: (newAnswer: string | number | object) => void): void {
+ questionElement.querySelectorAll('input[type=radio]').forEach(element => {
+ const input = element as HTMLInputElement;
+
+ input.addEventListener('change', () => {
+ answerUpdateCallback(parseInt(input.value));
+ });
+ // Optional: initialize value if already selected
+ if (input.checked) {
+ answerUpdateCallback(parseInt(input.value));
+ }
+ });
+ },
+
+ setAnswer(questionElement: Element, answer: string | number | object): void {
+ questionElement.querySelectorAll('input[type=radio]').forEach(element => {
+ const input = element as HTMLInputElement;
+ console.log(`input: ${input.value}, answer: ${answer}`);
+ input.checked = String(answer) === String(input.value);
+ console.log(input.checked);
+ });
+ }
+}