@windward/games 0.21.0 → 0.23.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 +19 -0
- package/components/content/blocks/multipleChoice/MultipleChoice.vue +25 -11
- package/components/content/blocks/multipleChoice/QuestionDialog.vue +0 -9
- package/components/settings/BucketGameSettingsManager.vue +136 -96
- package/components/settings/FlashCardSlidesManager.vue +122 -51
- package/components/settings/MatchingGameManager.vue +179 -84
- package/components/settings/MultipleChoiceSettingsManager.vue +132 -0
- package/components/settings/SevenStrikesSettingsManager.vue +91 -0
- package/components/settings/SortingGameSettingsManager.vue +103 -58
- package/components/settings/WordJumbleSettingsManager.vue +157 -0
- package/i18n/en-US/components/settings/multiple_choice.ts +4 -0
- package/i18n/en-US/components/settings/word_jumble.ts +9 -0
- package/i18n/es-ES/components/settings/multiple_choice.ts +4 -0
- package/i18n/es-ES/components/settings/word_jumble.ts +9 -0
- package/i18n/sv-SE/components/settings/multiple_choice.ts +4 -0
- package/i18n/sv-SE/components/settings/word_jumble.ts +9 -0
- package/package.json +2 -2
- package/plugin.js +1 -1
|
@@ -251,14 +251,18 @@
|
|
|
251
251
|
<v-container class="pa-4 mb-6">
|
|
252
252
|
<v-row>
|
|
253
253
|
<v-col cols="12">
|
|
254
|
-
<
|
|
255
|
-
|
|
256
|
-
:
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
254
|
+
<PluginRef
|
|
255
|
+
target="contentBlockSettingTool"
|
|
256
|
+
:attrs="{
|
|
257
|
+
value: block,
|
|
258
|
+
course: course,
|
|
259
|
+
content: currentContent,
|
|
260
|
+
}"
|
|
261
|
+
:on="{
|
|
262
|
+
input: onPluginSetBlock,
|
|
263
|
+
append: onPluginAppendBlock,
|
|
264
|
+
}"
|
|
265
|
+
></PluginRef>
|
|
262
266
|
</v-col>
|
|
263
267
|
</v-row>
|
|
264
268
|
</v-container>
|
|
@@ -269,7 +273,7 @@
|
|
|
269
273
|
import BaseContentSettings from '~/components/Content/Settings/BaseContentSettings.js'
|
|
270
274
|
import _ from 'lodash'
|
|
271
275
|
import { mapGetters } from 'vuex'
|
|
272
|
-
import
|
|
276
|
+
import PluginRef from '~/components/Core/PluginRef.vue'
|
|
273
277
|
import BaseContentBlockSettings from '~/components/Content/Settings/BaseContentBlockSettings.vue'
|
|
274
278
|
import SortableExpansionPanel from '~/components/Core/SortableExpansionPanel.vue'
|
|
275
279
|
import Uuid from '~/helpers/Uuid'
|
|
@@ -282,7 +286,7 @@ export default {
|
|
|
282
286
|
SortableExpansionPanel,
|
|
283
287
|
ImageAssetSettings,
|
|
284
288
|
BaseContentBlockSettings,
|
|
285
|
-
|
|
289
|
+
PluginRef,
|
|
286
290
|
},
|
|
287
291
|
beforeMount() {
|
|
288
292
|
if (_.isEmpty(this.block)) {
|
|
@@ -488,129 +492,220 @@ export default {
|
|
|
488
492
|
// holder array now has new answer positions
|
|
489
493
|
this.block.metadata.config.prompts = holderArray
|
|
490
494
|
},
|
|
491
|
-
// Handler for receiving matching game data from
|
|
492
|
-
|
|
493
|
-
|
|
495
|
+
// Handler for receiving matching game data from Plugins
|
|
496
|
+
onPluginSetBlock(activityData) {
|
|
494
497
|
this.loading = true
|
|
495
498
|
try {
|
|
496
499
|
// Process the activity data
|
|
497
|
-
if (
|
|
500
|
+
if (
|
|
501
|
+
activityData &&
|
|
502
|
+
activityData.metadata &&
|
|
498
503
|
activityData.metadata.config &&
|
|
499
504
|
activityData.metadata.config.answerObjects &&
|
|
500
505
|
activityData.metadata.config.prompts &&
|
|
501
506
|
Array.isArray(activityData.metadata.config.answerObjects) &&
|
|
502
|
-
Array.isArray(activityData.metadata.config.prompts)
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
this.block.metadata.config.
|
|
507
|
+
Array.isArray(activityData.metadata.config.prompts)
|
|
508
|
+
) {
|
|
509
|
+
// Replace mode: Clear existing answers and prompts
|
|
510
|
+
this.block.metadata.config.answerObjects.splice(
|
|
511
|
+
0,
|
|
512
|
+
this.block.metadata.config.answerObjects.length
|
|
513
|
+
)
|
|
514
|
+
this.block.metadata.config.prompts.splice(
|
|
515
|
+
0,
|
|
516
|
+
this.block.metadata.config.prompts.length
|
|
517
|
+
)
|
|
508
518
|
|
|
509
|
-
|
|
510
|
-
|
|
519
|
+
// Add all new answer objects and prompts
|
|
520
|
+
activityData.metadata.config.answerObjects.forEach(
|
|
521
|
+
(answerObj, index) => {
|
|
511
522
|
this.block.metadata.config.answerObjects.push({
|
|
512
|
-
id: index.toString(),
|
|
513
|
-
display: answerObj.display || ''
|
|
523
|
+
id: index.toString(), // string id
|
|
524
|
+
display: answerObj.display || '',
|
|
514
525
|
})
|
|
515
|
-
}
|
|
526
|
+
}
|
|
527
|
+
)
|
|
516
528
|
|
|
517
|
-
|
|
518
|
-
|
|
529
|
+
// Add all prompts - following the exact pattern from BucketGameSettingsManager
|
|
530
|
+
activityData.metadata.config.prompts.forEach(
|
|
531
|
+
(promptArray, index) => {
|
|
519
532
|
this.block.metadata.config.prompts[index] = []
|
|
520
533
|
if (Array.isArray(promptArray)) {
|
|
521
|
-
promptArray.forEach(prompt => {
|
|
534
|
+
promptArray.forEach((prompt) => {
|
|
522
535
|
// Ensure the answer object reference is correct
|
|
523
|
-
const answerObj =
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
536
|
+
const answerObj =
|
|
537
|
+
this.block.metadata.config
|
|
538
|
+
.answerObjects[index]
|
|
539
|
+
this.block.metadata.config.prompts[
|
|
540
|
+
index
|
|
541
|
+
].push({
|
|
542
|
+
id: index.toString(), // string id
|
|
543
|
+
textOrImage:
|
|
544
|
+
prompt.textOrImage || 'text',
|
|
527
545
|
prompt: prompt.prompt || '',
|
|
528
|
-
matchExplanation:
|
|
546
|
+
matchExplanation:
|
|
547
|
+
prompt.matchExplanation ||
|
|
548
|
+
this.$t(
|
|
549
|
+
'windward.games.components.settings.matching_game.form.correct_match'
|
|
550
|
+
),
|
|
529
551
|
fileConfig: prompt.fileConfig || {
|
|
530
552
|
hideBackground: true,
|
|
531
553
|
},
|
|
532
|
-
answer: answerObj
|
|
554
|
+
answer: answerObj,
|
|
533
555
|
})
|
|
534
556
|
})
|
|
535
557
|
}
|
|
536
|
-
})
|
|
537
|
-
} else {
|
|
538
|
-
// Merge mode: Add new terms and prompts to existing ones
|
|
539
|
-
// Check if there's only one empty answer (the default one created on init)
|
|
540
|
-
const hasOnlyEmptyAnswer = this.block.metadata.config.answerObjects.length === 1 &&
|
|
541
|
-
this.block.metadata.config.answerObjects[0].display === '';
|
|
542
|
-
|
|
543
|
-
if (hasOnlyEmptyAnswer) {
|
|
544
|
-
// If there's only one empty answer, replace it instead of merging
|
|
545
|
-
this.block.metadata.config.answerObjects.splice(0, 1);
|
|
546
|
-
this.block.metadata.config.prompts.splice(0, 1);
|
|
547
558
|
}
|
|
548
|
-
|
|
549
|
-
const existingAnswerCount = this.block.metadata.config.answerObjects.length
|
|
559
|
+
)
|
|
550
560
|
|
|
551
|
-
|
|
552
|
-
|
|
561
|
+
// Update title and instructions if provided and we're in replace mode
|
|
562
|
+
|
|
563
|
+
if (activityData.metadata.config.title) {
|
|
564
|
+
this.block.metadata.config.title =
|
|
565
|
+
activityData.metadata.config.title
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
if (activityData.metadata.config.instructions) {
|
|
569
|
+
this.block.metadata.config.instructions =
|
|
570
|
+
activityData.metadata.config.instructions
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
this.$toast.success(
|
|
574
|
+
this.$t(
|
|
575
|
+
'windward.games.components.settings.matching_game.form.replaced_successfully'
|
|
576
|
+
),
|
|
577
|
+
{ duration: 3000 }
|
|
578
|
+
)
|
|
579
|
+
} else {
|
|
580
|
+
this.$toast.error(
|
|
581
|
+
this.$t(
|
|
582
|
+
'windward.games.components.settings.matching_game.form.invalid_response'
|
|
583
|
+
),
|
|
584
|
+
{
|
|
585
|
+
duration: 5000,
|
|
586
|
+
}
|
|
587
|
+
)
|
|
588
|
+
}
|
|
589
|
+
} catch (error) {
|
|
590
|
+
// Extract error message from the response
|
|
591
|
+
const errorMessage = error.message || 'Unknown error occurred'
|
|
592
|
+
this.$toast.error(
|
|
593
|
+
`${this.$t(
|
|
594
|
+
'windward.games.components.settings.matching_game.form.failed_to_process'
|
|
595
|
+
)}: ${errorMessage}`,
|
|
596
|
+
{
|
|
597
|
+
duration: 5000,
|
|
598
|
+
}
|
|
599
|
+
)
|
|
600
|
+
} finally {
|
|
601
|
+
this.loading = false
|
|
602
|
+
}
|
|
603
|
+
},
|
|
604
|
+
|
|
605
|
+
onPluginAppendBlock(activityData) {
|
|
606
|
+
this.loading = true
|
|
607
|
+
try {
|
|
608
|
+
// Process the activity data
|
|
609
|
+
if (
|
|
610
|
+
activityData &&
|
|
611
|
+
activityData.metadata &&
|
|
612
|
+
activityData.metadata.config &&
|
|
613
|
+
activityData.metadata.config.answerObjects &&
|
|
614
|
+
activityData.metadata.config.prompts &&
|
|
615
|
+
Array.isArray(activityData.metadata.config.answerObjects) &&
|
|
616
|
+
Array.isArray(activityData.metadata.config.prompts)
|
|
617
|
+
) {
|
|
618
|
+
// Merge mode: Add new terms and prompts to existing ones
|
|
619
|
+
// Check if there's only one empty answer (the default one created on init)
|
|
620
|
+
const hasOnlyEmptyAnswer =
|
|
621
|
+
this.block.metadata.config.answerObjects.length === 1 &&
|
|
622
|
+
this.block.metadata.config.answerObjects[0].display ===
|
|
623
|
+
''
|
|
624
|
+
|
|
625
|
+
if (hasOnlyEmptyAnswer) {
|
|
626
|
+
// If there's only one empty answer, replace it instead of merging
|
|
627
|
+
this.block.metadata.config.answerObjects.splice(0, 1)
|
|
628
|
+
this.block.metadata.config.prompts.splice(0, 1)
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
const existingAnswerCount =
|
|
632
|
+
this.block.metadata.config.answerObjects.length
|
|
633
|
+
|
|
634
|
+
// Add new answer objects
|
|
635
|
+
activityData.metadata.config.answerObjects.forEach(
|
|
636
|
+
(answerObj, index) => {
|
|
553
637
|
const newIndex = existingAnswerCount + index
|
|
554
638
|
this.block.metadata.config.answerObjects.push({
|
|
555
|
-
id: newIndex.toString(),
|
|
556
|
-
display: answerObj.display || ''
|
|
639
|
+
id: newIndex.toString(), // string id
|
|
640
|
+
display: answerObj.display || '',
|
|
557
641
|
})
|
|
558
|
-
}
|
|
642
|
+
}
|
|
643
|
+
)
|
|
559
644
|
|
|
560
|
-
|
|
561
|
-
|
|
645
|
+
// Add new prompts
|
|
646
|
+
activityData.metadata.config.prompts.forEach(
|
|
647
|
+
(promptArray, index) => {
|
|
562
648
|
const adjustedIndex = existingAnswerCount + index
|
|
563
|
-
this.block.metadata.config.prompts[adjustedIndex] =
|
|
649
|
+
this.block.metadata.config.prompts[adjustedIndex] =
|
|
650
|
+
[]
|
|
564
651
|
if (Array.isArray(promptArray)) {
|
|
565
|
-
promptArray.forEach(prompt => {
|
|
566
|
-
const answerObj =
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
652
|
+
promptArray.forEach((prompt) => {
|
|
653
|
+
const answerObj =
|
|
654
|
+
this.block.metadata.config
|
|
655
|
+
.answerObjects[adjustedIndex]
|
|
656
|
+
this.block.metadata.config.prompts[
|
|
657
|
+
adjustedIndex
|
|
658
|
+
].push({
|
|
659
|
+
id: adjustedIndex.toString(), // string id
|
|
660
|
+
textOrImage:
|
|
661
|
+
prompt.textOrImage || 'text',
|
|
570
662
|
prompt: prompt.prompt || '',
|
|
571
|
-
matchExplanation:
|
|
663
|
+
matchExplanation:
|
|
664
|
+
prompt.matchExplanation ||
|
|
665
|
+
this.$t(
|
|
666
|
+
'windward.games.components.settings.matching_game.form.correct_match'
|
|
667
|
+
),
|
|
572
668
|
fileConfig: prompt.fileConfig || {
|
|
573
669
|
hideBackground: true,
|
|
574
670
|
},
|
|
575
|
-
answer: answerObj
|
|
671
|
+
answer: answerObj,
|
|
576
672
|
})
|
|
577
673
|
})
|
|
578
674
|
}
|
|
579
|
-
})
|
|
580
|
-
}
|
|
581
|
-
|
|
582
|
-
// Update title and instructions if provided and we're in replace mode
|
|
583
|
-
if (replaceMode) {
|
|
584
|
-
if (activityData.metadata.config.title) {
|
|
585
|
-
this.block.metadata.config.title = activityData.metadata.config.title
|
|
586
675
|
}
|
|
587
|
-
|
|
588
|
-
if (activityData.metadata.config.instructions) {
|
|
589
|
-
this.block.metadata.config.instructions = activityData.metadata.config.instructions
|
|
590
|
-
}
|
|
591
|
-
}
|
|
676
|
+
)
|
|
592
677
|
|
|
593
678
|
this.$toast.success(
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
679
|
+
this.$t(
|
|
680
|
+
'windward.games.components.settings.matching_game.form.added_successfully'
|
|
681
|
+
),
|
|
597
682
|
{ duration: 3000 }
|
|
598
683
|
)
|
|
599
684
|
} else {
|
|
600
|
-
this.$toast.error(
|
|
601
|
-
|
|
602
|
-
|
|
685
|
+
this.$toast.error(
|
|
686
|
+
this.$t(
|
|
687
|
+
'windward.games.components.settings.matching_game.form.invalid_response'
|
|
688
|
+
),
|
|
689
|
+
{
|
|
690
|
+
duration: 5000,
|
|
691
|
+
}
|
|
692
|
+
)
|
|
603
693
|
}
|
|
604
694
|
} catch (error) {
|
|
605
695
|
// Extract error message from the response
|
|
606
696
|
const errorMessage = error.message || 'Unknown error occurred'
|
|
607
|
-
this.$toast.error(
|
|
608
|
-
|
|
609
|
-
|
|
697
|
+
this.$toast.error(
|
|
698
|
+
`${this.$t(
|
|
699
|
+
'windward.games.components.settings.matching_game.form.failed_to_process'
|
|
700
|
+
)}: ${errorMessage}`,
|
|
701
|
+
{
|
|
702
|
+
duration: 5000,
|
|
703
|
+
}
|
|
704
|
+
)
|
|
610
705
|
} finally {
|
|
611
706
|
this.loading = false
|
|
612
707
|
}
|
|
613
|
-
}
|
|
708
|
+
},
|
|
614
709
|
},
|
|
615
710
|
}
|
|
616
711
|
</script>
|
|
@@ -47,6 +47,25 @@
|
|
|
47
47
|
}}
|
|
48
48
|
</v-btn>
|
|
49
49
|
</v-row>
|
|
50
|
+
<!-- AI Assistant: Generate Questions (appears below Add Question) -->
|
|
51
|
+
<v-container class="pa-4 mb-6">
|
|
52
|
+
<v-row>
|
|
53
|
+
<v-col cols="12">
|
|
54
|
+
<PluginRef
|
|
55
|
+
target="contentBlockSettingTool"
|
|
56
|
+
:attrs="{
|
|
57
|
+
value: block,
|
|
58
|
+
course: course,
|
|
59
|
+
content: currentContent,
|
|
60
|
+
}"
|
|
61
|
+
:on="{
|
|
62
|
+
input: onPluginSetBlock,
|
|
63
|
+
append: onPluginAppendBlock,
|
|
64
|
+
}"
|
|
65
|
+
></PluginRef>
|
|
66
|
+
</v-col>
|
|
67
|
+
</v-row>
|
|
68
|
+
</v-container>
|
|
50
69
|
</v-container>
|
|
51
70
|
<DialogBox
|
|
52
71
|
v-model="dialog"
|
|
@@ -88,6 +107,7 @@
|
|
|
88
107
|
</template>
|
|
89
108
|
<script>
|
|
90
109
|
import _ from 'lodash'
|
|
110
|
+
import { mapGetters } from 'vuex'
|
|
91
111
|
import BaseContentSettings from '~/components/Content/Settings/BaseContentSettings.js'
|
|
92
112
|
import SortableExpansionPanel from '~/components/Core/SortableExpansionPanel.vue'
|
|
93
113
|
import DialogBox from '~/components/Core/DialogBox.vue'
|
|
@@ -95,6 +115,7 @@ import QuestionDialog from '../content/blocks/multipleChoice/QuestionDialog.vue'
|
|
|
95
115
|
import Crypto from '~/helpers/Crypto'
|
|
96
116
|
import BaseContentBlockSettings from '~/components/Content/Settings/BaseContentBlockSettings.vue'
|
|
97
117
|
import Uuid from '~/helpers/Uuid'
|
|
118
|
+
import PluginRef from '~/components/Core/PluginRef.vue'
|
|
98
119
|
|
|
99
120
|
export default {
|
|
100
121
|
name: 'MultipleChoiceSettingsManager',
|
|
@@ -104,6 +125,7 @@ export default {
|
|
|
104
125
|
QuestionDialog,
|
|
105
126
|
DialogBox,
|
|
106
127
|
BaseContentBlockSettings,
|
|
128
|
+
PluginRef,
|
|
107
129
|
},
|
|
108
130
|
beforeMount() {
|
|
109
131
|
if (_.isEmpty(this.block)) {
|
|
@@ -150,6 +172,12 @@ export default {
|
|
|
150
172
|
mounted() {
|
|
151
173
|
this.emittedQuestion = {}
|
|
152
174
|
},
|
|
175
|
+
computed: {
|
|
176
|
+
...mapGetters({
|
|
177
|
+
course: 'course/get',
|
|
178
|
+
currentContent: 'content/get',
|
|
179
|
+
}),
|
|
180
|
+
},
|
|
153
181
|
methods: {
|
|
154
182
|
stripHtml(htmlString) {
|
|
155
183
|
if (htmlString) {
|
|
@@ -255,6 +283,110 @@ export default {
|
|
|
255
283
|
this.dialog = false
|
|
256
284
|
this.editingIndex = null
|
|
257
285
|
},
|
|
286
|
+
// Handle AI Assistant replace (input) event
|
|
287
|
+
onPluginSetBlock(activityData) {
|
|
288
|
+
this.loading = true
|
|
289
|
+
try {
|
|
290
|
+
if (
|
|
291
|
+
activityData &&
|
|
292
|
+
activityData.metadata &&
|
|
293
|
+
activityData.metadata.config &&
|
|
294
|
+
Array.isArray(activityData.metadata.config.questions)
|
|
295
|
+
) {
|
|
296
|
+
const newConfig = activityData.metadata.config
|
|
297
|
+
|
|
298
|
+
// Replace questions entirely
|
|
299
|
+
this.$set(
|
|
300
|
+
this.block.metadata.config,
|
|
301
|
+
'questions',
|
|
302
|
+
_.cloneDeep(newConfig.questions)
|
|
303
|
+
)
|
|
304
|
+
|
|
305
|
+
// Update title and instructions if provided
|
|
306
|
+
if (newConfig.title) {
|
|
307
|
+
this.$set(
|
|
308
|
+
this.block.metadata.config,
|
|
309
|
+
'title',
|
|
310
|
+
newConfig.title
|
|
311
|
+
)
|
|
312
|
+
}
|
|
313
|
+
if (newConfig.instructions) {
|
|
314
|
+
this.$set(
|
|
315
|
+
this.block.metadata.config,
|
|
316
|
+
'instructions',
|
|
317
|
+
newConfig.instructions
|
|
318
|
+
)
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
this.$toast.success(
|
|
322
|
+
this.$t(
|
|
323
|
+
'windward.games.components.settings.multiple_choice.replaced_successfully'
|
|
324
|
+
),
|
|
325
|
+
{ duration: 3000 }
|
|
326
|
+
)
|
|
327
|
+
} else {
|
|
328
|
+
this.$toast.error(
|
|
329
|
+
this.$t(
|
|
330
|
+
'windward.games.components.settings.multiple_choice.invalid_response'
|
|
331
|
+
),
|
|
332
|
+
{ duration: 5000 }
|
|
333
|
+
)
|
|
334
|
+
}
|
|
335
|
+
} catch (error) {
|
|
336
|
+
const errorMessage = error.message || 'Unknown error occurred'
|
|
337
|
+
this.$toast.error(
|
|
338
|
+
`${this.$t(
|
|
339
|
+
'windward.games.components.settings.multiple_choice.failed_to_process'
|
|
340
|
+
)}: ${errorMessage}`,
|
|
341
|
+
{ duration: 5000 }
|
|
342
|
+
)
|
|
343
|
+
} finally {
|
|
344
|
+
this.loading = false
|
|
345
|
+
}
|
|
346
|
+
},
|
|
347
|
+
// Handle AI Assistant append event: add new questions to existing
|
|
348
|
+
onPluginAppendBlock(activityData) {
|
|
349
|
+
this.loading = true
|
|
350
|
+
try {
|
|
351
|
+
if (
|
|
352
|
+
activityData &&
|
|
353
|
+
activityData.metadata &&
|
|
354
|
+
activityData.metadata.config &&
|
|
355
|
+
Array.isArray(activityData.metadata.config.questions)
|
|
356
|
+
) {
|
|
357
|
+
const newQuestions = activityData.metadata.config.questions
|
|
358
|
+
if (!Array.isArray(this.block.metadata.config.questions)) {
|
|
359
|
+
this.$set(this.block.metadata.config, 'questions', [])
|
|
360
|
+
}
|
|
361
|
+
newQuestions.forEach((q) => {
|
|
362
|
+
this.block.metadata.config.questions.push(_.cloneDeep(q))
|
|
363
|
+
})
|
|
364
|
+
this.$toast.success(
|
|
365
|
+
this.$t(
|
|
366
|
+
'windward.games.components.settings.multiple_choice.added_successfully'
|
|
367
|
+
),
|
|
368
|
+
{ duration: 3000 }
|
|
369
|
+
)
|
|
370
|
+
} else {
|
|
371
|
+
this.$toast.error(
|
|
372
|
+
this.$t(
|
|
373
|
+
'windward.games.components.settings.multiple_choice.invalid_response'
|
|
374
|
+
),
|
|
375
|
+
{ duration: 5000 }
|
|
376
|
+
)
|
|
377
|
+
}
|
|
378
|
+
} catch (error) {
|
|
379
|
+
const errorMessage = error.message || 'Unknown error occurred'
|
|
380
|
+
this.$toast.error(
|
|
381
|
+
`${this.$t(
|
|
382
|
+
'windward.games.components.settings.multiple_choice.failed_to_process'
|
|
383
|
+
)}: ${errorMessage}`,
|
|
384
|
+
{ duration: 5000 }
|
|
385
|
+
)
|
|
386
|
+
} finally {
|
|
387
|
+
this.loading = false
|
|
388
|
+
}
|
|
389
|
+
},
|
|
258
390
|
},
|
|
259
391
|
}
|
|
260
392
|
</script>
|
|
@@ -112,17 +112,45 @@
|
|
|
112
112
|
:disabled="render"
|
|
113
113
|
></v-textarea>
|
|
114
114
|
</v-row>
|
|
115
|
+
<div v-if="loading" class="text-center">
|
|
116
|
+
<v-progress-circular
|
|
117
|
+
:size="70"
|
|
118
|
+
:width="7"
|
|
119
|
+
color="primary"
|
|
120
|
+
indeterminate
|
|
121
|
+
></v-progress-circular>
|
|
122
|
+
</div>
|
|
123
|
+
<v-container class="pa-4 mb-6">
|
|
124
|
+
<v-row>
|
|
125
|
+
<v-col cols="12">
|
|
126
|
+
<PluginRef
|
|
127
|
+
target="contentBlockSettingTool"
|
|
128
|
+
:attrs="{
|
|
129
|
+
value: block,
|
|
130
|
+
course: course,
|
|
131
|
+
content: currentContent,
|
|
132
|
+
}"
|
|
133
|
+
:on="{
|
|
134
|
+
input: onPluginSetBlock,
|
|
135
|
+
append: onPluginAppendBlock,
|
|
136
|
+
}"
|
|
137
|
+
></PluginRef>
|
|
138
|
+
</v-col>
|
|
139
|
+
</v-row>
|
|
140
|
+
</v-container>
|
|
115
141
|
</div>
|
|
116
142
|
</template>
|
|
117
143
|
|
|
118
144
|
<script>
|
|
119
145
|
import _ from 'lodash'
|
|
120
146
|
import draggable from 'vuedraggable'
|
|
147
|
+
import { mapGetters } from 'vuex'
|
|
121
148
|
import BaseContentSettings from '~/components/Content/Settings/BaseContentSettings.js'
|
|
122
149
|
import CrudTable from '../content/CrudTable.vue'
|
|
123
150
|
import SortableExpansionPanel from '~/components/Core/SortableExpansionPanel.vue'
|
|
124
151
|
import BaseContentBlockSettings from '~/components/Content/Settings/BaseContentBlockSettings.vue'
|
|
125
152
|
import Uuid from '~/helpers/Uuid'
|
|
153
|
+
import PluginRef from '~/components/Core/PluginRef.vue'
|
|
126
154
|
|
|
127
155
|
export default {
|
|
128
156
|
name: 'SevenStrikesSettingsManager',
|
|
@@ -132,6 +160,7 @@ export default {
|
|
|
132
160
|
draggable,
|
|
133
161
|
SortableExpansionPanel,
|
|
134
162
|
BaseContentBlockSettings,
|
|
163
|
+
PluginRef,
|
|
135
164
|
},
|
|
136
165
|
beforeMount() {
|
|
137
166
|
if (_.isEmpty(this.block)) {
|
|
@@ -186,6 +215,12 @@ export default {
|
|
|
186
215
|
loading: false,
|
|
187
216
|
}
|
|
188
217
|
},
|
|
218
|
+
computed: {
|
|
219
|
+
...mapGetters({
|
|
220
|
+
course: 'course/get',
|
|
221
|
+
currentContent: 'content/get',
|
|
222
|
+
}),
|
|
223
|
+
},
|
|
189
224
|
methods: {
|
|
190
225
|
onBeforeSave() {
|
|
191
226
|
this.block.metadata.config.words.forEach((element) => {
|
|
@@ -220,6 +255,62 @@ export default {
|
|
|
220
255
|
this.block.metadata.config.currentWord =
|
|
221
256
|
this.block.metadata.config.words.length - 1
|
|
222
257
|
},
|
|
258
|
+
onPluginSetBlock(activityData) {
|
|
259
|
+
this.loading = true
|
|
260
|
+
try {
|
|
261
|
+
if (
|
|
262
|
+
activityData &&
|
|
263
|
+
activityData.metadata &&
|
|
264
|
+
activityData.metadata.config &&
|
|
265
|
+
Array.isArray(activityData.metadata.config.words)
|
|
266
|
+
) {
|
|
267
|
+
const newWords = activityData.metadata.config.words.map(
|
|
268
|
+
(w) => ({
|
|
269
|
+
value: w.value || '',
|
|
270
|
+
hint: w.hint || '',
|
|
271
|
+
expand: false,
|
|
272
|
+
splitWord: '',
|
|
273
|
+
})
|
|
274
|
+
)
|
|
275
|
+
this.block.metadata.config.words = newWords
|
|
276
|
+
this.block.metadata.config.currentWord = 0
|
|
277
|
+
|
|
278
|
+
if (activityData.metadata.config.title) {
|
|
279
|
+
this.block.metadata.config.title =
|
|
280
|
+
activityData.metadata.config.title
|
|
281
|
+
}
|
|
282
|
+
// Keep existing instructions (do not override)
|
|
283
|
+
}
|
|
284
|
+
} finally {
|
|
285
|
+
this.loading = false
|
|
286
|
+
}
|
|
287
|
+
},
|
|
288
|
+
onPluginAppendBlock(activityData) {
|
|
289
|
+
this.loading = true
|
|
290
|
+
try {
|
|
291
|
+
if (
|
|
292
|
+
activityData &&
|
|
293
|
+
activityData.metadata &&
|
|
294
|
+
activityData.metadata.config &&
|
|
295
|
+
Array.isArray(activityData.metadata.config.words)
|
|
296
|
+
) {
|
|
297
|
+
const appendWords = activityData.metadata.config.words.map(
|
|
298
|
+
(w) => ({
|
|
299
|
+
value: w.value || '',
|
|
300
|
+
hint: w.hint || '',
|
|
301
|
+
expand: false,
|
|
302
|
+
splitWord: '',
|
|
303
|
+
})
|
|
304
|
+
)
|
|
305
|
+
if (!Array.isArray(this.block.metadata.config.words)) {
|
|
306
|
+
this.block.metadata.config.words = []
|
|
307
|
+
}
|
|
308
|
+
this.block.metadata.config.words.push(...appendWords)
|
|
309
|
+
}
|
|
310
|
+
} finally {
|
|
311
|
+
this.loading = false
|
|
312
|
+
}
|
|
313
|
+
},
|
|
223
314
|
},
|
|
224
315
|
}
|
|
225
316
|
</script>
|