fcad-core-dragon 2.1.1 → 2.1.2
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/.editorconfig +7 -7
- package/.gitlab-ci.yml +124 -0
- package/.prettierrc +11 -11
- package/.vscode/extensions.json +8 -8
- package/.vscode/settings.json +46 -16
- package/CHANGELOG +520 -520
- package/README.md +57 -57
- package/documentation/.vitepress/config.js +114 -114
- package/documentation/api-examples.md +49 -49
- package/documentation/composants/app-base-button.md +58 -58
- package/documentation/composants/app-base-error-display.md +59 -59
- package/documentation/composants/app-base-popover.md +68 -68
- package/documentation/composants/app-comp-audio.md +75 -75
- package/documentation/composants/app-comp-branch-buttons.md +111 -111
- package/documentation/composants/app-comp-button-progress.md +53 -53
- package/documentation/composants/app-comp-carousel.md +53 -53
- package/documentation/composants/app-comp-container.md +53 -53
- package/documentation/composants/app-comp-input-checkbox-next.md +42 -42
- package/documentation/composants/app-comp-input-dropdown-next.md +34 -34
- package/documentation/composants/app-comp-input-radio-next.md +39 -39
- package/documentation/composants/app-comp-input-text-next.md +35 -35
- package/documentation/composants/app-comp-input-text-table-next.md +34 -34
- package/documentation/composants/app-comp-input-text-to-fill-dropdown-next.md +53 -53
- package/documentation/composants/app-comp-input-text-to-fill-next.md +31 -31
- package/documentation/composants/app-comp-jauge.md +31 -31
- package/documentation/composants/app-comp-menu-item.md +55 -55
- package/documentation/composants/app-comp-menu.md +29 -29
- package/documentation/composants/app-comp-navigation.md +41 -41
- package/documentation/composants/app-comp-note-call.md +53 -53
- package/documentation/composants/app-comp-note-credit.md +53 -53
- package/documentation/composants/app-comp-play-bar-next.md +53 -53
- package/documentation/composants/app-comp-pop-up-next.md +93 -93
- package/documentation/composants/app-comp-quiz-next.md +235 -235
- package/documentation/composants/app-comp-quiz-recall.md +53 -53
- package/documentation/composants/app-comp-svg-next.md +53 -53
- package/documentation/composants/app-comp-table-of-content.md +50 -50
- package/documentation/composants/app-comp-video-player.md +82 -82
- package/documentation/composants.md +46 -46
- package/documentation/composants_critiques/ModelPageComposant.md +53 -53
- package/documentation/composants_critiques/app-base-module.md +43 -43
- package/documentation/composants_critiques/app-base-page.md +48 -48
- package/documentation/composants_critiques/app-base.md +311 -311
- package/documentation/composants_critiques/main.md +15 -15
- package/documentation/demarrage.md +50 -50
- package/documentation/deploiement.md +57 -57
- package/documentation/index.md +33 -33
- package/documentation/markdown-examples.md +85 -85
- package/documentation/public/vite.svg +14 -14
- package/documentation/public/vuejs.svg +1 -1
- package/documentation/public/vuetify.svg +5 -5
- package/eslint.config.js +60 -60
- package/junit-report.xml +182 -0
- package/package.json +66 -59
- package/playwright/index.html +12 -0
- package/playwright/index.js +21 -0
- package/playwright-ct.config.js +95 -0
- package/src/$locales/en.json +157 -157
- package/src/$locales/fr.json +120 -120
- package/src/assets/data/onboardingMessages.json +47 -47
- package/src/components/AppBase.vue +1171 -1169
- package/src/components/AppBaseButton.vue +90 -95
- package/src/components/AppBaseErrorDisplay.vue +438 -438
- package/src/components/AppBaseFlipCard.vue +84 -84
- package/src/components/AppBaseModule.vue +1639 -1634
- package/src/components/AppBasePage.vue +867 -866
- package/src/components/AppBasePopover.vue +41 -41
- package/src/components/AppBaseSkeleton.vue +66 -66
- package/src/components/AppCompAudio.vue +261 -256
- package/src/components/AppCompBranchButtons.vue +508 -508
- package/src/components/AppCompButtonProgress.vue +137 -132
- package/src/components/AppCompCarousel.vue +342 -336
- package/src/components/AppCompContainer.vue +29 -29
- package/src/components/AppCompInputCheckBoxNx.vue +325 -323
- package/src/components/AppCompInputDropdownNx.vue +302 -299
- package/src/components/AppCompInputRadioNx.vue +287 -284
- package/src/components/AppCompInputTextNx.vue +156 -153
- package/src/components/AppCompInputTextTableNx.vue +205 -202
- package/src/components/AppCompInputTextToFillDropdownNx.vue +343 -340
- package/src/components/AppCompInputTextToFillNx.vue +316 -313
- package/src/components/AppCompJauge.vue +81 -81
- package/src/components/AppCompMenu.vue +6 -1
- package/src/components/AppCompMenuItem.vue +246 -240
- package/src/components/AppCompNavigation.vue +977 -972
- package/src/components/AppCompNoteCall.vue +167 -161
- package/src/components/AppCompNoteCredit.vue +496 -491
- package/src/components/AppCompPlayBarNext.vue +2290 -2288
- package/src/components/AppCompPopUpNext.vue +508 -504
- package/src/components/AppCompQuizNext.vue +515 -510
- package/src/components/AppCompQuizRecall.vue +355 -350
- package/src/components/AppCompSVGNext.vue +346 -346
- package/src/components/AppCompSettingsMenu.vue +177 -172
- package/src/components/AppCompTableOfContent.vue +433 -427
- package/src/components/AppCompVideoPlayer.vue +377 -377
- package/src/components/AppCompViewDisplay.vue +6 -6
- package/src/components/BaseModule.vue +55 -55
- package/src/composables/useIdleDetector.js +56 -56
- package/src/composables/useQuiz.js +89 -89
- package/src/composables/useTimer.js +172 -172
- package/src/directives/nvdaFix.js +53 -53
- package/src/externalComps/ModuleView.vue +22 -22
- package/src/externalComps/SummaryView.vue +91 -91
- package/src/main.js +493 -476
- package/src/module/stores/appStore.js +960 -947
- package/src/module/xapi/ADL.js +520 -520
- package/src/module/xapi/Crypto/Hasher.js +241 -241
- package/src/module/xapi/Crypto/WordArray.js +278 -278
- package/src/module/xapi/Crypto/algorithms/BufferedBlockAlgorithm.js +103 -103
- package/src/module/xapi/Crypto/algorithms/C_algo.js +315 -315
- package/src/module/xapi/Crypto/algorithms/HMAC.js +9 -9
- package/src/module/xapi/Crypto/algorithms/SHA1.js +9 -9
- package/src/module/xapi/Crypto/encoders/Base.js +105 -105
- package/src/module/xapi/Crypto/encoders/Base64.js +99 -99
- package/src/module/xapi/Crypto/encoders/Hex.js +61 -61
- package/src/module/xapi/Crypto/encoders/Latin1.js +61 -61
- package/src/module/xapi/Crypto/encoders/Utf8.js +45 -45
- package/src/module/xapi/Crypto/index.js +53 -53
- package/src/module/xapi/Statement/activity.js +47 -47
- package/src/module/xapi/Statement/agent.js +55 -55
- package/src/module/xapi/Statement/group.js +26 -26
- package/src/module/xapi/Statement/index.js +259 -259
- package/src/module/xapi/Statement/statement.js +253 -253
- package/src/module/xapi/Statement/statementRef.js +23 -23
- package/src/module/xapi/Statement/substatement.js +22 -22
- package/src/module/xapi/Statement/verb.js +36 -36
- package/src/module/xapi/activitytypes.js +17 -17
- package/src/module/xapi/launch.js +157 -157
- package/src/module/xapi/utils.js +167 -167
- package/src/module/xapi/verbs.js +294 -294
- package/src/module/xapi/wrapper.js +1895 -1895
- package/src/module/xapi/xapiStatement.js +444 -444
- package/src/plugins/analytics.js +34 -34
- package/src/plugins/bus.js +12 -8
- package/src/plugins/gsap.js +17 -17
- package/src/plugins/helper.js +355 -358
- package/src/plugins/i18n.js +27 -26
- package/src/plugins/idb.js +227 -227
- package/src/plugins/save.js +37 -37
- package/src/plugins/scorm.js +287 -287
- package/src/plugins/xapi.js +11 -11
- package/src/public/index.html +33 -33
- package/src/router/index.js +57 -57
- package/src/router/routes.js +312 -312
- package/src/shared/generalfuncs.js +344 -344
- package/src/shared/validators.js +1018 -1018
- package/tests/component/AppBaseButton.spec.js +53 -0
- package/tests/component/pinia.spec.js +24 -0
- package/{src/components/tests__ → tests/unit}/AppBaseButton.spec.js +53 -53
- package/tests/unit/AppCompInputCheckBoxNx.spec.js +59 -0
- package/tests/unit/AppCompInputDropdownNx.spec.js +51 -0
- package/tests/unit/AppCompInputRadioNx.spec.js +59 -0
- package/tests/unit/AppCompInputTextNx.spec.js +44 -0
- package/tests/unit/AppCompInputTextTableNx.spec.js +77 -0
- package/tests/unit/AppCompInputTextToFillDropdownNx.spec.js +60 -0
- package/tests/unit/AppCompInputTextToFillNx.spec.js +45 -0
- package/tests/unit/AppCompQuizNext.spec.js +114 -0
- package/tests/unit/AppCompVideoPlayer.spec.js +177 -0
- package/{src/components/tests__ → tests/unit}/useTimer.spec.js +91 -91
- package/vitest.config.js +28 -19
- package/vitest.setup.js +28 -0
- package/src/components/AppBaseButton.test.js +0 -21
|
@@ -1,350 +1,355 @@
|
|
|
1
|
-
<!--
|
|
2
|
-
@ Description: This component is used to display a quiz and its answer from a previous page if it has been completed by the user. The only quiz type supported is open answer (textarea) and the quiz must be in the same lesson.
|
|
3
|
-
@ What it does: Retrieve the quizData specific to an activity ID and pageID. Then, retrieve the answers previously saved by the user to this quiz. After, create an html element including title and conditional content. If the answer have been previously saved, a specific hypertext, the question and the answer (disabled textarea) are displayed. If the answer have not been saved, another hypertext is displayed.
|
|
4
|
-
@How to use: in a page call <app-comp-quiz-recall :quiz-recall-data="defineDQuizRecallData">
|
|
5
|
-
** where "defineDQuizRecallData" refers to data object of quiz to pass to component
|
|
6
|
-
** data object should containt following attributes: quizId,activityId,pageId,hypertext_done',hypertext_undone,title,titletag
|
|
7
|
-
-->
|
|
8
|
-
<template>
|
|
9
|
-
<section v-if="quizRecallData" class="quizRecall">
|
|
10
|
-
<!--Optionnal title, out of quiz-answer-conditionning, default tag H4, but can be change by user-->
|
|
11
|
-
<!--Show skeleton while app data is not ready-->
|
|
12
|
-
<template v-if="!isReady">
|
|
13
|
-
<app-base-skeleton :skeleton-text="''" :skeleton-type="`quiz-recall`" />
|
|
14
|
-
</template>
|
|
15
|
-
<!--Show app data when ready-->
|
|
16
|
-
<template v-else>
|
|
17
|
-
<component
|
|
18
|
-
:is="quizRecall.titletag"
|
|
19
|
-
v-if="quizRecall.title"
|
|
20
|
-
class="quizRecall-title"
|
|
21
|
-
>
|
|
22
|
-
{{ quizRecall.title }}
|
|
23
|
-
</component>
|
|
24
|
-
<!--Quiz answer conditionning-->
|
|
25
|
-
<app-base-error-display
|
|
26
|
-
v-if="hasError.length"
|
|
27
|
-
:error-group="'component'"
|
|
28
|
-
:error-title="`ERREUR: COMPOSANT QUIZ RECALL`"
|
|
29
|
-
:errors-list="hasError"
|
|
30
|
-
></app-base-error-display>
|
|
31
|
-
<template v-else>
|
|
32
|
-
<template v-if="quizRecall.done == true">
|
|
33
|
-
<div
|
|
34
|
-
v-if="quizRecall.hypertext_done"
|
|
35
|
-
class="quizRecall-text-done"
|
|
36
|
-
v-html="quizRecall.hypertext_done"
|
|
37
|
-
></div>
|
|
38
|
-
<div class="quizRecall-ennonce" v-html="quizRecall.ennonce"></div>
|
|
39
|
-
|
|
40
|
-
<textarea
|
|
41
|
-
:id="`quizRecall-answer-${quizRecallData.quizId}`"
|
|
42
|
-
v-model="quizRecall.answer"
|
|
43
|
-
disabled
|
|
44
|
-
class="form-control"
|
|
45
|
-
></textarea>
|
|
46
|
-
</template>
|
|
47
|
-
<template v-if="quizRecall.done == false">
|
|
48
|
-
<div
|
|
49
|
-
v-if="quizRecall.hypertext_undone"
|
|
50
|
-
class="quizRecall-text-undone"
|
|
51
|
-
v-html="quizRecall.hypertext_undone"
|
|
52
|
-
></div>
|
|
53
|
-
</template>
|
|
54
|
-
</template>
|
|
55
|
-
</template>
|
|
56
|
-
</section>
|
|
57
|
-
</template>
|
|
58
|
-
|
|
59
|
-
<script>
|
|
60
|
-
//Recall mixins has the necessary datas and functions to give back quizRecall statu
|
|
61
|
-
import { mapState } from 'pinia'
|
|
62
|
-
import { useAppStore } from '../module/stores/appStore'
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
//
|
|
129
|
-
if (
|
|
130
|
-
this.
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
searchObject[property].constructor
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
//
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
this.
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
this.
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
this.quizRecall.
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
let
|
|
261
|
-
let
|
|
262
|
-
|
|
263
|
-
//
|
|
264
|
-
|
|
265
|
-
let
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
1
|
+
<!--
|
|
2
|
+
@ Description: This component is used to display a quiz and its answer from a previous page if it has been completed by the user. The only quiz type supported is open answer (textarea) and the quiz must be in the same lesson.
|
|
3
|
+
@ What it does: Retrieve the quizData specific to an activity ID and pageID. Then, retrieve the answers previously saved by the user to this quiz. After, create an html element including title and conditional content. If the answer have been previously saved, a specific hypertext, the question and the answer (disabled textarea) are displayed. If the answer have not been saved, another hypertext is displayed.
|
|
4
|
+
@How to use: in a page call <app-comp-quiz-recall :quiz-recall-data="defineDQuizRecallData">
|
|
5
|
+
** where "defineDQuizRecallData" refers to data object of quiz to pass to component
|
|
6
|
+
** data object should containt following attributes: quizId,activityId,pageId,hypertext_done',hypertext_undone,title,titletag
|
|
7
|
+
-->
|
|
8
|
+
<template>
|
|
9
|
+
<section v-if="quizRecallData" class="quizRecall">
|
|
10
|
+
<!--Optionnal title, out of quiz-answer-conditionning, default tag H4, but can be change by user-->
|
|
11
|
+
<!--Show skeleton while app data is not ready-->
|
|
12
|
+
<template v-if="!isReady">
|
|
13
|
+
<app-base-skeleton :skeleton-text="''" :skeleton-type="`quiz-recall`" />
|
|
14
|
+
</template>
|
|
15
|
+
<!--Show app data when ready-->
|
|
16
|
+
<template v-else>
|
|
17
|
+
<component
|
|
18
|
+
:is="quizRecall.titletag"
|
|
19
|
+
v-if="quizRecall.title"
|
|
20
|
+
class="quizRecall-title"
|
|
21
|
+
>
|
|
22
|
+
{{ quizRecall.title }}
|
|
23
|
+
</component>
|
|
24
|
+
<!--Quiz answer conditionning-->
|
|
25
|
+
<app-base-error-display
|
|
26
|
+
v-if="hasError.length"
|
|
27
|
+
:error-group="'component'"
|
|
28
|
+
:error-title="`ERREUR: COMPOSANT QUIZ RECALL`"
|
|
29
|
+
:errors-list="hasError"
|
|
30
|
+
></app-base-error-display>
|
|
31
|
+
<template v-else>
|
|
32
|
+
<template v-if="quizRecall.done == true">
|
|
33
|
+
<div
|
|
34
|
+
v-if="quizRecall.hypertext_done"
|
|
35
|
+
class="quizRecall-text-done"
|
|
36
|
+
v-html="quizRecall.hypertext_done"
|
|
37
|
+
></div>
|
|
38
|
+
<div class="quizRecall-ennonce" v-html="quizRecall.ennonce"></div>
|
|
39
|
+
|
|
40
|
+
<textarea
|
|
41
|
+
:id="`quizRecall-answer-${quizRecallData.quizId}`"
|
|
42
|
+
v-model="quizRecall.answer"
|
|
43
|
+
disabled
|
|
44
|
+
class="form-control"
|
|
45
|
+
></textarea>
|
|
46
|
+
</template>
|
|
47
|
+
<template v-if="quizRecall.done == false">
|
|
48
|
+
<div
|
|
49
|
+
v-if="quizRecall.hypertext_undone"
|
|
50
|
+
class="quizRecall-text-undone"
|
|
51
|
+
v-html="quizRecall.hypertext_undone"
|
|
52
|
+
></div>
|
|
53
|
+
</template>
|
|
54
|
+
</template>
|
|
55
|
+
</template>
|
|
56
|
+
</section>
|
|
57
|
+
</template>
|
|
58
|
+
|
|
59
|
+
<script>
|
|
60
|
+
//Recall mixins has the necessary datas and functions to give back quizRecall statu
|
|
61
|
+
import { mapState } from 'pinia'
|
|
62
|
+
import { useAppStore } from '../module/stores/appStore'
|
|
63
|
+
import { useI18n } from 'vue-i18n'
|
|
64
|
+
|
|
65
|
+
export default {
|
|
66
|
+
name: 'AppCompQuizRecall',
|
|
67
|
+
props: {
|
|
68
|
+
quizRecallData: { type: Object, required: true } //{activityId,pageId,hypertext_done,hypertext_undone,title, titletag}
|
|
69
|
+
},
|
|
70
|
+
setup() {
|
|
71
|
+
const { t } = useI18n()
|
|
72
|
+
return { t }
|
|
73
|
+
},
|
|
74
|
+
data() {
|
|
75
|
+
return {
|
|
76
|
+
quizRecall: {
|
|
77
|
+
done: false,
|
|
78
|
+
answer: '',
|
|
79
|
+
ennonce: '',
|
|
80
|
+
title: '',
|
|
81
|
+
titletag: 'h4',
|
|
82
|
+
hypertext_done: `<p>${this.$t('message.recall_done')}</p>` /*String traduite par défaut*/,
|
|
83
|
+
hypertext_undone: `<p>${this.$t(
|
|
84
|
+
'message.recall_undone'
|
|
85
|
+
)}</p>` /*String traduite par défaut*/
|
|
86
|
+
},
|
|
87
|
+
hasError: [],
|
|
88
|
+
quizData: null,
|
|
89
|
+
isReady: false //Used to display skeleton while app data is not ready
|
|
90
|
+
}
|
|
91
|
+
},
|
|
92
|
+
computed: {
|
|
93
|
+
...mapState(useAppStore, [
|
|
94
|
+
'getAllCompleted',
|
|
95
|
+
'getUserInteraction',
|
|
96
|
+
'getPageInteraction',
|
|
97
|
+
'getAppStatus',
|
|
98
|
+
'getPageData'
|
|
99
|
+
])
|
|
100
|
+
},
|
|
101
|
+
|
|
102
|
+
watch: {
|
|
103
|
+
//Watch for user interaction change to get quizRecall answer
|
|
104
|
+
getUserInteraction: {
|
|
105
|
+
async handler(newValue) {
|
|
106
|
+
if (!this.getUserInteraction) return
|
|
107
|
+
|
|
108
|
+
const { activityId, pageId } = this.quizRecallData
|
|
109
|
+
const interaction = this.getPageInteraction(
|
|
110
|
+
activityId,
|
|
111
|
+
pageId
|
|
112
|
+
).userInteraction
|
|
113
|
+
|
|
114
|
+
if (!interaction) return
|
|
115
|
+
//Get quizRecall answer
|
|
116
|
+
if (this.quizRecallData && this.quizData) {
|
|
117
|
+
await this.getQuizRecallAnswer(interaction)
|
|
118
|
+
} else {
|
|
119
|
+
this.quizRecall.done == false
|
|
120
|
+
}
|
|
121
|
+
},
|
|
122
|
+
immediate: true,
|
|
123
|
+
deep: true
|
|
124
|
+
}
|
|
125
|
+
},
|
|
126
|
+
created() {
|
|
127
|
+
//Validate quizRecall data
|
|
128
|
+
//(no validation to the quiz, only to the new datas)
|
|
129
|
+
if (import.meta.env.DEV) {
|
|
130
|
+
this.validateQuizRecallData(this.quizRecallData)
|
|
131
|
+
}
|
|
132
|
+
const { activityId, pageId } = this.quizRecallData
|
|
133
|
+
//Get quizData and validate the quiz type
|
|
134
|
+
if (activityId && pageId) {
|
|
135
|
+
this.getQuizData(activityId, pageId)
|
|
136
|
+
}
|
|
137
|
+
},
|
|
138
|
+
methods: {
|
|
139
|
+
/**
|
|
140
|
+
* @description Finds a reponse_ouverte quiz data with specified ID
|
|
141
|
+
* @param {Object} searchObject Object that will be iterated over to find the quiz data (The page "data" object)
|
|
142
|
+
* @param {String} quizID ID of the quiz we are looking for
|
|
143
|
+
*/
|
|
144
|
+
findQuizdataObject(searchObject, quizID) {
|
|
145
|
+
for (let property in searchObject) {
|
|
146
|
+
//Should only check for not null poperties
|
|
147
|
+
if (!searchObject[property]) continue
|
|
148
|
+
|
|
149
|
+
// Should only check for Object or Array property
|
|
150
|
+
if (
|
|
151
|
+
searchObject[property].constructor !== Object &&
|
|
152
|
+
searchObject[property].constructor !== Array
|
|
153
|
+
)
|
|
154
|
+
continue
|
|
155
|
+
|
|
156
|
+
if (
|
|
157
|
+
searchObject[property].constructor == Array &&
|
|
158
|
+
searchObject[property][0].constructor !== Object
|
|
159
|
+
)
|
|
160
|
+
continue
|
|
161
|
+
|
|
162
|
+
// Convert if it not an Array but an Objet
|
|
163
|
+
const searchArray =
|
|
164
|
+
searchObject[property].constructor === Object
|
|
165
|
+
? [searchObject[property]]
|
|
166
|
+
: searchObject[property]
|
|
167
|
+
//Only Search for quiz:
|
|
168
|
+
//Search Array is a list of quiz if one of its element has at least the property 'type_question'
|
|
169
|
+
return searchArray[0]['type_question']
|
|
170
|
+
? searchArray.find(
|
|
171
|
+
(e) => e.id === quizID && e.type_question === 'reponse_ouverte'
|
|
172
|
+
)
|
|
173
|
+
: null
|
|
174
|
+
}
|
|
175
|
+
},
|
|
176
|
+
//Get datas from the original open answer quiz
|
|
177
|
+
getQuizData(activityId, pageId) {
|
|
178
|
+
if (pageId && activityId) {
|
|
179
|
+
let pageData = this.getPageData(activityId, pageId)
|
|
180
|
+
|
|
181
|
+
if (pageData) {
|
|
182
|
+
this.quizData = this.findQuizdataObject(
|
|
183
|
+
pageData,
|
|
184
|
+
this.quizRecallData.quizId
|
|
185
|
+
)
|
|
186
|
+
|
|
187
|
+
//Warn that the specified quiz could not be found
|
|
188
|
+
if (!this.quizData) {
|
|
189
|
+
let msgErr = `Aucun quiz avec id '${this.quizRecallData.quizId}' pour la ${pageId} de ${activityId}`
|
|
190
|
+
console.warn(
|
|
191
|
+
`%c WARNING!>>> Quiz Recall: Unable to find a quiz with type_question 'reponse_ouverte' and id '${this.quizRecallData.quizId}' in ${pageId} of ${activityId}`,
|
|
192
|
+
'background: orange; color: white; display: block; margin:5px;'
|
|
193
|
+
)
|
|
194
|
+
this.hasError.push(msgErr)
|
|
195
|
+
}
|
|
196
|
+
} else {
|
|
197
|
+
this.quizRecall.done == false
|
|
198
|
+
let msgErr = `Aucun quiz avec id '${this.quizRecallData.quizId}' pour la ${pageId} de ${activityId}`
|
|
199
|
+
console.warn(
|
|
200
|
+
`%c WARNING!>>> AppCompQuizRecall : QuizData ActivityID and PageID combinaison is invalid.`,
|
|
201
|
+
'background: orange; color: white; display: block; margin:5px;'
|
|
202
|
+
)
|
|
203
|
+
this.hasError.push(msgErr)
|
|
204
|
+
}
|
|
205
|
+
} else {
|
|
206
|
+
this.quizRecall.done == false
|
|
207
|
+
}
|
|
208
|
+
},
|
|
209
|
+
//Get datas from quizRecallData and userData and add them to quizRecall object
|
|
210
|
+
async getQuizRecallAnswer(userData) {
|
|
211
|
+
await this.$nextTick() //wait for the DOM to update
|
|
212
|
+
const { quizId, hypertext_done, hypertext_undone, title, titletag } =
|
|
213
|
+
this.quizRecallData
|
|
214
|
+
|
|
215
|
+
//Add hypertext_done and undone to quizRecall
|
|
216
|
+
if (hypertext_done) {
|
|
217
|
+
this.quizRecall.hypertext_done = hypertext_done
|
|
218
|
+
}
|
|
219
|
+
if (hypertext_undone) {
|
|
220
|
+
this.quizRecall.hypertext_undone = hypertext_undone
|
|
221
|
+
}
|
|
222
|
+
//Add the title if it exists
|
|
223
|
+
if (title) {
|
|
224
|
+
this.quizRecall.title = title
|
|
225
|
+
//Modify le titletag
|
|
226
|
+
if (titletag) {
|
|
227
|
+
let validator = this.validateTitleTag(titletag)
|
|
228
|
+
if (validator) {
|
|
229
|
+
this.quizRecall.titletag = titletag
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
//Get the quiz answers from userData
|
|
234
|
+
const answers = userData.quizAnswers || {}
|
|
235
|
+
let quizAnswer = answers[quizId] || null
|
|
236
|
+
|
|
237
|
+
//If quiz answer exists in userData, quizRecall done is true and add the quiz answer to quizRecall
|
|
238
|
+
quizAnswer
|
|
239
|
+
? (this.quizRecall.done = true)
|
|
240
|
+
: (this.quizRecall.done = false)
|
|
241
|
+
|
|
242
|
+
if (quizAnswer) {
|
|
243
|
+
this.quizRecall.answer = quizAnswer.value[0].filled || ''
|
|
244
|
+
this.quizRecall.ennonce = this.quizData.ennonce
|
|
245
|
+
}
|
|
246
|
+
this.quizRecall
|
|
247
|
+
this.isReady = true //Set isReady to true to display the component
|
|
248
|
+
},
|
|
249
|
+
|
|
250
|
+
//Validate quizRecallData
|
|
251
|
+
/*Validate if the required properties are present in the object and that there is not invalid properties */
|
|
252
|
+
validateQuizRecallData(value) {
|
|
253
|
+
let requiredProperties = [
|
|
254
|
+
'quizId',
|
|
255
|
+
'activityId',
|
|
256
|
+
'pageId',
|
|
257
|
+
'hypertext_done',
|
|
258
|
+
'hypertext_undone'
|
|
259
|
+
]
|
|
260
|
+
let optionalProperties = ['title', 'titletag']
|
|
261
|
+
let allProperties = requiredProperties.concat(optionalProperties)
|
|
262
|
+
|
|
263
|
+
//Verify if the properties are valid
|
|
264
|
+
let recallDataProperties = Object.keys(value)
|
|
265
|
+
let wrongProperties = []
|
|
266
|
+
let missingRequired = []
|
|
267
|
+
|
|
268
|
+
//Get all the invalids properties from recallQuizData
|
|
269
|
+
/*Add element from target array that are NOT in arr to the wrongArray*/
|
|
270
|
+
let checkerWrong = (arr, target, wrongArray) =>
|
|
271
|
+
target.every((v) => {
|
|
272
|
+
if (arr.includes(v)) {
|
|
273
|
+
return true
|
|
274
|
+
} else {
|
|
275
|
+
wrongArray.push(v)
|
|
276
|
+
return true
|
|
277
|
+
}
|
|
278
|
+
})
|
|
279
|
+
//Get all the required properties that are missing from recallQuizData
|
|
280
|
+
/*Add element from the arr that are NOT in target arr to the missingArray*/
|
|
281
|
+
|
|
282
|
+
let checkerMissing = (arr, target, missingArray) =>
|
|
283
|
+
arr.every((v) => {
|
|
284
|
+
if (target.includes(v)) {
|
|
285
|
+
return true
|
|
286
|
+
} else {
|
|
287
|
+
missingArray.push(v)
|
|
288
|
+
return true
|
|
289
|
+
}
|
|
290
|
+
})
|
|
291
|
+
|
|
292
|
+
checkerWrong(allProperties, recallDataProperties, wrongProperties)
|
|
293
|
+
checkerMissing(requiredProperties, recallDataProperties, missingRequired)
|
|
294
|
+
|
|
295
|
+
//Validate if all properties in quizRecallData are valid
|
|
296
|
+
if (wrongProperties.length > 0) {
|
|
297
|
+
let msgErr = `QuizRecallData ${wrongProperties} invalid`
|
|
298
|
+
console.warn(
|
|
299
|
+
`%c WARNING!>>> AppCompQuizRecall : ${msgErr}. Required properties: ${requiredProperties} . Optional properties: ${optionalProperties}`,
|
|
300
|
+
'background: orange; color: white; display: block; margin:5px;'
|
|
301
|
+
)
|
|
302
|
+
this.hasError.push(msgErr)
|
|
303
|
+
}
|
|
304
|
+
//Validate if all required properties are present in quizRecallData
|
|
305
|
+
if (missingRequired.length > 0) {
|
|
306
|
+
let msgErr = `QuizRecallData missing required ${missingRequired} property`
|
|
307
|
+
console.warn(
|
|
308
|
+
`%c WARNING!>>> AppCompQuizRecall : ${msgErr}. Required properties: activityId and pageId. Optional properties: title, titletag, hypertext_done and hypertext_undone.`,
|
|
309
|
+
'background: orange; color: white; display: block; margin:5px;'
|
|
310
|
+
)
|
|
311
|
+
this.hasError.push(msgErr)
|
|
312
|
+
}
|
|
313
|
+
},
|
|
314
|
+
/*Get a title tag (string). Return true if the tag is valid and false is it's not*/
|
|
315
|
+
|
|
316
|
+
validateTitleTag(value) {
|
|
317
|
+
let tags = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'p', 'span']
|
|
318
|
+
let lowerValue = value.toLowerCase()
|
|
319
|
+
if (tags && value && tags.find((element) => element == lowerValue))
|
|
320
|
+
return true
|
|
321
|
+
else {
|
|
322
|
+
let msgErr = `Your quizRecallData titletag is not valid`
|
|
323
|
+
console.warn(
|
|
324
|
+
'%c WARNING!>>> AppCompQuizRecall : Your quizRecallData titletag is not valid. You can use h1,h2,h3,h4,h5,h6,p,or span',
|
|
325
|
+
'background: orange; color: white; display: block; margin:5px;'
|
|
326
|
+
)
|
|
327
|
+
this.hasError.push(msgErr)
|
|
328
|
+
return false
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
</script>
|
|
334
|
+
|
|
335
|
+
<style>
|
|
336
|
+
.skeleton {
|
|
337
|
+
height: 20px;
|
|
338
|
+
width: 200px;
|
|
339
|
+
background-color: #ccc;
|
|
340
|
+
border-radius: 4px;
|
|
341
|
+
animation: pulse 1.5s infinite ease-in-out;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
@keyframes pulse {
|
|
345
|
+
0% {
|
|
346
|
+
opacity: 1;
|
|
347
|
+
}
|
|
348
|
+
50% {
|
|
349
|
+
opacity: 0.4;
|
|
350
|
+
}
|
|
351
|
+
100% {
|
|
352
|
+
opacity: 1;
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
</style>
|