cognikit 1.0.2 → 1.1.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 (124) hide show
  1. package/dist/builders/classification/index.d.ts +24 -0
  2. package/dist/builders/fill-blanks/index.d.ts +48 -0
  3. package/dist/client.js +2574 -2666
  4. package/dist/client.js.map +4 -4
  5. package/dist/core/builders/index.d.ts +48 -0
  6. package/dist/core/index.d.ts +2 -1
  7. package/dist/core/{BaseInteraction.d.ts → interactions/index.d.ts} +11 -12
  8. package/dist/engines/index.d.ts +0 -1
  9. package/dist/engines/tables/index.d.ts +40 -2
  10. package/dist/engines/tables/{implementation/utils.d.ts → utils.d.ts} +1 -1
  11. package/dist/index.d.ts +1 -1
  12. package/dist/index.js +2570 -2662
  13. package/dist/index.js.map +4 -4
  14. package/dist/interactions/adjacency-table/index.d.ts +6 -7
  15. package/dist/interactions/classification-matrix/index.d.ts +7 -6
  16. package/dist/interactions/fill-blanks/index.d.ts +36 -2
  17. package/dist/interactions/index.d.ts +0 -2
  18. package/dist/interactions/list-recall/index.d.ts +27 -1
  19. package/dist/interactions/lookup-table/index.d.ts +6 -7
  20. package/dist/interactions/mark-the-words/index.d.ts +34 -2
  21. package/dist/interactions/mcq-mrq/index.d.ts +37 -2
  22. package/dist/interactions/nary-choice-table/index.d.ts +7 -13
  23. package/dist/interactions/open-classification/index.d.ts +9 -6
  24. package/dist/interactions/rank-order/index.d.ts +49 -2
  25. package/dist/interactions/registry.d.ts +5 -5
  26. package/dist/interactions/sequential-classification/index.d.ts +8 -6
  27. package/dist/interactions/simultaneous-association/index.d.ts +7 -12
  28. package/dist/{shared/managers → managers}/AnimationsManager.d.ts +6 -1
  29. package/dist/managers/DragAndDropManager.d.ts +37 -0
  30. package/dist/{core/utilities/ProgressTracker.d.ts → managers/ProgressManager.d.ts} +8 -8
  31. package/dist/managers/ScoringManager.d.ts +73 -0
  32. package/dist/managers/index.d.ts +4 -0
  33. package/dist/shared/config.d.ts +1 -1
  34. package/dist/shared/index.d.ts +0 -2
  35. package/dist/shared/utils.d.ts +2 -1
  36. package/dist/shell/builders/index.d.ts +29 -0
  37. package/dist/shell/index.d.ts +2 -1
  38. package/dist/shell/{simple-shell/script.d.ts → interactions/index.d.ts} +8 -7
  39. package/dist/types/Builders.d.ts +17 -0
  40. package/dist/types/Data.d.ts +49 -9
  41. package/dist/types/Global.d.ts +2 -23
  42. package/dist/types/Grading.d.ts +2 -0
  43. package/dist/types/Input.d.ts +12 -16
  44. package/dist/types/Interactions.d.ts +10 -14
  45. package/dist/types/Tables.d.ts +2 -2
  46. package/dist/ui/{misc/block.d.ts → block/index.d.ts} +1 -1
  47. package/dist/ui/{misc/chip/chip.d.ts → chip/index.d.ts} +8 -4
  48. package/dist/ui/{misc/dialog.d.ts → dialog/index.d.ts} +0 -1
  49. package/dist/ui/index.d.ts +4 -1
  50. package/dist/ui/input/index.d.ts +22 -1
  51. package/dist/ui/{misc/media.d.ts → media/index.d.ts} +1 -1
  52. package/package.json +1 -1
  53. package/public/app.js +5874 -8649
  54. package/public/app.js.map +4 -4
  55. package/public/assets/images/landscape.jpg +0 -0
  56. package/public/assets/images/mountains.jpg +0 -0
  57. package/public/builders.html +87 -0
  58. package/public/examples/data.ts +167 -0
  59. package/public/index.html +1008 -779
  60. package/dist/core/utilities/index.d.ts +0 -1
  61. package/dist/engines/tables/implementation/graders.d.ts +0 -23
  62. package/dist/engines/tables/implementation/index.d.ts +0 -4
  63. package/dist/engines/tables/implementation/parsers.d.ts +0 -36
  64. package/dist/engines/tables/implementation/validators.d.ts +0 -9
  65. package/dist/engines/tables/script.d.ts +0 -37
  66. package/dist/engines/text/implementation/graders.d.ts +0 -69
  67. package/dist/engines/text/implementation/index.d.ts +0 -3
  68. package/dist/engines/text/implementation/parsers.d.ts +0 -9
  69. package/dist/engines/text/implementation/validators.d.ts +0 -41
  70. package/dist/engines/text/index.d.ts +0 -2
  71. package/dist/engines/text/script.d.ts +0 -56
  72. package/dist/interactions/categorize-the-words/index.d.ts +0 -2
  73. package/dist/interactions/categorize-the-words/sequential.d.ts +0 -33
  74. package/dist/interactions/categorize-the-words/static.d.ts +0 -22
  75. package/dist/interactions/fill-blanks/sequential.d.ts +0 -32
  76. package/dist/interactions/fill-blanks/static.d.ts +0 -23
  77. package/dist/interactions/list-recall/script.d.ts +0 -25
  78. package/dist/interactions/mark-the-words/sequential.d.ts +0 -34
  79. package/dist/interactions/mark-the-words/static.d.ts +0 -40
  80. package/dist/interactions/mcq-mrq/implementation/grader.d.ts +0 -20
  81. package/dist/interactions/mcq-mrq/implementation/index.d.ts +0 -3
  82. package/dist/interactions/mcq-mrq/implementation/parser.d.ts +0 -21
  83. package/dist/interactions/mcq-mrq/implementation/validator.d.ts +0 -17
  84. package/dist/interactions/mcq-mrq/script.d.ts +0 -37
  85. package/dist/interactions/rank-order/implementation/grader.d.ts +0 -15
  86. package/dist/interactions/rank-order/implementation/index.d.ts +0 -3
  87. package/dist/interactions/rank-order/implementation/parser.d.ts +0 -25
  88. package/dist/interactions/rank-order/implementation/validator.d.ts +0 -3
  89. package/dist/interactions/rank-order/script.d.ts +0 -39
  90. package/dist/interactions/shared/association-implementation/grader.d.ts +0 -3
  91. package/dist/interactions/shared/association-implementation/index.d.ts +0 -1
  92. package/dist/interactions/shared/association-implementation/validator.d.ts +0 -0
  93. package/dist/interactions/shared/classification-implementation/grader.d.ts +0 -3
  94. package/dist/interactions/shared/classification-implementation/index.d.ts +0 -1
  95. package/dist/interactions/shared/classification-implementation/parser.d.ts +0 -11
  96. package/dist/interactions/shared/classification-implementation/validator.d.ts +0 -3
  97. package/dist/interactions/text-transformation/index.d.ts +0 -2
  98. package/dist/interactions/text-transformation/sequential.d.ts +0 -37
  99. package/dist/interactions/text-transformation/static.d.ts +0 -47
  100. package/dist/shared/dsl.d.ts +0 -9
  101. package/dist/shared/managers/index.d.ts +0 -3
  102. package/dist/shared/types.d.ts +0 -25
  103. package/dist/shell/simple-shell/index.d.ts +0 -1
  104. package/dist/types/Text.d.ts +0 -125
  105. package/dist/ui/input/input/index.d.ts +0 -1
  106. package/dist/ui/input/input/input.d.ts +0 -22
  107. package/dist/ui/misc/chip/index.d.ts +0 -1
  108. package/dist/ui/misc/index.d.ts +0 -4
  109. package/public/assets/images/pointing-hand.svg +0 -1
  110. package/public/examples/chip.html +0 -495
  111. package/public/scalable-bare.html +0 -432
  112. package/public/tables-demo.html +0 -534
  113. package/public/text-interactions-demo.html +0 -604
  114. /package/dist/{interactions/list-recall/implementation → builders/list}/index.d.ts +0 -0
  115. /package/dist/{core/utilities/ScoringTracker.d.ts → builders/matching/inde.d.ts} +0 -0
  116. /package/dist/{ui/input/color → builders/ordering}/index.d.ts +0 -0
  117. /package/dist/{ui/input/letter → builders/tables}/index.d.ts +0 -0
  118. /package/dist/{interactions/list-recall/implementation/grader.d.ts → builders/text/index.d.ts} +0 -0
  119. /package/dist/interactions/{list-recall/implementation/parser.d.ts → exp/CategorizeTheWords.d.ts} +0 -0
  120. /package/dist/interactions/{list-recall/implementation/validator.d.ts → exp/DndFillBlanks.d.ts} +0 -0
  121. /package/dist/interactions/{shared/association-implementation/parser.d.ts → exp/TextTransformation.d.ts} +0 -0
  122. /package/dist/{shared/managers → managers}/SoundManager.d.ts +0 -0
  123. /package/dist/ui/{input/color/color-picker.d.ts → exp/color/index.d.ts} +0 -0
  124. /package/dist/ui/{input/letter/letter-picker.d.ts → exp/letter/index.d.ts} +0 -0
@@ -1,604 +0,0 @@
1
- <!DOCTYPE html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="UTF-8">
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>CogniKit - Text Interactions Demo</title>
7
- <style>
8
- * {
9
- margin: 0;
10
- padding: 0;
11
- box-sizing: border-box;
12
- }
13
-
14
- html, body {
15
- width: 100%;
16
- height: 100%;
17
- overflow: hidden;
18
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
19
- -webkit-font-smoothing: antialiased;
20
- }
21
-
22
- :root {
23
- --edu-bg: 247 249 252;
24
- --edu-card: 255 255 255;
25
- --edu-ink: 31 41 55;
26
- --edu-second-ink: 71 85 105;
27
- --edu-third-ink: 100 116 139;
28
- --edu-inverted-ink: 248 250 252;
29
- --edu-success: 22 163 74;
30
- --edu-error: 220 38 38;
31
- --edu-warning: 255 222 33;
32
- --edu-neutral: 14 165 233;
33
- --edu-first-accent: 49 120 198;
34
- --edu-second-accent: 245 158 11;
35
- --edu-third-accent: 236 72 153;
36
- --edu-border: 229 231 235;
37
- --edu-muted: 243 244 246;
38
- --edu-radius: 0.375rem;
39
- --edu-shadow-color: 0 0 0;
40
- --edu-pad: 1rem;
41
- --edu-mar: 0;
42
- }
43
-
44
- body {
45
- background: rgb(var(--edu-bg));
46
- display: flex;
47
- height: 100vh;
48
- }
49
-
50
- /* ==================== SIDEBAR ==================== */
51
-
52
- .sidebar {
53
- width: 280px;
54
- background: rgb(var(--edu-card));
55
- border-right: 2px solid rgb(var(--edu-border));
56
- padding: 1.5rem;
57
- overflow-y: auto;
58
- flex-shrink: 0;
59
- display: flex;
60
- flex-direction: column;
61
- gap: 1.25rem;
62
- }
63
-
64
- .sidebar-title {
65
- font-size: 1.1rem;
66
- font-weight: 700;
67
- color: rgb(var(--edu-ink));
68
- padding-bottom: 0.75rem;
69
- border-bottom: 2px solid rgb(var(--edu-border));
70
- }
71
-
72
- .group-label {
73
- font-size: 0.8rem;
74
- font-weight: 700;
75
- text-transform: uppercase;
76
- letter-spacing: 0.8px;
77
- color: rgb(var(--edu-first-accent));
78
- margin-bottom: 0.4rem;
79
- }
80
-
81
- .example-group {
82
- display: flex;
83
- flex-direction: column;
84
- gap: 0.4rem;
85
- }
86
-
87
- .example-btn {
88
- padding: 0.6rem 0.75rem;
89
- border: 2px solid rgb(var(--edu-border));
90
- border-radius: var(--edu-radius);
91
- background: rgb(var(--edu-card));
92
- color: rgb(var(--edu-ink));
93
- cursor: pointer;
94
- transition: all 0.15s;
95
- font-size: 0.85rem;
96
- font-weight: 500;
97
- text-align: left;
98
- line-height: 1.3;
99
- }
100
-
101
- .example-btn:hover {
102
- border-color: rgb(var(--edu-first-accent));
103
- background: rgba(var(--edu-first-accent), 0.05);
104
- }
105
-
106
- .example-btn.active {
107
- border-color: rgb(var(--edu-first-accent));
108
- background: rgba(var(--edu-first-accent), 0.1);
109
- color: rgb(var(--edu-first-accent));
110
- }
111
-
112
- .example-btn-desc {
113
- font-size: 0.72rem;
114
- font-weight: 400;
115
- opacity: 0.7;
116
- margin-top: 0.15rem;
117
- }
118
-
119
- /* ==================== VARIANT SELECTOR ==================== */
120
-
121
- .variant-controls {
122
- margin-top: auto;
123
- padding-top: 1rem;
124
- border-top: 2px solid rgb(var(--edu-border));
125
- }
126
-
127
- .variant-controls label {
128
- display: block;
129
- font-size: 0.8rem;
130
- font-weight: 600;
131
- color: rgb(var(--edu-second-ink));
132
- margin-bottom: 0.4rem;
133
- }
134
-
135
- .variant-controls select {
136
- width: 100%;
137
- padding: 0.45rem 0.6rem;
138
- border: 2px solid rgb(var(--edu-border));
139
- border-radius: var(--edu-radius);
140
- background: rgb(var(--edu-bg));
141
- color: rgb(var(--edu-ink));
142
- font-size: 0.85rem;
143
- cursor: pointer;
144
- }
145
-
146
- /* ==================== VIEWPORT ==================== */
147
-
148
- .viewport {
149
- flex: 1;
150
- display: flex;
151
- align-items: center;
152
- justify-content: center;
153
- padding: 2rem;
154
- overflow: hidden;
155
- }
156
-
157
- .interaction-container {
158
- width: 100%;
159
- height: 100%;
160
- max-width: 900px;
161
- display: flex;
162
- flex-direction: column;
163
- }
164
-
165
- edu-window {
166
- width: 100%;
167
- height: 100%;
168
- display: block;
169
- }
170
- </style>
171
- </head>
172
- <body>
173
- <div class="sidebar">
174
- <div class="sidebar-title">Text Interactions</div>
175
-
176
- <div>
177
- <div class="group-label">Mark The Words</div>
178
- <div class="example-group">
179
- <button class="example-btn active" data-example="mtw-programming">
180
- Female Names
181
- <div class="example-btn-desc">Highlight the female names of people that you find</div>
182
- </button>
183
- <button class="example-btn" data-example="mtw-biology">
184
- Brands
185
- <div class="example-btn-desc">Identify all the popular brands mentioned here</div>
186
- </button>
187
- </div>
188
- </div>
189
-
190
- <div>
191
- <div class="group-label">Text Transformation</div>
192
- <div class="example-group">
193
- <button class="example-btn" data-example="tt-verbs">
194
- Irregular Verbs
195
- <div class="example-btn-desc">Present tense &rarr; past tense</div>
196
- </button>
197
- <button class="example-btn" data-example="tt-plural">
198
- Singular &rarr; Plural
199
- <div class="example-btn-desc">Convert nouns to plural form</div>
200
- </button>
201
- </div>
202
- </div>
203
-
204
- <div>
205
- <div class="group-label">DND Blanks</div>
206
- <div class="example-group">
207
- <button class="example-btn" data-example="dnd-household">
208
- Household Chores
209
- <div class="example-btn-desc">Drag words into missing spots</div>
210
- </button>
211
- <button class="example-btn" data-example="dnd-space">
212
- Space Terms
213
- <div class="example-btn-desc">Place concepts in context</div>
214
- </button>
215
- </div>
216
- </div>
217
-
218
- <div>
219
- <div class="group-label">Fill Blanks</div>
220
- <div class="example-group">
221
- <button class="example-btn" data-example="fb-mixed">
222
- Mixed Inputs
223
- <div class="example-btn-desc">Text, number, and select in one prompt</div>
224
- </button>
225
- <button class="example-btn" data-example="fb-time-date">
226
- Time and Date
227
- <div class="example-btn-desc">Specific value constraints</div>
228
- </button>
229
- </div>
230
- </div>
231
-
232
- <div>
233
- <div class="group-label">Categorize Words</div>
234
- <div class="example-group">
235
- <button class="example-btn" data-example="cat-grammar">
236
- Grammar Labels
237
- <div class="example-btn-desc">Assign words to their category</div>
238
- </button>
239
- </div>
240
- </div>
241
-
242
- <div>
243
- <div class="group-label">Sequential</div>
244
- <div class="example-group">
245
- <button class="example-btn" data-example="seq-highlight-basics">
246
- Guided Multi-step Blanks
247
- <div class="example-btn-desc">Answers persist across slides</div>
248
- </button>
249
- <button class="example-btn" data-example="seq-mark-keywords">
250
- Guided Highlight Steps
251
- <div class="example-btn-desc">Per-slide mark-the-words grading</div>
252
- </button>
253
- <button class="example-btn" data-example="seq-transform-verbs">
254
- Guided Verb Transformations
255
- <div class="example-btn-desc">Per-slide transformation grading</div>
256
- </button>
257
- <button class="example-btn" data-example="seq-categorize-grammar">
258
- Guided Word Categorization
259
- <div class="example-btn-desc">Per-slide category assignments</div>
260
- </button>
261
- </div>
262
- </div>
263
-
264
- <div class="variant-controls">
265
- <label for="variant-select">UI Variant</label>
266
- <select id="variant-select">
267
- <option value="outline" selected>Outline</option>
268
- <option value="elegant">Elegant</option>
269
- <option value="playful">Playful</option>
270
- <option value="minimal">Minimal</option>
271
- <option value="letter">Letter</option>
272
- <option value="sign">Sign</option>
273
- <option value="glass">Glass</option>
274
- <option value="empty">Empty</option>
275
- </select>
276
- </div>
277
- </div>
278
-
279
- <div class="viewport">
280
- <div class="interaction-container">
281
- <edu-window id="interaction-viewport"></edu-window>
282
- </div>
283
- </div>
284
-
285
- <script type="module">
286
- import {
287
- BaseInteraction,
288
- EduText,
289
- MarkTheWords,
290
- SequentialMarkTheWords,
291
- CategorizeTheWords,
292
- SequentialCategorizeTheWords,
293
- TextTransformation,
294
- SequentialTextTransformation,
295
- FillBlanks,
296
- SequentialFillBlanks,
297
-
298
- textEngineBaseGrammarParser,
299
- textEngineBlanksGrammarParser,
300
- textEngineClassificationGrammarParser,
301
-
302
- parseTextEngineSequential,
303
-
304
- textEngineDNDGrader,
305
- getDNDGradingState,
306
-
307
- textEngineBlanksGrader,
308
- getBlanksGradingState
309
- } from './app.js';
310
-
311
- const viewport = document.getElementById('interaction-viewport');
312
- const variantSelect = document.getElementById('variant-select');
313
- let currentInteraction = null;
314
- let currentVariant = 'outline';
315
-
316
- // ==================== EXAMPLE DEFINITIONS ====================
317
-
318
- const examples = {
319
- 'mtw-programming': {
320
- type: 'MarkTheWords',
321
- title: 'Mark the female names.',
322
- code: '[Maria] was going to tell Juan about the concert she went to last light with her friends [Caroline] and [Michelle]. Before she did that, Juan was explaining how he made three friends named [Ana], [Elizabeth] and Pedro.'
323
- },
324
- 'mtw-biology': {
325
- type: 'MarkTheWords',
326
- title: 'Identify the popular brands',
327
- code: 'I dont really understand why people get so hyped with [Coca Cola] and not with [Pepsi] when it is literally quite close in terms of taste. It is like the [McDonals] guys trying to pretend [burger king] is not biting their tails, or that either [Nike] or [Jordan] are better than the other.'
328
- },
329
- 'tt-verbs': {
330
- type: 'TextTransformation',
331
- title: 'Convert present tense to past tense',
332
- code: 'Yesterday I [wake] up early and [go] to the gym. I [swim] for an hour, then I [run] three miles. After that, I [eat] a healthy breakfast and [begin] my workday.',
333
- expectedTransformations: {
334
- 0: ['woke'],
335
- 1: ['went'],
336
- 2: ['swam'],
337
- 3: ['ran'],
338
- 4: ['ate'],
339
- 5: ['began']
340
- }
341
- },
342
- 'tt-plural': {
343
- type: 'TextTransformation',
344
- title: 'Convert each noun to its plural form',
345
- code: 'The [child] played in the [garden]. Each [leaf] fell from the [tree]. A [mouse] scurried across the [bench]. The [wolf] howled at the [sky].',
346
- expectedTransformations: {
347
- 0: ['children'],
348
- 1: ['gardens'],
349
- 2: ['leaves'],
350
- 3: ['trees'],
351
- 4: ['mice'],
352
- 5: ['benches'],
353
- 6: ['wolves'],
354
- 7: ['skies']
355
- }
356
- },
357
- 'dnd-household': {
358
- type: 'DNDTextDemo',
359
- parserMode: 'base',
360
- title: 'Complete the household routine',
361
- code: '= ["surf", "moon", "paint"]; Every Saturday we [sweep] the floor, [wash] the dishes, and [fold] the clothes before lunch.'
362
- },
363
- 'dnd-space': {
364
- type: 'DNDTextDemo',
365
- parserMode: 'base',
366
- title: 'Complete the astronomy passage',
367
- code: '= ["car", "island"]; The [sun] is at the center of our solar system, while the [moon] orbits Earth and reflects [light] at night.'
368
- },
369
- 'fb-mixed': {
370
- type: 'FillBlanks',
371
- parserMode: 'blanks',
372
- title: 'Student profile form',
373
- code: 'My name @tx(is|\'s) Ana. I am @nm(14..16) years old and I solved @nm(7|8|9) exercises today. My favorite class is @sl([math]|science|history|music).'
374
- },
375
- 'fb-time-date': {
376
- type: 'FillBlanks',
377
- parserMode: 'blanks',
378
- title: 'Schedule confirmation',
379
- code: 'The quiz is on @dt(2026/03/05) and starts at @tm(08:30). Check-in closes at @tm(08:20).'
380
- },
381
- 'cat-grammar': {
382
- type: 'CategorizeTheWords',
383
- parserMode: 'classification',
384
- title: 'Assign each highlighted item to a grammar category',
385
- code: 'I @ct(noun, teacher) will @ct(verb, travel) to the @ct(noun, museum) and @ct(verb, study) there.'
386
- },
387
- 'seq-highlight-basics': {
388
- type: 'SequentialFillBlanks',
389
- parserMode: 'sequential-blanks',
390
- title: 'Complete each slide with the verb to be',
391
- code: 'She @tx(is|\'s) my sister and we @tx(are) from Santiago.;;Classes @tx(are|\'re) amazing!.;;Our families @tx(are|\'re) not very friendly! This @tx(is|\'r) not a good idea...'
392
- },
393
- 'seq-mark-keywords': {
394
- type: 'SequentialMarkTheWords',
395
- parserMode: 'sequential-base',
396
- title: 'Mark the target words on each step',
397
- code: 'Mark the female names: [Maria] met Juan and [Caroline] near the park.;;Mark the brands: I bought [Nike] shoes and drank [Pepsi].'
398
- },
399
- 'seq-transform-verbs': {
400
- type: 'SequentialTextTransformation',
401
- parserMode: 'sequential-base',
402
- title: 'Transform each highlighted verb according to the step',
403
- code: 'Yesterday I [wake] early and [go] to school.;;Last weekend they [run] in the park and [eat] dinner outside.',
404
- expectedTransformationsByStep: {
405
- 0: { 0: ['woke'], 1: ['went'] },
406
- 1: { 0: ['ran'], 1: ['ate'] }
407
- }
408
- },
409
- 'seq-categorize-grammar': {
410
- type: 'SequentialCategorizeTheWords',
411
- parserMode: 'sequential-classification',
412
- title: 'Assign highlighted words to the correct category on each step',
413
- code: 'I @ct(noun, teacher) will @ct(verb, travel) tomorrow.;;They @ct(noun, students) @ct(verb, study) every night.'
414
- }
415
- };
416
-
417
- class DNDTextDemo extends BaseInteraction {
418
- interactionMechanic = 'static';
419
- _textConfig;
420
- _$text;
421
-
422
- constructor(data, config) {
423
- super(data, config);
424
- this._textConfig = {
425
- data,
426
- mode: 'dnd',
427
- variant: config.variant ?? 'outline'
428
- };
429
- this.initializeProgress(this.getTargetCount());
430
- }
431
-
432
- getTargetCount() {
433
- return this.data.targets.reduce((sum, t) => sum + (t.endPos - t.startPos + 1), 0);
434
- }
435
-
436
- render() {
437
- this._textConfig.variant = this.config.variant;
438
-
439
- this._$text = document.createElement('edu-text');
440
- this._$text.config = this._textConfig;
441
- this._$text.addEventListener('change', () => {
442
- const userData = this._$text.getValue();
443
- const filled = Object.keys(userData.dndPlacements ?? {}).length;
444
- this.setProgress(filled);
445
- this.emitStateChange();
446
- });
447
-
448
- this.innerHTML = `
449
- <style>
450
- .text-wrapper {
451
- height: 100%;
452
- overflow: auto;
453
- padding: 1rem;
454
- }
455
- </style>
456
- <div class="text-wrapper"></div>
457
- `;
458
- this.querySelector('.text-wrapper').appendChild(this._$text);
459
- }
460
-
461
- getCurrentState() {
462
- return this._$text ? this._$text.getValue() : { dndPlacements: {} };
463
- }
464
-
465
- isInteractionComplete() {
466
- const progress = this.getProgress();
467
- return progress.current >= progress.total;
468
- }
469
-
470
- onVariantChange(newVariant) {
471
- this.config.variant = newVariant;
472
- this._textConfig.variant = newVariant;
473
- if (this._$text) this._$text.setAttribute('variant', newVariant);
474
- }
475
-
476
- onHint() {
477
- const userData = this.getCurrentState();
478
- const placements = userData.dndPlacements ?? {};
479
-
480
- for (const target of this.data.targets) {
481
- for (let i = target.startPos; i <= target.endPos; i++) {
482
- if (!placements[i]) {
483
- this.emitHintShown(`Try placing "${this.data.parts[i]}" in one of the empty spots.`);
484
- return;
485
- }
486
- }
487
- }
488
-
489
- this.emitHintShown('All blanks are filled. Submit to check.');
490
- }
491
-
492
- grade() {
493
- const userData = this.getCurrentState();
494
- const result = textEngineDNDGrader(this.data, userData);
495
- const gradingState = getDNDGradingState(this.data, userData);
496
- this._$text.setGradingState(gradingState);
497
- return result;
498
- }
499
-
500
- submit() {
501
- super.submit();
502
- const result = this.grade();
503
- this.dispatchEvent(new CustomEvent('interaction:graded', {
504
- detail: { result },
505
- bubbles: true,
506
- composed: true
507
- }));
508
- }
509
-
510
- reset() {
511
- super.reset();
512
- if (this._$text) {
513
- this._$text.reset();
514
- this._$text.clearGradingState();
515
- }
516
- }
517
- }
518
-
519
- if (!customElements.get('dnd-text-demo')) {
520
- customElements.define('dnd-text-demo', DNDTextDemo);
521
- }
522
-
523
- // ==================== LOAD & WIRE ====================
524
-
525
- function loadExample(key) {
526
- const example = examples[key];
527
- if (!example) return;
528
-
529
- const parseResult = example.parserMode === 'blanks'
530
- ? textEngineBlanksGrammarParser(example.code)
531
- : example.parserMode === 'classification'
532
- ? textEngineClassificationGrammarParser(example.code)
533
- : example.parserMode === 'sequential-base'
534
- ? parseTextEngineSequential(example.code, 'base')
535
- : example.parserMode === 'sequential-classification'
536
- ? parseTextEngineSequential(example.code, 'classification')
537
- : example.parserMode === 'sequential-blanks'
538
- ? parseTextEngineSequential(example.code, 'blanks')
539
- : textEngineBaseGrammarParser(example.code);
540
- if (!parseResult.ok) {
541
- console.error('Parse errors:', parseResult.errors);
542
- return;
543
- }
544
-
545
- const config = {
546
- prompt: example.title,
547
- variant: currentVariant,
548
- shuffle: false,
549
- attemptLimit: null,
550
- timer: null,
551
- animationsEnabled: true,
552
- soundEnabled: true
553
- };
554
-
555
- let interaction;
556
- if (example.type === 'MarkTheWords') {
557
- interaction = new MarkTheWords(parseResult.data, config);
558
- } else if (example.type === 'SequentialMarkTheWords') {
559
- interaction = new SequentialMarkTheWords(parseResult.data, config);
560
- } else if (example.type === 'TextTransformation') {
561
- interaction = new TextTransformation(parseResult.data, config, example.expectedTransformations);
562
- } else if (example.type === 'SequentialTextTransformation') {
563
- interaction = new SequentialTextTransformation(parseResult.data, config, example.expectedTransformationsByStep);
564
- } else if (example.type === 'SequentialCategorizeTheWords') {
565
- interaction = new SequentialCategorizeTheWords(parseResult.data, config);
566
- } else if (example.type === 'DNDTextDemo') {
567
- interaction = new DNDTextDemo(parseResult.data, config);
568
- } else if (example.type === 'FillBlanks') {
569
- interaction = new FillBlanks(parseResult.data, config);
570
- } else if (example.type === 'CategorizeTheWords') {
571
- interaction = new CategorizeTheWords(parseResult.data, config);
572
- } else {
573
- interaction = new SequentialFillBlanks(parseResult.data, config);
574
- }
575
-
576
- viewport.setInteraction(interaction);
577
- currentInteraction = interaction;
578
-
579
- // Update active button
580
- document.querySelectorAll('.example-btn').forEach(btn => {
581
- btn.classList.toggle('active', btn.dataset.example === key);
582
- });
583
- }
584
-
585
- // ==================== EVENT LISTENERS ====================
586
-
587
- document.querySelectorAll('.example-btn').forEach(btn => {
588
- btn.addEventListener('click', () => loadExample(btn.dataset.example));
589
- });
590
-
591
- variantSelect.addEventListener('change', (e) => {
592
- currentVariant = e.target.value;
593
- if (currentInteraction) {
594
- currentInteraction.onVariantChange(currentVariant);
595
- viewport.setAttribute('variant', currentVariant);
596
- }
597
- });
598
-
599
- // ==================== INIT ====================
600
-
601
- window.addEventListener('DOMContentLoaded', () => loadExample('mtw-programming'));
602
- </script>
603
- </body>
604
- </html>