fcad-core-dragon 2.0.0-beta.5 → 2.0.0-beta.6
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.
- package/.editorconfig +33 -33
- package/.eslintignore +29 -29
- package/.eslintrc.cjs +81 -81
- package/CHANGELOG +392 -377
- package/README.md +71 -71
- package/bk.scss +117 -117
- package/package.json +61 -61
- package/src/$locales/en.json +23 -25
- package/src/$locales/fr.json +22 -23
- package/src/assets/data/onboardingMessages.json +47 -47
- package/src/components/AppBase.vue +166 -99
- package/src/components/AppBaseButton.vue +2 -0
- package/src/components/AppBaseErrorDisplay.vue +438 -438
- package/src/components/AppBaseFlipCard.vue +84 -84
- package/src/components/AppBaseModule.vue +164 -106
- package/src/components/AppBasePage.vue +14 -4
- package/src/components/AppBasePopover.vue +41 -41
- package/src/components/AppCompAudio.vue +20 -48
- package/src/components/AppCompBranchButtons.vue +7 -53
- package/src/components/{AppCompTranscript.vue → AppCompContainer.vue} +8 -1
- package/src/components/AppCompInputRadioNext.vue +152 -152
- package/src/components/AppCompInputTextToFillNext.vue +171 -171
- package/src/components/AppCompJauge.vue +74 -74
- package/src/components/AppCompMenu.vue +429 -428
- package/src/components/AppCompMenuItem.vue +228 -228
- package/src/components/AppCompNavigation.vue +2 -2
- package/src/components/AppCompPlayBarNext.vue +5 -0
- package/src/components/AppCompPlayBarProgress.vue +82 -82
- package/src/components/AppCompSVGNext.vue +2 -3
- package/src/components/AppCompSettingsMenu.vue +172 -172
- package/src/components/AppCompVideoPlayer.vue +17 -15
- package/src/composables/useQuiz.js +206 -206
- package/src/externalComps/ModuleView.vue +22 -22
- package/src/externalComps/SummaryView.vue +91 -91
- package/src/main.js +34 -29
- package/src/mixins/$mediaMixins.js +819 -819
- package/src/mixins/timerMixin.js +155 -155
- package/src/module/stores/appStore.js +1 -1
- package/src/module/xapi/ADL.js +144 -4
- package/src/module/xapi/Crypto/Hasher.js +241 -241
- package/src/module/xapi/Crypto/WordArray.js +278 -278
- package/src/module/xapi/Crypto/algorithms/BufferedBlockAlgorithm.js +103 -103
- package/src/module/xapi/Crypto/algorithms/C_algo.js +315 -315
- package/src/module/xapi/Crypto/algorithms/HMAC.js +9 -9
- package/src/module/xapi/Crypto/algorithms/SHA1.js +9 -9
- package/src/module/xapi/Crypto/encoders/Base.js +105 -105
- package/src/module/xapi/Crypto/encoders/Base64.js +99 -99
- package/src/module/xapi/Crypto/encoders/Hex.js +61 -61
- package/src/module/xapi/Crypto/encoders/Latin1.js +61 -61
- package/src/module/xapi/Crypto/encoders/Utf8.js +45 -45
- package/src/module/xapi/Statement/agent.js +55 -55
- package/src/module/xapi/Statement/index.js +259 -259
- package/src/module/xapi/Statement/statement.js +253 -253
- package/src/module/xapi/utils.js +167 -167
- package/src/module/xapi/verbs.js +294 -294
- package/src/module/xapi/wrapper copy.js +1963 -0
- package/src/module/xapi/wrapper.js +121 -188
- package/src/module/xapi/xapiStatement.js +444 -444
- package/src/plugins/bus.js +8 -8
- package/src/plugins/gsap.js +14 -14
- package/src/plugins/helper.js +0 -1
- package/src/plugins/i18n.js +44 -44
- package/src/plugins/save.js +37 -37
- package/src/plugins/scorm.js +287 -287
- package/src/plugins/xapi.js +11 -11
- package/src/public/index.html +33 -33
- package/src/router/index.js +2 -1
- package/src/router/routes.js +312 -312
- package/src/shared/generalfuncs.js +210 -210
- package/src/shared/validators.js +2 -0
- package/src/components/AppCompPlayBar.vue +0 -1217
|
@@ -1,84 +1,84 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<!--
|
|
3
|
-
inspire by : https://vuejsexamples.com/generic-flip-card-in-vue-that-allows-completely-arbitrary-content-on-each-side/
|
|
4
|
-
-->
|
|
5
|
-
<div class="flip-card" role="button" aria-pressed="false" @click="fnClick">
|
|
6
|
-
<div class="inside-card" :class="{ flip: isFlipped }">
|
|
7
|
-
<div class="front-card" name="front-card">
|
|
8
|
-
<slot name="front-card" />
|
|
9
|
-
</div>
|
|
10
|
-
<div class="back-card">
|
|
11
|
-
<slot name="back-card" />
|
|
12
|
-
</div>
|
|
13
|
-
</div>
|
|
14
|
-
</div>
|
|
15
|
-
</template>
|
|
16
|
-
<script>
|
|
17
|
-
export default {
|
|
18
|
-
props: {
|
|
19
|
-
isActive: {
|
|
20
|
-
type: Boolean,
|
|
21
|
-
default: false
|
|
22
|
-
}
|
|
23
|
-
},
|
|
24
|
-
emits: ['click'],
|
|
25
|
-
data() {
|
|
26
|
-
return {
|
|
27
|
-
isFlipped: false
|
|
28
|
-
}
|
|
29
|
-
},
|
|
30
|
-
methods: {
|
|
31
|
-
/**
|
|
32
|
-
* @fires click to parent componant or page
|
|
33
|
-
*/
|
|
34
|
-
fnClick() {
|
|
35
|
-
this.$emit('click', this.$el)
|
|
36
|
-
this.isFlipped = !this.isFlipped
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
</script>
|
|
41
|
-
<style lang="scss">
|
|
42
|
-
.flip-card {
|
|
43
|
-
height: auto;
|
|
44
|
-
cursor: pointer;
|
|
45
|
-
|
|
46
|
-
/***** Parameretre modifiable *****/
|
|
47
|
-
perspective: 100%;
|
|
48
|
-
width: 90%;
|
|
49
|
-
|
|
50
|
-
.inside-card {
|
|
51
|
-
position: relative;
|
|
52
|
-
width: 100%;
|
|
53
|
-
height: 100%;
|
|
54
|
-
|
|
55
|
-
/***** Parameretre modifiable *****/
|
|
56
|
-
transform-style: preserve-3d;
|
|
57
|
-
transition: transform 0.5s;
|
|
58
|
-
|
|
59
|
-
&.flip {
|
|
60
|
-
/***** Parameretre modifiable *****/
|
|
61
|
-
transform: rotateY(180deg);
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
.front-card,
|
|
65
|
-
.back-card {
|
|
66
|
-
position: absolute;
|
|
67
|
-
width: 100%;
|
|
68
|
-
height: 100%;
|
|
69
|
-
-webkit-backface-visibility: hidden;
|
|
70
|
-
backface-visibility: hidden;
|
|
71
|
-
|
|
72
|
-
.img-flip-card {
|
|
73
|
-
width: 90%;
|
|
74
|
-
height: auto;
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
.back-card {
|
|
79
|
-
/***** Parameretre modifiable *****/
|
|
80
|
-
transform: rotateY(180deg);
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
</style>
|
|
1
|
+
<template>
|
|
2
|
+
<!--
|
|
3
|
+
inspire by : https://vuejsexamples.com/generic-flip-card-in-vue-that-allows-completely-arbitrary-content-on-each-side/
|
|
4
|
+
-->
|
|
5
|
+
<div class="flip-card" role="button" aria-pressed="false" @click="fnClick">
|
|
6
|
+
<div class="inside-card" :class="{ flip: isFlipped }">
|
|
7
|
+
<div class="front-card" name="front-card">
|
|
8
|
+
<slot name="front-card" />
|
|
9
|
+
</div>
|
|
10
|
+
<div class="back-card">
|
|
11
|
+
<slot name="back-card" />
|
|
12
|
+
</div>
|
|
13
|
+
</div>
|
|
14
|
+
</div>
|
|
15
|
+
</template>
|
|
16
|
+
<script>
|
|
17
|
+
export default {
|
|
18
|
+
props: {
|
|
19
|
+
isActive: {
|
|
20
|
+
type: Boolean,
|
|
21
|
+
default: false
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
emits: ['click'],
|
|
25
|
+
data() {
|
|
26
|
+
return {
|
|
27
|
+
isFlipped: false
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
methods: {
|
|
31
|
+
/**
|
|
32
|
+
* @fires click to parent componant or page
|
|
33
|
+
*/
|
|
34
|
+
fnClick() {
|
|
35
|
+
this.$emit('click', this.$el)
|
|
36
|
+
this.isFlipped = !this.isFlipped
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
</script>
|
|
41
|
+
<style lang="scss">
|
|
42
|
+
.flip-card {
|
|
43
|
+
height: auto;
|
|
44
|
+
cursor: pointer;
|
|
45
|
+
|
|
46
|
+
/***** Parameretre modifiable *****/
|
|
47
|
+
perspective: 100%;
|
|
48
|
+
width: 90%;
|
|
49
|
+
|
|
50
|
+
.inside-card {
|
|
51
|
+
position: relative;
|
|
52
|
+
width: 100%;
|
|
53
|
+
height: 100%;
|
|
54
|
+
|
|
55
|
+
/***** Parameretre modifiable *****/
|
|
56
|
+
transform-style: preserve-3d;
|
|
57
|
+
transition: transform 0.5s;
|
|
58
|
+
|
|
59
|
+
&.flip {
|
|
60
|
+
/***** Parameretre modifiable *****/
|
|
61
|
+
transform: rotateY(180deg);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.front-card,
|
|
65
|
+
.back-card {
|
|
66
|
+
position: absolute;
|
|
67
|
+
width: 100%;
|
|
68
|
+
height: 100%;
|
|
69
|
+
-webkit-backface-visibility: hidden;
|
|
70
|
+
backface-visibility: hidden;
|
|
71
|
+
|
|
72
|
+
.img-flip-card {
|
|
73
|
+
width: 90%;
|
|
74
|
+
height: auto;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
.back-card {
|
|
79
|
+
/***** Parameretre modifiable *****/
|
|
80
|
+
transform: rotateY(180deg);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
</style>
|
|
@@ -7,11 +7,11 @@
|
|
|
7
7
|
|
|
8
8
|
<template>
|
|
9
9
|
<div fluid class="module">
|
|
10
|
-
<
|
|
10
|
+
<span
|
|
11
11
|
id="page_info_section"
|
|
12
12
|
class="sr-only"
|
|
13
13
|
aria-labelledby="page_info"
|
|
14
|
-
></
|
|
14
|
+
></span>
|
|
15
15
|
<a class="skip-link" href="" @click.prevent="skipToMain">
|
|
16
16
|
{{ $t('message.skip_content') }}
|
|
17
17
|
</a>
|
|
@@ -108,13 +108,13 @@ import { mapState, mapActions } from 'pinia'
|
|
|
108
108
|
import { useAppStore } from '../module/stores/appStore'
|
|
109
109
|
import BaseModule from './BaseModule.vue'
|
|
110
110
|
import { timerMixin } from '../mixins/timerMixin'
|
|
111
|
-
import
|
|
111
|
+
import AppCompContainer from './AppCompContainer.vue'
|
|
112
112
|
import { defineAsyncComponent } from 'vue'
|
|
113
113
|
//import
|
|
114
114
|
export default {
|
|
115
115
|
components: {
|
|
116
116
|
BaseModule,
|
|
117
|
-
|
|
117
|
+
AppCompContainer
|
|
118
118
|
},
|
|
119
119
|
mixins: [timerMixin],
|
|
120
120
|
props: {
|
|
@@ -154,6 +154,8 @@ export default {
|
|
|
154
154
|
transcriptContent: null,
|
|
155
155
|
transcriptContainer: null,
|
|
156
156
|
branchingVisible: false,
|
|
157
|
+
customContentVisible: false,
|
|
158
|
+
customContent: null,
|
|
157
159
|
lessonCompletionStatus: false,
|
|
158
160
|
checkedDataFromServer: 0,
|
|
159
161
|
rightSidebarEvent: new CustomEvent('sidebarEvent', {
|
|
@@ -179,8 +181,8 @@ export default {
|
|
|
179
181
|
'getMenuSettings',
|
|
180
182
|
'getRouteHistory',
|
|
181
183
|
'getOnboardingEnabled',
|
|
182
|
-
'getApplicationSettings',
|
|
183
184
|
'getDataFromServer',
|
|
185
|
+
'getApplicationSettings',
|
|
184
186
|
'getCompStatusTracker'
|
|
185
187
|
]),
|
|
186
188
|
isMenu() {
|
|
@@ -264,50 +266,120 @@ export default {
|
|
|
264
266
|
return mainEl
|
|
265
267
|
},
|
|
266
268
|
|
|
269
|
+
// dynamicSidebarContent() {
|
|
270
|
+
// if (!this.transcriptVisible && !this.branchingVisible) return null
|
|
271
|
+
// let sidebarSettings = {}
|
|
272
|
+
// let _label = null
|
|
273
|
+
|
|
274
|
+
// if (this.transcriptVisible) {
|
|
275
|
+
// _label =
|
|
276
|
+
// this.$i18n.locale === 'fr'
|
|
277
|
+
// ? 'Contenu de la transcription'
|
|
278
|
+
// : 'Content of the transcript'
|
|
279
|
+
|
|
280
|
+
// sidebarSettings = {
|
|
281
|
+
// _component: AppCompContainer,
|
|
282
|
+
// _comProps: {
|
|
283
|
+
// content: this.transcriptContent
|
|
284
|
+
// },
|
|
285
|
+
// _context: 'ctxTranscript',
|
|
286
|
+
// _container: this.transcriptContainer,
|
|
287
|
+
// _label,
|
|
288
|
+
// _id: 'transcript'
|
|
289
|
+
// }
|
|
290
|
+
// } else if (this.branchingVisible) {
|
|
291
|
+
// if (this.$route.meta.type !== 'branching' || !this.compID) return null
|
|
292
|
+
|
|
293
|
+
// const componentName = this.compID
|
|
294
|
+
// const { activityRef } = this.getCurrentPage //get activity id from current page
|
|
295
|
+
|
|
296
|
+
// _label =
|
|
297
|
+
// this.$i18n.locale === 'fr'
|
|
298
|
+
// ? "contenu de l'embranchement"
|
|
299
|
+
// : 'content of the branching'
|
|
300
|
+
|
|
301
|
+
// sidebarSettings = {
|
|
302
|
+
// _component: defineAsyncComponent(
|
|
303
|
+
// async () =>
|
|
304
|
+
// await import(`@/module/${activityRef}/${componentName}.vue`)
|
|
305
|
+
// ),
|
|
306
|
+
|
|
307
|
+
// _comProps: false,
|
|
308
|
+
// _context: 'ctxBranching',
|
|
309
|
+
// _label,
|
|
310
|
+
// _id: componentName
|
|
311
|
+
// }
|
|
312
|
+
// }
|
|
313
|
+
// return sidebarSettings
|
|
314
|
+
// },
|
|
267
315
|
dynamicSidebarContent() {
|
|
268
|
-
if (
|
|
316
|
+
if (
|
|
317
|
+
!this.transcriptVisible &&
|
|
318
|
+
!this.branchingVisible &&
|
|
319
|
+
!this.customContentVisible
|
|
320
|
+
)
|
|
321
|
+
return null
|
|
269
322
|
let sidebarSettings = {}
|
|
270
323
|
let _label = null
|
|
324
|
+
//=========================================
|
|
325
|
+
switch (true) {
|
|
326
|
+
case this.transcriptVisible:
|
|
327
|
+
_label =
|
|
328
|
+
this.$i18n.locale === 'fr'
|
|
329
|
+
? 'Contenu de la transcription'
|
|
330
|
+
: 'Content of the transcript'
|
|
331
|
+
|
|
332
|
+
sidebarSettings = {
|
|
333
|
+
_component: AppCompContainer,
|
|
334
|
+
_comProps: {
|
|
335
|
+
content: this.transcriptContent,
|
|
336
|
+
id: 'transcript-content'
|
|
337
|
+
},
|
|
338
|
+
_context: 'ctxTranscript',
|
|
339
|
+
_container: this.transcriptContainer,
|
|
340
|
+
_label,
|
|
341
|
+
_id: 'transcript'
|
|
342
|
+
}
|
|
343
|
+
break
|
|
271
344
|
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
this.$i18n.locale === 'fr'
|
|
296
|
-
? "contenu de l'embranchement"
|
|
297
|
-
: 'content of the branching'
|
|
298
|
-
|
|
299
|
-
sidebarSettings = {
|
|
300
|
-
_component: defineAsyncComponent(
|
|
301
|
-
async () =>
|
|
302
|
-
await import(`@/module/${activityRef}/${componentName}.vue`)
|
|
303
|
-
),
|
|
304
|
-
|
|
305
|
-
_comProps: false,
|
|
306
|
-
_context: 'ctxBranching',
|
|
307
|
-
_label,
|
|
308
|
-
_id: componentName
|
|
345
|
+
case this.branchingVisible: {
|
|
346
|
+
if (this.$route.meta.type !== 'branching' || !this.compID) return null
|
|
347
|
+
|
|
348
|
+
const componentName = this.compID
|
|
349
|
+
const { activityRef } = this.getCurrentPage //get activity id from current page
|
|
350
|
+
|
|
351
|
+
_label =
|
|
352
|
+
this.$i18n.locale === 'fr'
|
|
353
|
+
? "contenu de l'embranchement"
|
|
354
|
+
: 'content of the branching'
|
|
355
|
+
|
|
356
|
+
sidebarSettings = {
|
|
357
|
+
_component: defineAsyncComponent(
|
|
358
|
+
async () =>
|
|
359
|
+
await import(`@/module/${activityRef}/${componentName}.vue`)
|
|
360
|
+
),
|
|
361
|
+
|
|
362
|
+
_comProps: false,
|
|
363
|
+
_context: 'ctxBranching',
|
|
364
|
+
_label,
|
|
365
|
+
_id: componentName
|
|
366
|
+
}
|
|
367
|
+
break
|
|
309
368
|
}
|
|
369
|
+
|
|
370
|
+
case this.customContentVisible:
|
|
371
|
+
sidebarSettings = {
|
|
372
|
+
_component: AppCompContainer,
|
|
373
|
+
_comProps: {
|
|
374
|
+
content: this.customContent
|
|
375
|
+
},
|
|
376
|
+
_context: 'ctxCustomContent',
|
|
377
|
+
_label,
|
|
378
|
+
_id: 'custom-content'
|
|
379
|
+
}
|
|
380
|
+
break
|
|
310
381
|
}
|
|
382
|
+
|
|
311
383
|
return sidebarSettings
|
|
312
384
|
},
|
|
313
385
|
|
|
@@ -532,12 +604,6 @@ export default {
|
|
|
532
604
|
}, 800)
|
|
533
605
|
},
|
|
534
606
|
mounted() {
|
|
535
|
-
//A11Y: Bring back the focus on the body element after each navigation
|
|
536
|
-
document.body.setAttribute('tabindex', -1) //needed to use .focus()
|
|
537
|
-
this.$router.afterEach(() => {
|
|
538
|
-
document.body.focus()
|
|
539
|
-
})
|
|
540
|
-
|
|
541
607
|
let nav = document.getElementById('navTool')
|
|
542
608
|
|
|
543
609
|
if (nav) nav.addEventListener('mouseleave', this.onNavMouseleave)
|
|
@@ -623,6 +689,9 @@ export default {
|
|
|
623
689
|
|
|
624
690
|
this.openBranchContent(content)
|
|
625
691
|
break
|
|
692
|
+
case 'ctxCustomContent':
|
|
693
|
+
this.displayCustomContent(content, wrapper)
|
|
694
|
+
break
|
|
626
695
|
}
|
|
627
696
|
//delay animation
|
|
628
697
|
this.rightSidebarVisible = true
|
|
@@ -661,10 +730,16 @@ export default {
|
|
|
661
730
|
this.closeBranchContent()
|
|
662
731
|
break
|
|
663
732
|
|
|
733
|
+
case 'ctxCustomContent':
|
|
734
|
+
this.closeCostumContent()
|
|
735
|
+
break
|
|
736
|
+
|
|
664
737
|
default:
|
|
665
738
|
this.branchingVisible = false
|
|
666
739
|
this.transcriptVisible = false
|
|
740
|
+
this.customContentVisible = false
|
|
667
741
|
this.transcriptContent = null
|
|
742
|
+
this.customContent = null
|
|
668
743
|
this.compID = null
|
|
669
744
|
}
|
|
670
745
|
this.updatesideBIsOpen(this.rightSidebarVisible)
|
|
@@ -732,10 +807,11 @@ export default {
|
|
|
732
807
|
* @fires 'transcript-hidden' to AppCompPlaybar
|
|
733
808
|
*/
|
|
734
809
|
closeTranscript(container = this.transcriptContainer) {
|
|
810
|
+
let t = this.customContentVisible ? 10 : 200
|
|
735
811
|
setTimeout(() => {
|
|
736
812
|
this.transcriptContent = null
|
|
737
813
|
this.transcriptVisible = false
|
|
738
|
-
},
|
|
814
|
+
}, t)
|
|
739
815
|
this.$bus.$emit('transcript-hidden')
|
|
740
816
|
this.$bus.$emit('resize-media', 'lg', container)
|
|
741
817
|
},
|
|
@@ -784,6 +860,21 @@ export default {
|
|
|
784
860
|
this.$bus.$emit('branching-hidden')
|
|
785
861
|
},
|
|
786
862
|
|
|
863
|
+
displayCustomContent(c, container) {
|
|
864
|
+
if (!c) return (this.customContentVisible = false)
|
|
865
|
+
//Change transcript content
|
|
866
|
+
if (this.transcriptVisible) this.closeTranscript()
|
|
867
|
+
//Change transcript content
|
|
868
|
+
this.customContent = c
|
|
869
|
+
this.customContentContainer = container
|
|
870
|
+
this.customContentVisible = true
|
|
871
|
+
},
|
|
872
|
+
|
|
873
|
+
closeCostumContent() {
|
|
874
|
+
this.customContentContainer = null
|
|
875
|
+
this.customContentVisible = false
|
|
876
|
+
},
|
|
877
|
+
|
|
787
878
|
/**
|
|
788
879
|
* @description reset the values of state (currentTimeline,currentMedialement, currentPage, media duration, appStatus')in the store
|
|
789
880
|
*/
|
|
@@ -874,25 +965,14 @@ export default {
|
|
|
874
965
|
this.$scorm.setValue('cmi.core.lesson_status', 'incomplete') // set the lesson status to in complete
|
|
875
966
|
this.$scorm.Commit() // persist data
|
|
876
967
|
}
|
|
968
|
+
//Redirect to current page or to menu if route is module
|
|
969
|
+
this.$route.name && this.$route.name !== 'module'
|
|
970
|
+
? this.$router.push({ name: this.$route.name })
|
|
971
|
+
: this.$router.push({ name: 'menu' })
|
|
877
972
|
|
|
878
|
-
// check for the bookmark existance in LMS
|
|
879
|
-
const bookmark = this.$scorm.GetValue(
|
|
880
|
-
'cmi.core.lesson_location',
|
|
881
|
-
false
|
|
882
|
-
)
|
|
883
|
-
|
|
884
|
-
// if none stored in the LMS redirect to the 1st page
|
|
885
|
-
if (bookmark === '' || bookmark === undefined) {
|
|
886
|
-
//Redirect to current page or to menu if route is module
|
|
887
|
-
this.$route.name && this.$route.name !== 'module'
|
|
888
|
-
? this.$router.push({ name: this.$route.name })
|
|
889
|
-
: this.$router.push({ name: 'menu' })
|
|
890
|
-
} else if (bookmark) {
|
|
891
|
-
this.$router.push({ name: bookmark })
|
|
892
|
-
}
|
|
893
973
|
// set the current page
|
|
894
974
|
this.fetchPage()
|
|
895
|
-
|
|
975
|
+
|
|
896
976
|
break
|
|
897
977
|
}
|
|
898
978
|
case 'xapi':
|
|
@@ -917,53 +997,31 @@ export default {
|
|
|
917
997
|
arg = arg || null
|
|
918
998
|
let existingRecord // hold record record
|
|
919
999
|
let toBeSaved // hold data to send to scorm
|
|
1000
|
+
|
|
920
1001
|
if (this.$scorm.initialized) {
|
|
921
1002
|
if (this.$scorm.GetValue('cmi.suspend_data') !== '')
|
|
922
1003
|
existingRecord = JSON.parse(this.$scorm.GetValue('cmi.suspend_data')) // try convert the scorm record to JSON Obiect
|
|
923
1004
|
// create entry for user data if there is no record in Scorm
|
|
924
1005
|
if (!existingRecord) existingRecord = {}
|
|
925
|
-
|
|
926
|
-
if
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
toBeSaved = JSON.stringify(existingRecord) // convert to JSON string format
|
|
942
|
-
}
|
|
943
|
-
// no valid arg
|
|
944
|
-
else return
|
|
945
|
-
}
|
|
946
|
-
// Update module & user record
|
|
947
|
-
else {
|
|
948
|
-
// create entry for module and user data if does not existe
|
|
949
|
-
if (
|
|
950
|
-
!existingRecord['userData'] &&
|
|
951
|
-
!existingRecord['moduleData'] &&
|
|
952
|
-
!existingRecord['routeHistory']
|
|
953
|
-
) {
|
|
954
|
-
existingRecord['moduleData'] = {}
|
|
955
|
-
existingRecord['userData'] = {}
|
|
956
|
-
existingRecord['routeHistory'] = []
|
|
957
|
-
}
|
|
958
|
-
// update values for module and user data
|
|
959
|
-
existingRecord.userData = this.getUserInteraction
|
|
960
|
-
existingRecord.routeHistory = this.routeData
|
|
961
|
-
// update value of user data
|
|
962
|
-
existingRecord.moduleConfig = JSON.stringify({}) // update value of module data
|
|
963
|
-
toBeSaved = JSON.stringify(existingRecord)
|
|
964
|
-
}
|
|
1006
|
+
|
|
1007
|
+
// create new entry for user data if does not existe
|
|
1008
|
+
existingRecord.userData = this.getUserInteraction || {}
|
|
1009
|
+
existingRecord.userSettings = this.getApplicationSettings || {}
|
|
1010
|
+
// existingRecord.routeHistory = this.getRouteHistory || []
|
|
1011
|
+
existingRecord.routeHistory = (() => {
|
|
1012
|
+
const history = this.getRouteHistory.toReversed() //get the route history from the last
|
|
1013
|
+
|
|
1014
|
+
history[0] = this.$route.meta // change the last recored route to the current route
|
|
1015
|
+
|
|
1016
|
+
return history.toReversed()
|
|
1017
|
+
})()
|
|
1018
|
+
// update value of user data
|
|
1019
|
+
|
|
1020
|
+
toBeSaved = JSON.stringify(existingRecord) // convert to JSON string format
|
|
1021
|
+
|
|
965
1022
|
this.$scorm.SetValue('cmi.suspend_data', toBeSaved) // converte to serialized string and save to scorm
|
|
966
1023
|
this.$scorm.Commit() // persist data in LMS
|
|
1024
|
+
if (arg === 'disconnect') this.$scorm.Finish()
|
|
967
1025
|
}
|
|
968
1026
|
},
|
|
969
1027
|
/**
|
|
@@ -15,9 +15,12 @@
|
|
|
15
15
|
:error-text="`Vous avez une/des erreur(s) dans la création de votre PAGE. Veuillez
|
|
16
16
|
corriger les erreurs ci-dessous:`"
|
|
17
17
|
/>
|
|
18
|
-
<span
|
|
19
|
-
|
|
20
|
-
|
|
18
|
+
<span
|
|
19
|
+
id="page_info"
|
|
20
|
+
ref="page_info"
|
|
21
|
+
class="sr-only"
|
|
22
|
+
aria-hidden="true"
|
|
23
|
+
></span>
|
|
21
24
|
<div id="hiddenAlertContainer" role="alert" class="sr-only"></div>
|
|
22
25
|
</div>
|
|
23
26
|
</template>
|
|
@@ -100,7 +103,11 @@ export default {
|
|
|
100
103
|
}
|
|
101
104
|
},
|
|
102
105
|
computed: {
|
|
103
|
-
...mapState(useAppStore, [
|
|
106
|
+
...mapState(useAppStore, [
|
|
107
|
+
'getDataNoteCredit',
|
|
108
|
+
'getAllActivities',
|
|
109
|
+
'getApplicationSettings'
|
|
110
|
+
]),
|
|
104
111
|
getRouteHistory() {
|
|
105
112
|
return this.store.getRouteHistory
|
|
106
113
|
},
|
|
@@ -373,6 +380,9 @@ export default {
|
|
|
373
380
|
this.$bus.$on('video-transcript-toggle', this.onVideoTranscriptToggle)
|
|
374
381
|
},
|
|
375
382
|
mounted() {
|
|
383
|
+
//Fix for firefox not updating aria-labelledby (was stuck saying Activite 1, page 1 on every pages)
|
|
384
|
+
this.$refs['page_info'].innerHTML = this.A11yPageInfo
|
|
385
|
+
|
|
376
386
|
setTimeout(() => {
|
|
377
387
|
if (this.pageData && this.type === 'pg_branch') return //Prevent scrolling to top of Parent when branching page are being viewed
|
|
378
388
|
this.$bus.$emit('move-to-target', 'page_info_section')
|
|
@@ -1,41 +1,41 @@
|
|
|
1
|
-
<!--
|
|
2
|
-
@ Description: This component is used to create a popover that is accessible via keyboard navigation (tab + space/enter)
|
|
3
|
-
-->
|
|
4
|
-
<template>
|
|
5
|
-
<v-tooltip
|
|
6
|
-
ref="tooltip"
|
|
7
|
-
v-bind="$attrs"
|
|
8
|
-
v-model="show"
|
|
9
|
-
transition="false"
|
|
10
|
-
:open-on-click="true"
|
|
11
|
-
:persistent="false"
|
|
12
|
-
>
|
|
13
|
-
<slot></slot>
|
|
14
|
-
</v-tooltip>
|
|
15
|
-
</template>
|
|
16
|
-
|
|
17
|
-
<script>
|
|
18
|
-
export default {
|
|
19
|
-
name: 'AppBasePopover',
|
|
20
|
-
data() {
|
|
21
|
-
return {
|
|
22
|
-
show: false,
|
|
23
|
-
alertContainer: null
|
|
24
|
-
}
|
|
25
|
-
},
|
|
26
|
-
watch: {
|
|
27
|
-
show: {
|
|
28
|
-
handler(newValue) {
|
|
29
|
-
if (newValue) {
|
|
30
|
-
const content = this.$refs.tooltip.contentEl.textContent
|
|
31
|
-
this.alertContainer.textContent = ''
|
|
32
|
-
this.alertContainer.textContent = content
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
},
|
|
37
|
-
mounted() {
|
|
38
|
-
this.alertContainer = document.getElementById('hiddenAlertContainer')
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
</script>
|
|
1
|
+
<!--
|
|
2
|
+
@ Description: This component is used to create a popover that is accessible via keyboard navigation (tab + space/enter)
|
|
3
|
+
-->
|
|
4
|
+
<template>
|
|
5
|
+
<v-tooltip
|
|
6
|
+
ref="tooltip"
|
|
7
|
+
v-bind="$attrs"
|
|
8
|
+
v-model="show"
|
|
9
|
+
transition="false"
|
|
10
|
+
:open-on-click="true"
|
|
11
|
+
:persistent="false"
|
|
12
|
+
>
|
|
13
|
+
<slot></slot>
|
|
14
|
+
</v-tooltip>
|
|
15
|
+
</template>
|
|
16
|
+
|
|
17
|
+
<script>
|
|
18
|
+
export default {
|
|
19
|
+
name: 'AppBasePopover',
|
|
20
|
+
data() {
|
|
21
|
+
return {
|
|
22
|
+
show: false,
|
|
23
|
+
alertContainer: null
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
watch: {
|
|
27
|
+
show: {
|
|
28
|
+
handler(newValue) {
|
|
29
|
+
if (newValue) {
|
|
30
|
+
const content = this.$refs.tooltip.contentEl.textContent
|
|
31
|
+
this.alertContainer.textContent = ''
|
|
32
|
+
this.alertContainer.textContent = content
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
mounted() {
|
|
38
|
+
this.alertContainer = document.getElementById('hiddenAlertContainer')
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
</script>
|