@webwriter/quiz 1.0.3 → 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.
- package/LICENSE +6 -6
- package/custom.d.ts +175 -175
- package/dist/widgets/webwriter-choice-item.js +58 -13
- package/dist/widgets/webwriter-choice.js +64 -19
- package/dist/widgets/webwriter-cloze-gap.js +59 -14
- package/dist/widgets/webwriter-cloze.js +56 -11
- package/dist/widgets/webwriter-mark.js +56 -11
- package/dist/widgets/webwriter-order-item.js +56 -11
- package/dist/widgets/webwriter-order.js +64 -19
- package/dist/widgets/webwriter-pairing.js +59 -14
- package/dist/widgets/webwriter-quiz.js +67 -22
- package/dist/widgets/webwriter-speech.js +66 -20
- package/dist/widgets/webwriter-task.js +534 -308
- package/dist/widgets/webwriter-text.js +60 -14
- package/package.json +200 -200
- package/src/lib/combobox.ts +455 -455
- package/src/snippets/choice.html +7 -7
- package/src/snippets/cloze.html +3 -3
- package/src/snippets/mark.html +3 -3
- package/src/snippets/order.html +7 -7
- package/src/snippets/pairing.html +9 -9
- package/src/snippets/speech.html +3 -3
- package/src/snippets/text.html +3 -3
- package/src/snippets/wordsearch.html +3 -3
- package/src/widgets/webwriter-choice-item.ts +250 -250
- package/src/widgets/webwriter-choice.ts +309 -309
- package/src/widgets/webwriter-cloze-gap.ts +216 -216
- package/src/widgets/webwriter-cloze.ts +135 -135
- package/src/widgets/webwriter-mark.ts +434 -434
- package/src/widgets/webwriter-order-item.ts +444 -444
- package/src/widgets/webwriter-order.ts +272 -272
- package/src/widgets/webwriter-pairing-item.ts +155 -155
- package/src/widgets/webwriter-pairing.ts +187 -187
- package/src/widgets/webwriter-quiz.ts +280 -280
- package/src/widgets/webwriter-speech.ts +267 -267
- package/src/widgets/webwriter-task-explainer.ts +37 -37
- package/src/widgets/webwriter-task-hint.ts +16 -16
- package/src/widgets/webwriter-task-prompt.ts +17 -17
- package/src/widgets/webwriter-task.ts +543 -543
- package/src/widgets/webwriter-text.ts +130 -130
- package/tsconfig.json +6 -6
|
@@ -1,188 +1,188 @@
|
|
|
1
|
-
import {html, css, PropertyValues} from "lit"
|
|
2
|
-
import {LitElementWw, option} from "@webwriter/lit"
|
|
3
|
-
import {customElement, property, queryAll} from "lit/decorators.js"
|
|
4
|
-
import "@shoelace-style/shoelace/dist/themes/light.css"
|
|
5
|
-
|
|
6
|
-
import IconPlus from "bootstrap-icons/icons/plus.svg"
|
|
7
|
-
import SlButton from "@shoelace-style/shoelace/dist/components/button/button.component.js"
|
|
8
|
-
import SlIcon from "@shoelace-style/shoelace/dist/components/icon/icon.component.js"
|
|
9
|
-
import { WebwriterPairingItem } from "./webwriter-pairing-item"
|
|
10
|
-
|
|
11
|
-
declare global {interface HTMLElementTagNameMap {
|
|
12
|
-
"webwriter-pairing": WebwriterPairing;
|
|
13
|
-
}}
|
|
14
|
-
|
|
15
|
-
@customElement("webwriter-pairing")
|
|
16
|
-
export class WebwriterPairing extends LitElementWw {
|
|
17
|
-
|
|
18
|
-
static shadowRootOptions = {...LitElementWw.shadowRootOptions, slotAssignment: "manual" as const}
|
|
19
|
-
|
|
20
|
-
static scopedElements = {
|
|
21
|
-
"sl-button": SlButton,
|
|
22
|
-
"sl-icon": SlIcon
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
static styles = css`
|
|
26
|
-
:host {
|
|
27
|
-
display: flex !important;
|
|
28
|
-
flex-direction: row;
|
|
29
|
-
flex-wrap: wrap;
|
|
30
|
-
gap: 30px;
|
|
31
|
-
padding-bottom: 30px;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
sl-button {
|
|
35
|
-
|
|
36
|
-
&::part(base) {
|
|
37
|
-
width: 125px;
|
|
38
|
-
height: 125px;
|
|
39
|
-
border: 1px solid darkgray;
|
|
40
|
-
border-radius: 2px;
|
|
41
|
-
padding: 10px;
|
|
42
|
-
overflow: hidden;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
&::part(label) {
|
|
46
|
-
padding: 0;
|
|
47
|
-
display: flex;
|
|
48
|
-
flex-direction: row;
|
|
49
|
-
align-items: center;
|
|
50
|
-
justify-content: center;
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
.pair {
|
|
55
|
-
position: relative;
|
|
56
|
-
|
|
57
|
-
& .a-slot, & .b-slot {
|
|
58
|
-
display: block;
|
|
59
|
-
|
|
60
|
-
&:is(:focus-within, :has(::selection)) {
|
|
61
|
-
background: green;
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
& .b-slot {
|
|
66
|
-
position: absolute;
|
|
67
|
-
left: 20px;
|
|
68
|
-
top: 20px;
|
|
69
|
-
z-index: 1000;
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
`
|
|
74
|
-
|
|
75
|
-
@property({attribute: true, reflect: true})
|
|
76
|
-
@option({type: "select", options: [
|
|
77
|
-
{value: "drag"},
|
|
78
|
-
{value: "memory"}
|
|
79
|
-
]})
|
|
80
|
-
accessor mode: "drag" | "memory" = "drag"
|
|
81
|
-
|
|
82
|
-
@property({type: Array, attribute: true, reflect: true})
|
|
83
|
-
accessor solution: ([string, string] | string)[] = []
|
|
84
|
-
|
|
85
|
-
addItem = () => {
|
|
86
|
-
const item = document.createElement("webwriter-pairing-item")
|
|
87
|
-
const picture = document.createElement("picture")
|
|
88
|
-
item.appendChild(picture)
|
|
89
|
-
this.appendChild(item)
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
Pair = (i: number) => {
|
|
93
|
-
return html`<div class="pair">
|
|
94
|
-
<slot class="a-slot" name=${`${i}a`}></slot>
|
|
95
|
-
<slot class="b-slot" name=${`${i}b`}></slot>
|
|
96
|
-
</div>`
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
getPairSlot() {}
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
get pairs() {
|
|
103
|
-
let allPairs = Array.from(this.children) as (WebwriterPairingItem | [WebwriterPairingItem, WebwriterPairingItem])[]
|
|
104
|
-
for(const [a, b] of this.solution) {
|
|
105
|
-
const elA = this.querySelector(`webwriter-pairing-item#${a}`) as WebwriterPairingItem
|
|
106
|
-
const elB = this.querySelector(`webwriter-pairing-item#${b}`) as WebwriterPairingItem
|
|
107
|
-
allPairs.splice(allPairs.indexOf(elA), 1, [elA, elB])
|
|
108
|
-
allPairs.splice(allPairs.indexOf(elB), 1)
|
|
109
|
-
}
|
|
110
|
-
return allPairs
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
pair(a: string, b?: string) {
|
|
114
|
-
let pairIds = this.pairs.map(entry => Array.isArray(entry)? [entry[0].id, entry[1].id]: entry.id)
|
|
115
|
-
const pairIndexOfA = this.solution.findIndex(val => Array.isArray(val) && val.includes(a))
|
|
116
|
-
const pairIndexOfB = this.solution.findIndex(val => Array.isArray(val) && val.includes(b))
|
|
117
|
-
if(!b) {
|
|
118
|
-
pairIds.splice(pairIndexOfA, 1, (pairIds[pairIndexOfA] as [string, string]).filter(id => id !== a)[0])
|
|
119
|
-
pairIds.push(a)
|
|
120
|
-
}
|
|
121
|
-
else {
|
|
122
|
-
if(pairIndexOfB !== -1) {
|
|
123
|
-
pairIds.splice(pairIndexOfB, 1, (pairIds[pairIndexOfB] as [string, string]).filter(id => id !== b)[0])
|
|
124
|
-
}
|
|
125
|
-
const indexOfA = this.solution.indexOf(a)
|
|
126
|
-
pairIds.splice(indexOfA, 1, [a, b])
|
|
127
|
-
pairIds = pairIds.filter(id => id !== b)
|
|
128
|
-
}
|
|
129
|
-
this.solution = pairIds.filter(entry => Array.isArray(entry)) as any
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
handlePairWith(e: CustomEvent) {
|
|
133
|
-
if(e.type === "ww-pairwith") {
|
|
134
|
-
this.pair((e.target as HTMLElement).id, e.detail.with)
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
observer: MutationObserver
|
|
139
|
-
|
|
140
|
-
connectedCallback(): void {
|
|
141
|
-
super.connectedCallback()
|
|
142
|
-
this.observer = new MutationObserver(() => {
|
|
143
|
-
let childIds = Array.from(this.children).map(child => child.id)
|
|
144
|
-
let solution = [...this.solution]
|
|
145
|
-
// solution = solution.filter(k => childIds.includes(k as any))
|
|
146
|
-
// solution = [...solution, ...childIds]
|
|
147
|
-
this.requestUpdate()
|
|
148
|
-
})
|
|
149
|
-
this.observer.observe(this, {childList: true})
|
|
150
|
-
this.addEventListener("ww-pairwith", this.handlePairWith)
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
disconnectedCallback(): void {
|
|
154
|
-
super.disconnectedCallback()
|
|
155
|
-
this.observer.disconnect()
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
protected willUpdate(_changedProperties: PropertyValues): void {
|
|
159
|
-
// this.solution = this.solution.filter(id => childIds.includes(id))
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
protected updated(_changedProperties: PropertyValues): void {
|
|
163
|
-
const slots = Array.from(this.slots)
|
|
164
|
-
for(const value of this.pairs) {
|
|
165
|
-
if(Array.isArray(value)) {
|
|
166
|
-
const [a, b] = value
|
|
167
|
-
slots.shift().assign(a)
|
|
168
|
-
slots.shift().assign(b)
|
|
169
|
-
}
|
|
170
|
-
else {
|
|
171
|
-
slots.shift().assign(value)
|
|
172
|
-
slots.shift()
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
@queryAll("slot")
|
|
178
|
-
accessor slots: NodeListOf<HTMLSlotElement>
|
|
179
|
-
|
|
180
|
-
render() {
|
|
181
|
-
return html`
|
|
182
|
-
${this.pairs.map((el, i) => this.Pair(i))}
|
|
183
|
-
<sl-button @click=${this.addItem}>
|
|
184
|
-
<sl-icon src=${IconPlus}></sl-icon>
|
|
185
|
-
</sl-button>
|
|
186
|
-
`
|
|
187
|
-
}
|
|
1
|
+
import {html, css, PropertyValues} from "lit"
|
|
2
|
+
import {LitElementWw, option} from "@webwriter/lit"
|
|
3
|
+
import {customElement, property, queryAll} from "lit/decorators.js"
|
|
4
|
+
import "@shoelace-style/shoelace/dist/themes/light.css"
|
|
5
|
+
|
|
6
|
+
import IconPlus from "bootstrap-icons/icons/plus.svg"
|
|
7
|
+
import SlButton from "@shoelace-style/shoelace/dist/components/button/button.component.js"
|
|
8
|
+
import SlIcon from "@shoelace-style/shoelace/dist/components/icon/icon.component.js"
|
|
9
|
+
import { WebwriterPairingItem } from "./webwriter-pairing-item"
|
|
10
|
+
|
|
11
|
+
declare global {interface HTMLElementTagNameMap {
|
|
12
|
+
"webwriter-pairing": WebwriterPairing;
|
|
13
|
+
}}
|
|
14
|
+
|
|
15
|
+
@customElement("webwriter-pairing")
|
|
16
|
+
export class WebwriterPairing extends LitElementWw {
|
|
17
|
+
|
|
18
|
+
static shadowRootOptions = {...LitElementWw.shadowRootOptions, slotAssignment: "manual" as const}
|
|
19
|
+
|
|
20
|
+
static scopedElements = {
|
|
21
|
+
"sl-button": SlButton,
|
|
22
|
+
"sl-icon": SlIcon
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
static styles = css`
|
|
26
|
+
:host {
|
|
27
|
+
display: flex !important;
|
|
28
|
+
flex-direction: row;
|
|
29
|
+
flex-wrap: wrap;
|
|
30
|
+
gap: 30px;
|
|
31
|
+
padding-bottom: 30px;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
sl-button {
|
|
35
|
+
|
|
36
|
+
&::part(base) {
|
|
37
|
+
width: 125px;
|
|
38
|
+
height: 125px;
|
|
39
|
+
border: 1px solid darkgray;
|
|
40
|
+
border-radius: 2px;
|
|
41
|
+
padding: 10px;
|
|
42
|
+
overflow: hidden;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
&::part(label) {
|
|
46
|
+
padding: 0;
|
|
47
|
+
display: flex;
|
|
48
|
+
flex-direction: row;
|
|
49
|
+
align-items: center;
|
|
50
|
+
justify-content: center;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
.pair {
|
|
55
|
+
position: relative;
|
|
56
|
+
|
|
57
|
+
& .a-slot, & .b-slot {
|
|
58
|
+
display: block;
|
|
59
|
+
|
|
60
|
+
&:is(:focus-within, :has(::selection)) {
|
|
61
|
+
background: green;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
& .b-slot {
|
|
66
|
+
position: absolute;
|
|
67
|
+
left: 20px;
|
|
68
|
+
top: 20px;
|
|
69
|
+
z-index: 1000;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
`
|
|
74
|
+
|
|
75
|
+
@property({attribute: true, reflect: true})
|
|
76
|
+
@option({type: "select", options: [
|
|
77
|
+
{value: "drag"},
|
|
78
|
+
{value: "memory"}
|
|
79
|
+
]})
|
|
80
|
+
accessor mode: "drag" | "memory" = "drag"
|
|
81
|
+
|
|
82
|
+
@property({type: Array, attribute: true, reflect: true})
|
|
83
|
+
accessor solution: ([string, string] | string)[] = []
|
|
84
|
+
|
|
85
|
+
addItem = () => {
|
|
86
|
+
const item = document.createElement("webwriter-pairing-item")
|
|
87
|
+
const picture = document.createElement("picture")
|
|
88
|
+
item.appendChild(picture)
|
|
89
|
+
this.appendChild(item)
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
Pair = (i: number) => {
|
|
93
|
+
return html`<div class="pair">
|
|
94
|
+
<slot class="a-slot" name=${`${i}a`}></slot>
|
|
95
|
+
<slot class="b-slot" name=${`${i}b`}></slot>
|
|
96
|
+
</div>`
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
getPairSlot() {}
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
get pairs() {
|
|
103
|
+
let allPairs = Array.from(this.children) as (WebwriterPairingItem | [WebwriterPairingItem, WebwriterPairingItem])[]
|
|
104
|
+
for(const [a, b] of this.solution) {
|
|
105
|
+
const elA = this.querySelector(`webwriter-pairing-item#${a}`) as WebwriterPairingItem
|
|
106
|
+
const elB = this.querySelector(`webwriter-pairing-item#${b}`) as WebwriterPairingItem
|
|
107
|
+
allPairs.splice(allPairs.indexOf(elA), 1, [elA, elB])
|
|
108
|
+
allPairs.splice(allPairs.indexOf(elB), 1)
|
|
109
|
+
}
|
|
110
|
+
return allPairs
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
pair(a: string, b?: string) {
|
|
114
|
+
let pairIds = this.pairs.map(entry => Array.isArray(entry)? [entry[0].id, entry[1].id]: entry.id)
|
|
115
|
+
const pairIndexOfA = this.solution.findIndex(val => Array.isArray(val) && val.includes(a))
|
|
116
|
+
const pairIndexOfB = this.solution.findIndex(val => Array.isArray(val) && val.includes(b))
|
|
117
|
+
if(!b) {
|
|
118
|
+
pairIds.splice(pairIndexOfA, 1, (pairIds[pairIndexOfA] as [string, string]).filter(id => id !== a)[0])
|
|
119
|
+
pairIds.push(a)
|
|
120
|
+
}
|
|
121
|
+
else {
|
|
122
|
+
if(pairIndexOfB !== -1) {
|
|
123
|
+
pairIds.splice(pairIndexOfB, 1, (pairIds[pairIndexOfB] as [string, string]).filter(id => id !== b)[0])
|
|
124
|
+
}
|
|
125
|
+
const indexOfA = this.solution.indexOf(a)
|
|
126
|
+
pairIds.splice(indexOfA, 1, [a, b])
|
|
127
|
+
pairIds = pairIds.filter(id => id !== b)
|
|
128
|
+
}
|
|
129
|
+
this.solution = pairIds.filter(entry => Array.isArray(entry)) as any
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
handlePairWith(e: CustomEvent) {
|
|
133
|
+
if(e.type === "ww-pairwith") {
|
|
134
|
+
this.pair((e.target as HTMLElement).id, e.detail.with)
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
observer: MutationObserver
|
|
139
|
+
|
|
140
|
+
connectedCallback(): void {
|
|
141
|
+
super.connectedCallback()
|
|
142
|
+
this.observer = new MutationObserver(() => {
|
|
143
|
+
let childIds = Array.from(this.children).map(child => child.id)
|
|
144
|
+
let solution = [...this.solution]
|
|
145
|
+
// solution = solution.filter(k => childIds.includes(k as any))
|
|
146
|
+
// solution = [...solution, ...childIds]
|
|
147
|
+
this.requestUpdate()
|
|
148
|
+
})
|
|
149
|
+
this.observer.observe(this, {childList: true})
|
|
150
|
+
this.addEventListener("ww-pairwith", this.handlePairWith)
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
disconnectedCallback(): void {
|
|
154
|
+
super.disconnectedCallback()
|
|
155
|
+
this.observer.disconnect()
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
protected willUpdate(_changedProperties: PropertyValues): void {
|
|
159
|
+
// this.solution = this.solution.filter(id => childIds.includes(id))
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
protected updated(_changedProperties: PropertyValues): void {
|
|
163
|
+
const slots = Array.from(this.slots)
|
|
164
|
+
for(const value of this.pairs) {
|
|
165
|
+
if(Array.isArray(value)) {
|
|
166
|
+
const [a, b] = value
|
|
167
|
+
slots.shift().assign(a)
|
|
168
|
+
slots.shift().assign(b)
|
|
169
|
+
}
|
|
170
|
+
else {
|
|
171
|
+
slots.shift().assign(value)
|
|
172
|
+
slots.shift()
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
@queryAll("slot")
|
|
178
|
+
accessor slots: NodeListOf<HTMLSlotElement>
|
|
179
|
+
|
|
180
|
+
render() {
|
|
181
|
+
return html`
|
|
182
|
+
${this.pairs.map((el, i) => this.Pair(i))}
|
|
183
|
+
<sl-button @click=${this.addItem}>
|
|
184
|
+
<sl-icon src=${IconPlus}></sl-icon>
|
|
185
|
+
</sl-button>
|
|
186
|
+
`
|
|
187
|
+
}
|
|
188
188
|
}
|