fcad-core-dragon 2.2.0 → 2.3.0-test.1
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/.gitlab-ci.yml +14 -28
- package/.releaserc +27 -0
- package/CHANGELOG.md +14 -0
- package/documentation/.vitepress/config.js +109 -32
- package/package.json +50 -36
- package/src/components/AppBase.vue +18 -64
- package/src/components/AppBaseModule.vue +34 -11
- package/src/components/AppBasePage.vue +0 -3
- package/src/components/AppCompInputMath.vue +20 -0
- package/src/components/AppCompInputTextToFillNx.vue +2 -1
- package/src/components/AppCompNoteCredit.vue +0 -4
- package/src/components/AppCompPlayBarNext.vue +0 -2
- package/src/components/AppCompQuizNext.vue +13 -0
- package/src/main.js +32 -45
- package/src/module/stores/appStore.js +3 -3
- package/src/module/xapi/ADL.js +66 -77
- package/src/shared/generalfuncs.js +0 -1
- package/vitest.setup.js +0 -5
- package/artifacts/playwright-report/index.html +0 -85
|
@@ -95,7 +95,6 @@ export default {
|
|
|
95
95
|
}
|
|
96
96
|
},
|
|
97
97
|
setup(props) {
|
|
98
|
-
//console.log('dans setup')
|
|
99
98
|
const store = useAppStore()
|
|
100
99
|
const { activityRef, id: pageID, type: pageType } = props.pageData
|
|
101
100
|
const { t } = useI18n()
|
|
@@ -374,8 +373,6 @@ export default {
|
|
|
374
373
|
/**
|
|
375
374
|
* Observe changes in the number of poperties to dispatch updates in the userdata in the Store
|
|
376
375
|
*/
|
|
377
|
-
// console.log('ici')
|
|
378
|
-
//console.log(this.userInteraction)
|
|
379
376
|
if (newValue && Object.entries(this.userInteraction).length) {
|
|
380
377
|
await this.store.updateUserMetaData({
|
|
381
378
|
activityRef: this.pageData.activityRef,
|
|
@@ -351,10 +351,6 @@ export default {
|
|
|
351
351
|
const elTarget = widgetContent.namedItem(ref) // Target current button
|
|
352
352
|
const pageRef = elTarget.getAttribute('pageref')
|
|
353
353
|
|
|
354
|
-
console.log('widgetContent :', widgetContent)
|
|
355
|
-
console.log('elTarget :', elTarget)
|
|
356
|
-
console.log('pageRef :', pageRef)
|
|
357
|
-
|
|
358
354
|
if (!this.sideBarIsOpen) this.prevNote = null //reset previous when sidebar is opened
|
|
359
355
|
|
|
360
356
|
let prevPageref = this.prevNote
|
|
@@ -922,7 +922,6 @@ export default {
|
|
|
922
922
|
//window handlers for playbar progress
|
|
923
923
|
window.addEventListener('mousemove', this.progressWindowMove)
|
|
924
924
|
window.addEventListener('mouseup', this.progressWindowUp)
|
|
925
|
-
// console.log('⚠️--- TEST AppCompPlayBarNext---', this.mediaElement)
|
|
926
925
|
//Update data when media as a timeupdate/ended
|
|
927
926
|
this.mediaElement.addEventListener(
|
|
928
927
|
'timeupdate',
|
|
@@ -1635,7 +1634,6 @@ export default {
|
|
|
1635
1634
|
*/
|
|
1636
1635
|
toggleFullScreen() {
|
|
1637
1636
|
const fullscreenElement = this.mediaContainer
|
|
1638
|
-
//console.log(fullscreenElement)
|
|
1639
1637
|
|
|
1640
1638
|
if (document.fullscreenElement) {
|
|
1641
1639
|
// exitFullscreen is only available on the Document object.
|
|
@@ -512,4 +512,17 @@ export default {
|
|
|
512
512
|
.custom-control {
|
|
513
513
|
z-index: 0;
|
|
514
514
|
}
|
|
515
|
+
|
|
516
|
+
.math-ex-infinity{
|
|
517
|
+
|
|
518
|
+
div.box-btn{
|
|
519
|
+
display: flex;
|
|
520
|
+
flex-wrap: wrap;
|
|
521
|
+
flex-direction: row;
|
|
522
|
+
|
|
523
|
+
:last-child{
|
|
524
|
+
margin-left: 10px;
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
}
|
|
515
528
|
</style>
|
package/src/main.js
CHANGED
|
@@ -6,7 +6,6 @@ import AppBaseFlipCard from './components/AppBaseFlipCard.vue'
|
|
|
6
6
|
import AppBasePopover from './components/AppBasePopover.vue'
|
|
7
7
|
import AppCompJauge from './components/AppCompJauge.vue'
|
|
8
8
|
import AppBaseErrorDisplay from './components/AppBaseErrorDisplay.vue'
|
|
9
|
-
//import AppCompBif from './components/AppCompBif.vue'
|
|
10
9
|
import AppCompAudio from './components/AppCompAudio.vue'
|
|
11
10
|
import AppCompBranchButtons from './components/AppCompBranchButtons.vue'
|
|
12
11
|
import AppCompCarousel from './components/AppCompCarousel.vue'
|
|
@@ -45,6 +44,7 @@ import fcadRouter from './router/index.js'
|
|
|
45
44
|
import '@mdi/font/css/materialdesignicons.css'
|
|
46
45
|
import 'vuetify/styles'
|
|
47
46
|
import { createVuetify } from 'vuetify'
|
|
47
|
+
|
|
48
48
|
import { fr, en } from 'vuetify/locale'
|
|
49
49
|
|
|
50
50
|
const pinia = createPinia()
|
|
@@ -60,6 +60,7 @@ export default {
|
|
|
60
60
|
app.component('FocusTrap', FocusTrap)
|
|
61
61
|
app.use(eventBus)
|
|
62
62
|
app.use($idb)
|
|
63
|
+
|
|
63
64
|
const vuetify = createVuetify({
|
|
64
65
|
locale: {
|
|
65
66
|
locale: 'fr',
|
|
@@ -76,7 +77,6 @@ export default {
|
|
|
76
77
|
app.component('AppBaseFlipCard', AppBaseFlipCard)
|
|
77
78
|
app.component('AppBaseErrorDisplay', AppBaseErrorDisplay)
|
|
78
79
|
app.component('AppCompMenu', AppCompMenu)
|
|
79
|
-
//app.component('app-comp-bif', AppCompBif)
|
|
80
80
|
app.component('AppCompAudioPlayer', AppCompAudio)
|
|
81
81
|
app.component('AppCompBranchButtons', AppCompBranchButtons)
|
|
82
82
|
app.component('AppCompCarousel', AppCompCarousel)
|
|
@@ -125,7 +125,6 @@ export default {
|
|
|
125
125
|
({
|
|
126
126
|
name, // name of the action
|
|
127
127
|
store, // store instance, same as `someStore`
|
|
128
|
-
args, // array of parameters passed to the action
|
|
129
128
|
after // hook after the action returns or resolves
|
|
130
129
|
}) => {
|
|
131
130
|
after(async (result) => {
|
|
@@ -189,8 +188,7 @@ export default {
|
|
|
189
188
|
|
|
190
189
|
if (playbarValues)
|
|
191
190
|
appStore.$state.mediaPlaybarValues = playbarValues
|
|
192
|
-
|
|
193
|
-
if (lessonPosition) appStore.setLessonPosition(lessonPosition)
|
|
191
|
+
if (lessonPosition) appStore.setLessonPosition([lessonPosition])
|
|
194
192
|
if (completedState) appStore.setCompletionState(completedState)
|
|
195
193
|
}
|
|
196
194
|
//Open Connection to IDB and Save the store state to localDB
|
|
@@ -278,9 +276,19 @@ export default {
|
|
|
278
276
|
}
|
|
279
277
|
}
|
|
280
278
|
// Get LRS autorisation info from serveur
|
|
281
|
-
const request = await axios.get(
|
|
282
|
-
|
|
283
|
-
|
|
279
|
+
const request = await axios.get(
|
|
280
|
+
'../../configs-xapi/xapi-org.json'
|
|
281
|
+
)
|
|
282
|
+
let { organization = null } = data
|
|
283
|
+
const { basicauth } =
|
|
284
|
+
organization && request.data[organization.toLowerCase()]
|
|
285
|
+
? (() => request.data[organization.toLowerCase()])()
|
|
286
|
+
: (() => {
|
|
287
|
+
console.warn(
|
|
288
|
+
`🚩 No organization found with the name '${organization}'. will default to organization 'root'.`
|
|
289
|
+
)
|
|
290
|
+
return request.data.root
|
|
291
|
+
})()
|
|
284
292
|
|
|
285
293
|
c.auth = basicauth
|
|
286
294
|
connectionInfo = c
|
|
@@ -345,12 +353,15 @@ export default {
|
|
|
345
353
|
} = config
|
|
346
354
|
|
|
347
355
|
let server = remote ? specification : 'local'
|
|
356
|
+
const unknownHost =
|
|
357
|
+
!window.location.hostname.includes('cegepadistance.ca') &&
|
|
358
|
+
window.location.hostname !== 'localhost'
|
|
348
359
|
//falback to idb when scorm and origin is localhost
|
|
349
360
|
if (
|
|
350
361
|
(specification == 'scorm' && window.location.hostname == 'localhost') ||
|
|
351
|
-
|
|
362
|
+
unknownHost
|
|
352
363
|
)
|
|
353
|
-
server = '
|
|
364
|
+
server = 'unknown'
|
|
354
365
|
|
|
355
366
|
let data = null
|
|
356
367
|
|
|
@@ -396,59 +407,34 @@ export default {
|
|
|
396
407
|
try {
|
|
397
408
|
const actorMbox = actor.mbox.replace('mailto:', '')
|
|
398
409
|
const activityId = activity_id
|
|
399
|
-
const _url = new URL(activityId)
|
|
400
|
-
const parentID = `${_url.origin}/${crs_id}` // redefining activity id for statement
|
|
401
|
-
|
|
402
410
|
const lessonProgressParam = { email: actorMbox, activityId }
|
|
403
411
|
const lessonStateParam = {
|
|
404
412
|
email: actorMbox,
|
|
405
413
|
activityId,
|
|
406
414
|
verb: 'completed'
|
|
407
415
|
}
|
|
408
|
-
const lessonPosionParam = {
|
|
409
|
-
email: actorMbox,
|
|
410
|
-
activityId
|
|
411
|
-
}
|
|
412
|
-
const playbarParam = {
|
|
413
|
-
email: actorMbox,
|
|
414
|
-
activityId,
|
|
415
|
-
verb: 'played'
|
|
416
|
-
}
|
|
417
|
-
const preferencesParam = {
|
|
418
|
-
email: actorMbox,
|
|
419
|
-
activityId: parentID,
|
|
420
|
-
verb: 'preferred'
|
|
421
|
-
}
|
|
422
416
|
|
|
423
|
-
const fetchParams = [
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
playbarParam,
|
|
428
|
-
preferencesParam
|
|
429
|
-
]
|
|
417
|
+
const fetchParams = [lessonProgressParam, lessonStateParam]
|
|
418
|
+
|
|
419
|
+
const { userData, preferredSettings, lessonStatus } =
|
|
420
|
+
await $xapi._getBulkData(fetchParams)
|
|
430
421
|
|
|
431
422
|
const {
|
|
432
|
-
|
|
423
|
+
routeHistory = [],
|
|
433
424
|
savedPoint,
|
|
434
|
-
preferredSettings,
|
|
435
425
|
playbarValues,
|
|
436
|
-
|
|
437
|
-
} =
|
|
438
|
-
|
|
439
|
-
const { routeHistory = [], ...progress } = userData
|
|
426
|
+
...progress
|
|
427
|
+
} = userData
|
|
440
428
|
|
|
441
429
|
const completedState = lessonStatus || {}
|
|
442
430
|
const lessonPosition = savedPoint || ''
|
|
443
|
-
const userSettings = preferredSettings || {}
|
|
444
431
|
|
|
445
432
|
data = {
|
|
446
433
|
progress,
|
|
447
434
|
routeHistory,
|
|
448
435
|
lessonPosition,
|
|
449
436
|
completedState,
|
|
450
|
-
playbarValues
|
|
451
|
-
userSettings
|
|
437
|
+
playbarValues
|
|
452
438
|
}
|
|
453
439
|
} catch (err) {
|
|
454
440
|
throw new Error(err)
|
|
@@ -489,8 +475,9 @@ export default {
|
|
|
489
475
|
|
|
490
476
|
appStore.applicationSettings = settingsOptions
|
|
491
477
|
//=================================END SETTING PREFERENCES ====================================//
|
|
492
|
-
|
|
493
|
-
|
|
478
|
+
app.provide('FCAD_STORE', appStore)
|
|
479
|
+
app.provide('FCAD_ROUTER', fcadRouter)
|
|
480
|
+
|
|
494
481
|
const i18n = initLocalisation(options.i18n)
|
|
495
482
|
app.use(i18n)
|
|
496
483
|
app.use(helper)
|
|
@@ -125,9 +125,9 @@ export const useAppStore = defineStore('$appStore', {
|
|
|
125
125
|
* @description: Check if auto-show subtitles is enabled in application settings
|
|
126
126
|
*/
|
|
127
127
|
getBookmarkEnabled: (state) => {
|
|
128
|
-
return state.
|
|
129
|
-
? state.
|
|
130
|
-
:
|
|
128
|
+
return state.appConfigs.bookmark_active
|
|
129
|
+
? state.appConfigs.bookmark_active
|
|
130
|
+
: false
|
|
131
131
|
},
|
|
132
132
|
|
|
133
133
|
/**
|
package/src/module/xapi/ADL.js
CHANGED
|
@@ -4,6 +4,7 @@ import xAPILaunch from './launch'
|
|
|
4
4
|
import { defineUtils } from './utils'
|
|
5
5
|
import { xapiwrapper } from './wrapper'
|
|
6
6
|
import { xapiStatement } from './xapiStatement'
|
|
7
|
+
import { de } from 'vuetify/locale'
|
|
7
8
|
|
|
8
9
|
//ref: https://github.com/adlnet/xAPI-Spec/blob/master/xAPI-Communication.md#partthree
|
|
9
10
|
|
|
@@ -156,11 +157,14 @@ export default class ADL {
|
|
|
156
157
|
params['activity'] = activityId // this current activity define by this id
|
|
157
158
|
params['agent'] = `{"mbox": "mailto:${email}"}` // the user identify by this email
|
|
158
159
|
params['limit'] = 200 //limit of record to return by the LRS
|
|
160
|
+
// params['limit'] = 1 //limit of record to return by the LRS
|
|
159
161
|
params['ascending'] = true //ordered by the oldest statement recorded
|
|
162
|
+
// params['ascending'] = false //ordered by the oldest statement recorded
|
|
160
163
|
|
|
161
164
|
let date = new Date()
|
|
162
165
|
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.
|
|
163
|
-
params['until'] = dd
|
|
166
|
+
// params['until'] = dd
|
|
167
|
+
params['until'] = 'now'
|
|
164
168
|
|
|
165
169
|
try {
|
|
166
170
|
let userData //placeholder for user data
|
|
@@ -172,6 +176,7 @@ export default class ADL {
|
|
|
172
176
|
completedStmts.statements.length
|
|
173
177
|
) {
|
|
174
178
|
let lastRecord = completedStmts.statements.toReversed()[0] // get last recorded statement
|
|
179
|
+
// let lastRecord = completedStmts.statements[0] // get last recorded statement
|
|
175
180
|
|
|
176
181
|
// Verify that the extensions value of the statement as elements
|
|
177
182
|
if (
|
|
@@ -419,102 +424,86 @@ export default class ADL {
|
|
|
419
424
|
let { email, verb, activityId } = param
|
|
420
425
|
let vb = verb && validVerbs.includes(verb) ? verb : 'terminated'
|
|
421
426
|
const params = {}
|
|
422
|
-
|
|
423
427
|
params['verb'] = this.verbs[vb].id // completed state
|
|
424
428
|
params['activity'] = activityId // this current activity define by this id
|
|
425
429
|
params['agent'] = `{"mbox": "mailto:${email}"}` // the user identify by this email
|
|
426
|
-
params['ascending'] =
|
|
427
|
-
params['limit'] =
|
|
430
|
+
params['ascending'] = false //ordered by the most recent statement recorded
|
|
431
|
+
params['limit'] = 1 //limit of record to return by the LRS
|
|
428
432
|
|
|
429
433
|
params['until'] = dd
|
|
430
434
|
paramList.push(params)
|
|
431
435
|
}
|
|
432
|
-
const { response } = await this.XAPIWrapper.getStatements(paramList)
|
|
433
|
-
|
|
434
436
|
let userData = {},
|
|
435
|
-
playbarValues = {},
|
|
436
437
|
preferredSettings = {},
|
|
437
|
-
lessonStatus = {}
|
|
438
|
-
savedPoint = ''
|
|
438
|
+
lessonStatus = {}
|
|
439
439
|
|
|
440
|
-
|
|
441
|
-
for (const res of response) {
|
|
442
|
-
const { statements } = await res.json()
|
|
443
|
-
if (!statements || statements.length == 0) continue
|
|
440
|
+
let { response } = await this.XAPIWrapper.getStatements(paramList)
|
|
444
441
|
|
|
445
|
-
|
|
446
|
-
|
|
442
|
+
if (!response || response.length == 0)
|
|
443
|
+
response = {
|
|
444
|
+
userData,
|
|
445
|
+
preferredSettings,
|
|
446
|
+
lessonStatus
|
|
447
|
+
}
|
|
447
448
|
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
}
|
|
449
|
+
const jsons = await Promise.all(
|
|
450
|
+
response.map((r) => r.json().catch(() => ({})))
|
|
451
|
+
)
|
|
452
452
|
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
453
|
+
for (const data of jsons) {
|
|
454
|
+
const { statements } = data
|
|
455
|
+
if (!statements || statements.length == 0) continue
|
|
456
|
+
let lastRecord = statements[0] // get last recorded statement
|
|
457
|
+
// Verify that the extensions value of the statement has elements
|
|
458
|
+
//Handeling Lession comppletion status
|
|
459
|
+
if (lastRecord.verb.id.includes('completed')) {
|
|
460
|
+
lessonStatus = lastRecord.result ? lastRecord.result : {}
|
|
461
|
+
}
|
|
460
462
|
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
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
|
-
}
|
|
463
|
+
if (
|
|
464
|
+
lastRecord.object.definition.extensions &&
|
|
465
|
+
Object.keys(lastRecord.object.definition.extensions).length
|
|
466
|
+
) {
|
|
467
|
+
const allExtensionsKeys = Object.keys(
|
|
468
|
+
lastRecord.object.definition.extensions
|
|
469
|
+
)
|
|
470
|
+
|
|
471
|
+
//Search for the user-data entry in the extensions
|
|
472
|
+
allExtensionsKeys.forEach((extension) => {
|
|
473
|
+
switch (true) {
|
|
474
|
+
case extension.includes('user-data'): {
|
|
475
|
+
//Search for the user-data entry in the extensions
|
|
476
|
+
const userDataExtension = allExtensionsKeys.filter((extension) =>
|
|
477
|
+
extension.includes('user-data')
|
|
478
|
+
)
|
|
479
|
+
userData =
|
|
480
|
+
lastRecord.object.definition.extensions[userDataExtension[0]]
|
|
481
|
+
break
|
|
506
482
|
}
|
|
507
|
-
|
|
508
|
-
|
|
483
|
+
case extension.includes('application-settings'): {
|
|
484
|
+
const userDataExtension = allExtensionsKeys.filter((extension) =>
|
|
485
|
+
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
|
+
default: {
|
|
496
|
+
return
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
})
|
|
509
500
|
}
|
|
510
501
|
}
|
|
511
502
|
|
|
512
503
|
return {
|
|
513
504
|
userData,
|
|
514
|
-
|
|
515
|
-
preferredSettings
|
|
516
|
-
playbarValues,
|
|
517
|
-
lessonStatus
|
|
505
|
+
lessonStatus,
|
|
506
|
+
preferredSettings
|
|
518
507
|
}
|
|
519
508
|
}
|
|
520
509
|
}
|
|
@@ -5,7 +5,6 @@ const allfile = import.meta.glob(['@/**/*.vue', '!@/**/_*'], {
|
|
|
5
5
|
|
|
6
6
|
const allfileKeys = Object.keys(allfile)
|
|
7
7
|
|
|
8
|
-
//console.log('ALL PATHS', fileArray)
|
|
9
8
|
allfileKeys.forEach(function (key, index, array) {
|
|
10
9
|
array[index] = {
|
|
11
10
|
name: key.replace('/src', '.').replace('.vue', ''),
|