fcad-core-dragon 2.1.0 → 2.1.2

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