fcad-core-dragon 2.0.0-beta.0 → 2.0.0-beta.10

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 (161) hide show
  1. package/.editorconfig +6 -31
  2. package/.prettierrc +11 -0
  3. package/.vscode/extensions.json +8 -0
  4. package/.vscode/settings.json +16 -0
  5. package/CHANGELOG +153 -0
  6. package/README.md +28 -43
  7. package/documentation/.vitepress/config.js +114 -0
  8. package/documentation/api-examples.md +49 -0
  9. package/documentation/composants/app-base-button.md +58 -0
  10. package/documentation/composants/app-base-error-display.md +59 -0
  11. package/documentation/composants/app-base-popover.md +68 -0
  12. package/documentation/composants/app-comp-audio.md +75 -0
  13. package/documentation/composants/app-comp-branch-buttons.md +111 -0
  14. package/documentation/composants/app-comp-button-progress.md +53 -0
  15. package/documentation/composants/app-comp-carousel.md +53 -0
  16. package/documentation/composants/app-comp-container.md +53 -0
  17. package/documentation/composants/app-comp-input-checkbox-next.md +42 -0
  18. package/documentation/composants/app-comp-input-dropdown-next.md +34 -0
  19. package/documentation/composants/app-comp-input-radio-next.md +39 -0
  20. package/documentation/composants/app-comp-input-text-next.md +35 -0
  21. package/documentation/composants/app-comp-input-text-table-next.md +34 -0
  22. package/documentation/composants/app-comp-input-text-to-fill-dropdown-next.md +53 -0
  23. package/documentation/composants/app-comp-input-text-to-fill-next.md +31 -0
  24. package/documentation/composants/app-comp-jauge.md +31 -0
  25. package/documentation/composants/app-comp-menu-item.md +55 -0
  26. package/documentation/composants/app-comp-menu.md +29 -0
  27. package/documentation/composants/app-comp-navigation.md +41 -0
  28. package/documentation/composants/app-comp-note-call.md +53 -0
  29. package/documentation/composants/app-comp-note-credit.md +53 -0
  30. package/documentation/composants/app-comp-play-bar-next.md +53 -0
  31. package/documentation/composants/app-comp-pop-up-next.md +93 -0
  32. package/documentation/composants/app-comp-quiz-next.md +235 -0
  33. package/documentation/composants/app-comp-quiz-recall.md +53 -0
  34. package/documentation/composants/app-comp-svg-next.md +53 -0
  35. package/documentation/composants/app-comp-table-of-content.md +50 -0
  36. package/documentation/composants/app-comp-video-player.md +82 -0
  37. package/documentation/composants.md +46 -0
  38. package/documentation/composants_critiques/ModelPageComposant.md +53 -0
  39. package/documentation/composants_critiques/app-base-module.md +43 -0
  40. package/documentation/composants_critiques/app-base-page.md +48 -0
  41. package/documentation/composants_critiques/app-base.md +311 -0
  42. package/documentation/composants_critiques/main.md +15 -0
  43. package/documentation/demarrage.md +50 -0
  44. package/documentation/deploiement.md +58 -0
  45. package/documentation/index.md +33 -0
  46. package/documentation/markdown-examples.md +85 -0
  47. package/documentation/public/npm_version.png +0 -0
  48. package/documentation/public/vite.svg +15 -0
  49. package/documentation/public/vuejs.svg +2 -0
  50. package/documentation/public/vuetify.svg +6 -0
  51. package/eslint.config.js +60 -0
  52. package/package.json +43 -49
  53. package/src/$locales/en.json +94 -92
  54. package/src/$locales/fr.json +77 -113
  55. package/src/assets/data/onboardingMessages.json +1 -1
  56. package/src/components/AppBase.vue +971 -437
  57. package/src/components/AppBaseButton.test.js +21 -0
  58. package/src/components/AppBaseButton.vue +42 -10
  59. package/src/components/AppBaseErrorDisplay.vue +209 -162
  60. package/src/components/AppBaseFlipCard.vue +1 -0
  61. package/src/components/AppBaseModule.vue +1021 -976
  62. package/src/components/AppBasePage.vue +656 -128
  63. package/src/components/AppBasePopover.vue +41 -0
  64. package/src/components/AppBaseSkeleton.vue +66 -0
  65. package/src/components/AppCompAudio.vue +256 -0
  66. package/src/components/AppCompBranchButtons.vue +108 -181
  67. package/src/components/AppCompButtonProgress.vue +44 -70
  68. package/src/components/AppCompCarousel.vue +284 -233
  69. package/src/components/AppCompContainer.vue +29 -0
  70. package/src/components/AppCompInputCheckBoxNx.vue +323 -0
  71. package/src/components/AppCompInputDropdownNx.vue +299 -0
  72. package/src/components/AppCompInputRadioNx.vue +284 -0
  73. package/src/components/AppCompInputTextNx.vue +153 -0
  74. package/src/components/AppCompInputTextTableNx.vue +202 -0
  75. package/src/components/AppCompInputTextToFillDropdownNx.vue +340 -0
  76. package/src/components/AppCompInputTextToFillNx.vue +313 -0
  77. package/src/components/AppCompJauge.vue +36 -11
  78. package/src/components/AppCompMenu.vue +312 -92
  79. package/src/components/AppCompMenuItem.vue +129 -105
  80. package/src/components/AppCompNavigation.vue +972 -0
  81. package/src/components/AppCompNoteCall.vue +161 -0
  82. package/src/components/AppCompNoteCredit.vue +491 -0
  83. package/src/components/AppCompPlayBarNext.vue +2288 -0
  84. package/src/components/AppCompPopUpNext.vue +504 -0
  85. package/src/components/AppCompQuizNext.vue +510 -0
  86. package/src/components/AppCompQuizRecall.vue +350 -0
  87. package/src/components/AppCompSVGNext.vue +346 -0
  88. package/src/components/AppCompSettingsMenu.vue +18 -16
  89. package/src/components/AppCompTableOfContent.vue +340 -122
  90. package/src/components/AppCompVideoPlayer.vue +377 -0
  91. package/src/components/BaseModule.vue +24 -117
  92. package/src/components/tests__/AppBaseButton.spec.js +53 -0
  93. package/src/components/tests__/useTimer.spec.js +91 -0
  94. package/src/composables/useIdleDetector.js +56 -0
  95. package/src/composables/useQuiz.js +89 -0
  96. package/src/composables/useTimer.js +172 -0
  97. package/src/directives/nvdaFix.js +53 -0
  98. package/src/externalComps/ModuleView.vue +22 -0
  99. package/src/externalComps/SummaryView.vue +91 -0
  100. package/src/main.js +400 -142
  101. package/src/module/stores/appStore.js +947 -0
  102. package/src/module/xapi/ADL.js +241 -60
  103. package/src/module/xapi/Crypto/Hasher.js +8 -8
  104. package/src/module/xapi/Crypto/WordArray.js +6 -6
  105. package/src/module/xapi/Crypto/algorithms/BufferedBlockAlgorithm.js +4 -4
  106. package/src/module/xapi/Crypto/algorithms/C_algo.js +14 -18
  107. package/src/module/xapi/Crypto/algorithms/HMAC.js +1 -1
  108. package/src/module/xapi/Crypto/algorithms/SHA1.js +1 -1
  109. package/src/module/xapi/Crypto/encoders/Base.js +7 -7
  110. package/src/module/xapi/Crypto/encoders/Base64.js +3 -3
  111. package/src/module/xapi/Crypto/encoders/Hex.js +4 -3
  112. package/src/module/xapi/Crypto/encoders/Latin1.js +3 -3
  113. package/src/module/xapi/Crypto/encoders/Utf8.js +3 -3
  114. package/src/module/xapi/Statement/index.js +3 -3
  115. package/src/module/xapi/launch.js +10 -10
  116. package/src/module/xapi/utils.js +17 -17
  117. package/src/module/xapi/wrapper.js +223 -218
  118. package/src/module/xapi/xapiStatement.js +29 -29
  119. package/src/plugins/analytics.js +34 -0
  120. package/src/plugins/bus.js +7 -2
  121. package/src/plugins/gsap.js +9 -8
  122. package/src/plugins/helper.js +141 -43
  123. package/src/plugins/i18n.js +13 -18
  124. package/src/plugins/idb.js +46 -30
  125. package/src/plugins/save.js +1 -1
  126. package/src/plugins/scorm.js +15 -15
  127. package/src/plugins/xapi.js +2 -2
  128. package/src/public/index.html +23 -11
  129. package/src/router/index.js +57 -0
  130. package/src/router/routes.js +312 -0
  131. package/src/shared/generalfuncs.js +241 -10
  132. package/src/shared/validators.js +1018 -0
  133. package/vitest.config.js +19 -0
  134. package/.eslintignore +0 -29
  135. package/.eslintrc.js +0 -86
  136. package/.prettierrc.js +0 -5
  137. package/babel.config.js +0 -3
  138. package/src/components/AppBaseDragChoice.vue +0 -91
  139. package/src/components/AppBaseDropZone.vue +0 -112
  140. package/src/components/AppCompDragAndDrop.vue +0 -339
  141. package/src/components/AppCompInputAssociation.vue +0 -332
  142. package/src/components/AppCompInputCheckBox.vue +0 -227
  143. package/src/components/AppCompInputDropdown.vue +0 -184
  144. package/src/components/AppCompInputRadio.vue +0 -169
  145. package/src/components/AppCompInputTextBox.vue +0 -91
  146. package/src/components/AppCompInputTextTable.vue +0 -155
  147. package/src/components/AppCompInputTextToFillDropdown.vue +0 -255
  148. package/src/components/AppCompInputTextToFillText.vue +0 -164
  149. package/src/components/AppCompMediaPlayer.vue +0 -365
  150. package/src/components/AppCompNavigationFull.vue +0 -1791
  151. package/src/components/AppCompPlayBar.vue +0 -1540
  152. package/src/components/AppCompPopUp.vue +0 -523
  153. package/src/components/AppCompQuiz.vue +0 -2998
  154. package/src/components/AppCompToolTip.vue +0 -94
  155. package/src/mixins/$pageMixins.js +0 -381
  156. package/src/mixins/$quizMixins.js +0 -456
  157. package/src/mixins/timerMixin.js +0 -132
  158. package/src/module/store.js +0 -874
  159. package/src/plugins/timeManager.js +0 -77
  160. package/src/routes.js +0 -734
  161. package/vue.config.js +0 -83
@@ -1,1791 +0,0 @@
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. Only work in EL+ mode
4
- -->
5
- <template>
6
- <div
7
- v-if="navigationRoutes"
8
- class="app-ctrl full"
9
- :class="{ branching: isBranching }"
10
- >
11
- <div id="nav_left_btns">
12
- <b-link
13
- v-if="!isBranching && !isMenu"
14
- id="btn_back_summary"
15
- :to="{ name: 'menu' }"
16
- class="btn btn-ghost"
17
- :title="$t('button.menu')"
18
- >
19
- <svg
20
- xmlns="http://www.w3.org/2000/svg"
21
- width="20"
22
- height="17"
23
- viewBox="0 0 20 17"
24
- >
25
- <path
26
- id="Path_3912"
27
- data-name="Path 3912"
28
- d="M10,20V14h4v6h5V12h3L12,3,2,12H5v8Z"
29
- transform="translate(-2 -3)"
30
- />
31
- </svg>
32
- <span v-if="!isBranching && !isMenu">{{ $t('button.menu') }}</span>
33
- </b-link>
34
- <b-link
35
- v-if="isBranching"
36
- id="btn_back_root"
37
- :to="{ name: $route.meta.branching_root }"
38
- class="btn btn-ghost"
39
- :title="$t('button.back_to_branching')"
40
- >
41
- <svg
42
- xmlns="http://www.w3.org/2000/svg"
43
- x="0px"
44
- y="0px"
45
- viewBox="0 0 21.3 18"
46
- xml:space="preserve"
47
- >
48
- <g transform="translate(-1.5 -5)">
49
- <path
50
- class="st0"
51
- d="M21,23H10.8C9.8,23,9,22.1,9,21v-3h1.8v3H21V7H10.8v3H9V7c0-1.1,0.8-2,1.8-2H21
52
- c1.1,0,1.9,0.9,1.8,2v14C22.9,22.1,22,23,21,23z"
53
- />
54
- <path
55
- class="st0"
56
- d="M5.3,15l2.6,2.6L6.5,19l-5-5l5-5l1.4,1.4L5.3,13H15v2H5.3z"
57
- />
58
- </g>
59
- </svg>
60
- <span>{{ $t('button.back_to_branching') }}</span>
61
- </b-link>
62
- <span v-if="isMenu">{{ $t('button.menu') }}</span>
63
- </div>
64
- <!----------- Navigation section --------------->
65
- <div v-if="!isMenu" id="page_nav">
66
- <button
67
- id="btn_previous_page"
68
- ref="btn_previous_page"
69
- :title="$t('button.previous')"
70
- class="btn btn-ghost"
71
- :disabled="!backAllowed || !enableNavLeftBtn"
72
- :class="{ md_disabled: !backAllowed || !enableNavLeftBtn }"
73
- @click="goPrevious"
74
- >
75
- <svg
76
- xmlns="http://www.w3.org/2000/svg"
77
- width="24"
78
- height="24"
79
- viewBox="0 0 24 24"
80
- >
81
- <g id="wrapper" transform="translate(48 -4) rotate(180)">
82
- <g id="navigate_next_black_24dp" transform="translate(24 -28)">
83
- <path
84
- id="Path_3899"
85
- data-name="Path 3899"
86
- d="M0,0H24V24H0Z"
87
- fill="none"
88
- />
89
- <path
90
- id="Path_3900"
91
- data-name="Path 3900"
92
- d="M10.02,6,8.61,7.41,13.19,12,8.61,16.59,10.02,18l6-6Z"
93
- transform="translate(0 0)"
94
- />
95
- </g>
96
- </g>
97
- </svg>
98
- </button>
99
- <div id="activity_progress" :class="{ branching_progress: isBranching }">
100
- <div v-if="!isBranching">
101
- <b-link
102
- v-for="(anchor, i) of anchors"
103
- :id="`${anchor.pageRef}-${i}`"
104
- :key="`${anchor.pageRef}-${i}`"
105
- class="activity_progress_link "
106
- :class="[
107
- {
108
- current_page: iscurrentAnchor(anchor),
109
- md_disable: blockBranching(anchor)
110
- }
111
- ]"
112
- :to="{
113
- name: anchor.path
114
- }"
115
- :disabled="blockBranching(anchor)"
116
- :aria-label="`${$t('label.section')} ${anchor.anchorName} `"
117
- :title="`${$t('label.section')} ${anchor.anchorName}`"
118
- >
119
- <div v-if="!isBranching" class="page_tooltip">
120
- <span>{{ anchor.anchorName }}</span>
121
- </div>
122
- </b-link>
123
- </div>
124
- <div v-if="isBranching">
125
- <b-link
126
- v-for="page of navigationRoutes.cat"
127
- :key="page._ref"
128
- class="activity_progress_link"
129
- :class="{
130
- current_page: $route.meta.id === page._ref,
131
- page_viewed: isBranchPageViewed(page._ref)
132
- }"
133
- :to="{
134
- name: page._namedRoute
135
- }"
136
- :title="titlePageBranching(page._path)"
137
- >
138
- <div v-if="!isBranching" class="page_tooltip">
139
- <span>
140
- <!-- {{ page._path }} -->
141
- {{ page._namedRoute }}
142
- </span>
143
- </div>
144
- </b-link>
145
- </div>
146
- </div>
147
- <button
148
- id="btn_next_page"
149
- ref="btn_next_page"
150
- :title="nextPageLabel"
151
- class="btn btn-ghost"
152
- :disabled="!nextAllowed || !enableNavRightBtn"
153
- :class="{ md_disabled: !nextAllowed || !enableNavRightBtn }"
154
- @click="goNext"
155
- >
156
- <svg
157
- id="navigate_next_black_24dp"
158
- xmlns="http://www.w3.org/2000/svg"
159
- width="24"
160
- height="24"
161
- viewBox="0 0 24 24"
162
- >
163
- <path
164
- id="Path_3899"
165
- data-name="Path 3899"
166
- d="M0,0H24V24H0Z"
167
- fill="none"
168
- />
169
- <path
170
- id="Path_3900"
171
- data-name="Path 3900"
172
- d="M10.02,6,8.61,7.41,13.19,12,8.61,16.59,10.02,18l6-6Z"
173
- transform="translate(0 0)"
174
- />
175
- </svg>
176
- </button>
177
- <portal to="page-count">
178
- <p v-show="navigationRoutes && !isMenu" class="pageCount">
179
- {{ $t('label.for_pagination') }} {{ pagination.counter }}/{{
180
- pagination.total
181
- }}
182
- </p>
183
- </portal>
184
- </div>
185
- <div id="nav_right_btns">
186
- <!-- BOUTON PRISE DE NOTES -->
187
- <!-- <button id="btn_notes" class="nav_main_btn" v-if="!isMenu" title="Prise de notes">
188
- <svg xmlns="http://www.w3.org/2000/svg" width="12.95" height="18.5" viewBox="0 0 12.95 18.5">
189
- <path id="Path_4223" data-name="Path 4223" d="M346.834,367.065h-8.241a2.354,2.354,0,0,0-2.355,2.354V383.21a2.355,2.355,0,0,0,2.355,2.355h8.241a2.355,2.355,0,0,0,2.355-2.355V369.419A2.354,2.354,0,0,0,346.834,367.065Zm-9.044,3.048H344v.789H337.79Zm9.444,9.807H337.79v-.788h9.444Zm0-2.255H337.79v-.789h9.444Zm0-2.255H337.79v-.788h9.444Zm0-2.255H337.79v-.788h9.444Z" transform="translate(-336.239 -367.065)" fill="#030504"/>
190
- </svg>
191
- <span>Prise de notes</span>
192
- </button> -->
193
- <!-- BOUTON MARQUE-PAGES -->
194
- <!-- <button id="btn_bookmarks" class="nav_main_btn" v-if="!isMenu" title="Signets">
195
- <svg xmlns="http://www.w3.org/2000/svg" width="16" height="18" viewBox="0 0 16 18">
196
- <path id="Path_3863" data-name="Path 3863" d="M21,7H19V9H17V7H15V5h2V3h2V5h2ZM19,21l-7-3L5,21V5A2.006,2.006,0,0,1,7,3h7a5,5,0,0,0,4,8,4.712,4.712,0,0,0,1-.1Z" transform="translate(-5 -3)" fill="#001729"/>
197
- </svg>
198
- </button> -->
199
- <button
200
- id="btn_settings"
201
- v-b-toggle.sidebar-settings
202
- class="btn nav_main_btn"
203
- :title="$t('button.setting')"
204
- >
205
- <svg
206
- xmlns="http://www.w3.org/2000/svg"
207
- width="18.676"
208
- height="19.2"
209
- viewBox="0 0 18.676 19.2"
210
- >
211
- <path
212
- id="Path_4228"
213
- data-name="Path 4228"
214
- d="M19.14,12.94A7.074,7.074,0,0,0,19.2,12a5.777,5.777,0,0,0-.07-.94l2.03-1.58a.491.491,0,0,0,.12-.61L19.36,5.55a.488.488,0,0,0-.59-.22l-2.39.96a7.064,7.064,0,0,0-1.62-.94L14.4,2.81a.484.484,0,0,0-.48-.41H10.08a.474.474,0,0,0-.47.41L9.25,5.35a7.22,7.22,0,0,0-1.62.94L5.24,5.33a.477.477,0,0,0-.59.22L2.74,8.87a.455.455,0,0,0,.12.61l2.03,1.58a5.563,5.563,0,0,0-.02,1.88L2.84,14.52a.491.491,0,0,0-.12.61l1.92,3.32a.488.488,0,0,0,.59.22l2.39-.96a7.064,7.064,0,0,0,1.62.94l.36,2.54a.492.492,0,0,0,.48.41h3.84a.466.466,0,0,0,.47-.41l.36-2.54a6.859,6.859,0,0,0,1.62-.94l2.39.96a.477.477,0,0,0,.59-.22l1.92-3.32a.463.463,0,0,0-.12-.61ZM12,15.6A3.6,3.6,0,1,1,15.6,12,3.611,3.611,0,0,1,12,15.6Z"
215
- transform="translate(-2.662 -2.4)"
216
- />
217
- </svg>
218
- </button>
219
- </div>
220
- <!-- Navigation dans le popup de retroaction -->
221
- <portal v-if="hasQuiz" to="popup_retro_nav">
222
- <button
223
- v-if="currentNavType === navTypes.QUIZ && nextActivity === null"
224
- id="popup_primary_nav_btn"
225
- ref="primary_popup_nav_btn"
226
- class="btn popup_primary_nav_btn"
227
- :disabled="!nextAllowed"
228
- :class="{ md_disabled: !nextAllowed }"
229
- :title="
230
- nextLesson ? $t('button.next_lesson') : $t('button.back_to_menu')
231
- "
232
- @click="backToMenu"
233
- >
234
- {{ nextLesson ? $t('button.next_lesson') : $t('button.back_to_menu') }}
235
- </button>
236
- <button
237
- v-if="
238
- currentNavType === navTypes.LASTBRANCHPAGE ||
239
- (currentNavType === navTypes.LASTBRANCHQUIZ &&
240
- getNextBranch !== false)
241
- "
242
- id="popup_primary_nav_btn"
243
- ref="primary_popup_nav_btn"
244
- class="btn popup_primary_nav_btn"
245
- :title="$t('button.next_branch')"
246
- @click="goNextBranch"
247
- >
248
- {{ $t('button.next_branch') }}
249
- </button>
250
- <button
251
- v-else-if="
252
- currentNavType === navTypes.LASTBRANCHPAGE ||
253
- currentNavType === navTypes.LASTBRANCHQUIZ
254
- "
255
- id="popup_primary_nav_btn"
256
- ref="primary_popup_nav_btn"
257
- class="btn popup_primary_nav_btn"
258
- :title="$t('button.return_to_branch')"
259
- @click="backToRoot"
260
- >
261
- {{ $t('button.back_to_branching') }}
262
- </button>
263
- <button
264
- v-else-if="nextActivity !== null"
265
- id="popup_primary_nav_btn"
266
- ref="primary_popup_nav_btn"
267
- class="btn popup_primary_nav_btn"
268
- :disabled="!nextAllowed"
269
- :class="{ md_disabled: !nextAllowed }"
270
- :title="nextPageLabel"
271
- @click="goNext"
272
- >
273
- {{ nextPageLabel }}
274
- </button>
275
- </portal>
276
- <!-- Navigation principale -->
277
- <portal to="primary_nav">
278
- <button
279
- v-if="
280
- currentNavType === navTypes.QUIZ ||
281
- currentNavType === navTypes.LASTBRANCHQUIZ
282
- "
283
- :id="'primary_' + currentNavType"
284
- ref="primary_nav_btn"
285
- class="btn primary_nav_btn right quiz"
286
- :title="quizNavLabel"
287
- @click="submitQuiz"
288
- >
289
- <span>{{ quizNavLabel }}</span>
290
- </button>
291
- <button
292
- v-else-if="
293
- currentNavType === navTypes.ACTIVITY ||
294
- currentNavType === navTypes.BRANCH
295
- "
296
- :id="'primary_' + currentNavType"
297
- ref="primary_nav_btn"
298
- class="btn primary_nav_btn right"
299
- :title="nextPageLabel"
300
- :disabled="!nextAllowed || !enablePrimaryBtn"
301
- :class="{ md_disabled: !nextAllowed || !enablePrimaryBtn }"
302
- :style="displayStyle(enablePrimaryBtn)"
303
- @click="goNext"
304
- >
305
- <span>{{ nextPageLabel }}</span>
306
-
307
- <svg
308
- xmlns="http://www.w3.org/2000/svg"
309
- width="7.41"
310
- height="12"
311
- viewBox="0 0 7.41 12"
312
- >
313
- <path
314
- id="Path_3900"
315
- data-name="Path 3900"
316
- d="M10.02,6,8.61,7.41,13.19,12,8.61,16.59,10.02,18l6-6Z"
317
- transform="translate(-8.61 -6)"
318
- fill="#fff"
319
- />
320
- </svg>
321
- </button>
322
- <button
323
- v-else-if="currentNavType === navTypes.FINALPAGE"
324
- :id="'primary_' + currentNavType"
325
- ref="primary_nav_btn"
326
- class="btn primary_nav_btn"
327
- :title="finalPageBtnLabel"
328
- :disabled="!enablePrimaryBtn"
329
- :class="{ md_disabled: !enablePrimaryBtn }"
330
- :style="displayStyle(enablePrimaryBtn)"
331
- @click="backToMenu"
332
- >
333
- <span>
334
- {{ finalPageBtnLabel }}
335
- </span>
336
-
337
- <svg
338
- v-show="!nextLesson"
339
- xmlns="http://www.w3.org/2000/svg"
340
- width="11.667"
341
- height="11.46"
342
- viewBox="0 0 11.667 11.46"
343
- >
344
- <path
345
- id="Path_4230"
346
- data-name="Path 4230"
347
- d="M433.865,369.022H433.6v-.005h-7.548l2.014-2.171-1.1-1.182-3.9,4.19,3.9,4.191,1.1-1.182-2.014-2.171H433v4.57h-2.5v1.861h3.366a.9.9,0,0,0,.866-.93v-6.346A.811.811,0,0,0,433.865,369.022Z"
348
- transform="translate(-423.065 -365.664)"
349
- fill="#fff"
350
- />
351
- </svg>
352
- <svg
353
- v-show="nextLesson"
354
- xmlns="http://www.w3.org/2000/svg"
355
- width="7.41"
356
- height="12"
357
- viewBox="0 0 7.41 12"
358
- >
359
- <path
360
- id="Path_3900"
361
- data-name="Path 3900"
362
- d="M10.02,6,8.61,7.41,13.19,12,8.61,16.59,10.02,18l6-6Z"
363
- transform="translate(-8.61 -6)"
364
- fill="#fff"
365
- />
366
- </svg>
367
- </button>
368
- <button
369
- v-if="currentNavType === navTypes.LASTBRANCHPAGE"
370
- :id="'primary_' + currentNavType"
371
- ref="primary_nav_btn"
372
- class="btn primary_nav_btn"
373
- :class="{
374
- right: getNextBranch == false
375
- }"
376
- :title="$t('button.back_to_branching')"
377
- @click="backToRoot"
378
- >
379
- <span>{{ $t('button.back_to_branching') }}</span>
380
- <svg
381
- class="ico-back-branch"
382
- xmlns="http://www.w3.org/2000/svg"
383
- x="0px"
384
- y="0px"
385
- viewBox="0 0 21.3 18"
386
- xml:space="preserve"
387
- >
388
- <g transform="translate(-1.5 -5)">
389
- <path
390
- class="st0"
391
- d="M21,23H10.8C9.8,23,9,22.1,9,21v-3h1.8v3H21V7H10.8v3H9V7c0-1.1,0.8-2,1.8-2H21
392
- c1.1,0,1.9,0.9,1.8,2v14C22.9,22.1,22,23,21,23z"
393
- />
394
- <path
395
- class="st0"
396
- d="M5.3,15l2.6,2.6L6.5,19l-5-5l5-5l1.4,1.4L5.3,13H15v2H5.3z"
397
- />
398
- </g>
399
- </svg>
400
- </button>
401
- <button
402
- v-if="
403
- currentNavType === navTypes.LASTBRANCHPAGE && getNextBranch !== false
404
- "
405
- :id="'primary_next_branch'"
406
- ref="primary_nav_btn"
407
- class="btn primary_nav_btn right"
408
- :title="$t('button.next_branch')"
409
- :style="displayStyle(enablePrimaryBtn)"
410
- @click="goNextBranch"
411
- >
412
- <span>{{ $t('button.next_branch') }}</span>
413
- <svg
414
- xmlns="http://www.w3.org/2000/svg"
415
- width="7.41"
416
- height="12"
417
- viewBox="0 0 7.41 12"
418
- >
419
- <path
420
- id="Path_3900"
421
- data-name="Path 3900"
422
- d="M10.02,6,8.61,7.41,13.19,12,8.61,16.59,10.02,18l6-6Z"
423
- transform="translate(-8.61 -6)"
424
- fill="#fff"
425
- />
426
- </svg>
427
- </button>
428
- </portal>
429
- <!-- AppCompSettingsMenu -->
430
- <app-comp-settings-menu />
431
- </div>
432
- </template>
433
-
434
- <script>
435
- import { mapGetters } from 'vuex'
436
- import AppCompSettingsMenu from './AppCompSettingsMenu.vue'
437
- export default {
438
- components: { AppCompSettingsMenu },
439
- props: {
440
- autoNavigate: { type: Boolean, default: false }
441
- },
442
-
443
- data() {
444
- return {
445
- nextPageLabel: null,
446
- hasMedia: false,
447
- mediaType: null,
448
- mediaPlaybackEnd: false,
449
- navTypes: {
450
- QUIZ: 'quiz',
451
- ACTIVITY: 'activity',
452
- BRANCH: 'branch',
453
- LASTBRANCHPAGE: 'lastbranch',
454
- LASTBRANCHQUIZ: 'lastbranchquiz',
455
- FINALPAGE: 'finalpage'
456
- },
457
- quizActions: {
458
- SAVE: 'save',
459
- VERIFY: 'verify',
460
- CONFIRM: 'confirm'
461
- },
462
- currentNavType: '',
463
- isTocOpen: false,
464
- previousBtn: null,
465
- menuBtn: null,
466
- nextBtn: null,
467
- navigation: {},
468
- currentPath: null,
469
- navigationRoutes: null,
470
- currentActivity: null,
471
- currentPageId: null,
472
- anchors: [],
473
- quizData: null,
474
- pageInfo: null,
475
- nextActivity: null,
476
- previousActivity: null
477
- }
478
- },
479
- computed: {
480
- ...mapGetters([
481
- 'getCurrentPage',
482
- 'getModuleChildren',
483
- 'getIntroStatus',
484
- 'getUserInteraction',
485
- 'getAnchorsForActivity',
486
- 'getAppConfigs',
487
- 'getPageData',
488
- 'getAllActivitiesState',
489
- 'getShowPrimaryCtrl',
490
- 'getShowNavRightCtrl',
491
- 'getShowNavLeftCtrl',
492
- 'getBifChoice',
493
- 'getMenuSettings'
494
- ]),
495
-
496
- finalPageBtnLabel() {
497
- let label
498
- if (!this.nextLesson) {
499
- label = this.$t('button.back_to_menu')
500
- } else if (this.nextLesson && this.getAppConfigs.nextConcluModule) {
501
- label = this.$t('button.next_before_conclu_module')
502
- } else if (this.nextLesson && !this.getAppConfigs.nextConcluModule) {
503
- label = this.$t('button.next_lesson')
504
- }
505
- return label
506
- },
507
- /*
508
- * Primary nav button label for all quiz, ma/mes
509
- */
510
- quizNavLabel() {
511
- let label = ''
512
- let action, plural
513
- const quizType = this.quizData.type_question
514
- //check if quiz has more then one choice
515
- if (this.quizData.choix_reponse === null) {
516
- plural = false
517
- } else {
518
- if (typeof this.quizData.choix_reponse !== 'undefined') {
519
- plural = this.quizData.choix_reponse.length > 1
520
- } else {
521
- plural = this.quizData.solution.length > 1
522
- }
523
- }
524
-
525
- switch (quizType) {
526
- case 'choix_mult':
527
- case 'choix_unique':
528
- action = this.isNeutralQuiz
529
- ? this.quizActions.CONFIRM
530
- : this.quizActions.VERIFY
531
- plural = false
532
- break
533
- case 'dropdown':
534
- action = this.isNeutralQuiz
535
- ? this.quizActions.CONFIRM
536
- : this.quizActions.VERIFY
537
- break
538
- case 'reponse_ouverte':
539
- action = this.quizActions.SAVE
540
- break
541
- case 'texte_tableau':
542
- action = this.quizActions.VERIFY
543
- break
544
- case 'texte_troue_select':
545
- case 'texte_troue':
546
- action = this.quizActions.VERIFY
547
- break
548
- case 'association':
549
- break
550
- case 'dragdrop':
551
- default:
552
- action = this.quizActions.VERIFY
553
- break
554
- }
555
-
556
- switch (action) {
557
- case this.quizActions.CONFIRM:
558
- label += this.$t('button.quiz_confirm')
559
- break
560
- case this.quizActions.SAVE:
561
- label += this.$t('button.quiz_save')
562
- break
563
- case this.quizActions.VERIFY:
564
- label += this.$t('button.quiz_verify')
565
- break
566
- }
567
- label += ' '
568
-
569
- label += plural
570
- ? this.$t('button.quiz_multiple')
571
- : this.$t('button.quiz_single')
572
-
573
- return label
574
- },
575
-
576
- getNextBranch() {
577
- if (!this.isBranching) {
578
- return false
579
- }
580
- //to get activity route from.
581
-
582
- const { all_routes } = this.$helper.getRoutesFromVueRouter()
583
-
584
- //Get the current activity
585
- const activity = all_routes.find(
586
- //const activity = this.$helper.getRoutesFromVueRouter.find(
587
- (route) => route.meta.id === this.$router.currentRoute.meta.activity_ref
588
- )
589
- //find root page of all branches
590
- const page = activity.children.find(
591
- (route) =>
592
- route.meta.id === this.$router.currentRoute.meta.branching_ref
593
- )
594
- //find the index of the current branch
595
- const branchIndex = page.children.findIndex(
596
- (route) => route.path === this.$router.currentRoute.meta.branch_ref
597
- )
598
- const pageCountInBranch = page.children.length - 1
599
- //if current branch is the last one, return false. else return next branch
600
- return branchIndex === pageCountInBranch
601
- ? false
602
- : page.children[branchIndex + 1]
603
- },
604
-
605
- collection() {
606
- return this.$store.getters.getModuleChildren
607
- },
608
-
609
- pagination() {
610
- let p = { counter: null, total: null }
611
-
612
- const { context } = this.navigationRoutes
613
-
614
- switch (context) {
615
- /* In the context of introduction, menu should not be counted in the pagination*/
616
- case 'introduction':
617
- {
618
- if (this.$route.name === 'menu') p.counter = 0
619
-
620
- p.total = this.navigationRoutes.cat.filter(
621
- (route) => route._path !== 'menu'
622
- ).length
623
-
624
- p.counter = this.navigationRoutes.cat.findIndex(
625
- (route) => route._ref === this.$route.meta.id
626
- )
627
- }
628
- break
629
-
630
- default:
631
- p.counter =
632
- this.navigationRoutes.cat.findIndex(
633
- (route) => route._ref === this.$route.meta.id
634
- ) + 1
635
-
636
- p.total = this.navigationRoutes.cat.length
637
- }
638
- return p
639
- },
640
-
641
- /**
642
- * Control clickable state of back btn (disable/ enable Back btn click)
643
- */
644
- backAllowed() {
645
- let isAllowed = true // by default
646
- // Navigation to next/previous activity is permitted. prevent negate navigation in conditions bellow.
647
- if (this.autoNavigate) {
648
- switch (this.navigationRoutes.context) {
649
- case 'introduction':
650
- if (this.$route.meta.id === this.navigationRoutes.cat[0]._ref)
651
- isAllowed = false
652
- break
653
-
654
- case 'normal':
655
- if (
656
- this.previousActivity &&
657
- this.previousActivity._namedRoute === 'menu'
658
- )
659
- isAllowed = false
660
- break
661
-
662
- case 'branching':
663
- //Check if this is the 1st page of branching
664
- if (this.$route.meta.id === this.navigationRoutes.cat[0]._ref)
665
- isAllowed = false
666
- break
667
- }
668
- }
669
- // Navigation to next/previous activity has not been permitted.
670
- else if (this.$route.meta.id === this.navigationRoutes.cat[0]._ref)
671
- isAllowed = false
672
- return isAllowed
673
- },
674
-
675
- /**
676
- * Controle clicable state of next btn (disable/ enable Next btn click)
677
- */
678
- nextAllowed() {
679
- let isAllowed = true
680
- const { length } = this.navigationRoutes.cat
681
-
682
- if (this.autoNavigate) {
683
- switch (this.navigationRoutes.context) {
684
- case 'normal':
685
- // Check if there is a next activity (could be page a page of current activity or page of next activity)
686
- if (!this.nextActivity) isAllowed = false
687
- break
688
- case 'branching':
689
- if (
690
- this.$route.meta.id === this.navigationRoutes.cat[length - 1]._ref
691
- )
692
- isAllowed = false
693
- break
694
- }
695
- } else {
696
- if (this.$route.meta.id === this.navigationRoutes.cat[length - 1]._ref)
697
- isAllowed = false
698
- }
699
- return isAllowed
700
- },
701
-
702
- isBranching() {
703
- return this.navigationRoutes.context === 'branching'
704
- },
705
-
706
- /**
707
- * @description
708
- * Check if the current page contains a quiz
709
- * @returns
710
- * Boolean: true if a quiz is present, false if not
711
- */
712
- hasQuiz() {
713
- let quiz = false
714
- const objKeys = Object.keys(this.getCurrentPage)
715
- for (let i = 0; i < objKeys.length; i++) {
716
- const key = objKeys[i]
717
- //check if a variable name starts with "quizData", you may find quizData1, quizData2... in some cases
718
- if (key.startsWith('quizData')) {
719
- quiz =
720
- typeof this.getCurrentPage[key] !== 'undefined' &&
721
- this.getCurrentPage[key] !== null
722
- break
723
- }
724
- }
725
- return quiz
726
- },
727
-
728
- /**
729
- * @description
730
- * Check if quiz is neutral, a neutral quiz has no solution
731
- */
732
- isNeutralQuiz() {
733
- return this.quizData.solution === null
734
- },
735
-
736
- isMenu() {
737
- return this.$route.name === 'menu'
738
- },
739
-
740
- nextLesson() {
741
- const { linkedResource } = this.getAppConfigs
742
- if (linkedResource) return linkedResource
743
- else return null
744
- },
745
-
746
- previousLabel() {
747
- let lable = this.$route.meta
748
- if (
749
- this.$route.meta.activity_ref == 'A00' &&
750
- this.$route.meta.id == 'P01'
751
- ) {
752
- lable = this.$t('button.back_to_menu')
753
- } else if (
754
- this.$route.meta.activity_ref == 'A01' &&
755
- this.$route.meta.id == 'P01'
756
- ) {
757
- lable = this.$t('button.next_introduction')
758
- } else {
759
- lable = this.$t('button.previous')
760
- }
761
-
762
- return lable
763
- },
764
-
765
- enablePrimaryBtn() {
766
- return this.getShowPrimaryCtrl
767
- },
768
-
769
- enableNavLeftBtn() {
770
- return this.getShowNavLeftCtrl
771
- },
772
-
773
- enableNavRightBtn() {
774
- return this.getShowNavRightCtrl
775
- }
776
- },
777
-
778
- watch: {
779
- $route() {
780
- this.setNavigation() // reset the navigation context when route change
781
-
782
- setTimeout(() => {
783
- this.initPage()
784
- }, 200)
785
- }
786
- },
787
- mounted() {
788
- this.$bus.$on('mediaPlaybackEnded', this.onMediaEnded)
789
- this.$bus.$on('quizNoAnswer', this.showPopupNoAnswer)
790
-
791
- this.$bus.$on('hide-nav-controls', (value) => {
792
- setTimeout(() => this.hideNavigationCtrls(value), 10)
793
- })
794
-
795
- this.$bus.$on('show-nav-controls', (value) => {
796
- setTimeout(() => this.showNavigationCtrls(value), 10)
797
- })
798
-
799
- this.setNavigation()
800
-
801
- setTimeout(() => {
802
- this.initPage()
803
- }, 200)
804
- },
805
- methods: {
806
- initPage() {
807
- this.$bus.$emit('set-comp-status', 'AppCompNavigationFull', 'loading')
808
- this.quizData = this.getQuizData()
809
- this.setNextActivity()
810
- this.setPreviousActivity()
811
- this.setNavType()
812
- this.setAnchors()
813
- this.mediaPlaybackEnd = false
814
- this.pageInfo = this.getPageData(
815
- this.currentActivity,
816
- this.currentPageId
817
- ).content
818
- this.getMediaInfo()
819
-
820
- this.$bus.$emit('set-comp-status', 'AppCompNavigationFull', 'ready')
821
- },
822
-
823
- getMediaInfo() {
824
- this.hasMedia = this.pageInfo.type === 'pg_media'
825
- if (this.hasMedia) {
826
- this.mediaType = this.pageInfo.mediaData.mType
827
- }
828
- },
829
- /**
830
- * @description
831
- * Get quiz data from page data, set to null if none
832
- * @returns
833
- * Object: quiz data as set in the page or null if no quiz
834
- */
835
- getQuizData() {
836
- let qData = null
837
- const objKeys = Object.keys(this.getCurrentPage)
838
- for (let i = 0; i < objKeys.length; i++) {
839
- const key = objKeys[i]
840
- //check if a variable name starts with "quizData", you may find quizData1, quizData2... in some cases
841
- if (key.startsWith('quizData')) {
842
- qData = this.getCurrentPage[key]
843
- break
844
- }
845
- }
846
- return typeof qData !== 'undefined' && qData !== null ? qData : null
847
- },
848
- getActivity() {
849
- const { all_routes } = this.$helper.getRoutesFromVueRouter()
850
- const activity = all_routes.find(
851
- (route) => route.meta.id === this.$router.currentRoute.meta.activity_ref
852
- )
853
- return activity
854
- },
855
-
856
- goNextBranch() {
857
- //get the next branch where we want to go
858
- const branch = this.getNextBranch
859
- //get the name of the route for the first page of the next branch
860
- const firstPageRoute = branch.children[0].meta.children[0]._namedRoute
861
- //go there
862
- this.$router.push({
863
- name: firstPageRoute
864
- })
865
- },
866
- onMediaEnded() {
867
- this.mediaPlaybackEnd = true
868
- },
869
- /**
870
- * Popup warning the user that he has not answered the quiz.
871
- */
872
- showPopupNoAnswer() {
873
- let popupData, popupTitle, popupText
874
- let concluNext = this.conclusionComming()
875
- let lastPageInActivity = null
876
- if (!concluNext) {
877
- lastPageInActivity =
878
- this.nextPageLabel === this.$t('button.next_activity')
879
- } else {
880
- lastPageInActivity =
881
- this.nextPageLabel === this.$t('button.next_conclu')
882
- }
883
-
884
- popupTitle = this.$t('popup.title_warning')
885
-
886
- if (this.isBranching) {
887
- //branching
888
- if (this.currentNavType === this.navTypes.LASTBRANCHQUIZ) {
889
- //last page of branch
890
- if (this.getNextBranch !== false) {
891
- //last page of current branch, go to next branch
892
- popupText = this.$t('popup.text_noanswer_next_branch')
893
- } else {
894
- //last page of last branch, back to root
895
- popupText = this.$t('popup.text_noanswer_back_root')
896
- }
897
- } else {
898
- //normal branch page
899
- popupText = this.$t('popup.text_noanswer_next_page')
900
- }
901
- } else {
902
- //page is not a branch
903
- if (lastPageInActivity) {
904
- //last page of the activity
905
- popupText = this.$t('popup.text_noanswer_next_activity')
906
- } else {
907
- //normal activity page
908
- popupText = this.$t('popup.text_noanswer_next_page')
909
- }
910
- }
911
-
912
- popupData = {
913
- type: 'popup-noanswer',
914
- value: {
915
- title: popupTitle,
916
- text_1: popupText
917
- }
918
- }
919
- this.$bus.$emit('open-popup', popupData)
920
- this.$bus.$emit('retro-type', 'no_answer')
921
- },
922
- isBranchPageViewed(pageId) {
923
- if (this.isBranching) {
924
- const userInter = this.getUserInteraction
925
-
926
- if (userInter[this.currentActivity]&& userInter[this.currentActivity][pageId]) {
927
- return (
928
- userInter[this.currentActivity][pageId].userInteraction.state ===
929
- 'completed'
930
- )
931
- }
932
- }
933
- },
934
- backToRoot() {
935
- this.$router.push({
936
- name: this.$route.meta.branching_root
937
- })
938
- },
939
- backToMenu() {
940
- if (this.nextLesson) {
941
- this.$bus.$emit(
942
- 'launch-xapi-resource',
943
- this.$helper.getNextLessonEnv(this.nextLesson)
944
- )
945
- } else {
946
- this.$router.push({
947
- name: 'menu'
948
- })
949
- }
950
- },
951
- submitQuiz() {
952
- this.$bus.$emit('validateQuiz')
953
- },
954
- /** *****************Nav Methods*********************** */
955
- getNextPageBifurcationNochoise(activity, page) {
956
- let menu = this.getMenuSettings
957
- let bif
958
- //return if the page you are on is a declare as branching in menuSetting
959
- menu[activity].anchors.forEach((value) => {
960
- if (value.pageRef == page && value.branching) {
961
- bif = true
962
- }
963
- })
964
-
965
- return bif
966
- },
967
- getFirtsPageBif(activity, page) {
968
- let data
969
-
970
- // play string to make path sentence
971
- if (page.indexOf('0') == 1) {
972
- data = `page_${page.substring(page.indexOf('P') + 2)}`
973
- } else {
974
- data = `page_${page.substring(page.indexOf('P') + 1)}`
975
- }
976
- let menu = this.getMenuSettings
977
- let back = false
978
-
979
- //return if the page you are on is a declare as branching in menuSetting
980
- menu[activity].anchors.forEach((value) => {
981
- if (value.branching && value.branching.end == data) {
982
- back = true
983
- }
984
- })
985
-
986
- return back
987
- },
988
- getPageNavBif(activity, page) {
989
- let menu = this.getMenuSettings
990
- let data
991
-
992
- // return data star and end page
993
- menu[activity].anchors.forEach((value) => {
994
- if (value.pageRef == page && value.branching) {
995
- data = value.branching
996
- }
997
- })
998
- console.log('PAGE BIF DATA: ', data)
999
- return data
1000
- },
1001
- getPageNavBifStart(activity, page) {
1002
- let data
1003
-
1004
- // play string to make path sentence
1005
- if (page.indexOf('0') == 1) {
1006
- data = `page_${page.substring(page.indexOf('P') + 2)}`
1007
- } else {
1008
- data = `page_${page.substring(page.indexOf('P') + 1)}`
1009
- }
1010
- let menu = this.getMenuSettings
1011
- let back
1012
-
1013
- //return the start page of bif
1014
- menu[activity].anchors.forEach((value) => {
1015
- if (value.branching && value.branching.end == data) {
1016
- back = value.branching.start
1017
- }
1018
- })
1019
-
1020
- return back
1021
- },
1022
- goNext() {
1023
- //= =============Normal Navigation============
1024
- if (
1025
- this.navigationRoutes.context === 'normal' ||
1026
- this.navigationRoutes.context === 'introduction'
1027
- ) {
1028
- const pageIndex = this.navigationRoutes.cat.findIndex(
1029
- (route) => route._ref === this.$route.meta.id
1030
- )
1031
- const next = pageIndex + 1
1032
- // check if you did made a choice
1033
- if (
1034
- !this.getBifChoice &&
1035
- this.getNextPageBifurcationNochoise(
1036
- this.$route.meta.activity_ref,
1037
- this.$route.meta.id
1038
- )
1039
- ) {
1040
- // create path to make the jump
1041
- this.$router.push({
1042
- name: `${this.navigationRoutes.cat[0]._namedRoute}.${
1043
- this.getPageNavBif(
1044
- this.$route.meta.activity_ref,
1045
- this.$route.meta.id
1046
- ).end
1047
- }`
1048
- })
1049
- }
1050
- // Last page not reached. Navigate to the next page of the current liste
1051
- else if (pageIndex > -1 && this.navigationRoutes.cat[next]) {
1052
- this.$router.push({
1053
- name: `${this.navigationRoutes.cat[next]._namedRoute}`
1054
- })
1055
- }
1056
-
1057
- // last page of the current list reached. Navigate to next lesson
1058
- else if (this.autoNavigate && this.nextActivity) {
1059
- this.$router.push({
1060
- name: this.nextActivity._namedRoute
1061
- })
1062
- // if choice not made jump to end of bifurcation
1063
- }
1064
- }
1065
- // ==============branching navigation ==============
1066
- else if (this.navigationRoutes.context === 'branching') {
1067
- const pageIndex = this.navigationRoutes.cat.findIndex(
1068
- (route) => route._ref === this.$route.meta.id
1069
- )
1070
- const next = pageIndex + 1
1071
- // go to next to page in branch (branch_xx.page_xx)
1072
- if (pageIndex > -1 && this.navigationRoutes.cat[next]) {
1073
- this.$router.push({
1074
- name: `${this.navigationRoutes.cat[next]._namedRoute}`
1075
- })
1076
- }
1077
- }
1078
- },
1079
-
1080
- goPrevious() {
1081
- // ==================nornamal navigation ====================
1082
- if (
1083
- this.navigationRoutes.context === 'normal' ||
1084
- this.navigationRoutes.context === 'introduction'
1085
- ) {
1086
- const pageIndex = this.navigationRoutes.cat.findIndex(
1087
- (route) => route._ref === this.$route.meta.id
1088
- )
1089
- const previous = pageIndex - 1
1090
-
1091
- // validate if ther a branching and did you make a choice
1092
- if (
1093
- !this.getBifChoice &&
1094
- this.getFirtsPageBif(
1095
- this.$route.meta.activity_ref,
1096
- this.$route.meta.id
1097
- )
1098
- ) {
1099
- // create path to make the jump
1100
- if (
1101
- this.getPageNavBifStart(
1102
- this.$route.meta.activity_ref,
1103
- this.$route.meta.id
1104
- ) == 'page_1'
1105
- ) {
1106
- this.$router.push({
1107
- name: `${this.navigationRoutes.cat[0]._namedRoute}`
1108
- })
1109
- } else {
1110
- this.$router.push({
1111
- name: `${
1112
- this.navigationRoutes.cat[0]._namedRoute
1113
- }.${this.getPageNavBifStart(
1114
- this.$route.meta.activity_ref,
1115
- this.$route.meta.id
1116
- )}`
1117
- })
1118
- }
1119
-
1120
- // back to previous page of module (module.page_xx)
1121
- } else if (pageIndex > 0 && this.navigationRoutes.cat[previous]._path) {
1122
- this.$router.push({
1123
- name: `${this.navigationRoutes.cat[previous]._namedRoute}`
1124
- })
1125
- // this is the last page
1126
- } else {
1127
- // if allow navigation to activity active, navigate to previous activity
1128
- if (this.autoNavigate && this.previousActivity) {
1129
- this.$router.push({ name: this.previousActivity._namedRoute })
1130
- } else this.$router.push('/')
1131
- }
1132
- }
1133
- // ===================branching navigation ===================
1134
- else if (this.navigationRoutes.context === 'branching') {
1135
- let pageIndex = this.navigationRoutes.cat.findIndex(
1136
- (route) => route._ref === this.$route.meta.id
1137
- )
1138
- if (pageIndex === 0) {
1139
- return
1140
- } else if (pageIndex > 0) {
1141
- // back to the banch root (branch_xx)
1142
- if (pageIndex === 1) {
1143
- this.$router.push({
1144
- name: `${this.navigationRoutes.cat[(pageIndex -= 1)]._namedRoute}`
1145
- })
1146
- }
1147
- // back to previous page in the branch (branch_xx.page_xx)
1148
- else {
1149
- this.$router.push({
1150
- name: `${this.navigationRoutes.cat[(pageIndex -= 1)]._namedRoute}`
1151
- })
1152
- }
1153
- }
1154
- }
1155
- },
1156
- setNavType() {
1157
- //no primary nav in menu
1158
- if (this.isMenu) {
1159
- this.currentNavType = ''
1160
-
1161
- return
1162
- }
1163
-
1164
- let typeToSet = ''
1165
- if (this.isBranching) {
1166
- if (!this.nextAllowed) {
1167
- typeToSet = this.hasQuiz
1168
- ? this.navTypes.LASTBRANCHQUIZ
1169
- : this.navTypes.LASTBRANCHPAGE
1170
- } else {
1171
- typeToSet = this.hasQuiz ? this.navTypes.QUIZ : this.navTypes.BRANCH
1172
- }
1173
- } else {
1174
- if (this.nextActivity === null) {
1175
- typeToSet = this.hasQuiz
1176
- ? this.navTypes.QUIZ
1177
- : this.navTypes.FINALPAGE
1178
- } else {
1179
- typeToSet = this.hasQuiz ? this.navTypes.QUIZ : this.navTypes.ACTIVITY
1180
- }
1181
- }
1182
- if (typeToSet != '') {
1183
- this.currentNavType = typeToSet
1184
- } else {
1185
- console.warn('Navigation principale: Type de page invalide')
1186
- }
1187
- },
1188
- /*
1189
- * watch currentRoute to define the navigation catalog
1190
- * check if currentRoute type is a branching
1191
- */
1192
- setNavigation() {
1193
- // current Route is module
1194
- this.$bus.$emit(
1195
- 'set-comp-status',
1196
- 'AppCompNavigationFull_setNavigation',
1197
- 'loading'
1198
- )
1199
- this.currentActivity = this.$router.currentRoute.meta.activity_ref
1200
- this.currentPageId = this.$router.currentRoute.meta.id
1201
-
1202
- const { all_routes, meta } = this.$helper.getRoutesFromVueRouter()
1203
-
1204
- if (this.$router.currentRoute.name === 'module') {
1205
- this.navigationRoutes = {
1206
- context: 'module',
1207
- cat: meta.children
1208
- }
1209
- }
1210
- // current Route is a branch of a branching
1211
- else if (this.$router.currentRoute.meta.type === 'branch') {
1212
- this.navigationRoutes = {
1213
- context: 'branching',
1214
- cat: this.$router.currentRoute.meta.activity_ref
1215
- }
1216
- }
1217
- // currentRoute is branch_page of a branch
1218
- // find the current branch to get its children
1219
- else if (this.$router.currentRoute.meta.type === 'branch_page') {
1220
- // find the activity
1221
- const a = all_routes.find(
1222
- (route) =>
1223
- route.meta.id === this.$router.currentRoute.meta.activity_ref
1224
- )
1225
- // find the Branching
1226
- if (a && a.children) {
1227
- const b = a.children.find(
1228
- (route) =>
1229
- route.meta.id === this.$router.currentRoute.meta.branching_ref
1230
- )
1231
- // find the branch to get its nested route
1232
- for (const route of b.children) {
1233
- if (route.path === this.$router.currentRoute.meta.parent._path) {
1234
- // define navigation routes
1235
- this.navigationRoutes = {
1236
- context: 'branching',
1237
- cat: route.meta.children
1238
- }
1239
- }
1240
- }
1241
- }
1242
- }
1243
- // Navigation catalog is the introduction
1244
- else if (
1245
- this.$router.currentRoute.meta.type === 'introduction' ||
1246
- this.$router.currentRoute.meta.type === 'menu'
1247
- ) {
1248
- const a = all_routes.find(
1249
- (route) =>
1250
- route.meta.id === this.$router.currentRoute.meta.activity_ref
1251
- )
1252
- if (a) {
1253
- let r = []
1254
- //if Intro acitive get all the routes for indroduction or just the menu
1255
- this.getIntroStatus
1256
- ? r.push(...a.meta.children)
1257
- : r.push(
1258
- a.meta.children.find(
1259
- (el) => !el._namedRoute.includes('introduction')
1260
- )
1261
- )
1262
- this.navigationRoutes = {
1263
- context: 'introduction',
1264
- cat: r
1265
- }
1266
- }
1267
- }
1268
- // Navigation catalog is pages of Activity ||menu
1269
- else {
1270
- const a = all_routes.find(
1271
- (route) =>
1272
- route.meta.id === this.$router.currentRoute.meta.activity_ref
1273
- )
1274
- if (a) {
1275
- this.navigationRoutes = {
1276
- context: 'normal',
1277
- cat: a.meta.children
1278
- }
1279
- }
1280
- }
1281
- this.$bus.$emit(
1282
- 'set-comp-status',
1283
- 'AppCompNavigationFull_setNavigation',
1284
- 'ready'
1285
- )
1286
- }, // END setNaviagation
1287
- /**
1288
- *@description: set the next activity to for the Navigation
1289
- */
1290
- setNextActivity() {
1291
- this.nextPageLabel = this.$t('button.next')
1292
- if (this.autoNavigate && this.navigationRoutes) {
1293
- // get all the activities routes from router
1294
- const { meta } = this.$helper.getRoutesFromVueRouter()
1295
- const allRoutes = meta.children
1296
-
1297
- // get the index of the current route
1298
- const current = this.navigationRoutes.cat.findIndex(
1299
- (route) => route._ref === this.$route.meta.id
1300
- )
1301
-
1302
- switch (this.navigationRoutes.context) {
1303
- case 'introduction': {
1304
- // This is the last page in the of introduction (this the menu)
1305
- if (
1306
- current === this.navigationRoutes.cat.length - 1 &&
1307
- allRoutes.length > 1
1308
- ) {
1309
- this.nextActivity = allRoutes[1] // go to the 1st activity
1310
- let conclu = this.conclusionComming()
1311
- if (!conclu) {
1312
- this.nextPageLabel = this.$t('button.next_activity')
1313
- } else {
1314
- this.nextPageLabel = this.$t('button.next_conclu')
1315
- }
1316
- }
1317
- //setting next activity or null if undefined, will show "next lesson" button
1318
- else
1319
- this.nextActivity = this.navigationRoutes.cat[current + 1] || null
1320
- break
1321
- }
1322
- case 'normal': {
1323
- // find the current activity ref in the router catalog
1324
- const currentRouteIndex = allRoutes.findIndex(
1325
- (route) => route._ref === this.$route.meta.activity_ref
1326
- )
1327
- // this is the Last page in current activity
1328
- if (
1329
- current === this.navigationRoutes.cat.length - 1 &&
1330
- allRoutes[currentRouteIndex + 1]
1331
- ) {
1332
- this.nextActivity = allRoutes[currentRouteIndex + 1] // get the next activity in the router catalog
1333
- let conclu = this.conclusionComming()
1334
- if (!conclu) {
1335
- this.nextPageLabel = this.$t('button.next_activity')
1336
- } else {
1337
- this.nextPageLabel = this.$t('button.next_conclu')
1338
- }
1339
- }
1340
- // this is in the same activity return the next page of the activity
1341
- else if (this.navigationRoutes.cat[current + 1]) {
1342
- this.nextActivity = this.navigationRoutes.cat[current + 1]
1343
- }
1344
- // There is no other activity after the current one
1345
- else this.nextActivity = null
1346
-
1347
- break
1348
- }
1349
- case 'branching': {
1350
- // find the current activity ref in the router catalog
1351
- const currentRouteIndex = allRoutes.findIndex(
1352
- (route) => route._ref === this.$route.meta.activity_ref
1353
- )
1354
- //this is the Last page the current branching
1355
- if (allRoutes[currentRouteIndex + 1]) {
1356
- this.nextActivity = allRoutes[currentRouteIndex + 1] // get the next activity in the router catalog
1357
- }
1358
- // There is no other activity after the current one
1359
- else {
1360
- this.nextActivity = null
1361
- }
1362
- break
1363
- }
1364
- }
1365
- } else this.nextActivity = null
1366
-
1367
- //Update next activity information to the store
1368
- this.$store.dispatch('updateNextActivity', this.nextActivity)
1369
- },
1370
- /**
1371
- * @description: set previous activity for the navigation
1372
- */
1373
- setPreviousActivity() {
1374
- if (this.autoNavigate && this.navigationRoutes) {
1375
- // get all the activities routes from router
1376
- const { all_routes: allRoutes } = this.$helper.getRoutesFromVueRouter()
1377
-
1378
- // get the index of the current route
1379
- const current = this.navigationRoutes.cat.findIndex(
1380
- (route) => route._ref === this.$route.meta.id
1381
- )
1382
-
1383
- switch (this.navigationRoutes.context) {
1384
- case 'introduction': {
1385
- // This is the first page in the introduction
1386
- if (current === 0) {
1387
- this.previousActivity = null
1388
- } else {
1389
- this.previousActivity = this.navigationRoutes.cat[current - 1]
1390
- }
1391
- break
1392
- }
1393
- case 'normal': {
1394
- // get the index of the current route
1395
- const currentRouteIndex = allRoutes.findIndex(
1396
- (route) => route.meta.id === this.$route.meta.activity_ref
1397
- )
1398
- // this is the 1st page of the 1st activity in the router catologue
1399
- // return point is introduction
1400
- if (current === 0 && currentRouteIndex === 1) {
1401
- const _length = allRoutes[0].children.length
1402
- this.previousActivity = allRoutes[0].meta.children[_length - 1] // get last page of the introduction navigation context
1403
- }
1404
- // This is the 1st page in another activity in the router catalogue
1405
- else if (allRoutes[currentRouteIndex - 1] && current === 0) {
1406
- const _length = allRoutes[currentRouteIndex - 1].children.length
1407
- this.previousActivity =
1408
- allRoutes[currentRouteIndex - 1].meta.children[_length - 1] // previous is last page of previous activity
1409
- }
1410
- // This is a simply another page in an activity
1411
- else this.previousActivity = this.navigationRoutes.cat[current - 1]
1412
- break
1413
- }
1414
- case 'branching': {
1415
- // get the index of the current route
1416
- const currentRouteIndex = allRoutes.findIndex(
1417
- (route) => route.meta.id === this.$route.meta.activity_ref
1418
- )
1419
- //this is the Last page the current branching
1420
- if (allRoutes[currentRouteIndex - 1]) {
1421
- this.previousActivity = allRoutes[currentRouteIndex - 1] // get the next activity in the router catalog
1422
- } else this.previousActivity = null
1423
- break
1424
- }
1425
- }
1426
- } else this.previousActivity = null
1427
-
1428
- //Update next activity information to the store
1429
- this.$store.dispatch('updatePreviousActivity', this.previousActivity)
1430
- },
1431
-
1432
- /**
1433
- * @description: set navigable section of the nav bar according to activity
1434
- */
1435
- setAnchors() {
1436
- let achrs = []
1437
- let activity = this.$route.meta.activity_ref
1438
- if (activity && this.getAnchorsForActivity(activity))
1439
- achrs = this.getAnchorsForActivity(activity)
1440
- // build routes for anchors
1441
- for (let a of achrs) {
1442
- //search the route for the anchor reference page in the navigation routes
1443
- const route = this.navigationRoutes.cat.find(
1444
- (r) => r._ref === a.pageRef
1445
- )
1446
- //set the anchors' path
1447
- if (route) {
1448
- a.path = route._namedRoute
1449
- }
1450
- }
1451
- this.anchors = achrs
1452
- },
1453
-
1454
- iscurrentAnchor(anchor) {
1455
- let num
1456
- let str
1457
- let col = []
1458
- let curent = parseInt(anchor.pageRef.substring(1))
1459
-
1460
- this.anchors.forEach((value) => {
1461
- num = parseInt(value.pageRef.substring(1))
1462
- col.push(num)
1463
- })
1464
-
1465
- if (this.$route.meta.id === anchor.pageRef) {
1466
- this.$store.dispatch('updateCurrentSection', anchor)
1467
- return true
1468
- } else {
1469
- let goal = parseInt(this.$route.meta.id.substring(1))
1470
-
1471
- // return closet number in the array
1472
- // https://stackoverflow.com/questions/8584902/get-the-closest-number-out-of-an-array
1473
- let closenum = col.reduce(function(prev, curr) {
1474
- if (Math.abs(curr - goal) < Math.abs(prev - goal)) {
1475
- // must add a nother condition to ensure that the goal is smaller than the current to ensure that the section is still the previous one
1476
- if (goal < curr) return prev
1477
- else return curr
1478
- } else {
1479
- return prev
1480
- }
1481
- })
1482
- if (closenum == curent) {
1483
- if (curent < 10) {
1484
- str = `P0${curent}`
1485
- } else {
1486
- str = `P${curent}`
1487
- }
1488
-
1489
- if (anchor.pageRef == str) {
1490
- this.$store.dispatch('updateCurrentSection', anchor)
1491
- return true
1492
- }
1493
- }
1494
- }
1495
- },
1496
- conclusionComming() {
1497
- //Get before to last activty
1498
- let act = Object.keys(this.getAllActivitiesState)
1499
- let beforeLastActivity = act[act.length - 2]
1500
-
1501
- //Get last page of before to last activty
1502
- let pageinfo = this.getActivity()
1503
- let lastPage = pageinfo.children[pageinfo.children.length - 1].meta.id
1504
-
1505
- //Get current page info
1506
- let currantActivity = this.getCurrentPage
1507
-
1508
- //compare and find
1509
- if (
1510
- currantActivity.activityRef == beforeLastActivity &&
1511
- currantActivity.id == lastPage
1512
- ) {
1513
- return true
1514
- } else {
1515
- return false
1516
- }
1517
- },
1518
- blockBranching(data) {
1519
- let page = data.pageRef
1520
- let act = this.getAct(data.path)
1521
- let choosen = this.getBifChoice
1522
- if (data.branching) {
1523
- if (choosen && choosen.act == act && choosen.page == page) {
1524
- return false
1525
- } else {
1526
- return true
1527
- }
1528
- }
1529
- },
1530
- getAct(data) {
1531
- if (data) {
1532
- if (data.substring(data.indexOf('_') + 1).length == 1) {
1533
- return `A0${data.substring(data.indexOf('_') + 1)}`
1534
- } else {
1535
- return `A${data.substring(data.indexOf('_') + 1)}`
1536
- }
1537
- }
1538
- },
1539
- titlePageBranching(data) {
1540
- return data.replace('-', ' ')
1541
- },
1542
-
1543
- /**
1544
- * @description hide the navigation of the application
1545
- * @param {String} s - s name of the navigation element to hide ('back' | 'next')
1546
- */
1547
- hideNavigationCtrls(s) {
1548
- s = s || 'all'
1549
-
1550
- if (s && !['back', 'next', 'all'].includes(s.toLowerCase(s))) return
1551
-
1552
- switch (s) {
1553
- case 'back':
1554
- {
1555
- this.$store.dispatch('setShowNavLeftCtrl', false)
1556
- }
1557
- break
1558
- case 'next':
1559
- {
1560
- this.$store.dispatch('setShowNavRightCtrl', false)
1561
- this.$store.dispatch('setShowPrimaryCtrl', false)
1562
- }
1563
-
1564
- break
1565
-
1566
- case 'all':
1567
- {
1568
- //hide the Upper Nav bar controls
1569
- this.$store.dispatch('setShowNavLeftCtrl', false)
1570
- this.$store.dispatch('setShowNavRightCtrl', false)
1571
-
1572
- //hide the main navigation to next page
1573
- this.$store.dispatch('setShowPrimaryCtrl', false)
1574
- }
1575
- break
1576
- }
1577
- },
1578
-
1579
- /**
1580
- * @description show the navigation of the application
1581
- * @param {String} s - s name of the navigation element to hide ('back' | 'next')
1582
- */
1583
- showNavigationCtrls(s) {
1584
- s = s || 'all'
1585
-
1586
- if (s && !['back', 'next', 'all'].includes(s.toLowerCase(s))) return
1587
-
1588
- switch (s) {
1589
- case 'back':
1590
- {
1591
- this.$store.dispatch('setShowNavLeftCtrl', true)
1592
- }
1593
- break
1594
- case 'next':
1595
- {
1596
- this.$store.dispatch('setShowNavRightCtrl', true)
1597
- this.$store.dispatch('setShowPrimaryCtrl', true)
1598
- }
1599
-
1600
- break
1601
-
1602
- case 'all':
1603
- {
1604
- //hide the Upper Nav bar controls
1605
- this.$store.dispatch('setShowNavLeftCtrl', true)
1606
- this.$store.dispatch('setShowNavRightCtrl', true)
1607
-
1608
- //hide the main navigation to next page
1609
- this.$store.dispatch('setShowPrimaryCtrl', true)
1610
- }
1611
- break
1612
- }
1613
- },
1614
-
1615
- /**
1616
- * @description - Method to dynamically set the css display poperty of the controls button
1617
- * @Param {Bool} - true|false
1618
- */
1619
- displayStyle(bool) {
1620
- let style = bool ? { display: 'flex' } : { display: 'none' }
1621
- return style
1622
- }
1623
- }
1624
- }
1625
- </script>
1626
-
1627
- <style lang="scss">
1628
- .full {
1629
- &.app-ctrl {
1630
- display: flex;
1631
- justify-content: center;
1632
- width: 100%;
1633
- * {
1634
- user-select: none;
1635
- }
1636
- padding-left: 15px;
1637
- padding-right: 15px;
1638
- }
1639
-
1640
- #btn_back_summary {
1641
- margin-right: 10px;
1642
- svg {
1643
- margin-right: 12px;
1644
- }
1645
-
1646
- //** label disapear in mobile**//
1647
- @media screen and (max-width: 1100px) {
1648
- span {
1649
- display: none;
1650
- }
1651
-
1652
- svg {
1653
- margin-right: 0;
1654
- }
1655
- }
1656
- }
1657
-
1658
- #btn_back_root {
1659
- svg {
1660
- width: 21px;
1661
- height: 18px;
1662
- margin-right: 12px;
1663
- }
1664
- }
1665
-
1666
- #btn_notes {
1667
- svg {
1668
- margin-right: 12px;
1669
- }
1670
- }
1671
-
1672
- .nav_main_btn {
1673
- padding-left: 12px;
1674
- padding-right: 12px;
1675
- display: flex;
1676
- align-items: center;
1677
- border: none;
1678
- justify-content: center;
1679
- box-sizing: border-box;
1680
- }
1681
-
1682
- #page_nav {
1683
- display: flex;
1684
- flex: 1;
1685
- align-items: center;
1686
- margin-right: 16px;
1687
- justify-content: center;
1688
- }
1689
-
1690
- #nav_left_btns {
1691
- display: flex;
1692
- flex: 1;
1693
- align-items: center;
1694
- justify-content: flex-start;
1695
- }
1696
- #nav_right_btns {
1697
- display: flex;
1698
- flex: 1;
1699
- align-items: center;
1700
- justify-content: flex-end;
1701
- margin-left: auto;
1702
- }
1703
-
1704
- $transProps: 0.15s ease-out;
1705
- #activity_progress {
1706
- height: 100%;
1707
- display: flex;
1708
- align-items: center;
1709
- justify-content: center;
1710
-
1711
- div {
1712
- display: flex;
1713
- justify-content: center;
1714
- align-items: center;
1715
-
1716
- .activity_progress_link {
1717
- display: flex;
1718
- justify-content: center;
1719
- position: relative;
1720
- margin: 0 5px;
1721
-
1722
- .page_tooltip {
1723
- opacity: 0;
1724
- visibility: hidden;
1725
- pointer-events: none;
1726
- padding: 15px;
1727
- position: relative;
1728
- display: flex;
1729
- flex-direction: column;
1730
- align-items: center;
1731
- margin-top: 35px;
1732
-
1733
- &::before {
1734
- position: relative;
1735
- content: '';
1736
- width: 0;
1737
- height: 0;
1738
- padding: 0;
1739
- }
1740
-
1741
- span {
1742
- white-space: nowrap;
1743
- display: block;
1744
- }
1745
- }
1746
-
1747
- &:hover {
1748
- .page_tooltip {
1749
- visibility: visible;
1750
- opacity: 1;
1751
- }
1752
- }
1753
- }
1754
-
1755
- &.branching_progress {
1756
- .activity_progress_link {
1757
- margin: 0 8px;
1758
- }
1759
- }
1760
- }
1761
- }
1762
-
1763
- .branching {
1764
- & > #page_nav {
1765
- margin-right: 0px;
1766
- }
1767
- }
1768
-
1769
- // primary navigation styling
1770
-
1771
- #popup_primary_nav_btn {
1772
- padding: 0 15px;
1773
- margin-left: 50px;
1774
- }
1775
- .primary_nav_btn {
1776
- padding: 0 30px;
1777
- display: inline-block;
1778
-
1779
- &.right {
1780
- margin-left: 35px;
1781
- }
1782
- svg {
1783
- margin-left: 19px;
1784
- }
1785
- }
1786
- }
1787
- .ico-back-branch {
1788
- width: 21px;
1789
- height: 18px;
1790
- }
1791
- </style>