fcad-core-dragon 2.0.0-beta.1 → 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 (118) hide show
  1. package/.editorconfig +33 -33
  2. package/.eslintignore +29 -29
  3. package/{.eslintrc.js → .eslintrc.cjs} +81 -86
  4. package/CHANGELOG +364 -364
  5. package/README.md +71 -71
  6. package/bk.scss +117 -0
  7. package/package.json +61 -63
  8. package/src/$locales/en.json +143 -179
  9. package/src/$locales/fr.json +105 -181
  10. package/src/assets/data/onboardingMessages.json +47 -47
  11. package/src/components/AppBase.vue +1054 -614
  12. package/src/components/AppBaseButton.vue +87 -63
  13. package/src/components/AppBaseErrorDisplay.vue +438 -420
  14. package/src/components/AppBaseFlipCard.vue +84 -83
  15. package/src/components/AppBaseModule.vue +1673 -1842
  16. package/src/components/AppBasePage.vue +779 -312
  17. package/src/components/AppBasePopover.vue +41 -0
  18. package/src/components/AppCompAudio.vue +234 -0
  19. package/src/components/AppCompBranchButtons.vue +552 -582
  20. package/src/components/AppCompButtonProgress.vue +126 -147
  21. package/src/components/AppCompCarousel.vue +298 -192
  22. package/src/components/AppCompInputCheckBoxNext.vue +195 -0
  23. package/src/components/AppCompInputDropdownNext.vue +159 -0
  24. package/src/components/AppCompInputRadioNext.vue +152 -0
  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 -55
  30. package/src/components/AppCompMenu.vue +413 -209
  31. package/src/components/AppCompMenuItem.vue +228 -174
  32. package/src/components/AppCompNavigation.vue +960 -949
  33. package/src/components/AppCompNoteCall.vue +133 -126
  34. package/src/components/AppCompNoteCredit.vue +292 -164
  35. package/src/components/AppCompPlayBar.vue +1218 -1319
  36. package/src/components/AppCompPlayBarNext.vue +2052 -0
  37. package/src/components/AppCompPlayBarProgress.vue +82 -0
  38. package/src/components/AppCompPopUpNext.vue +503 -0
  39. package/src/components/{AppCompQuiz.vue → AppCompQuizNext.vue} +2904 -2989
  40. package/src/components/AppCompQuizRecall.vue +276 -250
  41. package/src/components/AppCompSVGNext.vue +347 -0
  42. package/src/components/AppCompSettingsMenu.vue +172 -171
  43. package/src/components/AppCompTableOfContent.vue +387 -264
  44. package/src/components/AppCompTranscript.vue +24 -19
  45. package/src/components/AppCompVideoPlayer.vue +368 -336
  46. package/src/components/AppCompViewDisplay.vue +6 -6
  47. package/src/components/BaseModule.vue +72 -67
  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 -227
  52. package/src/mixins/$mediaMixins.js +819 -0
  53. package/src/mixins/timerMixin.js +155 -156
  54. package/src/module/stores/appStore.js +893 -0
  55. package/src/module/xapi/ADL.js +376 -339
  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 -319
  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 -1890
  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 -295
  85. package/src/plugins/i18n.js +44 -31
  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 -41
  92. package/src/router/routes.js +312 -337
  93. package/src/shared/generalfuncs.js +210 -188
  94. package/src/shared/validators.js +1069 -249
  95. package/vite.config.js +27 -0
  96. package/.prettierrc.js +0 -5
  97. package/babel.config.js +0 -3
  98. package/src/components/AppBaseDragChoice.vue +0 -91
  99. package/src/components/AppBaseDropZone.vue +0 -112
  100. package/src/components/AppCompBif.vue +0 -120
  101. package/src/components/AppCompDragAndDrop.vue +0 -339
  102. package/src/components/AppCompInputAssociation.vue +0 -332
  103. package/src/components/AppCompInputCheckBox.vue +0 -227
  104. package/src/components/AppCompInputDropdown.vue +0 -184
  105. package/src/components/AppCompInputRadio.vue +0 -169
  106. package/src/components/AppCompInputTextTable.vue +0 -155
  107. package/src/components/AppCompInputTextToFillDropdown.vue +0 -255
  108. package/src/components/AppCompMediaPlayer.vue +0 -397
  109. package/src/components/AppCompPopUp.vue +0 -522
  110. package/src/components/AppCompPopover.vue +0 -27
  111. package/src/components/AppCompSVG.vue +0 -309
  112. package/src/mixins/$pageMixins.js +0 -459
  113. package/src/mixins/$quizMixins.js +0 -456
  114. package/src/module/store.js +0 -895
  115. package/src/plugins/timeManager.js +0 -77
  116. package/src/routes_bckp.js +0 -313
  117. package/src/routes_static.js +0 -344
  118. package/vue.config.js +0 -83
@@ -1,949 +1,960 @@
1
- <!--
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. Portal 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
- <b-link
9
- id="btn_back_summary"
10
- :to="{ name: 'menu' }"
11
- class="btn btn-ghost"
12
- :title="$t('button.menu')"
13
- >
14
- <svg width="20" height="17">
15
- <use href="#home-icon" />
16
- </svg>
17
- <span>{{ $t('button.menu') }}</span>
18
- </b-link>
19
-
20
- <app-base-button id="toc" @click="openToc()">
21
- <svg width="20" height="17">
22
- <use href="#timeline-icon" />
23
- </svg>
24
- <span>{{ $t('button.toc') }}</span>
25
- </app-base-button>
26
-
27
- <app-base-button @click="openCreditNote()">
28
- <svg width="20" height="17">
29
- <use href="#info-icon" />
30
- </svg>
31
- <span>{{ $t('button.info') }}</span>
32
- </app-base-button>
33
- </div>
34
-
35
- <!-- Navigation principale -->
36
-
37
- <portal v-if="!isMenu" to="primary_nav">
38
- <button
39
- id="btn_previous_page"
40
- ref="btn_previous_page"
41
- :title="previousLabel"
42
- class="nav_main_btn primary_nav_btn"
43
- :class="{ md_disabled: !backAllowed || !enableNavLeftBtn }"
44
- :disabled="!backAllowed || !enableNavLeftBtn"
45
- @click="goPrevious"
46
- >
47
- <svg width="24" height="24">
48
- <use href="#navigate-previous-icon" fill="#fff" />
49
- </svg>
50
- </button>
51
- <button
52
- id="btn_next_page"
53
- ref="btn_next_page"
54
- :title="nextLabel"
55
- class="nav_main_btn primary_nav_btn"
56
- :class="{ md_disabled: !enableNavRightBtn }"
57
- :disabled="!enableNavRightBtn"
58
- @click="goNext"
59
- >
60
- <svg
61
- v-show="!nextLesson && !nextActivity"
62
- width="11.667"
63
- height="11.46"
64
- >
65
- <use href="#fleche-retour-icon" fill="#fff" />
66
- </svg>
67
- <svg v-show="nextLesson || nextActivity" width="7.41" height="12">
68
- <use href="#navigate-next-icon" fill="#fff"></use>
69
- </svg>
70
- </button>
71
- </portal>
72
- <!---------------------------- TEST ------------------------->
73
-
74
- <portal v-if="endActivityPopup" to="wrap-end-activity">
75
- <button @click="navigateTo(endActivityPopup.backRoute)">
76
- <span>{{ endActivityPopup.backLabel }}</span>
77
-
78
- <svg v-show="!nextLesson" width="11.667" height="11.46">
79
- <use href="#fleche-retour-icon" fill="#fff" />
80
- </svg>
81
- <svg v-show="nextLesson" width="7.41" height="12">
82
- <use href="#navigate-next-icon" fill="#fff"></use>
83
- </svg>
84
- </button>
85
-
86
- <button @click="navigateTo(endActivityPopup.nextRoute)">
87
- {{ endActivityPopup.nextLabel }}
88
- </button>
89
- </portal>
90
-
91
- <!---------------------------- END TEST ------------------------->
92
- <app-comp-settings-menu />
93
- <app-comp-table-of-content></app-comp-table-of-content>
94
- <app-comp-note-credit></app-comp-note-credit>
95
- </div>
96
- </template>
97
-
98
- <script>
99
- import { mapGetters } from 'vuex'
100
- import AppCompSettingsMenu from './AppCompSettingsMenu.vue'
101
- export default {
102
- components: { AppCompSettingsMenu },
103
- props: {
104
- autoNavigate: { type: Boolean, default: false }
105
- },
106
-
107
- data() {
108
- return {
109
- nextPageLabel: null,
110
- hasMedia: false,
111
- mediaType: null,
112
- mediaPlaybackEnd: false,
113
- navigation: {},
114
- currentPath: null,
115
- navigationRoutes: null,
116
- currentActivity: null,
117
- currentPageId: null,
118
- anchors: [],
119
- pageInfo: null,
120
- nextActivity: null,
121
- nextLabel: 'next',
122
- nextActivityRoute: null
123
- }
124
- },
125
- computed: {
126
- ...mapGetters([
127
- 'getCurrentPage',
128
- 'getModuleChildren',
129
- 'getIntroStatus',
130
- 'getUserInteraction',
131
- 'getAnchorsForActivity',
132
- 'getConnectionInfo',
133
- 'getAppConfigs',
134
- 'getPageData',
135
- 'getAllActivitiesState',
136
- 'getShowPrimaryCtrl',
137
- 'getShowNavRightCtrl',
138
- 'getShowNavLeftCtrl',
139
- 'getBifChoice',
140
- 'getMenuSettings'
141
- ]),
142
-
143
- // /// WAITING FOR UX UI CONCLUSION TO MODIF
144
- finalPageBtnLabel() {
145
- let label
146
- if (!this.nextLesson) {
147
- label = this.$t('button.back_to_menu')
148
- } else if (this.nextLesson && this.getAppConfigs.nextConcluModule) {
149
- label = this.$t('button.go_to_module_conclusion')
150
- } else if (this.nextLesson && !this.getAppConfigs.nextConcluModule) {
151
- label = this.$t('button.go_to_lesson')
152
- }
153
- return label
154
- },
155
-
156
- /// MUST BE MODIFY BECAUSE MENU IS VIEW NOW
157
- pagination() {
158
- let p = { counter: null, total: null }
159
-
160
- const { context } = this.navigationRoutes
161
-
162
- switch (context) {
163
- /* In the context of introduction, menu should not be counted in the pagination*/
164
- case 'introduction':
165
- {
166
- if (this.$route.name === 'menu') p.counter = 0
167
-
168
- p.total = this.navigationRoutes.cat.filter(
169
- (route) => route._path !== 'menu'
170
- ).length
171
-
172
- p.counter = this.navigationRoutes.cat.findIndex(
173
- (route) => route._ref === this.$route.meta.id
174
- )
175
- }
176
- break
177
-
178
- default:
179
- p.counter =
180
- this.navigationRoutes.cat.findIndex(
181
- (route) => route._ref === this.$route.meta.id
182
- ) + 1
183
-
184
- p.total = this.navigationRoutes.cat.length
185
- }
186
- return p
187
- },
188
- /**
189
- * TO MODIFY AFTER UX/UI
190
- */
191
- backAllowed() {
192
- let isAllowed = true // by default
193
- // Navigation to next/previous activity is permitted. prevent negate navigation in conditions bellow.
194
- if (this.autoNavigate) {
195
- switch (this.navigationRoutes.context) {
196
- case 'introduction':
197
- if (this.$route.meta.id === this.navigationRoutes.cat[0]._ref)
198
- isAllowed = false
199
- break
200
- case 'normal':
201
- if (
202
- this.previousActivity &&
203
- this.previousActivity._namedRoute === 'introduction'
204
- )
205
- isAllowed = false
206
- break
207
- }
208
- }
209
- // Navigation to next/previous activity has not been permitted.
210
- else if (this.$route.meta.id === this.navigationRoutes.cat[0]._ref)
211
- isAllowed = false
212
- return isAllowed
213
- },
214
- /**
215
- * TO MODIFY AFTER UX/UI
216
- */
217
- nextAllowed() {
218
- let isAllowed = true
219
- const { length } = this.navigationRoutes.cat
220
-
221
- if (this.autoNavigate) {
222
- // Check if there is a next activity (could be page a page of current activity or page of next activity)
223
- if (!this.nextActivity) isAllowed = false
224
- } else {
225
- if (this.$route.meta.id === this.navigationRoutes.cat[length - 1]._ref)
226
- isAllowed = false
227
- }
228
- return isAllowed
229
- },
230
- isMenu() {
231
- return this.$route.name === 'menu'
232
- },
233
- nextLesson() {
234
- const { linkedResource } = this.getAppConfigs
235
- if (linkedResource) return linkedResource
236
- else return null
237
- },
238
- /**
239
- * TO MODIFY AFTER UX/UI
240
- */
241
- previousLabel() {
242
- let label = this.$route.meta
243
- if (
244
- this.$route.meta.activity_ref == 'A00' &&
245
- this.$route.meta.id == 'P01'
246
- ) {
247
- label = this.$t('button.back_to_menu')
248
- } else if (
249
- this.$route.meta.activity_ref == 'A01' &&
250
- this.$route.meta.id == 'P01'
251
- ) {
252
- label = this.$t('button.go_to_introduction')
253
- } else {
254
- label = this.$t('button.previous')
255
- }
256
-
257
- return label
258
- },
259
- /**
260
- * TO MODIFY AFTER UX/UI
261
- */
262
- enablePrimaryBtn() {
263
- return this.getShowPrimaryCtrl
264
- },
265
- /**
266
- * TO MODIFY AFTER UX/UI
267
- */
268
- enableNavLeftBtn() {
269
- return this.getShowNavLeftCtrl
270
- },
271
- /**
272
- * TO MODIFY AFTER UX/UI
273
- */
274
- enableNavRightBtn() {
275
- return this.getShowNavRightCtrl
276
- },
277
- endActivityPopup() {
278
- let content = null
279
-
280
- let noMenu = this.$helper.getSettingsFromStore('no_menu')
281
-
282
- switch (true) {
283
- case this.nextActivity && noMenu: {
284
- const activityRoutes = this.$helper.getRoutesFromVueRouter(
285
- this.$route.meta.activity_ref
286
- )
287
- //Get the 1st route from the list of routes of this current activity
288
- const bckRoute = activityRoutes.meta.children[0]
289
- content = {
290
- nextLabel: this.$t('button.next_activity'),
291
- backLabel: this.$t('button.back_to_first_page'),
292
- nextRoute: this.nextActivity._namedRoute,
293
- backRoute: bckRoute._namedRoute
294
- }
295
- break
296
- }
297
-
298
- case this.nextActivity && !noMenu:
299
- content = {
300
- nextLabel: this.$t('button.next_activity'),
301
- backLabel: this.$t('button.go_to_menu'),
302
- nextRoute: this.nextActivity._namedRoute,
303
- backRoute: 'menu'
304
- }
305
- break
306
-
307
- case this.nextLesson && noMenu: {
308
- const activityRoutes = this.$helper.getRoutesFromVueRouter()
309
- //Get the 1st route from the list of routes
310
- const bckRoute = activityRoutes.meta.children[0]
311
- content = {
312
- nextLabel: this.$t('button.go_to_lesson'),
313
- backLabel: this.$t('button.back_to_first_page'),
314
- nextRoute: this.nextLesson,
315
- backRoute: bckRoute._namedRoute
316
- }
317
- break
318
- }
319
-
320
- case this.nextLesson && !noMenu:
321
- content = {
322
- nextLabel: this.$t('button.go_to_lesson'),
323
- backLabel: this.$t('button.go_to_menu'),
324
- nextRoute: this.nextLesson,
325
- backRoute: 'menu'
326
- }
327
- break
328
-
329
- case !this.nextLesson && noMenu && !this.nextActivity: {
330
- const activityRoutes = this.$helper.getRoutesFromVueRouter()
331
-
332
- //Get the 1st route from the list of routes
333
- const bckRoute = activityRoutes.meta.children[0]
334
- content = {
335
- nextLabel: this.$t('button.stay_on_page'),
336
- backLabel: this.$t('button.back_to_first_page'),
337
- nextRoute: '',
338
- backRoute: bckRoute._namedRoute
339
- }
340
- break
341
- }
342
-
343
- case !this.nextLesson && !noMenu && !this.nextActivity:
344
- content = {
345
- nextLabel: this.$t('button.stay_on_page'),
346
- backLabel: this.$t('button.go_to_menu'),
347
- nextRoute: '',
348
- backRoute: 'menu'
349
- }
350
- break
351
- }
352
-
353
- return content
354
- }
355
- },
356
- watch: {
357
- $route() {
358
- this.setNavigation() // reset the navigation context when route change
359
- setTimeout(() => {
360
- this.initPage()
361
- }, 200)
362
- }
363
- },
364
- mounted() {
365
- this.$bus.$on('mediaPlaybackEnded', this.onMediaEnded)
366
- this.$bus.$on('quizNoAnswer', this.showPopupNoAnswer)
367
-
368
- this.setNavigation()
369
- setTimeout(() => {
370
- this.initPage()
371
- }, 200)
372
- },
373
- methods: {
374
- initPage() {
375
- // TO CLEANNING
376
-
377
- this.setNextActivity()
378
- this.setPreviousActivity()
379
- },
380
- // TO CLEANNING WAITING FOR NEW PLAYER
381
- getMediaInfo() {
382
- this.hasMedia = this.pageInfo.type === 'pg_media'
383
- if (this.hasMedia) {
384
- this.mediaType = this.pageInfo.mediaData.mType
385
- }
386
- },
387
- getActivity() {
388
- const { all_routes } = this.$helper.getRoutesFromVueRouter()
389
- const activity = all_routes.find(
390
- (route) => route.meta.id === this.$router.currentRoute.meta.activity_ref
391
- )
392
- return activity
393
- },
394
- onMediaEnded() {
395
- this.mediaPlaybackEnd = true
396
- },
397
- //TO MODIFY AFTER UX/UI
398
- navigateTo(path) {
399
- if (path.constructor === Object)
400
- return this.$bus.$emit(
401
- 'launch-xapi-resource',
402
- this.$helper.getNextLessonEnv(this.nextLesson)
403
- )
404
-
405
- if (!path) return this.$bus.$emit('close-popup')
406
-
407
- this.$router.push({
408
- name: path
409
- })
410
- },
411
- /** *****************Nav Methods*********************** */
412
- // TO TEST!!!!
413
- getNextPageBifurcationNochoice(activity, page) {
414
- let menu = this.getMenuSettings
415
- let bif
416
- //return if the page you are on is a declare as branching in menuSetting
417
- menu[activity].anchors.forEach((value) => {
418
- if (value.pageRef == page && value.branching) {
419
- bif = true
420
- }
421
- })
422
-
423
- return bif
424
- },
425
- // TO TEST!!!!
426
- getFirtsPageBif(activity, page) {
427
- let data
428
-
429
- // play string to make path sentence
430
- if (page.indexOf('0') == 1) {
431
- data = `page_${page.substring(page.indexOf('P') + 2)}`
432
- } else {
433
- data = `page_${page.substring(page.indexOf('P') + 1)}`
434
- }
435
- let menu = this.getMenuSettings
436
- let back = false
437
-
438
- //return if the page you are on is a declare as branching in menuSetting
439
- menu[activity].anchors.forEach((value) => {
440
- if (value.branching && value.branching.end == data) {
441
- back = true
442
- }
443
- })
444
-
445
- return back
446
- },
447
- // TO TEST!!!!
448
- getPageNavBif(activity, page) {
449
- let menu = this.getMenuSettings
450
- let data
451
-
452
- // return data star and end page
453
- menu[activity].anchors.forEach((value) => {
454
- if (value.pageRef == page && value.branching) {
455
- data = value.branching
456
- }
457
- })
458
-
459
- return data
460
- },
461
- // TO TEST!!!!
462
- getPageNavBifStart(activity, page) {
463
- let data
464
-
465
- // play string to make path sentence
466
- if (page.indexOf('0') == 1) {
467
- data = `page_${page.substring(page.indexOf('P') + 2)}`
468
- } else {
469
- data = `page_${page.substring(page.indexOf('P') + 1)}`
470
- }
471
- let menu = this.getMenuSettings
472
- let back
473
-
474
- //return the start page of bif
475
- menu[activity].anchors.forEach((value) => {
476
- if (value.branching && value.branching.end == data) {
477
- back = value.branching.start
478
- }
479
- })
480
-
481
- return back
482
- },
483
- goNext() {
484
- this.$bus.$emit('close-widget')
485
-
486
- const pageIndex = this.navigationRoutes.cat.findIndex(
487
- (route) => route._ref === this.$route.meta.id
488
- )
489
- const next = pageIndex + 1
490
-
491
- // check if you did made a choice
492
- if (
493
- !this.getBifChoice &&
494
- this.getNextPageBifurcationNoChoice(
495
- this.$route.meta.activity_ref,
496
- this.$route.meta.id
497
- )
498
- ) {
499
- // create path to make the jump
500
- this.$router.push({
501
- name: `${this.navigationRoutes.cat[0]._namedRoute}.${
502
- this.getPageNavBif(
503
- this.$route.meta.activity_ref,
504
- this.$route.meta.id
505
- ).end
506
- }`
507
- })
508
- }
509
- // Last page not reached. Navigate to the next page of the current liste
510
- else if (pageIndex > -1 && this.navigationRoutes.cat[next]) {
511
- this.$router.push({
512
- name: `${this.navigationRoutes.cat[next]._namedRoute}`
513
- })
514
- }
515
-
516
- // last page of the current list reached. Navigate to next lesson
517
- else if (this.autoNavigate && this.nextActivity) {
518
- this.openPopup(
519
- {
520
- type: 'popup-endActivity',
521
- value: {
522
- title: this.$t('popup.text_congratulation'),
523
-
524
- hypertext_1: `<p>${this.$t('text.title_end_activity')}<p>`
525
- }
526
- },
527
- 'no_attempts'
528
- )
529
- this.nextActivityRoute = this.nextActivity._namedRoute
530
-
531
- // if choice not made jump to end of bifurcation
532
- } else {
533
- this.openPopup(
534
- {
535
- type: 'popup-endActivity',
536
- value: {
537
- title: '',
538
-
539
- hypertext_1: `<p>${this.$t('text.title_end_activity')}<p>`
540
- }
541
- },
542
- 'no_attempts'
543
- )
544
- this.nextActivityRoute = this.nextLesson
545
- }
546
- },
547
-
548
- goPrevious() {
549
- // ==================normal navigation ====================
550
-
551
- const pageIndex = this.navigationRoutes.cat.findIndex(
552
- (route) => route._ref === this.$route.meta.id
553
- )
554
- const previous = pageIndex - 1
555
-
556
- this.$bus.$emit('close-widget')
557
-
558
- // validate if ther a branching and did you make a choice
559
- if (
560
- !this.getBifChoice &&
561
- this.getFirtsPageBif(this.$route.meta.activity_ref, this.$route.meta.id)
562
- ) {
563
- // create path to make the jump
564
- if (
565
- this.getPageNavBifStart(
566
- this.$route.meta.activity_ref,
567
- this.$route.meta.id
568
- ) == 'page_1'
569
- ) {
570
- this.$router.push({
571
- name: `${this.navigationRoutes.cat[0]._namedRoute}`
572
- })
573
- } else {
574
- this.$router.push({
575
- name: `${
576
- this.navigationRoutes.cat[0]._namedRoute
577
- }.${this.getPageNavBifStart(
578
- this.$route.meta.activity_ref,
579
- this.$route.meta.id
580
- )}`
581
- })
582
- }
583
-
584
- // back to previous page of module (module.page_xx)
585
- } else if (pageIndex > 0 && this.navigationRoutes.cat[previous]._path) {
586
- this.$router.push({
587
- name: `${this.navigationRoutes.cat[previous]._namedRoute}`
588
- })
589
- // this is the last page
590
- } else {
591
- // if allow navigation to activity active, navigate to previous activity
592
- if (this.autoNavigate && this.previousActivity) {
593
- this.$router.push({ name: this.previousActivity._namedRoute })
594
- } else this.$router.push('/')
595
- }
596
- },
597
- // //// TO CLEAN JAI LE GO DE HUBERSON
598
- // /*
599
- // * watch currentRoute to define the navigation catalog
600
- // * check if currentRoute type is a branching
601
- // */
602
- setNavigation() {
603
- // current Route is module
604
- this.currentActivity = this.$router.currentRoute.meta.activity_ref
605
- this.currentPageId = this.$router.currentRoute.meta.id
606
-
607
- const { all_routes, meta } = this.$helper.getRoutesFromVueRouter()
608
-
609
- if (this.$router.currentRoute.name === 'module') {
610
- this.navigationRoutes = {
611
- context: 'module',
612
- cat: meta.children
613
- }
614
- }
615
- // Navigation catalog is the introduction
616
- else if (
617
- this.$router.currentRoute.meta.type === 'introduction' ||
618
- this.$router.currentRoute.meta.type === 'menu'
619
- ) {
620
- const a = all_routes.find(
621
- (route) =>
622
- route.meta.id ===
623
- this.$router.currentRoute.meta.activity_ref.$folderName
624
- )
625
-
626
- const b = all_routes.find(
627
- (route) =>
628
- route.meta.id === this.$router.currentRoute.meta.activity_ref
629
- )
630
- if (a) {
631
- let r = []
632
- //if Intro acitive get all the routes for indroduction or just the menu
633
- this.getIntroStatus
634
- ? r.push(...a.meta.children)
635
- : r.push(
636
- a.meta.children.find(
637
- (el) => !el._namedRoute.includes('introduction')
638
- )
639
- )
640
- this.navigationRoutes = {
641
- context: 'introduction',
642
- cat: r
643
- }
644
- } else if (b) {
645
- let r = []
646
- //if Intro acitive get all the routes for indroduction or just the menu
647
- this.getIntroStatus
648
- ? r.push(...b.meta.children)
649
- : r.push(
650
- b.meta.children.find(
651
- (el) => !el._namedRoute.includes('introduction')
652
- )
653
- )
654
- this.navigationRoutes = {
655
- context: 'introduction',
656
- cat: r
657
- }
658
- }
659
- }
660
- // Navigation catalog is pages of Activity ||menu
661
- else {
662
- const a = all_routes.find(
663
- (route) =>
664
- route.meta.id ===
665
- this.$router.currentRoute.meta.activity_ref.$folderName
666
- )
667
-
668
- // on refresh $forderName doesn't existe
669
- const b = all_routes.find(
670
- (route) =>
671
- route.meta.id === this.$router.currentRoute.meta.activity_ref
672
- )
673
-
674
- if (a) {
675
- this.navigationRoutes = {
676
- context: 'normal',
677
- cat: a.meta.children
678
- }
679
- } else if (b) {
680
- this.navigationRoutes = {
681
- context: 'normal',
682
- cat: b.meta.children
683
- }
684
- }
685
- }
686
-
687
- this.$bus.$emit('set-comp-status', 'AppCompNavigationFull', 'ready')
688
- }, // END setNaviagation
689
- /**
690
- *@description: set the next activity to for the Navigation
691
- */
692
- setNextActivity() {
693
- if (this.autoNavigate && this.navigationRoutes) {
694
- // get all the activities routes from router
695
- const { meta } = this.$helper.getRoutesFromVueRouter()
696
- const allRoutes = meta.children
697
-
698
- // get the index of the current route
699
- const current = this.navigationRoutes.cat.findIndex(
700
- (route) => route._ref === this.$route.meta.id
701
- )
702
-
703
- switch (this.navigationRoutes.context) {
704
- case 'introduction': {
705
- // This is the last page in the of introduction (this the menu)
706
- if (
707
- current === this.navigationRoutes.cat.length - 1 &&
708
- allRoutes.length > 1
709
- ) {
710
- this.nextActivity = allRoutes[1] // go to the 1st activity
711
-
712
- //let conclu = this.conclusionComming()
713
-
714
- // if (!conclu) {
715
- // this.nextPageLabel = this.$t('button.next_activity')
716
- // } else {
717
- // this.nextPageLabel = this.$t('button.go_to_conclusion')
718
- // }
719
- }
720
- //setting next activity or null if undefined, will show "next lesson" button
721
- else
722
- this.nextActivity = this.navigationRoutes.cat[current + 1] || null
723
- break
724
- }
725
- case 'normal': {
726
- // find the current activity ref in the router catalog
727
-
728
- const currentRouteIndex = allRoutes.findIndex(
729
- (route) => route._ref === this.$route.meta.activity_ref
730
- )
731
- // this is the Last page in current activity
732
- if (
733
- current === this.navigationRoutes.cat.length - 1 &&
734
- allRoutes[currentRouteIndex + 1]
735
- ) {
736
- this.nextActivity = allRoutes[currentRouteIndex + 1] // get the next activity in the router catalog
737
-
738
- // let conclu = this.conclusionComming()
739
- // if (!conclu) {
740
- // this.nextPageLabel = this.$t('button.next_activity')
741
- // } else {
742
- // this.nextPageLabel = this.$t('button.go_to_conclusion')
743
- // }
744
- }
745
- // this is in the same activity return the next page of the activity
746
- else if (this.navigationRoutes.cat[current + 1]) {
747
- this.nextActivity = this.navigationRoutes.cat[current + 1]
748
- }
749
- // There is no other activity after the current one
750
- else this.nextActivity = null
751
-
752
- break
753
- }
754
- }
755
- } else this.nextActivity = null
756
-
757
- this.$store.dispatch('updateNextActivity', this.nextActivity)
758
- },
759
- /**
760
- * @description: set previous activity for the navigation
761
- */
762
- setPreviousActivity() {
763
- if (this.autoNavigate && this.navigationRoutes) {
764
- // get all the activities routes from router
765
- const { all_routes: allRoutes } = this.$helper.getRoutesFromVueRouter()
766
-
767
- // get the index of the current route
768
- const current = this.navigationRoutes.cat.findIndex(
769
- (route) => route._ref === this.$route.meta.id
770
- )
771
-
772
- switch (this.navigationRoutes.context) {
773
- case 'introduction': {
774
- // This is the first page in the introduction
775
- if (current === 0) {
776
- this.previousActivity = null
777
- } else {
778
- this.previousActivity = this.navigationRoutes.cat[current - 1]
779
- }
780
- break
781
- }
782
- case 'normal': {
783
- // get the index of the current route
784
- const currentRouteIndex = allRoutes.findIndex(
785
- (route) => route.meta.id === this.$route.meta.activity_ref
786
- )
787
- // this is the 1st page of the 1st activity in the router catologue
788
- // return point is introduction
789
- if (current === 0 && currentRouteIndex === 1) {
790
- const _length = allRoutes[0].children.length
791
- this.previousActivity = allRoutes[0].meta.children[_length - 1] // 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] // previous is last page of previous activity
798
- }
799
- // This is a simply another page in an activity
800
- else this.previousActivity = this.navigationRoutes.cat[current - 1]
801
- break
802
- }
803
- }
804
- } else this.previousActivity = null
805
- },
806
- openPopup(popUpData) {
807
- this.$bus.$emit('open-popup', popUpData)
808
- },
809
- /**
810
- * @description hide the navigation of the application
811
- * @param {String} s - s name of the navigation element to hide ('back' | 'next')
812
- */
813
- hideNavigationCtrls(s) {
814
- s = s || 'all'
815
-
816
- if (s && !['back', 'next', 'all'].includes(s.toLowerCase(s))) return
817
-
818
- switch (s) {
819
- case 'back':
820
- {
821
- this.$store.dispatch('setShowNavLeftCtrl', false)
822
- }
823
- break
824
- case 'next':
825
- {
826
- this.$store.dispatch('setShowNavRightCtrl', false)
827
- this.$store.dispatch('setShowPrimaryCtrl', false)
828
- }
829
-
830
- break
831
-
832
- case 'all':
833
- {
834
- //hide the Upper Nav bar controls
835
- this.$store.dispatch('setShowNavLeftCtrl', false)
836
- this.$store.dispatch('setShowNavRightCtrl', false)
837
-
838
- //hide the main navigation to next page
839
- this.$store.dispatch('setShowPrimaryCtrl', false)
840
- }
841
- break
842
- }
843
- },
844
-
845
- // TO CLEANNING
846
- // /**
847
- // * @description show the navigation of the application
848
- // * @param {String} s - s name of the navigation element to hide ('back' | 'next')
849
- // */
850
- // showNavigationCtrls(s) {
851
- // s = s || 'all'
852
-
853
- // if (s && !['back', 'next', 'all'].includes(s.toLowerCase(s))) return
854
-
855
- // switch (s) {
856
- // case 'back':
857
- // {
858
- // this.$store.dispatch('setShowNavLeftCtrl', true)
859
- // }
860
- // break
861
- // case 'next':
862
- // {
863
- // this.$store.dispatch('setShowNavRightCtrl', true)
864
- // this.$store.dispatch('setShowPrimaryCtrl', true)
865
- // }
866
-
867
- // break
868
-
869
- // case 'all':
870
- // {
871
- // //hide the Upper Nav bar controls
872
- // this.$store.dispatch('setShowNavLeftCtrl', true)
873
- // this.$store.dispatch('setShowNavRightCtrl', true)
874
-
875
- // //hide the main navigation to next page
876
- // this.$store.dispatch('setShowPrimaryCtrl', true)
877
- // }
878
- // break
879
- // }
880
- // },
881
-
882
- /**
883
- * @description - send information to open toc
884
- */
885
- openToc() {
886
- this.$bus.$emit('toggle-widget', 'toc')
887
- this.$bus.$emit('info-activity', this.getCurrentPage.activityRef)
888
- },
889
- /**
890
- * @description - send information to open credit and note
891
- */
892
- openCreditNote() {
893
- this.$bus.$emit('toggle-widget', 'noteCredit')
894
- }
895
- }
896
- }
897
- </script>
898
-
899
- <style lang="scss">
900
- .navbar {
901
- transition: width 0.5s;
902
-
903
- &:focus,
904
- &:hover,
905
- &.show {
906
- width: 115px !important;
907
-
908
- #tool-bar {
909
- button,
910
- a {
911
- span {
912
- display: block;
913
- opacity: 1;
914
- }
915
- }
916
- }
917
- }
918
- }
919
-
920
- .app-ctrl {
921
- display: flex;
922
- flex-direction: column;
923
- align-items: start;
924
- height: 100%;
925
- width: 100%;
926
- position: relative;
927
-
928
- #tool-bar {
929
- width: 100%;
930
- padding: 32px 0;
931
- display: flex;
932
- flex-direction: column;
933
- align-items: center;
934
- flex-wrap: wrap;
935
-
936
- button,
937
- a {
938
- display: block;
939
- margin-bottom: 30px;
940
-
941
- span {
942
- transition: opacity 0.5s, display 0.5s;
943
- display: none;
944
- opacity: 0;
945
- }
946
- }
947
- }
948
- }
949
- </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
+
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>