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,960 +1,959 @@
1
- <!-- About this Component--
2
- @ Description: This component is used to display and create the navigation in el+ mode.
3
- @ What it does: Create the link to back back to the menu. Create link to the all the anchor to the current activity and display the curent anchor and the button next page and previous page. Teleport are use to place the element in the rigth place in the main frame.
4
- -->
5
- <template>
6
- <div v-if="navigationRoutes" class="app-ctrl">
7
- <div id="tool-bar">
8
- <router-link
9
- id="btn_back_summary"
10
- :to="{ name: homeLanding.route }"
11
- class="btn"
12
- :title="homeLanding.title"
13
- >
14
- <template #default>
15
- <svg class="home-icon">
16
- <use href="#home-icon" />
17
- </svg>
18
-
19
- <span class="toolbar_label">{{ homeLanding.title }}</span>
20
- </template>
21
- </router-link>
22
- <div class="ctn-w">
23
- <app-base-button
24
- id="toc"
25
- :title="$t('button.toc')"
26
- :aria-label="$t('button.toc')"
27
- @click="openToc()"
28
- >
29
- <svg class="toc-icon">
30
- <use href="#toc-icon" />
31
- </svg>
32
- <span class="toolbar_label">{{ $t('button.toc') }}</span>
33
- </app-base-button>
34
- <app-comp-table-of-content />
35
- </div>
36
- <div class="ctn-w">
37
- <app-base-button
38
- id="btn_infos"
39
- :title="$t('button.info')"
40
- :aria-label="$t('button.info')"
41
- :disabled="noInfo"
42
- :class="{ md_disabled: noInfo }"
43
- @click="openCreditNote()"
44
- >
45
- <svg class="info-icon">
46
- <use href="#info-icon" />
47
- </svg>
48
- <span class="toolbar_label">{{ $t('button.info') }}</span>
49
- </app-base-button>
50
- <app-comp-note-credit />
51
- </div>
52
- </div>
53
-
54
- <!-- Navigation principale -->
55
-
56
- <SafeTeleport to="#primary_nav_wrapper">
57
- <template v-if="!isMenu">
58
- <app-base-button
59
- id="btn_previous_page"
60
- ref="btn_previous_page"
61
- class="nav_main_btn primary_nav_btn"
62
- :title="$t('button.go_to_previous_page')"
63
- :aria-label="$t('button.go_to_previous_page')"
64
- :is-active="!backAllowed"
65
- @click="goPrevious"
66
- >
67
- <svg>
68
- <use href="#fleche-gauche-icon" />
69
- </svg>
70
- </app-base-button>
71
- <div class="pagination">
72
- <span aria-hidden="true">
73
- Page {{ pagination.counter }} / {{ pagination.total }}
74
- </span>
75
- <span class="sr-only">
76
- Page {{ pagination.counter }} {{ pagination.$W }}
77
- {{ pagination.total }}
78
- </span>
79
- </div>
80
- <app-base-button
81
- id="btn_next_page"
82
- ref="btn_next_page"
83
- class="nav_main_btn primary_nav_btn"
84
- :aria-label="$t('button.go_to_next_page')"
85
- :title="$t('button.go_to_next_page')"
86
- :is-active="!nextAllowed"
87
- @click="goNext"
88
- >
89
- <svg>
90
- <use href="#fleche-droite-icon"></use>
91
- </svg>
92
- </app-base-button>
93
- </template>
94
- </SafeTeleport>
95
- <!---------------------------- TEST ------------------------->
96
- <!---------------------------- END_ACTIVITY_POPUP SECTION ------------------------->
97
-
98
- <SafeTeleport
99
- v-if="endActivityPopup && getEndPopUp"
100
- defer
101
- to="#end-activity"
102
- >
103
- <div class="popup-bottom-buttons">
104
- <app-base-button
105
- :aria-label="endActivityPopup.backLabel"
106
- :title="endActivityPopup.backLabel"
107
- class="popup_primary_nav_btn btn btn-reserve"
108
- @click="navigateTo(endActivityPopup.backRoute)"
109
- >
110
- {{ endActivityPopup.backLabel }}
111
- </app-base-button>
112
-
113
- <app-base-button
114
- :aria-label="endActivityPopup.nextLabel"
115
- :title="endActivityPopup.nextLabel"
116
- class="popup_primary_nav_btn btn btn-main"
117
- @click="navigateTo(endActivityPopup.nextRoute)"
118
- >
119
- {{ endActivityPopup.nextLabel }}
120
- </app-base-button>
121
- </div>
122
- </SafeTeleport>
123
- <!---------------------------- END END_ACTIVITY_POPUP SECTION ------------------------->
124
- </div>
125
- </template>
126
-
127
- <script>
128
- import { mapState, mapActions } from 'pinia'
129
- import { useAppStore } from '../module/stores/appStore'
130
- export default {
131
- props: {
132
- autoNavigate: { type: Boolean, default: false }
133
- },
134
-
135
- data() {
136
- return {
137
- hasMedia: false,
138
- mediaType: null,
139
- mediaPlaybackEnd: false,
140
- navigation: {},
141
- currentPath: null,
142
- navigationRoutes: null,
143
- currentActivity: null,
144
- currentPageId: null,
145
- anchors: [],
146
- pageInfo: null,
147
- nextActivity: null,
148
- nextActivityRoute: null
149
- }
150
- },
151
- computed: {
152
- ...mapState(useAppStore, [
153
- 'getCurrentPage',
154
- 'getModuleInfo',
155
- 'getIntroStatus',
156
- 'getUserInteraction',
157
- 'getAnchorsForActivity',
158
- 'getAppConfigs',
159
- 'getBifChoice',
160
- 'getMenuSettings',
161
- 'getWidgetOpen',
162
- 'getDataNoteCredit',
163
- 'getPopStatus',
164
- 'getEndPopUp'
165
- ]),
166
- noInfo() {
167
- if (this.getDataNoteCredit.note || this.getDataNoteCredit.credit) {
168
- return false
169
- } else return true
170
- },
171
-
172
- /// MUST BE MODIFY BECAUSE MENU IS VIEW NOW
173
- pagination() {
174
- let p = { counter: null, total: null }
175
-
176
- p['$W'] = this.$i18n.locale === 'fr' ? 'de' : 'of'
177
-
178
- p.counter =
179
- this.navigationRoutes.cat.findIndex(
180
- (route) => route._ref === this.$route.meta.id
181
- ) + 1
182
-
183
- p.total = this.navigationRoutes.cat.length
184
-
185
- return p
186
- },
187
-
188
- backAllowed() {
189
- let isAllowed = true // by default
190
- const { all_routes } = this.$helper.getRoutesFromVueRouter() // get all route of all activities
191
- const theFirstRoute = all_routes[0].children[0] // get first route of 1st activity
192
-
193
- //Prevent back to previous when 1st page of the 1st group of activities
194
- if (theFirstRoute.name === this.$route.name) isAllowed = false
195
-
196
- return isAllowed
197
- },
198
- nextAllowed() {
199
- let isAllowed
200
-
201
- //const { auto_next_activity } = this.getAppConfigs
202
- const { all_routes } = this.$helper.getRoutesFromVueRouter() // get all route of all activities
203
- let lastRoute = null
204
-
205
- if (!this.autoNavigate) {
206
- lastRoute = this.navigationRoutes.cat.toReversed()[0] //get last route in courant route catalogue
207
- //block navigation at the end of an activity (last route of current activity)
208
- isAllowed = lastRoute._namedRoute === this.$route.name ? false : true
209
- } else {
210
- lastRoute = all_routes.toReversed()[0].children.toReversed()[0] // get the last route of last activity
211
-
212
- //block navigation when current route is last route and there is no next lesson
213
- isAllowed =
214
- lastRoute.name === this.$route.name && !this.nextLesson ? false : true
215
- }
216
-
217
- return isAllowed
218
- },
219
-
220
- isMenu() {
221
- return this.$route.name === 'menu'
222
- },
223
-
224
- nextLesson() {
225
- const { linkedResource } = this.getAppConfigs
226
- if (linkedResource) return linkedResource
227
- else return null
228
- },
229
-
230
- previousLabel() {
231
- let label =
232
- this.$route.meta.id !== 'P01' ? this.$t('button.previous') : ''
233
-
234
- return label
235
- },
236
-
237
- nextLabel() {
238
- const lastRoute = this.navigationRoutes.cat.toReversed()[0] // get the last route by reversing the order of the navigation catalog
239
- let label =
240
- this.$route.meta.id !== lastRoute._ref
241
- ? this.$t('button.go_to_next_page')
242
- : this.$t('button.carousel_next')
243
- return label
244
- },
245
-
246
- homeLanding() {
247
- let { no_menu: noMenu } = this.getAppConfigs
248
- const activityRoutes = this.$helper.getRoutesFromVueRouter()
249
- //Get the 1st route from the list of routes
250
- const bckRoute = activityRoutes.meta.children[0]
251
- return noMenu
252
- ? {
253
- title: this.$t('button.go_to_first_page'),
254
- route: bckRoute._namedRoute
255
- }
256
- : { title: this.$t('button.menu'), route: 'menu' }
257
- },
258
-
259
- endActivityPopup() {
260
- let content = null
261
-
262
- let { no_menu: noMenu } = this.getAppConfigs
263
-
264
- if (!this.nextActivity) return
265
-
266
- switch (true) {
267
- // Next is an activity and there is no menu
268
- case this.nextActivity.type_of_next === 'ACTIVITY' && noMenu: {
269
- const activityRoutes = this.$helper.getRoutesFromVueRouter(
270
- this.$route.meta.activity_ref
271
- )
272
- //Get the 1st route from the list of routes of this current activity
273
- const bckRoute = activityRoutes.meta.children[0]
274
- content = {
275
- nextLabel: this.$t('button.next_activity'),
276
- backLabel: this.$t('button.go_to_first_page'),
277
- nextRoute: this.nextActivity._namedRoute,
278
- backRoute: bckRoute._namedRoute,
279
- nextEnabled: true,
280
- backEnabled: true
281
- }
282
- break
283
- }
284
- // Next is an activity and there is a menu
285
- case this.nextActivity.type_of_next === 'ACTIVITY' && !noMenu:
286
- content = {
287
- nextLabel: this.$t('button.next_activity'),
288
- backLabel: this.$t('button.go_to_menu'),
289
- nextRoute: this.nextActivity._namedRoute,
290
- backRoute: 'menu',
291
- nextEnabled: true,
292
- backEnabled: true
293
- }
294
- break
295
- // Next is a lesson and there is no menu
296
- case this.nextActivity.type_of_next === 'LESSON' && noMenu: {
297
- const activityRoutes = this.$helper.getRoutesFromVueRouter()
298
- //Get the 1st route from the list of routes
299
- const bckRoute = activityRoutes.meta.children[0]
300
- content = {
301
- nextLabel: this.$t('button.go_to_lesson'),
302
- backLabel: this.$t('button.go_to_first_page'),
303
- nextRoute: this.nextLesson,
304
- backRoute: bckRoute._namedRoute,
305
- nextEnabled: true,
306
- //backEnabled: (() => (isSingleActivity ? false : true))() //show back button of the endActivity popup when it is not a single activity.
307
- backEnabled: true //show back button of the endActivity popup when it is not a single activity.
308
- }
309
- break
310
- }
311
- // Next is a lesson and there is a menu
312
- case this.nextActivity.type_of_next === 'LESSON' && !noMenu:
313
- content = {
314
- nextLabel: this.$t('button.go_to_lesson'),
315
- backLabel: this.$t('button.go_to_menu'),
316
- nextRoute: this.nextLesson,
317
- backRoute: 'menu',
318
- nextEnabled: true,
319
- backEnabled: true
320
- }
321
- break
322
- }
323
-
324
- return content
325
- }
326
- },
327
- watch: {
328
- $route: {
329
- handler() {
330
- this.setNavigation() // reset the navigation context when route change
331
-
332
- setTimeout(() => {
333
- this.initPage()
334
- }, 200)
335
- },
336
- deep: true
337
- }
338
- },
339
- beforeUnmount() {
340
- this.$bus.$off('mediaPlaybackEnded', this.onMediaEnded)
341
- this.$bus.$off('quizNoAnswer', this.showPopupNoAnswer)
342
- },
343
- mounted() {
344
- this.$bus.$on('mediaPlaybackEnded', this.onMediaEnded)
345
- this.$bus.$on('quizNoAnswer', this.showPopupNoAnswer)
346
-
347
- this.setNavigation()
348
- setTimeout(() => {
349
- this.initPage()
350
- }, 200)
351
- },
352
- methods: {
353
- ...mapActions(useAppStore, ['updateNextActivity']),
354
- initPage() {
355
- this.setNextActivity()
356
- this.setPreviousActivity()
357
- },
358
-
359
- getActivity() {
360
- const { all_routes } = this.$helper.getRoutesFromVueRouter()
361
- const activity = all_routes.find(
362
- (route) =>
363
- route.meta.id === this.$router.currentRoute.value.meta.activity_ref
364
- )
365
- return activity
366
- },
367
- onMediaEnded() {
368
- this.mediaPlaybackEnd = true
369
- },
370
- navigateTo(path) {
371
- if (path.constructor === Object)
372
- return this.$bus.$emit(
373
- 'launch-xapi-resource',
374
- this.$helper.getNextLessonEnv(this.nextLesson)
375
- )
376
-
377
- if (!path) return this.$bus.$emit('close-popup')
378
-
379
- this.$router.push({
380
- name: path
381
- })
382
- },
383
- /** *****************Nav Methods*********************** */
384
- // TO TEST!!!!
385
- getNextPageBifurcationNochoice(activity, page) {
386
- let menu = this.getMenuSettings
387
- let bif
388
- //return if the page you are on is a declare as branching in menuSetting
389
- menu[activity].anchors.forEach((value) => {
390
- if (value.pageRef == page && value.branching) {
391
- bif = true
392
- }
393
- })
394
-
395
- return bif
396
- },
397
- // TO TEST!!!!
398
- getFirtsPageBif(activity, page) {
399
- let data
400
-
401
- // play string to make path sentence
402
- if (page.indexOf('0') == 1) {
403
- data = `page_${page.substring(page.indexOf('P') + 2)}`
404
- } else {
405
- data = `page_${page.substring(page.indexOf('P') + 1)}`
406
- }
407
- let menu = this.getMenuSettings
408
- let back = false
409
-
410
- //return if the page you are on is a declare as branching in menuSetting
411
- menu[activity].anchors.forEach((value) => {
412
- if (value.branching && value.branching.end == data) {
413
- back = true
414
- }
415
- })
416
-
417
- return back
418
- },
419
- // TO TEST!!!!
420
- getPageNavBif(activity, page) {
421
- let menu = this.getMenuSettings
422
- let data
423
-
424
- // return data star and end page
425
- menu[activity].anchors.forEach((value) => {
426
- if (value.pageRef == page && value.branching) {
427
- data = value.branching
428
- }
429
- })
430
-
431
- return data
432
- },
433
- // TO TEST!!!!
434
- getPageNavBifStart(activity, page) {
435
- let data
436
-
437
- // play string to make path sentence
438
- if (page.indexOf('0') == 1) {
439
- data = `page_${page.substring(page.indexOf('P') + 2)}`
440
- } else {
441
- data = `page_${page.substring(page.indexOf('P') + 1)}`
442
- }
443
- let menu = this.getMenuSettings
444
- let back
445
-
446
- //return the start page of bif
447
- menu[activity].anchors.forEach((value) => {
448
- if (value.branching && value.branching.end == data) {
449
- back = value.branching.start
450
- }
451
- })
452
-
453
- return back
454
- },
455
- /** @description Method to handle navigation to next content.
456
- * At the end of Navigation:
457
- * - Emit completion status for activity
458
- * - Opens a popup at the end Of activity or Lesson
459
- * @fires send-completion-event - completion of ACTIVITY
460
- * @fires 'close-widget' - close credit widget
461
- *
462
- */
463
- goNext() {
464
- const pageIndex = this.navigationRoutes.cat.findIndex(
465
- (route) => route._ref === this.$route.meta.id
466
- )
467
- const next = pageIndex + 1
468
-
469
- //=====================BIF HANDLING =============================
470
- // check if you did made a choice
471
- if (
472
- !this.getBifChoice &&
473
- this.getNextPageBifurcationNoChoice(
474
- this.$route.meta.activity_ref,
475
- this.$route.meta.id
476
- )
477
- ) {
478
- // create path to make the jump
479
- return this.$router.push({
480
- name: `${this.navigationRoutes.cat[0]._namedRoute}.${
481
- this.getPageNavBif(
482
- this.$route.meta.activity_ref,
483
- this.$route.meta.id
484
- ).end
485
- }`
486
- })
487
- }
488
- //=====================END BIF HANDLING =============================
489
-
490
- if (!this.nextActivity) return
491
- //Handle navigation to page, activity or Lesson
492
- switch (true) {
493
- // Next navigate lead to next page of the current liste
494
- case this.nextActivity.type_of_next === 'PAGE':
495
- this.$router.push({
496
- name: `${this.navigationRoutes.cat[next]._namedRoute}`
497
- })
498
- break
499
- //Next navigation will lead next activity
500
- case this.nextActivity.type_of_next === 'ACTIVITY': {
501
- const endPopup = {
502
- type: 'popup-endActivity',
503
- value: {
504
- title: `${this.$t('popup.text_what_to_do')}`
505
- }
506
- }
507
-
508
- this.openPopup(endPopup)
509
-
510
- this.nextActivityRoute = this.nextActivity._namedRoute
511
-
512
- if (this.getModuleInfo.packageType !== 'xapi') return
513
-
514
- this.$bus.$emit('send-completion-event', 'ACTIVITY')
515
- break
516
- }
517
- //Next navigation will lead next activity
518
- case this.nextActivity.type_of_next === 'LESSON': {
519
- const endPopup = {
520
- type: 'popup-endActivity',
521
- value: {
522
- template: `<p>${this.$t('popup.text_what_to_do')}</p>`,
523
- title: ''
524
- }
525
- }
526
-
527
- this.openPopup(endPopup)
528
-
529
- this.nextActivityRoute = this.nextLesson
530
-
531
- if (this.getModuleInfo.packageType !== 'xapi') return
532
- this.$bus.$emit('send-completion-event', 'ACTIVITY')
533
-
534
- break
535
- }
536
- }
537
- },
538
-
539
- //=============================================================
540
- goPrevious() {
541
- // ==================normal navigation ====================
542
-
543
- const pageIndex = this.navigationRoutes.cat.findIndex(
544
- (route) => route._ref === this.$route.meta.id
545
- )
546
- const previous = pageIndex - 1
547
-
548
- // validate if ther a branching and did you make a choice
549
- if (
550
- !this.getBifChoice &&
551
- this.getFirtsPageBif(this.$route.meta.activity_ref, this.$route.meta.id)
552
- ) {
553
- // create path to make the jump
554
- if (
555
- this.getPageNavBifStart(
556
- this.$route.meta.activity_ref,
557
- this.$route.meta.id
558
- ) == 'page_1'
559
- ) {
560
- this.$router.push({
561
- name: `${this.navigationRoutes.cat[0]._namedRoute}`
562
- })
563
- } else {
564
- this.$router.push({
565
- name: `${this.navigationRoutes.cat[0]._namedRoute}.${this.getPageNavBifStart(
566
- this.$route.meta.activity_ref,
567
- this.$route.meta.id
568
- )}`
569
- })
570
- }
571
-
572
- // back to previous page of module (module.page_xx)
573
- } else if (pageIndex > 0 && this.navigationRoutes.cat[previous]._path) {
574
- this.$router.push({
575
- name: `${this.navigationRoutes.cat[previous]._namedRoute}`
576
- })
577
- // this is the last page
578
- } else {
579
- // if allow navigation to activity active, navigate to previous activity
580
- if (this.autoNavigate && this.previousActivity) {
581
- this.$router.push({ name: this.previousActivity._namedRoute })
582
- } else this.$router.push('/')
583
- }
584
- },
585
- setNavigation() {
586
- // Close the info widget before navigation
587
- if (this.getWidgetOpen) {
588
- this.$bus.$emit('close-widget')
589
- }
590
- // current Route is module
591
- this.currentActivity = this.$router.currentRoute.value.meta.activity_ref
592
- this.currentPageId = this.$router.currentRoute.value.meta.id
593
-
594
- const { all_routes, meta } = this.$helper.getRoutesFromVueRouter()
595
-
596
- if (this.$router.currentRoute.value.name === 'module') {
597
- this.navigationRoutes = {
598
- context: 'module',
599
- cat: meta.children
600
- }
601
- }
602
- // Navigation catalog is the introduction
603
- else if (
604
- this.$router.currentRoute.value.meta.type === 'introduction' ||
605
- this.$router.currentRoute.value.meta.type === 'menu'
606
- ) {
607
- const a = all_routes.find(
608
- (route) =>
609
- route.meta.id ===
610
- this.$router.currentRoute.value.meta.activity_ref.$folderName
611
- )
612
-
613
- const b = all_routes.find(
614
- (route) =>
615
- route.meta.id === this.$router.currentRoute.value.meta.activity_ref
616
- )
617
- if (a) {
618
- let r = []
619
- //if Intro acitive get all the routes for indroduction or just the menu
620
- this.getIntroStatus
621
- ? r.push(...a.meta.children)
622
- : r.push(
623
- a.meta.children.find(
624
- (el) => !el._namedRoute.includes('introduction')
625
- )
626
- )
627
- this.navigationRoutes = {
628
- context: 'introduction',
629
- cat: r
630
- }
631
- } else if (b) {
632
- let r = []
633
- //if Intro acitive get all the routes for indroduction or just the menu
634
- this.getIntroStatus
635
- ? r.push(...b.meta.children)
636
- : r.push(
637
- b.meta.children.find(
638
- (el) => !el._namedRoute.includes('introduction')
639
- )
640
- )
641
- this.navigationRoutes = {
642
- context: 'introduction',
643
- cat: r
644
- }
645
- }
646
- }
647
- // Navigation catalog is pages of Activity ||menu
648
- else {
649
- const a = all_routes.find(
650
- (route) =>
651
- route.meta.id ===
652
- this.$router.currentRoute.value.meta.activity_ref.$folderName
653
- )
654
-
655
- // on refresh $forderName doesn't existe
656
- const b = all_routes.find(
657
- (route) =>
658
- route.meta.id === this.$router.currentRoute.value.meta.activity_ref
659
- )
660
-
661
- if (a) {
662
- this.navigationRoutes = {
663
- context: 'normal',
664
- cat: a.meta.children
665
- }
666
- } else if (b) {
667
- this.navigationRoutes = {
668
- context: 'normal',
669
- cat: b.meta.children
670
- }
671
- }
672
- }
673
- }, // END setNaviagation
674
- /**
675
- *@description: set the next activity to for the Navigation
676
- */
677
- setNextActivity() {
678
- if (this.navigationRoutes) {
679
- // get all the activities routes from router
680
- const { meta } = this.$helper.getRoutesFromVueRouter()
681
- const allRoutes = meta.children
682
-
683
- // get the index of the current route
684
- const current = this.navigationRoutes.cat.findIndex(
685
- (route) => route._ref === this.$route.meta.id
686
- )
687
-
688
- switch (this.navigationRoutes.context) {
689
- case 'introduction': {
690
- //Reached the last page in Intro
691
- if (current === this.navigationRoutes.cat.length - 1) {
692
- //there is a next activity
693
- if (allRoutes[1])
694
- return (this.nextActivity = {
695
- ...allRoutes[1],
696
- type_of_next: 'ACTIVITY'
697
- })
698
-
699
- //There is a next lesson
700
- if (this.nextLesson)
701
- return (this.nextActivity = {
702
- ...this.nextLesson,
703
- type_of_next: 'LESSON'
704
- })
705
-
706
- //There is nothing
707
- this.nextActivity = null
708
- } else {
709
- //Other pages in Intro
710
- this.nextActivity = {
711
- ...this.navigationRoutes.cat[current + 1],
712
- type_of_next: 'PAGE'
713
- }
714
- }
715
- break
716
- }
717
- case 'normal': {
718
- // find the current activity ref in the router catalog
719
-
720
- const currentRouteIndex = allRoutes.findIndex(
721
- (route) => route._ref === this.$route.meta.activity_ref
722
- )
723
-
724
- // this is the Last page in current activity
725
- if (
726
- current === this.navigationRoutes.cat.length - 1 &&
727
- allRoutes[currentRouteIndex + 1]
728
- ) {
729
- this.nextActivity = {
730
- ...allRoutes[currentRouteIndex + 1],
731
- type_of_next: 'ACTIVITY'
732
- } // get the next activity in the router catalog
733
- }
734
- // this is in the same activity return the next page of the activity
735
- else if (this.navigationRoutes.cat[current + 1]) {
736
- this.nextActivity = {
737
- ...this.navigationRoutes.cat[current + 1],
738
- type_of_next: 'PAGE'
739
- }
740
- }
741
- // There is no other activity after the current one
742
- else if (this.nextLesson)
743
- this.nextActivity = { ...this.nextLesson, type_of_next: 'LESSON' }
744
- else this.nextActivity = null
745
-
746
- break
747
- }
748
- }
749
- } else this.nextActivity = null
750
-
751
- this.updateNextActivity(this.nextActivity)
752
- },
753
- /**
754
- * @description: set previous activity for the navigation
755
- */
756
- setPreviousActivity() {
757
- if (this.autoNavigate && this.navigationRoutes) {
758
- // get all the activities routes from router
759
- const { all_routes: allRoutes } = this.$helper.getRoutesFromVueRouter()
760
-
761
- // get the index of the current route
762
- const current = this.navigationRoutes.cat.findIndex(
763
- (route) => route._ref === this.$route.meta.id
764
- )
765
-
766
- switch (this.navigationRoutes.context) {
767
- case 'introduction': {
768
- // This is the first page in the introduction
769
- if (current === 0) {
770
- this.previousActivity = null
771
- } else {
772
- this.previousActivity = {
773
- ...this.navigationRoutes.cat[current - 1],
774
- type_of_previous: 'PAGE'
775
- }
776
- }
777
- break
778
- }
779
- case 'normal': {
780
- // get the index of the current route
781
- const currentRouteIndex = allRoutes.findIndex(
782
- (route) => route.meta.id === this.$route.meta.activity_ref
783
- )
784
- // this is the 1st page of the 1st activity in the router catalogue
785
- // return point is introduction
786
- if (current === 0 && currentRouteIndex === 1) {
787
- const _length = allRoutes[0].children.length
788
- this.previousActivity = {
789
- ...allRoutes[0].meta.children[_length - 1],
790
- type_of_previous: 'ACTIVITY'
791
- } // get last page of the introduction navigation context
792
- }
793
- // This is the 1st page in another activity in the router catalogue
794
- else if (allRoutes[currentRouteIndex - 1] && current === 0) {
795
- const _length = allRoutes[currentRouteIndex - 1].children.length
796
- this.previousActivity = {
797
- ...allRoutes[currentRouteIndex - 1].meta.children[_length - 1],
798
- type_of_previous: 'ACTIVITY'
799
- } // previous is last page of previous activity
800
- }
801
- // This is a simply another page in an activity
802
- else
803
- this.previousActivity = {
804
- ...this.navigationRoutes.cat[current - 1],
805
- type_of_previous: 'PAGE'
806
- }
807
- break
808
- }
809
- }
810
- } else this.previousActivity = null
811
- },
812
- openPopup(popUpData) {
813
- this.$bus.$emit('open-popup', popUpData)
814
- },
815
-
816
- /**
817
- * @description - send information to open toc
818
- */ openToc() {
819
- this.$bus.$emit('toggle-widget', 'toc')
820
- this.$bus.$emit('info-activity', this.getCurrentPage.activityRef)
821
- },
822
- /**
823
- * @description - send information to open credit and note
824
- */
825
- openCreditNote() {
826
- this.$bus.$emit('toggle-widget', 'noteCredit')
827
- }
828
- }
829
- }
830
- </script>
831
-
832
- <style lang="scss">
833
- .app-nav {
834
- transition: width 0.5s;
835
- position: fixed !important;
836
- top: 0;
837
- left: 0;
838
- z-index: 10;
839
- display: flex;
840
- flex-direction: column;
841
- flex-wrap: wrap;
842
- align-content: start !important;
843
- width: 67px;
844
- height: 100vh;
845
-
846
- .app-ctrl {
847
- display: flex;
848
- flex-direction: column;
849
- align-items: start;
850
- width: 100%;
851
-
852
- #tool-bar {
853
- width: 100%;
854
- padding: 32px 0;
855
- display: flex;
856
- flex-direction: column;
857
- align-items: center;
858
-
859
- & .ctn-w > button,
860
- & > a {
861
- //display: block;
862
- width: 80px;
863
- height: 80px;
864
- padding: 0 !important;
865
- margin-bottom: 24px;
866
- display: flex;
867
- flex-direction: column;
868
- align-content: center;
869
- justify-content: center;
870
- position: relative;
871
-
872
- .home-icon {
873
- width: 22px;
874
- height: 24px;
875
- }
876
-
877
- .toc-icon {
878
- width: 41px;
879
- height: 22px;
880
- }
881
-
882
- .info-icon {
883
- width: 24px;
884
- height: 24px;
885
- }
886
-
887
- span {
888
- &.toolbar_label {
889
- display: block;
890
- transition: opacity 0.5s;
891
- visibility: hidden;
892
- opacity: 0;
893
- }
894
- }
895
-
896
- &.active_toc,
897
- &.active_infos {
898
- &::before {
899
- content: '';
900
- display: block;
901
- position: absolute;
902
- height: 100%;
903
- width: 4px;
904
- left: -16px;
905
- }
906
- }
907
- }
908
-
909
- .ctn-w {
910
- position: relative;
911
- }
912
- }
913
- }
914
-
915
- &:focus,
916
- &:hover,
917
- &.show {
918
- width: 115px !important;
919
-
920
- #tool-bar {
921
- & .ctn-w > button,
922
- a {
923
- span.toolbar_label {
924
- visibility: visible;
925
- opacity: 1;
926
- }
927
- }
928
- }
929
- }
930
- }
931
-
932
- #primary_nav_wrapper {
933
- display: flex;
934
- flex-direction: row;
935
- flex-wrap: wrap;
936
- align-content: center;
937
- justify-content: center;
938
- margin: 25px 0;
939
-
940
- #btn_previous_page,
941
- #btn_next_page {
942
- border-radius: 50px;
943
- width: 45px;
944
- height: 45px;
945
- display: flex;
946
- justify-content: center;
947
-
948
- /*svg {
949
- width: 100%;
950
- height: auto;
951
- }*/
952
- }
953
-
954
- .pagination {
955
- display: flex;
956
- align-items: center;
957
- justify-content: center;
958
- }
959
- }
960
- </style>
1
+ <!-- About this Component--
2
+ @ Description: This component is used to display and create the navigation in el+ mode.
3
+ @ What it does: Create the link to back back to the menu. Create link to the all the anchor to the current activity and display the curent anchor and the button next page and previous page. Teleport are use to place the element in the rigth place in the main frame.
4
+ -->
5
+ <template>
6
+ <div v-if="navigationRoutes" class="app-ctrl">
7
+ <div id="tool-bar">
8
+ <router-link
9
+ id="btn_back_summary"
10
+ :to="{ name: homeLanding.route }"
11
+ class="btn"
12
+ :title="homeLanding.title"
13
+ >
14
+ <template #default>
15
+ <svg class="home-icon">
16
+ <use href="#home-icon" />
17
+ </svg>
18
+
19
+ <span class="toolbar_label">{{ homeLanding.title }}</span>
20
+ </template>
21
+ </router-link>
22
+ <div class="ctn-w">
23
+ <app-base-button
24
+ id="toc"
25
+ :title="$t('button.toc')"
26
+ :aria-label="$t('button.toc')"
27
+ @click="openToc()"
28
+ >
29
+ <svg class="toc-icon">
30
+ <use href="#toc-icon" />
31
+ </svg>
32
+ <span class="toolbar_label">{{ $t('button.toc') }}</span>
33
+ </app-base-button>
34
+ <app-comp-table-of-content />
35
+ </div>
36
+ <div class="ctn-w">
37
+ <app-base-button
38
+ id="btn_infos"
39
+ :title="$t('button.info')"
40
+ :aria-label="$t('button.info')"
41
+ :disabled="noInfo"
42
+ :class="{ md_disabled: noInfo }"
43
+ @click="openCreditNote()"
44
+ >
45
+ <svg class="info-icon">
46
+ <use href="#info-icon" />
47
+ </svg>
48
+ <span class="toolbar_label">{{ $t('button.info') }}</span>
49
+ </app-base-button>
50
+ <app-comp-note-credit />
51
+ </div>
52
+ </div>
53
+
54
+ <!-- Navigation principale -->
55
+
56
+ <SafeTeleport to="#primary_nav_wrapper">
57
+ <template v-if="!isMenu">
58
+ <app-base-button
59
+ id="btn_previous_page"
60
+ ref="btn_previous_page"
61
+ class="nav_main_btn primary_nav_btn"
62
+ :title="$t('button.go_to_previous_page')"
63
+ :aria-label="$t('button.go_to_previous_page')"
64
+ :is-active="!backAllowed"
65
+ @click="goPrevious"
66
+ >
67
+ <svg>
68
+ <use href="#fleche-gauche-icon" />
69
+ </svg>
70
+ </app-base-button>
71
+ <div class="pagination">
72
+ <span aria-hidden="true">
73
+ Page {{ pagination.counter }} / {{ pagination.total }}
74
+ </span>
75
+ <span class="sr-only">
76
+ Page {{ pagination.counter }} {{ pagination.$W }}
77
+ {{ pagination.total }}
78
+ </span>
79
+ </div>
80
+ <app-base-button
81
+ id="btn_next_page"
82
+ ref="btn_next_page"
83
+ class="nav_main_btn primary_nav_btn"
84
+ :aria-label="$t('button.go_to_next_page')"
85
+ :title="$t('button.go_to_next_page')"
86
+ :is-active="!nextAllowed"
87
+ @click="goNext"
88
+ >
89
+ <svg>
90
+ <use href="#fleche-droite-icon"></use>
91
+ </svg>
92
+ </app-base-button>
93
+ </template>
94
+ </SafeTeleport>
95
+ <!---------------------------- TEST ------------------------->
96
+ <!---------------------------- END_ACTIVITY_POPUP SECTION ------------------------->
97
+
98
+ <SafeTeleport
99
+ v-if="endActivityPopup && getEndPopUp"
100
+ defer
101
+ to="#end-activity"
102
+ >
103
+ <div class="popup-bottom-buttons">
104
+ <app-base-button
105
+ :aria-label="endActivityPopup.backLabel"
106
+ :title="endActivityPopup.backLabel"
107
+ class="popup_primary_nav_btn btn btn-reserve"
108
+ @click="navigateTo(endActivityPopup.backRoute)"
109
+ >
110
+ {{ endActivityPopup.backLabel }}
111
+ </app-base-button>
112
+
113
+ <app-base-button
114
+ :aria-label="endActivityPopup.nextLabel"
115
+ :title="endActivityPopup.nextLabel"
116
+ class="popup_primary_nav_btn btn btn-main"
117
+ @click="navigateTo(endActivityPopup.nextRoute)"
118
+ >
119
+ {{ endActivityPopup.nextLabel }}
120
+ </app-base-button>
121
+ </div>
122
+ </SafeTeleport>
123
+ <!---------------------------- END END_ACTIVITY_POPUP SECTION ------------------------->
124
+ </div>
125
+ </template>
126
+
127
+ <script>
128
+ import { mapState, mapActions } from 'pinia'
129
+ import { useAppStore } from '../module/stores/appStore'
130
+ export default {
131
+ props: {
132
+ autoNavigate: { type: Boolean, default: false }
133
+ },
134
+
135
+ data() {
136
+ return {
137
+ hasMedia: false,
138
+ mediaType: null,
139
+ mediaPlaybackEnd: false,
140
+ navigation: {},
141
+ currentPath: null,
142
+ navigationRoutes: null,
143
+ currentActivity: null,
144
+ currentPageId: null,
145
+ anchors: [],
146
+ pageInfo: null,
147
+ nextActivity: null,
148
+ nextActivityRoute: null
149
+ }
150
+ },
151
+ computed: {
152
+ ...mapState(useAppStore, [
153
+ 'getCurrentPage',
154
+ 'getModuleInfo',
155
+ 'getIntroStatus',
156
+ 'getUserInteraction',
157
+ 'getAnchorsForActivity',
158
+ 'getAppConfigs',
159
+ 'getBifChoice',
160
+ 'getMenuSettings',
161
+ 'getWidgetOpen',
162
+ 'getDataNoteCredit',
163
+ 'getPopStatus',
164
+ 'getEndPopUp'
165
+ ]),
166
+ noInfo() {
167
+ if (this.getDataNoteCredit.note || this.getDataNoteCredit.credit) {
168
+ return false
169
+ } else return true
170
+ },
171
+
172
+ /// MUST BE MODIFY BECAUSE MENU IS VIEW NOW
173
+ pagination() {
174
+ let p = { counter: null, total: null }
175
+
176
+ p['$W'] = this.$i18n.locale === 'fr' ? 'de' : 'of'
177
+
178
+ p.counter =
179
+ this.navigationRoutes.cat.findIndex(
180
+ (route) => route._ref === this.$route.meta.id
181
+ ) + 1
182
+
183
+ p.total = this.navigationRoutes.cat.length
184
+
185
+ return p
186
+ },
187
+
188
+ backAllowed() {
189
+ let isAllowed = true // by default
190
+ const { all_routes } = this.$helper.getRoutesFromVueRouter() // get all route of all activities
191
+ const theFirstRoute = all_routes[0].children[0] // get first route of 1st activity
192
+
193
+ //Prevent back to previous when 1st page of the 1st group of activities
194
+ if (theFirstRoute.name === this.$route.name) isAllowed = false
195
+
196
+ return isAllowed
197
+ },
198
+ nextAllowed() {
199
+ let isAllowed
200
+
201
+ //const { auto_next_activity } = this.getAppConfigs
202
+ const { all_routes } = this.$helper.getRoutesFromVueRouter() // get all route of all activities
203
+ let lastRoute = null
204
+
205
+ if (!this.autoNavigate) {
206
+ lastRoute = this.navigationRoutes.cat.toReversed()[0] //get last route in courant route catalogue
207
+ //block navigation at the end of an activity (last route of current activity)
208
+ isAllowed = lastRoute._namedRoute === this.$route.name ? false : true
209
+ } else {
210
+ lastRoute = all_routes.toReversed()[0].children.toReversed()[0] // get the last route of last activity
211
+
212
+ //block navigation when current route is last route and there is no next lesson
213
+ isAllowed =
214
+ lastRoute.name === this.$route.name && !this.nextLesson ? false : true
215
+ }
216
+
217
+ return isAllowed
218
+ },
219
+
220
+ isMenu() {
221
+ return this.$route.name === 'menu'
222
+ },
223
+
224
+ nextLesson() {
225
+ const { linkedResource } = this.getAppConfigs
226
+ if (linkedResource) return linkedResource
227
+ else return null
228
+ },
229
+
230
+ previousLabel() {
231
+ let label =
232
+ this.$route.meta.id !== 'P01' ? this.$t('button.previous') : ''
233
+
234
+ return label
235
+ },
236
+
237
+ nextLabel() {
238
+ const lastRoute = this.navigationRoutes.cat.toReversed()[0] // get the last route by reversing the order of the navigation catalog
239
+ let label =
240
+ this.$route.meta.id !== lastRoute._ref
241
+ ? this.$t('button.go_to_next_page')
242
+ : this.$t('button.carousel_next')
243
+ return label
244
+ },
245
+
246
+ homeLanding() {
247
+ let { no_menu: noMenu } = this.getAppConfigs
248
+ const activityRoutes = this.$helper.getRoutesFromVueRouter()
249
+ //Get the 1st route from the list of routes
250
+ const bckRoute = activityRoutes.meta.children[0]
251
+ return noMenu
252
+ ? {
253
+ title: this.$t('button.go_to_first_page'),
254
+ route: bckRoute._namedRoute
255
+ }
256
+ : { title: this.$t('button.menu'), route: 'menu' }
257
+ },
258
+
259
+ endActivityPopup() {
260
+ let content = null
261
+
262
+ let { no_menu: noMenu } = this.getAppConfigs
263
+
264
+ if (!this.nextActivity) return
265
+
266
+ switch (true) {
267
+ // Next is an activity and there is no menu
268
+ case this.nextActivity.type_of_next === 'ACTIVITY' && noMenu: {
269
+ const activityRoutes = this.$helper.getRoutesFromVueRouter(
270
+ this.$route.meta.activity_ref
271
+ )
272
+ //Get the 1st route from the list of routes of this current activity
273
+ const bckRoute = activityRoutes.meta.children[0]
274
+ content = {
275
+ nextLabel: this.$t('button.next_activity'),
276
+ backLabel: this.$t('button.go_to_first_page'),
277
+ nextRoute: this.nextActivity._namedRoute,
278
+ backRoute: bckRoute._namedRoute,
279
+ nextEnabled: true,
280
+ backEnabled: true
281
+ }
282
+ break
283
+ }
284
+ // Next is an activity and there is a menu
285
+ case this.nextActivity.type_of_next === 'ACTIVITY' && !noMenu:
286
+ content = {
287
+ nextLabel: this.$t('button.next_activity'),
288
+ backLabel: this.$t('button.go_to_menu'),
289
+ nextRoute: this.nextActivity._namedRoute,
290
+ backRoute: 'menu',
291
+ nextEnabled: true,
292
+ backEnabled: true
293
+ }
294
+ break
295
+ // Next is a lesson and there is no menu
296
+ case this.nextActivity.type_of_next === 'LESSON' && noMenu: {
297
+ const activityRoutes = this.$helper.getRoutesFromVueRouter()
298
+ //Get the 1st route from the list of routes
299
+ const bckRoute = activityRoutes.meta.children[0]
300
+ content = {
301
+ nextLabel: this.$t('button.go_to_lesson'),
302
+ backLabel: this.$t('button.go_to_first_page'),
303
+ nextRoute: this.nextLesson,
304
+ backRoute: bckRoute._namedRoute,
305
+ nextEnabled: true,
306
+ //backEnabled: (() => (isSingleActivity ? false : true))() //show back button of the endActivity popup when it is not a single activity.
307
+ backEnabled: true //show back button of the endActivity popup when it is not a single activity.
308
+ }
309
+ break
310
+ }
311
+ // Next is a lesson and there is a menu
312
+ case this.nextActivity.type_of_next === 'LESSON' && !noMenu:
313
+ content = {
314
+ nextLabel: this.$t('button.go_to_lesson'),
315
+ backLabel: this.$t('button.go_to_menu'),
316
+ nextRoute: this.nextLesson,
317
+ backRoute: 'menu',
318
+ nextEnabled: true,
319
+ backEnabled: true
320
+ }
321
+ break
322
+ }
323
+
324
+ return content
325
+ }
326
+ },
327
+ watch: {
328
+ $route: {
329
+ handler() {
330
+ this.setNavigation() // reset the navigation context when route change
331
+
332
+ setTimeout(() => {
333
+ this.initPage()
334
+ }, 200)
335
+ },
336
+ deep: true
337
+ }
338
+ },
339
+ beforeUnmount() {
340
+ this.$bus.$off('mediaPlaybackEnded', this.onMediaEnded)
341
+ this.$bus.$off('quizNoAnswer', this.showPopupNoAnswer)
342
+ },
343
+ mounted() {
344
+ this.$bus.$on('mediaPlaybackEnded', this.onMediaEnded)
345
+ this.$bus.$on('quizNoAnswer', this.showPopupNoAnswer)
346
+
347
+ this.setNavigation()
348
+ setTimeout(() => {
349
+ this.initPage()
350
+ }, 200)
351
+ },
352
+ methods: {
353
+ ...mapActions(useAppStore, ['updateNextActivity']),
354
+ initPage() {
355
+ this.setNextActivity()
356
+ this.setPreviousActivity()
357
+ },
358
+
359
+ getActivity() {
360
+ const { all_routes } = this.$helper.getRoutesFromVueRouter()
361
+ const activity = all_routes.find(
362
+ (route) =>
363
+ route.meta.id === this.$router.currentRoute.value.meta.activity_ref
364
+ )
365
+ return activity
366
+ },
367
+ onMediaEnded() {
368
+ this.mediaPlaybackEnd = true
369
+ },
370
+ navigateTo(path) {
371
+ if (path.constructor === Object)
372
+ return this.$bus.$emit(
373
+ 'launch-xapi-resource',
374
+ this.$helper.getNextLessonEnv(this.nextLesson)
375
+ )
376
+
377
+ if (!path) return this.$bus.$emit('close-popup')
378
+
379
+ this.$router.push({
380
+ name: path
381
+ })
382
+ },
383
+ /** *****************Nav Methods*********************** */
384
+ // TO TEST!!!!
385
+ getNextPageBifurcationNochoice(activity, page) {
386
+ let menu = this.getMenuSettings
387
+ let bif
388
+ //return if the page you are on is a declare as branching in menuSetting
389
+ menu[activity].anchors.forEach((value) => {
390
+ if (value.pageRef == page && value.branching) {
391
+ bif = true
392
+ }
393
+ })
394
+
395
+ return bif
396
+ },
397
+ // TO TEST!!!!
398
+ getFirtsPageBif(activity, page) {
399
+ let data
400
+
401
+ // play string to make path sentence
402
+ if (page.indexOf('0') == 1) {
403
+ data = `page_${page.substring(page.indexOf('P') + 2)}`
404
+ } else {
405
+ data = `page_${page.substring(page.indexOf('P') + 1)}`
406
+ }
407
+ let menu = this.getMenuSettings
408
+ let back = false
409
+
410
+ //return if the page you are on is a declare as branching in menuSetting
411
+ menu[activity].anchors.forEach((value) => {
412
+ if (value.branching && value.branching.end == data) {
413
+ back = true
414
+ }
415
+ })
416
+
417
+ return back
418
+ },
419
+ // TO TEST!!!!
420
+ getPageNavBif(activity, page) {
421
+ let menu = this.getMenuSettings
422
+ let data
423
+
424
+ // return data star and end page
425
+ menu[activity].anchors.forEach((value) => {
426
+ if (value.pageRef == page && value.branching) {
427
+ data = value.branching
428
+ }
429
+ })
430
+
431
+ return data
432
+ },
433
+ // TO TEST!!!!
434
+ getPageNavBifStart(activity, page) {
435
+ let data
436
+
437
+ // play string to make path sentence
438
+ if (page.indexOf('0') == 1) {
439
+ data = `page_${page.substring(page.indexOf('P') + 2)}`
440
+ } else {
441
+ data = `page_${page.substring(page.indexOf('P') + 1)}`
442
+ }
443
+ let menu = this.getMenuSettings
444
+ let back
445
+
446
+ //return the start page of bif
447
+ menu[activity].anchors.forEach((value) => {
448
+ if (value.branching && value.branching.end == data) {
449
+ back = value.branching.start
450
+ }
451
+ })
452
+
453
+ return back
454
+ },
455
+ /** @description Method to handle navigation to next content.
456
+ * At the end of Navigation:
457
+ * - Emit completion status for activity
458
+ * - Opens a popup at the end Of activity or Lesson
459
+ * @fires send-completion-event - completion of ACTIVITY
460
+ * @fires 'close-widget' - close credit widget
461
+ *
462
+ */
463
+ goNext() {
464
+ const pageIndex = this.navigationRoutes.cat.findIndex(
465
+ (route) => route._ref === this.$route.meta.id
466
+ )
467
+ const next = pageIndex + 1
468
+
469
+ //=====================BIF HANDLING =============================
470
+ // check if you did made a choice
471
+ if (
472
+ !this.getBifChoice &&
473
+ this.getNextPageBifurcationNoChoice(
474
+ this.$route.meta.activity_ref,
475
+ this.$route.meta.id
476
+ )
477
+ ) {
478
+ // create path to make the jump
479
+ return this.$router.push({
480
+ name: `${this.navigationRoutes.cat[0]._namedRoute}.${
481
+ this.getPageNavBif(
482
+ this.$route.meta.activity_ref,
483
+ this.$route.meta.id
484
+ ).end
485
+ }`
486
+ })
487
+ }
488
+ //=====================END BIF HANDLING =============================
489
+ if (!this.nextActivity) return
490
+ //Handle navigation to page, activity or Lesson
491
+ switch (true) {
492
+ // Next navigate lead to next page of the current liste
493
+ case this.nextActivity.type_of_next === 'PAGE':
494
+ this.$router.push({
495
+ name: `${this.navigationRoutes.cat[next]._namedRoute}`
496
+ })
497
+ break
498
+ //Next navigation will lead next activity
499
+ case this.nextActivity.type_of_next === 'ACTIVITY': {
500
+ const endPopup = {
501
+ type: 'popup-endActivity',
502
+ value: {
503
+ title: `${this.$t('popup.text_what_to_do')}`
504
+ }
505
+ }
506
+
507
+ this.openPopup(endPopup)
508
+
509
+ this.nextActivityRoute = this.nextActivity._namedRoute
510
+
511
+ if (this.getModuleInfo.packageType !== 'xapi') return
512
+
513
+ this.$bus.$emit('send-completion-event', 'ACTIVITY')
514
+ break
515
+ }
516
+ //Next navigation will lead next activity
517
+ case this.nextActivity.type_of_next === 'LESSON': {
518
+ const endPopup = {
519
+ type: 'popup-endActivity',
520
+ value: {
521
+ template: `<p>${this.$t('popup.text_what_to_do')}</p>`,
522
+ title: ''
523
+ }
524
+ }
525
+
526
+ this.openPopup(endPopup)
527
+
528
+ this.nextActivityRoute = this.nextLesson
529
+
530
+ if (this.getModuleInfo.packageType !== 'xapi') return
531
+ this.$bus.$emit('send-completion-event', 'ACTIVITY')
532
+
533
+ break
534
+ }
535
+ }
536
+ },
537
+
538
+ //=============================================================
539
+ goPrevious() {
540
+ // ==================normal navigation ====================
541
+
542
+ const pageIndex = this.navigationRoutes.cat.findIndex(
543
+ (route) => route._ref === this.$route.meta.id
544
+ )
545
+ const previous = pageIndex - 1
546
+
547
+ // validate if ther a branching and did you make a choice
548
+ if (
549
+ !this.getBifChoice &&
550
+ this.getFirtsPageBif(this.$route.meta.activity_ref, this.$route.meta.id)
551
+ ) {
552
+ // create path to make the jump
553
+ if (
554
+ this.getPageNavBifStart(
555
+ this.$route.meta.activity_ref,
556
+ this.$route.meta.id
557
+ ) == 'page_1'
558
+ ) {
559
+ this.$router.push({
560
+ name: `${this.navigationRoutes.cat[0]._namedRoute}`
561
+ })
562
+ } else {
563
+ this.$router.push({
564
+ name: `${this.navigationRoutes.cat[0]._namedRoute}.${this.getPageNavBifStart(
565
+ this.$route.meta.activity_ref,
566
+ this.$route.meta.id
567
+ )}`
568
+ })
569
+ }
570
+
571
+ // back to previous page of module (module.page_xx)
572
+ } else if (pageIndex > 0 && this.navigationRoutes.cat[previous]._path) {
573
+ this.$router.push({
574
+ name: `${this.navigationRoutes.cat[previous]._namedRoute}`
575
+ })
576
+ // this is the last page
577
+ } else {
578
+ // if allow navigation to activity active, navigate to previous activity
579
+ if (this.autoNavigate && this.previousActivity) {
580
+ this.$router.push({ name: this.previousActivity._namedRoute })
581
+ } else this.$router.push('/')
582
+ }
583
+ },
584
+ setNavigation() {
585
+ // Close the info widget before navigation
586
+ if (this.getWidgetOpen) {
587
+ this.$bus.$emit('close-widget')
588
+ }
589
+ // current Route is module
590
+ this.currentActivity = this.$router.currentRoute.value.meta.activity_ref
591
+ this.currentPageId = this.$router.currentRoute.value.meta.id
592
+
593
+ const { all_routes, meta } = this.$helper.getRoutesFromVueRouter()
594
+
595
+ if (this.$router.currentRoute.value.name === 'module') {
596
+ this.navigationRoutes = {
597
+ context: 'module',
598
+ cat: meta.children
599
+ }
600
+ }
601
+ // Navigation catalog is the introduction
602
+ else if (
603
+ this.$router.currentRoute.value.meta.type === 'introduction' ||
604
+ this.$router.currentRoute.value.meta.type === 'menu'
605
+ ) {
606
+ const a = all_routes.find(
607
+ (route) =>
608
+ route.meta.id ===
609
+ this.$router.currentRoute.value.meta.activity_ref.$folderName
610
+ )
611
+
612
+ const b = all_routes.find(
613
+ (route) =>
614
+ route.meta.id === this.$router.currentRoute.value.meta.activity_ref
615
+ )
616
+ if (a) {
617
+ let r = []
618
+ //if Intro acitive get all the routes for indroduction or just the menu
619
+ this.getIntroStatus
620
+ ? r.push(...a.meta.children)
621
+ : r.push(
622
+ a.meta.children.find(
623
+ (el) => !el._namedRoute.includes('introduction')
624
+ )
625
+ )
626
+ this.navigationRoutes = {
627
+ context: 'introduction',
628
+ cat: r
629
+ }
630
+ } else if (b) {
631
+ let r = []
632
+ //if Intro acitive get all the routes for indroduction or just the menu
633
+ this.getIntroStatus
634
+ ? r.push(...b.meta.children)
635
+ : r.push(
636
+ b.meta.children.find(
637
+ (el) => !el._namedRoute.includes('introduction')
638
+ )
639
+ )
640
+ this.navigationRoutes = {
641
+ context: 'introduction',
642
+ cat: r
643
+ }
644
+ }
645
+ }
646
+ // Navigation catalog is pages of Activity ||menu
647
+ else {
648
+ const a = all_routes.find(
649
+ (route) =>
650
+ route.meta.id ===
651
+ this.$router.currentRoute.value.meta.activity_ref.$folderName
652
+ )
653
+
654
+ // on refresh $forderName doesn't existe
655
+ const b = all_routes.find(
656
+ (route) =>
657
+ route.meta.id === this.$router.currentRoute.value.meta.activity_ref
658
+ )
659
+
660
+ if (a) {
661
+ this.navigationRoutes = {
662
+ context: 'normal',
663
+ cat: a.meta.children
664
+ }
665
+ } else if (b) {
666
+ this.navigationRoutes = {
667
+ context: 'normal',
668
+ cat: b.meta.children
669
+ }
670
+ }
671
+ }
672
+ }, // END setNaviagation
673
+ /**
674
+ *@description: set the next activity to for the Navigation
675
+ */
676
+ setNextActivity() {
677
+ if (this.navigationRoutes) {
678
+ // get all the activities routes from router
679
+ const { meta } = this.$helper.getRoutesFromVueRouter()
680
+ const allRoutes = meta.children
681
+
682
+ // get the index of the current route
683
+ const current = this.navigationRoutes.cat.findIndex(
684
+ (route) => route._ref === this.$route.meta.id
685
+ )
686
+
687
+ switch (this.navigationRoutes.context) {
688
+ case 'introduction': {
689
+ //Reached the last page in Intro
690
+ if (current === this.navigationRoutes.cat.length - 1) {
691
+ //there is a next activity
692
+ if (allRoutes[1])
693
+ return (this.nextActivity = {
694
+ ...allRoutes[1],
695
+ type_of_next: 'ACTIVITY'
696
+ })
697
+
698
+ //There is a next lesson
699
+ if (this.nextLesson)
700
+ return (this.nextActivity = {
701
+ ...this.nextLesson,
702
+ type_of_next: 'LESSON'
703
+ })
704
+
705
+ //There is nothing
706
+ this.nextActivity = null
707
+ } else {
708
+ //Other pages in Intro
709
+ this.nextActivity = {
710
+ ...this.navigationRoutes.cat[current + 1],
711
+ type_of_next: 'PAGE'
712
+ }
713
+ }
714
+ break
715
+ }
716
+ case 'normal': {
717
+ // find the current activity ref in the router catalog
718
+
719
+ const currentRouteIndex = allRoutes.findIndex(
720
+ (route) => route._ref === this.$route.meta.activity_ref
721
+ )
722
+
723
+ // this is the Last page in current activity
724
+ if (
725
+ current === this.navigationRoutes.cat.length - 1 &&
726
+ allRoutes[currentRouteIndex + 1]
727
+ ) {
728
+ this.nextActivity = {
729
+ ...allRoutes[currentRouteIndex + 1],
730
+ type_of_next: 'ACTIVITY'
731
+ } // get the next activity in the router catalog
732
+ }
733
+ // this is in the same activity return the next page of the activity
734
+ else if (this.navigationRoutes.cat[current + 1]) {
735
+ this.nextActivity = {
736
+ ...this.navigationRoutes.cat[current + 1],
737
+ type_of_next: 'PAGE'
738
+ }
739
+ }
740
+ // There is no other activity after the current one
741
+ else if (this.nextLesson)
742
+ this.nextActivity = { ...this.nextLesson, type_of_next: 'LESSON' }
743
+ else this.nextActivity = null
744
+
745
+ break
746
+ }
747
+ }
748
+ } else this.nextActivity = null
749
+
750
+ this.updateNextActivity(this.nextActivity)
751
+ },
752
+ /**
753
+ * @description: set previous activity for the navigation
754
+ */
755
+ setPreviousActivity() {
756
+ if (this.autoNavigate && this.navigationRoutes) {
757
+ // get all the activities routes from router
758
+ const { all_routes: allRoutes } = this.$helper.getRoutesFromVueRouter()
759
+
760
+ // get the index of the current route
761
+ const current = this.navigationRoutes.cat.findIndex(
762
+ (route) => route._ref === this.$route.meta.id
763
+ )
764
+
765
+ switch (this.navigationRoutes.context) {
766
+ case 'introduction': {
767
+ // This is the first page in the introduction
768
+ if (current === 0) {
769
+ this.previousActivity = null
770
+ } else {
771
+ this.previousActivity = {
772
+ ...this.navigationRoutes.cat[current - 1],
773
+ type_of_previous: 'PAGE'
774
+ }
775
+ }
776
+ break
777
+ }
778
+ case 'normal': {
779
+ // get the index of the current route
780
+ const currentRouteIndex = allRoutes.findIndex(
781
+ (route) => route.meta.id === this.$route.meta.activity_ref
782
+ )
783
+ // this is the 1st page of the 1st activity in the router catalogue
784
+ // return point is introduction
785
+ if (current === 0 && currentRouteIndex === 1) {
786
+ const _length = allRoutes[0].children.length
787
+ this.previousActivity = {
788
+ ...allRoutes[0].meta.children[_length - 1],
789
+ type_of_previous: 'ACTIVITY'
790
+ } // get last page of the introduction navigation context
791
+ }
792
+ // This is the 1st page in another activity in the router catalogue
793
+ else if (allRoutes[currentRouteIndex - 1] && current === 0) {
794
+ const _length = allRoutes[currentRouteIndex - 1].children.length
795
+ this.previousActivity = {
796
+ ...allRoutes[currentRouteIndex - 1].meta.children[_length - 1],
797
+ type_of_previous: 'ACTIVITY'
798
+ } // previous is last page of previous activity
799
+ }
800
+ // This is a simply another page in an activity
801
+ else
802
+ this.previousActivity = {
803
+ ...this.navigationRoutes.cat[current - 1],
804
+ type_of_previous: 'PAGE'
805
+ }
806
+ break
807
+ }
808
+ }
809
+ } else this.previousActivity = null
810
+ },
811
+ openPopup(popUpData) {
812
+ this.$bus.$emit('open-popup', popUpData)
813
+ },
814
+
815
+ /**
816
+ * @description - send information to open toc
817
+ */ openToc() {
818
+ this.$bus.$emit('toggle-widget', 'toc')
819
+ this.$bus.$emit('info-activity', this.getCurrentPage.activityRef)
820
+ },
821
+ /**
822
+ * @description - send information to open credit and note
823
+ */
824
+ openCreditNote() {
825
+ this.$bus.$emit('toggle-widget', 'noteCredit')
826
+ }
827
+ }
828
+ }
829
+ </script>
830
+
831
+ <style lang="scss">
832
+ .app-nav {
833
+ transition: width 0.5s;
834
+ position: fixed !important;
835
+ top: 0;
836
+ left: 0;
837
+ z-index: 10;
838
+ display: flex;
839
+ flex-direction: column;
840
+ flex-wrap: wrap;
841
+ align-content: start !important;
842
+ width: 67px;
843
+ height: 100vh;
844
+
845
+ .app-ctrl {
846
+ display: flex;
847
+ flex-direction: column;
848
+ align-items: start;
849
+ width: 100%;
850
+
851
+ #tool-bar {
852
+ width: 100%;
853
+ padding: 32px 0;
854
+ display: flex;
855
+ flex-direction: column;
856
+ align-items: center;
857
+
858
+ & .ctn-w > button,
859
+ & > a {
860
+ //display: block;
861
+ width: 80px;
862
+ height: 80px;
863
+ padding: 0 !important;
864
+ margin-bottom: 24px;
865
+ display: flex;
866
+ flex-direction: column;
867
+ align-content: center;
868
+ justify-content: center;
869
+ position: relative;
870
+
871
+ .home-icon {
872
+ width: 22px;
873
+ height: 24px;
874
+ }
875
+
876
+ .toc-icon {
877
+ width: 41px;
878
+ height: 22px;
879
+ }
880
+
881
+ .info-icon {
882
+ width: 24px;
883
+ height: 24px;
884
+ }
885
+
886
+ span {
887
+ &.toolbar_label {
888
+ display: block;
889
+ transition: opacity 0.5s;
890
+ visibility: hidden;
891
+ opacity: 0;
892
+ }
893
+ }
894
+
895
+ &.active_toc,
896
+ &.active_infos {
897
+ &::before {
898
+ content: '';
899
+ display: block;
900
+ position: absolute;
901
+ height: 100%;
902
+ width: 4px;
903
+ left: -16px;
904
+ }
905
+ }
906
+ }
907
+
908
+ .ctn-w {
909
+ position: relative;
910
+ }
911
+ }
912
+ }
913
+
914
+ &:focus,
915
+ &:hover,
916
+ &.show {
917
+ width: 115px !important;
918
+
919
+ #tool-bar {
920
+ & .ctn-w > button,
921
+ a {
922
+ span.toolbar_label {
923
+ visibility: visible;
924
+ opacity: 1;
925
+ }
926
+ }
927
+ }
928
+ }
929
+ }
930
+
931
+ #primary_nav_wrapper {
932
+ display: flex;
933
+ flex-direction: row;
934
+ flex-wrap: wrap;
935
+ align-content: center;
936
+ justify-content: center;
937
+ margin: 25px 0;
938
+
939
+ #btn_previous_page,
940
+ #btn_next_page {
941
+ border-radius: 50px;
942
+ width: 45px;
943
+ height: 45px;
944
+ display: flex;
945
+ justify-content: center;
946
+
947
+ /*svg {
948
+ width: 100%;
949
+ height: auto;
950
+ }*/
951
+ }
952
+
953
+ .pagination {
954
+ display: flex;
955
+ align-items: center;
956
+ justify-content: center;
957
+ }
958
+ }
959
+ </style>