fcad-core-dragon 2.0.0-beta.3 → 2.0.0-beta.5

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 (90) hide show
  1. package/.editorconfig +33 -33
  2. package/.eslintignore +29 -29
  3. package/.eslintrc.cjs +81 -81
  4. package/CHANGELOG +13 -0
  5. package/README.md +71 -71
  6. package/bk.scss +117 -117
  7. package/package.json +8 -8
  8. package/src/$locales/en.json +145 -143
  9. package/src/$locales/fr.json +107 -105
  10. package/src/assets/data/onboardingMessages.json +47 -47
  11. package/src/components/AppBase.vue +1150 -1054
  12. package/src/components/AppBaseButton.test.js +22 -0
  13. package/src/components/AppBaseButton.vue +93 -87
  14. package/src/components/AppBaseErrorDisplay.vue +438 -438
  15. package/src/components/AppBaseFlipCard.vue +84 -84
  16. package/src/components/AppBaseModule.vue +1657 -1673
  17. package/src/components/AppBasePage.vue +742 -779
  18. package/src/components/AppBasePopover.vue +41 -41
  19. package/src/components/AppCompAudio.vue +265 -234
  20. package/src/components/AppCompBranchButtons.vue +556 -552
  21. package/src/components/AppCompButtonProgress.vue +121 -126
  22. package/src/components/AppCompCarousel.vue +328 -298
  23. package/src/components/AppCompInputCheckBoxNext.vue +200 -195
  24. package/src/components/AppCompInputDropdownNext.vue +201 -159
  25. package/src/components/AppCompInputRadioNext.vue +152 -152
  26. package/src/components/AppCompInputTextNext.vue +125 -106
  27. package/src/components/AppCompInputTextTableNext.vue +142 -141
  28. package/src/components/AppCompInputTextToFillDropdownNext.vue +238 -230
  29. package/src/components/AppCompInputTextToFillNext.vue +171 -171
  30. package/src/components/AppCompJauge.vue +74 -74
  31. package/src/components/AppCompMenu.vue +25 -10
  32. package/src/components/AppCompMenuItem.vue +228 -228
  33. package/src/components/AppCompNavigation.vue +972 -960
  34. package/src/components/AppCompNoteCall.vue +159 -133
  35. package/src/components/AppCompNoteCredit.vue +490 -292
  36. package/src/components/AppCompPlayBar.vue +1217 -1218
  37. package/src/components/AppCompPlayBarNext.vue +2060 -2052
  38. package/src/components/AppCompPlayBarProgress.vue +82 -82
  39. package/src/components/AppCompPopUpNext.vue +500 -503
  40. package/src/components/AppCompQuizNext.vue +2908 -2904
  41. package/src/components/AppCompQuizRecall.vue +298 -276
  42. package/src/components/AppCompSVGNext.vue +347 -347
  43. package/src/components/AppCompSettingsMenu.vue +172 -172
  44. package/src/components/AppCompTableOfContent.vue +386 -387
  45. package/src/components/AppCompTranscript.vue +24 -24
  46. package/src/components/AppCompVideoPlayer.vue +368 -368
  47. package/src/components/BaseModule.vue +55 -72
  48. package/src/components/tests__/AppBaseButton.spec.js +53 -0
  49. package/src/composables/useQuiz.js +206 -206
  50. package/src/externalComps/ModuleView.vue +22 -22
  51. package/src/externalComps/SummaryView.vue +91 -91
  52. package/src/main.js +272 -272
  53. package/src/mixins/$mediaMixins.js +819 -819
  54. package/src/mixins/timerMixin.js +155 -155
  55. package/src/module/stores/appStore.js +954 -893
  56. package/src/module/xapi/ADL.js +380 -376
  57. package/src/module/xapi/Crypto/Hasher.js +241 -241
  58. package/src/module/xapi/Crypto/WordArray.js +278 -278
  59. package/src/module/xapi/Crypto/algorithms/BufferedBlockAlgorithm.js +103 -103
  60. package/src/module/xapi/Crypto/algorithms/C_algo.js +315 -315
  61. package/src/module/xapi/Crypto/algorithms/HMAC.js +9 -9
  62. package/src/module/xapi/Crypto/algorithms/SHA1.js +9 -9
  63. package/src/module/xapi/Crypto/encoders/Base.js +105 -105
  64. package/src/module/xapi/Crypto/encoders/Base64.js +99 -99
  65. package/src/module/xapi/Crypto/encoders/Hex.js +61 -61
  66. package/src/module/xapi/Crypto/encoders/Latin1.js +61 -61
  67. package/src/module/xapi/Crypto/encoders/Utf8.js +45 -45
  68. package/src/module/xapi/Statement/agent.js +55 -55
  69. package/src/module/xapi/Statement/index.js +259 -259
  70. package/src/module/xapi/Statement/statement.js +253 -253
  71. package/src/module/xapi/launch.js +157 -157
  72. package/src/module/xapi/utils.js +167 -167
  73. package/src/module/xapi/verbs.js +294 -294
  74. package/src/module/xapi/wrapper.js +1963 -1963
  75. package/src/module/xapi/xapiStatement.js +444 -444
  76. package/src/plugins/bus.js +8 -8
  77. package/src/plugins/gsap.js +14 -14
  78. package/src/plugins/helper.js +355 -308
  79. package/src/plugins/i18n.js +44 -44
  80. package/src/plugins/idb.js +227 -219
  81. package/src/plugins/save.js +37 -37
  82. package/src/plugins/scorm.js +287 -287
  83. package/src/plugins/xapi.js +11 -11
  84. package/src/public/index.html +33 -33
  85. package/src/router/index.js +48 -43
  86. package/src/router/routes.js +312 -312
  87. package/src/shared/generalfuncs.js +210 -210
  88. package/src/shared/validators.js +926 -1069
  89. package/vitest.config.js +19 -0
  90. package/vite.config.js +0 -27
@@ -1,387 +1,386 @@
1
- <!--
2
- ----------------- MUST ADD ERROR GESTION ------------------
3
- ----------------- MUST ADD label terminer ------------------
4
- ----------------- MUST ADD css ------------------
5
-
6
- @ Description: This component is used to display the sub menu to show the anchor of a activity.
7
- @ What it does: The component show the data that was enter in menu.json and create de link to the anchor from those information. This componant must be use with app-comp-menu-Item and app-comp-menu.
8
- -->
9
-
10
- <template>
11
- <div v-if="error" id="sidebar-submenu" :class="{ isOpen: open }">
12
- <app-base-button
13
- id="close-toc"
14
- class="btn-ghost"
15
- :title="$t('button.closePopUp')"
16
- @click="close()"
17
- >
18
- <svg>
19
- <use href="#close-square-icon" />
20
- </svg>
21
- </app-base-button>
22
-
23
- <p class="t-act" v-html="title"></p>
24
-
25
- <div class="box-prog-act">
26
- <p>
27
- {{ $t('text.activity_progress') }}
28
- <span>{{ actProgress }}</span>
29
- </p>
30
- </div>
31
-
32
- <div class="box-anchor">
33
- <p class="t-toc">{{ $t('text.toc') }}</p>
34
-
35
- <a
36
- v-for="(anchor, index) of anchors"
37
- :key="anchor.title"
38
- class="toc-item"
39
- :done="sectionProgress(index)"
40
- @click="closeAndNextPage(anchor.path)"
41
- >
42
- <div class="box-text-anchor">
43
- <div class="text-anchor">
44
- <p class="anchor-t" v-html="anchor.title"></p>
45
- <p class="state">
46
- <svg>
47
- <use href="#check-toc" />
48
- </svg>
49
- {{ $t('text.complete') }}
50
- </p>
51
- </div>
52
- <svg>
53
- <use href="#chevronD-icon" />
54
- </svg>
55
- </div>
56
- </a>
57
- </div>
58
- </div>
59
- <div v-else id="sidebar-submenu" :class="{ isOpen: open }">
60
- <p>
61
- Cette activité n'existe pas dans menu setting, svp l'ajouter à votre menu
62
- setting
63
- </p>
64
- </div>
65
- </template>
66
-
67
- <script>
68
- import { mapState, mapActions } from 'pinia'
69
- import { useAppStore } from '../module/stores/appStore'
70
- export default {
71
- data() {
72
- return {
73
- title: '',
74
- anchors: [],
75
- activity: '',
76
- open: false,
77
- menuInfo: null,
78
- actProgress: null,
79
- error: true
80
- }
81
- },
82
- computed: {
83
- ...mapState(useAppStore, [
84
- 'getMenuSettings',
85
- 'getAnchorsForActivity',
86
- 'getBifChoice',
87
- 'getAllCompleted',
88
- 'getAllActivitiesState'
89
- ])
90
- },
91
- beforeUnmount() {
92
- this.$bus.$off('toggle-widget', this.onToggleWidget)
93
- this.$bus.$off('close-widget', this.onCloseWidget)
94
- this.$bus.$off('info-activity', this.onInfoActivity)
95
- },
96
- mounted() {
97
- this.$bus.$on('toggle-widget', this.onToggleWidget)
98
- this.$bus.$on('close-widget', this.onCloseWidget)
99
- this.$bus.$on('info-activity', this.onInfoActivity)
100
- },
101
- methods: {
102
- ...mapActions(useAppStore, ['updateWidgetOpen']),
103
- onInfoActivity(data) {
104
- //should be condition to avoid event fireing multiple time on call
105
-
106
- if (data) {
107
- this.reset()
108
- this.activity = data
109
-
110
- if (!this.getMenuSettings[data]) {
111
- return (this.error = false)
112
- } else {
113
- this.getInfoSubMenu(data)
114
- this.getProgressActivity(data)
115
- }
116
- }
117
- },
118
- onCloseWidget(data) {
119
- this.open = false
120
- this.updateWidgetOpen(false)
121
- this.reset()
122
- },
123
- onToggleWidget(data) {
124
- if (data == 'toc') {
125
- this.open = !this.open
126
- this.updateWidgetOpen(true)
127
- } else {
128
- this.updateWidgetOpen(false)
129
- this.open = false
130
- }
131
- },
132
- /* @Description:Get and set the section to output
133
- * @params: activity {Object}: the activity which sections need to be output
134
- */
135
- //
136
- getInfoSubMenu(activity) {
137
- //get the anchors for this activity from the store
138
- let menuInfo = this.getMenuSettings
139
-
140
- let nb = null
141
-
142
- //Get title are if no title construct acitivty
143
- if (menuInfo[activity] && menuInfo[activity].title)
144
- this.title = menuInfo[activity].title
145
-
146
- if (activity.charAt(1) == '0' || activity.charAt(1) == 0)
147
- nb = activity.substr(2)
148
- else nb = activity.substr(1)
149
-
150
- this.title = `${this.$t('text.activity')} ${nb} : ${menuInfo[activity].subTitle}`
151
-
152
- //create anchors title and path
153
- if (menuInfo[activity] && menuInfo[activity].anchors) {
154
- menuInfo[activity].anchors.forEach((element) => {
155
- //
156
- let _path = null
157
- let b = null
158
- if (nb == 0 || nb == '0') {
159
- b = `introduction`
160
- } else {
161
- b = `activite_${nb}`
162
- }
163
-
164
- if (element.page == 'page_1') {
165
- _path = `${b}`
166
- } else {
167
- _path = `${b}.${element.page}`
168
- }
169
-
170
- let info = {
171
- title: `${element.anchorName}`,
172
- path: _path
173
- }
174
- this.anchors.push(info)
175
- })
176
- }
177
- },
178
- disable(data) {
179
- let page = data.pageRef
180
- let act = this.getAct(data.path)
181
- let choosen = this.getBifChoice
182
-
183
- // disable if bif
184
- if (data.bif && choosen) {
185
- if (choosen.act == act && choosen.page == page) {
186
- return false
187
- } else {
188
- return true
189
- }
190
- } else {
191
- return false
192
- }
193
- },
194
- getAct(data) {
195
- //return the id need it
196
- if (data) {
197
- if (data.substring(data.indexOf('_') + 1).length == 1) {
198
- return `A0${data.substring(data.indexOf('_') + 1)}`
199
- } else {
200
- return `A${data.substring(data.indexOf('_') + 1)}`
201
- }
202
- }
203
- },
204
- /**
205
- * @description Gives gives length of completed page for an activity
206
- * @param {String} idActivity
207
- * @returns {Number}
208
- */
209
- getProgressActivity(idActivity) {
210
- /// give all the page that are complete to the gauge
211
- if (idActivity) {
212
- let completed = []
213
- if (this.getAllCompleted[idActivity]) {
214
- completed = this.getAllCompleted[idActivity] //get all completed page for the activity
215
- }
216
-
217
- const allActivitiesState = JSON.parse(
218
- JSON.stringify(this.getAllActivitiesState)
219
- )
220
- let size = allActivitiesState[idActivity]
221
- ? allActivitiesState[idActivity].size
222
- : 0
223
-
224
- // return pourcent of activity completion
225
- this.actProgress = `${Math.round((completed.length * 100) / size)} %`
226
- }
227
- },
228
- close() {
229
- this.open = !this.open
230
- this.updateWidgetOpen(this.open)
231
- },
232
- closeAndNextPage(NextPage) {
233
- this.open = !this.open
234
- this.updateWidgetOpen(this.open)
235
- this.$router.push({ name: NextPage })
236
- },
237
- reset() {
238
- this.anchors = []
239
- this.activity = ''
240
- },
241
- sectionProgress(index) {
242
- let menuInfo = this.getMenuSettings
243
- let nextIndex = index + 1
244
- let nextSec
245
- let curSec = menuInfo[this.activity].anchors[index].pageRef
246
-
247
- let nb
248
- let tabPageSec = []
249
- let tabcomplete = []
250
-
251
- if (nextIndex < menuInfo[this.activity].anchors.length) {
252
- nextSec = menuInfo[this.activity].anchors[nextIndex].pageRef
253
- }
254
-
255
- if (nextSec != undefined) {
256
- nb = parseInt(nextSec.substring(1))
257
-
258
- while (nb > parseInt(curSec.substring(1))) {
259
- nb--
260
- if (nb < 10) tabPageSec.push(`P0${nb}`)
261
- else tabPageSec.push(`P${nb}`)
262
- }
263
- } else {
264
- if (menuInfo[this.activity].anchors.length == 1) {
265
- let numPage = this.getAllActivitiesState[this.activity].size
266
-
267
- for (let g = 1; g == numPage; g++) {
268
- tabPageSec.push(`P${g}`)
269
- }
270
-
271
- if (
272
- this.getAllCompleted[this.activity].length !==
273
- this.getAllActivitiesState[this.activity].size
274
- )
275
- return false
276
- }
277
- tabPageSec.push(curSec)
278
- }
279
-
280
- let completeActPage = this.getAllCompleted[this.activity]
281
-
282
- if (completeActPage) {
283
- completeActPage.find((value) => {
284
- let w = Object.keys(value)
285
- tabcomplete.push(w[0])
286
- })
287
-
288
- const isSubset = (array1, array2) =>
289
- array2.every((element) => array1.includes(element))
290
-
291
- return isSubset(tabcomplete, tabPageSec)
292
- }
293
- }
294
- }
295
- }
296
- </script>
297
- <style lang="scss">
298
- #sidebar-submenu {
299
- display: none;
300
- position: absolute;
301
- left: 75px;
302
- top: 0;
303
- max-height: 592px;
304
- width: 476px;
305
- transition: left 0.5s ease-in-out;
306
-
307
- &.isOpen {
308
- display: block;
309
- }
310
-
311
- #close-toc {
312
- position: absolute;
313
- right: 24px;
314
- margin-bottom: 0;
315
- padding: 11px;
316
- width: 48px;
317
- height: 48px;
318
- display: flex;
319
- justify-content: center;
320
-
321
- &:focus {
322
- box-shadow: inherit !important;
323
- }
324
- }
325
-
326
- .box-prog-act {
327
- width: 319px;
328
- display: flex;
329
- flex-direction: row;
330
- margin-bottom: 16px;
331
-
332
- p {
333
- position: relative;
334
- width: 100%;
335
-
336
- span {
337
- position: absolute;
338
- right: 0;
339
- top: 0;
340
- }
341
- }
342
- }
343
-
344
- .box-anchor {
345
- max-height: 366px;
346
- overflow-y: auto;
347
- padding: 0 4px;
348
-
349
- .t-toc {
350
- margin-bottom: 16px;
351
- }
352
-
353
- .toc-item {
354
- display: block;
355
- width: 95%;
356
- margin-bottom: 8px;
357
-
358
- .state {
359
- display: none;
360
- }
361
- &[done='true'] {
362
- .state {
363
- display: block;
364
- }
365
- }
366
-
367
- .box-text-anchor {
368
- display: flex;
369
- flex-direction: row;
370
- align-items: center;
371
- justify-content: space-between;
372
- }
373
- }
374
- }
375
- }
376
-
377
- .app-nav {
378
- &.show,
379
- &:hover {
380
- .ctn-w {
381
- #sidebar-submenu {
382
- left: 120px;
383
- }
384
- }
385
- }
386
- }
387
- </style>
1
+ <!--
2
+ ----------------- MUST ADD ERROR GESTION ------------------
3
+ ----------------- MUST ADD label terminer ------------------
4
+ ----------------- MUST ADD css ------------------
5
+
6
+ @ Description: This component is used to display the sub menu to show the anchor of a activity.
7
+ @ What it does: The component show the data that was enter in menu.json and create de link to the anchor from those information. This componant must be use with app-comp-menu-Item and app-comp-menu.
8
+ -->
9
+
10
+ <template>
11
+ <div v-if="error" id="sidebar-submenu" :class="{ isOpen: isOpened }">
12
+ <focus-trap :active="isOpened">
13
+ <div ref="target">
14
+ <app-base-button
15
+ id="close-toc"
16
+ class="btn-ghost"
17
+ :title="$t('button.closePopUp')"
18
+ @click="onCloseWidget('toc')"
19
+ >
20
+ <svg>
21
+ <use href="#close-square-icon" />
22
+ </svg>
23
+ </app-base-button>
24
+
25
+ <p class="t-act" v-html="title"></p>
26
+
27
+ <div class="box-prog-act">
28
+ <p>
29
+ {{ $t('text.activity_progress') }}
30
+ <span>{{ actProgress }}</span>
31
+ </p>
32
+ </div>
33
+ <div class="box-anchor">
34
+ <p class="t-toc">{{ $t('text.toc') }}</p>
35
+
36
+ <RouterLink
37
+ v-for="(anchor, index) of anchors"
38
+ :key="anchor.title"
39
+ class="toc-item"
40
+ :done="sectionProgress(index)"
41
+ :to="{ name: anchor.path }"
42
+ @click="closeAndNextPage(anchor.path)"
43
+ >
44
+ <div class="box-text-anchor">
45
+ <div class="text-anchor">
46
+ <p class="anchor-t" v-html="anchor.title"></p>
47
+ <p class="state">
48
+ <svg>
49
+ <use href="#check-toc" />
50
+ </svg>
51
+ {{ $t('text.complete') }}
52
+ </p>
53
+ </div>
54
+ <svg>
55
+ <use href="#chevronD-icon" />
56
+ </svg>
57
+ </div>
58
+ </RouterLink>
59
+ </div>
60
+ </div>
61
+ </focus-trap>
62
+ </div>
63
+ <div v-else id="sidebar-submenu" :class="{ isOpen: isOpened }">
64
+ <p>
65
+ Cette activité n'existe pas dans menu setting, svp l'ajouter à votre menu
66
+ setting
67
+ </p>
68
+ </div>
69
+ </template>
70
+
71
+ <script>
72
+ import { mapState, mapActions } from 'pinia'
73
+ import { useAppStore } from '../module/stores/appStore'
74
+ export default {
75
+ data() {
76
+ return {
77
+ title: '',
78
+ anchors: [],
79
+ activity: '',
80
+ isOpened: false,
81
+ menuInfo: null,
82
+ actProgress: null,
83
+ error: true
84
+ }
85
+ },
86
+ computed: {
87
+ ...mapState(useAppStore, [
88
+ 'getMenuSettings',
89
+ 'getAnchorsForActivity',
90
+ 'getBifChoice',
91
+ 'getAllCompleted',
92
+ 'getAllActivitiesState'
93
+ ])
94
+ },
95
+ beforeUnmount() {
96
+ this.$bus.$off('toggle-widget', this.onToggleWidget)
97
+ this.$bus.$off('close-widget', this.onCloseWidget)
98
+ this.$bus.$off('info-activity', this.onInfoActivity)
99
+ },
100
+ mounted() {
101
+ this.$bus.$on('toggle-widget', this.onToggleWidget)
102
+ this.$bus.$on('close-widget', this.onCloseWidget)
103
+ this.$bus.$on('info-activity', this.onInfoActivity)
104
+ },
105
+ methods: {
106
+ ...mapActions(useAppStore, ['updateWidgetOpen']),
107
+ onInfoActivity(data) {
108
+ //should be conditioned to avoid event firing multiple time on call
109
+
110
+ if (data) {
111
+ this.reset()
112
+ this.activity = data
113
+
114
+ if (!this.getMenuSettings[data]) {
115
+ return (this.error = false)
116
+ } else {
117
+ this.getInfoSubMenu(data)
118
+ this.getProgressActivity(data)
119
+ }
120
+ }
121
+ },
122
+ onCloseWidget(data) {
123
+ this.isOpened = false
124
+ this.updateWidgetOpen(false)
125
+ this.reset()
126
+ },
127
+ onToggleWidget(data) {
128
+ if (data.type !== 'toc') return (this.isOpened = false)
129
+ this.isOpened = !this.isOpened
130
+ this.updateWidgetOpen(this.isOpened)
131
+ },
132
+ /* @Description:Get and set the section to output
133
+ * @params: activity {Object}: the activity which sections need to be output
134
+ */
135
+ getInfoSubMenu(activity) {
136
+ //get the anchors for this activity from the store
137
+ let menuInfo = this.getMenuSettings
138
+
139
+ let nb = null
140
+
141
+ //Get title are if no title construct acitivty
142
+ if (menuInfo[activity] && menuInfo[activity].title)
143
+ this.title = menuInfo[activity].title
144
+
145
+ if (activity.charAt(1) == '0' || activity.charAt(1) == 0)
146
+ nb = activity.substr(2)
147
+ else nb = activity.substr(1)
148
+
149
+ this.title = `${this.$t('text.activity')} ${nb} : ${menuInfo[activity].subTitle}`
150
+
151
+ //create anchors title and path
152
+ if (menuInfo[activity] && menuInfo[activity].anchors) {
153
+ menuInfo[activity].anchors.forEach((element) => {
154
+ //
155
+ let _path = null
156
+ let b = null
157
+ if (nb == 0 || nb == '0') {
158
+ b = `introduction`
159
+ } else {
160
+ b = `activite_${nb}`
161
+ }
162
+
163
+ if (element.page == 'page_1') {
164
+ _path = `${b}`
165
+ } else {
166
+ _path = `${b}.${element.page}`
167
+ }
168
+
169
+ let info = {
170
+ title: `${element.anchorName}`,
171
+ path: _path
172
+ }
173
+ this.anchors.push(info)
174
+ })
175
+ }
176
+ },
177
+ disable(data) {
178
+ let page = data.pageRef
179
+ let act = this.getAct(data.path)
180
+ let choosen = this.getBifChoice
181
+
182
+ // disable if bif
183
+ if (data.bif && choosen) {
184
+ if (choosen.act == act && choosen.page == page) {
185
+ return false
186
+ } else {
187
+ return true
188
+ }
189
+ } else {
190
+ return false
191
+ }
192
+ },
193
+ getAct(data) {
194
+ //return the id need it
195
+ if (data) {
196
+ if (data.substring(data.indexOf('_') + 1).length == 1) {
197
+ return `A0${data.substring(data.indexOf('_') + 1)}`
198
+ } else {
199
+ return `A${data.substring(data.indexOf('_') + 1)}`
200
+ }
201
+ }
202
+ },
203
+ /**
204
+ * @description Gives gives length of completed page for an activity
205
+ * @param {String} idActivity
206
+ * @returns {Number}
207
+ */
208
+ getProgressActivity(idActivity) {
209
+ /// give all the page that are complete to the gauge
210
+ if (idActivity) {
211
+ let completed = []
212
+ if (this.getAllCompleted[idActivity]) {
213
+ completed = this.getAllCompleted[idActivity] //get all completed page for the activity
214
+ }
215
+
216
+ const allActivitiesState = JSON.parse(
217
+ JSON.stringify(this.getAllActivitiesState)
218
+ )
219
+ let size = allActivitiesState[idActivity]
220
+ ? allActivitiesState[idActivity].size
221
+ : 0
222
+
223
+ // return pourcent of activity completion
224
+ this.actProgress = `${Math.round((completed.length * 100) / size)} %`
225
+ }
226
+ },
227
+ close() {
228
+ this.isOpened = !this.isOpened
229
+ this.updateWidgetOpen(this.isOpened)
230
+ },
231
+ closeAndNextPage(NextPage) {
232
+ this.isOpened = !this.isOpened
233
+ this.updateWidgetOpen(this.isOpened)
234
+ this.$router.push({ name: NextPage })
235
+ },
236
+ reset() {
237
+ this.anchors = []
238
+ this.activity = ''
239
+ },
240
+ sectionProgress(index) {
241
+ let menuInfo = this.getMenuSettings
242
+ let nextIndex = index + 1
243
+ let nextSec
244
+ let curSec = menuInfo[this.activity].anchors[index].pageRef
245
+
246
+ let nb
247
+ let tabPageSec = []
248
+ let tabcomplete = []
249
+
250
+ if (nextIndex < menuInfo[this.activity].anchors.length) {
251
+ nextSec = menuInfo[this.activity].anchors[nextIndex].pageRef
252
+ }
253
+
254
+ if (nextSec != undefined) {
255
+ nb = parseInt(nextSec.substring(1))
256
+
257
+ while (nb > parseInt(curSec.substring(1))) {
258
+ nb--
259
+ if (nb < 10) tabPageSec.push(`P0${nb}`)
260
+ else tabPageSec.push(`P${nb}`)
261
+ }
262
+ } else {
263
+ if (menuInfo[this.activity].anchors.length == 1) {
264
+ let numPage = this.getAllActivitiesState[this.activity].size
265
+
266
+ for (let g = 1; g == numPage; g++) {
267
+ tabPageSec.push(`P${g}`)
268
+ }
269
+ if (
270
+ typeof this.getAllCompleted[this.activity] !== 'undefined' &&
271
+ this.getAllCompleted[this.activity].length !==
272
+ this.getAllActivitiesState[this.activity].size
273
+ )
274
+ return false
275
+ }
276
+ tabPageSec.push(curSec)
277
+ }
278
+
279
+ let completeActPage = this.getAllCompleted[this.activity]
280
+
281
+ if (completeActPage) {
282
+ completeActPage.find((value) => {
283
+ let w = Object.keys(value)
284
+ tabcomplete.push(w[0])
285
+ })
286
+
287
+ const isSubset = (array1, array2) =>
288
+ array2.every((element) => array1.includes(element))
289
+
290
+ return isSubset(tabcomplete, tabPageSec)
291
+ }
292
+ }
293
+ }
294
+ }
295
+ </script>
296
+ <style lang="scss">
297
+ #sidebar-submenu {
298
+ display: none;
299
+ position: absolute;
300
+ left: 75px;
301
+ top: 0;
302
+ max-height: 592px;
303
+ width: 476px;
304
+ transition: left 0.5s ease-in-out;
305
+
306
+ &.isOpen {
307
+ display: block;
308
+ }
309
+
310
+ #close-toc {
311
+ position: absolute;
312
+ right: 24px;
313
+ margin-bottom: 0;
314
+ padding: 11px;
315
+ width: 48px;
316
+ height: 48px;
317
+ display: flex;
318
+ justify-content: center;
319
+
320
+ &:focus {
321
+ box-shadow: inherit !important;
322
+ }
323
+ }
324
+
325
+ .box-prog-act {
326
+ width: 319px;
327
+ display: flex;
328
+ flex-direction: row;
329
+ margin-bottom: 16px;
330
+
331
+ p {
332
+ position: relative;
333
+ width: 100%;
334
+
335
+ span {
336
+ position: absolute;
337
+ right: 0;
338
+ top: 0;
339
+ }
340
+ }
341
+ }
342
+
343
+ .box-anchor {
344
+ max-height: 366px;
345
+ overflow-y: auto;
346
+ padding: 0 4px;
347
+
348
+ .t-toc {
349
+ margin-bottom: 16px;
350
+ }
351
+
352
+ .toc-item {
353
+ display: block;
354
+ width: 95%;
355
+ margin-bottom: 8px;
356
+
357
+ .state {
358
+ display: none;
359
+ }
360
+ &[done='true'] {
361
+ .state {
362
+ display: block;
363
+ }
364
+ }
365
+
366
+ .box-text-anchor {
367
+ display: flex;
368
+ flex-direction: row;
369
+ align-items: center;
370
+ justify-content: space-between;
371
+ }
372
+ }
373
+ }
374
+ }
375
+
376
+ .app-nav {
377
+ &.show,
378
+ &:hover {
379
+ .ctn-w {
380
+ #sidebar-submenu {
381
+ left: 120px;
382
+ }
383
+ }
384
+ }
385
+ }
386
+ </style>