@windward/games 0.23.0 → 0.25.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # Changelog
2
2
 
3
+ ## Release [0.25.0] - 2025-12-02
4
+
5
+ * Merged in feature/LE-2156-block-settings-label (pull request #264)
6
+ * Merged in LE-2184-feedback-text-placeholder (pull request #267)
7
+
8
+
9
+ ## Release [0.24.0] - 2025-10-23
10
+
11
+ * Merged in feature/LE-2034/generate-crossword (pull request #262)
12
+ * Merged in bugfix/LE-2020-the-quiz-show-manager-panel-does (pull request #263)
13
+
14
+
3
15
  ## Release [0.23.0] - 2025-09-16
4
16
 
5
17
  * Merged in feature/LE-2035/seven-strikes (pull request #259)
@@ -30,16 +30,10 @@
30
30
  )
31
31
  }}
32
32
  </h4>
33
- <v-alert fluid :class="status">
33
+ <v-alert v-if="feedback" fluid :class="status">
34
34
  <v-row class="pa-4 d-flex justify-center">
35
35
  <p class="mb-0 p-text-override">
36
- {{
37
- feedback
38
- ? feedback
39
- : $t(
40
- 'windward.games.components.content.blocks.bucket_game.form.feedback.feedback_here'
41
- )
42
- }}
36
+ {{ feedback }}
43
37
  </p>
44
38
  </v-row>
45
39
  <v-row class="d-flex justify-center mt-0 mb-1">
@@ -176,7 +176,7 @@ export default {
176
176
  isDisabled: false,
177
177
  reload: false,
178
178
  input: [],
179
- feedback: 'feedback here',
179
+ feedback: '',
180
180
  success: [],
181
181
  fail: [],
182
182
  seed: 123,
@@ -26,10 +26,6 @@
26
26
  <v-container :class="status">
27
27
  <v-row class="d-flex justify-center pa-2">{{
28
28
  feedback
29
- ? feedback
30
- : $t(
31
- 'windward.games.components.content.blocks.bucket_game.form.feedback.feedback_here'
32
- )
33
29
  }}</v-row>
34
30
  <v-row class="d-flex justify-center pa-2" v-if="!gameCompleted">
35
31
  <v-btn
@@ -392,9 +388,7 @@ export default {
392
388
  },
393
389
  data() {
394
390
  return {
395
- feedback: this.$t(
396
- 'windward.games.components.content.blocks.matching_game.default_feedback'
397
- ),
391
+ feedback: '',
398
392
  gameCompleted: false,
399
393
  shufflePrompts: [],
400
394
  solvedQuestions: [],
@@ -528,9 +522,7 @@ export default {
528
522
  this.status = 'default'
529
523
  this.allowDrag = true
530
524
  this.droppedElement = null
531
- this.feedback = this.$t(
532
- 'windward.games.components.content.blocks.matching_game.default_feedback'
533
- )
525
+ this.feedback = ''
534
526
  },
535
527
  onContinueGame() {
536
528
  if (!this.render) {
@@ -541,9 +533,7 @@ export default {
541
533
  this.mainPrompt = this.shufflePrompts.shift()
542
534
  this.allowDrag = true
543
535
  this.droppedElement = null
544
- this.feedback = this.$t(
545
- 'windward.games.components.content.blocks.matching_game.default_feedback'
546
- )
536
+ this.feedback = ''
547
537
  },
548
538
  onReset() {
549
539
  this.shufflePrompts = []
@@ -552,9 +542,7 @@ export default {
552
542
  this.solvedQuestions = []
553
543
  this.gameCompleted = false
554
544
  this.allowDrag = true
555
- this.feedback = this.$t(
556
- 'windward.games.components.content.blocks.matching_game.default_feedback'
557
- )
545
+ this.feedback = ''
558
546
  this.setMainPrompt()
559
547
  },
560
548
  },
@@ -31,10 +31,10 @@ export default {
31
31
  icons: {
32
32
  type: Object,
33
33
  required: false,
34
- default: {
34
+ default: () => ({
35
35
  success: 'mdi-check-circle-outline',
36
36
  error: 'mdi-close-circle-outline',
37
- },
37
+ }),
38
38
  },
39
39
  },
40
40
  }
@@ -90,6 +90,24 @@
90
90
  </v-row>
91
91
  </v-container>
92
92
  </v-container>
93
+ <v-container class="pa-4 mb-6">
94
+ <v-row>
95
+ <v-col cols="12">
96
+ <PluginRef
97
+ target="contentBlockSettingTool"
98
+ :attrs="{
99
+ value: block,
100
+ course: course,
101
+ content: currentContent,
102
+ }"
103
+ :on="{
104
+ input: onPluginSetBlock,
105
+ append: onPluginAppendBlock,
106
+ }"
107
+ ></PluginRef>
108
+ </v-col>
109
+ </v-row>
110
+ </v-container>
93
111
  <div v-if="loading" class="text-center">
94
112
  <v-progress-circular
95
113
  :size="70"
@@ -103,15 +121,17 @@
103
121
 
104
122
  <script>
105
123
  import _ from 'lodash'
124
+ import { mapGetters } from 'vuex'
106
125
  import BaseContentBlockSettings from '~/components/Content/Settings/BaseContentBlockSettings.vue'
107
126
  import BaseContentSettings from '~/components/Content/Settings/BaseContentSettings.js'
108
127
  import SortableExpansionPanel from '~/components/Core/SortableExpansionPanel.vue'
128
+ import PluginRef from '~/components/Core/PluginRef.vue'
109
129
  import Uuid from '~/helpers/Uuid'
110
130
 
111
131
  export default {
112
132
  name: 'CrosswordPuzzleSettingsManager',
113
133
  extends: BaseContentSettings,
114
- components: { SortableExpansionPanel, BaseContentBlockSettings },
134
+ components: { SortableExpansionPanel, BaseContentBlockSettings, PluginRef },
115
135
  beforeMount() {
116
136
  if (_.isEmpty(this.block)) {
117
137
  this.block = {}
@@ -186,6 +206,12 @@ export default {
186
206
  },
187
207
  }
188
208
  },
209
+ computed: {
210
+ ...mapGetters({
211
+ course: 'course/get',
212
+ currentContent: 'content/get',
213
+ }),
214
+ },
189
215
  methods: {
190
216
  onAddElement() {
191
217
  // pushes in new crossword object
@@ -207,6 +233,227 @@ export default {
207
233
  this.onAddElement()
208
234
  }
209
235
  },
236
+ onPluginSetBlock(activityData) {
237
+ this.loading = true
238
+ try {
239
+ const result = this.processGeneratedCrossword(activityData)
240
+ if (!result) {
241
+ this.showInvalidResponseToast()
242
+ return
243
+ }
244
+
245
+ this.$set(
246
+ this.block.metadata,
247
+ 'config',
248
+ this.block.metadata.config || {}
249
+ )
250
+
251
+ this.$set(
252
+ this.block.metadata.config,
253
+ 'words',
254
+ result.words.map((item, index) => ({
255
+ id: index,
256
+ word: item.word,
257
+ clue: item.clue,
258
+ expand: false,
259
+ }))
260
+ )
261
+
262
+ if (result.title) {
263
+ this.block.metadata.config.title = result.title
264
+ }
265
+
266
+ this.$toast.success(
267
+ this.$t(
268
+ 'windward.games.components.settings.crossword.replaced_successfully'
269
+ ),
270
+ { duration: 3000 }
271
+ )
272
+ } catch (error) {
273
+ console.error('Failed to process generated crossword items', error)
274
+ this.$toast.error(
275
+ this.$t(
276
+ 'windward.games.components.settings.crossword.failed_to_process'
277
+ ),
278
+ { duration: 5000 }
279
+ )
280
+ } finally {
281
+ this.loading = false
282
+ }
283
+ },
284
+ onPluginAppendBlock(activityData) {
285
+ this.loading = true
286
+ try {
287
+ const result = this.processGeneratedCrossword(activityData)
288
+ if (!result) {
289
+ this.showInvalidResponseToast()
290
+ return
291
+ }
292
+
293
+ if (!Array.isArray(this.block.metadata.config.words)) {
294
+ this.$set(this.block.metadata.config, 'words', [])
295
+ }
296
+
297
+ const startingIndex = this.block.metadata.config.words.length
298
+
299
+ result.words.forEach((item, index) => {
300
+ this.block.metadata.config.words.push({
301
+ id: startingIndex + index,
302
+ word: item.word,
303
+ clue: item.clue,
304
+ expand: false,
305
+ })
306
+ })
307
+
308
+ this.renumberWordIds()
309
+
310
+ if (result.title) {
311
+ const defaultTitle = this.$t(
312
+ 'windward.games.components.content.blocks.crossword.crossword'
313
+ )
314
+ if (
315
+ !this.block.metadata.config.title ||
316
+ this.block.metadata.config.title === defaultTitle
317
+ ) {
318
+ this.block.metadata.config.title = result.title
319
+ }
320
+ }
321
+
322
+ this.$toast.success(
323
+ this.$t(
324
+ 'windward.games.components.settings.crossword.added_successfully'
325
+ ),
326
+ { duration: 3000 }
327
+ )
328
+ } catch (error) {
329
+ console.error('Failed to append generated crossword items', error)
330
+ this.$toast.error(
331
+ this.$t(
332
+ 'windward.games.components.settings.crossword.failed_to_process'
333
+ ),
334
+ { duration: 5000 }
335
+ )
336
+ } finally {
337
+ this.loading = false
338
+ }
339
+ },
340
+ processGeneratedCrossword(activityData) {
341
+ const config = _.get(activityData, 'metadata.config', null)
342
+ const words = _.get(config, 'words', [])
343
+
344
+ if (!Array.isArray(words) || words.length === 0) {
345
+ return null
346
+ }
347
+
348
+ const sanitizedWords = words
349
+ .map((item) => {
350
+ const sanitizedWord = this.normalizeWord(item?.word)
351
+ const sanitizedClue = this.normalizeClue(item?.clue)
352
+
353
+ if (!sanitizedWord || !sanitizedClue) {
354
+ return null
355
+ }
356
+
357
+ return {
358
+ word: sanitizedWord,
359
+ clue: sanitizedClue,
360
+ expand: false,
361
+ }
362
+ })
363
+ .filter((item) => item !== null)
364
+
365
+ if (sanitizedWords.length < 2) {
366
+ return null
367
+ }
368
+
369
+ const limitedWords = sanitizedWords.slice(0, 10)
370
+
371
+ const normalizedTitle = this.normalizeTitle(_.get(config, 'title', ''))
372
+
373
+ return {
374
+ title: normalizedTitle,
375
+ words: limitedWords,
376
+ }
377
+ },
378
+ normalizeWord(word) {
379
+ if (!word) {
380
+ return ''
381
+ }
382
+
383
+ const formatted = word
384
+ .toString()
385
+ .normalize('NFKD')
386
+ .replace(/[^A-Za-z]/g, '')
387
+ .toUpperCase()
388
+ .slice(0, 20)
389
+
390
+ return formatted
391
+ },
392
+ normalizeClue(clue) {
393
+ if (!clue) {
394
+ return ''
395
+ }
396
+
397
+ let normalized = clue
398
+ .toString()
399
+ .replace(/\s+/g, ' ')
400
+ .trim()
401
+
402
+ if (!normalized) {
403
+ return ''
404
+ }
405
+
406
+ if (normalized.endsWith('?')) {
407
+ normalized = normalized.slice(0, -1).trim()
408
+ }
409
+
410
+ const maxLength = 155
411
+ if (normalized.length > maxLength) {
412
+ normalized = normalized.slice(0, maxLength).trim()
413
+ }
414
+
415
+ if (normalized && !/[.!]$/.test(normalized)) {
416
+ if (normalized.length >= maxLength) {
417
+ normalized = normalized.slice(0, maxLength - 1).trim()
418
+ }
419
+ normalized += '.'
420
+ }
421
+
422
+ return normalized
423
+ },
424
+ normalizeTitle(title) {
425
+ if (!title) {
426
+ return ''
427
+ }
428
+
429
+ let normalized = title
430
+ .toString()
431
+ .replace(/\s+/g, ' ')
432
+ .trim()
433
+
434
+ if (!normalized) {
435
+ return ''
436
+ }
437
+
438
+ if (normalized.length > 100) {
439
+ normalized = normalized.slice(0, 100).trim()
440
+ }
441
+
442
+ return normalized
443
+ },
444
+ renumberWordIds() {
445
+ this.block.metadata.config.words.forEach((item, index) => {
446
+ item.id = index
447
+ })
448
+ },
449
+ showInvalidResponseToast() {
450
+ this.$toast.error(
451
+ this.$t(
452
+ 'windward.games.components.settings.crossword.invalid_response'
453
+ ),
454
+ { duration: 5000 }
455
+ )
456
+ },
210
457
  },
211
458
  }
212
459
  </script>
@@ -267,7 +267,8 @@ export default {
267
267
  },
268
268
  computed: {},
269
269
  beforeMount() {
270
- if (_.isEmpty(this.block.metadata.config)) {
270
+ // since display_title is already set so we'll look at a quiz show property to set settings for first mount
271
+ if (_.isEmpty(this.block.metadata.config.title)) {
271
272
  this.block.metadata.config = _.cloneDeep(this.quizShowSettings)
272
273
  }
273
274
  if (!_.isBoolean(this.block.metadata.config.display_title)) {
@@ -5,4 +5,8 @@ export default {
5
5
  min_length: 'Cannot have less than two words',
6
6
  alert: 'Alert',
7
7
  instructions: 'Complete the crossword by clicking on each square to type the appropriate letter. Use the tab key to move left to right across the grid. Click on the clue to highlight the corresponding word in the puzzle.',
8
+ replaced_successfully: 'Crossword items replaced successfully',
9
+ added_successfully: 'Crossword items added successfully',
10
+ failed_to_process: 'Failed to process generated crossword items',
11
+ invalid_response: 'Unable to process generated crossword items',
8
12
  }
@@ -1,15 +1,6 @@
1
1
  export default {
2
2
  title: {
3
- card_manager: ' Flashcard Slides Manager',
4
- bucket_manager: ' Bucket Game Manager',
5
- sorting_manager: 'Sorting Game Manager',
6
- matching_game_manager: ' Matching Game Manager',
7
- slideshow_manager: 'Slideshow Manager',
8
- quizshow_manager: 'Quizshow Manager',
9
- multiple_choice_manager: 'Multiple Choice Manager',
10
- wordjumble_manager: 'Word Jumble Manager',
11
- seven_strikes_manager: 'Seven Strikes Manager',
12
- crossword_puzzle_manager: 'Crossword Puzzle Manager',
3
+ block_builder: 'Block Builder',
13
4
  },
14
5
  errors: {
15
6
  input_limitations: 'Must be less than {0} characters.'
@@ -6,4 +6,8 @@ export default {
6
6
  alert: 'Alerta',
7
7
  instructions:
8
8
  'Complete el crucigrama haciendo clic en cada cuadrado para escribir la letra correspondiente. Utilice la tecla de tabulación para moverse de izquierda a derecha a través de la cuadrícula. Haga clic en la pista para resaltar la palabra correspondiente en el rompecabezas.',
9
+ replaced_successfully: 'Elementos del crucigrama reemplazados correctamente',
10
+ added_successfully: 'Elementos del crucigrama agregados correctamente',
11
+ failed_to_process: 'Error al procesar los elementos generados del crucigrama',
12
+ invalid_response: 'No se pudieron procesar los elementos generados del crucigrama',
9
13
  }
@@ -1,15 +1,6 @@
1
1
  export default {
2
2
  title: {
3
- card_manager: ' Administrador de diapositivas de tarjetas flash ',
4
- bucket_manager: 'Administrador del juego de cubos',
5
- sorting_manager: 'Gestor de juegos de clasificación',
6
- matching_game_manager: 'Administrador de juegos de combinación',
7
- slideshow_manager: 'Administrador de presentaciones',
8
- quizshow_manager: 'Administrador de concursos',
9
- multiple_choice_manager: 'Administrador de opciones múltiples',
10
- wordjumble_manager: 'Administrador de revoltijos de palabras',
11
- seven_strikes_manager: 'Gerente de los Siete Golpes',
12
- crossword_puzzle_manager: 'Administrador de crucigramas',
3
+ block_builder: 'Constructor de bloques',
13
4
  },
14
5
  errors: {
15
6
  input_limitations: 'Måste vara mindre än {0} tecken.',
@@ -5,4 +5,8 @@ export default {
5
5
  min_length: 'Kan inte ha mindre än två ord',
6
6
  alert: 'Alert',
7
7
  instructions: 'Fyll i korsordet genom att klicka på varje ruta för att skriva rätt bokstav. Använd tabbtangenten för att flytta från vänster till höger över rutnätet. Klicka på ledtråden för att markera motsvarande ord i pusslet.',
8
+ replaced_successfully: 'Korsordsobjekt ersattes',
9
+ added_successfully: 'Korsordsobjekt lades till',
10
+ failed_to_process: 'Det gick inte att bearbeta genererade korsordsobjekt',
11
+ invalid_response: 'Det gick inte att behandla genererade korsordsobjekt',
8
12
  }
@@ -1,15 +1,6 @@
1
1
  export default {
2
2
  title: {
3
- card_manager: ' Flashcard Slides Manager ',
4
- bucket_manager: ' Bucket Game Manager',
5
- sorting_manager: 'Sorteringsspelhanteraren',
6
- matching_game_manager: ' Matchande spelhanterare',
7
- slideshow_manager: 'Bildspelshanteraren',
8
- quizshow_manager: 'Quizshow Manager',
9
- multiple_choice_manager: 'Flervalschef',
10
- wordjumble_manager: 'Ord virrvarr manager',
11
- seven_strikes_manager: 'Sju strejker manager',
12
- crossword_puzzle_manager: 'Korsordshanterare',
3
+ block_builder: 'Blockbyggare',
13
4
  },
14
5
  errors: {
15
6
  input_limitations: 'Måste vara mindre än {0} tecken.',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@windward/games",
3
- "version": "0.23.0",
3
+ "version": "0.25.0",
4
4
  "description": "Windward UI Plugin Games",
5
5
  "main": "plugin.js",
6
6
  "scripts": {
package/plugin.js CHANGED
@@ -135,7 +135,7 @@ export default {
135
135
  context: ['block.games-flash-card'],
136
136
  metadata: {
137
137
  icon: 'mdi-cog',
138
- name: 'windward.games.shared.settings.title.card_manager',
138
+ name: 'windward.games.shared.settings.title.block_builder',
139
139
  },
140
140
  },
141
141
  {
@@ -144,7 +144,7 @@ export default {
144
144
  context: ['block.games-bucket'],
145
145
  metadata: {
146
146
  icon: 'mdi-cog',
147
- name: 'windward.games.shared.settings.title.bucket_manager',
147
+ name: 'windward.games.shared.settings.title.block_builder',
148
148
  },
149
149
  },
150
150
  {
@@ -153,7 +153,7 @@ export default {
153
153
  context: ['block.games-sorting'],
154
154
  metadata: {
155
155
  icon: 'mdi-cog',
156
- name: 'windward.games.shared.settings.title.sorting_manager',
156
+ name: 'windward.games.shared.settings.title.block_builder',
157
157
  },
158
158
  },
159
159
  {
@@ -162,7 +162,7 @@ export default {
162
162
  context: ['block.games-slideshow'],
163
163
  metadata: {
164
164
  icon: 'mdi-cog',
165
- name: 'windward.games.shared.settings.title.slideshow_manager',
165
+ name: 'windward.games.shared.settings.title.block_builder',
166
166
  },
167
167
  },
168
168
  {
@@ -171,7 +171,7 @@ export default {
171
171
  context: ['block.games-matching-game'],
172
172
  metadata: {
173
173
  icon: 'mdi-cog',
174
- name: 'windward.games.shared.settings.title.matching_game_manager',
174
+ name: 'windward.games.shared.settings.title.block_builder',
175
175
  },
176
176
  },
177
177
  {
@@ -180,7 +180,7 @@ export default {
180
180
  context: ['block.games-quizshow-game'],
181
181
  metadata: {
182
182
  icon: 'mdi-cog',
183
- name: 'windward.games.shared.settings.title.quizshow_manager',
183
+ name: 'windward.games.shared.settings.title.block_builder',
184
184
  },
185
185
  },
186
186
  {
@@ -189,7 +189,7 @@ export default {
189
189
  context: ['block.games-multiple-choice'],
190
190
  metadata: {
191
191
  icon: 'mdi-cog',
192
- name: 'windward.games.shared.settings.title.multiple_choice_manager',
192
+ name: 'windward.games.shared.settings.title.block_builder',
193
193
  },
194
194
  },
195
195
  {
@@ -198,7 +198,7 @@ export default {
198
198
  context: ['block.games-wordjumble-game'],
199
199
  metadata: {
200
200
  icon: 'mdi-cog',
201
- name: 'windward.games.shared.settings.title.wordjumble_manager',
201
+ name: 'windward.games.shared.settings.title.block_builder',
202
202
  },
203
203
  },
204
204
  {
@@ -207,7 +207,7 @@ export default {
207
207
  context: ['block.games-seven-strikes-game'],
208
208
  metadata: {
209
209
  icon: 'mdi-cog',
210
- name: 'windward.games.shared.settings.title.seven_strikes_manager',
210
+ name: 'windward.games.shared.settings.title.block_builder',
211
211
  },
212
212
  },
213
213
  {
@@ -216,7 +216,7 @@ export default {
216
216
  context: ['block.games-crossword-puzzle-game'],
217
217
  metadata: {
218
218
  icon: 'mdi-cog',
219
- name: 'windward.games.shared.settings.title.crossword_puzzle_manager',
219
+ name: 'windward.games.shared.settings.title.block_builder',
220
220
  },
221
221
  },
222
222
  ],