@lernapps/app-templates 0.0.1 → 0.1.1
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.
- package/LICENSE +22 -0
- package/README.md +195 -2
- package/dist/appname-Bh23cUuz.mjs +12 -0
- package/dist/assessment-Dy359O1O.mjs +1696 -0
- package/dist/block-BK_ohsH1.mjs +82 -0
- package/dist/blocks-CxtCPAa5.mjs +149 -0
- package/dist/blocks.mjs +4 -0
- package/dist/check-CteIFN96.mjs +254 -0
- package/dist/content-DO6oEJxj.mjs +140 -0
- package/dist/contract-PONpxJtd.mjs +52 -0
- package/dist/e2e-CU0n_unV.mjs +89 -0
- package/dist/engine-CArxqizW.mjs +136 -0
- package/dist/explainer-e2e.mjs +1311 -0
- package/dist/explainer-islands.mjs +197 -0
- package/dist/explainer-plugin.mjs +2132 -0
- package/dist/explainer.mjs +1246 -0
- package/dist/html-mffkHGHh.mjs +89 -0
- package/dist/image-CspJVfyQ.mjs +21 -0
- package/dist/interactive-e2e.mjs +140 -0
- package/dist/interactive-plugin.mjs +242 -0
- package/dist/interactive.mjs +75 -0
- package/dist/load-RosvaPZf.mjs +16976 -0
- package/dist/needs-BzEahJ6X.mjs +97 -0
- package/dist/pages-9RaaomoO.mjs +81 -0
- package/dist/questions-e2e.mjs +1 -0
- package/dist/questions-engine.mjs +3 -0
- package/dist/questions.mjs +6 -0
- package/dist/quiz-DnW-xtCh.mjs +70 -0
- package/dist/quiz-e2e.mjs +174 -0
- package/dist/quiz-plugin.mjs +266 -0
- package/dist/quiz.mjs +246 -0
- package/dist/render-D5kwkNt1.mjs +507 -0
- package/dist/render-DqHOJyHK.mjs +146 -0
- package/dist/render-GS1Htlu8.mjs +545 -0
- package/dist/result-D_mmCVwN.mjs +180 -0
- package/dist/tasks-DADUYy52.mjs +74 -0
- package/dist/validate-BDwL7Su3.mjs +1076 -0
- package/dist/validate-Bxy9NfB8.mjs +146 -0
- package/dist/vue-DO1m6q1R.mjs +40 -0
- package/dist/vue-code-BkJjW_I_.mjs +320 -0
- package/docs/arc42/01-introduction-and-goals.arc42.md +82 -0
- package/docs/arc42/02-constraints.arc42.md +228 -0
- package/docs/arc42/03-system-context.arc42.md +118 -0
- package/docs/arc42/04-solution-strategy.arc42.md +47 -0
- package/docs/arc42/05-building-blocks.arc42.md +307 -0
- package/docs/arc42/06-runtime-view.arc42.md +98 -0
- package/docs/arc42/07-deployment-view.arc42.md +160 -0
- package/docs/arc42/08-concepts.arc42.md +123 -0
- package/docs/arc42/09-decisions.arc42.md +246 -0
- package/docs/arc42/10-quality-requirements.arc42.md +155 -0
- package/docs/arc42/11-risks.arc42.md +113 -0
- package/docs/arc42/12-glossary.arc42.md +162 -0
- package/docs/arc42/architecture-evidence.md +395 -0
- package/explainer/.arc42ignore +3 -0
- package/explainer/README.md +54 -0
- package/explainer/_gitignore +5 -0
- package/explainer/docs/arc42/03-explainer-system-context.arc42.md +35 -0
- package/explainer/docs/arc42/05-explainer-building-blocks.arc42.md +659 -0
- package/explainer/docs/arc42/06-explainer-runtime-view.arc42.md +105 -0
- package/explainer/docs/arc42/07-explainer-deployment-view.arc42.md +34 -0
- package/explainer/docs/arc42/08-explainer-concepts.arc42.md +17 -0
- package/explainer/docs/arc42/09-explainer-decisions.arc42.md +443 -0
- package/explainer/docs/arc42/10-explainer-quality-requirements.arc42.md +54 -0
- package/explainer/docs/arc42/11-explainer-risks.arc42.md +17 -0
- package/explainer/docs/arc42/12-explainer-glossary.arc42.md +185 -0
- package/explainer/e2e/explainer.e2e.ts +3 -0
- package/explainer/index.html +11 -0
- package/explainer/package.json +18 -0
- package/explainer/playwright.config.ts +1 -0
- package/explainer/src/app.yaml +20 -0
- package/explainer/src/components/ProzentFeld.test.ts +30 -0
- package/explainer/src/components/ProzentFeld.ts +121 -0
- package/explainer/src/components/ProzentFeld.vue +84 -0
- package/explainer/src/images/hunderterfeld-klammern.svg +105 -0
- package/explainer/src/main.ts +4 -0
- package/explainer/src/prozent/chapter.yaml +18 -0
- package/explainer/src/prozent/grundwert.yaml +115 -0
- package/explainer/src/prozent/prozentsatz.yaml +99 -0
- package/explainer/src/prozent/prozentwert.yaml +119 -0
- package/explainer/tsconfig.json +1 -0
- package/explainer/vite.config.ts +4 -0
- package/interactive/.arc42ignore +5 -0
- package/interactive/README.md +28 -0
- package/interactive/_gitignore +4 -0
- package/interactive/docs/arc42/05-interactive-building-blocks.arc42.md +518 -0
- package/interactive/docs/arc42/06-interactive-runtime-view.arc42.md +58 -0
- package/interactive/docs/arc42/07-interactive-deployment-view.arc42.md +35 -0
- package/interactive/docs/arc42/08-interactive-concepts.arc42.md +52 -0
- package/interactive/docs/arc42/09-interactive-decisions.arc42.md +130 -0
- package/interactive/docs/arc42/10-interactive-quality-requirements.arc42.md +45 -0
- package/interactive/docs/arc42/11-interactive-risks.arc42.md +20 -0
- package/interactive/docs/arc42/12-interactive-glossary.arc42.md +80 -0
- package/interactive/e2e/interactive.e2e.ts +3 -0
- package/interactive/index.html +11 -0
- package/interactive/package.json +18 -0
- package/interactive/playwright.config.ts +1 -0
- package/interactive/src/app.yaml +28 -0
- package/interactive/src/core/index.ts +101 -0
- package/interactive/src/data/lessons.json +4 -0
- package/interactive/src/env.d.ts +6 -0
- package/interactive/src/main.ts +6 -0
- package/interactive/src/messages/de.json +12 -0
- package/interactive/src/playthroughs/grundreihe.yaml +33 -0
- package/interactive/src/playthroughs/obere-reihe.yaml +14 -0
- package/interactive/src/ui/App.vue +85 -0
- package/interactive/tsconfig.json +1 -0
- package/interactive/vite.config.ts +4 -0
- package/package.json +143 -4
- package/quiz/README.md +31 -0
- package/quiz/_gitignore +5 -0
- package/quiz/docs/arc42/05-quiz-building-blocks.arc42.md +283 -0
- package/quiz/docs/arc42/06-quiz-runtime-view.arc42.md +21 -0
- package/quiz/docs/arc42/07-quiz-deployment-view.arc42.md +33 -0
- package/quiz/docs/arc42/09-quiz-decisions.arc42.md +36 -0
- package/quiz/docs/arc42/10-quiz-quality-requirements.arc42.md +53 -0
- package/quiz/docs/arc42/11-quiz-risks.arc42.md +19 -0
- package/quiz/docs/arc42/12-quiz-glossary.arc42.md +27 -0
- package/quiz/e2e/quiz.e2e.ts +3 -0
- package/quiz/index.html +11 -0
- package/quiz/package.json +18 -0
- package/quiz/playwright.config.ts +1 -0
- package/quiz/src/images/berge-ordnen.jpg +0 -0
- package/quiz/src/images/everest-hoehe.jpg +0 -0
- package/quiz/src/images/galapagos.jpg +0 -0
- package/quiz/src/images/grand-canyon.jpg +0 -0
- package/quiz/src/images/totes-meer.jpg +0 -0
- package/quiz/src/images/uluru.jpg +0 -0
- package/quiz/src/images/wasserfaelle-laender.jpg +0 -0
- package/quiz/src/main.ts +4 -0
- package/quiz/src/quiz.json +312 -0
- package/quiz/tsconfig.json +1 -0
- package/quiz/vite.config.ts +4 -0
- package/runtime/explainer/assessment-client.ts +478 -0
- package/runtime/explainer/assessment-page.ts +448 -0
- package/runtime/explainer/assessment.ts +393 -0
- package/runtime/explainer/check-page.ts +520 -0
- package/runtime/explainer/components/exercise.ts +409 -0
- package/runtime/explainer/components/props.ts +230 -0
- package/runtime/explainer/components/read.ts +428 -0
- package/runtime/explainer/content.ts +277 -0
- package/runtime/explainer/e2e.ts +1488 -0
- package/runtime/explainer/exercises.ts +326 -0
- package/runtime/explainer/explainer.css +1283 -0
- package/runtime/explainer/explainer.ts +838 -0
- package/runtime/explainer/explainer.v1.schema.json +1165 -0
- package/runtime/explainer/expression.ts +407 -0
- package/runtime/explainer/fraction.ts +107 -0
- package/runtime/explainer/generated/comparator.ts +31 -0
- package/runtime/explainer/generated/question.ts +165 -0
- package/runtime/explainer/generated/soundness.ts +280 -0
- package/runtime/explainer/generated/texts.ts +257 -0
- package/runtime/explainer/generated/types.ts +103 -0
- package/runtime/explainer/generated/values.ts +136 -0
- package/runtime/explainer/islands.ts +281 -0
- package/runtime/explainer/load.ts +457 -0
- package/runtime/explainer/messages/de.json +200 -0
- package/runtime/explainer/messages/en.json +200 -0
- package/runtime/explainer/messages.ts +13 -0
- package/runtime/explainer/needs.ts +122 -0
- package/runtime/explainer/open-task.ts +235 -0
- package/runtime/explainer/outline.ts +306 -0
- package/runtime/explainer/plugin.ts +488 -0
- package/runtime/explainer/position.ts +62 -0
- package/runtime/explainer/prompt.ts +75 -0
- package/runtime/explainer/render.ts +686 -0
- package/runtime/explainer/result.ts +238 -0
- package/runtime/explainer/routes.ts +119 -0
- package/runtime/explainer/schema.ts +140 -0
- package/runtime/explainer/scope.ts +87 -0
- package/runtime/explainer/stuck.ts +57 -0
- package/runtime/explainer/tasks.ts +109 -0
- package/runtime/explainer/tutor.ts +469 -0
- package/runtime/explainer/tutorpage.ts +669 -0
- package/runtime/explainer/video.ts +123 -0
- package/runtime/interactive/contract.ts +121 -0
- package/runtime/interactive/e2e.ts +190 -0
- package/runtime/interactive/interactive.css +82 -0
- package/runtime/interactive/interactive.ts +115 -0
- package/runtime/interactive/interactive.v1.schema.json +146 -0
- package/runtime/interactive/load.ts +188 -0
- package/runtime/interactive/messages/de.json +14 -0
- package/runtime/interactive/messages/en.json +14 -0
- package/runtime/interactive/messages.ts +11 -0
- package/runtime/interactive/playthrough.v1.schema.json +143 -0
- package/runtime/interactive/plugin.ts +266 -0
- package/runtime/interactive/render.ts +126 -0
- package/runtime/quiz/e2e.ts +233 -0
- package/runtime/quiz/engine.ts +242 -0
- package/runtime/quiz/messages/de.json +23 -0
- package/runtime/quiz/messages/en.json +23 -0
- package/runtime/quiz/plugin.ts +150 -0
- package/runtime/quiz/quiz.css +154 -0
- package/runtime/quiz/quiz.ts +56 -0
- package/runtime/quiz/quiz.v1.schema.json +72 -0
- package/runtime/quiz/render.ts +173 -0
- package/runtime/quiz/validate.ts +108 -0
- package/runtime/shared/appname.ts +16 -0
- package/runtime/shared/blocks/block.ts +162 -0
- package/runtime/shared/blocks/blocks.css +190 -0
- package/runtime/shared/blocks/blocks.v1.schema.json +432 -0
- package/runtime/shared/blocks/code.ts +26 -0
- package/runtime/shared/blocks/figures.ts +49 -0
- package/runtime/shared/blocks/image.ts +25 -0
- package/runtime/shared/blocks/index.ts +13 -0
- package/runtime/shared/blocks/messages/de.json +4 -0
- package/runtime/shared/blocks/messages/en.json +4 -0
- package/runtime/shared/blocks/render.ts +134 -0
- package/runtime/shared/blocks/validate.ts +165 -0
- package/runtime/shared/content.ts +197 -0
- package/runtime/shared/examples.ts +20 -0
- package/runtime/shared/html.ts +10 -0
- package/runtime/shared/languages.ts +94 -0
- package/runtime/shared/page.css +101 -0
- package/runtime/shared/pages.ts +114 -0
- package/runtime/shared/questions/e2e.ts +115 -0
- package/runtime/shared/questions/engine.ts +209 -0
- package/runtime/shared/questions/index.ts +39 -0
- package/runtime/shared/questions/messages/de.json +26 -0
- package/runtime/shared/questions/messages/en.json +26 -0
- package/runtime/shared/questions/question.ts +433 -0
- package/runtime/shared/questions/question.v1.schema.json +346 -0
- package/runtime/shared/questions/questions.css +192 -0
- package/runtime/shared/questions/render.ts +255 -0
- package/runtime/shared/questions/validate.ts +518 -0
- package/runtime/shared/schema.ts +44 -0
- package/runtime/shared/text/check.ts +68 -0
- package/runtime/shared/text/formula.ts +69 -0
- package/runtime/shared/text/markdown.ts +185 -0
- package/runtime/shared/text/speech.ts +39 -0
- package/runtime/shared/text/text.v1.schema.json +34 -0
- package/runtime/shared/vue-code.ts +395 -0
- package/runtime/shared/vue.ts +38 -0
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
import { x as rightEntries } from "./render-GS1Htlu8.mjs";
|
|
2
|
+
import { w as message } from "./assessment-Dy359O1O.mjs";
|
|
3
|
+
// runtime/explainer/result.ts
|
|
4
|
+
const key = (id, n) => n === void 0 ? id : `${id}=${n}`;
|
|
5
|
+
/**
|
|
6
|
+
* What the learner did on this page, by task (an exercise and its task number), kept in memory only: the page stores
|
|
7
|
+
* nothing, so the session is this visit of the page, which a tutor's link opens in a tab of its own.
|
|
8
|
+
*/
|
|
9
|
+
var Progress = class {
|
|
10
|
+
#tasks = /* @__PURE__ */ new Map();
|
|
11
|
+
#listeners = [];
|
|
12
|
+
#last;
|
|
13
|
+
/** Calls `listener` with the exercise's id whenever the state of one of its tasks changes. */
|
|
14
|
+
listen(listener) {
|
|
15
|
+
this.#listeners.push(listener);
|
|
16
|
+
}
|
|
17
|
+
#set(id, n, state) {
|
|
18
|
+
this.#tasks.set(key(id, n), state);
|
|
19
|
+
for (const listener of this.#listeners) listener(id);
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* A complete answer to the task number `n` of the exercise `id` (none for an exercise without numbers): the input as
|
|
23
|
+
* text, and the message the app showed for a wrong one, word for word.
|
|
24
|
+
*/
|
|
25
|
+
answered(id, n, right, input, message) {
|
|
26
|
+
this.#last = id;
|
|
27
|
+
const state = this.state(id, n);
|
|
28
|
+
if (state.rightAt !== void 0 || state.revealed) return;
|
|
29
|
+
const attempts = state.attempts + 1;
|
|
30
|
+
const { input: _input, message: _message, ...rest } = state;
|
|
31
|
+
this.#set(id, n, {
|
|
32
|
+
...rest,
|
|
33
|
+
attempts,
|
|
34
|
+
...right ? { rightAt: attempts } : {},
|
|
35
|
+
...right || input === void 0 ? {} : { input },
|
|
36
|
+
...right || message === void 0 || message === "" ? {} : { message }
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* The open task `id` as the learner compared it: `ticked` of `total` points, the `missed` ones named (P2, P4), the
|
|
41
|
+
* answer as text (or that it is a photo). `attempt`: a new comparing, which counts as a try; a changed tick changes
|
|
42
|
+
* the same try. Its model answer shows once compared.
|
|
43
|
+
*/
|
|
44
|
+
compared(id, ticked, total, missed, input, attempt = true) {
|
|
45
|
+
this.#last = id;
|
|
46
|
+
const state = this.state(id, void 0);
|
|
47
|
+
const attempts = attempt ? state.attempts + 1 : Math.max(state.attempts, 1);
|
|
48
|
+
const { points: _points, input: _input, rightAt: _rightAt, ...rest } = state;
|
|
49
|
+
this.#set(id, void 0, {
|
|
50
|
+
...rest,
|
|
51
|
+
attempts,
|
|
52
|
+
revealed: true,
|
|
53
|
+
...ticked === total ? { rightAt: attempts } : {
|
|
54
|
+
points: {
|
|
55
|
+
ticked,
|
|
56
|
+
total,
|
|
57
|
+
missed
|
|
58
|
+
},
|
|
59
|
+
input
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
/** The learner opened the hint of the task. */
|
|
64
|
+
hinted(id, n) {
|
|
65
|
+
const state = this.state(id, n);
|
|
66
|
+
if (state.hint === true) return;
|
|
67
|
+
this.#set(id, n, {
|
|
68
|
+
...state,
|
|
69
|
+
hint: true
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
/** The solution of the task shows ("Lösung"; also after the right answer, which then stays right). */
|
|
73
|
+
revealed(id, n) {
|
|
74
|
+
this.#last = id;
|
|
75
|
+
const state = this.state(id, n);
|
|
76
|
+
if (state.rightAt !== void 0) return;
|
|
77
|
+
this.#set(id, n, {
|
|
78
|
+
...state,
|
|
79
|
+
revealed: true
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
/** How far the learner got with the task. */
|
|
83
|
+
state(id, n) {
|
|
84
|
+
return this.#tasks.get(key(id, n)) ?? {
|
|
85
|
+
attempts: 0,
|
|
86
|
+
revealed: false
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
/** The exercise the learner answered last, if any. */
|
|
90
|
+
get last() {
|
|
91
|
+
return this.#last;
|
|
92
|
+
}
|
|
93
|
+
/** Each task the learner answered or looked up in this session, in the order they first did. */
|
|
94
|
+
tasks() {
|
|
95
|
+
return [...this.#tasks.entries()].filter(([, state]) => state.attempts > 0 || state.revealed).map(([key, state]) => {
|
|
96
|
+
const [id = "", n] = key.split("=");
|
|
97
|
+
return {
|
|
98
|
+
id,
|
|
99
|
+
...n === void 0 ? {} : { number: Number(n) },
|
|
100
|
+
state
|
|
101
|
+
};
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
/** The count of the session. */
|
|
105
|
+
session() {
|
|
106
|
+
const states = [...this.#tasks.values()].filter((state) => state.attempts > 0 || state.revealed);
|
|
107
|
+
return {
|
|
108
|
+
right: states.filter((state) => state.rightAt !== void 0).length,
|
|
109
|
+
total: states.length
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
/** How far the learner got with a task, in `lang`: "richtig im 2. Versuch", "noch nicht gelöst (1 Versuch, …)". */
|
|
114
|
+
function statusOf(state, lang) {
|
|
115
|
+
if (state.rightAt !== void 0) return message(lang, "resultRight", { n: String(state.rightAt) });
|
|
116
|
+
if (state.points !== void 0) {
|
|
117
|
+
const partly = message(lang, "resultPartly", {
|
|
118
|
+
n: String(state.points.ticked),
|
|
119
|
+
total: String(state.points.total),
|
|
120
|
+
missed: state.points.missed
|
|
121
|
+
});
|
|
122
|
+
return state.input === void 0 ? partly : `${partly}, ${message(lang, "resultAnswer", { input: state.input })}`;
|
|
123
|
+
}
|
|
124
|
+
const status = message(lang, state.revealed ? "resultSolution" : "resultOpen");
|
|
125
|
+
if (state.attempts === 0) return status;
|
|
126
|
+
return `${status} (${state.attempts === 1 ? message(lang, "resultTry") : message(lang, "resultTries", { n: String(state.attempts) })}${state.input === void 0 ? "" : `, ${message(lang, "resultInput", { input: state.input })}`})`;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* What "Zurück zum Tutor" at the top or the end of a page copies, in `lang`: the page's tutor page with the page's
|
|
130
|
+
* task numbers, then a line for each task the learner answered or looked up in this session (the exercise, its task
|
|
131
|
+
* number, how far the learner got, the last wrong input and the app's message for it, word for word), then the count of
|
|
132
|
+
* the session; a tutor loads the tutor page and coaches on exactly these tasks.
|
|
133
|
+
*/
|
|
134
|
+
function sessionLines(tutor, tasks, session, lang) {
|
|
135
|
+
if (tasks.length === 0) return message(lang, "sessionNone", { url: tutor });
|
|
136
|
+
return [
|
|
137
|
+
message(lang, "sessionIntro", { url: tutor }),
|
|
138
|
+
...tasks.map((task) => {
|
|
139
|
+
const said = task.state.rightAt === void 0 && task.state.message !== void 0 ? ` ${message(lang, "stuckMessage", { message: task.state.message.replace(/\s+/g, " ").trim() })}` : "";
|
|
140
|
+
return `- ${message(lang, "sessionTask", {
|
|
141
|
+
exercise: task.id,
|
|
142
|
+
number: task.number === void 0 ? "" : message(lang, "resultNumber", { n: String(task.number) }),
|
|
143
|
+
status: statusOf(task.state, lang)
|
|
144
|
+
})}${said}`;
|
|
145
|
+
}),
|
|
146
|
+
message(lang, "resultSession", {
|
|
147
|
+
right: String(session.right),
|
|
148
|
+
total: String(session.total)
|
|
149
|
+
})
|
|
150
|
+
].join("\n");
|
|
151
|
+
}
|
|
152
|
+
/** The result line, two lines in `lang`: the result, and the page's tutor page. */
|
|
153
|
+
function resultLine(line, lang) {
|
|
154
|
+
return [`${message(lang, "resultLine", {
|
|
155
|
+
page: line.page,
|
|
156
|
+
exercise: line.exercise,
|
|
157
|
+
number: line.number === void 0 ? "" : message(lang, "resultNumber", { n: String(line.number) }),
|
|
158
|
+
status: statusOf(line.state, lang)
|
|
159
|
+
})}${line.session.total === 0 ? "" : ` ${message(lang, "resultSession", {
|
|
160
|
+
right: String(line.session.right),
|
|
161
|
+
total: String(line.session.total)
|
|
162
|
+
})}`}`, `${message(lang, "resultTutor")} ${line.tutor}`].join("\n");
|
|
163
|
+
}
|
|
164
|
+
const oneLine = (text) => text.replace(/\s+/g, " ").trim();
|
|
165
|
+
/** The learner's answer to a question as text, in `lang`: the options chosen, the number typed, the order given. */
|
|
166
|
+
function answerShown(question, answer, lang) {
|
|
167
|
+
const indices = typeof answer === "number" ? [answer] : Array.isArray(answer) ? answer : [];
|
|
168
|
+
switch (question.type) {
|
|
169
|
+
case "single-choice":
|
|
170
|
+
case "multiple-choice": return indices.map((index) => oneLine(question.options[index]?.text ?? "?")).join("; ");
|
|
171
|
+
case "true-false": return message(lang, answer === true ? "resultTrue" : "resultFalse");
|
|
172
|
+
case "number": return oneLine(String(answer));
|
|
173
|
+
case "ordering": return indices.map((place, item) => ({
|
|
174
|
+
place,
|
|
175
|
+
item
|
|
176
|
+
})).filter(({ place }) => place >= 0).sort((a, b) => a.place - b.place).map(({ item }) => oneLine(question.items[item] ?? "?")).join(" → ");
|
|
177
|
+
case "matching": return question.pairs.map((pair, index) => `${oneLine(pair.left)} → ${oneLine(rightEntries(question)[indices[index] ?? -1] ?? "?")}`).join("; ");
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
export { sessionLines as i, answerShown as n, resultLine as r, Progress as t };
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/** How many seeds the build tries at most to find MAX_TASKS distinct tasks. */
|
|
2
|
+
const SEED_TRIES = 1340;
|
|
3
|
+
/**
|
|
4
|
+
* The seeds of the distinct tasks, in order: seed 1, 2, 3, … kept when `key(seed)` (what the learner sees of its task,
|
|
5
|
+
* language-independent) differs from every kept one's, until `max` are kept or `tries` seeds are tried; a seed whose
|
|
6
|
+
* key is undefined (its task cannot be drawn) is skipped.
|
|
7
|
+
*/
|
|
8
|
+
function distinctSeeds(key, max = 67, tries = SEED_TRIES) {
|
|
9
|
+
const seen = /* @__PURE__ */ new Set();
|
|
10
|
+
const seeds = [];
|
|
11
|
+
for (let seed = 1; seed <= tries && seeds.length < max; seed++) {
|
|
12
|
+
const found = key(seed);
|
|
13
|
+
if (found === void 0 || seen.has(found)) continue;
|
|
14
|
+
seen.add(found);
|
|
15
|
+
seeds.push(seed);
|
|
16
|
+
}
|
|
17
|
+
return seeds;
|
|
18
|
+
}
|
|
19
|
+
/** The task number `n` within 1 to `count`: a number outside wraps around into it (68 of 67 is 1). */
|
|
20
|
+
const taskNumber = (n, count) => ((Math.trunc(n) - 1) % count + count) % count + 1;
|
|
21
|
+
/** The task number after `n`, for "Neue Aufgabe": the next one, from `count` back to 1. */
|
|
22
|
+
const nextTaskNumber = (n, count) => n % count + 1;
|
|
23
|
+
/** A task number to start with when the address names none. */
|
|
24
|
+
const randomTaskNumber = (count) => 1 + Math.floor(Math.random() * count);
|
|
25
|
+
/**
|
|
26
|
+
* Address parameters that are no exercise's: the page's (seed, via) and those of its tutor page, whose address holds
|
|
27
|
+
* the page's task numbers beside them (uebung, abschnitt; position.ts). An exercise id must not be one of them (the
|
|
28
|
+
* build checks).
|
|
29
|
+
*/
|
|
30
|
+
const RESERVED_PARAMS = [
|
|
31
|
+
"seed",
|
|
32
|
+
"via",
|
|
33
|
+
"uebung",
|
|
34
|
+
"abschnitt"
|
|
35
|
+
];
|
|
36
|
+
/**
|
|
37
|
+
* The task number the address `href` gives the exercise `id`: the parameter named by its id (?<id>=<n>, one per
|
|
38
|
+
* exercise, so that the address holds the task of every exercise of the page), or, as before, ?seed=<n>#<id>.
|
|
39
|
+
*/
|
|
40
|
+
function numberFromAddress(href, id) {
|
|
41
|
+
const url = new URL(href);
|
|
42
|
+
const asNumber = (text) => {
|
|
43
|
+
const n = Number(text);
|
|
44
|
+
return text !== null && Number.isInteger(n) && n > 0 ? n : void 0;
|
|
45
|
+
};
|
|
46
|
+
const own = asNumber(url.searchParams.get(id));
|
|
47
|
+
if (own !== void 0) return own;
|
|
48
|
+
return decodeURIComponent(url.hash.slice(1)) === id ? asNumber(url.searchParams.get("seed")) : void 0;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* The address `href` with the task number `n` of the exercise `id`: ?…&<id>=<n>, its other parameters and its anchor
|
|
52
|
+
* kept. A ?seed=<n> that named this exercise's task (it is the anchor) becomes the exercise's own parameter.
|
|
53
|
+
*/
|
|
54
|
+
function addressOf(href, id, n) {
|
|
55
|
+
const url = new URL(href);
|
|
56
|
+
if (decodeURIComponent(url.hash.slice(1)) === id) url.searchParams.delete("seed");
|
|
57
|
+
url.searchParams.set(id, String(n));
|
|
58
|
+
return url.href;
|
|
59
|
+
}
|
|
60
|
+
/** "Neue Aufgabe" as a symbol beside the task number: a circular arrow; the button's label is its name. */
|
|
61
|
+
const NEW_TASK_ICON = "<svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><path d=\"M21 12a9 9 0 1 1-2.6-6.4\"/><path d=\"M21 3v6h-6\"/></svg>";
|
|
62
|
+
/** The event an exercise sends on its element once it shows a task: the tutor's help button takes its place again. */
|
|
63
|
+
const SHOWN_EVENT = "explainer-shown";
|
|
64
|
+
/**
|
|
65
|
+
* The events between a self-assessment (assessment-client.ts) and the islands (islands.ts): the self-assessment put
|
|
66
|
+
* its exercises into the page (on the document); it gives an exercise component the task of `seed` (on its element);
|
|
67
|
+
* the component's answer changed, as { correct, partly?, answer?, message?, mistake?, missed? }, with mistake the
|
|
68
|
+
* index of the typical mistake it makes from 0, and missed the indexes of the points of a good answer it lacks, each
|
|
69
|
+
* from 0; or null when it has none: emptied, incomplete, or one its logic cannot read (on its element, bubbling).
|
|
70
|
+
*/
|
|
71
|
+
const ASSESSMENT_UNPACKED_EVENT = "explainer-assessment-unpacked";
|
|
72
|
+
const ASSESSMENT_TASK_EVENT = "explainer-assessment-task";
|
|
73
|
+
const ASSESSMENT_ANSWER_EVENT = "explainer-assessment-answer";
|
|
74
|
+
export { RESERVED_PARAMS as a, addressOf as c, numberFromAddress as d, randomTaskNumber as f, NEW_TASK_ICON as i, distinctSeeds as l, ASSESSMENT_TASK_EVENT as n, SEED_TRIES as o, taskNumber as p, ASSESSMENT_UNPACKED_EVENT as r, SHOWN_EVENT as s, ASSESSMENT_ANSWER_EVENT as t, nextTaskNumber as u };
|