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