fcad-core-dragon 2.0.0-beta.3 → 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.
Files changed (95) hide show
  1. package/.editorconfig +33 -33
  2. package/.eslintignore +29 -29
  3. package/.eslintrc.cjs +81 -81
  4. package/CHANGELOG +373 -364
  5. package/README.md +71 -71
  6. package/bk.scss +117 -117
  7. package/package.json +61 -61
  8. package/src/$locales/en.json +143 -143
  9. package/src/$locales/fr.json +105 -105
  10. package/src/assets/data/onboardingMessages.json +47 -47
  11. package/src/components/AppBase.vue +1147 -1054
  12. package/src/components/AppBaseButton.vue +87 -87
  13. package/src/components/AppBaseErrorDisplay.vue +438 -438
  14. package/src/components/AppBaseFlipCard.vue +84 -84
  15. package/src/components/AppBaseModule.vue +1636 -1673
  16. package/src/components/AppBasePage.vue +779 -779
  17. package/src/components/AppBasePopover.vue +41 -41
  18. package/src/components/AppCompAudio.vue +234 -234
  19. package/src/components/AppCompBranchButtons.vue +552 -552
  20. package/src/components/AppCompButtonProgress.vue +126 -126
  21. package/src/components/AppCompCarousel.vue +298 -298
  22. package/src/components/AppCompInputCheckBoxNext.vue +195 -195
  23. package/src/components/AppCompInputDropdownNext.vue +159 -159
  24. package/src/components/AppCompInputRadioNext.vue +152 -152
  25. package/src/components/AppCompInputTextNext.vue +106 -106
  26. package/src/components/AppCompInputTextTableNext.vue +141 -141
  27. package/src/components/AppCompInputTextToFillDropdownNext.vue +230 -230
  28. package/src/components/AppCompInputTextToFillNext.vue +171 -171
  29. package/src/components/AppCompJauge.vue +74 -74
  30. package/src/components/AppCompMenu.vue +423 -413
  31. package/src/components/AppCompMenuItem.vue +228 -228
  32. package/src/components/AppCompNavigation.vue +959 -960
  33. package/src/components/AppCompNoteCall.vue +133 -133
  34. package/src/components/AppCompNoteCredit.vue +292 -292
  35. package/src/components/AppCompPlayBar.vue +1218 -1218
  36. package/src/components/AppCompPlayBarNext.vue +2052 -2052
  37. package/src/components/AppCompPlayBarProgress.vue +82 -82
  38. package/src/components/AppCompPopUpNext.vue +503 -503
  39. package/src/components/AppCompQuizNext.vue +2904 -2904
  40. package/src/components/AppCompQuizRecall.vue +276 -276
  41. package/src/components/AppCompSVGNext.vue +347 -347
  42. package/src/components/AppCompSettingsMenu.vue +172 -172
  43. package/src/components/AppCompTableOfContent.vue +387 -387
  44. package/src/components/AppCompTranscript.vue +24 -24
  45. package/src/components/AppCompVideoPlayer.vue +368 -368
  46. package/src/components/AppCompViewDisplay.vue +6 -6
  47. package/src/components/BaseModule.vue +72 -72
  48. package/src/composables/useQuiz.js +206 -206
  49. package/src/externalComps/ModuleView.vue +22 -22
  50. package/src/externalComps/SummaryView.vue +91 -91
  51. package/src/main.js +272 -272
  52. package/src/mixins/$mediaMixins.js +819 -819
  53. package/src/mixins/timerMixin.js +155 -155
  54. package/src/module/stores/appStore.js +901 -893
  55. package/src/module/xapi/ADL.js +380 -376
  56. package/src/module/xapi/Crypto/Hasher.js +241 -241
  57. package/src/module/xapi/Crypto/WordArray.js +278 -278
  58. package/src/module/xapi/Crypto/algorithms/BufferedBlockAlgorithm.js +103 -103
  59. package/src/module/xapi/Crypto/algorithms/C_algo.js +315 -315
  60. package/src/module/xapi/Crypto/algorithms/HMAC.js +9 -9
  61. package/src/module/xapi/Crypto/algorithms/SHA1.js +9 -9
  62. package/src/module/xapi/Crypto/encoders/Base.js +105 -105
  63. package/src/module/xapi/Crypto/encoders/Base64.js +99 -99
  64. package/src/module/xapi/Crypto/encoders/Hex.js +61 -61
  65. package/src/module/xapi/Crypto/encoders/Latin1.js +61 -61
  66. package/src/module/xapi/Crypto/encoders/Utf8.js +45 -45
  67. package/src/module/xapi/Crypto/index.js +53 -53
  68. package/src/module/xapi/Statement/activity.js +47 -47
  69. package/src/module/xapi/Statement/agent.js +55 -55
  70. package/src/module/xapi/Statement/group.js +26 -26
  71. package/src/module/xapi/Statement/index.js +259 -259
  72. package/src/module/xapi/Statement/statement.js +253 -253
  73. package/src/module/xapi/Statement/statementRef.js +23 -23
  74. package/src/module/xapi/Statement/substatement.js +22 -22
  75. package/src/module/xapi/Statement/verb.js +36 -36
  76. package/src/module/xapi/activitytypes.js +17 -17
  77. package/src/module/xapi/launch.js +157 -157
  78. package/src/module/xapi/utils.js +167 -167
  79. package/src/module/xapi/verbs.js +294 -294
  80. package/src/module/xapi/wrapper.js +1963 -1963
  81. package/src/module/xapi/xapiStatement.js +444 -444
  82. package/src/plugins/bus.js +8 -8
  83. package/src/plugins/gsap.js +14 -14
  84. package/src/plugins/helper.js +314 -308
  85. package/src/plugins/i18n.js +44 -44
  86. package/src/plugins/idb.js +227 -219
  87. package/src/plugins/save.js +37 -37
  88. package/src/plugins/scorm.js +287 -287
  89. package/src/plugins/xapi.js +11 -11
  90. package/src/public/index.html +33 -33
  91. package/src/router/index.js +43 -43
  92. package/src/router/routes.js +312 -312
  93. package/src/shared/generalfuncs.js +210 -210
  94. package/src/shared/validators.js +1069 -1069
  95. package/vite.config.js +0 -27
@@ -1,413 +1,423 @@
1
- <!--
2
- @ Description: This component is used to create the menu and the ard that will bring you back where you were before the menu.
3
- @ What it does: Look in the store what was the last page you saw before you came to the menu and create the the link for the card. It display's AppCompMenuItem
4
- -->
5
- <template>
6
- <div class="menu-container">
7
- <div
8
- id="page_info_section"
9
- aria-labelledby="page_info"
10
- aria-live="true"
11
- ></div>
12
- <a
13
- class="skip-link"
14
- href=""
15
- @click.prevent="$bus.$emit('move-to-target', 'menu-main')"
16
- >
17
- {{ $t('message.skip_content') }}
18
- </a>
19
- <div class="contain-lr">
20
- <div class="wrapper-lasRoute">
21
- <div class="box-menu">
22
- <h1>{{ getLessonid }}</h1>
23
- <h2 v-html="getLessonTitle"></h2>
24
-
25
- <p class="lesson-progess">
26
- {{ $t('message.progress_card') }} {{ lessonProg() }}
27
- </p>
28
- <router-link
29
- id="btn_last_route"
30
- class="nav_last_route btn-main"
31
- :title="handelLabel"
32
- :to="{ name: GoToLastRoute() }"
33
- data-test="menu-back-btn"
34
- >
35
- {{ handelLabel }}
36
- </router-link>
37
- </div>
38
- </div>
39
- <v-row justify="center" align="center" class="r-menu">
40
- <v-col id="menu-main" md="10" class="wrapper-MenuItem">
41
- <h3>{{ $t('text.activity_title') }}</h3>
42
-
43
- <app-comp-menu-item></app-comp-menu-item>
44
- </v-col>
45
- </v-row>
46
- </div>
47
- <v-row justify="center" align="center">
48
- <v-col md="7">
49
- <div v-show="appDebugMode" id="_debug-area">
50
- <h5>Mode de débogage activé</h5>
51
- <p>
52
- Cliquez sur le bouton pour réinitialiser toutes les données de ce
53
- paquet.
54
- </p>
55
-
56
- <app-base-button
57
- :id="`btn-quiz`"
58
- class="btn lk-btn"
59
- :is-active="resetStatus !== false"
60
- @click="askResetUserData"
61
- >
62
- Réinitialiser la leçon
63
- </app-base-button>
64
- <div v-show="resetStatus !== false" id="resetOverlay">
65
- <div
66
- v-show="resetStatus === resetState.LOADING"
67
- class="lds-ellipsis"
68
- >
69
- <div></div>
70
- <div></div>
71
- <div></div>
72
- <div></div>
73
- </div>
74
- <span v-show="resetStatus === resetState.COMPLETE" id="reset_label">
75
- Opération réussie!
76
- </span>
77
- </div>
78
- </div>
79
- </v-col>
80
- </v-row>
81
- <div id="page_info" class="sr-only" aria-hidden="true">
82
- {{ $t('text.title_content_view') }}
83
- </div>
84
- </div>
85
- </template>
86
- <script>
87
- // ...
88
- import { mapState } from 'pinia'
89
- import { useAppStore } from '../module/stores/appStore'
90
- export default {
91
- name: 'AppCompMenu',
92
- data() {
93
- return {
94
- totalAttempts: 0,
95
- resetStatus: false,
96
- resetState: { LOADING: 'LOADING', COMPLETE: 'COMPLETE' }
97
- }
98
- },
99
-
100
- computed: {
101
- ...mapState(useAppStore, [
102
- 'getRouteHistory',
103
- 'getAllActivitiesState',
104
- 'getAllCompleted',
105
- 'getModuleInfo',
106
- 'getMenuSettings',
107
- 'getAppDebugMode',
108
- 'getAllCompleted'
109
- ]),
110
- appDebugMode() {
111
- return this.getAppDebugMode
112
- },
113
- handelLabel() {
114
- let label = ''
115
- const { allActivitiesState, allCompleted } = this.progressWithMenu()
116
-
117
- let activity = Object.values(allActivitiesState)
118
- let completeActivity = Object.values(allCompleted)
119
-
120
- if (this.noProgress(activity)) {
121
- label = this.$t('button.menu_item.start')
122
- } else {
123
- if (activity.length == completeActivity.length) {
124
- label = this.$t('button.menu_item.end')
125
- } else {
126
- label = this.$t('button.menu_item.end')
127
- }
128
- }
129
- return label
130
- },
131
- getLessonid() {
132
- // ATTENDRE UX*UI poure voir si on garde le concept ou pas
133
- let lessonLabel = this.$t('text.lesson')
134
- let lessonId = 99
135
- return `${lessonLabel} ${lessonId}`
136
- },
137
- getLessonTitle() {
138
- let lessonT
139
- if (this.getMenuSettings.lessonTitle) {
140
- lessonT = this.getMenuSettings.lessonTitle
141
- } else {
142
- lessonT = 'Entrer un titre à pour votre leçon dans menu setting svp.'
143
- }
144
- return `${lessonT}`
145
- }
146
- },
147
- mounted() {
148
- setTimeout(() => {
149
- this.$bus.$emit('move-to-target', 'page_info_section')
150
- }, 200)
151
- },
152
- beforeUnmount() {
153
- this.$bus.$off('reset-complete', this.onResetComplete)
154
- },
155
- methods: {
156
- //When server responds after a reset request
157
- onResetComplete() {
158
- this.$bus.$off('reset-complete', this.onResetComplete)
159
- //show Operation reussie! for 2 seconds then exit debugmode
160
- this.resetStatus = this.resetState.COMPLETE
161
- setTimeout(() => {
162
- window.setDebugMode(false)
163
- if (this.resetStatus) {
164
- this.resetStatus = false
165
- }
166
- }, 2000)
167
- },
168
- GoToLastRoute() {
169
- let lastRoute
170
- let path
171
-
172
- //Get all activity state (menu not included)
173
- const { allActivitiesState } = this.progressWithMenu()
174
- let state = Object.values(allActivitiesState)
175
-
176
- if (this.getRouteHistory.length) {
177
- if (this.getRouteHistory.length == 1) {
178
- lastRoute = this.getRouteHistory[0]
179
- } else {
180
- lastRoute = this.getRouteHistory[this.getRouteHistory.length - 1]
181
- }
182
- }
183
-
184
- //if course was not started bring you to the introduction
185
- if (this.noProgress(state)) {
186
- path = 'introduction'
187
- return path
188
- }
189
- // create path from the last you saw
190
- if (lastRoute) path = this.createdRoute(lastRoute)
191
-
192
- return path
193
- },
194
-
195
- noProgress(obj) {
196
- //validator to see if anything was seen before
197
- for (let i = 0; i < obj.length; i++) {
198
- if (obj[i].progressions.length != 0) return false //something was seen
199
- }
200
- return true //nothing was seen
201
- },
202
- createdRoute(objRoute) {
203
- // create link for activity
204
- let newRoute = objRoute
205
- let activity
206
- let page
207
- let path
208
-
209
- const typesToCatch = ['menu', 'introduction', 'conclusion']
210
- //Define activity
211
- if (typesToCatch.includes(newRoute.type)) {
212
- activity = newRoute.type
213
- } else {
214
- activity =
215
- newRoute.activity_ref.charAt(1) == '0'
216
- ? `activite_${newRoute.activity_ref.substring(2)}`
217
- : `activite_${newRoute.activity_ref.substring(1)}`
218
- }
219
-
220
- //Define page
221
- const idToIgnore = ['P01', 'pg_menu']
222
- page = idToIgnore.includes(newRoute.id) ? ' ' : newRoute.id.substring(2)
223
-
224
- //Define path
225
- path = page !== ' ' ? `${activity}.page_${page}` : activity
226
-
227
- return path
228
- },
229
- progressWithMenu() {
230
- /*
231
- * Note:
232
- * Assaging by reference would change the property of the getters when the valued are changed in the new object in. * To prevent this behaviour we will make a deep copy of the getter
233
- * cf: https://reactgo.com/javascript-clone-object/
234
- */
235
-
236
- const allActivitiesState = JSON.parse(
237
- JSON.stringify(this.getAllActivitiesState)
238
- )
239
-
240
- const allCompleted = JSON.parse(JSON.stringify(this.getAllCompleted))
241
-
242
- for (let activity in allActivitiesState) {
243
- if (
244
- activity === 'A00' &&
245
- allActivitiesState[activity] &&
246
- allCompleted[activity]
247
- ) {
248
- let completedIntro = allCompleted[activity]
249
-
250
- if (!completedIntro.length) completedIntro = []
251
-
252
- allCompleted[activity] = completedIntro
253
- }
254
- }
255
-
256
- return {
257
- allActivitiesState,
258
- allCompleted
259
- }
260
- },
261
- lessonProg() {
262
- let lstActivity = Object.keys(this.getAllActivitiesState)
263
- let progress = null
264
- let info = this.progressWithMenu()
265
- let page = null
266
- let pageCmplt = null
267
-
268
- lstActivity.forEach((element) => {
269
- //Get the total of all the page
270
- page += info.allActivitiesState[element].size
271
-
272
- if (info.allCompleted[element]) {
273
- // GEt all page complete
274
- pageCmplt += Object.values(info.allCompleted[element]).length
275
- }
276
- })
277
-
278
- // Create pourcentage complete
279
- progress = Math.round((pageCmplt * 100) / page)
280
-
281
- return `${progress}%`
282
- },
283
- askResetUserData() {
284
- //show loader animation
285
- this.resetStatus = this.resetState.LOADING
286
- //callback on server response
287
- this.$bus.$on('reset-complete', this.onResetComplete)
288
- //launch reset call
289
- this.$bus.$emit('reset-userdata')
290
- }
291
- }
292
- }
293
- </script>
294
- <style lang="scss">
295
- .contain-lr {
296
- display: flex;
297
- flex-direction: column;
298
- flex-wrap: wrap;
299
- width: 100%;
300
-
301
- .wrapper-lasRoute {
302
- display: flex;
303
- justify-content: flex-end;
304
-
305
- .nav_last_route {
306
- display: inline-block;
307
- }
308
- }
309
- }
310
-
311
- .menu-container {
312
- width: 100%;
313
- height: 100%;
314
-
315
- .r-menu {
316
- margin: 0 0 0 0;
317
- }
318
- }
319
-
320
- #_debug-area {
321
- display: flex;
322
- flex-direction: column;
323
- align-items: center;
324
- justify-content: center;
325
- margin: 25px;
326
- padding: 20px;
327
- background-color: #eaabb685;
328
- border-block: dotted yellow 5px;
329
- p {
330
- padding: 15px;
331
- text-align: center;
332
- font-size: 1em;
333
- }
334
- button {
335
- background-color: #8dff95;
336
- font-size: 1.3em;
337
- }
338
- #resetOverlay {
339
- position: absolute;
340
- display: flex;
341
- flex-direction: column;
342
- width: 33%;
343
- height: 40%;
344
- align-items: center;
345
- justify-content: center;
346
- background-color: rgba($color: #000000, $alpha: 0.9);
347
- border-radius: 10px;
348
- box-shadow: 2px 2px 4px 0px rgba($color: #000000, $alpha: 0.2);
349
- }
350
- #reset_label {
351
- font-family: arial;
352
- color: #fff;
353
- font-weight: bold;
354
- font-size: 18px;
355
- }
356
- .lds-ellipsis {
357
- display: flex;
358
- display: inline-block;
359
- position: relative;
360
- width: 80px;
361
- height: 80px;
362
- }
363
- .lds-ellipsis div {
364
- position: absolute;
365
- top: 33px;
366
- width: 13px;
367
- height: 13px;
368
- border-radius: 50%;
369
- background: #fff;
370
- animation-timing-function: cubic-bezier(0, 1, 1, 0);
371
- }
372
- .lds-ellipsis div:nth-child(1) {
373
- left: 8px;
374
- animation: lds-ellipsis1 0.6s infinite;
375
- }
376
- .lds-ellipsis div:nth-child(2) {
377
- left: 8px;
378
- animation: lds-ellipsis2 0.6s infinite;
379
- }
380
- .lds-ellipsis div:nth-child(3) {
381
- left: 32px;
382
- animation: lds-ellipsis2 0.6s infinite;
383
- }
384
- .lds-ellipsis div:nth-child(4) {
385
- left: 56px;
386
- animation: lds-ellipsis3 0.6s infinite;
387
- }
388
- @keyframes lds-ellipsis1 {
389
- 0% {
390
- transform: scale(0);
391
- }
392
- 100% {
393
- transform: scale(1);
394
- }
395
- }
396
- @keyframes lds-ellipsis3 {
397
- 0% {
398
- transform: scale(1);
399
- }
400
- 100% {
401
- transform: scale(0);
402
- }
403
- }
404
- @keyframes lds-ellipsis2 {
405
- 0% {
406
- transform: translate(0, 0);
407
- }
408
- 100% {
409
- transform: translate(24px, 0);
410
- }
411
- }
412
- }
413
- </style>
1
+ <!--
2
+ @ Description: This component is used to create the menu and the ard that will bring you back where you were before the menu.
3
+ @ What it does: Look in the store what was the last page you saw before you came to the menu and create the the link for the card. It display's AppCompMenuItem
4
+ -->
5
+ <template>
6
+ <div class="menu-container">
7
+ <div
8
+ id="page_info_section"
9
+ aria-labelledby="page_info"
10
+ aria-live="true"
11
+ ></div>
12
+ <a
13
+ class="skip-link"
14
+ href=""
15
+ @click.prevent="$bus.$emit('move-to-target', 'menu-main')"
16
+ >
17
+ {{ $t('message.skip_content') }}
18
+ </a>
19
+ <div class="contain-lr">
20
+ <div class="wrapper-lasRoute">
21
+ <div class="box-menu">
22
+ <h1>{{ getLessonid }}</h1>
23
+ <h2 v-html="getLessonTitle"></h2>
24
+
25
+ <p class="lesson-progess">
26
+ {{ $t('message.progress_card') }} {{ lessonProg() }}
27
+ </p>
28
+ <router-link
29
+ id="btn_last_route"
30
+ class="nav_last_route btn-main"
31
+ :title="handelLabel"
32
+ :to="{ name: GoToLastRoute() }"
33
+ data-test="menu-back-btn"
34
+ >
35
+ {{ handelLabel }}
36
+ </router-link>
37
+ </div>
38
+ </div>
39
+ <v-row justify="center" align="center" class="r-menu">
40
+ <v-col id="menu-main" md="10" class="wrapper-MenuItem">
41
+ <h3>{{ $t('text.activity_title') }}</h3>
42
+
43
+ <app-comp-menu-item></app-comp-menu-item>
44
+ </v-col>
45
+ </v-row>
46
+ </div>
47
+ <v-row justify="center" align="center">
48
+ <v-col md="7">
49
+ <div v-show="appDebugMode" id="_debug-area">
50
+ <h5>Mode de débogage activé</h5>
51
+ <p>
52
+ Cliquez sur le bouton pour réinitialiser toutes les données de ce
53
+ paquet.
54
+ </p>
55
+
56
+ <app-base-button
57
+ :id="`btn-quiz`"
58
+ class="btn lk-btn"
59
+ :is-active="resetStatus !== false"
60
+ @click="askResetUserData"
61
+ >
62
+ Réinitialiser la leçon
63
+ </app-base-button>
64
+ <div v-show="resetStatus !== false" id="resetOverlay">
65
+ <div
66
+ v-show="resetStatus === resetState.LOADING"
67
+ class="lds-ellipsis"
68
+ >
69
+ <div></div>
70
+ <div></div>
71
+ <div></div>
72
+ <div></div>
73
+ </div>
74
+ <span v-show="resetStatus === resetState.COMPLETE" id="reset_label">
75
+ Opération réussie!
76
+ </span>
77
+ </div>
78
+ </div>
79
+ </v-col>
80
+ </v-row>
81
+ <div id="page_info" class="sr-only" aria-hidden="true">
82
+ {{ $t('text.title_content_view') }}
83
+ </div>
84
+ </div>
85
+ </template>
86
+ <script>
87
+ // ...
88
+ import { mapState } from 'pinia'
89
+ import { useAppStore } from '../module/stores/appStore'
90
+ export default {
91
+ name: 'AppCompMenu',
92
+ data() {
93
+ return {
94
+ totalAttempts: 0,
95
+ resetStatus: false,
96
+ resetState: { LOADING: 'LOADING', COMPLETE: 'COMPLETE' }
97
+ }
98
+ },
99
+
100
+ computed: {
101
+ ...mapState(useAppStore, [
102
+ 'getRouteHistory',
103
+ 'getAllActivitiesState',
104
+ 'getAllCompleted',
105
+ 'getModuleInfo',
106
+ 'getMenuSettings',
107
+ 'getAppDebugMode',
108
+ 'getAllCompleted',
109
+ 'getDataFromServer'
110
+ ]),
111
+ appDebugMode() {
112
+ return this.getAppDebugMode
113
+ },
114
+ handelLabel() {
115
+ let label = ''
116
+ const { allActivitiesState, allCompleted } = this.progressWithMenu()
117
+
118
+ let activity = Object.values(allActivitiesState)
119
+ let completeActivity = Object.values(allCompleted)
120
+
121
+ if (this.noProgress(activity)) {
122
+ label = this.$t('button.menu_item.start')
123
+ } else {
124
+ if (activity.length == completeActivity.length) {
125
+ label = this.$t('button.menu_item.end')
126
+ } else {
127
+ label = this.$t('button.menu_item.end')
128
+ }
129
+ }
130
+ return label
131
+ },
132
+ getLessonid() {
133
+ // ATTENDRE UX*UI poure voir si on garde le concept ou pas
134
+ let lessonLabel = this.$t('text.lesson')
135
+ let lessonId = 99
136
+ return `${lessonLabel} ${lessonId}`
137
+ },
138
+ getLessonTitle() {
139
+ let lessonT
140
+ if (this.getMenuSettings.lessonTitle) {
141
+ lessonT = this.getMenuSettings.lessonTitle
142
+ } else {
143
+ lessonT = 'Entrer un titre à pour votre leçon dans menu setting svp.'
144
+ }
145
+ return `${lessonT}`
146
+ }
147
+ },
148
+ mounted() {
149
+ setTimeout(() => {
150
+ this.$bus.$emit('move-to-target', 'page_info_section')
151
+ }, 200)
152
+ },
153
+ beforeUnmount() {
154
+ this.$bus.$off('reset-complete', this.onResetComplete)
155
+ },
156
+ methods: {
157
+ //When server responds after a reset request
158
+ onResetComplete() {
159
+ this.$bus.$off('reset-complete', this.onResetComplete)
160
+ //show Operation reussie! for 2 seconds then exit debugmode
161
+ this.resetStatus = this.resetState.COMPLETE
162
+ setTimeout(() => {
163
+ window.setDebugMode(false)
164
+ if (this.resetStatus) {
165
+ this.resetStatus = false
166
+ }
167
+ }, 2000)
168
+ },
169
+ // GoToLastRoute() {
170
+ // let lastRoute
171
+ // //Get all activity state (menu not included)
172
+
173
+ // //No route history Should link to introduction route
174
+ // if (!this.getRouteHistory.length) return 'introduction'
175
+ // //last Route should be the last element in route history
176
+ // lastRoute = this.getRouteHistory.toReversed()[0]
177
+ // //create the route link and return it
178
+ // return this.createdRoute(lastRoute)
179
+ // },
180
+ GoToLastRoute() {
181
+ let lastRoute
182
+ let path
183
+ //Get all activity state (menu not included)
184
+ const { allActivitiesState } = this.progressWithMenu()
185
+ let state = Object.values(allActivitiesState)
186
+
187
+ if (this.getRouteHistory.length) {
188
+ if (this.getRouteHistory.length == 1) {
189
+ lastRoute = this.getRouteHistory[0]
190
+ } else {
191
+ lastRoute = this.getRouteHistory[this.getRouteHistory.length - 1]
192
+ }
193
+ }
194
+
195
+ //if course was not started bring you to the introduction
196
+ if (this.noProgress(state)) {
197
+ path = 'introduction'
198
+ return path
199
+ }
200
+ // create path from the last you saw
201
+ if (lastRoute) path = this.createdRoute(lastRoute)
202
+
203
+ return path
204
+ },
205
+
206
+ noProgress(obj) {
207
+ //validator to see if anything was seen before
208
+ for (let i = 0; i < obj.length; i++) {
209
+ if (obj[i].progressions.length != 0) return false //something was seen
210
+ }
211
+ return true //nothing was seen
212
+ },
213
+ createdRoute(objRoute) {
214
+ // create link for activity
215
+ let newRoute = objRoute
216
+ let activity
217
+ let page
218
+ let path
219
+
220
+ const typesToCatch = ['menu', 'introduction', 'conclusion']
221
+ //Define activity
222
+ if (typesToCatch.includes(newRoute.type)) {
223
+ activity = newRoute.type
224
+ } else {
225
+ activity =
226
+ newRoute.activity_ref && newRoute.activity_ref.charAt(1) == '0'
227
+ ? `activite_${newRoute.activity_ref.substring(2)}`
228
+ : `activite_${newRoute.activity_ref.substring(1)}`
229
+ }
230
+
231
+ //Define page
232
+ const idToIgnore = ['P01', 'pg_menu']
233
+ page = idToIgnore.includes(newRoute.id) ? ' ' : newRoute.id.substring(2)
234
+
235
+ //Define path
236
+ path = page !== ' ' ? `${activity}.page_${page}` : activity
237
+ return path
238
+ },
239
+ progressWithMenu() {
240
+ /*
241
+ * Note:
242
+ * Assaging by reference would change the property of the getters when the valued are changed in the new object in. * To prevent this behaviour we will make a deep copy of the getter
243
+ * cf: https://reactgo.com/javascript-clone-object/
244
+ */
245
+
246
+ const allActivitiesState = JSON.parse(
247
+ JSON.stringify(this.getAllActivitiesState)
248
+ )
249
+
250
+ const allCompleted = JSON.parse(JSON.stringify(this.getAllCompleted))
251
+
252
+ for (let activity in allActivitiesState) {
253
+ if (
254
+ activity === 'A00' &&
255
+ allActivitiesState[activity] &&
256
+ allCompleted[activity]
257
+ ) {
258
+ let completedIntro = allCompleted[activity]
259
+
260
+ if (!completedIntro.length) completedIntro = []
261
+
262
+ allCompleted[activity] = completedIntro
263
+ }
264
+ }
265
+
266
+ return {
267
+ allActivitiesState,
268
+ allCompleted
269
+ }
270
+ },
271
+ lessonProg() {
272
+ let lstActivity = Object.keys(this.getAllActivitiesState)
273
+ let progress = null
274
+ let info = this.progressWithMenu()
275
+ let page = null
276
+ let pageCmplt = null
277
+
278
+ lstActivity.forEach((element) => {
279
+ //Get the total of all the page
280
+ page += info.allActivitiesState[element].size
281
+
282
+ if (info.allCompleted[element]) {
283
+ // GEt all page complete
284
+ pageCmplt += Object.values(info.allCompleted[element]).length
285
+ }
286
+ })
287
+
288
+ // Create pourcentage complete
289
+ progress = Math.round((pageCmplt * 100) / page)
290
+
291
+ return `${progress}%`
292
+ },
293
+ askResetUserData() {
294
+ //show loader animation
295
+ this.resetStatus = this.resetState.LOADING
296
+ //callback on server response
297
+ this.$bus.$on('reset-complete', this.onResetComplete)
298
+ //launch reset call
299
+ this.$bus.$emit('reset-userdata')
300
+ }
301
+ }
302
+ }
303
+ </script>
304
+ <style lang="scss">
305
+ .contain-lr {
306
+ display: flex;
307
+ flex-direction: column;
308
+ flex-wrap: wrap;
309
+ width: 100%;
310
+
311
+ .wrapper-lasRoute {
312
+ display: flex;
313
+ justify-content: flex-end;
314
+
315
+ .nav_last_route {
316
+ display: inline-block;
317
+ }
318
+ }
319
+ }
320
+
321
+ .menu-container {
322
+ width: 100%;
323
+ height: 100%;
324
+
325
+ .r-menu {
326
+ margin: 0 0 0 0;
327
+ }
328
+ }
329
+
330
+ #_debug-area {
331
+ display: flex;
332
+ flex-direction: column;
333
+ align-items: center;
334
+ justify-content: center;
335
+ margin: 25px;
336
+ padding: 20px;
337
+ background-color: #eaabb685;
338
+ border-block: dotted yellow 5px;
339
+ p {
340
+ padding: 15px;
341
+ text-align: center;
342
+ font-size: 1em;
343
+ }
344
+ button {
345
+ background-color: #8dff95;
346
+ font-size: 1.3em;
347
+ }
348
+ #resetOverlay {
349
+ position: absolute;
350
+ display: flex;
351
+ flex-direction: column;
352
+ width: 33%;
353
+ height: 40%;
354
+ align-items: center;
355
+ justify-content: center;
356
+ background-color: rgba($color: #000000, $alpha: 0.9);
357
+ border-radius: 10px;
358
+ box-shadow: 2px 2px 4px 0px rgba($color: #000000, $alpha: 0.2);
359
+ }
360
+ #reset_label {
361
+ font-family: arial;
362
+ color: #fff;
363
+ font-weight: bold;
364
+ font-size: 18px;
365
+ }
366
+ .lds-ellipsis {
367
+ display: flex;
368
+ display: inline-block;
369
+ position: relative;
370
+ width: 80px;
371
+ height: 80px;
372
+ }
373
+ .lds-ellipsis div {
374
+ position: absolute;
375
+ top: 33px;
376
+ width: 13px;
377
+ height: 13px;
378
+ border-radius: 50%;
379
+ background: #fff;
380
+ animation-timing-function: cubic-bezier(0, 1, 1, 0);
381
+ }
382
+ .lds-ellipsis div:nth-child(1) {
383
+ left: 8px;
384
+ animation: lds-ellipsis1 0.6s infinite;
385
+ }
386
+ .lds-ellipsis div:nth-child(2) {
387
+ left: 8px;
388
+ animation: lds-ellipsis2 0.6s infinite;
389
+ }
390
+ .lds-ellipsis div:nth-child(3) {
391
+ left: 32px;
392
+ animation: lds-ellipsis2 0.6s infinite;
393
+ }
394
+ .lds-ellipsis div:nth-child(4) {
395
+ left: 56px;
396
+ animation: lds-ellipsis3 0.6s infinite;
397
+ }
398
+ @keyframes lds-ellipsis1 {
399
+ 0% {
400
+ transform: scale(0);
401
+ }
402
+ 100% {
403
+ transform: scale(1);
404
+ }
405
+ }
406
+ @keyframes lds-ellipsis3 {
407
+ 0% {
408
+ transform: scale(1);
409
+ }
410
+ 100% {
411
+ transform: scale(0);
412
+ }
413
+ }
414
+ @keyframes lds-ellipsis2 {
415
+ 0% {
416
+ transform: translate(0, 0);
417
+ }
418
+ 100% {
419
+ transform: translate(24px, 0);
420
+ }
421
+ }
422
+ }
423
+ </style>