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.
Files changed (71) hide show
  1. package/.editorconfig +33 -33
  2. package/.eslintignore +29 -29
  3. package/.eslintrc.cjs +81 -81
  4. package/CHANGELOG +392 -377
  5. package/README.md +71 -71
  6. package/bk.scss +117 -117
  7. package/package.json +61 -61
  8. package/src/$locales/en.json +23 -25
  9. package/src/$locales/fr.json +22 -23
  10. package/src/assets/data/onboardingMessages.json +47 -47
  11. package/src/components/AppBase.vue +166 -99
  12. package/src/components/AppBaseButton.vue +2 -0
  13. package/src/components/AppBaseErrorDisplay.vue +438 -438
  14. package/src/components/AppBaseFlipCard.vue +84 -84
  15. package/src/components/AppBaseModule.vue +164 -106
  16. package/src/components/AppBasePage.vue +14 -4
  17. package/src/components/AppBasePopover.vue +41 -41
  18. package/src/components/AppCompAudio.vue +20 -48
  19. package/src/components/AppCompBranchButtons.vue +7 -53
  20. package/src/components/{AppCompTranscript.vue → AppCompContainer.vue} +8 -1
  21. package/src/components/AppCompInputRadioNext.vue +152 -152
  22. package/src/components/AppCompInputTextToFillNext.vue +171 -171
  23. package/src/components/AppCompJauge.vue +74 -74
  24. package/src/components/AppCompMenu.vue +429 -428
  25. package/src/components/AppCompMenuItem.vue +228 -228
  26. package/src/components/AppCompNavigation.vue +2 -2
  27. package/src/components/AppCompPlayBarNext.vue +5 -0
  28. package/src/components/AppCompPlayBarProgress.vue +82 -82
  29. package/src/components/AppCompSVGNext.vue +2 -3
  30. package/src/components/AppCompSettingsMenu.vue +172 -172
  31. package/src/components/AppCompVideoPlayer.vue +17 -15
  32. package/src/composables/useQuiz.js +206 -206
  33. package/src/externalComps/ModuleView.vue +22 -22
  34. package/src/externalComps/SummaryView.vue +91 -91
  35. package/src/main.js +34 -29
  36. package/src/mixins/$mediaMixins.js +819 -819
  37. package/src/mixins/timerMixin.js +155 -155
  38. package/src/module/stores/appStore.js +1 -1
  39. package/src/module/xapi/ADL.js +144 -4
  40. package/src/module/xapi/Crypto/Hasher.js +241 -241
  41. package/src/module/xapi/Crypto/WordArray.js +278 -278
  42. package/src/module/xapi/Crypto/algorithms/BufferedBlockAlgorithm.js +103 -103
  43. package/src/module/xapi/Crypto/algorithms/C_algo.js +315 -315
  44. package/src/module/xapi/Crypto/algorithms/HMAC.js +9 -9
  45. package/src/module/xapi/Crypto/algorithms/SHA1.js +9 -9
  46. package/src/module/xapi/Crypto/encoders/Base.js +105 -105
  47. package/src/module/xapi/Crypto/encoders/Base64.js +99 -99
  48. package/src/module/xapi/Crypto/encoders/Hex.js +61 -61
  49. package/src/module/xapi/Crypto/encoders/Latin1.js +61 -61
  50. package/src/module/xapi/Crypto/encoders/Utf8.js +45 -45
  51. package/src/module/xapi/Statement/agent.js +55 -55
  52. package/src/module/xapi/Statement/index.js +259 -259
  53. package/src/module/xapi/Statement/statement.js +253 -253
  54. package/src/module/xapi/utils.js +167 -167
  55. package/src/module/xapi/verbs.js +294 -294
  56. package/src/module/xapi/wrapper copy.js +1963 -0
  57. package/src/module/xapi/wrapper.js +121 -188
  58. package/src/module/xapi/xapiStatement.js +444 -444
  59. package/src/plugins/bus.js +8 -8
  60. package/src/plugins/gsap.js +14 -14
  61. package/src/plugins/helper.js +0 -1
  62. package/src/plugins/i18n.js +44 -44
  63. package/src/plugins/save.js +37 -37
  64. package/src/plugins/scorm.js +287 -287
  65. package/src/plugins/xapi.js +11 -11
  66. package/src/public/index.html +33 -33
  67. package/src/router/index.js +2 -1
  68. package/src/router/routes.js +312 -312
  69. package/src/shared/generalfuncs.js +210 -210
  70. package/src/shared/validators.js +2 -0
  71. package/src/components/AppCompPlayBar.vue +0 -1217
@@ -1,155 +1,155 @@
1
- /*
2
- @ Description: Mixins to extends general fonctionnalities in a page of an activity. Add time tracker in activities
3
- @ Note: .
4
- */
5
- export const timerMixin = {
6
- data() {
7
- return {
8
- lessonTimeCounter: 0,
9
- activityTimeCounter: 0,
10
- elapsedCounter: 0, // count the elapse time since lesson started
11
- activityInterval: null,
12
- lessonInterval: null,
13
- fullInterval: null,
14
- timerState: 'stopped',
15
- elapsedInterval: null // interval of passed time since the lesson is started. used only for saving purposed
16
- }
17
- },
18
- methods: {
19
- /* Start the timer */
20
- startTimer(op) {
21
- if (op && !['activity', 'lesson'].includes(op))
22
- throw new Error('this is not a valid option for the timer')
23
- if (this.timerState === 'stopped') {
24
- switch (op) {
25
- case 'activity':
26
- this.activityInterval = setInterval(() => {
27
- this.activityTimeCounter += 1
28
- }, 1000)
29
- this.timerState = 'started'
30
-
31
- break
32
-
33
- case 'lesson':
34
- this.lessonInterval = setInterval(() => {
35
- this.lessonTimeCounter += 1
36
- }, 1000)
37
- break
38
-
39
- default:
40
- this.fullInterval = setInterval(() => {
41
- this.activityTimeCounter += 1
42
- this.lessonTimeCounter += 1
43
- }, 1000)
44
- }
45
- }
46
- },
47
- /* Stop the timer and reset thimer to zero */
48
- stopTimer(op) {
49
- if (op && !['activity', 'lesson'].includes(op))
50
- throw new Error('this is not a valid parameter')
51
-
52
- if (this.timerState === 'started') {
53
- if (op === 'activity' && this.activityTimeCounter > 0) {
54
- this.lessonTimeCounter =
55
- this.lessonTimeCounter + this.activityTimeCounter //add to the lesson counter
56
- clearInterval(this.activityInterval) //clear the interval
57
- this.activityTimeCounter = 0 // reset the counter
58
- this.timerState = 'stopped'
59
- } else if (op === 'lesson' && this.lessonTimeCounter > 0) {
60
- clearInterval(this.lessonInterval)
61
- this.lessonTimeCounter = 0
62
- } else {
63
- clearInterval(this.fullInterval)
64
- clearInterval(this.elapsedCounter)
65
- clearInterval(this.elapsedInterval)
66
-
67
- this.activityTimeCounter = 0
68
- this.lessonTimeCounter = 0
69
- this.elapsedCounter = 0
70
- }
71
- }
72
- },
73
- /* Pause the timer but does not reset to zero*/
74
- pauseTimer(op) {
75
- if (op && !['activity', 'lesson'].includes(op))
76
- throw new Error('this is not a valid parameter')
77
-
78
- if (op === 'activity' && this.activityTimeCounter > 0) {
79
- clearInterval(this.activityInterval)
80
- } else if (op === 'lesson') {
81
- clearInterval(this.lessonInterval)
82
- } else {
83
- clearInterval(this.fullInterval)
84
- clearInterval(this.elapsedInterval)
85
- }
86
- },
87
-
88
- /* Format seconds to ISO 8601 format */
89
- formatToISOString(seconds) {
90
- let d = new Date(null) //create a default date ref
91
- d.setSeconds(seconds) //set the time with passed numbers of seconds
92
- //Example of ISO 8601 time format of 24 chars: "1970-01-04T14:50:00.000Z"
93
- let ISOTime = d.toISOString()
94
-
95
- return ISOTime // YYYY-MM-DDTHH:mm:ss.sssZ
96
- },
97
-
98
- /* Parse a ISO string time period to the format of HH:mm:ss */
99
- ISOTimeParser(seconds) {
100
- let ISOTimePeriod = this.formatToISOString(seconds).substring(8, 19) // only the time portion of it
101
- ISOTimePeriod = ISOTimePeriod.split('T')
102
- const DDToHrs = (parseInt(ISOTimePeriod[0]) - 1) * 24 // convert xxT to hrs
103
- const periodOfTime = ISOTimePeriod[1] ? ISOTimePeriod[1].split(':') : null
104
-
105
- if (!periodOfTime) return '00:00:00'
106
-
107
- let timeString = ''
108
- let HH = (DDToHrs + parseInt(periodOfTime[0])).toString()
109
- let mm = periodOfTime[1]
110
- let ss = periodOfTime[2]
111
-
112
- if (HH.length === 1) HH = `0${HH}`
113
-
114
- timeString = `${HH}:${mm}:${ss}`
115
-
116
- return timeString
117
- }
118
- },
119
- beforeUnmount() {
120
- this.$bus.$off('start-timer', this.startTimer)
121
- this.$bus.$off('stop-timer', this.stopTimer)
122
- this.$bus.$off('pause-timer', this.pauseTimer)
123
- },
124
- mounted() {
125
- this.$bus.$on('start-timer', this.startTimer)
126
-
127
- this.$bus.$on('stop-timer', this.stopTimer)
128
-
129
- this.$bus.$on('pause-timer', this.pauseTimer)
130
-
131
- this.elapsedInterval = setInterval(() => {
132
- this.elapsedCounter += 1
133
- }, 1000)
134
- },
135
- computed: {
136
- activityDuration() {
137
- let duration
138
- if (this.activityTimeCounter > 0)
139
- duration = this.ISOTimeParser(this.activityTimeCounter)
140
- else duration = '00:00:00'
141
-
142
- return duration
143
- },
144
- lessonDuration() {
145
- this.lessonTimeCounter = this.lessonTimeCounter + this.activityTimeCounter
146
-
147
- let duration = this.ISOTimeParser(this.lessonTimeCounter)
148
- return duration
149
- },
150
- elapsedTime() {
151
- const eTime = this.elapsedCounter
152
- return eTime
153
- }
154
- }
155
- }
1
+ /*
2
+ @ Description: Mixins to extends general fonctionnalities in a page of an activity. Add time tracker in activities
3
+ @ Note: .
4
+ */
5
+ export const timerMixin = {
6
+ data() {
7
+ return {
8
+ lessonTimeCounter: 0,
9
+ activityTimeCounter: 0,
10
+ elapsedCounter: 0, // count the elapse time since lesson started
11
+ activityInterval: null,
12
+ lessonInterval: null,
13
+ fullInterval: null,
14
+ timerState: 'stopped',
15
+ elapsedInterval: null // interval of passed time since the lesson is started. used only for saving purposed
16
+ }
17
+ },
18
+ methods: {
19
+ /* Start the timer */
20
+ startTimer(op) {
21
+ if (op && !['activity', 'lesson'].includes(op))
22
+ throw new Error('this is not a valid option for the timer')
23
+ if (this.timerState === 'stopped') {
24
+ switch (op) {
25
+ case 'activity':
26
+ this.activityInterval = setInterval(() => {
27
+ this.activityTimeCounter += 1
28
+ }, 1000)
29
+ this.timerState = 'started'
30
+
31
+ break
32
+
33
+ case 'lesson':
34
+ this.lessonInterval = setInterval(() => {
35
+ this.lessonTimeCounter += 1
36
+ }, 1000)
37
+ break
38
+
39
+ default:
40
+ this.fullInterval = setInterval(() => {
41
+ this.activityTimeCounter += 1
42
+ this.lessonTimeCounter += 1
43
+ }, 1000)
44
+ }
45
+ }
46
+ },
47
+ /* Stop the timer and reset thimer to zero */
48
+ stopTimer(op) {
49
+ if (op && !['activity', 'lesson'].includes(op))
50
+ throw new Error('this is not a valid parameter')
51
+
52
+ if (this.timerState === 'started') {
53
+ if (op === 'activity' && this.activityTimeCounter > 0) {
54
+ this.lessonTimeCounter =
55
+ this.lessonTimeCounter + this.activityTimeCounter //add to the lesson counter
56
+ clearInterval(this.activityInterval) //clear the interval
57
+ this.activityTimeCounter = 0 // reset the counter
58
+ this.timerState = 'stopped'
59
+ } else if (op === 'lesson' && this.lessonTimeCounter > 0) {
60
+ clearInterval(this.lessonInterval)
61
+ this.lessonTimeCounter = 0
62
+ } else {
63
+ clearInterval(this.fullInterval)
64
+ clearInterval(this.elapsedCounter)
65
+ clearInterval(this.elapsedInterval)
66
+
67
+ this.activityTimeCounter = 0
68
+ this.lessonTimeCounter = 0
69
+ this.elapsedCounter = 0
70
+ }
71
+ }
72
+ },
73
+ /* Pause the timer but does not reset to zero*/
74
+ pauseTimer(op) {
75
+ if (op && !['activity', 'lesson'].includes(op))
76
+ throw new Error('this is not a valid parameter')
77
+
78
+ if (op === 'activity' && this.activityTimeCounter > 0) {
79
+ clearInterval(this.activityInterval)
80
+ } else if (op === 'lesson') {
81
+ clearInterval(this.lessonInterval)
82
+ } else {
83
+ clearInterval(this.fullInterval)
84
+ clearInterval(this.elapsedInterval)
85
+ }
86
+ },
87
+
88
+ /* Format seconds to ISO 8601 format */
89
+ formatToISOString(seconds) {
90
+ let d = new Date(null) //create a default date ref
91
+ d.setSeconds(seconds) //set the time with passed numbers of seconds
92
+ //Example of ISO 8601 time format of 24 chars: "1970-01-04T14:50:00.000Z"
93
+ let ISOTime = d.toISOString()
94
+
95
+ return ISOTime // YYYY-MM-DDTHH:mm:ss.sssZ
96
+ },
97
+
98
+ /* Parse a ISO string time period to the format of HH:mm:ss */
99
+ ISOTimeParser(seconds) {
100
+ let ISOTimePeriod = this.formatToISOString(seconds).substring(8, 19) // only the time portion of it
101
+ ISOTimePeriod = ISOTimePeriod.split('T')
102
+ const DDToHrs = (parseInt(ISOTimePeriod[0]) - 1) * 24 // convert xxT to hrs
103
+ const periodOfTime = ISOTimePeriod[1] ? ISOTimePeriod[1].split(':') : null
104
+
105
+ if (!periodOfTime) return '00:00:00'
106
+
107
+ let timeString = ''
108
+ let HH = (DDToHrs + parseInt(periodOfTime[0])).toString()
109
+ let mm = periodOfTime[1]
110
+ let ss = periodOfTime[2]
111
+
112
+ if (HH.length === 1) HH = `0${HH}`
113
+
114
+ timeString = `${HH}:${mm}:${ss}`
115
+
116
+ return timeString
117
+ }
118
+ },
119
+ beforeUnmount() {
120
+ this.$bus.$off('start-timer', this.startTimer)
121
+ this.$bus.$off('stop-timer', this.stopTimer)
122
+ this.$bus.$off('pause-timer', this.pauseTimer)
123
+ },
124
+ mounted() {
125
+ this.$bus.$on('start-timer', this.startTimer)
126
+
127
+ this.$bus.$on('stop-timer', this.stopTimer)
128
+
129
+ this.$bus.$on('pause-timer', this.pauseTimer)
130
+
131
+ this.elapsedInterval = setInterval(() => {
132
+ this.elapsedCounter += 1
133
+ }, 1000)
134
+ },
135
+ computed: {
136
+ activityDuration() {
137
+ let duration
138
+ if (this.activityTimeCounter > 0)
139
+ duration = this.ISOTimeParser(this.activityTimeCounter)
140
+ else duration = '00:00:00'
141
+
142
+ return duration
143
+ },
144
+ lessonDuration() {
145
+ this.lessonTimeCounter = this.lessonTimeCounter + this.activityTimeCounter
146
+
147
+ let duration = this.ISOTimeParser(this.lessonTimeCounter)
148
+ return duration
149
+ },
150
+ elapsedTime() {
151
+ const eTime = this.elapsedCounter
152
+ return eTime
153
+ }
154
+ }
155
+ }
@@ -672,7 +672,7 @@ export const useAppStore = defineStore('$appStore', {
672
672
  },
673
673
 
674
674
  /* set/update the Application configuration*/
675
- setAppConfigs(data) {
675
+ async setAppConfigs(data) {
676
676
  this.appConfigs = data
677
677
  const {
678
678
  id,
@@ -154,7 +154,7 @@ export default class ADL {
154
154
  params['verb'] = this.verbs[vb].id // completed state
155
155
  params['activity'] = activityId // this current activity define by this id
156
156
  params['agent'] = `{"mbox": "mailto:${email}"}` // the user identify by this email
157
- params['limit'] = 500 //limit of record to return by the LRS
157
+ params['limit'] = 200 //limit of record to return by the LRS
158
158
  params['ascending'] = true //ordered by the oldest statement recorded
159
159
 
160
160
  let date = new Date()
@@ -191,6 +191,7 @@ export default class ADL {
191
191
  } else {
192
192
  userData = {}
193
193
  }
194
+
194
195
  return userData
195
196
  } catch (err) {
196
197
  console.log(err)
@@ -245,7 +246,7 @@ export default class ADL {
245
246
  params['activity'] = activityId // this current activity define by this id
246
247
  params['agent'] = `{"mbox": "mailto:${email}"}` // the user identify by this email
247
248
  params['ascending'] = true //ordered by the oldest statement recorded
248
- params['limit'] = 500 //limit of record to return by the LRS
249
+ params['limit'] = 200 //limit of record to return by the LRS
249
250
 
250
251
  let date = new Date()
251
252
  let dd = new Date(date.setDate(date.getDate() + 1)).toISOString() //Date is set to next day(tomorrow) for Lrs to take in account statement registered today.
@@ -296,7 +297,7 @@ export default class ADL {
296
297
  params['activity'] = activityId // this current activity define by this id
297
298
  params['agent'] = `{"mbox": "mailto:${email}"}` // the user identify by this email
298
299
  params['ascending'] = true //ordered by the oldest statement recorded
299
- params['limit'] = 500 //limit of record to return by the LRS
300
+ params['limit'] = 200 //limit of record to return by the LRS
300
301
 
301
302
  let date = new Date()
302
303
  let dd = new Date(date.setDate(date.getDate() + 1)).toISOString() //Date is set to next day(tomorrow) for Lrs to take in account statement registered today.
@@ -345,7 +346,7 @@ export default class ADL {
345
346
  params['activity'] = activityId // this current activity define by this id
346
347
  params['agent'] = `{"mbox": "mailto:${email}"}` // the user identify by this email
347
348
  params['ascending'] = true //ordered by the oldest statement recorded
348
- params['limit'] = 500 //limit of record to return by the LRS
349
+ params['limit'] = 200 //limit of record to return by the LRS
349
350
 
350
351
  let date = new Date()
351
352
  let dd = new Date(date.setDate(date.getDate() + 1)).toISOString() //Date is set to next day(tomorrow) for Lrs to take in account statement registered today.
@@ -377,4 +378,143 @@ export default class ADL {
377
378
  }
378
379
  return playbarValues[0] ? playbarValues[0] : {}
379
380
  }
381
+ /**
382
+ * Method to get a multiple concurent requests using promiseAll to the server
383
+ * and return all data at once.
384
+ * the following request are made to the server:
385
+ * get application-settings: saved value for the user preferred settings
386
+ * get user-data: saved values for user progression
387
+ * get playbar-value : saved value for the medias play-bar
388
+ * get lesson-status : saved value for the lession status
389
+ *
390
+ * @param {Array} searchParams - Array of Object with key value representing each search paremeter.
391
+ * a parameter object definition is expected to have the following signature:
392
+ * {
393
+ * email{String} agent email,
394
+ * verb {String} verb for the request,
395
+ * activityId {String} - activity id ,
396
+ * }
397
+ * @example here is an exemple of the search param:
398
+ * {email: 'wizardy0@mymailbox.com', verb: 'completed',activityId:'"http://localhost:5173/vuetify_p4/v3"' }
399
+ * @return {object} data with a collection of all the reponses
400
+ * from the promiseAll and the status of last request
401
+ */
402
+ async _getBulkData(searchParams) {
403
+ const validVerbs = [
404
+ 'progressed',
405
+ 'completed',
406
+ 'suspended',
407
+ 'terminated',
408
+ 'preferred',
409
+ 'played',
410
+ 'exited'
411
+ ]
412
+
413
+ const paramList = []
414
+ // account statement registered today.
415
+ let date = new Date()
416
+ let dd = new Date(date.setDate(date.getDate() + 1)).toISOString() //Date is set to next day(tomorrow) for Lrs to take in
417
+
418
+ for (let param of searchParams) {
419
+ let { email, verb, activityId } = param
420
+ let vb = verb && validVerbs.includes(verb) ? verb : 'terminated'
421
+ const params = {}
422
+
423
+ params['verb'] = this.verbs[vb].id // completed state
424
+ params['activity'] = activityId // this current activity define by this id
425
+ params['agent'] = `{"mbox": "mailto:${email}"}` // the user identify by this email
426
+ params['ascending'] = true //ordered by the oldest statement recorded
427
+ params['limit'] = 250 //limit of record to return by the LRS
428
+
429
+ params['until'] = dd
430
+ paramList.push(params)
431
+ }
432
+ const { response } = await this.XAPIWrapper.getStatements(paramList)
433
+
434
+ let userData = {},
435
+ playbarValues = {},
436
+ preferredSettings = {},
437
+ lessonStatus = {},
438
+ savedPoint = ''
439
+
440
+ if (response && response.length > 0) {
441
+ for (const res of response) {
442
+ const { statements } = await res.json()
443
+ if (!statements || statements.length == 0) continue
444
+
445
+ let lastRecord = statements.toReversed()[0] // get last recorded statement
446
+ // Verify that the extensions value of the statement has elements
447
+
448
+ //Handeling Lession comppletion status
449
+ if (lastRecord.verb.id.includes('completed')) {
450
+ lessonStatus = lastRecord.result ? lastRecord.result : {}
451
+ }
452
+
453
+ if (
454
+ lastRecord.object.definition.extensions &&
455
+ Object.keys(lastRecord.object.definition.extensions).length
456
+ ) {
457
+ const allExtensionsKeys = Object.keys(
458
+ lastRecord.object.definition.extensions
459
+ )
460
+
461
+ //Search for the user-data entry in the extensions
462
+ allExtensionsKeys.forEach((extension) => {
463
+ switch (true) {
464
+ case extension.includes('user-data'): {
465
+ //Search for the user-data entry in the extensions
466
+ const userDataExtension = allExtensionsKeys.filter(
467
+ (extension) => extension.includes('user-data')
468
+ )
469
+ userData =
470
+ lastRecord.object.definition.extensions[userDataExtension[0]]
471
+
472
+ break
473
+ }
474
+ case extension.includes('ending-point'): {
475
+ const userDataExtension = allExtensionsKeys.filter(
476
+ (extension) => extension.includes('ending-point')
477
+ )
478
+ savedPoint =
479
+ lastRecord.object.definition.extensions[userDataExtension[0]]
480
+
481
+ break
482
+ }
483
+ case extension.includes('application-settings'): {
484
+ const userDataExtension = allExtensionsKeys.filter(
485
+ (extension) => extension.includes('application-settings')
486
+ )
487
+
488
+ const settingsData =
489
+ lastRecord.object.definition.extensions[userDataExtension[0]]
490
+
491
+ preferredSettings = settingsData ? settingsData : {}
492
+
493
+ break
494
+ }
495
+ case extension.includes('playbar-values'): {
496
+ const userDataExtension = allExtensionsKeys.filter(
497
+ (extension) => extension.includes('playbar-values')
498
+ )
499
+
500
+ const playbarData =
501
+ lastRecord.object.definition.extensions[userDataExtension[0]]
502
+ playbarValues = playbarData ? playbarData : {}
503
+
504
+ break
505
+ }
506
+ }
507
+ })
508
+ }
509
+ }
510
+ }
511
+
512
+ return {
513
+ userData,
514
+ savedPoint,
515
+ preferredSettings,
516
+ playbarValues,
517
+ lessonStatus
518
+ }
519
+ }
380
520
  }