fcad-core-dragon 2.0.0-beta.5 → 2.0.0-beta.7
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 +395 -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 +124 -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/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>
|
|
@@ -104,17 +104,19 @@
|
|
|
104
104
|
</div>
|
|
105
105
|
</template>
|
|
106
106
|
<script>
|
|
107
|
+
// const modules = import.meta.glob('@/module/**/*.vue')
|
|
108
|
+
import { fileAssets } from '../shared/generalfuncs.js'
|
|
107
109
|
import { mapState, mapActions } from 'pinia'
|
|
108
110
|
import { useAppStore } from '../module/stores/appStore'
|
|
109
111
|
import BaseModule from './BaseModule.vue'
|
|
110
112
|
import { timerMixin } from '../mixins/timerMixin'
|
|
111
|
-
import
|
|
113
|
+
import AppCompContainer from './AppCompContainer.vue'
|
|
112
114
|
import { defineAsyncComponent } from 'vue'
|
|
113
115
|
//import
|
|
114
116
|
export default {
|
|
115
117
|
components: {
|
|
116
118
|
BaseModule,
|
|
117
|
-
|
|
119
|
+
AppCompContainer
|
|
118
120
|
},
|
|
119
121
|
mixins: [timerMixin],
|
|
120
122
|
props: {
|
|
@@ -154,6 +156,8 @@ export default {
|
|
|
154
156
|
transcriptContent: null,
|
|
155
157
|
transcriptContainer: null,
|
|
156
158
|
branchingVisible: false,
|
|
159
|
+
customContentVisible: false,
|
|
160
|
+
customContent: null,
|
|
157
161
|
lessonCompletionStatus: false,
|
|
158
162
|
checkedDataFromServer: 0,
|
|
159
163
|
rightSidebarEvent: new CustomEvent('sidebarEvent', {
|
|
@@ -179,8 +183,8 @@ export default {
|
|
|
179
183
|
'getMenuSettings',
|
|
180
184
|
'getRouteHistory',
|
|
181
185
|
'getOnboardingEnabled',
|
|
182
|
-
'getApplicationSettings',
|
|
183
186
|
'getDataFromServer',
|
|
187
|
+
'getApplicationSettings',
|
|
184
188
|
'getCompStatusTracker'
|
|
185
189
|
]),
|
|
186
190
|
isMenu() {
|
|
@@ -265,49 +269,77 @@ export default {
|
|
|
265
269
|
},
|
|
266
270
|
|
|
267
271
|
dynamicSidebarContent() {
|
|
268
|
-
if (
|
|
272
|
+
if (
|
|
273
|
+
!this.transcriptVisible &&
|
|
274
|
+
!this.branchingVisible &&
|
|
275
|
+
!this.customContentVisible
|
|
276
|
+
)
|
|
277
|
+
return null
|
|
269
278
|
let sidebarSettings = {}
|
|
270
279
|
let _label = null
|
|
280
|
+
//=========================================
|
|
281
|
+
switch (true) {
|
|
282
|
+
case this.transcriptVisible:
|
|
283
|
+
_label =
|
|
284
|
+
this.$i18n.locale === 'fr'
|
|
285
|
+
? 'Contenu de la transcription'
|
|
286
|
+
: 'Content of the transcript'
|
|
287
|
+
|
|
288
|
+
sidebarSettings = {
|
|
289
|
+
_component: AppCompContainer,
|
|
290
|
+
_comProps: {
|
|
291
|
+
content: this.transcriptContent,
|
|
292
|
+
id: 'transcript-content'
|
|
293
|
+
},
|
|
294
|
+
_context: 'ctxTranscript',
|
|
295
|
+
_container: this.transcriptContainer,
|
|
296
|
+
_label,
|
|
297
|
+
_id: 'transcript'
|
|
298
|
+
}
|
|
299
|
+
break
|
|
271
300
|
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
this.$
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
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
|
|
301
|
+
case this.branchingVisible: {
|
|
302
|
+
const allActivities = fileAssets.getActivities()
|
|
303
|
+
if (this.$route.meta.type !== 'branching' || !this.compID) return null
|
|
304
|
+
|
|
305
|
+
const componentName = this.compID
|
|
306
|
+
const { activityRef } = this.getCurrentPage //get activity id from current page
|
|
307
|
+
|
|
308
|
+
_label =
|
|
309
|
+
this.$i18n.locale === 'fr'
|
|
310
|
+
? "contenu de l'embranchement"
|
|
311
|
+
: 'content of the branching'
|
|
312
|
+
|
|
313
|
+
sidebarSettings = {
|
|
314
|
+
_component: defineAsyncComponent(async () => {
|
|
315
|
+
const compFile = allActivities.filter((f) => {
|
|
316
|
+
return f.name.includes(`/${activityRef}/${componentName}`)
|
|
317
|
+
})[0]
|
|
318
|
+
|
|
319
|
+
return compFile.content
|
|
320
|
+
}),
|
|
321
|
+
|
|
322
|
+
_comProps: false,
|
|
323
|
+
_context: 'ctxBranching',
|
|
324
|
+
_label,
|
|
325
|
+
_id: componentName
|
|
326
|
+
}
|
|
327
|
+
break
|
|
309
328
|
}
|
|
329
|
+
|
|
330
|
+
case this.customContentVisible:
|
|
331
|
+
sidebarSettings = {
|
|
332
|
+
_component: AppCompContainer,
|
|
333
|
+
_comProps: {
|
|
334
|
+
content: this.customContent
|
|
335
|
+
},
|
|
336
|
+
_context: 'ctxCustomContent',
|
|
337
|
+
_label,
|
|
338
|
+
_id: 'custom-content'
|
|
339
|
+
}
|
|
340
|
+
break
|
|
310
341
|
}
|
|
342
|
+
|
|
311
343
|
return sidebarSettings
|
|
312
344
|
},
|
|
313
345
|
|
|
@@ -532,12 +564,6 @@ export default {
|
|
|
532
564
|
}, 800)
|
|
533
565
|
},
|
|
534
566
|
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
567
|
let nav = document.getElementById('navTool')
|
|
542
568
|
|
|
543
569
|
if (nav) nav.addEventListener('mouseleave', this.onNavMouseleave)
|
|
@@ -623,6 +649,9 @@ export default {
|
|
|
623
649
|
|
|
624
650
|
this.openBranchContent(content)
|
|
625
651
|
break
|
|
652
|
+
case 'ctxCustomContent':
|
|
653
|
+
this.displayCustomContent(content, wrapper)
|
|
654
|
+
break
|
|
626
655
|
}
|
|
627
656
|
//delay animation
|
|
628
657
|
this.rightSidebarVisible = true
|
|
@@ -661,10 +690,16 @@ export default {
|
|
|
661
690
|
this.closeBranchContent()
|
|
662
691
|
break
|
|
663
692
|
|
|
693
|
+
case 'ctxCustomContent':
|
|
694
|
+
this.closeCostumContent()
|
|
695
|
+
break
|
|
696
|
+
|
|
664
697
|
default:
|
|
665
698
|
this.branchingVisible = false
|
|
666
699
|
this.transcriptVisible = false
|
|
700
|
+
this.customContentVisible = false
|
|
667
701
|
this.transcriptContent = null
|
|
702
|
+
this.customContent = null
|
|
668
703
|
this.compID = null
|
|
669
704
|
}
|
|
670
705
|
this.updatesideBIsOpen(this.rightSidebarVisible)
|
|
@@ -732,10 +767,11 @@ export default {
|
|
|
732
767
|
* @fires 'transcript-hidden' to AppCompPlaybar
|
|
733
768
|
*/
|
|
734
769
|
closeTranscript(container = this.transcriptContainer) {
|
|
770
|
+
let t = this.customContentVisible ? 10 : 200
|
|
735
771
|
setTimeout(() => {
|
|
736
772
|
this.transcriptContent = null
|
|
737
773
|
this.transcriptVisible = false
|
|
738
|
-
},
|
|
774
|
+
}, t)
|
|
739
775
|
this.$bus.$emit('transcript-hidden')
|
|
740
776
|
this.$bus.$emit('resize-media', 'lg', container)
|
|
741
777
|
},
|
|
@@ -784,6 +820,21 @@ export default {
|
|
|
784
820
|
this.$bus.$emit('branching-hidden')
|
|
785
821
|
},
|
|
786
822
|
|
|
823
|
+
displayCustomContent(c, container) {
|
|
824
|
+
if (!c) return (this.customContentVisible = false)
|
|
825
|
+
//Change transcript content
|
|
826
|
+
if (this.transcriptVisible) this.closeTranscript()
|
|
827
|
+
//Change transcript content
|
|
828
|
+
this.customContent = c
|
|
829
|
+
this.customContentContainer = container
|
|
830
|
+
this.customContentVisible = true
|
|
831
|
+
},
|
|
832
|
+
|
|
833
|
+
closeCostumContent() {
|
|
834
|
+
this.customContentContainer = null
|
|
835
|
+
this.customContentVisible = false
|
|
836
|
+
},
|
|
837
|
+
|
|
787
838
|
/**
|
|
788
839
|
* @description reset the values of state (currentTimeline,currentMedialement, currentPage, media duration, appStatus')in the store
|
|
789
840
|
*/
|
|
@@ -874,25 +925,14 @@ export default {
|
|
|
874
925
|
this.$scorm.setValue('cmi.core.lesson_status', 'incomplete') // set the lesson status to in complete
|
|
875
926
|
this.$scorm.Commit() // persist data
|
|
876
927
|
}
|
|
928
|
+
//Redirect to current page or to menu if route is module
|
|
929
|
+
this.$route.name && this.$route.name !== 'module'
|
|
930
|
+
? this.$router.push({ name: this.$route.name })
|
|
931
|
+
: this.$router.push({ name: 'menu' })
|
|
877
932
|
|
|
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
933
|
// set the current page
|
|
894
934
|
this.fetchPage()
|
|
895
|
-
|
|
935
|
+
|
|
896
936
|
break
|
|
897
937
|
}
|
|
898
938
|
case 'xapi':
|
|
@@ -917,53 +957,31 @@ export default {
|
|
|
917
957
|
arg = arg || null
|
|
918
958
|
let existingRecord // hold record record
|
|
919
959
|
let toBeSaved // hold data to send to scorm
|
|
960
|
+
|
|
920
961
|
if (this.$scorm.initialized) {
|
|
921
962
|
if (this.$scorm.GetValue('cmi.suspend_data') !== '')
|
|
922
963
|
existingRecord = JSON.parse(this.$scorm.GetValue('cmi.suspend_data')) // try convert the scorm record to JSON Obiect
|
|
923
964
|
// create entry for user data if there is no record in Scorm
|
|
924
965
|
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
|
-
}
|
|
966
|
+
|
|
967
|
+
// create new entry for user data if does not existe
|
|
968
|
+
existingRecord.userData = this.getUserInteraction || {}
|
|
969
|
+
existingRecord.userSettings = this.getApplicationSettings || {}
|
|
970
|
+
// existingRecord.routeHistory = this.getRouteHistory || []
|
|
971
|
+
existingRecord.routeHistory = (() => {
|
|
972
|
+
const history = this.getRouteHistory.toReversed() //get the route history from the last
|
|
973
|
+
|
|
974
|
+
history[0] = this.$route.meta // change the last recored route to the current route
|
|
975
|
+
|
|
976
|
+
return history.toReversed()
|
|
977
|
+
})()
|
|
978
|
+
// update value of user data
|
|
979
|
+
|
|
980
|
+
toBeSaved = JSON.stringify(existingRecord) // convert to JSON string format
|
|
981
|
+
|
|
965
982
|
this.$scorm.SetValue('cmi.suspend_data', toBeSaved) // converte to serialized string and save to scorm
|
|
966
983
|
this.$scorm.Commit() // persist data in LMS
|
|
984
|
+
if (arg === 'disconnect') this.$scorm.Finish()
|
|
967
985
|
}
|
|
968
986
|
},
|
|
969
987
|
/**
|
|
@@ -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>
|