@windward/games 0.16.0 → 0.17.1
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 +6 -0
- package/components/content/blocks/flashcards/CardFace.vue +2 -1
- package/components/content/blocks/flashcards/Flashcard.vue +15 -5
- package/components/content/blocks/multipleChoice/MultipleChoice.vue +48 -8
- package/components/settings/FlashCardSlidesManager.vue +88 -0
- package/i18n/en-US/components/content/blocks/multiple_choice.ts +1 -0
- package/i18n/en-US/components/settings/flashcard.ts +5 -0
- package/i18n/es-ES/components/content/blocks/flashcard.ts +1 -0
- package/i18n/es-ES/components/content/blocks/multiple_choice.ts +1 -0
- package/i18n/es-ES/components/settings/flashcard.ts +5 -0
- package/i18n/sv-SE/components/content/blocks/flashcard.ts +1 -0
- package/i18n/sv-SE/components/content/blocks/multiple_choice.ts +1 -0
- package/i18n/sv-SE/components/settings/flashcard.ts +5 -0
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<v-container
|
|
3
|
+
:key="updateCardKey"
|
|
3
4
|
style="height: 100%"
|
|
4
5
|
class="div-container"
|
|
5
|
-
:key="updateCardKey"
|
|
6
6
|
>
|
|
7
7
|
<v-card
|
|
8
|
-
|
|
9
|
-
@click="toggleCard"
|
|
8
|
+
ref="cardFront"
|
|
10
9
|
v-show="side"
|
|
10
|
+
outlined
|
|
11
11
|
:class="cardClass"
|
|
12
12
|
style="height: 90%"
|
|
13
|
+
@keyup.enter="toggleCard"
|
|
14
|
+
@click="toggleCard"
|
|
13
15
|
>
|
|
14
16
|
<v-card-text class="fill-height">
|
|
15
17
|
<CardFace
|
|
@@ -20,11 +22,13 @@
|
|
|
20
22
|
</v-card-text>
|
|
21
23
|
</v-card>
|
|
22
24
|
<v-card
|
|
23
|
-
|
|
24
|
-
@click="toggleCard"
|
|
25
|
+
ref="cardBack"
|
|
25
26
|
v-show="!side"
|
|
27
|
+
outlined
|
|
26
28
|
:class="cardClass"
|
|
27
29
|
style="height: 90%"
|
|
30
|
+
@keyup.enter="toggleCard"
|
|
31
|
+
@click="toggleCard"
|
|
28
32
|
>
|
|
29
33
|
<v-card-title class="card-title">
|
|
30
34
|
<v-row align="center" justify="center">{{
|
|
@@ -118,6 +122,12 @@ export default {
|
|
|
118
122
|
this.side = !this.side
|
|
119
123
|
// update container with correct side
|
|
120
124
|
this.updateCardKey = Crypto.id()
|
|
125
|
+
this.$nextTick(() => {
|
|
126
|
+
const target = this.side
|
|
127
|
+
? this.$refs.cardFront
|
|
128
|
+
: this.$refs.cardBack
|
|
129
|
+
target.$el.focus()
|
|
130
|
+
})
|
|
121
131
|
},
|
|
122
132
|
},
|
|
123
133
|
}
|
|
@@ -71,7 +71,10 @@
|
|
|
71
71
|
@keyup.enter="onChooseAnswer(answer, question)"
|
|
72
72
|
>
|
|
73
73
|
<div class="d-flex justify-space-between">
|
|
74
|
-
<p
|
|
74
|
+
<p
|
|
75
|
+
class="mb-0"
|
|
76
|
+
:aria-labelledby="answer.value"
|
|
77
|
+
>
|
|
75
78
|
{{
|
|
76
79
|
getCharacter(question, answer) +
|
|
77
80
|
'. ' +
|
|
@@ -86,6 +89,18 @@
|
|
|
86
89
|
answer
|
|
87
90
|
) !== undefined
|
|
88
91
|
"
|
|
92
|
+
:ref="
|
|
93
|
+
'icon-information-' +
|
|
94
|
+
question.id +
|
|
95
|
+
'-' +
|
|
96
|
+
answer.id
|
|
97
|
+
"
|
|
98
|
+
tabindex="0"
|
|
99
|
+
:aria-label="
|
|
100
|
+
$t(
|
|
101
|
+
'windward.games.components.content.blocks.multiple_choice.information'
|
|
102
|
+
)
|
|
103
|
+
"
|
|
89
104
|
:class="
|
|
90
105
|
handleInformationClass(
|
|
91
106
|
question,
|
|
@@ -93,7 +108,10 @@
|
|
|
93
108
|
)
|
|
94
109
|
"
|
|
95
110
|
@click="
|
|
96
|
-
onAnswerDescription(
|
|
111
|
+
onAnswerDescription(
|
|
112
|
+
question,
|
|
113
|
+
answer
|
|
114
|
+
)
|
|
97
115
|
"
|
|
98
116
|
>{{
|
|
99
117
|
handleInformationOutline(
|
|
@@ -112,6 +130,7 @@
|
|
|
112
130
|
<v-col cols="12" md="12">
|
|
113
131
|
<v-row class="d-flex justify-center">
|
|
114
132
|
<v-btn
|
|
133
|
+
:ref="'btn-hint-' + question.id"
|
|
115
134
|
color="primary"
|
|
116
135
|
text
|
|
117
136
|
elevation="0"
|
|
@@ -179,7 +198,6 @@
|
|
|
179
198
|
:trigger="false"
|
|
180
199
|
@click:outside="close"
|
|
181
200
|
@click:close="close"
|
|
182
|
-
@keydown.esc="close"
|
|
183
201
|
>
|
|
184
202
|
<template #title>
|
|
185
203
|
<div v-if="hint">
|
|
@@ -253,6 +271,8 @@ export default {
|
|
|
253
271
|
answerDescriptionModal: false,
|
|
254
272
|
answerDescription: '',
|
|
255
273
|
studentResponses: [],
|
|
274
|
+
activeQuestion: '',
|
|
275
|
+
activeAnswer: '',
|
|
256
276
|
}
|
|
257
277
|
},
|
|
258
278
|
computed: {
|
|
@@ -282,7 +302,9 @@ export default {
|
|
|
282
302
|
},
|
|
283
303
|
},
|
|
284
304
|
methods: {
|
|
285
|
-
onAnswerDescription(question) {
|
|
305
|
+
onAnswerDescription(question, answer) {
|
|
306
|
+
this.activeQuestion = question
|
|
307
|
+
this.activeAnswer = answer
|
|
286
308
|
//launches modal and displays anwer description
|
|
287
309
|
this.dialog = true
|
|
288
310
|
this.answerDescriptionModal = true
|
|
@@ -471,6 +493,7 @@ export default {
|
|
|
471
493
|
return letters[answerIndex]
|
|
472
494
|
},
|
|
473
495
|
onHint(question) {
|
|
496
|
+
this.activeQuestion = question
|
|
474
497
|
// launches dialog modal
|
|
475
498
|
this.dialog = true
|
|
476
499
|
this.hint = true
|
|
@@ -514,11 +537,28 @@ export default {
|
|
|
514
537
|
return array
|
|
515
538
|
},
|
|
516
539
|
close() {
|
|
540
|
+
if (this.answerDescriptionModal) {
|
|
541
|
+
this.answerDescriptionModal = false
|
|
542
|
+
this.answerDescription = ''
|
|
543
|
+
const iconButton =
|
|
544
|
+
this.$refs[
|
|
545
|
+
'icon-information-' +
|
|
546
|
+
this.activeQuestion.id +
|
|
547
|
+
'-' +
|
|
548
|
+
this.activeAnswer.id
|
|
549
|
+
][0].$el
|
|
550
|
+
iconButton.focus()
|
|
551
|
+
this.activeAnswer = ''
|
|
552
|
+
this.activeQuestion = ''
|
|
553
|
+
} else if (this.hint) {
|
|
554
|
+
this.hint = false
|
|
555
|
+
this.hintText = ''
|
|
556
|
+
const hintButton =
|
|
557
|
+
this.$refs['btn-hint-' + this.activeQuestion.id][0].$el
|
|
558
|
+
hintButton.focus()
|
|
559
|
+
this.activeQuestion = ''
|
|
560
|
+
}
|
|
517
561
|
this.dialog = false
|
|
518
|
-
this.hint = false
|
|
519
|
-
this.answerDescriptionModal = false
|
|
520
|
-
this.hintText = ''
|
|
521
|
-
this.answerDescription = ''
|
|
522
562
|
},
|
|
523
563
|
},
|
|
524
564
|
}
|
|
@@ -277,15 +277,31 @@
|
|
|
277
277
|
indeterminate
|
|
278
278
|
></v-progress-circular>
|
|
279
279
|
</div>
|
|
280
|
+
<v-container class="pa-4 mb-6">
|
|
281
|
+
<v-row>
|
|
282
|
+
<v-col cols="12">
|
|
283
|
+
<GenerateAIQuestionButton
|
|
284
|
+
:course="course"
|
|
285
|
+
:content="content"
|
|
286
|
+
:block="block"
|
|
287
|
+
question-type="flashcard"
|
|
288
|
+
:replace-existing-mode="replaceExisting"
|
|
289
|
+
@click:generate="onGeneratedFlashcards"
|
|
290
|
+
></GenerateAIQuestionButton>
|
|
291
|
+
</v-col>
|
|
292
|
+
</v-row>
|
|
293
|
+
</v-container>
|
|
280
294
|
</div>
|
|
281
295
|
</template>
|
|
282
296
|
|
|
283
297
|
<script>
|
|
284
298
|
import _ from 'lodash'
|
|
299
|
+
import { mapGetters } from 'vuex'
|
|
285
300
|
import {
|
|
286
301
|
MathExpressionEditor,
|
|
287
302
|
MathLiveWrapper,
|
|
288
303
|
ContentViewer,
|
|
304
|
+
GenerateAIQuestionButton
|
|
289
305
|
} from '@windward/core/utils'
|
|
290
306
|
import BaseContentSettings from '~/components/Content/Settings/BaseContentSettings.js'
|
|
291
307
|
import ContentBlockAsset from '~/components/Content/ContentBlockAsset.vue'
|
|
@@ -305,11 +321,13 @@ export default {
|
|
|
305
321
|
TextEditor,
|
|
306
322
|
SortableExpansionPanel,
|
|
307
323
|
ImageAssetSettings,
|
|
324
|
+
GenerateAIQuestionButton,
|
|
308
325
|
},
|
|
309
326
|
data() {
|
|
310
327
|
return {
|
|
311
328
|
loading: false,
|
|
312
329
|
valid: true,
|
|
330
|
+
replaceExisting: false,
|
|
313
331
|
}
|
|
314
332
|
},
|
|
315
333
|
beforeMount() {
|
|
@@ -342,6 +360,10 @@ export default {
|
|
|
342
360
|
},
|
|
343
361
|
|
|
344
362
|
computed: {
|
|
363
|
+
...mapGetters({
|
|
364
|
+
course: 'course/get',
|
|
365
|
+
content: 'content/get',
|
|
366
|
+
}),
|
|
345
367
|
defaultCard() {
|
|
346
368
|
return {
|
|
347
369
|
front: {
|
|
@@ -440,6 +462,72 @@ export default {
|
|
|
440
462
|
}
|
|
441
463
|
return htmlString.replace(/(<([^>]+)>)/gi, '')
|
|
442
464
|
},
|
|
465
|
+
// Handler for receiving flashcards from GenerateAIQuestionButton
|
|
466
|
+
onGeneratedFlashcards(activityData, replaceCards) {
|
|
467
|
+
this.loading = true
|
|
468
|
+
try {
|
|
469
|
+
// Now process the activity data
|
|
470
|
+
if (activityData && activityData.metadata &&
|
|
471
|
+
activityData.metadata.config &&
|
|
472
|
+
activityData.metadata.config.cards &&
|
|
473
|
+
Array.isArray(activityData.metadata.config.cards)) {
|
|
474
|
+
|
|
475
|
+
// Save new cards
|
|
476
|
+
const newCards = activityData.metadata.config.cards.map(card => ({
|
|
477
|
+
front: { ...card.front },
|
|
478
|
+
back: { ...card.back },
|
|
479
|
+
side: card.side !== undefined ? card.side : true,
|
|
480
|
+
expand: false
|
|
481
|
+
}))
|
|
482
|
+
|
|
483
|
+
if (replaceCards) {
|
|
484
|
+
// Replace mode: Clear existing cards
|
|
485
|
+
this.block.metadata.config.cards.splice(0, this.block.metadata.config.cards.length)
|
|
486
|
+
|
|
487
|
+
// Add all new cards
|
|
488
|
+
newCards.forEach(card => {
|
|
489
|
+
this.block.metadata.config.cards.push(card)
|
|
490
|
+
})
|
|
491
|
+
} else {
|
|
492
|
+
// Merge mode: Add new cards to existing ones
|
|
493
|
+
newCards.forEach(card => {
|
|
494
|
+
this.block.metadata.config.cards.push(card)
|
|
495
|
+
})
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
// Update title and instructions if provided and we're in replace mode
|
|
499
|
+
if (replaceCards) {
|
|
500
|
+
if (activityData.metadata.config.title) {
|
|
501
|
+
this.block.metadata.config.title = activityData.metadata.config.title
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
if (activityData.metadata.config.instructions) {
|
|
505
|
+
this.block.metadata.config.instructions = activityData.metadata.config.instructions
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
this.$toast.success(
|
|
510
|
+
replaceCards
|
|
511
|
+
? this.$t('windward.games.components.settings.flashcard.form.replaced_successfully')
|
|
512
|
+
: this.$t('windward.games.components.settings.flashcard.form.added_successfully'),
|
|
513
|
+
{ duration: 3000 }
|
|
514
|
+
)
|
|
515
|
+
} else {
|
|
516
|
+
this.$toast.error(this.$t('windward.games.components.settings.flashcard.form.invalid_response'), {
|
|
517
|
+
duration: 5000
|
|
518
|
+
})
|
|
519
|
+
}
|
|
520
|
+
} catch (error) {
|
|
521
|
+
// Extract error message from the response
|
|
522
|
+
const errorMessage = error.message || 'Unknown error occurred'
|
|
523
|
+
this.$toast.error(`${this.$t('windward.games.components.settings.flashcard.form.failed_to_process')}: ${errorMessage}`, {
|
|
524
|
+
duration: 5000
|
|
525
|
+
})
|
|
526
|
+
} finally {
|
|
527
|
+
this.loading = false
|
|
528
|
+
}
|
|
529
|
+
}
|
|
443
530
|
},
|
|
444
531
|
}
|
|
445
532
|
</script>
|
|
533
|
+
|
|
@@ -26,5 +26,10 @@ export default {
|
|
|
26
26
|
'The character count for this field must be less than',
|
|
27
27
|
},
|
|
28
28
|
instructions:"Click on each card to reveal the term's definition. Use the arrows to move through the deck.",
|
|
29
|
+
replace_existing: 'Replace existing flashcards',
|
|
30
|
+
replaced_successfully: 'Flashcards replaced successfully',
|
|
31
|
+
added_successfully: 'New flashcards added successfully',
|
|
32
|
+
invalid_response: 'Invalid response from flashcard generation',
|
|
33
|
+
failed_to_process: 'Failed to process generated flashcards'
|
|
29
34
|
},
|
|
30
35
|
}
|
|
@@ -26,5 +26,10 @@ export default {
|
|
|
26
26
|
'El número de caracteres para este campo debe ser menor que',
|
|
27
27
|
},
|
|
28
28
|
instructions:"Haga clic en cada tarjeta para revelar la definición del término. Usa las flechas para moverte por el mazo.",
|
|
29
|
+
replace_existing: 'Reemplazar tarjetas existentes',
|
|
30
|
+
replaced_successfully: 'Tarjetas reemplazadas con éxito',
|
|
31
|
+
added_successfully: 'Nuevas tarjetas agregadas con éxito',
|
|
32
|
+
invalid_response: 'Respuesta inválida de la generación de tarjetas',
|
|
33
|
+
failed_to_process: 'Error al procesar las tarjetas generadas'
|
|
29
34
|
},
|
|
30
35
|
}
|
|
@@ -26,5 +26,10 @@ export default {
|
|
|
26
26
|
'Teckenantalet för detta fält måste vara mindre än',
|
|
27
27
|
},
|
|
28
28
|
instructions:"Klicka på varje kort för att avslöja termens definition. Använd pilarna för att flytta genom däcket.",
|
|
29
|
+
replace_existing: 'Ersätt befintliga flashcards',
|
|
30
|
+
replaced_successfully: 'Flashkort har ersatts framgångsrikt',
|
|
31
|
+
added_successfully: 'Nya flashkort har lagts till',
|
|
32
|
+
invalid_response: 'Ogiltigt svar från genereringen av flashkort',
|
|
33
|
+
failed_to_process: 'Kunde inte bearbeta genererade flashkort'
|
|
29
34
|
},
|
|
30
35
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@windward/games",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.17.1",
|
|
4
4
|
"description": "Windward UI Plugin Games",
|
|
5
5
|
"main": "plugin.js",
|
|
6
6
|
"scripts": {
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"license": "MIT",
|
|
22
22
|
"homepage": "https://bitbucket.org/mindedge/windward-ui-plugin-games#readme",
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"@windward/core": "^0.
|
|
24
|
+
"@windward/core": "^0.17.0",
|
|
25
25
|
"eslint": "^8.11.0",
|
|
26
26
|
"lodash": "^4.17.21",
|
|
27
27
|
"prettier": "^2.6.0",
|