@webwriter/quiz 1.0.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.
Files changed (62) hide show
  1. package/LICENSE +7 -0
  2. package/custom.d.ts +176 -0
  3. package/dist/widgets/webwriter-choice-item.css +444 -0
  4. package/dist/widgets/webwriter-choice-item.js +288 -0
  5. package/dist/widgets/webwriter-choice.css +444 -0
  6. package/dist/widgets/webwriter-choice.js +327 -0
  7. package/dist/widgets/webwriter-cloze-gap.css +444 -0
  8. package/dist/widgets/webwriter-cloze-gap.js +722 -0
  9. package/dist/widgets/webwriter-cloze.css +444 -0
  10. package/dist/widgets/webwriter-cloze.js +177 -0
  11. package/dist/widgets/webwriter-mark.css +444 -0
  12. package/dist/widgets/webwriter-mark.js +410 -0
  13. package/dist/widgets/webwriter-order-item.css +444 -0
  14. package/dist/widgets/webwriter-order-item.js +464 -0
  15. package/dist/widgets/webwriter-order.css +444 -0
  16. package/dist/widgets/webwriter-order.js +560 -0
  17. package/dist/widgets/webwriter-pairing-item.css +444 -0
  18. package/dist/widgets/webwriter-pairing-item.js +203 -0
  19. package/dist/widgets/webwriter-pairing.css +444 -0
  20. package/dist/widgets/webwriter-pairing.js +224 -0
  21. package/dist/widgets/webwriter-quiz.css +444 -0
  22. package/dist/widgets/webwriter-quiz.js +323 -0
  23. package/dist/widgets/webwriter-speech.css +444 -0
  24. package/dist/widgets/webwriter-speech.js +320 -0
  25. package/dist/widgets/webwriter-task-explainer.css +444 -0
  26. package/dist/widgets/webwriter-task-explainer.js +90 -0
  27. package/dist/widgets/webwriter-task-hint.css +444 -0
  28. package/dist/widgets/webwriter-task-hint.js +67 -0
  29. package/dist/widgets/webwriter-task-prompt.css +444 -0
  30. package/dist/widgets/webwriter-task-prompt.js +68 -0
  31. package/dist/widgets/webwriter-task.css +444 -0
  32. package/dist/widgets/webwriter-task.js +546 -0
  33. package/dist/widgets/webwriter-text.css +444 -0
  34. package/dist/widgets/webwriter-text.js +174 -0
  35. package/package.json +199 -0
  36. package/src/lib/combobox.ts +456 -0
  37. package/src/lib/highlighter-fill.svg +6 -0
  38. package/src/snippets/choice.html +8 -0
  39. package/src/snippets/cloze.html +4 -0
  40. package/src/snippets/mark.html +4 -0
  41. package/src/snippets/order.html +8 -0
  42. package/src/snippets/pairing.html +10 -0
  43. package/src/snippets/speech.html +4 -0
  44. package/src/snippets/text.html +4 -0
  45. package/src/snippets/wordsearch.html +4 -0
  46. package/src/widgets/webwriter-choice-item.ts +251 -0
  47. package/src/widgets/webwriter-choice.ts +310 -0
  48. package/src/widgets/webwriter-cloze-gap.ts +217 -0
  49. package/src/widgets/webwriter-cloze.ts +136 -0
  50. package/src/widgets/webwriter-mark.ts +435 -0
  51. package/src/widgets/webwriter-order-item.ts +445 -0
  52. package/src/widgets/webwriter-order.ts +273 -0
  53. package/src/widgets/webwriter-pairing-item.ts +156 -0
  54. package/src/widgets/webwriter-pairing.ts +188 -0
  55. package/src/widgets/webwriter-quiz.ts +281 -0
  56. package/src/widgets/webwriter-speech.ts +268 -0
  57. package/src/widgets/webwriter-task-explainer.ts +38 -0
  58. package/src/widgets/webwriter-task-hint.ts +17 -0
  59. package/src/widgets/webwriter-task-prompt.ts +18 -0
  60. package/src/widgets/webwriter-task.ts +544 -0
  61. package/src/widgets/webwriter-text.ts +131 -0
  62. package/tsconfig.json +7 -0
@@ -0,0 +1,546 @@
1
+ var __create = Object.create;
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __knownSymbol = (name, symbol) => (symbol = Symbol[name]) ? symbol : Symbol.for("Symbol." + name);
5
+ var __typeError = (msg) => {
6
+ throw TypeError(msg);
7
+ };
8
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
9
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
10
+ var __decoratorStart = (base) => [, , , __create(base?.[__knownSymbol("metadata")] ?? null)];
11
+ var __decoratorStrings = ["class", "method", "getter", "setter", "accessor", "field", "value", "get", "set"];
12
+ var __expectFn = (fn) => fn !== void 0 && typeof fn !== "function" ? __typeError("Function expected") : fn;
13
+ var __decoratorContext = (kind, name, done, metadata, fns) => ({ kind: __decoratorStrings[kind], name, metadata, addInitializer: (fn) => done._ ? __typeError("Already initialized") : fns.push(__expectFn(fn || null)) });
14
+ var __decoratorMetadata = (array, target) => __defNormalProp(target, __knownSymbol("metadata"), array[3]);
15
+ var __runInitializers = (array, flags, self, value) => {
16
+ for (var i = 0, fns = array[flags >> 1], n = fns && fns.length; i < n; i++) flags & 1 ? fns[i].call(self) : value = fns[i].call(self, value);
17
+ return value;
18
+ };
19
+ var __decorateElement = (array, flags, name, decorators, target, extra) => {
20
+ var fn, it, done, ctx, access, k = flags & 7, s = !!(flags & 8), p = !!(flags & 16);
21
+ var j = k > 3 ? array.length + 1 : k ? s ? 1 : 2 : 0, key = __decoratorStrings[k + 5];
22
+ var initializers = k > 3 && (array[j - 1] = []), extraInitializers = array[j] || (array[j] = []);
23
+ var desc = k && (!p && !s && (target = target.prototype), k < 5 && (k > 3 || !p) && __getOwnPropDesc(k < 4 ? target : { get [name]() {
24
+ return __privateGet(this, extra);
25
+ }, set [name](x) {
26
+ return __privateSet(this, extra, x);
27
+ } }, name));
28
+ k ? p && k < 4 && __name(extra, (k > 2 ? "set " : k > 1 ? "get " : "") + name) : __name(target, name);
29
+ for (var i = decorators.length - 1; i >= 0; i--) {
30
+ ctx = __decoratorContext(k, name, done = {}, array[3], extraInitializers);
31
+ if (k) {
32
+ ctx.static = s, ctx.private = p, access = ctx.access = { has: p ? (x) => __privateIn(target, x) : (x) => name in x };
33
+ if (k ^ 3) access.get = p ? (x) => (k ^ 1 ? __privateGet : __privateMethod)(x, target, k ^ 4 ? extra : desc.get) : (x) => x[name];
34
+ if (k > 2) access.set = p ? (x, y) => __privateSet(x, target, y, k ^ 4 ? extra : desc.set) : (x, y) => x[name] = y;
35
+ }
36
+ it = (0, decorators[i])(k ? k < 4 ? p ? extra : desc[key] : k > 4 ? void 0 : { get: desc.get, set: desc.set } : target, ctx), done._ = 1;
37
+ if (k ^ 4 || it === void 0) __expectFn(it) && (k > 4 ? initializers.unshift(it) : k ? p ? extra = it : desc[key] = it : target = it);
38
+ else if (typeof it !== "object" || it === null) __typeError("Object expected");
39
+ else __expectFn(fn = it.get) && (desc.get = fn), __expectFn(fn = it.set) && (desc.set = fn), __expectFn(fn = it.init) && initializers.unshift(fn);
40
+ }
41
+ return k || __decoratorMetadata(array, target), desc && __defProp(target, name, desc), p ? k ^ 4 ? extra : desc : target;
42
+ };
43
+ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
44
+ var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot " + msg);
45
+ var __privateIn = (member, obj) => Object(obj) !== obj ? __typeError('Cannot use the "in" operator on this value') : member.has(obj);
46
+ var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
47
+ var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
48
+ var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), setter ? setter.call(obj, value) : member.set(obj, value), value);
49
+ var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "access private method"), method);
50
+
51
+ // src/widgets/webwriter-task.ts
52
+ import { html, css } from "lit";
53
+ import { styleMap } from "lit/directives/style-map.js";
54
+ import { LitElementWw } from "@webwriter/lit";
55
+ import { customElement, queryAssignedElements, property, query } from "lit/decorators.js";
56
+ import SlIconButton from "@shoelace-style/shoelace/dist/components/icon-button/icon-button.component.js";
57
+ import SlButton from "@shoelace-style/shoelace/dist/components/button/button.component.js";
58
+ import SlDetails from "@shoelace-style/shoelace/dist/components/details/details.component.js";
59
+ import SlPopup from "@shoelace-style/shoelace/dist/components/popup/popup.component.js";
60
+ import SlButtonGroup from "@shoelace-style/shoelace/dist/components/button-group/button-group.component.js";
61
+ import SlTabGroup from "@shoelace-style/shoelace/dist/components/tab-group/tab-group.component.js";
62
+ import SlTab from "@shoelace-style/shoelace/dist/components/tab/tab.component.js";
63
+ import SlTabPanel from "@shoelace-style/shoelace/dist/components/tab-panel/tab-panel.component.js";
64
+
65
+ // ../../node_modules/bootstrap-icons/icons/patch-question.svg
66
+ var patch_question_default = 'data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-patch-question" viewBox="0 0 16 16">%0A <path d="M8.05 9.6c.336 0 .504-.24.554-.627.04-.534.198-.815.847-1.26.673-.475 1.049-1.09 1.049-1.986 0-1.325-.92-2.227-2.262-2.227-1.02 0-1.792.492-2.1 1.29A1.7 1.7 0 0 0 6 5.48c0 .393.203.64.545.64.272 0 .455-.147.564-.51.158-.592.525-.915 1.074-.915.61 0 1.03.446 1.03 1.084 0 .563-.208.885-.822 1.325-.619.433-.926.914-.926 1.64v.111c0 .428.208.745.585.745"/>%0A <path d="m10.273 2.513-.921-.944.715-.698.622.637.89-.011a2.89 2.89 0 0 1 2.924 2.924l-.01.89.636.622a2.89 2.89 0 0 1 0 4.134l-.637.622.011.89a2.89 2.89 0 0 1-2.924 2.924l-.89-.01-.622.636a2.89 2.89 0 0 1-4.134 0l-.622-.637-.89.011a2.89 2.89 0 0 1-2.924-2.924l.01-.89-.636-.622a2.89 2.89 0 0 1 0-4.134l.637-.622-.011-.89a2.89 2.89 0 0 1 2.924-2.924l.89.01.622-.636a2.89 2.89 0 0 1 4.134 0l-.715.698a1.89 1.89 0 0 0-2.704 0l-.92.944-1.32-.016a1.89 1.89 0 0 0-1.911 1.912l.016 1.318-.944.921a1.89 1.89 0 0 0 0 2.704l.944.92-.016 1.32a1.89 1.89 0 0 0 1.912 1.911l1.318-.016.921.944a1.89 1.89 0 0 0 2.704 0l.92-.944 1.32.016a1.89 1.89 0 0 0 1.911-1.912l-.016-1.318.944-.921a1.89 1.89 0 0 0 0-2.704l-.944-.92.016-1.32a1.89 1.89 0 0 0-1.912-1.911z"/>%0A <path d="M7.001 11a1 1 0 1 1 2 0 1 1 0 0 1-2 0"/>%0A</svg>';
67
+
68
+ // ../../node_modules/bootstrap-icons/icons/patch-question-fill.svg
69
+ var patch_question_fill_default = 'data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-patch-question-fill" viewBox="0 0 16 16">%0A <path d="M5.933.87a2.89 2.89 0 0 1 4.134 0l.622.638.89-.011a2.89 2.89 0 0 1 2.924 2.924l-.01.89.636.622a2.89 2.89 0 0 1 0 4.134l-.637.622.011.89a2.89 2.89 0 0 1-2.924 2.924l-.89-.01-.622.636a2.89 2.89 0 0 1-4.134 0l-.622-.637-.89.011a2.89 2.89 0 0 1-2.924-2.924l.01-.89-.636-.622a2.89 2.89 0 0 1 0-4.134l.637-.622-.011-.89a2.89 2.89 0 0 1 2.924-2.924l.89.01zM7.002 11a1 1 0 1 0 2 0 1 1 0 0 0-2 0m1.602-2.027c.04-.534.198-.815.846-1.26.674-.475 1.05-1.09 1.05-1.986 0-1.325-.92-2.227-2.262-2.227-1.02 0-1.792.492-2.1 1.29A1.7 1.7 0 0 0 6 5.48c0 .393.203.64.545.64.272 0 .455-.147.564-.51.158-.592.525-.915 1.074-.915.61 0 1.03.446 1.03 1.084 0 .563-.208.885-.822 1.325-.619.433-.926.914-.926 1.64v.111c0 .428.208.745.585.745.336 0 .504-.24.554-.627"/>%0A</svg>';
70
+
71
+ // ../../node_modules/bootstrap-icons/icons/patch-check.svg
72
+ var patch_check_default = 'data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-patch-check" viewBox="0 0 16 16">%0A <path fill-rule="evenodd" d="M10.354 6.146a.5.5 0 0 1 0 .708l-3 3a.5.5 0 0 1-.708 0l-1.5-1.5a.5.5 0 1 1 .708-.708L7 8.793l2.646-2.647a.5.5 0 0 1 .708 0"/>%0A <path d="m10.273 2.513-.921-.944.715-.698.622.637.89-.011a2.89 2.89 0 0 1 2.924 2.924l-.01.89.636.622a2.89 2.89 0 0 1 0 4.134l-.637.622.011.89a2.89 2.89 0 0 1-2.924 2.924l-.89-.01-.622.636a2.89 2.89 0 0 1-4.134 0l-.622-.637-.89.011a2.89 2.89 0 0 1-2.924-2.924l.01-.89-.636-.622a2.89 2.89 0 0 1 0-4.134l.637-.622-.011-.89a2.89 2.89 0 0 1 2.924-2.924l.89.01.622-.636a2.89 2.89 0 0 1 4.134 0l-.715.698a1.89 1.89 0 0 0-2.704 0l-.92.944-1.32-.016a1.89 1.89 0 0 0-1.911 1.912l.016 1.318-.944.921a1.89 1.89 0 0 0 0 2.704l.944.92-.016 1.32a1.89 1.89 0 0 0 1.912 1.911l1.318-.016.921.944a1.89 1.89 0 0 0 2.704 0l.92-.944 1.32.016a1.89 1.89 0 0 0 1.911-1.912l-.016-1.318.944-.921a1.89 1.89 0 0 0 0-2.704l-.944-.92.016-1.32a1.89 1.89 0 0 0-1.912-1.911z"/>%0A</svg>';
73
+
74
+ // ../../node_modules/bootstrap-icons/icons/patch-check-fill.svg
75
+ var patch_check_fill_default = 'data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-patch-check-fill" viewBox="0 0 16 16">%0A <path d="M10.067.87a2.89 2.89 0 0 0-4.134 0l-.622.638-.89-.011a2.89 2.89 0 0 0-2.924 2.924l.01.89-.636.622a2.89 2.89 0 0 0 0 4.134l.637.622-.011.89a2.89 2.89 0 0 0 2.924 2.924l.89-.01.622.636a2.89 2.89 0 0 0 4.134 0l.622-.637.89.011a2.89 2.89 0 0 0 2.924-2.924l-.01-.89.636-.622a2.89 2.89 0 0 0 0-4.134l-.637-.622.011-.89a2.89 2.89 0 0 0-2.924-2.924l-.89.01zm.287 5.984-3 3a.5.5 0 0 1-.708 0l-1.5-1.5a.5.5 0 1 1 .708-.708L7 8.793l2.646-2.647a.5.5 0 0 1 .708.708"/>%0A</svg>';
76
+
77
+ // src/widgets/webwriter-task.ts
78
+ async function arrayBufferToDataUrl(buffer) {
79
+ return new Promise((r) => {
80
+ const reader = new FileReader();
81
+ reader.onload = () => r(reader.result);
82
+ reader.readAsDataURL(new Blob([buffer]));
83
+ });
84
+ }
85
+ async function dataUrlToArrayBuffer(url) {
86
+ return await (await (await fetch(url)).blob()).arrayBuffer();
87
+ }
88
+ function getKeyMaterial(password) {
89
+ let enc = new TextEncoder();
90
+ return window.crypto.subtle.importKey(
91
+ "raw",
92
+ enc.encode(password),
93
+ { name: "PBKDF2" },
94
+ false,
95
+ ["deriveBits", "deriveKey"]
96
+ );
97
+ }
98
+ function getKey(keyMaterial, salt) {
99
+ return window.crypto.subtle.deriveKey(
100
+ {
101
+ "name": "PBKDF2",
102
+ salt,
103
+ "iterations": 1e5,
104
+ "hash": "SHA-256"
105
+ },
106
+ keyMaterial,
107
+ { "name": "AES-GCM", "length": 256 },
108
+ true,
109
+ ["encrypt", "decrypt"]
110
+ );
111
+ }
112
+ function romanOrdinal(num, capitalize = false) {
113
+ let roman = {
114
+ m: 1e3,
115
+ cm: 900,
116
+ d: 500,
117
+ cd: 400,
118
+ c: 100,
119
+ xc: 90,
120
+ l: 50,
121
+ xl: 40,
122
+ x: 10,
123
+ ix: 9,
124
+ v: 5,
125
+ iv: 4,
126
+ i: 1
127
+ };
128
+ let str = "";
129
+ for (let i of Object.keys(roman)) {
130
+ let q = Math.floor(num / roman[i]);
131
+ num -= q * roman[i];
132
+ str += i.repeat(q);
133
+ }
134
+ return capitalize ? str.toUpperCase() : str;
135
+ }
136
+ function alphabeticalOrdinal(num, capitalize = false, alphabet = "abcdefghijklmnopqrstuvwxyz") {
137
+ const a = alphabet[0];
138
+ const k = alphabet.length;
139
+ const str = a.repeat(Math.floor(num / k)) + alphabet[num % k];
140
+ return capitalize ? str.toUpperCase() : str;
141
+ }
142
+ var _activeExplainer_dec, _hintSlotEl_dec, _slotEl_dec, _iv_dec, _salt_dec, _password_dec, _solution_dec, _counter_dec, _hintOpen_dec, _submitted_dec, _directSubmit_dec, _isChanged_dec, _hint_dec, _hints_dec, _a, _WebwriterTask_decorators, _init, _hints, _hint, _isChanged, _submitted, _hintOpen, _counter, _solution, _password, _salt, _iv, _WebwriterTask_instances, encodeSolution_fn, decodeSolution_fn, _slotEl, _hintSlotEl, _activeExplainer;
143
+ _WebwriterTask_decorators = [customElement("webwriter-task")];
144
+ var _WebwriterTask = class _WebwriterTask extends (_a = LitElementWw, _hints_dec = [queryAssignedElements({ slot: "hint" })], _hint_dec = [property({ type: Boolean, attribute: true, reflect: true })], _isChanged_dec = [property({ type: Boolean, state: true, attribute: false, reflect: false })], _directSubmit_dec = [property({ type: Boolean, attribute: false, reflect: true })], _submitted_dec = [property({ type: Boolean, attribute: true, reflect: true })], _hintOpen_dec = [property({ attribute: false, state: true })], _counter_dec = [property({ attribute: true, reflect: true })], _solution_dec = [property({ type: String, attribute: true, reflect: true })], _password_dec = [property({ type: String, attribute: false, reflect: false })], _salt_dec = [property({ type: String, attribute: true, reflect: true })], _iv_dec = [property({ type: String, attribute: true, reflect: true })], _slotEl_dec = [query("slot:not([name])")], _hintSlotEl_dec = [query("slot[name=hint]")], _activeExplainer_dec = [property()], _a) {
145
+ constructor() {
146
+ super(...arguments);
147
+ __runInitializers(_init, 5, this);
148
+ __privateAdd(this, _WebwriterTask_instances);
149
+ __publicField(this, "msg", (str) => this.lang in _WebwriterTask.localization ? _WebwriterTask.localization[this.lang][str] ?? str : str);
150
+ __privateAdd(this, _hints, __runInitializers(_init, 8, this)), __runInitializers(_init, 11, this);
151
+ __privateAdd(this, _hint, __runInitializers(_init, 12, this, false)), __runInitializers(_init, 15, this);
152
+ __privateAdd(this, _isChanged, __runInitializers(_init, 16, this, false)), __runInitializers(_init, 19, this);
153
+ __privateAdd(this, _submitted, __runInitializers(_init, 20, this, false)), __runInitializers(_init, 23, this);
154
+ __publicField(this, "toggleExplainers", () => {
155
+ if (this.explainers.length) {
156
+ this.explainers.forEach((explainer) => explainer.remove());
157
+ this.activeExplainer = void 0;
158
+ } else {
159
+ const solutionExplainer = this.ownerDocument.createElement("webwriter-task-explainer");
160
+ solutionExplainer.slot = "explainer";
161
+ solutionExplainer.id = "solution";
162
+ solutionExplainer.active = true;
163
+ this.append(solutionExplainer);
164
+ this.ownerDocument.getSelection().setBaseAndExtent(solutionExplainer, 0, solutionExplainer, 0);
165
+ this.requestUpdate();
166
+ this.activeExplainer = "solution";
167
+ }
168
+ });
169
+ __privateAdd(this, _hintOpen, __runInitializers(_init, 24, this, false)), __runInitializers(_init, 27, this);
170
+ __privateAdd(this, _counter, __runInitializers(_init, 28, this)), __runInitializers(_init, 31, this);
171
+ __publicField(this, "observer");
172
+ __privateAdd(this, _solution, __runInitializers(_init, 32, this)), __runInitializers(_init, 35, this);
173
+ // @option({type: String, label: {_: "Password"}, description: {_: "Password-protects quiz answers"}})
174
+ __privateAdd(this, _password, __runInitializers(_init, 36, this, "B08bxd82SAOf")), __runInitializers(_init, 39, this);
175
+ __privateAdd(this, _salt, __runInitializers(_init, 40, this)), __runInitializers(_init, 43, this);
176
+ __privateAdd(this, _iv, __runInitializers(_init, 44, this)), __runInitializers(_init, 47, this);
177
+ __privateAdd(this, _slotEl, __runInitializers(_init, 48, this)), __runInitializers(_init, 51, this);
178
+ __privateAdd(this, _hintSlotEl, __runInitializers(_init, 52, this)), __runInitializers(_init, 55, this);
179
+ __publicField(this, "handleHintSlotChange", (e) => {
180
+ if (!this.hasHintElement) {
181
+ this.hintOpen = false;
182
+ this.hint = false;
183
+ }
184
+ });
185
+ __publicField(this, "handleHintKeydown", (e) => {
186
+ console.log(document.getSelection().anchorOffset === 0, this.hints.includes(document.getSelection().anchorNode.parentElement));
187
+ if (e.key === "Backspace" && document.getSelection().anchorOffset === 0 && this.hints.includes(document.getSelection().anchorNode.parentElement)) {
188
+ this.hintOpen = false;
189
+ this.hint = false;
190
+ }
191
+ });
192
+ __publicField(this, "handleSubmit", async () => {
193
+ await __privateMethod(this, _WebwriterTask_instances, decodeSolution_fn).call(this);
194
+ this.answer.reportSolution();
195
+ this.dispatchEvent(new SubmitEvent("submit", { bubbles: true, composed: true }));
196
+ this.activeExplainer = this.explainers[0].id;
197
+ this.submitted = true;
198
+ });
199
+ __publicField(this, "handleReset", () => {
200
+ this.answer.reset && this.answer.reset();
201
+ this.isChanged = false;
202
+ this.submitted = false;
203
+ });
204
+ __publicField(this, "handleAnswerChange", async (e) => {
205
+ this.isChanged = true;
206
+ if (this.isContentEditable) {
207
+ __privateMethod(this, _WebwriterTask_instances, encodeSolution_fn).call(this);
208
+ }
209
+ });
210
+ __publicField(this, "handleSlotChange", (e) => {
211
+ this.requestUpdate();
212
+ if (this.isContentEditable) {
213
+ const solution = __privateMethod(this, _WebwriterTask_instances, decodeSolution_fn).call(this) ?? {};
214
+ Object.entries(solution).forEach(([k, v]) => {
215
+ this.answer[k] = v;
216
+ });
217
+ }
218
+ });
219
+ __privateAdd(this, _activeExplainer, __runInitializers(_init, 56, this)), __runInitializers(_init, 59, this);
220
+ }
221
+ get hasHintElement() {
222
+ return this.hints.length > 0;
223
+ }
224
+ get hasHintContent() {
225
+ return this.hints.some((hint) => hint.innerText.trim() !== "");
226
+ }
227
+ get directSubmit() {
228
+ return !this.closest("webwriter-quiz");
229
+ }
230
+ set directSubmit(value) {
231
+ return;
232
+ }
233
+ toggleHint() {
234
+ this.hintOpen = !this.hintOpen;
235
+ if (this.isContentEditable && this.hintOpen) {
236
+ this.hint = true;
237
+ if (!this.hasHintElement) {
238
+ const hintEl = this.ownerDocument.createElement("webwriter-task-hint");
239
+ hintEl.slot = "hint";
240
+ this.answer.insertAdjacentElement("beforebegin", hintEl);
241
+ this.ownerDocument.getSelection().setBaseAndExtent(hintEl, 0, hintEl, 0);
242
+ }
243
+ } else if (this.isContentEditable && !this.hintOpen) {
244
+ if (!this.hasHintContent) {
245
+ this.hint = false;
246
+ this.hintSlotEl.assignedElements().forEach((el) => el.remove());
247
+ }
248
+ }
249
+ }
250
+ get explainers() {
251
+ return Array.from(this.querySelectorAll("webwriter-task-explainer"));
252
+ }
253
+ get index() {
254
+ return [...this?.parentElement?.children ?? []].indexOf(this);
255
+ }
256
+ get ordinalExpr() {
257
+ if (this.index === void 0 || this.index === -1) {
258
+ return void 0;
259
+ }
260
+ if (this.counter === "number") {
261
+ return `${this.index + 1}.`;
262
+ } else if (this.counter === "roman") {
263
+ return `${romanOrdinal(this.index + 1)}.`;
264
+ } else if (this.counter === "roman-capitalized") {
265
+ return `${romanOrdinal(this.index + 1, true)}.`;
266
+ } else if (this.counter === "alphabetical") {
267
+ return `${alphabeticalOrdinal(this.index)}.`;
268
+ } else if (this.counter === "alphabetical-capitalized") {
269
+ return `${alphabeticalOrdinal(this.index, true)}.`;
270
+ }
271
+ }
272
+ connectedCallback() {
273
+ super.connectedCallback();
274
+ this.observer = new MutationObserver(() => this.requestUpdate());
275
+ this.parentElement && this.observer.observe(this.parentElement, { childList: true });
276
+ this.addEventListener("keydown", (e) => this.handleHintKeydown(e));
277
+ }
278
+ firstUpdated(_changedProperties) {
279
+ if (this.isContentEditable) {
280
+ __privateMethod(this, _WebwriterTask_instances, decodeSolution_fn).call(this);
281
+ }
282
+ }
283
+ disconnectedCallback() {
284
+ super.disconnectedCallback();
285
+ this.observer.disconnect();
286
+ }
287
+ checkSolution() {
288
+ const solution = __privateMethod(this, _WebwriterTask_instances, decodeSolution_fn).call(this);
289
+ return Object.entries(solution).every(([k, v]) => {
290
+ return JSON.stringify(this.answer[k]) === JSON.stringify(v);
291
+ });
292
+ }
293
+ reportSolution() {
294
+ this.answer.reportSolution(__privateMethod(this, _WebwriterTask_instances, decodeSolution_fn).call(this));
295
+ }
296
+ get answer() {
297
+ return this.slotEl?.assignedElements()[0];
298
+ }
299
+ selectExplainer(id) {
300
+ const explainer = this.explainers.find((node) => node.id === id);
301
+ explainer.active = true;
302
+ this.explainers.filter((node) => node.id !== id).forEach((node) => node.active = false);
303
+ this.activeExplainer = id;
304
+ setTimeout(() => this.ownerDocument.getSelection().setBaseAndExtent(explainer, 0, explainer, 0));
305
+ }
306
+ get explainerLabels() {
307
+ return {
308
+ "solution": "Explainer",
309
+ "else": "Else"
310
+ };
311
+ }
312
+ render() {
313
+ return html`
314
+ <header>
315
+ <span>${this.ordinalExpr}</span>
316
+ <slot name="prompt"></slot>
317
+ <div id="task-buttons">
318
+ <sl-icon-button class="author-only" id="feedback" src=${!this.explainers.length ? patch_check_default : patch_check_fill_default} @click=${() => this.toggleExplainers()}></sl-icon-button>
319
+ <sl-popup id="hint-popup" ?active=${this.hintOpen} placement="left" arrow auto-size shift @selectstart=${(e) => e.stopImmediatePropagation()}>
320
+ <sl-icon-button class="author-only" slot="anchor" id="hint" src=${!this.hasHintContent && !this.hintOpen ? patch_question_default : patch_question_fill_default} @click=${() => this.toggleHint()}></sl-icon-button>
321
+ <div id="hint-content">
322
+ <slot name="hint" @slotchange=${this.handleHintSlotChange}></slot>
323
+ </div>
324
+ </sl-popup>
325
+ </div>
326
+ </header>
327
+ <slot @ww-answer-change=${this.handleAnswerChange} @slotchange=${this.handleSlotChange} ?inert=${this.submitted}></slot>
328
+ <sl-tab-group id="explainer-group" placement="end" ?data-empty=${!this.explainers.length} ?data-single=${this.explainers.length === 1}>
329
+ ${this.explainers.map((explainer, i) => html`<sl-tab ?active=${this.activeExplainer === explainer.id} slot="nav" @click=${() => this.selectExplainer(explainer.id)}>${this.explainerLabels[explainer.id] ?? explainer.id}</sl-tab>`)}
330
+ <slot name="explainer" style=${styleMap({ "--ww-placeholder": `"${this.msg("Explanation")}"` })}></slot>
331
+ </sl-tab-group>
332
+ ${!this.directSubmit || !this.answer?.reportSolution ? null : html`
333
+ <sl-button-group class="user-only user-actions">
334
+ <sl-button id="submit" @click=${this.handleSubmit}>Check your answers</sl-button>
335
+ <sl-button ?disabled=${!this.isChanged && !this.submitted} id="reset" class="user-only" @click=${this.handleReset}>Try again</sl-button>
336
+ </sl-button-group>
337
+ `}
338
+ `;
339
+ }
340
+ };
341
+ _init = __decoratorStart(_a);
342
+ _hints = new WeakMap();
343
+ _hint = new WeakMap();
344
+ _isChanged = new WeakMap();
345
+ _submitted = new WeakMap();
346
+ _hintOpen = new WeakMap();
347
+ _counter = new WeakMap();
348
+ _solution = new WeakMap();
349
+ _password = new WeakMap();
350
+ _salt = new WeakMap();
351
+ _iv = new WeakMap();
352
+ _WebwriterTask_instances = new WeakSet();
353
+ encodeSolution_fn = async function() {
354
+ const value = this.answer.solution;
355
+ console.log(value);
356
+ let keyMaterial = await getKeyMaterial(this.password);
357
+ let salt = window.crypto.getRandomValues(new Uint8Array(16));
358
+ let iv = window.crypto.getRandomValues(new Uint8Array(12));
359
+ let key = await getKey(keyMaterial, salt);
360
+ let encoder = new TextEncoder();
361
+ let encodedMessage = encoder.encode(JSON.stringify(value));
362
+ const solution = await window.crypto.subtle.encrypt(
363
+ { name: "AES-GCM", iv },
364
+ key,
365
+ encodedMessage
366
+ );
367
+ this.solution = await arrayBufferToDataUrl(solution);
368
+ this.iv = await arrayBufferToDataUrl(iv);
369
+ this.salt = await arrayBufferToDataUrl(salt);
370
+ };
371
+ decodeSolution_fn = async function() {
372
+ if (!this.solution) {
373
+ return;
374
+ }
375
+ const encodedSolution = await dataUrlToArrayBuffer(this.solution);
376
+ const iv = await dataUrlToArrayBuffer(this.iv);
377
+ const salt = await dataUrlToArrayBuffer(this.salt);
378
+ let keyMaterial = await getKeyMaterial(this.password);
379
+ let key = await getKey(keyMaterial, new Uint8Array(salt));
380
+ try {
381
+ const solutionBuffer = await window.crypto.subtle.decrypt({ name: "AES-GCM", iv }, key, encodedSolution);
382
+ let decoder = new TextDecoder();
383
+ const solution = JSON.parse(decoder.decode(solutionBuffer));
384
+ this.answer.solution = solution;
385
+ } catch (err) {
386
+ console.error(err);
387
+ throw new Error("Invalid password");
388
+ }
389
+ };
390
+ _slotEl = new WeakMap();
391
+ _hintSlotEl = new WeakMap();
392
+ _activeExplainer = new WeakMap();
393
+ __decorateElement(_init, 4, "hints", _hints_dec, _WebwriterTask, _hints);
394
+ __decorateElement(_init, 4, "hint", _hint_dec, _WebwriterTask, _hint);
395
+ __decorateElement(_init, 4, "isChanged", _isChanged_dec, _WebwriterTask, _isChanged);
396
+ __decorateElement(_init, 3, "directSubmit", _directSubmit_dec, _WebwriterTask);
397
+ __decorateElement(_init, 4, "submitted", _submitted_dec, _WebwriterTask, _submitted);
398
+ __decorateElement(_init, 4, "hintOpen", _hintOpen_dec, _WebwriterTask, _hintOpen);
399
+ __decorateElement(_init, 4, "counter", _counter_dec, _WebwriterTask, _counter);
400
+ __decorateElement(_init, 4, "solution", _solution_dec, _WebwriterTask, _solution);
401
+ __decorateElement(_init, 4, "password", _password_dec, _WebwriterTask, _password);
402
+ __decorateElement(_init, 4, "salt", _salt_dec, _WebwriterTask, _salt);
403
+ __decorateElement(_init, 4, "iv", _iv_dec, _WebwriterTask, _iv);
404
+ __decorateElement(_init, 4, "slotEl", _slotEl_dec, _WebwriterTask, _slotEl);
405
+ __decorateElement(_init, 4, "hintSlotEl", _hintSlotEl_dec, _WebwriterTask, _hintSlotEl);
406
+ __decorateElement(_init, 4, "activeExplainer", _activeExplainer_dec, _WebwriterTask, _activeExplainer);
407
+ _WebwriterTask = __decorateElement(_init, 0, "WebwriterTask", _WebwriterTask_decorators, _WebwriterTask);
408
+ __publicField(_WebwriterTask, "localization", {});
409
+ __publicField(_WebwriterTask, "scopedElements", {
410
+ "sl-icon-button": SlIconButton,
411
+ "sl-details": SlDetails,
412
+ "sl-popup": SlPopup,
413
+ "sl-button": SlButton,
414
+ "sl-button-group": SlButtonGroup,
415
+ "sl-tab-group": SlTabGroup,
416
+ "sl-tab": SlTab,
417
+ "sl-tab-panel": SlTabPanel
418
+ });
419
+ __publicField(_WebwriterTask, "styles", css`
420
+ :host {
421
+ display: flex !important;
422
+ flex-direction: column;
423
+ gap: 1rem;
424
+ position: relative;
425
+ z-index: 1;
426
+ }
427
+
428
+
429
+ :host(:not([hint])) details {
430
+ display: none;
431
+ }
432
+
433
+ sl-tooltip::part(base__popup) {
434
+ cursor: text;
435
+ }
436
+
437
+ #hint-popup {
438
+ --arrow-color: var(--sl-color-neutral-700);
439
+ z-index: 1000;
440
+ }
441
+
442
+ #hint-popup::part(popup) {
443
+ z-index: 100;
444
+ max-width: 200px;
445
+ }
446
+
447
+ :host(:not([contenteditable=true]):not([contenteditable=""]):not([hint])) #hint {
448
+ display: none;
449
+ }
450
+
451
+ :host(:not([contenteditable=true]):not([contenteditable=""])) .author-only {
452
+ display: none;
453
+ }
454
+
455
+ :host(:is([contenteditable=true], [contenteditable=""])) .user-only {
456
+ display: none;
457
+ }
458
+
459
+ :host(:not([contenteditable=true]):not([contenteditable=""])) {
460
+ ::slotted([slot=prompt]:empty) {
461
+ display: none;
462
+ }
463
+ }
464
+
465
+ :host(:not([submitted]):not([contenteditable=true]):not([contenteditable=""])) #explainer-group {
466
+ display: none;
467
+ }
468
+
469
+ #task-buttons {
470
+ position: absolute;
471
+ right: 0;
472
+ top: 0;
473
+ background: rgba(255, 255, 255, 0.9);
474
+ user-select: none;
475
+ z-index: 100;
476
+ }
477
+
478
+ #hint-content {
479
+ background: var(--sl-color-neutral-700);
480
+ color: var(--sl-color-neutral-50);
481
+ min-width: 2ch;
482
+ font-size: 0.75rem;
483
+ padding: 0.5rem;
484
+ border-radius: 4px;
485
+ user-select: auto;
486
+ }
487
+
488
+ ::slotted([slot=explainer]:not([active])) {
489
+ display: none !important;
490
+ }
491
+
492
+ sl-tab-group {
493
+ &[data-empty] {
494
+ display: none;
495
+ }
496
+
497
+ &[data-single] sl-tab {
498
+ display: none;
499
+ }
500
+
501
+ & sl-tab::part(base) {
502
+ padding: 10px;
503
+ }
504
+
505
+ &::part(tabs) {
506
+ height: 100px;
507
+ margin-left: -1px;
508
+ z-index: 10;
509
+ }
510
+
511
+ & ::slotted([name=explainer]) {
512
+ height: 100%;
513
+ }
514
+ }
515
+
516
+ header {
517
+ display: flex;
518
+ flex-direction: row;
519
+ gap: 1ch;
520
+
521
+ & span:empty {
522
+ display: none;
523
+ }
524
+
525
+ & slot {
526
+ display: block;
527
+ flex-grow: 1;
528
+ }
529
+ }
530
+
531
+ .user-actions {
532
+ & #submit {
533
+ flex-grow: 3;
534
+ }
535
+
536
+ & #reset {
537
+ flex-grow: 1;
538
+ }
539
+ }
540
+
541
+ `);
542
+ __runInitializers(_init, 1, _WebwriterTask);
543
+ var WebwriterTask = _WebwriterTask;
544
+ export {
545
+ WebwriterTask
546
+ };