@webwriter/quiz 1.0.2 → 1.0.4

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 (45) hide show
  1. package/LICENSE +6 -6
  2. package/custom.d.ts +175 -175
  3. package/dist/widgets/webwriter-choice-item.js +3257 -59
  4. package/dist/widgets/webwriter-choice.js +4941 -79
  5. package/dist/widgets/webwriter-cloze-gap.js +4092 -179
  6. package/dist/widgets/webwriter-cloze.js +2415 -36
  7. package/dist/widgets/webwriter-mark.js +2471 -61
  8. package/dist/widgets/webwriter-order-item.js +2447 -68
  9. package/dist/widgets/webwriter-order.js +4990 -135
  10. package/dist/widgets/webwriter-pairing-item.js +1581 -48
  11. package/dist/widgets/webwriter-pairing.js +3686 -72
  12. package/dist/widgets/webwriter-quiz.js +6938 -76
  13. package/dist/widgets/webwriter-speech.js +6265 -76
  14. package/dist/widgets/webwriter-task-explainer.js +1564 -31
  15. package/dist/widgets/webwriter-task-hint.js +1523 -28
  16. package/dist/widgets/webwriter-task-prompt.js +1586 -29
  17. package/dist/widgets/webwriter-task.js +7132 -101
  18. package/dist/widgets/webwriter-text.js +4044 -54
  19. package/package.json +200 -200
  20. package/src/lib/combobox.ts +455 -455
  21. package/src/snippets/choice.html +7 -7
  22. package/src/snippets/cloze.html +3 -3
  23. package/src/snippets/mark.html +3 -3
  24. package/src/snippets/order.html +7 -7
  25. package/src/snippets/pairing.html +9 -9
  26. package/src/snippets/speech.html +3 -3
  27. package/src/snippets/text.html +3 -3
  28. package/src/snippets/wordsearch.html +3 -3
  29. package/src/widgets/webwriter-choice-item.ts +250 -250
  30. package/src/widgets/webwriter-choice.ts +309 -309
  31. package/src/widgets/webwriter-cloze-gap.ts +216 -216
  32. package/src/widgets/webwriter-cloze.ts +135 -135
  33. package/src/widgets/webwriter-mark.ts +434 -434
  34. package/src/widgets/webwriter-order-item.ts +444 -444
  35. package/src/widgets/webwriter-order.ts +272 -272
  36. package/src/widgets/webwriter-pairing-item.ts +155 -155
  37. package/src/widgets/webwriter-pairing.ts +187 -187
  38. package/src/widgets/webwriter-quiz.ts +280 -280
  39. package/src/widgets/webwriter-speech.ts +267 -267
  40. package/src/widgets/webwriter-task-explainer.ts +37 -37
  41. package/src/widgets/webwriter-task-hint.ts +16 -16
  42. package/src/widgets/webwriter-task-prompt.ts +17 -17
  43. package/src/widgets/webwriter-task.ts +543 -543
  44. package/src/widgets/webwriter-text.ts +130 -130
  45. package/tsconfig.json +6 -6
@@ -1,136 +1,136 @@
1
- import {html, css, LitElement} from "lit"
2
- import {LitElementWw} from "@webwriter/lit"
3
- import {customElement, query} from "lit/decorators.js"
4
- import {styleMap} from "lit/directives/style-map.js"
5
-
6
- import SlIconButton from "@shoelace-style/shoelace/dist/components/icon-button/icon-button.component.js"
7
-
8
-
9
- import IconTextarea from "bootstrap-icons/icons/textarea.svg"
10
- import { WebwriterClozeGap } from "./webwriter-cloze-gap.js"
11
- import "@shoelace-style/shoelace/dist/themes/light.css"
12
-
13
- declare global {interface HTMLElementTagNameMap {
14
- "webwriter-cloze": WebwriterCloze;
15
- }}
16
-
17
- @customElement("webwriter-cloze")
18
- export class WebwriterCloze extends LitElementWw {
19
-
20
- static shadowRootOptions: ShadowRootInit = {...LitElementWw.shadowRootOptions, delegatesFocus: false}
21
-
22
- static localization = {}
23
-
24
- msg = (str: string) => this.lang in WebwriterCloze.localization? WebwriterCloze.localization[this.lang][str] ?? str: str
25
-
26
-
27
- static scopedElements = {
28
- "sl-icon-button": SlIconButton
29
- }
30
-
31
- static styles = css`
32
- :host {
33
- min-height: 1rem;
34
- position: relative;
35
- }
36
-
37
- slot {
38
- display: block;
39
- cursor: text;
40
- }
41
-
42
- slot[data-empty]:after {
43
- content: var(--placeholder);
44
- position: absolute;
45
- left: 0;
46
- top: 0;
47
- color: darkgray;
48
- pointer-events: none;
49
- user-select: none;
50
- }
51
-
52
- slot::after, slot::before {
53
- content: ' ';
54
- }
55
-
56
- #add-gap {
57
- position: absolute;
58
- right: 0;
59
- top: 0;
60
- background: rgba(255, 255, 255, 0.85);
61
-
62
- &[data-highlighting]::part(base) {
63
- background: var(--sl-color-primary-100);
64
- }
65
- }
66
-
67
- :host(:not([contenteditable=true]):not([contenteditable=""])) .author-only {
68
- display: none;
69
- }
70
- `
71
-
72
- @query("#add-gap")
73
- accessor addGapButton: SlIconButton
74
-
75
- observer: MutationObserver
76
-
77
- connectedCallback(): void {
78
- super.connectedCallback()
79
- document.addEventListener("selectionchange", e => {
80
- const sel = document.getSelection()
81
- const node = document.getSelection()?.anchorNode
82
- const el = node.nodeType === node.TEXT_NODE? node.parentElement: node as HTMLElement
83
- this.addGapButton.toggleAttribute("data-visible", el?.closest("webwriter-cloze")? true: false)
84
- if(el?.closest("webwriter-cloze") && !sel.isCollapsed) {
85
- this.addGapButton.toggleAttribute("data-highlighting", true)
86
- }
87
- else {
88
- this.addGapButton.toggleAttribute("data-highlighting", false)
89
- }
90
- })
91
- this.observer = new MutationObserver(() => this.requestUpdate())
92
- this.observer.observe(this, {characterData: true, childList: true, subtree: true})
93
- }
94
-
95
-
96
- disconnectedCallback(): void {
97
- super.disconnectedCallback()
98
- this.observer?.disconnect()
99
- }
100
-
101
- toggleGap = () => {
102
- const sel = document.getSelection()
103
- const selectedElement = sel.anchorNode.childNodes.item(sel.anchorOffset)
104
- if(selectedElement?.nodeName.toLowerCase() === "webwriter-cloze-gap") {
105
- const gap = selectedElement as WebwriterClozeGap
106
- selectedElement.replaceWith(document.createTextNode(gap.value))
107
- }
108
- else if(this.contains(sel.anchorNode)) {
109
- if(sel.anchorNode !== this) {
110
- const textContent = sel.toString()
111
- sel.deleteFromDocument()
112
- const textNode = sel.anchorNode as Text
113
- const at = sel.anchorOffset
114
- const clozeGap = document.createElement("webwriter-cloze-gap")
115
- clozeGap.classList.add("webwriter-new")
116
- clozeGap.setAttribute("value", textContent)
117
- const afterTextNode = textNode.splitText(at)
118
- afterTextNode.textContent = afterTextNode.textContent.trimStart()
119
- textNode.textContent = textNode.textContent.trimEnd()
120
- textNode.parentElement.insertBefore(clozeGap, afterTextNode)
121
- }
122
- else {
123
- const clozeGap = document.createElement("webwriter-cloze-gap")
124
- clozeGap.setAttribute("value", "")
125
- this.append(clozeGap)
126
- }
127
- }
128
- }
129
-
130
- render() {
131
- return html`
132
- <slot style=${styleMap({"--placeholder": `"${this.msg("Text to add gaps to")}"`})} ?data-empty=${!this.textContent.trim() && !this.querySelectorAll("& > p *:not(br)").length}></slot>
133
- <sl-icon-button class="author-only" id="add-gap" src=${IconTextarea} @click=${this.toggleGap}></sl-icon-button>
134
- `
135
- }
1
+ import {html, css, LitElement} from "lit"
2
+ import {LitElementWw} from "@webwriter/lit"
3
+ import {customElement, query} from "lit/decorators.js"
4
+ import {styleMap} from "lit/directives/style-map.js"
5
+
6
+ import SlIconButton from "@shoelace-style/shoelace/dist/components/icon-button/icon-button.component.js"
7
+
8
+
9
+ import IconTextarea from "bootstrap-icons/icons/textarea.svg"
10
+ import { WebwriterClozeGap } from "./webwriter-cloze-gap.js"
11
+ import "@shoelace-style/shoelace/dist/themes/light.css"
12
+
13
+ declare global {interface HTMLElementTagNameMap {
14
+ "webwriter-cloze": WebwriterCloze;
15
+ }}
16
+
17
+ @customElement("webwriter-cloze")
18
+ export class WebwriterCloze extends LitElementWw {
19
+
20
+ static shadowRootOptions: ShadowRootInit = {...LitElementWw.shadowRootOptions, delegatesFocus: false}
21
+
22
+ static localization = {}
23
+
24
+ msg = (str: string) => this.lang in WebwriterCloze.localization? WebwriterCloze.localization[this.lang][str] ?? str: str
25
+
26
+
27
+ static scopedElements = {
28
+ "sl-icon-button": SlIconButton
29
+ }
30
+
31
+ static styles = css`
32
+ :host {
33
+ min-height: 1rem;
34
+ position: relative;
35
+ }
36
+
37
+ slot {
38
+ display: block;
39
+ cursor: text;
40
+ }
41
+
42
+ slot[data-empty]:after {
43
+ content: var(--placeholder);
44
+ position: absolute;
45
+ left: 0;
46
+ top: 0;
47
+ color: darkgray;
48
+ pointer-events: none;
49
+ user-select: none;
50
+ }
51
+
52
+ slot::after, slot::before {
53
+ content: ' ';
54
+ }
55
+
56
+ #add-gap {
57
+ position: absolute;
58
+ right: 0;
59
+ top: 0;
60
+ background: rgba(255, 255, 255, 0.85);
61
+
62
+ &[data-highlighting]::part(base) {
63
+ background: var(--sl-color-primary-100);
64
+ }
65
+ }
66
+
67
+ :host(:not([contenteditable=true]):not([contenteditable=""])) .author-only {
68
+ display: none;
69
+ }
70
+ `
71
+
72
+ @query("#add-gap")
73
+ accessor addGapButton: SlIconButton
74
+
75
+ observer: MutationObserver
76
+
77
+ connectedCallback(): void {
78
+ super.connectedCallback()
79
+ document.addEventListener("selectionchange", e => {
80
+ const sel = document.getSelection()
81
+ const node = document.getSelection()?.anchorNode
82
+ const el = node.nodeType === node.TEXT_NODE? node.parentElement: node as HTMLElement
83
+ this.addGapButton.toggleAttribute("data-visible", el?.closest("webwriter-cloze")? true: false)
84
+ if(el?.closest("webwriter-cloze") && !sel.isCollapsed) {
85
+ this.addGapButton.toggleAttribute("data-highlighting", true)
86
+ }
87
+ else {
88
+ this.addGapButton.toggleAttribute("data-highlighting", false)
89
+ }
90
+ })
91
+ this.observer = new MutationObserver(() => this.requestUpdate())
92
+ this.observer.observe(this, {characterData: true, childList: true, subtree: true})
93
+ }
94
+
95
+
96
+ disconnectedCallback(): void {
97
+ super.disconnectedCallback()
98
+ this.observer?.disconnect()
99
+ }
100
+
101
+ toggleGap = () => {
102
+ const sel = document.getSelection()
103
+ const selectedElement = sel.anchorNode.childNodes.item(sel.anchorOffset)
104
+ if(selectedElement?.nodeName.toLowerCase() === "webwriter-cloze-gap") {
105
+ const gap = selectedElement as WebwriterClozeGap
106
+ selectedElement.replaceWith(document.createTextNode(gap.value))
107
+ }
108
+ else if(this.contains(sel.anchorNode)) {
109
+ if(sel.anchorNode !== this) {
110
+ const textContent = sel.toString()
111
+ sel.deleteFromDocument()
112
+ const textNode = sel.anchorNode as Text
113
+ const at = sel.anchorOffset
114
+ const clozeGap = document.createElement("webwriter-cloze-gap")
115
+ clozeGap.classList.add("webwriter-new")
116
+ clozeGap.setAttribute("value", textContent)
117
+ const afterTextNode = textNode.splitText(at)
118
+ afterTextNode.textContent = afterTextNode.textContent.trimStart()
119
+ textNode.textContent = textNode.textContent.trimEnd()
120
+ textNode.parentElement.insertBefore(clozeGap, afterTextNode)
121
+ }
122
+ else {
123
+ const clozeGap = document.createElement("webwriter-cloze-gap")
124
+ clozeGap.setAttribute("value", "")
125
+ this.append(clozeGap)
126
+ }
127
+ }
128
+ }
129
+
130
+ render() {
131
+ return html`
132
+ <slot style=${styleMap({"--placeholder": `"${this.msg("Text to add gaps to")}"`})} ?data-empty=${!this.textContent.trim() && !this.querySelectorAll("& > p *:not(br)").length}></slot>
133
+ <sl-icon-button class="author-only" id="add-gap" src=${IconTextarea} @click=${this.toggleGap}></sl-icon-button>
134
+ `
135
+ }
136
136
  }