@windward/games 0.18.0 → 0.19.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 +2 -0
- package/components/content/blocks/multipleChoice/MultipleChoice.vue +24 -18
- package/components/content/blocks/multipleChoice/QuestionDialog.vue +335 -112
- package/components/settings/BucketGameSettingsManager.vue +143 -0
- package/components/settings/MultipleChoiceSettingsManager.vue +24 -2
- package/i18n/en-US/components/content/blocks/flashcard.ts +1 -0
- package/i18n/en-US/components/settings/bucket_game.ts +5 -0
- package/i18n/en-US/components/settings/multiple_choice.ts +4 -3
- package/i18n/es-ES/components/settings/bucket_game.ts +5 -0
- package/i18n/es-ES/components/settings/multiple_choice.ts +2 -3
- package/i18n/sv-SE/components/settings/bucket_game.ts +5 -0
- package/i18n/sv-SE/components/settings/multiple_choice.ts +2 -2
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -52,7 +52,9 @@
|
|
|
52
52
|
:key="question.id"
|
|
53
53
|
>
|
|
54
54
|
<v-col class="d-flex justify-center">
|
|
55
|
-
<p>
|
|
55
|
+
<p>
|
|
56
|
+
<TextViewer v-model="question.body"></TextViewer>
|
|
57
|
+
</p>
|
|
56
58
|
</v-col>
|
|
57
59
|
<v-container :key="updateKey" class="pl-16 pr-16">
|
|
58
60
|
<v-row
|
|
@@ -77,16 +79,20 @@
|
|
|
77
79
|
@keyup.enter="onChooseAnswer(answer, question)"
|
|
78
80
|
>
|
|
79
81
|
<div class="d-flex justify-space-between">
|
|
80
|
-
<
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
82
|
+
<div class="d-flex">
|
|
83
|
+
<p
|
|
84
|
+
class="mb-0"
|
|
85
|
+
:aria-labelledby="answer.value"
|
|
86
|
+
>
|
|
87
|
+
{{
|
|
88
|
+
getCharacter(question, answer) +
|
|
89
|
+
'. '
|
|
90
|
+
}}
|
|
91
|
+
</p>
|
|
92
|
+
<TextViewer
|
|
93
|
+
v-model="answer.value"
|
|
94
|
+
></TextViewer>
|
|
95
|
+
</div>
|
|
90
96
|
<div>
|
|
91
97
|
<v-icon
|
|
92
98
|
v-if="
|
|
@@ -223,12 +229,11 @@
|
|
|
223
229
|
</template>
|
|
224
230
|
<template #form="{ on, attrs }">
|
|
225
231
|
<div v-bind="attrs" v-on="on">
|
|
226
|
-
<
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
</div>
|
|
232
|
+
<TextViewer v-if="hint" v-model="hintText"></TextViewer>
|
|
233
|
+
<TextViewer
|
|
234
|
+
v-if="answerDescriptionModal"
|
|
235
|
+
v-model="answerDescription"
|
|
236
|
+
></TextViewer>
|
|
232
237
|
</div>
|
|
233
238
|
</template>
|
|
234
239
|
</DialogBox>
|
|
@@ -241,11 +246,12 @@ import Crypto from '~/helpers/Crypto'
|
|
|
241
246
|
import { mapGetters } from 'vuex'
|
|
242
247
|
import BaseContentBlock from '~/components/Content/Blocks/BaseContentBlock'
|
|
243
248
|
import DialogBox from '~/components/Core/DialogBox.vue'
|
|
249
|
+
import TextViewer from '~/components/Text/TextViewer.vue'
|
|
244
250
|
|
|
245
251
|
export default {
|
|
246
252
|
name: 'MultipleChoice',
|
|
247
253
|
extends: BaseContentBlock,
|
|
248
|
-
components: { DialogBox },
|
|
254
|
+
components: { DialogBox, TextViewer },
|
|
249
255
|
beforeMount() {
|
|
250
256
|
if (_.isEmpty(this.block)) {
|
|
251
257
|
this.block = {}
|
|
@@ -1,20 +1,40 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<v-
|
|
3
|
-
<v-row>
|
|
4
|
-
<v-col cols="12">
|
|
5
|
-
<
|
|
6
|
-
|
|
7
|
-
:label="
|
|
2
|
+
<v-container>
|
|
3
|
+
<v-row :key="updateKey">
|
|
4
|
+
<v-col xl="12" lg="12" md="12" sm="12" cols="12">
|
|
5
|
+
<p class="font-weight-bold p-bold-text">
|
|
6
|
+
{{
|
|
8
7
|
$t(
|
|
9
|
-
'
|
|
8
|
+
'components.content.blocks.assessment.questions.question'
|
|
10
9
|
)
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
10
|
+
}}
|
|
11
|
+
</p>
|
|
12
|
+
<TextEditor
|
|
13
|
+
id="question-body"
|
|
14
|
+
:key="'question-body-' + updateKey"
|
|
15
|
+
v-model="question.body"
|
|
16
|
+
:height="200"
|
|
17
|
+
lazy-load
|
|
18
|
+
@input="onCheckValidation"
|
|
19
|
+
></TextEditor>
|
|
20
|
+
</v-col>
|
|
21
|
+
<v-col xl="3" lg="3" md="4" sm="12" cols="12" v-if="false">
|
|
22
|
+
<GenerateAIQuestionButton
|
|
23
|
+
:course="course"
|
|
24
|
+
:content="content"
|
|
25
|
+
:block="block"
|
|
26
|
+
:question-type="questionType"
|
|
27
|
+
@click:generate="onQuestionGenerated"
|
|
28
|
+
></GenerateAIQuestionButton>
|
|
29
|
+
</v-col>
|
|
30
|
+
<v-col cols="12">
|
|
31
|
+
<ImageAssetSettings
|
|
32
|
+
v-model="question.question_metadata.body_asset"
|
|
33
|
+
:assets.sync="question.assets"
|
|
34
|
+
hide-background
|
|
35
|
+
hide-decorative
|
|
36
|
+
hide-modal
|
|
37
|
+
></ImageAssetSettings>
|
|
18
38
|
<v-textarea
|
|
19
39
|
v-model="question.hint"
|
|
20
40
|
:label="
|
|
@@ -22,120 +42,233 @@
|
|
|
22
42
|
'windward.games.components.settings.multiple_choice.question_hint'
|
|
23
43
|
)
|
|
24
44
|
"
|
|
45
|
+
outlined
|
|
25
46
|
rows="2"
|
|
26
|
-
:rules="$Validation.getRule('exists')"
|
|
27
47
|
prepend-inner-icon="mdi-lightbulb-on-10"
|
|
28
48
|
:disabled="disabled"
|
|
29
49
|
></v-textarea>
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
$t(
|
|
34
|
-
'windward.games.components.settings.multiple_choice.answer_feedback'
|
|
35
|
-
)
|
|
36
|
-
"
|
|
37
|
-
rows="2"
|
|
38
|
-
:rules="$Validation.getRule('exists')"
|
|
39
|
-
prepend-inner-icon="mdi-comment"
|
|
40
|
-
:disabled="disabled"
|
|
41
|
-
></v-textarea>
|
|
42
|
-
<br />
|
|
50
|
+
</v-col>
|
|
51
|
+
<br />
|
|
52
|
+
<v-col cols="12">
|
|
43
53
|
<h4 class="pb-2">
|
|
44
54
|
{{
|
|
45
55
|
$t(
|
|
46
|
-
'windward.games.components.settings.multiple_choice.
|
|
56
|
+
'windward.games.components.settings.multiple_choice.answer'
|
|
47
57
|
)
|
|
48
58
|
}}
|
|
49
59
|
</h4>
|
|
50
|
-
<
|
|
60
|
+
<v-radio-group
|
|
61
|
+
:key="updateKey"
|
|
62
|
+
v-model="question.correctAnswer"
|
|
63
|
+
:rules="validation.optionRules"
|
|
64
|
+
>
|
|
65
|
+
<draggable
|
|
66
|
+
:list="question.answer_options"
|
|
67
|
+
tag="tbody"
|
|
68
|
+
v-bind="dragOptions"
|
|
69
|
+
handle=".question-drag-handle"
|
|
70
|
+
@change="onDragChange"
|
|
71
|
+
>
|
|
72
|
+
<div
|
|
73
|
+
v-for="(answer, index) in question.answer_options"
|
|
74
|
+
:key="index"
|
|
75
|
+
>
|
|
76
|
+
<v-alert outlined elevation="2">
|
|
77
|
+
<v-row>
|
|
78
|
+
<v-col
|
|
79
|
+
cols="1"
|
|
80
|
+
lg="1"
|
|
81
|
+
md="1"
|
|
82
|
+
class="d-flex justify-center align-center pa-0"
|
|
83
|
+
>
|
|
84
|
+
<v-btn
|
|
85
|
+
elevation="0"
|
|
86
|
+
text
|
|
87
|
+
class="question-drag-handle"
|
|
88
|
+
>
|
|
89
|
+
<v-icon>mdi-drag-vertical</v-icon>
|
|
90
|
+
</v-btn>
|
|
91
|
+
</v-col>
|
|
92
|
+
<v-col
|
|
93
|
+
cols="10"
|
|
94
|
+
lg="10"
|
|
95
|
+
md="10"
|
|
96
|
+
class="pl-0 pr-0"
|
|
97
|
+
>
|
|
98
|
+
<v-row>
|
|
99
|
+
<v-col cols="12">
|
|
100
|
+
<v-radio
|
|
101
|
+
color="success"
|
|
102
|
+
:value="answer.id"
|
|
103
|
+
:disabled="disabled"
|
|
104
|
+
v-on:keydown.enter="
|
|
105
|
+
onSetAnswer(
|
|
106
|
+
answer,
|
|
107
|
+
true
|
|
108
|
+
)
|
|
109
|
+
"
|
|
110
|
+
@click="onSetAnswer(answer)"
|
|
111
|
+
>
|
|
112
|
+
<template #label>
|
|
113
|
+
<div
|
|
114
|
+
:class="
|
|
115
|
+
onContainerLabel(
|
|
116
|
+
answer
|
|
117
|
+
)
|
|
118
|
+
"
|
|
119
|
+
>
|
|
120
|
+
{{
|
|
121
|
+
answer.correctAnswer
|
|
122
|
+
? $t(
|
|
123
|
+
'components.content.blocks.assessment.questions.correct'
|
|
124
|
+
)
|
|
125
|
+
: $t(
|
|
126
|
+
'components.content.blocks.assessment.questions.incorrect'
|
|
127
|
+
)
|
|
128
|
+
}}
|
|
129
|
+
</div>
|
|
130
|
+
</template>
|
|
131
|
+
</v-radio>
|
|
132
|
+
</v-col>
|
|
133
|
+
</v-row>
|
|
134
|
+
<v-row>
|
|
135
|
+
<v-col cols="12" md="6">
|
|
136
|
+
<TextEditor
|
|
137
|
+
:id="'option-' + answer.id"
|
|
138
|
+
:key="
|
|
139
|
+
'option-' +
|
|
140
|
+
answer.id +
|
|
141
|
+
'-' +
|
|
142
|
+
updateKey
|
|
143
|
+
"
|
|
144
|
+
v-model="answer.value"
|
|
145
|
+
:label="
|
|
146
|
+
$t(
|
|
147
|
+
'components.content.blocks.assessment.answer_option'
|
|
148
|
+
)
|
|
149
|
+
"
|
|
150
|
+
:height="200"
|
|
151
|
+
lazy-load
|
|
152
|
+
@input="onCheckValidation"
|
|
153
|
+
></TextEditor>
|
|
154
|
+
</v-col>
|
|
155
|
+
<v-col cols="12" md="6">
|
|
156
|
+
<TextEditor
|
|
157
|
+
:id="
|
|
158
|
+
'feedback-' + answer.id
|
|
159
|
+
"
|
|
160
|
+
:key="
|
|
161
|
+
'feedback-' +
|
|
162
|
+
answer.id +
|
|
163
|
+
'-' +
|
|
164
|
+
updateKey
|
|
165
|
+
"
|
|
166
|
+
v-model="
|
|
167
|
+
question.answer_options[
|
|
168
|
+
index
|
|
169
|
+
].feedback
|
|
170
|
+
"
|
|
171
|
+
:label="
|
|
172
|
+
$t(
|
|
173
|
+
'components.content.blocks.assessment.answer_explanation'
|
|
174
|
+
)
|
|
175
|
+
"
|
|
176
|
+
:height="200"
|
|
177
|
+
lazy-load
|
|
178
|
+
></TextEditor>
|
|
179
|
+
</v-col>
|
|
180
|
+
</v-row>
|
|
181
|
+
</v-col>
|
|
182
|
+
<v-col
|
|
183
|
+
cols="1"
|
|
184
|
+
lg="1"
|
|
185
|
+
md="1"
|
|
186
|
+
class="d-flex justify-center align-center pa-0"
|
|
187
|
+
>
|
|
188
|
+
<v-btn
|
|
189
|
+
elevation="0"
|
|
190
|
+
text
|
|
191
|
+
class="pa-0 ma-0"
|
|
192
|
+
color="error"
|
|
193
|
+
:disabled="removeDisabled"
|
|
194
|
+
@click="onDelete(index)"
|
|
195
|
+
>
|
|
196
|
+
<span class="sr-only">{{
|
|
197
|
+
$t(
|
|
198
|
+
'components.content.blocks.assessment.questions.types.multi_choice_single_answer.add_option'
|
|
199
|
+
)
|
|
200
|
+
}}</span>
|
|
201
|
+
<v-icon>mdi-delete-outline</v-icon>
|
|
202
|
+
</v-btn>
|
|
203
|
+
</v-col>
|
|
204
|
+
</v-row>
|
|
205
|
+
</v-alert>
|
|
206
|
+
</div>
|
|
207
|
+
</draggable>
|
|
208
|
+
</v-radio-group>
|
|
209
|
+
<v-container class="d-flex justify-center" v-if="overLength">
|
|
210
|
+
<v-btn
|
|
211
|
+
:class="cursor"
|
|
212
|
+
color="primary"
|
|
213
|
+
elevation="0"
|
|
214
|
+
:disabled="disabled"
|
|
215
|
+
@click="onAddAnswer"
|
|
216
|
+
>
|
|
217
|
+
<v-icon>mdi-plus</v-icon>
|
|
218
|
+
{{
|
|
219
|
+
$t(
|
|
220
|
+
'windward.games.components.settings.multiple_choice.add_answer'
|
|
221
|
+
)
|
|
222
|
+
}}
|
|
223
|
+
</v-btn>
|
|
224
|
+
</v-container>
|
|
225
|
+
</v-col>
|
|
226
|
+
<v-col cols="12">
|
|
227
|
+
<p class="font-weight-bold p-bold-text">
|
|
51
228
|
{{
|
|
52
229
|
$t(
|
|
53
|
-
'
|
|
230
|
+
'components.content.blocks.assessment.questions.question_feedback'
|
|
54
231
|
)
|
|
55
232
|
}}
|
|
56
233
|
</p>
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
:key="index"
|
|
61
|
-
>
|
|
62
|
-
<v-row>
|
|
63
|
-
<v-col
|
|
64
|
-
cols="12"
|
|
65
|
-
md="1"
|
|
66
|
-
class="d-flex justify-center"
|
|
67
|
-
@mouseover="onHover"
|
|
68
|
-
@mouseleave="onHoverLeave"
|
|
69
|
-
>
|
|
70
|
-
<v-radio-group v-model="question.correctAnswer">
|
|
71
|
-
<v-radio
|
|
72
|
-
:ref="'checkbox' + index"
|
|
73
|
-
:value="answer.id"
|
|
74
|
-
:disabled="disabled"
|
|
75
|
-
v-on:keydown.enter="onSetAnswer(answer, true)"
|
|
76
|
-
@click="onSetAnswer(answer)"
|
|
77
|
-
></v-radio>
|
|
78
|
-
</v-radio-group>
|
|
79
|
-
</v-col>
|
|
80
|
-
<v-col cols="12" md="10">
|
|
81
|
-
<v-textarea
|
|
82
|
-
v-model="answer.value"
|
|
83
|
-
flat
|
|
84
|
-
solo
|
|
85
|
-
:autofocus="answer.focus"
|
|
86
|
-
:outlined="setOutline(answer)"
|
|
87
|
-
hide-details
|
|
88
|
-
:class="getCorrectAnswer(answer)"
|
|
89
|
-
:label="
|
|
90
|
-
$t(
|
|
91
|
-
'windward.games.components.settings.multiple_choice.answer_option'
|
|
92
|
-
)
|
|
93
|
-
"
|
|
94
|
-
rows="2"
|
|
95
|
-
:rules="$Validation.getRule('exists')"
|
|
96
|
-
:disabled="disabled"
|
|
97
|
-
></v-textarea>
|
|
98
|
-
</v-col>
|
|
99
|
-
<v-col cols="12" md="1" class="d-flex justify-center">
|
|
100
|
-
<v-btn
|
|
101
|
-
text
|
|
102
|
-
elevation="0"
|
|
103
|
-
:disabled="disabled"
|
|
104
|
-
@click="onDelete(index)"
|
|
105
|
-
>
|
|
106
|
-
<v-icon color="error">mdi-delete-outline</v-icon>
|
|
107
|
-
<span class="d-sr-only">{{
|
|
108
|
-
$t('shared.forms.delete')
|
|
109
|
-
}}</span>
|
|
110
|
-
</v-btn>
|
|
111
|
-
</v-col>
|
|
112
|
-
</v-row>
|
|
113
|
-
</v-container>
|
|
114
|
-
<v-container class="d-flex justify-center" v-if="overLength">
|
|
115
|
-
<v-btn
|
|
116
|
-
:class="cursor"
|
|
117
|
-
color="primary"
|
|
118
|
-
elevation="0"
|
|
119
|
-
:disabled="disabled"
|
|
120
|
-
@click="onAddAnswer"
|
|
121
|
-
>
|
|
122
|
-
<v-icon>mdi-plus</v-icon>
|
|
123
|
-
{{
|
|
234
|
+
<v-switch
|
|
235
|
+
v-model="question.metadata.config.single_feedback"
|
|
236
|
+
:label="
|
|
124
237
|
$t(
|
|
125
|
-
'
|
|
238
|
+
'components.content.blocks.assessment.single_feedback_label'
|
|
126
239
|
)
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
240
|
+
"
|
|
241
|
+
></v-switch>
|
|
242
|
+
<TextEditor
|
|
243
|
+
v-if="question.metadata.config.single_feedback"
|
|
244
|
+
id="question-feedback"
|
|
245
|
+
:key="'question-feedback-' + updateKey"
|
|
246
|
+
v-model="question.answer_description"
|
|
247
|
+
:height="200"
|
|
248
|
+
lazy-load
|
|
249
|
+
></TextEditor>
|
|
250
|
+
</v-col>
|
|
251
|
+
<v-col cols="12" md="12" v-if="false">
|
|
252
|
+
<QuestionSkills></QuestionSkills>
|
|
253
|
+
</v-col>
|
|
130
254
|
</v-row>
|
|
131
|
-
</v-
|
|
255
|
+
</v-container>
|
|
132
256
|
</template>
|
|
133
257
|
<script>
|
|
134
258
|
import Form from '~/components/Core/Form'
|
|
135
259
|
import _ from 'lodash'
|
|
260
|
+
import draggable from 'vuedraggable'
|
|
136
261
|
import Crypto from '~/helpers/Crypto'
|
|
262
|
+
import ImageAssetSettings from '~/components/Content/Settings/ImageAssetSettings.vue'
|
|
263
|
+
import TextEditor from '~/components/Text/TextEditor.vue'
|
|
264
|
+
|
|
137
265
|
export default {
|
|
138
266
|
name: 'QuestionDialog',
|
|
267
|
+
components: {
|
|
268
|
+
TextEditor,
|
|
269
|
+
ImageAssetSettings,
|
|
270
|
+
draggable,
|
|
271
|
+
},
|
|
139
272
|
extends: Form,
|
|
140
273
|
layout: 'authenticated',
|
|
141
274
|
middleware: ['auth', 'course'],
|
|
@@ -159,6 +292,7 @@ export default {
|
|
|
159
292
|
disabled: false,
|
|
160
293
|
chosen: false,
|
|
161
294
|
focus: false,
|
|
295
|
+
feedback: '',
|
|
162
296
|
},
|
|
163
297
|
{
|
|
164
298
|
id: Crypto.id(),
|
|
@@ -167,8 +301,17 @@ export default {
|
|
|
167
301
|
disabled: false,
|
|
168
302
|
chosen: false,
|
|
169
303
|
focus: false,
|
|
304
|
+
feedback: '',
|
|
170
305
|
},
|
|
171
306
|
],
|
|
307
|
+
question_metadata: {
|
|
308
|
+
body_asset: null,
|
|
309
|
+
},
|
|
310
|
+
metadata: {
|
|
311
|
+
config: {
|
|
312
|
+
single_feedback: false,
|
|
313
|
+
},
|
|
314
|
+
},
|
|
172
315
|
// needed to add this bc radio group needs the id of the answer to set correct
|
|
173
316
|
correctAnswer: 1,
|
|
174
317
|
body: '',
|
|
@@ -177,8 +320,9 @@ export default {
|
|
|
177
320
|
id: Crypto.id(),
|
|
178
321
|
}
|
|
179
322
|
}
|
|
323
|
+
// resets form if brand new question was created
|
|
180
324
|
if (newValue && newValue.body === '') {
|
|
181
|
-
this
|
|
325
|
+
this.updateKey = Crypto.id()
|
|
182
326
|
}
|
|
183
327
|
},
|
|
184
328
|
},
|
|
@@ -195,6 +339,14 @@ export default {
|
|
|
195
339
|
return false
|
|
196
340
|
}
|
|
197
341
|
},
|
|
342
|
+
dragOptions() {
|
|
343
|
+
return {
|
|
344
|
+
animation: 200,
|
|
345
|
+
}
|
|
346
|
+
},
|
|
347
|
+
removeDisabled() {
|
|
348
|
+
return this.question.answer_options.length <= 2
|
|
349
|
+
},
|
|
198
350
|
},
|
|
199
351
|
data() {
|
|
200
352
|
return {
|
|
@@ -213,19 +365,81 @@ export default {
|
|
|
213
365
|
},
|
|
214
366
|
cursor: null,
|
|
215
367
|
updateKey: 0,
|
|
368
|
+
formValid: false,
|
|
216
369
|
}
|
|
217
370
|
},
|
|
218
|
-
|
|
371
|
+
beforeMount() {
|
|
219
372
|
if (this.value.body === '') {
|
|
220
|
-
this.$refs.form.resetValidation()
|
|
373
|
+
// this.$refs.form.resetValidation()
|
|
221
374
|
this.question = _.cloneDeep(this.value)
|
|
222
375
|
} else if (!_.isEmpty(this.value)) {
|
|
223
376
|
this.question = _.cloneDeep(this.value)
|
|
377
|
+
if (_.isEmpty(this.question.question_metadata)) {
|
|
378
|
+
this.question.question_metadata = {
|
|
379
|
+
body_asset: null,
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
if (_.isEmpty(this.question.metadata)) {
|
|
383
|
+
// if legacy has no feedback than set toggle to false
|
|
384
|
+
if (_.isEmpty(this.question.answer_description)) {
|
|
385
|
+
this.question.metadata = {
|
|
386
|
+
config: {
|
|
387
|
+
single_feedback: false,
|
|
388
|
+
},
|
|
389
|
+
}
|
|
390
|
+
} else {
|
|
391
|
+
this.question.metadata = {
|
|
392
|
+
config: {
|
|
393
|
+
single_feedback: true,
|
|
394
|
+
},
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
}
|
|
224
398
|
}
|
|
225
|
-
// refreshes data for modal on mount
|
|
226
|
-
this.updateKey = Crypto.id()
|
|
227
399
|
},
|
|
228
400
|
methods: {
|
|
401
|
+
onContainerLabel(answer) {
|
|
402
|
+
if (answer.correctAnswer) {
|
|
403
|
+
return 'container-label-correct'
|
|
404
|
+
} else {
|
|
405
|
+
return ''
|
|
406
|
+
}
|
|
407
|
+
},
|
|
408
|
+
onDragChange() {
|
|
409
|
+
this.updateKey = Crypto.id()
|
|
410
|
+
},
|
|
411
|
+
onCheckValidation() {
|
|
412
|
+
let questionValid = true
|
|
413
|
+
const condition1 = '<div> </div><div> </div>'
|
|
414
|
+
const condition2 = '<div> </div>'
|
|
415
|
+
const condition3 = '<div> </div>\n<div> </div>'
|
|
416
|
+
if (
|
|
417
|
+
_.isEmpty(this.question.body) ||
|
|
418
|
+
this.question.body === condition1 ||
|
|
419
|
+
this.question.body === condition2 ||
|
|
420
|
+
this.question.body === condition3
|
|
421
|
+
) {
|
|
422
|
+
questionValid = false
|
|
423
|
+
}
|
|
424
|
+
let correctAnswerChosen = false
|
|
425
|
+
this.question.answer_options.forEach((answer) => {
|
|
426
|
+
if (
|
|
427
|
+
_.isEmpty(answer.value) ||
|
|
428
|
+
answer.value === condition1 ||
|
|
429
|
+
answer.value === condition2 ||
|
|
430
|
+
answer.value === condition3
|
|
431
|
+
) {
|
|
432
|
+
questionValid = false
|
|
433
|
+
}
|
|
434
|
+
if (answer.correctAnswer) {
|
|
435
|
+
correctAnswerChosen = true
|
|
436
|
+
}
|
|
437
|
+
})
|
|
438
|
+
if (!correctAnswerChosen) {
|
|
439
|
+
questionValid = false
|
|
440
|
+
}
|
|
441
|
+
this.$emit('change:valid', questionValid)
|
|
442
|
+
},
|
|
229
443
|
onSave() {
|
|
230
444
|
// clones questions so that input areas aren't linked when reset
|
|
231
445
|
const emittedQuestion = _.cloneDeep(this.question)
|
|
@@ -253,9 +467,11 @@ export default {
|
|
|
253
467
|
element.correctAnswer = false
|
|
254
468
|
}
|
|
255
469
|
})
|
|
470
|
+
this.onCheckValidation()
|
|
256
471
|
},
|
|
257
472
|
onDelete(index) {
|
|
258
473
|
this.question.answer_options.splice(index, 1)
|
|
474
|
+
this.onCheckValidation()
|
|
259
475
|
},
|
|
260
476
|
onAddAnswer() {
|
|
261
477
|
// pushes new answer object into answer options
|
|
@@ -268,11 +484,12 @@ export default {
|
|
|
268
484
|
focus: true,
|
|
269
485
|
}
|
|
270
486
|
this.question.answer_options.push(answerObject)
|
|
487
|
+
this.onCheckValidation()
|
|
271
488
|
},
|
|
272
489
|
getCorrectAnswer(answer) {
|
|
273
490
|
// if input area is the correct answer adds a green border
|
|
274
491
|
if (answer.correctAnswer === true) {
|
|
275
|
-
return '
|
|
492
|
+
return 'container-success-outline'
|
|
276
493
|
} else {
|
|
277
494
|
return ''
|
|
278
495
|
}
|
|
@@ -285,7 +502,7 @@ export default {
|
|
|
285
502
|
}
|
|
286
503
|
},
|
|
287
504
|
onHover() {
|
|
288
|
-
this.cursor = '
|
|
505
|
+
this.cursor = 'cursor-pointer'
|
|
289
506
|
},
|
|
290
507
|
onHoverLeave() {
|
|
291
508
|
this.cursor = ''
|
|
@@ -294,11 +511,17 @@ export default {
|
|
|
294
511
|
}
|
|
295
512
|
</script>
|
|
296
513
|
<style lang="scss" scoped>
|
|
297
|
-
.
|
|
514
|
+
.container-success-outline {
|
|
298
515
|
border: 4px solid var(--v-success-base);
|
|
299
516
|
color: var(--v-success-base);
|
|
300
517
|
}
|
|
301
|
-
.
|
|
518
|
+
.cursor-pointer {
|
|
302
519
|
cursor: pointer !important;
|
|
303
520
|
}
|
|
521
|
+
.p-bold-text {
|
|
522
|
+
color: var(--v-primary-base);
|
|
523
|
+
}
|
|
524
|
+
.container-label-correct {
|
|
525
|
+
color: var(--v-success-base) !important;
|
|
526
|
+
}
|
|
304
527
|
</style>
|
|
@@ -193,15 +193,31 @@
|
|
|
193
193
|
indeterminate
|
|
194
194
|
></v-progress-circular>
|
|
195
195
|
</div>
|
|
196
|
+
<v-container class="pa-4 mb-6">
|
|
197
|
+
<v-row>
|
|
198
|
+
<v-col cols="12">
|
|
199
|
+
<GenerateAIQuestionButton
|
|
200
|
+
:course="course"
|
|
201
|
+
:content="content"
|
|
202
|
+
:block="block"
|
|
203
|
+
question-type="bucket_game"
|
|
204
|
+
:replace-existing-mode="replaceExisting"
|
|
205
|
+
@click:generate="onGeneratedBucketGame"
|
|
206
|
+
></GenerateAIQuestionButton>
|
|
207
|
+
</v-col>
|
|
208
|
+
</v-row>
|
|
209
|
+
</v-container>
|
|
196
210
|
</div>
|
|
197
211
|
</template>
|
|
198
212
|
|
|
199
213
|
<script>
|
|
200
214
|
import _ from 'lodash'
|
|
215
|
+
import { mapGetters } from 'vuex'
|
|
201
216
|
import {
|
|
202
217
|
MathExpressionEditor,
|
|
203
218
|
MathLiveWrapper,
|
|
204
219
|
ContentViewer,
|
|
220
|
+
GenerateAIQuestionButton
|
|
205
221
|
} from '@windward/core/utils'
|
|
206
222
|
import colors from 'vuetify/lib/util/colors'
|
|
207
223
|
import TextEditor from '~/components/Text/TextEditor'
|
|
@@ -221,6 +237,7 @@ export default {
|
|
|
221
237
|
SortableExpansionPanel,
|
|
222
238
|
BaseContentBlockSettings,
|
|
223
239
|
TextEditor,
|
|
240
|
+
GenerateAIQuestionButton,
|
|
224
241
|
},
|
|
225
242
|
beforeMount() {
|
|
226
243
|
if (_.isEmpty(this.block)) {
|
|
@@ -271,6 +288,7 @@ export default {
|
|
|
271
288
|
loading: false,
|
|
272
289
|
panel: 0,
|
|
273
290
|
expansionPanelKey: '0',
|
|
291
|
+
replaceExisting: false,
|
|
274
292
|
swatches: [
|
|
275
293
|
[colors.grey.lighten1, colors.blueGrey.lighten5],
|
|
276
294
|
[colors.brown.lighten3, colors.red.lighten3],
|
|
@@ -280,6 +298,12 @@ export default {
|
|
|
280
298
|
],
|
|
281
299
|
}
|
|
282
300
|
},
|
|
301
|
+
computed: {
|
|
302
|
+
...mapGetters({
|
|
303
|
+
course: 'course/get',
|
|
304
|
+
content: 'content/get',
|
|
305
|
+
}),
|
|
306
|
+
},
|
|
283
307
|
methods: {
|
|
284
308
|
onDragged(panels, oldPanelOrder) {
|
|
285
309
|
const oldAnswerArray = _.cloneDeep(
|
|
@@ -400,6 +424,125 @@ export default {
|
|
|
400
424
|
return htmlString.replace(/(<([^>]+)>)/gi, '')
|
|
401
425
|
}
|
|
402
426
|
},
|
|
427
|
+
// Handler for receiving bucket game data from GenerateAIQuestionButton
|
|
428
|
+
onGeneratedBucketGame(activityData, replaceMode) {
|
|
429
|
+
this.loading = true
|
|
430
|
+
try {
|
|
431
|
+
// Process the activity data
|
|
432
|
+
if (activityData && activityData.metadata &&
|
|
433
|
+
activityData.metadata.config &&
|
|
434
|
+
activityData.metadata.config.bucket_titles &&
|
|
435
|
+
activityData.metadata.config.bucket_answers &&
|
|
436
|
+
Array.isArray(activityData.metadata.config.bucket_titles) &&
|
|
437
|
+
Array.isArray(activityData.metadata.config.bucket_answers)) {
|
|
438
|
+
|
|
439
|
+
// Save new buckets and answers
|
|
440
|
+
const newBuckets = activityData.metadata.config.bucket_titles
|
|
441
|
+
const newAnswers = activityData.metadata.config.bucket_answers
|
|
442
|
+
|
|
443
|
+
if (replaceMode) {
|
|
444
|
+
// Replace mode: Clear existing buckets and answers
|
|
445
|
+
this.block.metadata.config.bucket_titles.splice(0, this.block.metadata.config.bucket_titles.length)
|
|
446
|
+
this.block.metadata.config.bucket_answers.splice(0, this.block.metadata.config.bucket_answers.length)
|
|
447
|
+
|
|
448
|
+
// Add all new buckets
|
|
449
|
+
newBuckets.forEach(bucket => {
|
|
450
|
+
this.block.metadata.config.bucket_titles.push({
|
|
451
|
+
title: bucket.title || '',
|
|
452
|
+
color: bucket.color || colors.blueGrey.lighten5,
|
|
453
|
+
expand: false
|
|
454
|
+
})
|
|
455
|
+
})
|
|
456
|
+
|
|
457
|
+
// Add all new answers
|
|
458
|
+
newAnswers.forEach((bucketAnswers, index) => {
|
|
459
|
+
this.block.metadata.config.bucket_answers[index] = []
|
|
460
|
+
if (Array.isArray(bucketAnswers)) {
|
|
461
|
+
bucketAnswers.forEach(answer => {
|
|
462
|
+
this.block.metadata.config.bucket_answers[index].push({
|
|
463
|
+
bucket_index: index,
|
|
464
|
+
display: answer.display || '',
|
|
465
|
+
feedback: answer.feedback || '',
|
|
466
|
+
expand: false,
|
|
467
|
+
id: Crypto.id()
|
|
468
|
+
})
|
|
469
|
+
})
|
|
470
|
+
}
|
|
471
|
+
})
|
|
472
|
+
} else {
|
|
473
|
+
// Merge mode: Add new buckets and answers to existing ones
|
|
474
|
+
const existingBucketCount = this.block.metadata.config.bucket_titles.length
|
|
475
|
+
|
|
476
|
+
// Add new buckets
|
|
477
|
+
newBuckets.forEach(bucket => {
|
|
478
|
+
this.block.metadata.config.bucket_titles.push({
|
|
479
|
+
title: bucket.title || '',
|
|
480
|
+
color: bucket.color || colors.blueGrey.lighten5,
|
|
481
|
+
expand: false
|
|
482
|
+
})
|
|
483
|
+
})
|
|
484
|
+
|
|
485
|
+
// Add new answers with adjusted bucket indices
|
|
486
|
+
newAnswers.forEach((bucketAnswers, index) => {
|
|
487
|
+
const adjustedIndex = existingBucketCount + index
|
|
488
|
+
if (!this.block.metadata.config.bucket_answers[adjustedIndex]) {
|
|
489
|
+
this.block.metadata.config.bucket_answers[adjustedIndex] = []
|
|
490
|
+
}
|
|
491
|
+
if (Array.isArray(bucketAnswers)) {
|
|
492
|
+
bucketAnswers.forEach(answer => {
|
|
493
|
+
this.block.metadata.config.bucket_answers[adjustedIndex].push({
|
|
494
|
+
bucket_index: adjustedIndex,
|
|
495
|
+
display: answer.display || '',
|
|
496
|
+
feedback: answer.feedback || '',
|
|
497
|
+
expand: false,
|
|
498
|
+
id: Crypto.id()
|
|
499
|
+
})
|
|
500
|
+
})
|
|
501
|
+
}
|
|
502
|
+
})
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
// Update title and instructions if provided and we're in replace mode
|
|
506
|
+
if (replaceMode) {
|
|
507
|
+
if (activityData.metadata.config.title) {
|
|
508
|
+
this.block.metadata.config.title = activityData.metadata.config.title
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
if (activityData.metadata.config.instructions) {
|
|
512
|
+
this.block.metadata.config.instructions = activityData.metadata.config.instructions
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
// Update feedback messages if provided
|
|
516
|
+
if (activityData.metadata.config.feedback_correct) {
|
|
517
|
+
this.block.metadata.config.feedback_correct = activityData.metadata.config.feedback_correct
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
if (activityData.metadata.config.feedback_incorrect) {
|
|
521
|
+
this.block.metadata.config.feedback_incorrect = activityData.metadata.config.feedback_incorrect
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
this.$toast.success(
|
|
526
|
+
replaceMode
|
|
527
|
+
? this.$t('windward.games.components.settings.bucket_game.form.replaced_successfully')
|
|
528
|
+
: this.$t('windward.games.components.settings.bucket_game.form.added_successfully'),
|
|
529
|
+
{ duration: 3000 }
|
|
530
|
+
)
|
|
531
|
+
} else {
|
|
532
|
+
this.$toast.error(this.$t('windward.games.components.settings.bucket_game.form.invalid_response'), {
|
|
533
|
+
duration: 5000
|
|
534
|
+
})
|
|
535
|
+
}
|
|
536
|
+
} catch (error) {
|
|
537
|
+
// Extract error message from the response
|
|
538
|
+
const errorMessage = error.message || 'Unknown error occurred'
|
|
539
|
+
this.$toast.error(`${this.$t('windward.games.components.settings.bucket_game.form.failed_to_process')}: ${errorMessage}`, {
|
|
540
|
+
duration: 5000
|
|
541
|
+
})
|
|
542
|
+
} finally {
|
|
543
|
+
this.loading = false
|
|
544
|
+
}
|
|
545
|
+
}
|
|
403
546
|
},
|
|
404
547
|
}
|
|
405
548
|
</script>
|
|
@@ -24,8 +24,8 @@
|
|
|
24
24
|
>
|
|
25
25
|
<template #header="{ item }">
|
|
26
26
|
{{
|
|
27
|
-
item.body
|
|
28
|
-
? item.body
|
|
27
|
+
stripHtml(item.body)
|
|
28
|
+
? stripHtml(item.body)
|
|
29
29
|
: $t(
|
|
30
30
|
'windward.games.components.settings.bucket_game.form.enter_text'
|
|
31
31
|
)
|
|
@@ -68,6 +68,7 @@
|
|
|
68
68
|
v-bind="attrs"
|
|
69
69
|
v-on="on"
|
|
70
70
|
v-model="block.metadata.config.questions[editingIndex]"
|
|
71
|
+
:block="block"
|
|
71
72
|
:disabled="render"
|
|
72
73
|
@saveAndNew="saveAndNewCalled"
|
|
73
74
|
></QuestionDialog>
|
|
@@ -150,6 +151,11 @@ export default {
|
|
|
150
151
|
this.emittedQuestion = {}
|
|
151
152
|
},
|
|
152
153
|
methods: {
|
|
154
|
+
stripHtml(htmlString) {
|
|
155
|
+
if (htmlString) {
|
|
156
|
+
return htmlString.replace(/(<([^>]+)>)/gi, '')
|
|
157
|
+
}
|
|
158
|
+
},
|
|
153
159
|
onOpenModal(e, questionIndex = null) {
|
|
154
160
|
//checks if modal is opening to edit or create new
|
|
155
161
|
if (questionIndex !== null) {
|
|
@@ -179,6 +185,14 @@ export default {
|
|
|
179
185
|
focus: false,
|
|
180
186
|
},
|
|
181
187
|
],
|
|
188
|
+
question_metadata: {
|
|
189
|
+
body_asset: null,
|
|
190
|
+
},
|
|
191
|
+
metadata: {
|
|
192
|
+
config: {
|
|
193
|
+
single_feedback: false,
|
|
194
|
+
},
|
|
195
|
+
},
|
|
182
196
|
correctAnswer: firstAnswerId,
|
|
183
197
|
body: '',
|
|
184
198
|
hint: '',
|
|
@@ -211,6 +225,14 @@ export default {
|
|
|
211
225
|
chosen: false,
|
|
212
226
|
},
|
|
213
227
|
],
|
|
228
|
+
question_metadata: {
|
|
229
|
+
body_asset: null,
|
|
230
|
+
},
|
|
231
|
+
metadata: {
|
|
232
|
+
config: {
|
|
233
|
+
single_feedback: false,
|
|
234
|
+
},
|
|
235
|
+
},
|
|
214
236
|
// needed to add this bc radio group needs the id of the answer in answerobjects array to set correct value
|
|
215
237
|
correctAnswer: firstAnswerId,
|
|
216
238
|
body: '',
|
|
@@ -36,5 +36,10 @@ export default {
|
|
|
36
36
|
click_here: 'Click here to enter text',
|
|
37
37
|
add_answer: 'Add Answer',
|
|
38
38
|
color: 'Bucket Color',
|
|
39
|
+
replace_existing: 'Replace existing buckets',
|
|
40
|
+
replaced_successfully: 'Buckets replaced successfully',
|
|
41
|
+
added_successfully: 'New buckets added successfully',
|
|
42
|
+
invalid_response: 'Invalid response from bucket game generation',
|
|
43
|
+
failed_to_process: 'Failed to process generated buckets'
|
|
39
44
|
},
|
|
40
45
|
}
|
|
@@ -2,7 +2,8 @@ export default {
|
|
|
2
2
|
game_title: 'Multiple Choice Game',
|
|
3
3
|
title_placeholder: 'Title',
|
|
4
4
|
instructions: 'Instructions',
|
|
5
|
-
default_instructions:
|
|
5
|
+
default_instructions:
|
|
6
|
+
'Read the question and click the correct answer below. Use the arrows to move between questions.',
|
|
6
7
|
questions: 'Questions',
|
|
7
8
|
modal_title: 'Multiple Choice Question',
|
|
8
9
|
question_hint: 'Question Hint',
|
|
@@ -11,7 +12,7 @@ export default {
|
|
|
11
12
|
answer_options: 'Answer Options',
|
|
12
13
|
answer_option: 'Answer Option',
|
|
13
14
|
correct: 'Correct',
|
|
14
|
-
|
|
15
|
-
add_answer: 'Add Answer',
|
|
15
|
+
add_answer: 'Add Answer Option',
|
|
16
16
|
add_question: 'Add Question',
|
|
17
|
+
answer: 'Answers',
|
|
17
18
|
}
|
|
@@ -37,5 +37,10 @@ export default {
|
|
|
37
37
|
click_here: 'Haga clic aquí para ingresar texto',
|
|
38
38
|
add_answer: 'Agregar respuesta',
|
|
39
39
|
color: 'Color del cubo',
|
|
40
|
+
replace_existing: 'Reemplazar cubos existentes',
|
|
41
|
+
replaced_successfully: 'Cubos reemplazados exitosamente',
|
|
42
|
+
added_successfully: 'Nuevos cubos añadidos exitosamente',
|
|
43
|
+
invalid_response: 'Respuesta inválida de la generación del juego de cubos',
|
|
44
|
+
failed_to_process: 'Error al procesar los cubos generados'
|
|
40
45
|
},
|
|
41
46
|
}
|
|
@@ -12,8 +12,7 @@ export default {
|
|
|
12
12
|
answer_options: 'Opciones de respuesta',
|
|
13
13
|
answer_option: 'Opción de respuesta',
|
|
14
14
|
correct: 'Correcto',
|
|
15
|
-
|
|
16
|
-
'Haga clic en una respuesta para establecerla como la respuesta correcta',
|
|
17
|
-
add_answer: 'Agregar respuesta',
|
|
15
|
+
add_answer: 'Agregar opción de respuesta',
|
|
18
16
|
add_question: 'Agregar pregunta',
|
|
17
|
+
answer: 'Respuestas',
|
|
19
18
|
}
|
|
@@ -36,5 +36,10 @@ export default {
|
|
|
36
36
|
click_here: 'Klicka här för att skriva in text',
|
|
37
37
|
add_answer: 'Lägg till svar',
|
|
38
38
|
color: 'Bucket Color',
|
|
39
|
+
replace_existing: 'Ersätt befintliga hinkar',
|
|
40
|
+
replaced_successfully: 'Hinkar ersatta',
|
|
41
|
+
added_successfully: 'Nya hinkar tillagda',
|
|
42
|
+
invalid_response: 'Ogiltig svar från hinkspel',
|
|
43
|
+
failed_to_process: 'Misslyckades att bearbeta hinkar'
|
|
39
44
|
},
|
|
40
45
|
}
|
|
@@ -11,7 +11,7 @@ export default {
|
|
|
11
11
|
answer_options: 'Svarsalternativ',
|
|
12
12
|
answer_option: 'Svarsalternativ',
|
|
13
13
|
correct: 'Korrekt',
|
|
14
|
-
|
|
15
|
-
add_answer: 'Lägg till svar',
|
|
14
|
+
add_answer: 'Lägg till svarsalternativ',
|
|
16
15
|
add_question: 'Lägg till fråga',
|
|
16
|
+
answer: 'Svar',
|
|
17
17
|
}
|