@windward/games 0.0.1 → 0.0.3
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/components/content/blocks/dragDrop/BucketGame.vue +4 -4
- package/components/content/blocks/dragDrop/SortingGame.vue +1 -1
- package/components/content/blocks/flashcards/FlashcardSlides.vue +2 -2
- package/components/content/blocks/matchingGame/MatchingGame.vue +2 -2
- package/components/content/blocks/multipleChoice/MultipleChoice.vue +565 -0
- package/components/content/blocks/multipleChoice/QuestionDialog.vue +276 -0
- package/components/content/blocks/quizshowGame/QuizShow.vue +2 -2
- package/components/content/blocks/slideshow/SlideShow.vue +2 -2
- package/components/content/blocks/wordJumble/Jumble.vue +97 -0
- package/components/content/blocks/wordJumble/WordJumble.vue +239 -0
- package/components/settings/MultipleChoiceSettingsManager.vue +290 -0
- package/components/settings/SortingGameSettingsManager.vue +10 -5
- package/components/settings/WordJumbleSettingsManager.vue +293 -0
- package/i18n/en-US/components/content/blocks/index.ts +4 -0
- package/i18n/en-US/components/content/blocks/matching_game.ts +1 -1
- package/i18n/en-US/components/content/blocks/multiple_choice.ts +11 -0
- package/i18n/en-US/components/content/blocks/word_jumble.ts +9 -0
- package/i18n/en-US/components/settings/index.ts +6 -0
- package/i18n/en-US/components/settings/multiple_choice.ts +16 -0
- package/i18n/en-US/components/settings/sorting_game.ts +3 -0
- package/i18n/en-US/components/settings/word_jumble.ts +11 -0
- package/i18n/en-US/shared/content_blocks.ts +2 -0
- package/i18n/en-US/shared/settings.ts +2 -0
- package/package.json +1 -1
- package/plugin.js +42 -0
- package/test/blocks/multipleChoice/MultipleChoice.spec.js +26 -0
- package/test/blocks/multipleChoice/QuestionDialog.spec.js +26 -0
- package/test/blocks/wordJumble/Jumble.spec.js +27 -0
- package/test/blocks/wordJumble/WordJumble.spec.js +24 -0
- package/test/settings/MultipleChoiceGameManager.spec.js +30 -0
- package/test/settings/WordJumbleManager.spec.js +87 -0
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<v-form ref="form" v-model="formValid" :key="updateKey">
|
|
3
|
+
<v-row>
|
|
4
|
+
<v-col cols="12">
|
|
5
|
+
<v-textarea
|
|
6
|
+
v-model="question.body"
|
|
7
|
+
:label="
|
|
8
|
+
$t(
|
|
9
|
+
'plugin.games.components.settings.multiple_choice.question'
|
|
10
|
+
)
|
|
11
|
+
"
|
|
12
|
+
:autofocus="true"
|
|
13
|
+
rows="2"
|
|
14
|
+
:rules="validation.textRules"
|
|
15
|
+
prepend-inner-icon="mdi-help"
|
|
16
|
+
></v-textarea>
|
|
17
|
+
<v-textarea
|
|
18
|
+
v-model="question.hint"
|
|
19
|
+
:label="
|
|
20
|
+
$t(
|
|
21
|
+
'plugin.games.components.settings.multiple_choice.question_hint'
|
|
22
|
+
)
|
|
23
|
+
"
|
|
24
|
+
rows="2"
|
|
25
|
+
:rules="validation.textRules"
|
|
26
|
+
prepend-inner-icon="mdi-lightbulb-on-10"
|
|
27
|
+
></v-textarea>
|
|
28
|
+
<v-textarea
|
|
29
|
+
v-model="question.answer_description"
|
|
30
|
+
:label="
|
|
31
|
+
$t(
|
|
32
|
+
'plugin.games.components.settings.multiple_choice.answer_description'
|
|
33
|
+
)
|
|
34
|
+
"
|
|
35
|
+
rows="2"
|
|
36
|
+
:rules="validation.textRules"
|
|
37
|
+
prepend-inner-icon="mdi-comment"
|
|
38
|
+
></v-textarea>
|
|
39
|
+
<h3>
|
|
40
|
+
{{
|
|
41
|
+
$t(
|
|
42
|
+
'plugin.games.components.settings.multiple_choice.answer_options'
|
|
43
|
+
)
|
|
44
|
+
}}
|
|
45
|
+
</h3>
|
|
46
|
+
<p>
|
|
47
|
+
{{
|
|
48
|
+
$t(
|
|
49
|
+
'plugin.games.components.settings.multiple_choice.correct_answer'
|
|
50
|
+
)
|
|
51
|
+
}}
|
|
52
|
+
</p>
|
|
53
|
+
</v-col>
|
|
54
|
+
<v-container
|
|
55
|
+
v-for="(answer, index) in question.answer_options"
|
|
56
|
+
:key="index"
|
|
57
|
+
>
|
|
58
|
+
<v-row>
|
|
59
|
+
<v-col
|
|
60
|
+
cols="12"
|
|
61
|
+
md="1"
|
|
62
|
+
class="d-flex justify-center"
|
|
63
|
+
@mouseover="onHover"
|
|
64
|
+
@mouseleave="onHoverLeave"
|
|
65
|
+
>
|
|
66
|
+
<v-checkbox
|
|
67
|
+
v-model="answer.correctAnswer"
|
|
68
|
+
:ref="'checkbox' + index"
|
|
69
|
+
@click="onSetAnswer(answer)"
|
|
70
|
+
></v-checkbox>
|
|
71
|
+
</v-col>
|
|
72
|
+
<v-col cols="12" md="10">
|
|
73
|
+
<v-textarea
|
|
74
|
+
flat
|
|
75
|
+
solo
|
|
76
|
+
v-model="answer.value"
|
|
77
|
+
:outlined="setOutline(answer)"
|
|
78
|
+
hide-details
|
|
79
|
+
:class="getCorrectAnswer(answer)"
|
|
80
|
+
:label="
|
|
81
|
+
$t(
|
|
82
|
+
'plugin.games.components.settings.multiple_choice.answer_option'
|
|
83
|
+
)
|
|
84
|
+
"
|
|
85
|
+
rows="2"
|
|
86
|
+
:rules="validation.textRules"
|
|
87
|
+
></v-textarea>
|
|
88
|
+
</v-col>
|
|
89
|
+
<v-col
|
|
90
|
+
cols="12"
|
|
91
|
+
md="1"
|
|
92
|
+
class="d-flex justify-center"
|
|
93
|
+
@mouseover="onHover"
|
|
94
|
+
@mouseleave="onHoverLeave"
|
|
95
|
+
@click="onDelete(index)"
|
|
96
|
+
>
|
|
97
|
+
<v-icon>mdi-delete</v-icon>
|
|
98
|
+
</v-col>
|
|
99
|
+
</v-row>
|
|
100
|
+
</v-container>
|
|
101
|
+
<v-container class="d-flex justify-center" v-if="overLength">
|
|
102
|
+
<p
|
|
103
|
+
@mouseover="onHover"
|
|
104
|
+
@mouseleave="onHoverLeave"
|
|
105
|
+
@click="onAddAnswer"
|
|
106
|
+
v-on:keyup.enter="onAddAnswer"
|
|
107
|
+
class="fullWidth"
|
|
108
|
+
:class="cursor"
|
|
109
|
+
tabindex="0"
|
|
110
|
+
>
|
|
111
|
+
<v-icon class="primary addIcon">mdi-plus</v-icon>
|
|
112
|
+
{{
|
|
113
|
+
$t(
|
|
114
|
+
'plugin.games.components.settings.multiple_choice.add_answer'
|
|
115
|
+
)
|
|
116
|
+
}}
|
|
117
|
+
</p>
|
|
118
|
+
</v-container>
|
|
119
|
+
</v-row>
|
|
120
|
+
</v-form>
|
|
121
|
+
</template>
|
|
122
|
+
<script>
|
|
123
|
+
import Form from '~/components/Form'
|
|
124
|
+
import _ from 'lodash'
|
|
125
|
+
import Crypto from '~/helpers/Crypto'
|
|
126
|
+
export default {
|
|
127
|
+
name: 'QuestionDialog',
|
|
128
|
+
extends: Form,
|
|
129
|
+
layout: 'authenticated',
|
|
130
|
+
middleware: ['auth', 'course'],
|
|
131
|
+
props: {
|
|
132
|
+
value: { type: Object, required: false },
|
|
133
|
+
},
|
|
134
|
+
watch: {
|
|
135
|
+
value: {
|
|
136
|
+
deep: true,
|
|
137
|
+
handler(newValue) {
|
|
138
|
+
// clone so that the modal isn't opening with filled in outputs each time
|
|
139
|
+
// if we wrote directly to value it would save on settings side and populate modal when opened
|
|
140
|
+
this.question = _.cloneDeep(newValue)
|
|
141
|
+
if (_.get(this.question, 'answer_options', null) === null) {
|
|
142
|
+
this.question = {
|
|
143
|
+
answer_options: [
|
|
144
|
+
{
|
|
145
|
+
id: 1,
|
|
146
|
+
value: '',
|
|
147
|
+
correctAnswer: true,
|
|
148
|
+
disabled: false,
|
|
149
|
+
},
|
|
150
|
+
{
|
|
151
|
+
id: 2,
|
|
152
|
+
value: '',
|
|
153
|
+
correctAnswer: false,
|
|
154
|
+
disabled: false,
|
|
155
|
+
},
|
|
156
|
+
],
|
|
157
|
+
body: '',
|
|
158
|
+
hint: '',
|
|
159
|
+
answer_description: '',
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
},
|
|
163
|
+
},
|
|
164
|
+
},
|
|
165
|
+
computed: {
|
|
166
|
+
// won't allow more than four answers to be input
|
|
167
|
+
overLength() {
|
|
168
|
+
if (
|
|
169
|
+
this.question.answer_options &&
|
|
170
|
+
this.question.answer_options.length < 4
|
|
171
|
+
) {
|
|
172
|
+
return true
|
|
173
|
+
} else {
|
|
174
|
+
return false
|
|
175
|
+
}
|
|
176
|
+
},
|
|
177
|
+
},
|
|
178
|
+
data() {
|
|
179
|
+
return {
|
|
180
|
+
question: {},
|
|
181
|
+
validation: {
|
|
182
|
+
textRules: [
|
|
183
|
+
(v) => !!v || this.$t('shared.forms.errors.required'),
|
|
184
|
+
],
|
|
185
|
+
optionRules: [
|
|
186
|
+
(v) => {
|
|
187
|
+
return (
|
|
188
|
+
!!v ||
|
|
189
|
+
this.$t(
|
|
190
|
+
'components.content.blocks.assessment.questions.types.multi_choice_single_answer.correct_required'
|
|
191
|
+
)
|
|
192
|
+
)
|
|
193
|
+
},
|
|
194
|
+
],
|
|
195
|
+
},
|
|
196
|
+
cursor: null,
|
|
197
|
+
updateKey: 0,
|
|
198
|
+
}
|
|
199
|
+
},
|
|
200
|
+
mounted() {
|
|
201
|
+
if (!_.isEmpty(this.value)) {
|
|
202
|
+
this.question = _.cloneDeep(this.value)
|
|
203
|
+
}
|
|
204
|
+
// refreshes data for modal on mount
|
|
205
|
+
this.updateKey = Crypto.id()
|
|
206
|
+
},
|
|
207
|
+
methods: {
|
|
208
|
+
onSave() {
|
|
209
|
+
// clones questions so that input areas aren't linked when reset
|
|
210
|
+
const emittedQuestion = _.cloneDeep(this.question)
|
|
211
|
+
// // emit value from inputs to parent components of the settings manager
|
|
212
|
+
this.$emit('input', emittedQuestion)
|
|
213
|
+
},
|
|
214
|
+
onSaveAndNew() {
|
|
215
|
+
// clones questions so that input areas aren't linked when reset
|
|
216
|
+
const emittedQuestion = _.cloneDeep(this.question)
|
|
217
|
+
// // emit value from inputs to parent components of the settings manager
|
|
218
|
+
this.$emit('input', emittedQuestion)
|
|
219
|
+
this.$emit('saveAndNew')
|
|
220
|
+
},
|
|
221
|
+
onSetAnswer(answer) {
|
|
222
|
+
// changes all inputs that aren't the choosen correct answer to be unchecked
|
|
223
|
+
const index = this.question.answer_options.indexOf(answer)
|
|
224
|
+
this.question.answer_options.forEach((element) => {
|
|
225
|
+
const loopIndex = this.question.answer_options.indexOf(element)
|
|
226
|
+
if (loopIndex !== index) {
|
|
227
|
+
element.correctAnswer = false
|
|
228
|
+
}
|
|
229
|
+
})
|
|
230
|
+
},
|
|
231
|
+
onDelete(index) {
|
|
232
|
+
this.question.answer_options.splice(index, 1)
|
|
233
|
+
},
|
|
234
|
+
onAddAnswer() {
|
|
235
|
+
// pushes new answer object into answer options
|
|
236
|
+
const answerObject = {
|
|
237
|
+
id: this.question.answer_options.length + 1,
|
|
238
|
+
value: '',
|
|
239
|
+
correctAnswer: false,
|
|
240
|
+
disabled: false,
|
|
241
|
+
}
|
|
242
|
+
this.question.answer_options.push(answerObject)
|
|
243
|
+
},
|
|
244
|
+
getCorrectAnswer(answer) {
|
|
245
|
+
// if input area is the correct answer adds a green border
|
|
246
|
+
if (answer.correctAnswer === true) {
|
|
247
|
+
return 'successOutline'
|
|
248
|
+
} else {
|
|
249
|
+
return ''
|
|
250
|
+
}
|
|
251
|
+
},
|
|
252
|
+
setOutline(answer) {
|
|
253
|
+
if (answer.correctAnswer === true) {
|
|
254
|
+
return false
|
|
255
|
+
} else {
|
|
256
|
+
return true
|
|
257
|
+
}
|
|
258
|
+
},
|
|
259
|
+
onHover() {
|
|
260
|
+
this.cursor = 'changePointer'
|
|
261
|
+
},
|
|
262
|
+
onHoverLeave() {
|
|
263
|
+
this.cursor = ''
|
|
264
|
+
},
|
|
265
|
+
},
|
|
266
|
+
}
|
|
267
|
+
</script>
|
|
268
|
+
<style lang="scss" scoped>
|
|
269
|
+
.successOutline {
|
|
270
|
+
border: 4px solid var(--v-success-base);
|
|
271
|
+
color: var(--v-success-base);
|
|
272
|
+
}
|
|
273
|
+
.changePointer {
|
|
274
|
+
cursor: pointer !important;
|
|
275
|
+
}
|
|
276
|
+
</style>
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
></v-switch>
|
|
13
13
|
<div v-if="!tableMode">
|
|
14
14
|
<div>
|
|
15
|
-
<
|
|
15
|
+
<h3
|
|
16
16
|
:aria-label="
|
|
17
17
|
$t(
|
|
18
18
|
'plugin.games.components.content.blocks.quizshow_game.title'
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
tabindex="0"
|
|
22
22
|
>
|
|
23
23
|
{{ block.metadata.config.title }}
|
|
24
|
-
</
|
|
24
|
+
</h3>
|
|
25
25
|
|
|
26
26
|
<p tabindex="0">
|
|
27
27
|
<TextViewer v-model="block.metadata.config.instructions" />
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div>
|
|
3
3
|
<div class="header-description">
|
|
4
|
-
<
|
|
4
|
+
<h3
|
|
5
5
|
:aria-label="
|
|
6
6
|
$t(
|
|
7
7
|
'plugin.games.components.content.blocks.slideshow.slideshow_title'
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
tabindex="0"
|
|
11
11
|
>
|
|
12
12
|
{{ block.metadata.config.title }}
|
|
13
|
-
</
|
|
13
|
+
</h3>
|
|
14
14
|
|
|
15
15
|
<p tabindex="0" class="pt-3">
|
|
16
16
|
{{ block.metadata.config.instructions }}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<v-container>
|
|
3
|
+
<v-row class="d-flex justify-center">
|
|
4
|
+
<div v-for="(item, index) in letterArray" :key="index">
|
|
5
|
+
<v-text-field
|
|
6
|
+
v-model="item.value"
|
|
7
|
+
:ref="'input' + index"
|
|
8
|
+
:autofocus="index === 0 ? true : false"
|
|
9
|
+
class="textArea ml-1 mr-1"
|
|
10
|
+
maxlength="1"
|
|
11
|
+
@input="onInput($event, index)"
|
|
12
|
+
v-on:keydown="onSpaceHandler($event)"
|
|
13
|
+
></v-text-field>
|
|
14
|
+
</div>
|
|
15
|
+
</v-row>
|
|
16
|
+
</v-container>
|
|
17
|
+
</template>
|
|
18
|
+
<script>
|
|
19
|
+
import _ from 'lodash'
|
|
20
|
+
export default {
|
|
21
|
+
name: 'Jumble',
|
|
22
|
+
props: {
|
|
23
|
+
value: { type: Object, required: true, default: '' },
|
|
24
|
+
reveal: { type: Boolean, required: true, default: false },
|
|
25
|
+
reset: { type: Boolean, required: true, default: false },
|
|
26
|
+
},
|
|
27
|
+
watch: {
|
|
28
|
+
reveal: {
|
|
29
|
+
handler(newValue) {
|
|
30
|
+
// reveals correct answer in input areas
|
|
31
|
+
if (newValue === true) {
|
|
32
|
+
for (let i = 0; i < this.value.value.length; i++) {
|
|
33
|
+
const letter = this.answer.charAt(i)
|
|
34
|
+
this.letterArray[i].value = letter
|
|
35
|
+
}
|
|
36
|
+
} else {
|
|
37
|
+
this.splitUpWord()
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
immediate: true,
|
|
41
|
+
},
|
|
42
|
+
reset: {
|
|
43
|
+
handler(newValue) {
|
|
44
|
+
// removes students answer from input if they got it correct
|
|
45
|
+
this.splitUpWord()
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
data() {
|
|
50
|
+
return {
|
|
51
|
+
saveState: false,
|
|
52
|
+
letterArray: [],
|
|
53
|
+
answer: '',
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
mounted() {
|
|
57
|
+
this.letterArray = []
|
|
58
|
+
this.answer = this.value.value
|
|
59
|
+
this.splitUpWord()
|
|
60
|
+
},
|
|
61
|
+
methods: {
|
|
62
|
+
splitUpWord() {
|
|
63
|
+
this.letterArray = []
|
|
64
|
+
// gets length of word and creates input area for each letter
|
|
65
|
+
if (!_.isEmpty(this.value.value)) {
|
|
66
|
+
for (let i = 0; i < this.value.value.length; i++) {
|
|
67
|
+
let defaultObject = {
|
|
68
|
+
value: '',
|
|
69
|
+
}
|
|
70
|
+
this.letterArray.push(defaultObject)
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
},
|
|
74
|
+
onSpaceHandler(event) {
|
|
75
|
+
// prevents empty space from being entered
|
|
76
|
+
if (event.keyCode === 32) {
|
|
77
|
+
event.preventDefault()
|
|
78
|
+
return false
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
onInput(event, index) {
|
|
82
|
+
// handles focusing on next element after student enters a letter
|
|
83
|
+
if (!_.isEmpty(event) && this.$refs['input' + (index + 1)]) {
|
|
84
|
+
this.$refs['input' + (index + 1)][0].focus()
|
|
85
|
+
} else if (index !== 0 && _.isEmpty(event)) {
|
|
86
|
+
this.$refs['input' + (index - 1)][0].focus()
|
|
87
|
+
}
|
|
88
|
+
this.$emit('input', this.letterArray)
|
|
89
|
+
},
|
|
90
|
+
},
|
|
91
|
+
}
|
|
92
|
+
</script>
|
|
93
|
+
<style scoped>
|
|
94
|
+
.textArea {
|
|
95
|
+
width: 20px;
|
|
96
|
+
}
|
|
97
|
+
</style>
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<v-container>
|
|
3
|
+
<v-col class="pa-0">
|
|
4
|
+
<h3>
|
|
5
|
+
{{
|
|
6
|
+
block.metadata.config.title
|
|
7
|
+
? block.metadata.config.title
|
|
8
|
+
: $t(
|
|
9
|
+
'plugin.games.components.content.blocks.word_jumble.title'
|
|
10
|
+
)
|
|
11
|
+
}}
|
|
12
|
+
</h3>
|
|
13
|
+
<p>{{ block.metadata.config.instructions }}</p>
|
|
14
|
+
</v-col>
|
|
15
|
+
<v-col class="pa-0">
|
|
16
|
+
<template>
|
|
17
|
+
<v-carousel @change="onSlideChanged()">
|
|
18
|
+
<v-carousel-item
|
|
19
|
+
v-for="(word, index) in block.metadata.config.words"
|
|
20
|
+
:key="index"
|
|
21
|
+
>
|
|
22
|
+
<v-row class="d-flex justify-center outline ma-2">
|
|
23
|
+
<p class="pa-3 mb-0 clueAndJumble">
|
|
24
|
+
<span class="spanBold"
|
|
25
|
+
>{{
|
|
26
|
+
$t(
|
|
27
|
+
'plugin.games.components.content.blocks.word_jumble.clue'
|
|
28
|
+
)
|
|
29
|
+
}}
|
|
30
|
+
</span>
|
|
31
|
+
{{ word.hint }}
|
|
32
|
+
</p>
|
|
33
|
+
</v-row>
|
|
34
|
+
<v-row class="d-flex justify-center outline ma-2">
|
|
35
|
+
<p class="pa-3 mb-0 clueAndJumble">
|
|
36
|
+
{{ shuffle(word.value) }}
|
|
37
|
+
</p>
|
|
38
|
+
</v-row>
|
|
39
|
+
<v-container :key="'feedback'" :class="feedbackStatus">
|
|
40
|
+
<br />
|
|
41
|
+
<v-row
|
|
42
|
+
class="d-flex justify-space-around"
|
|
43
|
+
align="center"
|
|
44
|
+
justify="center"
|
|
45
|
+
>{{ feedback }}
|
|
46
|
+
</v-row>
|
|
47
|
+
<br />
|
|
48
|
+
</v-container>
|
|
49
|
+
<v-row class="justify-center mt-4">
|
|
50
|
+
<Jumble
|
|
51
|
+
:value="word"
|
|
52
|
+
:reveal="showAnswer"
|
|
53
|
+
:reset="resetValue"
|
|
54
|
+
@input="getResponse($event)"
|
|
55
|
+
></Jumble>
|
|
56
|
+
</v-row>
|
|
57
|
+
<v-row class="justify-center mt-8">
|
|
58
|
+
<v-btn
|
|
59
|
+
color="primary mr-4"
|
|
60
|
+
@click="onCheckAnswer(word)"
|
|
61
|
+
>{{
|
|
62
|
+
$t(
|
|
63
|
+
'plugin.games.components.content.blocks.word_jumble.check'
|
|
64
|
+
)
|
|
65
|
+
}}</v-btn
|
|
66
|
+
>
|
|
67
|
+
<v-btn
|
|
68
|
+
color="primary ml-4"
|
|
69
|
+
@click="onRevealAnswer"
|
|
70
|
+
>{{
|
|
71
|
+
$t(
|
|
72
|
+
'plugin.games.components.content.blocks.word_jumble.reveal'
|
|
73
|
+
)
|
|
74
|
+
}}</v-btn
|
|
75
|
+
>
|
|
76
|
+
</v-row>
|
|
77
|
+
</v-carousel-item>
|
|
78
|
+
</v-carousel>
|
|
79
|
+
</template>
|
|
80
|
+
</v-col>
|
|
81
|
+
</v-container>
|
|
82
|
+
</template>
|
|
83
|
+
<script>
|
|
84
|
+
import _ from 'lodash'
|
|
85
|
+
import Jumble from './Jumble.vue'
|
|
86
|
+
import BaseContentBlock from '~/components/Content/Blocks/BaseContentBlock'
|
|
87
|
+
|
|
88
|
+
export default {
|
|
89
|
+
name: 'WordJumble',
|
|
90
|
+
extends: BaseContentBlock,
|
|
91
|
+
components: {
|
|
92
|
+
Jumble,
|
|
93
|
+
},
|
|
94
|
+
beforeMount() {
|
|
95
|
+
if (_.isEmpty(this.block)) {
|
|
96
|
+
this.block = {}
|
|
97
|
+
}
|
|
98
|
+
if (_.isEmpty(this.block.metadata)) {
|
|
99
|
+
this.block.metadata = {}
|
|
100
|
+
}
|
|
101
|
+
if (_.isEmpty(this.block.metadata.config)) {
|
|
102
|
+
this.block.metadata.config = {}
|
|
103
|
+
}
|
|
104
|
+
if (_.isEmpty(this.block.metadata.config.title)) {
|
|
105
|
+
this.block.metadata.config.title = ''
|
|
106
|
+
}
|
|
107
|
+
if (_.isEmpty(this.block.metadata.config.instructions)) {
|
|
108
|
+
this.block.metadata.config.instructions = ''
|
|
109
|
+
}
|
|
110
|
+
if (_.isEmpty(this.block.metadata.config.feedback_correct)) {
|
|
111
|
+
this.block.metadata.config.feedback_correct = ''
|
|
112
|
+
}
|
|
113
|
+
if (_.isEmpty(this.block.metadata.config.feedback_incorrect)) {
|
|
114
|
+
this.block.metadata.config.feedback_incorrect = ''
|
|
115
|
+
}
|
|
116
|
+
if (_.isEmpty(this.block.metadata.config.words)) {
|
|
117
|
+
this.block.metadata.config.words = []
|
|
118
|
+
}
|
|
119
|
+
},
|
|
120
|
+
data() {
|
|
121
|
+
return {
|
|
122
|
+
saveState: false,
|
|
123
|
+
feedback: this.$t(
|
|
124
|
+
'plugin.games.components.content.blocks.word_jumble.feedback'
|
|
125
|
+
),
|
|
126
|
+
showAnswer: false,
|
|
127
|
+
resetValue: false,
|
|
128
|
+
studentResponse: '',
|
|
129
|
+
feedbackStatus: '',
|
|
130
|
+
}
|
|
131
|
+
},
|
|
132
|
+
mounted() {
|
|
133
|
+
this.showAnswer = false
|
|
134
|
+
},
|
|
135
|
+
methods: {
|
|
136
|
+
shuffle(str) {
|
|
137
|
+
var a = str
|
|
138
|
+
var newArr = []
|
|
139
|
+
var neww = ''
|
|
140
|
+
var text = a.replace(/[\r\n]/g, '').split(' ')
|
|
141
|
+
|
|
142
|
+
text.map(function (v) {
|
|
143
|
+
v.split('').map(function () {
|
|
144
|
+
var hash = Math.floor(Math.random() * v.length)
|
|
145
|
+
neww += v[hash]
|
|
146
|
+
v = v.replace(v.charAt(hash), '')
|
|
147
|
+
})
|
|
148
|
+
newArr.push(neww)
|
|
149
|
+
neww = ''
|
|
150
|
+
})
|
|
151
|
+
var x = newArr.map((v) => v.split('').join(' ')).join('\n')
|
|
152
|
+
str = x
|
|
153
|
+
.split('')
|
|
154
|
+
.map((v) => v.toUpperCase())
|
|
155
|
+
.join('')
|
|
156
|
+
return str
|
|
157
|
+
},
|
|
158
|
+
getResponse(event) {
|
|
159
|
+
// child component emits event that triggers this function to get the students response as they enter it
|
|
160
|
+
this.studentResponse = ''
|
|
161
|
+
event.forEach((element) => {
|
|
162
|
+
this.studentResponse = this.studentResponse + element.value
|
|
163
|
+
})
|
|
164
|
+
},
|
|
165
|
+
onRevealAnswer() {
|
|
166
|
+
// reveal prop changed to true to show answer
|
|
167
|
+
this.showAnswer = true
|
|
168
|
+
},
|
|
169
|
+
onCheckAnswer(word) {
|
|
170
|
+
this.studentResponse = this.studentResponse.toLowerCase()
|
|
171
|
+
const answer = word.value.toLowerCase()
|
|
172
|
+
if (this.studentResponse === answer) {
|
|
173
|
+
// updates class
|
|
174
|
+
this.feedbackStatus = 'success'
|
|
175
|
+
// gets custom or standard feedback
|
|
176
|
+
if (
|
|
177
|
+
!_.isEmpty(this.block.metadata.config.feedback_correct) &&
|
|
178
|
+
this.block.metadata.config.feedback_correct !== ''
|
|
179
|
+
) {
|
|
180
|
+
this.feedback = this.block.metadata.config.feedback_correct
|
|
181
|
+
} else {
|
|
182
|
+
this.feedback = this.$t(
|
|
183
|
+
'plugin.games.components.content.blocks.word_jumble.correct'
|
|
184
|
+
)
|
|
185
|
+
}
|
|
186
|
+
} else {
|
|
187
|
+
// updates class
|
|
188
|
+
this.feedbackStatus = 'error'
|
|
189
|
+
// gets custom or standard feedback
|
|
190
|
+
if (
|
|
191
|
+
!_.isEmpty(this.block.metadata.config.feedback_incorrect) &&
|
|
192
|
+
this.block.metadata.config.feedback_incorrect !== ''
|
|
193
|
+
) {
|
|
194
|
+
this.feedback =
|
|
195
|
+
this.block.metadata.config.feedback_incorrect
|
|
196
|
+
} else {
|
|
197
|
+
this.feedback = this.$t(
|
|
198
|
+
'plugin.games.components.content.blocks.word_jumble.incorrect'
|
|
199
|
+
)
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
},
|
|
203
|
+
onSlideChanged() {
|
|
204
|
+
// this function is called when the slide is changed
|
|
205
|
+
// reset the game each time this occurs via props due to fact
|
|
206
|
+
// that components do not remount on slides each time the slide is revisited
|
|
207
|
+
// updates class
|
|
208
|
+
this.feedbackStatus = ''
|
|
209
|
+
this.feedback = this.$t(
|
|
210
|
+
'plugin.games.components.content.blocks.word_jumble.feedback'
|
|
211
|
+
)
|
|
212
|
+
// ensure answer no longder revealed
|
|
213
|
+
this.showAnswer = false
|
|
214
|
+
// if student has entered a response the input values are reset to empty on slide change
|
|
215
|
+
this.resetValue = !this.resetValue
|
|
216
|
+
},
|
|
217
|
+
},
|
|
218
|
+
}
|
|
219
|
+
</script>
|
|
220
|
+
<style lang="scss" scoped>
|
|
221
|
+
.outline {
|
|
222
|
+
border: 2px solid black;
|
|
223
|
+
border-radius: 10px;
|
|
224
|
+
}
|
|
225
|
+
.clueAndJumble {
|
|
226
|
+
font-size: 20px;
|
|
227
|
+
}
|
|
228
|
+
.spanBold {
|
|
229
|
+
font-weight: 900;
|
|
230
|
+
}
|
|
231
|
+
.error {
|
|
232
|
+
border: dashed 2px #dc3d1a;
|
|
233
|
+
background-color: #fff1f1;
|
|
234
|
+
}
|
|
235
|
+
.success {
|
|
236
|
+
border: dashed 2px #76b778;
|
|
237
|
+
background-color: #f1fff3;
|
|
238
|
+
}
|
|
239
|
+
</style>
|