fcad-core-dragon 2.0.2-beta.2 → 2.0.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 +5 -0
- package/bk.scss +117 -117
- package/package.json +1 -1
- package/src/assets/data/onboardingMessages.json +47 -47
- package/src/components/AppBaseErrorDisplay.vue +438 -438
- package/src/components/AppBaseFlipCard.vue +84 -84
- package/src/components/AppBasePopover.vue +41 -41
- package/src/components/AppCompPlayBarProgress.vue +82 -82
- package/src/components/AppCompSettingsMenu.vue +172 -172
- package/src/components/AppCompViewDisplay.vue +6 -6
- package/src/externalComps/ModuleView.vue +22 -22
- package/src/externalComps/SummaryView.vue +91 -91
- 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/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
|
@@ -1,444 +1,444 @@
|
|
|
1
|
-
import verbs from './verbs'
|
|
2
|
-
|
|
3
|
-
export function xapiStatement(ADL) {
|
|
4
|
-
function _getobj(obj, path) {
|
|
5
|
-
var parts = path.split('.')
|
|
6
|
-
|
|
7
|
-
var part = parts[0]
|
|
8
|
-
path = parts.slice(1).join('.')
|
|
9
|
-
|
|
10
|
-
if (!obj[part]) {
|
|
11
|
-
if (/\[\]$/.test(part)) {
|
|
12
|
-
part = part.slice(0, -2)
|
|
13
|
-
if (!Array.isArray(obj[part])) {
|
|
14
|
-
obj[part] = []
|
|
15
|
-
}
|
|
16
|
-
} else obj[part] = {}
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
if (!path) return obj[part]
|
|
20
|
-
else return _getobj(obj[part], path)
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
/*******************************************************************************
|
|
24
|
-
* XAPIStatement - a convenience class to wrap statement objects
|
|
25
|
-
*
|
|
26
|
-
* This sub-API is supposed to make it easier to author valid xAPI statements
|
|
27
|
-
* by adding constructors and encouraging best practices. All objects in this
|
|
28
|
-
* API are fully JSON-compatible, so anything expecting an xAPI statement can
|
|
29
|
-
* take an improved statement and vice versa.
|
|
30
|
-
*
|
|
31
|
-
* A working knowledge of what exactly the LRS expects is still expected,
|
|
32
|
-
* but it's easier to map an 'I did this' statement to xAPI now.
|
|
33
|
-
*
|
|
34
|
-
* Tech note: All constructors also double as shallow clone functions. E.g.
|
|
35
|
-
*
|
|
36
|
-
* var activity1 = new Activity('A walk in the park');
|
|
37
|
-
* var activity2 = new Activity(activity1);
|
|
38
|
-
* var activity3 = new Activity(stmt_from_lrs.object);
|
|
39
|
-
*
|
|
40
|
-
*******************************************************************************/
|
|
41
|
-
|
|
42
|
-
/*
|
|
43
|
-
* A convenient JSON-compatible xAPI statement wrapper
|
|
44
|
-
* All args are optional, but the statement may not be complete or valid
|
|
45
|
-
* Can also pass an Agent IFI, Verb ID, and an Activity ID in lieu of these args
|
|
46
|
-
* @param {string} [actor] The Agent or Group committing the action described by the statement
|
|
47
|
-
* @param {string} [verb] The Verb for the action described by the statement
|
|
48
|
-
* @param {string} [object] The receiver of the action. An Agent, Group, Activity, SubStatement, or StatementRef
|
|
49
|
-
* @example
|
|
50
|
-
* var stmt = new ADL.XAPIStatement(
|
|
51
|
-
* 'mailto:steve.vergenz.ctr@adlnet.gov',
|
|
52
|
-
* 'http://adlnet.gov/expapi/verbs/launched',
|
|
53
|
-
* 'http://vwf.adlnet.gov/xapi/virtual_world_sandbox'
|
|
54
|
-
* );
|
|
55
|
-
* >> {
|
|
56
|
-
* "actor": {
|
|
57
|
-
* "objectType": "Agent",
|
|
58
|
-
* "mbox": "mailto:steve.vergenz.ctr@adlnet.gov" },
|
|
59
|
-
* "verb": {
|
|
60
|
-
* "id": "http://adlnet.gov/expapi/verbs/launched" },
|
|
61
|
-
* "object": {
|
|
62
|
-
* "objectType": "Activity",
|
|
63
|
-
* "id": "http://vwf.adlnet.gov/xapi/virtual_world_sandbox" },
|
|
64
|
-
* "result": {
|
|
65
|
-
* "An optional property that represents a measured outcome related to the Statement in which it is included."}}
|
|
66
|
-
*/
|
|
67
|
-
var XAPIStatement = function (actor, verb, object, context, result) {
|
|
68
|
-
// initialize
|
|
69
|
-
|
|
70
|
-
// if first arg is an xapi statement, parse
|
|
71
|
-
if (actor && actor.actor && actor.verb && actor.object) {
|
|
72
|
-
var stmt = actor
|
|
73
|
-
for (var i in stmt) {
|
|
74
|
-
if (i != 'actor' && i != 'verb' && i != 'object') this[i] = stmt[i]
|
|
75
|
-
}
|
|
76
|
-
actor = stmt.actor
|
|
77
|
-
verb = stmt.verb
|
|
78
|
-
object = stmt.object
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
if (actor) {
|
|
82
|
-
if (actor instanceof Agent) this.actor = actor
|
|
83
|
-
else if (actor.objectType === 'Agent' || !actor.objectType)
|
|
84
|
-
this.actor = new Agent(actor)
|
|
85
|
-
else if (actor.objectType === 'Group') this.actor = new Group(actor)
|
|
86
|
-
} else this.actor = null
|
|
87
|
-
|
|
88
|
-
if (verb) {
|
|
89
|
-
this._setVerb(verb)
|
|
90
|
-
// if (verb instanceof Verb) this.verb = verb
|
|
91
|
-
// else this.verb = new Verb(verb)
|
|
92
|
-
} else this.verb = null
|
|
93
|
-
|
|
94
|
-
// decide what kind of object was passed
|
|
95
|
-
if (object) {
|
|
96
|
-
// if (object.objectType === 'Activity' || !object.objectType) {
|
|
97
|
-
// if (object instanceof Activity) this.object = object
|
|
98
|
-
// else this.object = new Activity(object)
|
|
99
|
-
// } else if (object.objectType === 'Agent') {
|
|
100
|
-
// if (object instanceof Agent) this.object = object
|
|
101
|
-
// else this.object = new Agent(object)
|
|
102
|
-
// } else if (object.objectType === 'Group') {
|
|
103
|
-
// if (object instanceof Group) this.object = object
|
|
104
|
-
// else this.object = new Group(object)
|
|
105
|
-
// } else if (object.objectType === 'StatementRef') {
|
|
106
|
-
// if (object instanceof StatementRef) this.object = object
|
|
107
|
-
// else this.object = new StatementRef(object)
|
|
108
|
-
// } else if (object.objectType === 'SubStatement') {
|
|
109
|
-
// if (object instanceof SubStatement) this.object = object
|
|
110
|
-
// else this.object = new SubStatement(object)
|
|
111
|
-
// } else this.object = null
|
|
112
|
-
this._setObject(object)
|
|
113
|
-
} else this.object = null
|
|
114
|
-
|
|
115
|
-
// add support for result object
|
|
116
|
-
if (result) {
|
|
117
|
-
this.result = result
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
// add support for result context
|
|
121
|
-
if (context) {
|
|
122
|
-
this.context = context
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
this.generateId = function () {
|
|
126
|
-
this.id = ADL.ruuid()
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
XAPIStatement.prototype.toString = function () {
|
|
131
|
-
return (
|
|
132
|
-
this.actor.toString() +
|
|
133
|
-
' ' +
|
|
134
|
-
this.verb.toString() +
|
|
135
|
-
' ' +
|
|
136
|
-
this.object.toString() +
|
|
137
|
-
' ' +
|
|
138
|
-
this.result.toString()
|
|
139
|
-
)
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
XAPIStatement.prototype.isValid = function () {
|
|
143
|
-
return (
|
|
144
|
-
this.actor &&
|
|
145
|
-
this.actor.isValid() &&
|
|
146
|
-
this.verb &&
|
|
147
|
-
this.verb.isValid() &&
|
|
148
|
-
this.object &&
|
|
149
|
-
this.object.isValid() &&
|
|
150
|
-
this.result &&
|
|
151
|
-
this.result.isValid()
|
|
152
|
-
)
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
XAPIStatement.prototype.generateRegistration = function () {
|
|
156
|
-
_getobj(this, 'context').registration = ADL.ruuid()
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
XAPIStatement.prototype.addParentActivity = function (activity) {
|
|
160
|
-
_getobj(this, 'context.contextActivities.parent[]').push(
|
|
161
|
-
new Activity(activity)
|
|
162
|
-
)
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
XAPIStatement.prototype.addGroupingActivity = function (activity) {
|
|
166
|
-
_getobj(this, 'context.contextActivities.grouping[]').push(
|
|
167
|
-
new Activity(activity)
|
|
168
|
-
)
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
XAPIStatement.prototype.addOtherContextActivity = function (activity) {
|
|
172
|
-
_getobj(this, 'context.contextActivities.other[]').push(
|
|
173
|
-
new Activity(activity)
|
|
174
|
-
)
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
///////////////////////////////////////////////////////////////
|
|
178
|
-
XAPIStatement.prototype._setActor = function (email, name, objectType) {
|
|
179
|
-
let actor = {
|
|
180
|
-
mbox: 'mailto:' + email,
|
|
181
|
-
name: name,
|
|
182
|
-
objectType: ''
|
|
183
|
-
}
|
|
184
|
-
actor.objectType = objectType || 'Agent'
|
|
185
|
-
|
|
186
|
-
this.actor = actor
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
/* helper function to set/change the verb of a statement
|
|
190
|
-
* @Params {String | Object} verb
|
|
191
|
-
*
|
|
192
|
-
*/
|
|
193
|
-
XAPIStatement.prototype._setVerb = function (verb) {
|
|
194
|
-
if (verb instanceof Verb) this.verb = verb
|
|
195
|
-
else if (verbs[verb]) this.verb = verbs[verb]
|
|
196
|
-
else this.verb = new Verb(verb)
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
XAPIStatement.prototype._setObject = function (object) {
|
|
200
|
-
if (object.objectType === 'Activity' || !object.objectType) {
|
|
201
|
-
if (object instanceof Activity) this.object = object
|
|
202
|
-
else this.object = new Activity(object)
|
|
203
|
-
} else if (object.objectType === 'Agent') {
|
|
204
|
-
if (object instanceof Agent) this.object = object
|
|
205
|
-
else this.object = new Agent(object)
|
|
206
|
-
} else if (object.objectType === 'Group') {
|
|
207
|
-
if (object instanceof Group) this.object = object
|
|
208
|
-
else this.object = new Group(object)
|
|
209
|
-
} else if (object.objectType === 'StatementRef') {
|
|
210
|
-
if (object instanceof StatementRef) this.object = object
|
|
211
|
-
else this.object = new StatementRef(object)
|
|
212
|
-
} else if (object.objectType === 'SubStatement') {
|
|
213
|
-
if (object instanceof SubStatement) this.object = object
|
|
214
|
-
else this.object = new SubStatement(object)
|
|
215
|
-
} else this.object = null
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
XAPIStatement.prototype._setResultScore = function (
|
|
219
|
-
score,
|
|
220
|
-
scoreScale,
|
|
221
|
-
scoreMin,
|
|
222
|
-
scoreMax
|
|
223
|
-
) {
|
|
224
|
-
if (!this.result) this.result = {}
|
|
225
|
-
this.result.score = {
|
|
226
|
-
scaled: scoreScale || 1,
|
|
227
|
-
min: scoreMin,
|
|
228
|
-
max: scoreMax,
|
|
229
|
-
raw: score
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
XAPIStatement.prototype._setResultKey = function (key, value) {
|
|
234
|
-
if (!this.result) this.result = {} //define the result key
|
|
235
|
-
//define the extra keys of the result
|
|
236
|
-
if (key == 'success') this.result.success = value
|
|
237
|
-
else if (key == 'response') this.result.response = value
|
|
238
|
-
else if (key == 'duration') this.result.duration = value
|
|
239
|
-
else if (key == 'extensions') this.result.extensions = value
|
|
240
|
-
else if (key == 'completion') this.result.completion = value
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
XAPIStatement.prototype._setContext = function (context) {
|
|
244
|
-
if (typeof context !== 'object') throw 'this not a valid context'
|
|
245
|
-
if (!this.context)
|
|
246
|
-
Object.defineProperty(this, 'context', { value: {}, writable: true })
|
|
247
|
-
this.context = { ...context }
|
|
248
|
-
|
|
249
|
-
// if (key == 'instructor') this.context.instructor = value
|
|
250
|
-
// else if (key == 'contextActivities') this.context.contextActivities = value
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
///////////////////////////////////////////////////////////////
|
|
254
|
-
|
|
255
|
-
/*
|
|
256
|
-
* Provides an easy constructor for xAPI agent objects
|
|
257
|
-
* @param {string} identifier One of the Inverse Functional Identifiers specified in the spec.
|
|
258
|
-
* That is, an email, a hashed email, an OpenID, or an account object.
|
|
259
|
-
* See (https://github.com/adlnet/xAPI-Spec/blob/master/xAPI.md#inversefunctional)
|
|
260
|
-
* @param {string} [name] The natural-language name of the agent
|
|
261
|
-
*/
|
|
262
|
-
var Agent = function (identifier, name) {
|
|
263
|
-
this.objectType = 'Agent'
|
|
264
|
-
this.name = name
|
|
265
|
-
|
|
266
|
-
// figure out what type of identifier was given
|
|
267
|
-
if (
|
|
268
|
-
identifier &&
|
|
269
|
-
(identifier.mbox ||
|
|
270
|
-
identifier.mbox_sha1sum ||
|
|
271
|
-
identifier.openid ||
|
|
272
|
-
identifier.account)
|
|
273
|
-
) {
|
|
274
|
-
for (var i in identifier) {
|
|
275
|
-
this[i] = identifier[i]
|
|
276
|
-
}
|
|
277
|
-
} else if (/^mailto:/.test(identifier)) {
|
|
278
|
-
this.mbox = identifier
|
|
279
|
-
} else if (/^[0-9a-f]{40}$/i.test(identifier)) {
|
|
280
|
-
this.mbox_sha1sum = identifier
|
|
281
|
-
} else if (/^http[s]?:/.test(identifier)) {
|
|
282
|
-
this.openid = identifier
|
|
283
|
-
} else if (identifier && identifier.homePage && identifier.name) {
|
|
284
|
-
this.account = identifier
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
Agent.prototype.toString = function () {
|
|
288
|
-
return (
|
|
289
|
-
this.name ||
|
|
290
|
-
this.mbox ||
|
|
291
|
-
this.openid ||
|
|
292
|
-
this.mbox_sha1sum ||
|
|
293
|
-
this.account.name
|
|
294
|
-
)
|
|
295
|
-
}
|
|
296
|
-
Agent.prototype.isValid = function () {
|
|
297
|
-
return (
|
|
298
|
-
this.mbox ||
|
|
299
|
-
this.mbox_sha1sum ||
|
|
300
|
-
this.openid ||
|
|
301
|
-
(this.account.homePage && this.account.name) ||
|
|
302
|
-
(this.objectType === 'Group' && this.member)
|
|
303
|
-
)
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
/*
|
|
307
|
-
* A type of agent, can contain multiple agents
|
|
308
|
-
* @param {string} [identifier] (optional if `members` specified) See Agent.
|
|
309
|
-
* @param {string} [members] An array of Agents describing the membership of the group
|
|
310
|
-
* @param {string} [name] The natural-language name of the agent
|
|
311
|
-
*/
|
|
312
|
-
var Group = function (identifier, members, name) {
|
|
313
|
-
Agent.call(this, identifier, name)
|
|
314
|
-
this.member = members
|
|
315
|
-
this.objectType = 'Group'
|
|
316
|
-
}
|
|
317
|
-
Group.prototype = new Agent()
|
|
318
|
-
|
|
319
|
-
/*
|
|
320
|
-
* Really only provides a convenient language map
|
|
321
|
-
* @param {string} id The IRI of the action taken
|
|
322
|
-
* @param {string} [description] An English-language description, or a Language Map
|
|
323
|
-
*/
|
|
324
|
-
var Verb = function (id, description) {
|
|
325
|
-
// if passed a verb object then copy and return
|
|
326
|
-
if (id && id.id) {
|
|
327
|
-
for (var i in id) {
|
|
328
|
-
this[i] = id[i]
|
|
329
|
-
}
|
|
330
|
-
return
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
// save id and build language map
|
|
334
|
-
this.id = id
|
|
335
|
-
if (description) {
|
|
336
|
-
if (typeof description === 'string' || description instanceof String) {
|
|
337
|
-
this.display = { 'en-US': description }
|
|
338
|
-
} else {
|
|
339
|
-
this.display = description
|
|
340
|
-
}
|
|
341
|
-
}
|
|
342
|
-
}
|
|
343
|
-
Verb.prototype.toString = function () {
|
|
344
|
-
if (this.display && (this.display['en-US'] || this.display['en']))
|
|
345
|
-
return this.display['en-US'] || this.display['en']
|
|
346
|
-
else return this.id
|
|
347
|
-
}
|
|
348
|
-
Verb.prototype.isValid = function () {
|
|
349
|
-
return this.id
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
/*
|
|
353
|
-
* Describes an object that an agent interacts with
|
|
354
|
-
* @param {string} id The unique activity IRI
|
|
355
|
-
* @param {string} name An English-language identifier for the activity, or a Language Map
|
|
356
|
-
* @param {string} description An English-language description of the activity, or a Language Map
|
|
357
|
-
*/
|
|
358
|
-
var Activity = function (id, name, description) {
|
|
359
|
-
// if first arg is activity, copy everything over
|
|
360
|
-
if (id && id.id) {
|
|
361
|
-
var act = id
|
|
362
|
-
for (var i in act) {
|
|
363
|
-
this[i] = act[i]
|
|
364
|
-
}
|
|
365
|
-
return
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
this.objectType = 'Activity'
|
|
369
|
-
this.id = id
|
|
370
|
-
if (name || description) {
|
|
371
|
-
this.definition = {}
|
|
372
|
-
|
|
373
|
-
if (typeof name === 'string' || name instanceof String)
|
|
374
|
-
this.definition.name = { 'en-US': name }
|
|
375
|
-
else if (name) this.definition.name = name
|
|
376
|
-
|
|
377
|
-
if (typeof description === 'string' || description instanceof String)
|
|
378
|
-
this.definition.description = { 'en-US': description }
|
|
379
|
-
else if (description) this.definition.description = description
|
|
380
|
-
}
|
|
381
|
-
}
|
|
382
|
-
Activity.prototype.toString = function () {
|
|
383
|
-
if (
|
|
384
|
-
this.definition &&
|
|
385
|
-
this.definition.name &&
|
|
386
|
-
(this.definition.name['en-US'] || this.definition.name['en'])
|
|
387
|
-
)
|
|
388
|
-
return this.definition.name['en-US'] || this.definition.name['en']
|
|
389
|
-
else return this.id
|
|
390
|
-
}
|
|
391
|
-
Activity.prototype.isValid = function () {
|
|
392
|
-
return this.id && (!this.objectType || this.objectType === 'Activity')
|
|
393
|
-
}
|
|
394
|
-
|
|
395
|
-
/*
|
|
396
|
-
* An object that refers to a separate statement
|
|
397
|
-
* @param {string} id The UUID of another xAPI statement
|
|
398
|
-
*/
|
|
399
|
-
var StatementRef = function (id) {
|
|
400
|
-
if (id && id.id) {
|
|
401
|
-
for (var i in id) {
|
|
402
|
-
this[i] = id[i]
|
|
403
|
-
}
|
|
404
|
-
} else {
|
|
405
|
-
this.objectType = 'StatementRef'
|
|
406
|
-
this.id = id
|
|
407
|
-
}
|
|
408
|
-
}
|
|
409
|
-
StatementRef.prototype.toString = function () {
|
|
410
|
-
return 'statement(' + this.id + ')'
|
|
411
|
-
}
|
|
412
|
-
StatementRef.prototype.isValid = function () {
|
|
413
|
-
return this.id && this.objectType && this.objectType === 'StatementRef'
|
|
414
|
-
}
|
|
415
|
-
|
|
416
|
-
/*
|
|
417
|
-
* A self-contained statement as the object of another statement
|
|
418
|
-
* See XAPIStatement for constructor details
|
|
419
|
-
* @param {string} actor The Agent or Group committing the action described by the statement
|
|
420
|
-
* @param {string} verb The Verb for the action described by the statement
|
|
421
|
-
* @param {string} object The receiver of the action. An Agent, Group, Activity, or StatementRef
|
|
422
|
-
*/
|
|
423
|
-
var SubStatement = function (actor, verb, object) {
|
|
424
|
-
XAPIStatement.call(this, actor, verb, object)
|
|
425
|
-
this.objectType = 'SubStatement'
|
|
426
|
-
|
|
427
|
-
delete this.id
|
|
428
|
-
delete this.stored
|
|
429
|
-
delete this.version
|
|
430
|
-
delete this.authority
|
|
431
|
-
}
|
|
432
|
-
SubStatement.prototype = new XAPIStatement()
|
|
433
|
-
SubStatement.prototype.toString = function () {
|
|
434
|
-
return '"' + SubStatement.prototype.prototype.toString.call(this) + '"'
|
|
435
|
-
}
|
|
436
|
-
|
|
437
|
-
XAPIStatement.Agent = Agent
|
|
438
|
-
XAPIStatement.Group = Group
|
|
439
|
-
XAPIStatement.Verb = Verb
|
|
440
|
-
XAPIStatement.Activity = Activity
|
|
441
|
-
XAPIStatement.StatementRef = StatementRef
|
|
442
|
-
XAPIStatement.SubStatement = SubStatement
|
|
443
|
-
ADL.XAPIStatement = XAPIStatement
|
|
444
|
-
}
|
|
1
|
+
import verbs from './verbs'
|
|
2
|
+
|
|
3
|
+
export function xapiStatement(ADL) {
|
|
4
|
+
function _getobj(obj, path) {
|
|
5
|
+
var parts = path.split('.')
|
|
6
|
+
|
|
7
|
+
var part = parts[0]
|
|
8
|
+
path = parts.slice(1).join('.')
|
|
9
|
+
|
|
10
|
+
if (!obj[part]) {
|
|
11
|
+
if (/\[\]$/.test(part)) {
|
|
12
|
+
part = part.slice(0, -2)
|
|
13
|
+
if (!Array.isArray(obj[part])) {
|
|
14
|
+
obj[part] = []
|
|
15
|
+
}
|
|
16
|
+
} else obj[part] = {}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
if (!path) return obj[part]
|
|
20
|
+
else return _getobj(obj[part], path)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/*******************************************************************************
|
|
24
|
+
* XAPIStatement - a convenience class to wrap statement objects
|
|
25
|
+
*
|
|
26
|
+
* This sub-API is supposed to make it easier to author valid xAPI statements
|
|
27
|
+
* by adding constructors and encouraging best practices. All objects in this
|
|
28
|
+
* API are fully JSON-compatible, so anything expecting an xAPI statement can
|
|
29
|
+
* take an improved statement and vice versa.
|
|
30
|
+
*
|
|
31
|
+
* A working knowledge of what exactly the LRS expects is still expected,
|
|
32
|
+
* but it's easier to map an 'I did this' statement to xAPI now.
|
|
33
|
+
*
|
|
34
|
+
* Tech note: All constructors also double as shallow clone functions. E.g.
|
|
35
|
+
*
|
|
36
|
+
* var activity1 = new Activity('A walk in the park');
|
|
37
|
+
* var activity2 = new Activity(activity1);
|
|
38
|
+
* var activity3 = new Activity(stmt_from_lrs.object);
|
|
39
|
+
*
|
|
40
|
+
*******************************************************************************/
|
|
41
|
+
|
|
42
|
+
/*
|
|
43
|
+
* A convenient JSON-compatible xAPI statement wrapper
|
|
44
|
+
* All args are optional, but the statement may not be complete or valid
|
|
45
|
+
* Can also pass an Agent IFI, Verb ID, and an Activity ID in lieu of these args
|
|
46
|
+
* @param {string} [actor] The Agent or Group committing the action described by the statement
|
|
47
|
+
* @param {string} [verb] The Verb for the action described by the statement
|
|
48
|
+
* @param {string} [object] The receiver of the action. An Agent, Group, Activity, SubStatement, or StatementRef
|
|
49
|
+
* @example
|
|
50
|
+
* var stmt = new ADL.XAPIStatement(
|
|
51
|
+
* 'mailto:steve.vergenz.ctr@adlnet.gov',
|
|
52
|
+
* 'http://adlnet.gov/expapi/verbs/launched',
|
|
53
|
+
* 'http://vwf.adlnet.gov/xapi/virtual_world_sandbox'
|
|
54
|
+
* );
|
|
55
|
+
* >> {
|
|
56
|
+
* "actor": {
|
|
57
|
+
* "objectType": "Agent",
|
|
58
|
+
* "mbox": "mailto:steve.vergenz.ctr@adlnet.gov" },
|
|
59
|
+
* "verb": {
|
|
60
|
+
* "id": "http://adlnet.gov/expapi/verbs/launched" },
|
|
61
|
+
* "object": {
|
|
62
|
+
* "objectType": "Activity",
|
|
63
|
+
* "id": "http://vwf.adlnet.gov/xapi/virtual_world_sandbox" },
|
|
64
|
+
* "result": {
|
|
65
|
+
* "An optional property that represents a measured outcome related to the Statement in which it is included."}}
|
|
66
|
+
*/
|
|
67
|
+
var XAPIStatement = function (actor, verb, object, context, result) {
|
|
68
|
+
// initialize
|
|
69
|
+
|
|
70
|
+
// if first arg is an xapi statement, parse
|
|
71
|
+
if (actor && actor.actor && actor.verb && actor.object) {
|
|
72
|
+
var stmt = actor
|
|
73
|
+
for (var i in stmt) {
|
|
74
|
+
if (i != 'actor' && i != 'verb' && i != 'object') this[i] = stmt[i]
|
|
75
|
+
}
|
|
76
|
+
actor = stmt.actor
|
|
77
|
+
verb = stmt.verb
|
|
78
|
+
object = stmt.object
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (actor) {
|
|
82
|
+
if (actor instanceof Agent) this.actor = actor
|
|
83
|
+
else if (actor.objectType === 'Agent' || !actor.objectType)
|
|
84
|
+
this.actor = new Agent(actor)
|
|
85
|
+
else if (actor.objectType === 'Group') this.actor = new Group(actor)
|
|
86
|
+
} else this.actor = null
|
|
87
|
+
|
|
88
|
+
if (verb) {
|
|
89
|
+
this._setVerb(verb)
|
|
90
|
+
// if (verb instanceof Verb) this.verb = verb
|
|
91
|
+
// else this.verb = new Verb(verb)
|
|
92
|
+
} else this.verb = null
|
|
93
|
+
|
|
94
|
+
// decide what kind of object was passed
|
|
95
|
+
if (object) {
|
|
96
|
+
// if (object.objectType === 'Activity' || !object.objectType) {
|
|
97
|
+
// if (object instanceof Activity) this.object = object
|
|
98
|
+
// else this.object = new Activity(object)
|
|
99
|
+
// } else if (object.objectType === 'Agent') {
|
|
100
|
+
// if (object instanceof Agent) this.object = object
|
|
101
|
+
// else this.object = new Agent(object)
|
|
102
|
+
// } else if (object.objectType === 'Group') {
|
|
103
|
+
// if (object instanceof Group) this.object = object
|
|
104
|
+
// else this.object = new Group(object)
|
|
105
|
+
// } else if (object.objectType === 'StatementRef') {
|
|
106
|
+
// if (object instanceof StatementRef) this.object = object
|
|
107
|
+
// else this.object = new StatementRef(object)
|
|
108
|
+
// } else if (object.objectType === 'SubStatement') {
|
|
109
|
+
// if (object instanceof SubStatement) this.object = object
|
|
110
|
+
// else this.object = new SubStatement(object)
|
|
111
|
+
// } else this.object = null
|
|
112
|
+
this._setObject(object)
|
|
113
|
+
} else this.object = null
|
|
114
|
+
|
|
115
|
+
// add support for result object
|
|
116
|
+
if (result) {
|
|
117
|
+
this.result = result
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// add support for result context
|
|
121
|
+
if (context) {
|
|
122
|
+
this.context = context
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
this.generateId = function () {
|
|
126
|
+
this.id = ADL.ruuid()
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
XAPIStatement.prototype.toString = function () {
|
|
131
|
+
return (
|
|
132
|
+
this.actor.toString() +
|
|
133
|
+
' ' +
|
|
134
|
+
this.verb.toString() +
|
|
135
|
+
' ' +
|
|
136
|
+
this.object.toString() +
|
|
137
|
+
' ' +
|
|
138
|
+
this.result.toString()
|
|
139
|
+
)
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
XAPIStatement.prototype.isValid = function () {
|
|
143
|
+
return (
|
|
144
|
+
this.actor &&
|
|
145
|
+
this.actor.isValid() &&
|
|
146
|
+
this.verb &&
|
|
147
|
+
this.verb.isValid() &&
|
|
148
|
+
this.object &&
|
|
149
|
+
this.object.isValid() &&
|
|
150
|
+
this.result &&
|
|
151
|
+
this.result.isValid()
|
|
152
|
+
)
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
XAPIStatement.prototype.generateRegistration = function () {
|
|
156
|
+
_getobj(this, 'context').registration = ADL.ruuid()
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
XAPIStatement.prototype.addParentActivity = function (activity) {
|
|
160
|
+
_getobj(this, 'context.contextActivities.parent[]').push(
|
|
161
|
+
new Activity(activity)
|
|
162
|
+
)
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
XAPIStatement.prototype.addGroupingActivity = function (activity) {
|
|
166
|
+
_getobj(this, 'context.contextActivities.grouping[]').push(
|
|
167
|
+
new Activity(activity)
|
|
168
|
+
)
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
XAPIStatement.prototype.addOtherContextActivity = function (activity) {
|
|
172
|
+
_getobj(this, 'context.contextActivities.other[]').push(
|
|
173
|
+
new Activity(activity)
|
|
174
|
+
)
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
///////////////////////////////////////////////////////////////
|
|
178
|
+
XAPIStatement.prototype._setActor = function (email, name, objectType) {
|
|
179
|
+
let actor = {
|
|
180
|
+
mbox: 'mailto:' + email,
|
|
181
|
+
name: name,
|
|
182
|
+
objectType: ''
|
|
183
|
+
}
|
|
184
|
+
actor.objectType = objectType || 'Agent'
|
|
185
|
+
|
|
186
|
+
this.actor = actor
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/* helper function to set/change the verb of a statement
|
|
190
|
+
* @Params {String | Object} verb
|
|
191
|
+
*
|
|
192
|
+
*/
|
|
193
|
+
XAPIStatement.prototype._setVerb = function (verb) {
|
|
194
|
+
if (verb instanceof Verb) this.verb = verb
|
|
195
|
+
else if (verbs[verb]) this.verb = verbs[verb]
|
|
196
|
+
else this.verb = new Verb(verb)
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
XAPIStatement.prototype._setObject = function (object) {
|
|
200
|
+
if (object.objectType === 'Activity' || !object.objectType) {
|
|
201
|
+
if (object instanceof Activity) this.object = object
|
|
202
|
+
else this.object = new Activity(object)
|
|
203
|
+
} else if (object.objectType === 'Agent') {
|
|
204
|
+
if (object instanceof Agent) this.object = object
|
|
205
|
+
else this.object = new Agent(object)
|
|
206
|
+
} else if (object.objectType === 'Group') {
|
|
207
|
+
if (object instanceof Group) this.object = object
|
|
208
|
+
else this.object = new Group(object)
|
|
209
|
+
} else if (object.objectType === 'StatementRef') {
|
|
210
|
+
if (object instanceof StatementRef) this.object = object
|
|
211
|
+
else this.object = new StatementRef(object)
|
|
212
|
+
} else if (object.objectType === 'SubStatement') {
|
|
213
|
+
if (object instanceof SubStatement) this.object = object
|
|
214
|
+
else this.object = new SubStatement(object)
|
|
215
|
+
} else this.object = null
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
XAPIStatement.prototype._setResultScore = function (
|
|
219
|
+
score,
|
|
220
|
+
scoreScale,
|
|
221
|
+
scoreMin,
|
|
222
|
+
scoreMax
|
|
223
|
+
) {
|
|
224
|
+
if (!this.result) this.result = {}
|
|
225
|
+
this.result.score = {
|
|
226
|
+
scaled: scoreScale || 1,
|
|
227
|
+
min: scoreMin,
|
|
228
|
+
max: scoreMax,
|
|
229
|
+
raw: score
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
XAPIStatement.prototype._setResultKey = function (key, value) {
|
|
234
|
+
if (!this.result) this.result = {} //define the result key
|
|
235
|
+
//define the extra keys of the result
|
|
236
|
+
if (key == 'success') this.result.success = value
|
|
237
|
+
else if (key == 'response') this.result.response = value
|
|
238
|
+
else if (key == 'duration') this.result.duration = value
|
|
239
|
+
else if (key == 'extensions') this.result.extensions = value
|
|
240
|
+
else if (key == 'completion') this.result.completion = value
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
XAPIStatement.prototype._setContext = function (context) {
|
|
244
|
+
if (typeof context !== 'object') throw 'this not a valid context'
|
|
245
|
+
if (!this.context)
|
|
246
|
+
Object.defineProperty(this, 'context', { value: {}, writable: true })
|
|
247
|
+
this.context = { ...context }
|
|
248
|
+
|
|
249
|
+
// if (key == 'instructor') this.context.instructor = value
|
|
250
|
+
// else if (key == 'contextActivities') this.context.contextActivities = value
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
///////////////////////////////////////////////////////////////
|
|
254
|
+
|
|
255
|
+
/*
|
|
256
|
+
* Provides an easy constructor for xAPI agent objects
|
|
257
|
+
* @param {string} identifier One of the Inverse Functional Identifiers specified in the spec.
|
|
258
|
+
* That is, an email, a hashed email, an OpenID, or an account object.
|
|
259
|
+
* See (https://github.com/adlnet/xAPI-Spec/blob/master/xAPI.md#inversefunctional)
|
|
260
|
+
* @param {string} [name] The natural-language name of the agent
|
|
261
|
+
*/
|
|
262
|
+
var Agent = function (identifier, name) {
|
|
263
|
+
this.objectType = 'Agent'
|
|
264
|
+
this.name = name
|
|
265
|
+
|
|
266
|
+
// figure out what type of identifier was given
|
|
267
|
+
if (
|
|
268
|
+
identifier &&
|
|
269
|
+
(identifier.mbox ||
|
|
270
|
+
identifier.mbox_sha1sum ||
|
|
271
|
+
identifier.openid ||
|
|
272
|
+
identifier.account)
|
|
273
|
+
) {
|
|
274
|
+
for (var i in identifier) {
|
|
275
|
+
this[i] = identifier[i]
|
|
276
|
+
}
|
|
277
|
+
} else if (/^mailto:/.test(identifier)) {
|
|
278
|
+
this.mbox = identifier
|
|
279
|
+
} else if (/^[0-9a-f]{40}$/i.test(identifier)) {
|
|
280
|
+
this.mbox_sha1sum = identifier
|
|
281
|
+
} else if (/^http[s]?:/.test(identifier)) {
|
|
282
|
+
this.openid = identifier
|
|
283
|
+
} else if (identifier && identifier.homePage && identifier.name) {
|
|
284
|
+
this.account = identifier
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
Agent.prototype.toString = function () {
|
|
288
|
+
return (
|
|
289
|
+
this.name ||
|
|
290
|
+
this.mbox ||
|
|
291
|
+
this.openid ||
|
|
292
|
+
this.mbox_sha1sum ||
|
|
293
|
+
this.account.name
|
|
294
|
+
)
|
|
295
|
+
}
|
|
296
|
+
Agent.prototype.isValid = function () {
|
|
297
|
+
return (
|
|
298
|
+
this.mbox ||
|
|
299
|
+
this.mbox_sha1sum ||
|
|
300
|
+
this.openid ||
|
|
301
|
+
(this.account.homePage && this.account.name) ||
|
|
302
|
+
(this.objectType === 'Group' && this.member)
|
|
303
|
+
)
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/*
|
|
307
|
+
* A type of agent, can contain multiple agents
|
|
308
|
+
* @param {string} [identifier] (optional if `members` specified) See Agent.
|
|
309
|
+
* @param {string} [members] An array of Agents describing the membership of the group
|
|
310
|
+
* @param {string} [name] The natural-language name of the agent
|
|
311
|
+
*/
|
|
312
|
+
var Group = function (identifier, members, name) {
|
|
313
|
+
Agent.call(this, identifier, name)
|
|
314
|
+
this.member = members
|
|
315
|
+
this.objectType = 'Group'
|
|
316
|
+
}
|
|
317
|
+
Group.prototype = new Agent()
|
|
318
|
+
|
|
319
|
+
/*
|
|
320
|
+
* Really only provides a convenient language map
|
|
321
|
+
* @param {string} id The IRI of the action taken
|
|
322
|
+
* @param {string} [description] An English-language description, or a Language Map
|
|
323
|
+
*/
|
|
324
|
+
var Verb = function (id, description) {
|
|
325
|
+
// if passed a verb object then copy and return
|
|
326
|
+
if (id && id.id) {
|
|
327
|
+
for (var i in id) {
|
|
328
|
+
this[i] = id[i]
|
|
329
|
+
}
|
|
330
|
+
return
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
// save id and build language map
|
|
334
|
+
this.id = id
|
|
335
|
+
if (description) {
|
|
336
|
+
if (typeof description === 'string' || description instanceof String) {
|
|
337
|
+
this.display = { 'en-US': description }
|
|
338
|
+
} else {
|
|
339
|
+
this.display = description
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
Verb.prototype.toString = function () {
|
|
344
|
+
if (this.display && (this.display['en-US'] || this.display['en']))
|
|
345
|
+
return this.display['en-US'] || this.display['en']
|
|
346
|
+
else return this.id
|
|
347
|
+
}
|
|
348
|
+
Verb.prototype.isValid = function () {
|
|
349
|
+
return this.id
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
/*
|
|
353
|
+
* Describes an object that an agent interacts with
|
|
354
|
+
* @param {string} id The unique activity IRI
|
|
355
|
+
* @param {string} name An English-language identifier for the activity, or a Language Map
|
|
356
|
+
* @param {string} description An English-language description of the activity, or a Language Map
|
|
357
|
+
*/
|
|
358
|
+
var Activity = function (id, name, description) {
|
|
359
|
+
// if first arg is activity, copy everything over
|
|
360
|
+
if (id && id.id) {
|
|
361
|
+
var act = id
|
|
362
|
+
for (var i in act) {
|
|
363
|
+
this[i] = act[i]
|
|
364
|
+
}
|
|
365
|
+
return
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
this.objectType = 'Activity'
|
|
369
|
+
this.id = id
|
|
370
|
+
if (name || description) {
|
|
371
|
+
this.definition = {}
|
|
372
|
+
|
|
373
|
+
if (typeof name === 'string' || name instanceof String)
|
|
374
|
+
this.definition.name = { 'en-US': name }
|
|
375
|
+
else if (name) this.definition.name = name
|
|
376
|
+
|
|
377
|
+
if (typeof description === 'string' || description instanceof String)
|
|
378
|
+
this.definition.description = { 'en-US': description }
|
|
379
|
+
else if (description) this.definition.description = description
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
Activity.prototype.toString = function () {
|
|
383
|
+
if (
|
|
384
|
+
this.definition &&
|
|
385
|
+
this.definition.name &&
|
|
386
|
+
(this.definition.name['en-US'] || this.definition.name['en'])
|
|
387
|
+
)
|
|
388
|
+
return this.definition.name['en-US'] || this.definition.name['en']
|
|
389
|
+
else return this.id
|
|
390
|
+
}
|
|
391
|
+
Activity.prototype.isValid = function () {
|
|
392
|
+
return this.id && (!this.objectType || this.objectType === 'Activity')
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
/*
|
|
396
|
+
* An object that refers to a separate statement
|
|
397
|
+
* @param {string} id The UUID of another xAPI statement
|
|
398
|
+
*/
|
|
399
|
+
var StatementRef = function (id) {
|
|
400
|
+
if (id && id.id) {
|
|
401
|
+
for (var i in id) {
|
|
402
|
+
this[i] = id[i]
|
|
403
|
+
}
|
|
404
|
+
} else {
|
|
405
|
+
this.objectType = 'StatementRef'
|
|
406
|
+
this.id = id
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
StatementRef.prototype.toString = function () {
|
|
410
|
+
return 'statement(' + this.id + ')'
|
|
411
|
+
}
|
|
412
|
+
StatementRef.prototype.isValid = function () {
|
|
413
|
+
return this.id && this.objectType && this.objectType === 'StatementRef'
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
/*
|
|
417
|
+
* A self-contained statement as the object of another statement
|
|
418
|
+
* See XAPIStatement for constructor details
|
|
419
|
+
* @param {string} actor The Agent or Group committing the action described by the statement
|
|
420
|
+
* @param {string} verb The Verb for the action described by the statement
|
|
421
|
+
* @param {string} object The receiver of the action. An Agent, Group, Activity, or StatementRef
|
|
422
|
+
*/
|
|
423
|
+
var SubStatement = function (actor, verb, object) {
|
|
424
|
+
XAPIStatement.call(this, actor, verb, object)
|
|
425
|
+
this.objectType = 'SubStatement'
|
|
426
|
+
|
|
427
|
+
delete this.id
|
|
428
|
+
delete this.stored
|
|
429
|
+
delete this.version
|
|
430
|
+
delete this.authority
|
|
431
|
+
}
|
|
432
|
+
SubStatement.prototype = new XAPIStatement()
|
|
433
|
+
SubStatement.prototype.toString = function () {
|
|
434
|
+
return '"' + SubStatement.prototype.prototype.toString.call(this) + '"'
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
XAPIStatement.Agent = Agent
|
|
438
|
+
XAPIStatement.Group = Group
|
|
439
|
+
XAPIStatement.Verb = Verb
|
|
440
|
+
XAPIStatement.Activity = Activity
|
|
441
|
+
XAPIStatement.StatementRef = StatementRef
|
|
442
|
+
XAPIStatement.SubStatement = SubStatement
|
|
443
|
+
ADL.XAPIStatement = XAPIStatement
|
|
444
|
+
}
|