fcad-core-dragon 2.0.1 → 2.0.2-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.editorconfig +33 -33
- package/.eslintignore +29 -29
- package/.eslintrc.cjs +81 -81
- package/CHANGELOG +17 -1
- package/bk.scss +117 -117
- package/package.json +1 -1
- package/src/$locales/en.json +18 -4
- package/src/$locales/fr.json +17 -3
- package/src/assets/data/onboardingMessages.json +47 -47
- package/src/components/AppBase.vue +36 -341
- package/src/components/AppBaseErrorDisplay.vue +438 -438
- package/src/components/AppBaseFlipCard.vue +84 -84
- package/src/components/AppBaseModule.vue +16 -21
- package/src/components/AppBasePage.vue +45 -14
- package/src/components/AppBasePopover.vue +41 -41
- package/src/components/AppBaseSkeleton.vue +45 -0
- package/src/components/AppCompAudio.vue +12 -3
- package/src/components/AppCompButtonProgress.vue +13 -2
- package/src/components/AppCompCarousel.vue +12 -4
- package/src/components/AppCompInputCheckBoxNx.vue +324 -0
- package/src/components/AppCompInputDropdownNx.vue +295 -0
- package/src/components/AppCompInputRadioNx.vue +264 -0
- package/src/components/AppCompInputTextNx.vue +148 -0
- package/src/components/AppCompInputTextTableNx.vue +198 -0
- package/src/components/AppCompInputTextToFillDropdownNx.vue +291 -0
- package/src/components/AppCompInputTextToFillNx.vue +277 -0
- package/src/components/AppCompJauge.vue +11 -4
- package/src/components/AppCompMenu.vue +7 -14
- package/src/components/AppCompMenuItem.vue +7 -5
- package/src/components/AppCompNavigation.vue +21 -21
- package/src/components/AppCompNoteCall.vue +1 -0
- package/src/components/AppCompNoteCredit.vue +2 -1
- package/src/components/AppCompPlayBarNext.vue +94 -41
- package/src/components/AppCompPlayBarProgress.vue +82 -82
- package/src/components/AppCompPopUpNext.vue +6 -6
- package/src/components/AppCompQuiz.vue +500 -0
- package/src/components/AppCompQuizRecall.vue +113 -66
- package/src/components/AppCompSettingsMenu.vue +172 -172
- package/src/components/AppCompTableOfContent.vue +39 -10
- package/src/components/AppCompVideoPlayer.vue +1 -1
- package/src/components/AppCompViewDisplay.vue +6 -6
- package/src/composables/useQuiz.js +62 -179
- package/src/directives/nvdaFix.js +53 -0
- package/src/externalComps/ModuleView.vue +22 -22
- package/src/externalComps/SummaryView.vue +91 -91
- package/src/main.js +227 -30
- package/src/mixins/$mediaMixins.js +1 -11
- package/src/module/stores/appStore.js +29 -11
- 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/Crypto/index.js +53 -53
- package/src/module/xapi/Statement/activity.js +47 -47
- package/src/module/xapi/Statement/agent.js +55 -55
- package/src/module/xapi/Statement/group.js +26 -26
- package/src/module/xapi/Statement/index.js +259 -259
- package/src/module/xapi/Statement/statement.js +253 -253
- package/src/module/xapi/Statement/statementRef.js +23 -23
- package/src/module/xapi/Statement/substatement.js +22 -22
- package/src/module/xapi/Statement/verb.js +36 -36
- package/src/module/xapi/activitytypes.js +17 -17
- package/src/module/xapi/utils.js +167 -167
- package/src/module/xapi/verbs.js +294 -294
- 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/i18n.js +44 -44
- package/src/plugins/idb.js +1 -1
- 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/shared/generalfuncs.js +134 -0
- package/src/shared/validators.js +308 -234
- package/src/components/AppCompInputCheckBoxNext.vue +0 -205
- package/src/components/AppCompInputDropdownNext.vue +0 -201
- package/src/components/AppCompInputRadioNext.vue +0 -158
- package/src/components/AppCompInputTextNext.vue +0 -124
- package/src/components/AppCompInputTextTableNext.vue +0 -142
- package/src/components/AppCompInputTextToFillDropdownNext.vue +0 -238
- package/src/components/AppCompInputTextToFillNext.vue +0 -171
- package/src/components/AppCompQuizNext.vue +0 -2908
|
@@ -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>
|
|
@@ -76,10 +76,9 @@
|
|
|
76
76
|
)
|
|
77
77
|
"
|
|
78
78
|
>
|
|
79
|
-
<svg>
|
|
79
|
+
<svg aria-hidden="true" focusable="false">
|
|
80
80
|
<use href="#close-square-icon" />
|
|
81
81
|
</svg>
|
|
82
|
-
<span class="sr-only">{{ $t('button.closePopUp') }}</span>
|
|
83
82
|
</app-base-button>
|
|
84
83
|
</div>
|
|
85
84
|
|
|
@@ -151,7 +150,6 @@ export default {
|
|
|
151
150
|
customContentVisible: false,
|
|
152
151
|
customContent: null,
|
|
153
152
|
lessonCompletionStatus: false,
|
|
154
|
-
checkedDataFromServer: 0,
|
|
155
153
|
rightSidebarEvent: new CustomEvent('sidebarEvent', {
|
|
156
154
|
bubbles: true,
|
|
157
155
|
detail: {
|
|
@@ -175,9 +173,10 @@ export default {
|
|
|
175
173
|
'getMenuSettings',
|
|
176
174
|
'getRouteHistory',
|
|
177
175
|
'getOnboardingEnabled',
|
|
178
|
-
'getDataFromServer',
|
|
179
176
|
'getApplicationSettings',
|
|
180
|
-
'getCompStatusTracker'
|
|
177
|
+
'getCompStatusTracker',
|
|
178
|
+
'getLessonPosition',
|
|
179
|
+
'getCompletionState'
|
|
181
180
|
]),
|
|
182
181
|
isMenu() {
|
|
183
182
|
return this.$route.name === 'menu'
|
|
@@ -385,14 +384,13 @@ export default {
|
|
|
385
384
|
getAllCompleted: {
|
|
386
385
|
handler() {
|
|
387
386
|
// Check once the server to set the completion status of the lesson
|
|
388
|
-
if (this.
|
|
389
|
-
const
|
|
387
|
+
if (this.getCompletionState) {
|
|
388
|
+
const completedState = this.getCompletionState
|
|
390
389
|
|
|
391
390
|
this.lessonCompletionStatus =
|
|
392
391
|
!completedState || !completedState.completion
|
|
393
392
|
? false
|
|
394
393
|
: completedState.completion
|
|
395
|
-
this.checkedDataFromServer += 1
|
|
396
394
|
}
|
|
397
395
|
|
|
398
396
|
if (!this.lessonCompletionStatus) this.sendCompletionStatus('LESSON')
|
|
@@ -412,10 +410,9 @@ export default {
|
|
|
412
410
|
this.getModuleInfo.packageType === 'xapi' &&
|
|
413
411
|
this.getConnectionInfo &&
|
|
414
412
|
this.getConnectionInfo.actor &&
|
|
415
|
-
this.getConnectionInfo.remote
|
|
416
|
-
this.getDataFromServer
|
|
413
|
+
this.getConnectionInfo.remote
|
|
417
414
|
) {
|
|
418
|
-
const
|
|
415
|
+
const lessonPosition = this.getLessonPosition
|
|
419
416
|
|
|
420
417
|
const lastReached = lessonPosition.length ? lessonPosition[0] : ''
|
|
421
418
|
|
|
@@ -568,8 +565,8 @@ export default {
|
|
|
568
565
|
'updateCurrentTimeline',
|
|
569
566
|
'updateCurrentMediaElements',
|
|
570
567
|
'updateCurrentPage',
|
|
571
|
-
'updateDataFetchFromServer',
|
|
572
568
|
'updatesideBIsOpen',
|
|
569
|
+
'setCompletionState',
|
|
573
570
|
'updatepopIsOpen'
|
|
574
571
|
]),
|
|
575
572
|
onNavMouseleave() {
|
|
@@ -1352,7 +1349,6 @@ export default {
|
|
|
1352
1349
|
!this.getConnectionInfo ||
|
|
1353
1350
|
!this.getConnectionInfo.actor ||
|
|
1354
1351
|
!this.getConnectionInfo.remote ||
|
|
1355
|
-
!this.getDataFromServer ||
|
|
1356
1352
|
!context
|
|
1357
1353
|
)
|
|
1358
1354
|
return
|
|
@@ -1370,9 +1366,8 @@ export default {
|
|
|
1370
1366
|
thisActivityProgressLength,
|
|
1371
1367
|
thisActivityLength
|
|
1372
1368
|
|
|
1373
|
-
const { userProgress } = this.getDataFromServer
|
|
1374
1369
|
const thisActivityServerState =
|
|
1375
|
-
|
|
1370
|
+
this.getUserInteraction[this.$route.meta.activity_ref]
|
|
1376
1371
|
|
|
1377
1372
|
if (thisActivityServerState)
|
|
1378
1373
|
recordInServerLength = Object.keys(thisActivityServerState).length
|
|
@@ -1497,9 +1492,7 @@ export default {
|
|
|
1497
1492
|
duration: this.lessonDuration,
|
|
1498
1493
|
completion: this.lessonCompletionStatus
|
|
1499
1494
|
}
|
|
1500
|
-
this.
|
|
1501
|
-
completedState
|
|
1502
|
-
})
|
|
1495
|
+
this.setCompletionState(completedState)
|
|
1503
1496
|
}
|
|
1504
1497
|
|
|
1505
1498
|
break
|
|
@@ -1517,7 +1510,7 @@ export default {
|
|
|
1517
1510
|
*/
|
|
1518
1511
|
|
|
1519
1512
|
sendStartStatement(a) {
|
|
1520
|
-
if (!a
|
|
1513
|
+
if (!a) return
|
|
1521
1514
|
const { id } = a
|
|
1522
1515
|
let aName = null
|
|
1523
1516
|
|
|
@@ -1544,8 +1537,10 @@ export default {
|
|
|
1544
1537
|
/*
|
|
1545
1538
|
*Determine if activity as been initialized. Activity is initialized when it is in the serverRecords
|
|
1546
1539
|
*/
|
|
1547
|
-
|
|
1548
|
-
const thisActivityServerState =
|
|
1540
|
+
|
|
1541
|
+
const thisActivityServerState = this.getUserInteraction[id]
|
|
1542
|
+
? this.getUserInteraction[id]
|
|
1543
|
+
: {}
|
|
1549
1544
|
const recordInServerLength = Object.keys(thisActivityServerState).length
|
|
1550
1545
|
|
|
1551
1546
|
const stmt = {
|
|
@@ -83,6 +83,7 @@ export default {
|
|
|
83
83
|
//Getting initial existing userIntaction from store
|
|
84
84
|
const { userInteraction: previousInteraction = {} } =
|
|
85
85
|
store.getPageInteraction(activityRef, pageID)
|
|
86
|
+
|
|
86
87
|
return { store, previousInteraction, pageID, pageType }
|
|
87
88
|
},
|
|
88
89
|
|
|
@@ -124,6 +125,9 @@ export default {
|
|
|
124
125
|
getUserInteraction() {
|
|
125
126
|
return this.store.getUserInteraction
|
|
126
127
|
},
|
|
128
|
+
getPageInteraction() {
|
|
129
|
+
return this.store.getPageInteraction
|
|
130
|
+
},
|
|
127
131
|
|
|
128
132
|
getCurrentPage() {
|
|
129
133
|
return this.store.getCurrentPage
|
|
@@ -153,10 +157,6 @@ export default {
|
|
|
153
157
|
return this.store.getBifChoice
|
|
154
158
|
},
|
|
155
159
|
|
|
156
|
-
getDataFromServer() {
|
|
157
|
-
return this.store.getDataFromServer
|
|
158
|
-
},
|
|
159
|
-
|
|
160
160
|
isBranchingPage() {
|
|
161
161
|
return this.$route.meta.type === 'branching' && this.type !== 'pg_branch'
|
|
162
162
|
},
|
|
@@ -332,13 +332,13 @@ export default {
|
|
|
332
332
|
},
|
|
333
333
|
watch: {
|
|
334
334
|
userInteraction: {
|
|
335
|
-
handler(newValue) {
|
|
335
|
+
async handler(newValue) {
|
|
336
336
|
/**
|
|
337
|
-
*
|
|
337
|
+
* Observe changes in the number of poperties to dispatch updates in the userdata in the Store
|
|
338
338
|
*/
|
|
339
339
|
|
|
340
340
|
if (newValue && Object.entries(this.userInteraction).length) {
|
|
341
|
-
this.store.updateUserMetaData({
|
|
341
|
+
await this.store.updateUserMetaData({
|
|
342
342
|
activityRef: this.pageData.activityRef,
|
|
343
343
|
id: this.pageData.id,
|
|
344
344
|
userInteraction: { ...this.userInteraction }
|
|
@@ -347,6 +347,14 @@ export default {
|
|
|
347
347
|
},
|
|
348
348
|
immediate: true,
|
|
349
349
|
deep: true
|
|
350
|
+
},
|
|
351
|
+
'store.userDataLoaded': {
|
|
352
|
+
async handler() {
|
|
353
|
+
if (!this.store.userDataLoaded) return
|
|
354
|
+
this.userInteraction = await this.setInitialInteraction()
|
|
355
|
+
},
|
|
356
|
+
immediate: true,
|
|
357
|
+
deep: true
|
|
350
358
|
}
|
|
351
359
|
},
|
|
352
360
|
created() {
|
|
@@ -367,7 +375,6 @@ export default {
|
|
|
367
375
|
// Handeling presence of animation in the page
|
|
368
376
|
if (this.pageData.animation) {
|
|
369
377
|
// update the store with the information of currentTimeline
|
|
370
|
-
//this.store.updateCurrentTimeline(this.$gsap.timeline({ paused: true }))
|
|
371
378
|
}
|
|
372
379
|
|
|
373
380
|
if (this.type == 'pg_branch')
|
|
@@ -378,6 +385,7 @@ export default {
|
|
|
378
385
|
this.$bus.$on('media-viewed', this.setMediaViewed)
|
|
379
386
|
this.$bus.$on('manage-media-players', this.managePlayingMedia)
|
|
380
387
|
this.$bus.$on('video-transcript-toggle', this.onVideoTranscriptToggle)
|
|
388
|
+
this.$bus.$on('save-quiz-answers', this.saveQuizAnswers)
|
|
381
389
|
},
|
|
382
390
|
mounted() {
|
|
383
391
|
//Fix for firefox not updating aria-labelledby (was stuck saying Activite 1, page 1 on every pages)
|
|
@@ -424,6 +432,7 @@ export default {
|
|
|
424
432
|
this.$bus.$off('media-viewed', this.setMediaViewed)
|
|
425
433
|
this.$bus.$off('manage-media-players', this.managePlayingMedia)
|
|
426
434
|
this.$bus.$off('video-transcript-toggle', this.onVideoTranscriptToggle)
|
|
435
|
+
this.$bus.$off('save-quiz-answers', this.saveQuizAnswers)
|
|
427
436
|
window.removeEventListener('scroll', this.onFirstScroll, { once: true }) //in case user did not scroll
|
|
428
437
|
window.removeEventListener('scroll', this.handleScroll)
|
|
429
438
|
},
|
|
@@ -440,7 +449,10 @@ export default {
|
|
|
440
449
|
handleScroll(event) {
|
|
441
450
|
event
|
|
442
451
|
/*
|
|
443
|
-
* DocumentElement properties does not alway work properly on all Browser.
|
|
452
|
+
* DocumentElement properties does not alway work properly on all Browser.
|
|
453
|
+
* To Ensure reliable value of its properties on all.
|
|
454
|
+
* Browser we will calculate the Document Height by taking the maximum of
|
|
455
|
+
* body and documentElement height poperties.
|
|
444
456
|
* ref:https://javascript.info/size-and-scroll-window
|
|
445
457
|
*/
|
|
446
458
|
|
|
@@ -515,10 +527,7 @@ export default {
|
|
|
515
527
|
getProgress(id) {
|
|
516
528
|
id = id || this.pageData.id
|
|
517
529
|
|
|
518
|
-
const record = this.
|
|
519
|
-
this.pageData.activityRef,
|
|
520
|
-
id
|
|
521
|
-
)
|
|
530
|
+
const record = this.getPageInteraction(this.pageData.activityRef, id)
|
|
522
531
|
|
|
523
532
|
if (Object.entries(record).length) {
|
|
524
533
|
const { userInteraction } = record
|
|
@@ -620,7 +629,7 @@ export default {
|
|
|
620
629
|
})
|
|
621
630
|
},
|
|
622
631
|
getAnchorComplete() {
|
|
623
|
-
const records = this.
|
|
632
|
+
const records = this.getPageInteraction(
|
|
624
633
|
this.pageData.activityRef,
|
|
625
634
|
this.pageData.id
|
|
626
635
|
)
|
|
@@ -671,6 +680,7 @@ export default {
|
|
|
671
680
|
|
|
672
681
|
this.userInteraction.mediasViewed = mediasViewed
|
|
673
682
|
}
|
|
683
|
+
|
|
674
684
|
//Should add ID in media viewed list if viewed for the 1st time
|
|
675
685
|
if (mediasViewed.includes(mediaID)) return
|
|
676
686
|
|
|
@@ -729,6 +739,27 @@ export default {
|
|
|
729
739
|
const playbarInstance = m[attrKeys[3]]
|
|
730
740
|
playbarInstance.otherVideoTranscriptShown = transcriptShown
|
|
731
741
|
})
|
|
742
|
+
},
|
|
743
|
+
setInitialInteraction() {
|
|
744
|
+
const { activityRef, id: pageID } = this.pageData
|
|
745
|
+
const { userInteraction: previousInteraction = {} } =
|
|
746
|
+
this.getPageInteraction(activityRef, pageID)
|
|
747
|
+
|
|
748
|
+
return previousInteraction
|
|
749
|
+
},
|
|
750
|
+
saveQuizAnswers(el, quiz) {
|
|
751
|
+
if (!this.userInteraction.quizAnswers)
|
|
752
|
+
return (this.userInteraction.quizAnswers = { ...quiz })
|
|
753
|
+
const quizID = Object.keys(quiz)[0]
|
|
754
|
+
|
|
755
|
+
if (!this.userInteraction.quizAnswers[quizID])
|
|
756
|
+
return (this.userInteraction.quizAnswers = {
|
|
757
|
+
...this.userInteraction.quizAnswers,
|
|
758
|
+
...quiz
|
|
759
|
+
})
|
|
760
|
+
const quizValue = Object.values(quiz)[0]
|
|
761
|
+
this.userInteraction.quizAnswers[quizID] = quizValue
|
|
762
|
+
// const {}
|
|
732
763
|
}
|
|
733
764
|
}
|
|
734
765
|
}
|
|
@@ -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>
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
@ Description: This component is used to display skeleton screens while content is loading.
|
|
3
|
+
|
|
4
|
+
-->
|
|
5
|
+
|
|
6
|
+
<template>
|
|
7
|
+
<div class="skeleton-wrapper">
|
|
8
|
+
<div v-if="skeletonText" class="skeleton-text">{{ skeletonText }}</div>
|
|
9
|
+
<div v-for="line in skeletonLines" :key="line" class="skeleton-line"></div>
|
|
10
|
+
</div>
|
|
11
|
+
</template>
|
|
12
|
+
|
|
13
|
+
<script>
|
|
14
|
+
export default {
|
|
15
|
+
name: 'AppBaseSkeleton',
|
|
16
|
+
props: {
|
|
17
|
+
skeletonLines: { type: Number, default: 1 }, //number of skeleton lines to display
|
|
18
|
+
skeletonText: { type: String, default: `⏳ LOADING...` } //number of skeleton lines to display
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
</script>
|
|
22
|
+
|
|
23
|
+
<style lang="scss">
|
|
24
|
+
.skeleton-wrapper {
|
|
25
|
+
display: flex;
|
|
26
|
+
flex-direction: column;
|
|
27
|
+
width: 100%;
|
|
28
|
+
gap: 8px;
|
|
29
|
+
}
|
|
30
|
+
skeleton-text {
|
|
31
|
+
font-size: larger;
|
|
32
|
+
}
|
|
33
|
+
.skeleton-line {
|
|
34
|
+
height: 25px;
|
|
35
|
+
background: linear-gradient(90deg, #ddd, #eee, #ddd);
|
|
36
|
+
background-size: 200% 100%;
|
|
37
|
+
animation: skeleton-loading 1.2s infinite linear;
|
|
38
|
+
border-radius: 4px;
|
|
39
|
+
}
|
|
40
|
+
@keyframes skeleton-loading {
|
|
41
|
+
to {
|
|
42
|
+
background-position-x: -200%;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
</style>
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
<div v-show="!isLoading && !hasSourceLoadingError" class="audio-content">
|
|
30
30
|
<img v-if="mPoster" class="audio-img" :src="mPoster" :alt="mAlt" />
|
|
31
31
|
<div class="audio-media">
|
|
32
|
-
<
|
|
32
|
+
<span>{{ mTitle }}</span>
|
|
33
33
|
<div class="audio-media-player">
|
|
34
34
|
<audio
|
|
35
35
|
:id="id"
|
|
@@ -174,13 +174,17 @@ export default {
|
|
|
174
174
|
</script>
|
|
175
175
|
<style scoped lang="scss">
|
|
176
176
|
.audio-card {
|
|
177
|
-
// --primary100: #deeff8;
|
|
178
|
-
// --primary700: #005c8d;
|
|
179
177
|
position: relative;
|
|
180
178
|
border-radius: 4px;
|
|
181
179
|
padding: 24px;
|
|
180
|
+
min-width: 425px;
|
|
182
181
|
max-width: 600px;
|
|
183
182
|
box-shadow: 0px 3px 6px rgb(26 25 25 / 0.16);
|
|
183
|
+
|
|
184
|
+
@media screen and (max-width: 1000px) {
|
|
185
|
+
display: flex;
|
|
186
|
+
flex-direction: column;
|
|
187
|
+
}
|
|
184
188
|
.audio-img {
|
|
185
189
|
width: 128px;
|
|
186
190
|
margin-right: 24px;
|
|
@@ -190,6 +194,11 @@ export default {
|
|
|
190
194
|
flex-direction: row;
|
|
191
195
|
align-items: center;
|
|
192
196
|
padding-bottom: 24px;
|
|
197
|
+
|
|
198
|
+
@media screen and (max-width: 1000px) {
|
|
199
|
+
display: flex;
|
|
200
|
+
flex-direction: column;
|
|
201
|
+
}
|
|
193
202
|
.audio-media {
|
|
194
203
|
width: 100%;
|
|
195
204
|
h5 {
|
|
@@ -3,7 +3,10 @@
|
|
|
3
3
|
<app-base-button
|
|
4
4
|
:id="`btn_branch_${branchData.id}`"
|
|
5
5
|
:target-ref="branchData.id"
|
|
6
|
+
aria-controls="right-sidebar"
|
|
6
7
|
:title="btnTitle || $t('text.place_holder.for_title_btn_progress')"
|
|
8
|
+
:aria-label="btnTitle || $t('text.place_holder.for_title_btn_progress')"
|
|
9
|
+
:aria-expanded="isActive"
|
|
7
10
|
:class="
|
|
8
11
|
branchData.state === status.COMPLETE
|
|
9
12
|
? 'branch-btn-default branche-complete'
|
|
@@ -11,10 +14,18 @@
|
|
|
11
14
|
"
|
|
12
15
|
@click="openBranch(branchData.id)"
|
|
13
16
|
>
|
|
14
|
-
<svg
|
|
17
|
+
<svg
|
|
18
|
+
v-if="branchData.state === status.COMPLETE"
|
|
19
|
+
aria-hidden="true"
|
|
20
|
+
focusable="false"
|
|
21
|
+
>
|
|
15
22
|
<use href="#check-icon"></use>
|
|
16
23
|
</svg>
|
|
17
|
-
<svg
|
|
24
|
+
<svg
|
|
25
|
+
v-if="branchData.state != status.COMPLETE"
|
|
26
|
+
aria-hidden="true"
|
|
27
|
+
focusable="false"
|
|
28
|
+
>
|
|
18
29
|
<use href="#navigate-next-icon"></use>
|
|
19
30
|
</svg>
|
|
20
31
|
</app-base-button>
|