@webwriter/quiz 1.1.5 → 2.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 (165) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +778 -0
  3. package/assets/icons/grip-horizontal.svg +8 -0
  4. package/assets/icons/grip-vertical.svg +8 -0
  5. package/assets/icons/truefalse.svg +6 -0
  6. package/custom-elements.json +2779 -0
  7. package/custom.d.ts +5 -1
  8. package/dist/api/index.d.ts +27 -0
  9. package/dist/api/index.js +40 -0
  10. package/dist/migrate.js +1434 -0
  11. package/dist/widgets/webwriter-choice-item.js +4095 -3818
  12. package/dist/widgets/webwriter-choice.js +2179 -5598
  13. package/dist/widgets/webwriter-gap-item.js +3987 -0
  14. package/dist/widgets/webwriter-gap.js +2908 -0
  15. package/dist/widgets/webwriter-mark.js +4347 -3368
  16. package/dist/widgets/webwriter-order-item.js +4038 -3197
  17. package/dist/widgets/webwriter-order.js +2885 -4200
  18. package/dist/widgets/webwriter-pairing-item.js +1070 -2330
  19. package/dist/widgets/webwriter-pairing.js +2968 -4231
  20. package/dist/widgets/webwriter-quiz-hint.js +2469 -0
  21. package/dist/widgets/webwriter-quiz.js +3337 -4364
  22. package/dist/widgets/webwriter-speech.js +6100 -5120
  23. package/dist/widgets/webwriter-task-prompt.js +4787 -2068
  24. package/dist/widgets/webwriter-task.js +2264 -8157
  25. package/dist/widgets/webwriter-text.js +4075 -4132
  26. package/dist/widgets/webwriter-true-false.js +4674 -0
  27. package/editing-config.json +106 -0
  28. package/lit-localize.json +20 -14
  29. package/localization/de.xlf +395 -65
  30. package/localization/es.xlf +396 -61
  31. package/localization/fr.xlf +396 -61
  32. package/localization/generated/de.ts +97 -15
  33. package/localization/generated/es.ts +97 -15
  34. package/localization/generated/fr.ts +98 -16
  35. package/localization/generated/index.d.ts +5 -0
  36. package/localization/generated/it.ts +96 -14
  37. package/localization/generated/locale-codes.js +0 -48
  38. package/localization/generated/nl.ts +99 -17
  39. package/localization/it.xlf +396 -61
  40. package/localization/nl.xlf +396 -61
  41. package/package.json +120 -254
  42. package/scripts/apply-translations.mjs +97 -0
  43. package/src/api/index.ts +72 -0
  44. package/src/lib/artboard.ts +686 -0
  45. package/src/lib/draggable-grid.ts +432 -0
  46. package/src/lib/encrypted-property.ts +202 -0
  47. package/src/lib/hint-popup.ts +152 -0
  48. package/src/lib/utils.ts +97 -0
  49. package/src/lib/webwriter-quirks.ts +121 -0
  50. package/src/migrate/index.ts +622 -0
  51. package/src/migrate/legacy-solution.ts +362 -0
  52. package/src/snippets/order.html +8 -7
  53. package/src/widgets/choice/webwriter-choice-item.ts +316 -0
  54. package/src/widgets/choice/webwriter-choice.ts +328 -0
  55. package/src/widgets/choice/webwriter-true-false.ts +113 -0
  56. package/src/widgets/dnd/webwriter-dnd-draggable.ts +28 -0
  57. package/src/widgets/dnd/webwriter-dnd-dropzone.ts +9 -0
  58. package/src/widgets/dnd/webwriter-dnd.ts +36 -0
  59. package/src/widgets/gap/webwriter-gap-item.ts +250 -0
  60. package/src/widgets/gap/webwriter-gap.ts +447 -0
  61. package/src/widgets/order/webwriter-order-item.ts +243 -0
  62. package/src/widgets/order/webwriter-order.ts +282 -0
  63. package/src/widgets/pairing/webwriter-pairing-item.ts +46 -0
  64. package/src/widgets/pairing/webwriter-pairing.ts +934 -0
  65. package/src/widgets/speech/audio-player.ts +325 -0
  66. package/src/widgets/speech/audio-recorder.ts +285 -0
  67. package/src/widgets/speech/waveform.ts +113 -0
  68. package/src/widgets/speech/webwriter-speech.ts +87 -0
  69. package/src/widgets/webwriter-mark.ts +366 -424
  70. package/src/widgets/webwriter-quiz-hint.ts +36 -0
  71. package/src/widgets/webwriter-quiz.ts +318 -280
  72. package/src/widgets/webwriter-task-prompt.ts +43 -18
  73. package/src/widgets/webwriter-task.ts +212 -551
  74. package/src/widgets/webwriter-text.ts +286 -172
  75. package/tsconfig.api.json +12 -0
  76. package/tsconfig.json +7 -6
  77. package/dist/widgets/webwriter-choice.css +0 -444
  78. package/dist/widgets/webwriter-cloze-gap.css +0 -444
  79. package/dist/widgets/webwriter-cloze-gap.js +0 -5727
  80. package/dist/widgets/webwriter-cloze.css +0 -444
  81. package/dist/widgets/webwriter-cloze.js +0 -3653
  82. package/dist/widgets/webwriter-mark.css +0 -444
  83. package/dist/widgets/webwriter-order.css +0 -444
  84. package/dist/widgets/webwriter-pairing-item.css +0 -444
  85. package/dist/widgets/webwriter-pairing.css +0 -444
  86. package/dist/widgets/webwriter-quiz.css +0 -444
  87. package/dist/widgets/webwriter-task-explainer.css +0 -444
  88. package/dist/widgets/webwriter-task-explainer.js +0 -2769
  89. package/dist/widgets/webwriter-task-hint.css +0 -444
  90. package/dist/widgets/webwriter-task-hint.js +0 -2708
  91. package/dist/widgets/webwriter-task.css +0 -444
  92. package/dist/widgets/webwriter-text.css +0 -444
  93. package/localization/bg.xlf +0 -72
  94. package/localization/cs.xlf +0 -72
  95. package/localization/da.xlf +0 -72
  96. package/localization/el.xlf +0 -72
  97. package/localization/et.xlf +0 -72
  98. package/localization/fi.xlf +0 -72
  99. package/localization/generated/bg.ts +0 -31
  100. package/localization/generated/cs.ts +0 -31
  101. package/localization/generated/da.ts +0 -31
  102. package/localization/generated/el.ts +0 -31
  103. package/localization/generated/et.ts +0 -31
  104. package/localization/generated/fi.ts +0 -31
  105. package/localization/generated/hu.ts +0 -31
  106. package/localization/generated/id.ts +0 -31
  107. package/localization/generated/ja.ts +0 -31
  108. package/localization/generated/ko.ts +0 -31
  109. package/localization/generated/lt.ts +0 -31
  110. package/localization/generated/lv.ts +0 -31
  111. package/localization/generated/nb.ts +0 -31
  112. package/localization/generated/pl.ts +0 -31
  113. package/localization/generated/pt-BR.ts +0 -31
  114. package/localization/generated/pt-PT.ts +0 -31
  115. package/localization/generated/ro.ts +0 -31
  116. package/localization/generated/ru.ts +0 -31
  117. package/localization/generated/sk.ts +0 -31
  118. package/localization/generated/sl.ts +0 -31
  119. package/localization/generated/sv.ts +0 -31
  120. package/localization/generated/tr.ts +0 -31
  121. package/localization/generated/uk.ts +0 -31
  122. package/localization/generated/zh-hans.ts +0 -31
  123. package/localization/hu.xlf +0 -72
  124. package/localization/id.xlf +0 -72
  125. package/localization/ja.xlf +0 -72
  126. package/localization/ko.xlf +0 -72
  127. package/localization/lt.xlf +0 -72
  128. package/localization/lv.xlf +0 -72
  129. package/localization/nb.xlf +0 -72
  130. package/localization/pl.xlf +0 -72
  131. package/localization/pt-BR.xlf +0 -72
  132. package/localization/pt-PT.xlf +0 -72
  133. package/localization/ro.xlf +0 -72
  134. package/localization/ru.xlf +0 -72
  135. package/localization/sk.xlf +0 -72
  136. package/localization/sl.xlf +0 -72
  137. package/localization/sv.xlf +0 -72
  138. package/localization/tr.xlf +0 -72
  139. package/localization/uk.xlf +0 -72
  140. package/localization/zh-hans.xlf +0 -72
  141. package/src/lib/combobox.ts +0 -456
  142. package/src/lib/highlighter-fill.svg +0 -6
  143. package/src/snippets/Beispiel-Choice.html +0 -57
  144. package/src/snippets/Beispiel-Mark.html +0 -14
  145. package/src/snippets/Beispiel-Order.html +0 -52
  146. package/src/snippets/Beispiel-Text.html +0 -20
  147. package/src/snippets/blank.html +0 -1
  148. package/src/snippets/choice.html +0 -8
  149. package/src/snippets/cloze.html +0 -4
  150. package/src/snippets/mark.html +0 -4
  151. package/src/snippets/pairing.html +0 -10
  152. package/src/snippets/speech.html +0 -4
  153. package/src/snippets/text.html +0 -4
  154. package/src/snippets/wordsearch.html +0 -4
  155. package/src/widgets/webwriter-choice-item.ts +0 -257
  156. package/src/widgets/webwriter-choice.ts +0 -353
  157. package/src/widgets/webwriter-cloze-gap.ts +0 -216
  158. package/src/widgets/webwriter-cloze.ts +0 -136
  159. package/src/widgets/webwriter-order-item.ts +0 -441
  160. package/src/widgets/webwriter-order.ts +0 -327
  161. package/src/widgets/webwriter-pairing-item.ts +0 -161
  162. package/src/widgets/webwriter-pairing.ts +0 -193
  163. package/src/widgets/webwriter-speech.ts +0 -273
  164. package/src/widgets/webwriter-task-explainer.ts +0 -43
  165. package/src/widgets/webwriter-task-hint.ts +0 -23
@@ -1,273 +0,0 @@
1
- import {html, css, PropertyValueMap} from "lit"
2
- import {LitElementWw} from "@webwriter/lit"
3
- import {customElement, property, query} from "lit/decorators.js"
4
- import "@shoelace-style/shoelace/dist/themes/light.css"
5
-
6
- import IconMic from "bootstrap-icons/icons/mic.svg"
7
- import IconMicFill from "bootstrap-icons/icons/mic-fill.svg"
8
- import IconStopFill from "bootstrap-icons/icons/stop-fill.svg"
9
- import IconTrash from "bootstrap-icons/icons/trash.svg"
10
- import IconPlay from "bootstrap-icons/icons/play.svg"
11
- import IconPause from "bootstrap-icons/icons/pause.svg"
12
- import IconVolumeDown from "bootstrap-icons/icons/volume-down.svg"
13
- import SlButton from "@shoelace-style/shoelace/dist/components/button/button.component.js"
14
- import SlRange from "@shoelace-style/shoelace/dist/components/range/range.component.js"
15
- import SlButtonGroup from "@shoelace-style/shoelace/dist/components/button-group/button-group.component.js"
16
- import SlIcon from "@shoelace-style/shoelace/dist/components/icon/icon.component.js"
17
- import SlFormatDate from "@shoelace-style/shoelace/dist/components/format-date/format-date.component.js"
18
- import SlPopup from "@shoelace-style/shoelace/dist/components/popup/popup.component.js"
19
-
20
- declare global {interface HTMLElementTagNameMap {
21
- "webwriter-speech": WebwriterSpeech;
22
- }}
23
-
24
- import LOCALIZE from "../../localization/generated"
25
- import {msg} from "@lit/localize"
26
-
27
- @customElement("webwriter-speech")
28
- export class WebwriterSpeech extends LitElementWw {
29
-
30
- localize = LOCALIZE
31
-
32
- static scopedElements = {
33
- "sl-button": SlButton,
34
- "sl-icon": SlIcon,
35
- "sl-button-group": SlButtonGroup,
36
- "sl-range": SlRange,
37
- "sl-format-date": SlFormatDate,
38
- "sl-popup": SlPopup
39
- }
40
-
41
- static styles = css`
42
-
43
- @keyframes blinker {
44
- 50% {
45
- opacity: 0;
46
- }
47
- }
48
-
49
- sl-icon {
50
- height: 20px;
51
- width: 20px;
52
- }
53
-
54
- sl-button-group {
55
- width: 100%;
56
- }
57
-
58
- #record {
59
- position: relative;
60
- #recording-indicator {
61
- background: darkred;
62
- border-radius: 100%;
63
- height: 10px;
64
- width: 10px;
65
- position: absolute;
66
- top: 5px;
67
- right: 5px;
68
- animation: blinker 1.25s linear infinite;
69
- }
70
- }
71
-
72
- #record:hover .idle {
73
- display: none;
74
- }
75
-
76
- :host([recording]) #record .torecord, :host(:not([recording])) #record:not(:hover) .torecord {
77
- display: none;
78
- }
79
-
80
- :host(:not([recording])) #record .tostop, :host([recording]) #record:not(:hover) .tostop {
81
- display: none;
82
- }
83
-
84
- :host(:not([recording])) #recording-indicator {
85
- display: none;
86
- }
87
-
88
- #playback {
89
- width: 100%;
90
- display: flex;
91
- flex-direction: row;
92
- align-items: center;
93
- border-top: 1px solid var(--sl-color-gray-300);
94
- border-bottom: 1px solid var(--sl-color-gray-300);
95
- padding: 0 1ch;
96
- gap: 1ch;
97
- color: var(--sl-color-gray-800);
98
- font-size: var(--sl-font-size-small);
99
- user-select: none;
100
-
101
- sl-range {
102
- flex-grow: 1;
103
- display: flex;
104
- flex-direction: row;
105
- align-items: center;
106
-
107
- &::part(form-control) {
108
- width: 100%;
109
- }
110
- }
111
- }
112
-
113
- :host(:not([src])) #playback {
114
- opacity: 0.5;
115
- }
116
-
117
- sl-button {
118
- &::part(label) {
119
- display: flex;
120
- flex-direction: row;
121
- align-items: center;
122
- gap: 1ch;
123
- }
124
- }
125
-
126
- sl-tooltip {
127
- z-index: 1;
128
- }
129
-
130
- #volume {
131
- --arrow-color: var(--sl-color-gray-600);
132
- &::part(popup) {
133
- background: var(--arrow-color);
134
- height: 30px;
135
- padding: 1ch;
136
- }
137
- }
138
- `
139
-
140
- mediaRecorder: MediaRecorder
141
- chunks = [] as Blob[]
142
-
143
- @property({type: Boolean, attribute: true})
144
- accessor loading = false
145
-
146
- @property({type: String, attribute: true, reflect: true})
147
- accessor src: string
148
-
149
- firstUpdated() {
150
- const evs = ["abort", "canplay", "canplaythrough", "durationchange", "emptied", "ended", "error", "loadeddata", "loadedmetadata", "loadstart", "pause", "play", "playing", "progress", "ratechange", "resize", "seeked", "seeking", "stalled", "suspend", "timeupdate", "volumechange", "waiting"] as const
151
- evs.forEach(k => this.audioEl.addEventListener(k, ()=>this.requestUpdate()))
152
- }
153
-
154
- connectedCallback(): void {
155
- super.connectedCallback()
156
- }
157
-
158
- async initializeRecorder() {
159
- if(!this.mediaRecorder) {
160
- this.loading = true
161
- try {
162
- const stream = await navigator.mediaDevices.getUserMedia({audio: true})
163
- this.mediaRecorder = new MediaRecorder(stream)
164
- this.mediaRecorder.addEventListener("start", e => {
165
- this.requestUpdate("recording")
166
- })
167
- this.mediaRecorder.addEventListener("dataavailable", e => {
168
- this.chunks.push(e.data)
169
- })
170
- this.mediaRecorder.addEventListener("stop", async e => {
171
- const blob = new Blob(this.chunks, {type: "audio/ogg; codecs=opus"})
172
- this.chunks = []
173
- this.src = URL.createObjectURL(blob)
174
- const reader = new FileReader()
175
- reader.readAsDataURL(blob)
176
- reader.addEventListener("load", e => {
177
- this.src = reader.result as string
178
- this.requestUpdate("recording")
179
- })
180
- })
181
- }
182
- finally {
183
- this.loading = false
184
- }
185
- }
186
- }
187
-
188
- toggleRecording = async () => {
189
- if(this.mediaRecorder?.state === "recording") {
190
- this.mediaRecorder.stop()
191
- this.mediaRecorder.stream.getTracks().forEach(track => track.stop())
192
- }
193
- else {
194
- await this.initializeRecorder()
195
- this.mediaRecorder.start()
196
- }
197
- }
198
-
199
- @query("audio")
200
- accessor audioEl: HTMLAudioElement
201
-
202
- get duration() {
203
- const d = this.audioEl?.duration
204
- return !Number.isNaN(d) && Number.isFinite(d)? d: 0
205
- }
206
-
207
- get currentTime() {
208
- return this.audioEl?.currentTime
209
- }
210
-
211
- get playing() {
212
- return !this.audioEl?.paused && !this.audioEl?.ended
213
- }
214
-
215
-
216
- get recording() {
217
- return this.mediaRecorder?.state === "recording"
218
- }
219
-
220
- @property({type: Boolean, attribute: true, reflect: true})
221
- set recording(value: boolean) {
222
- return
223
- }
224
-
225
- get volume() {
226
- return Math.round(this.audioEl?.volume * 100)
227
- }
228
-
229
- set volume(value: number) {
230
- this.audioEl.volume = value / 100
231
- }
232
-
233
- togglePlay = () => {
234
- !this.playing? this.audioEl.play(): this.audioEl.pause()
235
- }
236
-
237
- @property({type: Boolean})
238
- accessor volumeOpen = false
239
-
240
- render() {
241
- return html`<sl-button-group>
242
- <sl-button id="record" @click=${this.toggleRecording} ?loading=${this.loading} ?disabled=${this.loading}>
243
- <sl-icon class="idle" src=${IconMic}></sl-icon>
244
- <sl-icon class="torecord" src=${IconMicFill}></sl-icon>
245
- <sl-icon class="tostop" src=${IconStopFill}></sl-icon>
246
- <div id="recording-indicator"></div>
247
- </sl-button>
248
- <sl-button id="playpause" ?disabled=${this.loading || !this.src} @click=${this.togglePlay}>
249
- <sl-icon src=${!this.playing? IconPlay: IconPause}></sl-icon>
250
- </sl-button>
251
- <div id="playback">
252
- <audio src=${this.src} preload="metadata"></audio>
253
- <div>
254
- <sl-format-date .date=${new Date(this.currentTime * 1000)} minute="numeric" second="numeric"></sl-format-date>
255
- /
256
- <sl-format-date .date=${new Date(this.duration * 1000)} minute="numeric" second="numeric"></sl-format-date>
257
- </div>
258
- <sl-range ?disabled=${this.loading || !this.src}></sl-range>
259
- </div>
260
- <sl-popup id="volume" ?active=${this.volumeOpen} hoist strategy="fixed" arrow distance="6">
261
- <sl-button ?disabled=${this.loading || !this.src} slot="anchor" @click=${() => this.volumeOpen = !this.volumeOpen}>
262
- <sl-icon src=${IconVolumeDown}></sl-icon>
263
- </sl-button>
264
- <sl-range ?disabled=${this.loading || !this.src} id="volume-range" value=${this.volume} @sl-change=${(e: any) => this.volume = e.target.value}>
265
-
266
- </sl-range>
267
- </sl-popup>
268
- <sl-button ?disabled=${this.loading || !this.src} id="delete" @click=${() => this.src = undefined}>
269
- <sl-icon src=${IconTrash}></sl-icon>
270
- </sl-button>
271
- </sl-button-group>`
272
- }
273
- }
@@ -1,43 +0,0 @@
1
- import {html, css} from "lit"
2
- import {LitElementWw} from "@webwriter/lit"
3
- import {customElement, property} from "lit/decorators.js"
4
- import "@shoelace-style/shoelace/dist/themes/light.css"
5
- import { styleMap } from "lit/directives/style-map.js";
6
-
7
- import LOCALIZE from "../../localization/generated"
8
- import {msg} from "@lit/localize"
9
-
10
- declare global {interface HTMLElementTagNameMap {
11
- "webwriter-task-explainer": WebwriterTaskExplainer;
12
- }}
13
-
14
- @customElement("webwriter-task-explainer")
15
- export class WebwriterTaskExplainer extends LitElementWw {
16
-
17
- localize = LOCALIZE
18
-
19
- @property({type: Boolean, attribute: true, reflect: true})
20
- accessor active = false
21
-
22
- static styles = css`
23
- :host {
24
- background: var(--sl-color-gray-100);
25
- border: 2px solid var(--sl-color-gray-200);
26
- box-sizing: border-box;
27
- padding: 10px;
28
- font-size: 0.8rem;
29
- height: 100px;
30
- min-height: 100px;
31
- overflow-y: auto;
32
- scrollbar-width: thin;
33
- resize: vertical;
34
- display: block;
35
- }
36
- `
37
-
38
- render() {
39
- return html`<slot>
40
-
41
- </slot>`
42
- }
43
- }
@@ -1,23 +0,0 @@
1
- import {html} from "lit"
2
- import {LitElementWw} from "@webwriter/lit"
3
- import {customElement} from "lit/decorators.js"
4
- import "@shoelace-style/shoelace/dist/themes/light.css"
5
-
6
- import LOCALIZE from "../../localization/generated"
7
- import {msg} from "@lit/localize"
8
-
9
- declare global {interface HTMLElementTagNameMap {
10
- "webwriter-task-hint": WebwriterTaskHint;
11
- }}
12
-
13
- @customElement("webwriter-task-hint")
14
- export class WebwriterTaskHint extends LitElementWw {
15
-
16
- localize = LOCALIZE
17
-
18
- render() {
19
- return html`<slot>
20
-
21
- </slot>`
22
- }
23
- }