fcad-core-dragon 2.0.0-beta.1 → 2.0.0-beta.10
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 +6 -31
- package/.prettierrc +11 -0
- package/.vscode/extensions.json +8 -0
- package/.vscode/settings.json +16 -0
- package/CHANGELOG +153 -0
- package/README.md +28 -43
- package/documentation/.vitepress/config.js +114 -0
- package/documentation/api-examples.md +49 -0
- package/documentation/composants/app-base-button.md +58 -0
- package/documentation/composants/app-base-error-display.md +59 -0
- package/documentation/composants/app-base-popover.md +68 -0
- package/documentation/composants/app-comp-audio.md +75 -0
- package/documentation/composants/app-comp-branch-buttons.md +111 -0
- package/documentation/composants/app-comp-button-progress.md +53 -0
- package/documentation/composants/app-comp-carousel.md +53 -0
- package/documentation/composants/app-comp-container.md +53 -0
- package/documentation/composants/app-comp-input-checkbox-next.md +42 -0
- package/documentation/composants/app-comp-input-dropdown-next.md +34 -0
- package/documentation/composants/app-comp-input-radio-next.md +39 -0
- package/documentation/composants/app-comp-input-text-next.md +35 -0
- package/documentation/composants/app-comp-input-text-table-next.md +34 -0
- package/documentation/composants/app-comp-input-text-to-fill-dropdown-next.md +53 -0
- package/documentation/composants/app-comp-input-text-to-fill-next.md +31 -0
- package/documentation/composants/app-comp-jauge.md +31 -0
- package/documentation/composants/app-comp-menu-item.md +55 -0
- package/documentation/composants/app-comp-menu.md +29 -0
- package/documentation/composants/app-comp-navigation.md +41 -0
- package/documentation/composants/app-comp-note-call.md +53 -0
- package/documentation/composants/app-comp-note-credit.md +53 -0
- package/documentation/composants/app-comp-play-bar-next.md +53 -0
- package/documentation/composants/app-comp-pop-up-next.md +93 -0
- package/documentation/composants/app-comp-quiz-next.md +235 -0
- package/documentation/composants/app-comp-quiz-recall.md +53 -0
- package/documentation/composants/app-comp-svg-next.md +53 -0
- package/documentation/composants/app-comp-table-of-content.md +50 -0
- package/documentation/composants/app-comp-video-player.md +82 -0
- package/documentation/composants.md +46 -0
- package/documentation/composants_critiques/ModelPageComposant.md +53 -0
- package/documentation/composants_critiques/app-base-module.md +43 -0
- package/documentation/composants_critiques/app-base-page.md +48 -0
- package/documentation/composants_critiques/app-base.md +311 -0
- package/documentation/composants_critiques/main.md +15 -0
- package/documentation/demarrage.md +50 -0
- package/documentation/deploiement.md +58 -0
- package/documentation/index.md +33 -0
- package/documentation/markdown-examples.md +85 -0
- package/documentation/public/npm_version.png +0 -0
- package/documentation/public/vite.svg +15 -0
- package/documentation/public/vuejs.svg +2 -0
- package/documentation/public/vuetify.svg +6 -0
- package/eslint.config.js +60 -0
- package/package.json +43 -47
- package/src/$locales/en.json +86 -108
- package/src/$locales/fr.json +66 -127
- package/src/assets/data/onboardingMessages.json +1 -1
- package/src/components/AppBase.vue +960 -405
- package/src/components/AppBaseButton.test.js +21 -0
- package/src/components/AppBaseButton.vue +42 -10
- package/src/components/AppBaseErrorDisplay.vue +207 -189
- package/src/components/AppBaseFlipCard.vue +1 -0
- package/src/components/AppBaseModule.vue +769 -977
- package/src/components/AppBasePage.vue +635 -81
- package/src/components/AppBasePopover.vue +41 -0
- package/src/components/AppBaseSkeleton.vue +66 -0
- package/src/components/AppCompAudio.vue +256 -0
- package/src/components/AppCompBranchButtons.vue +79 -153
- package/src/components/AppCompButtonProgress.vue +21 -36
- package/src/components/AppCompCarousel.vue +231 -87
- package/src/components/{AppCompTranscript.vue → AppCompContainer.vue} +12 -2
- package/src/components/AppCompInputCheckBoxNx.vue +323 -0
- package/src/components/AppCompInputDropdownNx.vue +299 -0
- package/src/components/AppCompInputRadioNx.vue +284 -0
- package/src/components/AppCompInputTextNx.vue +153 -0
- package/src/components/AppCompInputTextTableNx.vue +202 -0
- package/src/components/AppCompInputTextToFillDropdownNx.vue +340 -0
- package/src/components/AppCompInputTextToFillNx.vue +313 -0
- package/src/components/AppCompJauge.vue +36 -10
- package/src/components/AppCompMenu.vue +246 -32
- package/src/components/AppCompMenuItem.vue +87 -21
- package/src/components/AppCompNavigation.vue +470 -447
- package/src/components/AppCompNoteCall.vue +93 -58
- package/src/components/AppCompNoteCredit.vue +423 -96
- package/src/components/AppCompPlayBarNext.vue +2288 -0
- package/src/components/AppCompPopUpNext.vue +504 -0
- package/src/components/AppCompQuizNext.vue +510 -0
- package/src/components/AppCompQuizRecall.vue +199 -99
- package/src/components/AppCompSVGNext.vue +346 -0
- package/src/components/AppCompSettingsMenu.vue +17 -16
- package/src/components/AppCompTableOfContent.vue +262 -99
- package/src/components/AppCompVideoPlayer.vue +183 -142
- package/src/components/BaseModule.vue +8 -20
- package/src/components/tests__/AppBaseButton.spec.js +53 -0
- package/src/components/tests__/useTimer.spec.js +91 -0
- package/src/composables/useIdleDetector.js +56 -0
- package/src/composables/useQuiz.js +89 -0
- package/src/composables/useTimer.js +172 -0
- package/src/directives/nvdaFix.js +53 -0
- package/src/externalComps/ModuleView.vue +22 -0
- package/src/externalComps/SummaryView.vue +91 -0
- package/src/main.js +397 -148
- package/src/module/stores/appStore.js +947 -0
- package/src/module/xapi/ADL.js +241 -60
- package/src/module/xapi/Crypto/Hasher.js +8 -8
- package/src/module/xapi/Crypto/WordArray.js +6 -6
- package/src/module/xapi/Crypto/algorithms/BufferedBlockAlgorithm.js +4 -4
- package/src/module/xapi/Crypto/algorithms/C_algo.js +14 -18
- package/src/module/xapi/Crypto/algorithms/HMAC.js +1 -1
- package/src/module/xapi/Crypto/algorithms/SHA1.js +1 -1
- package/src/module/xapi/Crypto/encoders/Base.js +7 -7
- package/src/module/xapi/Crypto/encoders/Base64.js +3 -3
- package/src/module/xapi/Crypto/encoders/Hex.js +2 -2
- package/src/module/xapi/Crypto/encoders/Latin1.js +3 -3
- package/src/module/xapi/Crypto/encoders/Utf8.js +3 -3
- package/src/module/xapi/Statement/index.js +3 -3
- package/src/module/xapi/launch.js +10 -10
- package/src/module/xapi/utils.js +17 -17
- package/src/module/xapi/wrapper.js +219 -214
- package/src/module/xapi/xapiStatement.js +29 -29
- package/src/plugins/analytics.js +34 -0
- package/src/plugins/bus.js +7 -2
- package/src/plugins/gsap.js +5 -7
- package/src/plugins/helper.js +97 -34
- package/src/plugins/i18n.js +13 -18
- package/src/plugins/idb.js +45 -30
- package/src/plugins/save.js +1 -1
- package/src/plugins/scorm.js +15 -15
- package/src/plugins/xapi.js +2 -2
- package/src/public/index.html +22 -10
- package/src/router/index.js +29 -13
- package/src/router/routes.js +29 -54
- package/src/shared/generalfuncs.js +186 -30
- package/src/shared/validators.js +809 -40
- package/vitest.config.js +19 -0
- package/.eslintignore +0 -29
- package/.eslintrc.js +0 -86
- package/.prettierrc.js +0 -5
- package/babel.config.js +0 -3
- package/src/components/AppBaseDragChoice.vue +0 -91
- package/src/components/AppBaseDropZone.vue +0 -112
- package/src/components/AppCompBif.vue +0 -120
- package/src/components/AppCompDragAndDrop.vue +0 -339
- package/src/components/AppCompInputAssociation.vue +0 -332
- package/src/components/AppCompInputCheckBox.vue +0 -227
- package/src/components/AppCompInputDropdown.vue +0 -184
- package/src/components/AppCompInputRadio.vue +0 -169
- package/src/components/AppCompInputTextBox.vue +0 -91
- package/src/components/AppCompInputTextTable.vue +0 -155
- package/src/components/AppCompInputTextToFillDropdown.vue +0 -255
- package/src/components/AppCompInputTextToFillText.vue +0 -164
- package/src/components/AppCompMediaPlayer.vue +0 -397
- package/src/components/AppCompPlayBar.vue +0 -1319
- package/src/components/AppCompPopUp.vue +0 -522
- package/src/components/AppCompPopover.vue +0 -27
- package/src/components/AppCompQuiz.vue +0 -2989
- package/src/components/AppCompSVG.vue +0 -309
- package/src/mixins/$pageMixins.js +0 -459
- package/src/mixins/$quizMixins.js +0 -456
- package/src/mixins/timerMixin.js +0 -156
- package/src/module/store.js +0 -895
- package/src/plugins/timeManager.js +0 -77
- package/src/routes_bckp.js +0 -313
- package/src/routes_static.js +0 -344
- package/vue.config.js +0 -83
package/src/module/xapi/ADL.js
CHANGED
|
@@ -41,7 +41,7 @@ export default class ADL {
|
|
|
41
41
|
let res = null
|
|
42
42
|
const withResult =
|
|
43
43
|
statement.verb.id.includes('answered') ||
|
|
44
|
-
statement.verb.id.includes('
|
|
44
|
+
statement.verb.id.includes('suspended') ||
|
|
45
45
|
statement.verb.id.includes('completed')
|
|
46
46
|
|
|
47
47
|
if (statement.result && !withResult) {
|
|
@@ -56,11 +56,45 @@ export default class ADL {
|
|
|
56
56
|
|
|
57
57
|
if (withFetch) this.XAPIWrapper.sendStatementWithFetch(statement)
|
|
58
58
|
else {
|
|
59
|
-
this.XAPIWrapper.sendStatement(statement, function(response) {
|
|
59
|
+
this.XAPIWrapper.sendStatement(statement, function (response) {
|
|
60
60
|
if (cb) cb()
|
|
61
61
|
res = response
|
|
62
62
|
})
|
|
63
|
+
return res
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/*
|
|
68
|
+
* Helper function to Dispatch statement to the LRS
|
|
69
|
+
* @params: Statement {Object}:xapi Statement
|
|
70
|
+
*/
|
|
71
|
+
_sendStatements(statements, cb, withFetch = false) {
|
|
72
|
+
//remove the statement Result if it not answer action.
|
|
73
|
+
let res = null
|
|
74
|
+
statements.forEach((statement) => {
|
|
75
|
+
const withResult =
|
|
76
|
+
statement.verb.id.includes('answered') ||
|
|
77
|
+
statement.verb.id.includes('played') ||
|
|
78
|
+
statement.verb.id.includes('suspended') ||
|
|
79
|
+
statement.verb.id.includes('completed')
|
|
80
|
+
|
|
81
|
+
if (statement.result && !withResult) {
|
|
82
|
+
delete statement.result
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
//Clear existing id of the statement if any to allow xapi to generate new ID for the Statement.
|
|
86
|
+
if (statement.id) statement.id = ''
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
// Dispatch the statement to the LRS
|
|
90
|
+
if (!this.XAPIWrapper) return
|
|
63
91
|
|
|
92
|
+
if (withFetch) this.XAPIWrapper.sendStatementsWithFetch(statements)
|
|
93
|
+
else {
|
|
94
|
+
this.XAPIWrapper.sendStatements(statements, function (response) {
|
|
95
|
+
if (cb) cb()
|
|
96
|
+
res = response
|
|
97
|
+
})
|
|
64
98
|
return res
|
|
65
99
|
}
|
|
66
100
|
}
|
|
@@ -102,58 +136,66 @@ export default class ADL {
|
|
|
102
136
|
*
|
|
103
137
|
* @Params {String} email: user email
|
|
104
138
|
* @Params {String} activityId: the IRI string of the activity
|
|
105
|
-
* @Params {String} verb: the verb to search by completed |
|
|
139
|
+
* @Params {String} verb: the verb to search by completed | terminated
|
|
106
140
|
*/
|
|
107
|
-
|
|
141
|
+
|
|
142
|
+
async _getProgress(email, activityId, verb) {
|
|
108
143
|
let params
|
|
109
|
-
|
|
110
|
-
|
|
144
|
+
const validVerbs = [
|
|
145
|
+
'progressed',
|
|
146
|
+
'completed',
|
|
147
|
+
'suspended',
|
|
148
|
+
'terminated',
|
|
149
|
+
'exited'
|
|
150
|
+
]
|
|
111
151
|
if (this.XAPIWrapper) params = this.XAPIWrapper.searchParams()
|
|
112
152
|
|
|
113
|
-
verb && validVerbs.includes(verb) ?
|
|
153
|
+
let vb = verb && validVerbs.includes(verb) ? verb : 'terminated'
|
|
114
154
|
|
|
115
155
|
params['verb'] = this.verbs[vb].id // completed state
|
|
116
156
|
params['activity'] = activityId // this current activity define by this id
|
|
117
157
|
params['agent'] = `{"mbox": "mailto:${email}"}` // the user identify by this email
|
|
118
|
-
params['limit'] =
|
|
158
|
+
params['limit'] = 200 //limit of record to return by the LRS
|
|
119
159
|
params['ascending'] = true //ordered by the oldest statement recorded
|
|
120
160
|
|
|
121
161
|
let date = new Date()
|
|
122
162
|
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.
|
|
123
|
-
|
|
124
163
|
params['until'] = dd
|
|
125
164
|
|
|
126
|
-
|
|
127
|
-
|
|
165
|
+
try {
|
|
166
|
+
let userData //placeholder for user data
|
|
167
|
+
let completedStmts = await this.XAPIWrapper.getStatements(params)
|
|
128
168
|
|
|
129
|
-
if (
|
|
130
|
-
completedStmts &&
|
|
131
|
-
completedStmts.statements &&
|
|
132
|
-
completedStmts.statements.length
|
|
133
|
-
) {
|
|
134
|
-
let length = completedStmts.statements.length
|
|
135
|
-
let lastRecord = completedStmts.statements[length - 1] // get last recorded statement
|
|
136
|
-
// Verify that the extensions value of the statement as elements
|
|
137
169
|
if (
|
|
138
|
-
|
|
139
|
-
|
|
170
|
+
completedStmts &&
|
|
171
|
+
completedStmts.statements &&
|
|
172
|
+
completedStmts.statements.length
|
|
140
173
|
) {
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
174
|
+
let lastRecord = completedStmts.statements.toReversed()[0] // get last recorded statement
|
|
175
|
+
|
|
176
|
+
// Verify that the extensions value of the statement as elements
|
|
177
|
+
if (
|
|
178
|
+
lastRecord.object.definition.extensions &&
|
|
179
|
+
Object.keys(lastRecord.object.definition.extensions).length
|
|
180
|
+
) {
|
|
181
|
+
const allExtensionsKeys = Object.keys(
|
|
182
|
+
lastRecord.object.definition.extensions
|
|
183
|
+
)
|
|
184
|
+
|
|
185
|
+
//Search for the user-data entry in the extensions
|
|
186
|
+
const userDataExtension = allExtensionsKeys.filter((extension) =>
|
|
187
|
+
extension.includes('user-data')
|
|
188
|
+
)
|
|
189
|
+
userData =
|
|
190
|
+
lastRecord.object.definition.extensions[userDataExtension[0]]
|
|
191
|
+
}
|
|
192
|
+
} else {
|
|
193
|
+
userData = {}
|
|
151
194
|
}
|
|
152
195
|
return userData
|
|
153
|
-
}
|
|
154
|
-
|
|
196
|
+
} catch (err) {
|
|
197
|
+
console.log(err)
|
|
155
198
|
}
|
|
156
|
-
return userData
|
|
157
199
|
}
|
|
158
200
|
|
|
159
201
|
/*@Description: Helper to The Lesson Status (result) -
|
|
@@ -161,24 +203,24 @@ export default class ADL {
|
|
|
161
203
|
* @Params {String} email: user email
|
|
162
204
|
* @Params {String} activityId: the IRI string of the activity
|
|
163
205
|
*/
|
|
164
|
-
_getLessonStatus(email, activityId) {
|
|
206
|
+
async _getLessonStatus(email, activityId, verb) {
|
|
165
207
|
let params
|
|
208
|
+
const validVerbs = ['completed', 'suspended']
|
|
166
209
|
if (this.XAPIWrapper) params = this.XAPIWrapper.searchParams()
|
|
167
|
-
|
|
168
|
-
params['verb'] = this.verbs.
|
|
210
|
+
let vb = verb && validVerbs.includes(verb) ? verb : 'suspended'
|
|
211
|
+
params['verb'] = this.verbs[vb].id // completed state
|
|
169
212
|
params['activity'] = activityId // this current activity define by this id
|
|
170
213
|
params['agent'] = `{"mbox": "mailto:${email}"}` // the user identify by this email
|
|
171
214
|
params['ascending'] = true //ordered by the oldest statement recorded
|
|
172
215
|
|
|
173
|
-
let completedStmts = this.XAPIWrapper.getStatements(params)
|
|
216
|
+
let completedStmts = await this.XAPIWrapper.getStatements(params)
|
|
174
217
|
let status //placeholder for user data
|
|
175
218
|
if (
|
|
176
219
|
completedStmts &&
|
|
177
220
|
completedStmts.statements &&
|
|
178
221
|
completedStmts.statements.length
|
|
179
222
|
) {
|
|
180
|
-
let
|
|
181
|
-
let lastRecord = completedStmts.statements[length - 1] // get last recorded statement
|
|
223
|
+
let lastRecord = completedStmts.statements.toReversed()[0] // get last recorded statement
|
|
182
224
|
|
|
183
225
|
// Verify that result exist
|
|
184
226
|
if (lastRecord.result) status = lastRecord.result
|
|
@@ -195,32 +237,32 @@ export default class ADL {
|
|
|
195
237
|
* @Params {String} activityId: the IRI string of the activity
|
|
196
238
|
*/
|
|
197
239
|
|
|
198
|
-
_getLessonPosition(email, activityId) {
|
|
240
|
+
async _getLessonPosition(email, activityId) {
|
|
199
241
|
let params
|
|
200
242
|
let savedPoint = []
|
|
201
243
|
if (this.XAPIWrapper) params = this.XAPIWrapper.searchParams()
|
|
202
244
|
|
|
203
|
-
params['verb'] = this.verbs.
|
|
245
|
+
params['verb'] = this.verbs.terminated.id // completed state
|
|
204
246
|
params['activity'] = activityId // this current activity define by this id
|
|
205
247
|
params['agent'] = `{"mbox": "mailto:${email}"}` // the user identify by this email
|
|
206
248
|
params['ascending'] = true //ordered by the oldest statement recorded
|
|
207
|
-
params['limit'] =
|
|
249
|
+
params['limit'] = 200 //limit of record to return by the LRS
|
|
208
250
|
|
|
209
251
|
let date = new Date()
|
|
210
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.
|
|
211
253
|
|
|
212
254
|
params['until'] = dd
|
|
213
255
|
|
|
214
|
-
let progressedStmts = this.XAPIWrapper.getStatements(params)
|
|
256
|
+
let progressedStmts = await this.XAPIWrapper.getStatements(params)
|
|
215
257
|
|
|
216
258
|
if (
|
|
217
259
|
progressedStmts &&
|
|
218
260
|
progressedStmts.statements &&
|
|
219
261
|
progressedStmts.statements.length
|
|
220
262
|
) {
|
|
221
|
-
let
|
|
222
|
-
let lastRecord = progressedStmts.statements[length - 1] // get last recorded statement
|
|
263
|
+
let lastRecord = progressedStmts.statements.toReversed()[0] // get last recorded statement
|
|
223
264
|
// Verify that the extensions value of the statement has elements
|
|
265
|
+
|
|
224
266
|
if (
|
|
225
267
|
lastRecord.object.definition.extensions &&
|
|
226
268
|
Object.keys(lastRecord.object.definition.extensions).length
|
|
@@ -228,6 +270,7 @@ export default class ADL {
|
|
|
228
270
|
const allExtensionsKeys = Object.keys(
|
|
229
271
|
lastRecord.object.definition.extensions
|
|
230
272
|
)
|
|
273
|
+
|
|
231
274
|
//Search for the user-data entry in the extensions
|
|
232
275
|
savedPoint = allExtensionsKeys.map((extension) => {
|
|
233
276
|
if (extension.includes('ending-point'))
|
|
@@ -235,7 +278,8 @@ export default class ADL {
|
|
|
235
278
|
})
|
|
236
279
|
}
|
|
237
280
|
}
|
|
238
|
-
|
|
281
|
+
|
|
282
|
+
return savedPoint && savedPoint.length > 0 ? savedPoint[0] : ''
|
|
239
283
|
}
|
|
240
284
|
|
|
241
285
|
/* @description: Helper to get the Preferred Settings of the user
|
|
@@ -244,7 +288,7 @@ export default class ADL {
|
|
|
244
288
|
* @Params {String} activityId: the IRI string of the activity
|
|
245
289
|
*/
|
|
246
290
|
|
|
247
|
-
_getPreferredSettings(email, activityId) {
|
|
291
|
+
async _getPreferredSettings(email, activityId) {
|
|
248
292
|
let params
|
|
249
293
|
let preferredSettings = []
|
|
250
294
|
if (this.XAPIWrapper) params = this.XAPIWrapper.searchParams()
|
|
@@ -253,22 +297,21 @@ export default class ADL {
|
|
|
253
297
|
params['activity'] = activityId // this current activity define by this id
|
|
254
298
|
params['agent'] = `{"mbox": "mailto:${email}"}` // the user identify by this email
|
|
255
299
|
params['ascending'] = true //ordered by the oldest statement recorded
|
|
256
|
-
params['limit'] =
|
|
300
|
+
params['limit'] = 200 //limit of record to return by the LRS
|
|
257
301
|
|
|
258
302
|
let date = new Date()
|
|
259
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.
|
|
260
304
|
|
|
261
305
|
params['until'] = dd
|
|
262
306
|
|
|
263
|
-
let preferredStmts = this.XAPIWrapper.getStatements(params)
|
|
307
|
+
let preferredStmts = await this.XAPIWrapper.getStatements(params)
|
|
264
308
|
|
|
265
309
|
if (
|
|
266
310
|
preferredStmts &&
|
|
267
311
|
preferredStmts.statements &&
|
|
268
312
|
preferredStmts.statements.length
|
|
269
313
|
) {
|
|
270
|
-
let
|
|
271
|
-
let lastRecord = preferredStmts.statements[length - 1] // get last recorded statement
|
|
314
|
+
let lastRecord = preferredStmts.statements.toReversed()[0] // get last recorded statement
|
|
272
315
|
|
|
273
316
|
// Verify that the extensions value of the statement has elements
|
|
274
317
|
if (
|
|
@@ -278,6 +321,7 @@ export default class ADL {
|
|
|
278
321
|
const allExtensionsKeys = Object.keys(
|
|
279
322
|
lastRecord.object.definition.extensions
|
|
280
323
|
)
|
|
324
|
+
|
|
281
325
|
//Search for the user-data entry in the extensions
|
|
282
326
|
preferredSettings = allExtensionsKeys.map((extension) => {
|
|
283
327
|
if (extension.includes('application-settings'))
|
|
@@ -285,7 +329,7 @@ export default class ADL {
|
|
|
285
329
|
})
|
|
286
330
|
}
|
|
287
331
|
}
|
|
288
|
-
return preferredSettings
|
|
332
|
+
return preferredSettings[0] ? preferredSettings[0] : {}
|
|
289
333
|
}
|
|
290
334
|
|
|
291
335
|
/* @description: Helper to get the Playbar values of the user
|
|
@@ -293,7 +337,7 @@ export default class ADL {
|
|
|
293
337
|
* @Params {String} activityId: the IRI string of the activity
|
|
294
338
|
*/
|
|
295
339
|
|
|
296
|
-
_getPlaybarValues(email, activityId) {
|
|
340
|
+
async _getPlaybarValues(email, activityId) {
|
|
297
341
|
let params
|
|
298
342
|
let playbarValues = []
|
|
299
343
|
if (this.XAPIWrapper) params = this.XAPIWrapper.searchParams()
|
|
@@ -302,23 +346,21 @@ export default class ADL {
|
|
|
302
346
|
params['activity'] = activityId // this current activity define by this id
|
|
303
347
|
params['agent'] = `{"mbox": "mailto:${email}"}` // the user identify by this email
|
|
304
348
|
params['ascending'] = true //ordered by the oldest statement recorded
|
|
305
|
-
params['limit'] =
|
|
349
|
+
params['limit'] = 200 //limit of record to return by the LRS
|
|
306
350
|
|
|
307
351
|
let date = new Date()
|
|
308
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.
|
|
309
353
|
|
|
310
354
|
params['until'] = dd
|
|
311
355
|
|
|
312
|
-
let playedStmts = this.XAPIWrapper.getStatements(params)
|
|
356
|
+
let playedStmts = await this.XAPIWrapper.getStatements(params)
|
|
313
357
|
|
|
314
358
|
if (
|
|
315
359
|
playedStmts &&
|
|
316
360
|
playedStmts.statements &&
|
|
317
361
|
playedStmts.statements.length
|
|
318
362
|
) {
|
|
319
|
-
let
|
|
320
|
-
let lastRecord = playedStmts.statements[length - 1] // get last recorded statement
|
|
321
|
-
|
|
363
|
+
let lastRecord = playedStmts.statements.toReversed()[0] // get last recorded statement
|
|
322
364
|
// Verify that the extensions value of the statement has elements
|
|
323
365
|
if (
|
|
324
366
|
lastRecord.object.definition.extensions &&
|
|
@@ -334,6 +376,145 @@ export default class ADL {
|
|
|
334
376
|
})
|
|
335
377
|
}
|
|
336
378
|
}
|
|
337
|
-
return playbarValues
|
|
379
|
+
return playbarValues[0] ? playbarValues[0] : {}
|
|
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
|
+
}
|
|
338
519
|
}
|
|
339
520
|
}
|
|
@@ -21,7 +21,7 @@ export const Hasher = BufferedBlockAlgorithm.extend({
|
|
|
21
21
|
*
|
|
22
22
|
* var hasher = CryptoJS.algo.SHA256.create();
|
|
23
23
|
*/
|
|
24
|
-
init: function(cfg) {
|
|
24
|
+
init: function (cfg) {
|
|
25
25
|
// Apply config defaults
|
|
26
26
|
this.cfg = this.cfg.extend(cfg)
|
|
27
27
|
|
|
@@ -36,7 +36,7 @@ export const Hasher = BufferedBlockAlgorithm.extend({
|
|
|
36
36
|
*
|
|
37
37
|
* hasher.reset();
|
|
38
38
|
*/
|
|
39
|
-
reset: function() {
|
|
39
|
+
reset: function () {
|
|
40
40
|
// Reset data buffer
|
|
41
41
|
BufferedBlockAlgorithm.reset.call(this)
|
|
42
42
|
|
|
@@ -56,7 +56,7 @@ export const Hasher = BufferedBlockAlgorithm.extend({
|
|
|
56
56
|
* hasher.update('message');
|
|
57
57
|
* hasher.update(wordArray);
|
|
58
58
|
*/
|
|
59
|
-
update: function(messageUpdate) {
|
|
59
|
+
update: function (messageUpdate) {
|
|
60
60
|
// Append
|
|
61
61
|
this._append(messageUpdate)
|
|
62
62
|
|
|
@@ -81,7 +81,7 @@ export const Hasher = BufferedBlockAlgorithm.extend({
|
|
|
81
81
|
* var hash = hasher.finalize('message');
|
|
82
82
|
* var hash = hasher.finalize(wordArray);
|
|
83
83
|
*/
|
|
84
|
-
finalize: function(messageUpdate) {
|
|
84
|
+
finalize: function (messageUpdate) {
|
|
85
85
|
// Final message update
|
|
86
86
|
if (messageUpdate) {
|
|
87
87
|
this._append(messageUpdate)
|
|
@@ -108,8 +108,8 @@ export const Hasher = BufferedBlockAlgorithm.extend({
|
|
|
108
108
|
*
|
|
109
109
|
* var SHA256 = CryptoJS.lib.Hasher._createHelper(CryptoJS.algo.SHA256);
|
|
110
110
|
*/
|
|
111
|
-
_createHelper: function(hasher) {
|
|
112
|
-
return function(message, cfg) {
|
|
111
|
+
_createHelper: function (hasher) {
|
|
112
|
+
return function (message, cfg) {
|
|
113
113
|
return new hasher.init(cfg).finalize(message)
|
|
114
114
|
}
|
|
115
115
|
},
|
|
@@ -127,8 +127,8 @@ export const Hasher = BufferedBlockAlgorithm.extend({
|
|
|
127
127
|
*
|
|
128
128
|
* var HmacSHA256 = CryptoJS.lib.Hasher._createHmacHelper(CryptoJS.algo.SHA256);
|
|
129
129
|
*/
|
|
130
|
-
_createHmacHelper: function(hasher) {
|
|
131
|
-
return function(message, key) {
|
|
130
|
+
_createHmacHelper: function (hasher) {
|
|
131
|
+
return function (message, key) {
|
|
132
132
|
return new C_algo().HMAC.init(hasher, key).finalize(message)
|
|
133
133
|
}
|
|
134
134
|
}
|
|
@@ -19,7 +19,7 @@ export const WordArray = Base.extend({
|
|
|
19
19
|
* let wordArray = CryptoJS.lib.WordArray.create([0x00010203, 0x04050607]);
|
|
20
20
|
* let wordArray = CryptoJS.lib.WordArray.create([0x00010203, 0x04050607], 6);
|
|
21
21
|
*/
|
|
22
|
-
init: function(words, sigBytes) {
|
|
22
|
+
init: function (words, sigBytes) {
|
|
23
23
|
words = this.words = words || []
|
|
24
24
|
|
|
25
25
|
if (sigBytes != undefined) {
|
|
@@ -42,7 +42,7 @@ export const WordArray = Base.extend({
|
|
|
42
42
|
* let string = wordArray.toString();
|
|
43
43
|
* let string = wordArray.toString(CryptoJS.enc.Utf8);
|
|
44
44
|
*/
|
|
45
|
-
toString: function(encoder) {
|
|
45
|
+
toString: function (encoder) {
|
|
46
46
|
return (encoder || Hex).stringify(this)
|
|
47
47
|
},
|
|
48
48
|
|
|
@@ -57,7 +57,7 @@ export const WordArray = Base.extend({
|
|
|
57
57
|
*
|
|
58
58
|
* wordArray1.concat(wordArray2);
|
|
59
59
|
*/
|
|
60
|
-
concat: function(wordArray) {
|
|
60
|
+
concat: function (wordArray) {
|
|
61
61
|
// Shortcuts
|
|
62
62
|
let thisWords = this.words
|
|
63
63
|
let thatWords = wordArray.words
|
|
@@ -97,7 +97,7 @@ export const WordArray = Base.extend({
|
|
|
97
97
|
*
|
|
98
98
|
* wordArray.clamp();
|
|
99
99
|
*/
|
|
100
|
-
clamp: function() {
|
|
100
|
+
clamp: function () {
|
|
101
101
|
// Shortcuts
|
|
102
102
|
let words = this.words
|
|
103
103
|
let sigBytes = this.sigBytes
|
|
@@ -116,7 +116,7 @@ export const WordArray = Base.extend({
|
|
|
116
116
|
*
|
|
117
117
|
* let clone = wordArray.clone();
|
|
118
118
|
*/
|
|
119
|
-
clone: function() {
|
|
119
|
+
clone: function () {
|
|
120
120
|
let clone = Base.clone.call(this)
|
|
121
121
|
clone.words = this.words.slice(0)
|
|
122
122
|
|
|
@@ -136,7 +136,7 @@ export const WordArray = Base.extend({
|
|
|
136
136
|
*
|
|
137
137
|
* let wordArray = CryptoJS.lib.WordArray.random(16);
|
|
138
138
|
*/
|
|
139
|
-
random: function(nBytes) {
|
|
139
|
+
random: function (nBytes) {
|
|
140
140
|
let words = []
|
|
141
141
|
for (let i = 0; i < nBytes; i += 4) {
|
|
142
142
|
words.push((Math.random() * 0x100000000) | 0)
|
|
@@ -12,7 +12,7 @@ export const BufferedBlockAlgorithm = Base.extend({
|
|
|
12
12
|
* @example
|
|
13
13
|
* bufferedBlockAlgorithm.reset();
|
|
14
14
|
*/
|
|
15
|
-
reset: function() {
|
|
15
|
+
reset: function () {
|
|
16
16
|
// Initial values
|
|
17
17
|
this._data = new WordArray.init()
|
|
18
18
|
this._nDataBytes = 0
|
|
@@ -25,7 +25,7 @@ export const BufferedBlockAlgorithm = Base.extend({
|
|
|
25
25
|
* bufferedBlockAlgorithm._append('data');
|
|
26
26
|
* bufferedBlockAlgorithm._append(wordArray);
|
|
27
27
|
*/
|
|
28
|
-
_append: function(data) {
|
|
28
|
+
_append: function (data) {
|
|
29
29
|
// Convert string to WordArray, else assume WordArray already
|
|
30
30
|
if (typeof data == 'string') {
|
|
31
31
|
data = Utf8.parse(data)
|
|
@@ -46,7 +46,7 @@ export const BufferedBlockAlgorithm = Base.extend({
|
|
|
46
46
|
* var processedData = bufferedBlockAlgorithm._process();
|
|
47
47
|
* var processedData = bufferedBlockAlgorithm._process(!!'flush');
|
|
48
48
|
*/
|
|
49
|
-
_process: function(doFlush) {
|
|
49
|
+
_process: function (doFlush) {
|
|
50
50
|
// Shortcuts
|
|
51
51
|
var data = this._data
|
|
52
52
|
var dataWords = data.words
|
|
@@ -93,7 +93,7 @@ export const BufferedBlockAlgorithm = Base.extend({
|
|
|
93
93
|
* @example
|
|
94
94
|
* var clone = bufferedBlockAlgorithm.clone();
|
|
95
95
|
*/
|
|
96
|
-
clone: function() {
|
|
96
|
+
clone: function () {
|
|
97
97
|
var clone = Base.clone.call(this)
|
|
98
98
|
clone._data = this._data.clone()
|
|
99
99
|
return clone
|