fcad-core-dragon 2.0.0-beta.2 → 2.0.0-beta.4
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/.eslintrc.cjs +1 -1
- package/CHANGELOG +9 -0
- package/package.json +26 -12
- package/src/$locales/en.json +37 -87
- package/src/$locales/fr.json +17 -106
- package/src/assets/data/onboardingMessages.json +1 -1
- package/src/components/AppBase.vue +241 -143
- package/src/components/AppBaseButton.vue +2 -6
- package/src/components/AppBaseErrorDisplay.vue +193 -183
- package/src/components/AppBaseFlipCard.vue +1 -0
- package/src/components/AppBaseModule.vue +195 -225
- package/src/components/AppBasePage.vue +519 -64
- package/src/components/AppBasePopover.vue +41 -0
- package/src/components/AppCompAudio.vue +32 -64
- package/src/components/AppCompBranchButtons.vue +52 -71
- package/src/components/AppCompButtonProgress.vue +12 -18
- package/src/components/AppCompCarousel.vue +102 -0
- package/src/components/{AppCompInputCheckBox.vue → AppCompInputCheckBoxNext.vue} +56 -94
- package/src/components/AppCompInputDropdownNext.vue +159 -0
- package/src/components/{AppCompInputRadio.vue → AppCompInputRadioNext.vue} +53 -63
- package/src/components/AppCompInputTextNext.vue +106 -0
- package/src/components/AppCompInputTextTableNext.vue +141 -0
- package/src/components/AppCompInputTextToFillDropdownNext.vue +230 -0
- package/src/components/{AppCompInputTextToFillText.vue → AppCompInputTextToFillNext.vue} +71 -64
- package/src/components/AppCompJauge.vue +16 -9
- package/src/components/AppCompMenu.vue +50 -29
- package/src/components/AppCompMenuItem.vue +52 -15
- package/src/components/AppCompNavigation.vue +225 -211
- package/src/components/AppCompNoteCall.vue +22 -30
- package/src/components/AppCompNoteCredit.vue +45 -20
- package/src/components/AppCompPlayBar.vue +55 -108
- package/src/components/AppCompPlayBarNext.vue +2052 -0
- package/src/components/AppCompPlayBarProgress.vue +10 -1
- package/src/components/AppCompPopUpNext.vue +503 -0
- package/src/components/{AppCompQuiz.vue → AppCompQuizNext.vue} +632 -703
- package/src/components/AppCompQuizRecall.vue +74 -75
- package/src/components/{AppCompSVG.vue → AppCompSVGNext.vue} +111 -99
- package/src/components/AppCompSettingsMenu.vue +11 -8
- package/src/components/AppCompTableOfContent.vue +78 -76
- package/src/components/AppCompTranscript.vue +5 -0
- package/src/components/AppCompVideoPlayer.vue +30 -42
- package/src/components/BaseModule.vue +1 -0
- package/src/composables/useQuiz.js +206 -0
- package/src/externalComps/ModuleView.vue +22 -0
- package/src/externalComps/SummaryView.vue +91 -0
- package/src/main.js +99 -90
- package/src/mixins/$mediaMixins.js +13 -21
- package/src/mixins/timerMixin.js +1 -1
- package/src/module/stores/appStore.js +901 -0
- package/src/module/xapi/ADL.js +8 -4
- package/src/plugins/bus.js +7 -2
- package/src/plugins/gsap.js +4 -7
- package/src/plugins/helper.js +33 -13
- package/src/plugins/i18n.js +2 -2
- package/src/plugins/idb.js +44 -29
- package/src/plugins/save.js +1 -1
- package/src/plugins/scorm.js +2 -2
- package/src/plugins/xapi.js +2 -2
- package/src/public/index.html +22 -10
- package/src/router/index.js +13 -10
- package/src/router/routes.js +20 -25
- package/src/shared/generalfuncs.js +33 -18
- package/src/shared/validators.js +116 -6
- package/src/components/AppCompInputDropdown.vue +0 -182
- package/src/components/AppCompInputTextBox.vue +0 -91
- package/src/components/AppCompInputTextTable.vue +0 -158
- package/src/components/AppCompInputTextToFillDropdown.vue +0 -257
- package/src/components/AppCompPopUp.vue +0 -583
- package/src/components/AppCompPopover.vue +0 -27
- package/src/mixins/$pageMixins.js +0 -415
- package/src/mixins/$quizMixins.js +0 -442
- package/src/module/store.js +0 -1014
|
@@ -11,10 +11,13 @@
|
|
|
11
11
|
<div v-if="error" id="sidebar-submenu" :class="{ isOpen: open }">
|
|
12
12
|
<app-base-button
|
|
13
13
|
id="close-toc"
|
|
14
|
+
class="btn-ghost"
|
|
14
15
|
:title="$t('button.closePopUp')"
|
|
15
16
|
@click="close()"
|
|
16
17
|
>
|
|
17
|
-
|
|
18
|
+
<svg>
|
|
19
|
+
<use href="#close-square-icon" />
|
|
20
|
+
</svg>
|
|
18
21
|
</app-base-button>
|
|
19
22
|
|
|
20
23
|
<p class="t-act" v-html="title"></p>
|
|
@@ -29,7 +32,7 @@
|
|
|
29
32
|
<div class="box-anchor">
|
|
30
33
|
<p class="t-toc">{{ $t('text.toc') }}</p>
|
|
31
34
|
|
|
32
|
-
<
|
|
35
|
+
<a
|
|
33
36
|
v-for="(anchor, index) of anchors"
|
|
34
37
|
:key="anchor.title"
|
|
35
38
|
class="toc-item"
|
|
@@ -37,10 +40,20 @@
|
|
|
37
40
|
@click="closeAndNextPage(anchor.path)"
|
|
38
41
|
>
|
|
39
42
|
<div class="box-text-anchor">
|
|
40
|
-
<
|
|
41
|
-
|
|
43
|
+
<div class="text-anchor">
|
|
44
|
+
<p class="anchor-t" v-html="anchor.title"></p>
|
|
45
|
+
<p class="state">
|
|
46
|
+
<svg>
|
|
47
|
+
<use href="#check-toc" />
|
|
48
|
+
</svg>
|
|
49
|
+
{{ $t('text.complete') }}
|
|
50
|
+
</p>
|
|
51
|
+
</div>
|
|
52
|
+
<svg>
|
|
53
|
+
<use href="#chevronD-icon" />
|
|
54
|
+
</svg>
|
|
42
55
|
</div>
|
|
43
|
-
</
|
|
56
|
+
</a>
|
|
44
57
|
</div>
|
|
45
58
|
</div>
|
|
46
59
|
<div v-else id="sidebar-submenu" :class="{ isOpen: open }">
|
|
@@ -52,8 +65,8 @@
|
|
|
52
65
|
</template>
|
|
53
66
|
|
|
54
67
|
<script>
|
|
55
|
-
import {
|
|
56
|
-
|
|
68
|
+
import { mapState, mapActions } from 'pinia'
|
|
69
|
+
import { useAppStore } from '../module/stores/appStore'
|
|
57
70
|
export default {
|
|
58
71
|
data() {
|
|
59
72
|
return {
|
|
@@ -67,7 +80,7 @@ export default {
|
|
|
67
80
|
}
|
|
68
81
|
},
|
|
69
82
|
computed: {
|
|
70
|
-
...
|
|
83
|
+
...mapState(useAppStore, [
|
|
71
84
|
'getMenuSettings',
|
|
72
85
|
'getAnchorsForActivity',
|
|
73
86
|
'getBifChoice',
|
|
@@ -86,6 +99,7 @@ export default {
|
|
|
86
99
|
this.$bus.$on('info-activity', this.onInfoActivity)
|
|
87
100
|
},
|
|
88
101
|
methods: {
|
|
102
|
+
...mapActions(useAppStore, ['updateWidgetOpen']),
|
|
89
103
|
onInfoActivity(data) {
|
|
90
104
|
//should be condition to avoid event fireing multiple time on call
|
|
91
105
|
|
|
@@ -103,15 +117,15 @@ export default {
|
|
|
103
117
|
},
|
|
104
118
|
onCloseWidget(data) {
|
|
105
119
|
this.open = false
|
|
106
|
-
this
|
|
120
|
+
this.updateWidgetOpen(false)
|
|
107
121
|
this.reset()
|
|
108
122
|
},
|
|
109
123
|
onToggleWidget(data) {
|
|
110
124
|
if (data == 'toc') {
|
|
111
125
|
this.open = !this.open
|
|
112
|
-
this
|
|
126
|
+
this.updateWidgetOpen(true)
|
|
113
127
|
} else {
|
|
114
|
-
this
|
|
128
|
+
this.updateWidgetOpen(false)
|
|
115
129
|
this.open = false
|
|
116
130
|
}
|
|
117
131
|
},
|
|
@@ -133,17 +147,11 @@ export default {
|
|
|
133
147
|
nb = activity.substr(2)
|
|
134
148
|
else nb = activity.substr(1)
|
|
135
149
|
|
|
136
|
-
this.title = `${this.$t('text.activity')} ${nb} : ${
|
|
137
|
-
menuInfo[activity].subTitle
|
|
138
|
-
}`
|
|
139
|
-
|
|
140
|
-
let count = 0
|
|
150
|
+
this.title = `${this.$t('text.activity')} ${nb} : ${menuInfo[activity].subTitle}`
|
|
141
151
|
|
|
142
152
|
//create anchors title and path
|
|
143
153
|
if (menuInfo[activity] && menuInfo[activity].anchors) {
|
|
144
154
|
menuInfo[activity].anchors.forEach((element) => {
|
|
145
|
-
count++
|
|
146
|
-
|
|
147
155
|
//
|
|
148
156
|
let _path = null
|
|
149
157
|
let b = null
|
|
@@ -219,12 +227,12 @@ export default {
|
|
|
219
227
|
},
|
|
220
228
|
close() {
|
|
221
229
|
this.open = !this.open
|
|
222
|
-
this
|
|
230
|
+
this.updateWidgetOpen(this.open)
|
|
223
231
|
},
|
|
224
232
|
closeAndNextPage(NextPage) {
|
|
225
|
-
this.$router.push({ name: NextPage })
|
|
226
233
|
this.open = !this.open
|
|
227
|
-
this
|
|
234
|
+
this.updateWidgetOpen(this.open)
|
|
235
|
+
this.$router.push({ name: NextPage })
|
|
228
236
|
},
|
|
229
237
|
reset() {
|
|
230
238
|
this.anchors = []
|
|
@@ -292,33 +300,61 @@ export default {
|
|
|
292
300
|
position: absolute;
|
|
293
301
|
left: 75px;
|
|
294
302
|
top: 0;
|
|
303
|
+
max-height: 592px;
|
|
304
|
+
width: 476px;
|
|
295
305
|
transition: left 0.5s ease-in-out;
|
|
296
306
|
|
|
297
|
-
|
|
298
|
-
content: '';
|
|
307
|
+
&.isOpen {
|
|
299
308
|
display: block;
|
|
300
|
-
|
|
301
|
-
height: 0;
|
|
302
|
-
border-top: 10px solid transparent;
|
|
303
|
-
border-bottom: 10px solid transparent;
|
|
304
|
-
border-right: 10px solid;
|
|
309
|
+
}
|
|
305
310
|
|
|
311
|
+
#close-toc {
|
|
306
312
|
position: absolute;
|
|
307
|
-
|
|
308
|
-
|
|
313
|
+
right: 24px;
|
|
314
|
+
margin-bottom: 0;
|
|
315
|
+
padding: 11px;
|
|
316
|
+
width: 48px;
|
|
317
|
+
height: 48px;
|
|
318
|
+
display: flex;
|
|
319
|
+
justify-content: center;
|
|
320
|
+
|
|
321
|
+
&:focus {
|
|
322
|
+
box-shadow: inherit !important;
|
|
323
|
+
}
|
|
309
324
|
}
|
|
310
325
|
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
326
|
+
.box-prog-act {
|
|
327
|
+
width: 319px;
|
|
328
|
+
display: flex;
|
|
329
|
+
flex-direction: row;
|
|
330
|
+
margin-bottom: 16px;
|
|
331
|
+
|
|
332
|
+
p {
|
|
333
|
+
position: relative;
|
|
334
|
+
width: 100%;
|
|
314
335
|
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
336
|
+
span {
|
|
337
|
+
position: absolute;
|
|
338
|
+
right: 0;
|
|
339
|
+
top: 0;
|
|
340
|
+
}
|
|
341
|
+
}
|
|
318
342
|
}
|
|
319
343
|
|
|
320
344
|
.box-anchor {
|
|
345
|
+
max-height: 366px;
|
|
346
|
+
overflow-y: auto;
|
|
347
|
+
padding: 0 4px;
|
|
348
|
+
|
|
349
|
+
.t-toc {
|
|
350
|
+
margin-bottom: 16px;
|
|
351
|
+
}
|
|
352
|
+
|
|
321
353
|
.toc-item {
|
|
354
|
+
display: block;
|
|
355
|
+
width: 95%;
|
|
356
|
+
margin-bottom: 8px;
|
|
357
|
+
|
|
322
358
|
.state {
|
|
323
359
|
display: none;
|
|
324
360
|
}
|
|
@@ -327,52 +363,18 @@ export default {
|
|
|
327
363
|
display: block;
|
|
328
364
|
}
|
|
329
365
|
}
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
.box-time {
|
|
333
|
-
width: 100%;
|
|
334
|
-
padding: 10px 20px;
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
.box-contenu {
|
|
338
|
-
padding: 20px;
|
|
339
|
-
@media screen and (max-width: 1100px) {
|
|
340
|
-
padding: 0;
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
.box-ttl {
|
|
344
|
-
@media screen and (max-width: 1100px) {
|
|
345
|
-
padding: 15px 0px 10px 20px;
|
|
346
|
-
}
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
.container-anchor {
|
|
350
|
-
margin-top: 35px;
|
|
351
|
-
margin-left: 35px;
|
|
352
|
-
padding-left: 24px;
|
|
353
|
-
padding-top: 14px;
|
|
354
|
-
max-height: 75vh;
|
|
355
|
-
overflow-y: auto;
|
|
356
|
-
|
|
357
|
-
@media screen and (max-width: 1100px) {
|
|
358
|
-
padding: 0;
|
|
359
|
-
margin: 0;
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
.box-sa {
|
|
363
|
-
margin-bottom: 16px;
|
|
364
366
|
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
367
|
+
.box-text-anchor {
|
|
368
|
+
display: flex;
|
|
369
|
+
flex-direction: row;
|
|
370
|
+
align-items: center;
|
|
371
|
+
justify-content: space-between;
|
|
370
372
|
}
|
|
371
373
|
}
|
|
372
374
|
}
|
|
373
375
|
}
|
|
374
376
|
|
|
375
|
-
.
|
|
377
|
+
.app-nav {
|
|
376
378
|
&.show,
|
|
377
379
|
&:hover {
|
|
378
380
|
.ctn-w {
|
|
@@ -13,30 +13,13 @@
|
|
|
13
13
|
:class="[{ FS: fullScreen }, CCBrowser]"
|
|
14
14
|
aria-label="Video"
|
|
15
15
|
>
|
|
16
|
-
<
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
</div>
|
|
24
|
-
<div class="box">
|
|
25
|
-
<p>
|
|
26
|
-
Vous avez une/des erreur(s) pour la création de votre composant.
|
|
27
|
-
Veuillez corriger les erreurs ci-dessous:
|
|
28
|
-
<br />
|
|
29
|
-
</p>
|
|
30
|
-
<ul>
|
|
31
|
-
<li
|
|
32
|
-
v-for="(err, index) in hasErr"
|
|
33
|
-
:key="`error_type_${index}`"
|
|
34
|
-
v-html="err"
|
|
35
|
-
/>
|
|
36
|
-
</ul>
|
|
37
|
-
</div>
|
|
38
|
-
</b-col>
|
|
39
|
-
</b-row>
|
|
16
|
+
<app-base-error-display
|
|
17
|
+
v-if="hasErr.length"
|
|
18
|
+
:error-group="'component'"
|
|
19
|
+
:error-title="'ERREUR: COMPOSANT DE VIDEO'"
|
|
20
|
+
:errors-list="hasErr"
|
|
21
|
+
/>
|
|
22
|
+
|
|
40
23
|
<!------------------video section --------------------------->
|
|
41
24
|
|
|
42
25
|
<template v-else>
|
|
@@ -75,7 +58,7 @@
|
|
|
75
58
|
/>
|
|
76
59
|
</video>
|
|
77
60
|
</div>
|
|
78
|
-
<app-comp-play-bar
|
|
61
|
+
<app-comp-play-bar-next
|
|
79
62
|
v-if="$vidElement && !isLoading && !hasSourceLoadingError"
|
|
80
63
|
:ref="`plyr_${id}`"
|
|
81
64
|
:media-to-play="$vidElement"
|
|
@@ -86,10 +69,13 @@
|
|
|
86
69
|
</template>
|
|
87
70
|
|
|
88
71
|
<script>
|
|
89
|
-
import {
|
|
72
|
+
import { mapState, mapActions } from 'pinia'
|
|
73
|
+
import { useAppStore } from '../module/stores/appStore'
|
|
90
74
|
import { validateVideoData } from '../shared/validators'
|
|
75
|
+
import AppCompPlayBarNext from './AppCompPlayBarNext.vue'
|
|
91
76
|
|
|
92
77
|
export default {
|
|
78
|
+
components: { AppCompPlayBarNext },
|
|
93
79
|
props: {
|
|
94
80
|
vidData: {
|
|
95
81
|
type: Object,
|
|
@@ -122,7 +108,7 @@ export default {
|
|
|
122
108
|
}
|
|
123
109
|
},
|
|
124
110
|
computed: {
|
|
125
|
-
...
|
|
111
|
+
...mapState(useAppStore, ['getCurrentBrowser', 'getCurrentPage']),
|
|
126
112
|
//Return true if the video is loading (to show the loading display)
|
|
127
113
|
isLoading() {
|
|
128
114
|
if (!this.isSet && !this.hasSourceLoadingError) return true
|
|
@@ -168,6 +154,7 @@ export default {
|
|
|
168
154
|
},
|
|
169
155
|
|
|
170
156
|
methods: {
|
|
157
|
+
...mapActions(useAppStore, ['updateCurrentMediaElements']),
|
|
171
158
|
errorHandling(e) {
|
|
172
159
|
this.hasSourceLoadingError = true
|
|
173
160
|
},
|
|
@@ -190,12 +177,15 @@ export default {
|
|
|
190
177
|
*/
|
|
191
178
|
updateMediaData(e) {
|
|
192
179
|
//dispatch loading status of for this component
|
|
180
|
+
|
|
193
181
|
this.$bus.$emit('set-comp-status', 'AppCompMediaPlayer', 'loading')
|
|
194
182
|
this.$bus.$emit('update-media-duration')
|
|
195
183
|
//Should Check that the the media Element is unique im Media Liste
|
|
196
184
|
const { mElements } = this.getCurrentPage
|
|
197
185
|
|
|
198
|
-
const hasEntry = mElements.
|
|
186
|
+
const hasEntry = mElements.findLastIndex(
|
|
187
|
+
(media) => media.id === e.target.id
|
|
188
|
+
)
|
|
199
189
|
|
|
200
190
|
if (hasEntry !== -1) {
|
|
201
191
|
// Should report Error to Console and Component template about this media
|
|
@@ -210,7 +200,7 @@ export default {
|
|
|
210
200
|
return this.hasErr.push(errmsg)
|
|
211
201
|
}
|
|
212
202
|
|
|
213
|
-
this
|
|
203
|
+
this.updateCurrentMediaElements(e.target).then(() => {
|
|
214
204
|
this.isSet = true
|
|
215
205
|
this.$bus.$emit('set-comp-status', 'AppCompMediaPlayer', 'ready')
|
|
216
206
|
})
|
|
@@ -222,18 +212,17 @@ export default {
|
|
|
222
212
|
*/
|
|
223
213
|
runPlaybackAnimation() {
|
|
224
214
|
//this.isPlaying = !this.$vidElement.mElement.paused
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
)
|
|
236
|
-
animation.play()
|
|
215
|
+
// let animation = this.$gsap.fromTo(
|
|
216
|
+
// '.playback-animation',
|
|
217
|
+
// { opacity: 1, scale: 0.8 },
|
|
218
|
+
// {
|
|
219
|
+
// opacity: 0,
|
|
220
|
+
// scale: 1.3,
|
|
221
|
+
// duration: 0.8,
|
|
222
|
+
// ease: 'power2.out'
|
|
223
|
+
// }
|
|
224
|
+
// )
|
|
225
|
+
// animation.play()
|
|
237
226
|
},
|
|
238
227
|
|
|
239
228
|
/**
|
|
@@ -300,7 +289,6 @@ export default {
|
|
|
300
289
|
spaceKeyPreventDefault(evt) {
|
|
301
290
|
let { code } = evt
|
|
302
291
|
if (code == 'Space') {
|
|
303
|
-
//console.log('\x1b[43mspace i')
|
|
304
292
|
evt.preventDefault()
|
|
305
293
|
this.handlePlayBack('spacebar')
|
|
306
294
|
}
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
//This composable sould Extend the functionality of a the quiz
|
|
2
|
+
|
|
3
|
+
import i18n from '@/i18n' //Must import directly the local from project app because vue-18in does not work in legacy mode with composable
|
|
4
|
+
|
|
5
|
+
export function useQuiz(quiz) {
|
|
6
|
+
const { quizType, solution, showSolution, quizInputType } = quiz
|
|
7
|
+
const { t } = i18n.global
|
|
8
|
+
|
|
9
|
+
// /**
|
|
10
|
+
// * @param {String} inputId
|
|
11
|
+
// * @returns {Array} the class
|
|
12
|
+
// */
|
|
13
|
+
function classInput(inputId, optSelected = null) {
|
|
14
|
+
let theClass = []
|
|
15
|
+
|
|
16
|
+
switch (true) {
|
|
17
|
+
case ['choix_unique', 'reponse_ouverte'].includes(quizType.value):
|
|
18
|
+
if (inputId == quizInputType.value) {
|
|
19
|
+
theClass.push('reponseSelectionner')
|
|
20
|
+
}
|
|
21
|
+
break
|
|
22
|
+
|
|
23
|
+
case quizType.value == 'choix_mult':
|
|
24
|
+
if (containsValue(quizInputType.value, inputId)) {
|
|
25
|
+
theClass.push('reponseSelectionner')
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (showSolution.value) {
|
|
30
|
+
if (solution.value !== null) {
|
|
31
|
+
switch (true) {
|
|
32
|
+
case ['choix_unique', 'reponse_ouverte'].includes(quizType.value):
|
|
33
|
+
if (inputId == solution.value) {
|
|
34
|
+
theClass.push('correct_answer')
|
|
35
|
+
} else {
|
|
36
|
+
theClass.push('wrong_answer')
|
|
37
|
+
}
|
|
38
|
+
break
|
|
39
|
+
|
|
40
|
+
case quizType.value == 'choix_mult':
|
|
41
|
+
if (containsValue(solution.value, inputId)) {
|
|
42
|
+
theClass.push('correct_answer')
|
|
43
|
+
} else {
|
|
44
|
+
theClass.push('wrong_answer')
|
|
45
|
+
}
|
|
46
|
+
break
|
|
47
|
+
case quizType.value == 'dropdown':
|
|
48
|
+
if (!optSelected || !optSelected[inputId]) return
|
|
49
|
+
if (solution.value[inputId] == optSelected[inputId]) {
|
|
50
|
+
theClass.push('correct_answer')
|
|
51
|
+
} else {
|
|
52
|
+
theClass.push('wrong_answer')
|
|
53
|
+
}
|
|
54
|
+
break
|
|
55
|
+
|
|
56
|
+
case quizType.value == 'texte_troue_select':
|
|
57
|
+
if (typeof optSelected[inputId] !== 'undefined') {
|
|
58
|
+
if (
|
|
59
|
+
Object.values(solution.value[inputId])[0] ==
|
|
60
|
+
optSelected[inputId]
|
|
61
|
+
) {
|
|
62
|
+
theClass.push('correct_answer')
|
|
63
|
+
} else {
|
|
64
|
+
theClass.push('wrong_answer')
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
break
|
|
68
|
+
|
|
69
|
+
case quizType.value == 'texte_tableau':
|
|
70
|
+
if (
|
|
71
|
+
containsValue(
|
|
72
|
+
solution.value[inputId].reponse_value,
|
|
73
|
+
optSelected[inputId]
|
|
74
|
+
)
|
|
75
|
+
) {
|
|
76
|
+
theClass.push('correct_answer')
|
|
77
|
+
} else {
|
|
78
|
+
theClass.push('wrong_answer')
|
|
79
|
+
}
|
|
80
|
+
break
|
|
81
|
+
case quizType.value == 'texte_troue':
|
|
82
|
+
if (typeof optSelected[inputId] !== 'undefined') {
|
|
83
|
+
if (
|
|
84
|
+
containsValue(
|
|
85
|
+
Object.values(solution.value[inputId])[0],
|
|
86
|
+
optSelected[inputId]
|
|
87
|
+
)
|
|
88
|
+
) {
|
|
89
|
+
theClass.push('correct_answer')
|
|
90
|
+
} else {
|
|
91
|
+
theClass.push('wrong_answer')
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
break
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
return theClass
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function messageAccessibility(inputId, optSelected = null) {
|
|
102
|
+
let mess = ''
|
|
103
|
+
if (showSolution.value) {
|
|
104
|
+
if (solution.value !== null) {
|
|
105
|
+
switch (true) {
|
|
106
|
+
case ['choix_unique', 'reponse_ouverte'].includes(quizType.value):
|
|
107
|
+
if (inputId == solution.value) {
|
|
108
|
+
mess = `${t('quizState.goodAnswer')}`
|
|
109
|
+
} else {
|
|
110
|
+
mess = `${t('quizState.badAnswer')}`
|
|
111
|
+
}
|
|
112
|
+
break
|
|
113
|
+
|
|
114
|
+
case quizType.value == 'choix_mult':
|
|
115
|
+
if (containsValue(solution.value, inputId)) {
|
|
116
|
+
mess = `${t('quizState.goodAnswer')}`
|
|
117
|
+
} else {
|
|
118
|
+
mess = `${t('quizState.badAnswer')}`
|
|
119
|
+
}
|
|
120
|
+
break
|
|
121
|
+
case quizType.value == 'dropdown':
|
|
122
|
+
if (solution[inputId.value] == optSelected[inputId.value]) {
|
|
123
|
+
mess = `${t('quizState.goodAnswer')}`
|
|
124
|
+
} else {
|
|
125
|
+
mess = `${t('quizState.badAnswer')}`
|
|
126
|
+
}
|
|
127
|
+
break
|
|
128
|
+
|
|
129
|
+
case quizType.value == 'texte_troue_select':
|
|
130
|
+
if (typeof optSelected[inputId] !== 'undefined') {
|
|
131
|
+
if (
|
|
132
|
+
Object.values(solution.value[inputId])[0] ==
|
|
133
|
+
optSelected[inputId]
|
|
134
|
+
) {
|
|
135
|
+
mess = `${t('quizState.goodAnswer')}`
|
|
136
|
+
} else {
|
|
137
|
+
mess = `${t('quizState.badAnswer')}`
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
break
|
|
141
|
+
|
|
142
|
+
case quizType.value == 'texte_tableau':
|
|
143
|
+
if (
|
|
144
|
+
containsValue(
|
|
145
|
+
solution.value[inputId].reponse_value,
|
|
146
|
+
optSelected[inputId]
|
|
147
|
+
)
|
|
148
|
+
) {
|
|
149
|
+
mess = `${t('quizState.goodAnswer')}`
|
|
150
|
+
} else {
|
|
151
|
+
mess = `${t('quizState.badAnswer')}`
|
|
152
|
+
}
|
|
153
|
+
break
|
|
154
|
+
case quizType.value == 'texte_troue':
|
|
155
|
+
if (typeof optSelected[inputId] !== 'undefined') {
|
|
156
|
+
if (
|
|
157
|
+
containsValue(
|
|
158
|
+
Object.values(solution.value[inputId])[0],
|
|
159
|
+
optSelected[inputId]
|
|
160
|
+
)
|
|
161
|
+
) {
|
|
162
|
+
mess = `${t('quizState.goodAnswer')}`
|
|
163
|
+
} else {
|
|
164
|
+
mess = `${t('quizState.badAnswer')}`
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
break
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
return mess
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* @description check if a values exists in a array
|
|
176
|
+
* @param {Array} array
|
|
177
|
+
* @param value
|
|
178
|
+
* @returns {Boolean}
|
|
179
|
+
*/
|
|
180
|
+
function containsValue(array, value) {
|
|
181
|
+
return array.includes(value)
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* @description shuffles an array used to randomized the option order if shuffleAnswers is true
|
|
186
|
+
* @param {Array} array
|
|
187
|
+
* @returns {Array}
|
|
188
|
+
*/
|
|
189
|
+
function shuffleArray(array) {
|
|
190
|
+
let newArray = []
|
|
191
|
+
let newArray2 = []
|
|
192
|
+
|
|
193
|
+
for (let i = 0; i < array.length; i++) {
|
|
194
|
+
const element = array[i]
|
|
195
|
+
newArray.push(element)
|
|
196
|
+
}
|
|
197
|
+
while (newArray.length > 0) {
|
|
198
|
+
let pos = Math.floor(newArray.length * Math.random())
|
|
199
|
+
newArray2.push(newArray[pos])
|
|
200
|
+
newArray.splice(pos, 1)
|
|
201
|
+
}
|
|
202
|
+
return newArray2
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
return { containsValue, shuffleArray, classInput, messageAccessibility }
|
|
206
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<app-base-module :module-config="$data" />
|
|
3
|
+
</template>
|
|
4
|
+
|
|
5
|
+
<script>
|
|
6
|
+
export default {
|
|
7
|
+
data() {
|
|
8
|
+
return {
|
|
9
|
+
id: 'module_99',
|
|
10
|
+
consigneBehavior: 'onHover', //Controle the behavior of desplaying instruction
|
|
11
|
+
bookmarkActive: true, // Controle the use of saved point
|
|
12
|
+
allowNavigationToActivity: null
|
|
13
|
+
|
|
14
|
+
//main:''// Edit to define the ID of the node that will be main. When skipping to main content in the page.
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
created() {
|
|
18
|
+
this.allowNavigationToActivity =
|
|
19
|
+
this.$helper.getSettingsFromStore('auto_next_activity')
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
</script>
|