Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
var H5P = window.H5P = window.H5P || {};
2
 
3
/**
4
 * Used for xAPI events.
5
 *
6
 * @class
7
 * @extends H5P.Event
8
 */
9
H5P.XAPIEvent = function () {
10
  H5P.Event.call(this, 'xAPI', {'statement': {}}, {bubbles: true, external: true});
11
};
12
 
13
H5P.XAPIEvent.prototype = Object.create(H5P.Event.prototype);
14
H5P.XAPIEvent.prototype.constructor = H5P.XAPIEvent;
15
 
16
/**
17
 * Set scored result statements.
18
 *
19
 * @param {number} score
20
 * @param {number} maxScore
21
 * @param {object} instance
22
 * @param {boolean} completion
23
 * @param {boolean} success
24
 */
25
H5P.XAPIEvent.prototype.setScoredResult = function (score, maxScore, instance, completion, success) {
26
  this.data.statement.result = {};
27
 
28
  if (typeof score !== 'undefined') {
29
    if (typeof maxScore === 'undefined') {
30
      this.data.statement.result.score = {'raw': score};
31
    }
32
    else {
33
      this.data.statement.result.score = {
34
        'min': 0,
35
        'max': maxScore,
36
        'raw': score
37
      };
38
      if (maxScore > 0) {
39
        this.data.statement.result.score.scaled = Math.round(score / maxScore * 10000) / 10000;
40
      }
41
    }
42
  }
43
 
44
  if (typeof completion === 'undefined') {
45
    this.data.statement.result.completion = (this.getVerb() === 'completed' || this.getVerb() === 'answered');
46
  }
47
  else {
48
    this.data.statement.result.completion = completion;
49
  }
50
 
51
  if (typeof success !== 'undefined') {
52
    this.data.statement.result.success = success;
53
  }
54
 
55
  if (instance && instance.activityStartTime) {
56
    var duration = Math.round((Date.now() - instance.activityStartTime ) / 10) / 100;
57
    // xAPI spec allows a precision of 0.01 seconds
58
 
59
    this.data.statement.result.duration = 'PT' + duration + 'S';
60
  }
61
};
62
 
63
/**
64
 * Set a verb.
65
 *
66
 * @param {string} verb
67
 *   Verb in short form, one of the verbs defined at
68
 *   {@link http://adlnet.gov/expapi/verbs/|ADL xAPI Vocabulary}
69
 *
70
 */
71
H5P.XAPIEvent.prototype.setVerb = function (verb) {
72
  if (H5P.jQuery.inArray(verb, H5P.XAPIEvent.allowedXAPIVerbs) !== -1) {
73
    this.data.statement.verb = {
74
      'id': 'http://adlnet.gov/expapi/verbs/' + verb,
75
      'display': {
76
        'en-US': verb
77
      }
78
    };
79
  }
80
  else if (verb.id !== undefined) {
81
    this.data.statement.verb = verb;
82
  }
83
};
84
 
85
/**
86
 * Get the statements verb id.
87
 *
88
 * @param {boolean} full
89
 *   if true the full verb id prefixed by http://adlnet.gov/expapi/verbs/
90
 *   will be returned
91
 * @returns {string}
92
 *   Verb or null if no verb with an id has been defined
93
 */
94
H5P.XAPIEvent.prototype.getVerb = function (full) {
95
  var statement = this.data.statement;
96
  if ('verb' in statement) {
97
    if (full === true) {
98
      return statement.verb;
99
    }
100
    return statement.verb.id.slice(31);
101
  }
102
  else {
103
    return null;
104
  }
105
};
106
 
107
/**
108
 * Set the object part of the statement.
109
 *
110
 * The id is found automatically (the url to the content)
111
 *
112
 * @param {Object} instance
113
 *   The H5P instance
114
 */
115
H5P.XAPIEvent.prototype.setObject = function (instance) {
116
  if (instance.contentId) {
117
    this.data.statement.object = {
118
      'id': this.getContentXAPIId(instance),
119
      'objectType': 'Activity',
120
      'definition': {
121
        'extensions': {
122
          'http://h5p.org/x-api/h5p-local-content-id': instance.contentId
123
        }
124
      }
125
    };
126
    if (instance.subContentId) {
127
      this.data.statement.object.definition.extensions['http://h5p.org/x-api/h5p-subContentId'] = instance.subContentId;
128
      // Don't set titles on main content, title should come from publishing platform
129
      if (typeof instance.getTitle === 'function') {
130
        this.data.statement.object.definition.name = {
131
          "en-US": instance.getTitle()
132
        };
133
      }
134
    }
135
    else {
136
      var content = H5P.getContentForInstance(instance.contentId);
137
      if (content && content.metadata && content.metadata.title) {
138
        this.data.statement.object.definition.name = {
139
          "en-US": H5P.createTitle(content.metadata.title)
140
        };
141
      }
142
    }
143
  }
144
  else {
145
    // Content types view always expect to have a contentId when they are displayed.
146
    // This is not the case if they are displayed in the editor as part of a preview.
147
    // The fix is to set an empty object with definition for the xAPI event, so all
148
    // the content types that rely on this does not have to handle it. This means
149
    // that content types that are being previewed will send xAPI completed events,
150
    // but since there are no scripts that catch these events in the editor,
151
    // this is not a problem.
152
    this.data.statement.object = {
153
      definition: {}
154
    };
155
  }
156
};
157
 
158
/**
159
 * Set the context part of the statement.
160
 *
161
 * @param {Object} instance
162
 *   The H5P instance
163
 */
164
H5P.XAPIEvent.prototype.setContext = function (instance) {
165
  if (instance.parent && (instance.parent.contentId || instance.parent.subContentId)) {
166
    this.data.statement.context = {
167
      "contextActivities": {
168
        "parent": [
169
          {
170
            "id": this.getContentXAPIId(instance.parent),
171
            "objectType": "Activity"
172
          }
173
        ]
174
      }
175
    };
176
  }
177
  if (instance.libraryInfo) {
178
    if (this.data.statement.context === undefined) {
179
      this.data.statement.context = {"contextActivities":{}};
180
    }
181
    this.data.statement.context.contextActivities.category = [
182
      {
183
        "id": "http://h5p.org/libraries/" + instance.libraryInfo.versionedNameNoSpaces,
184
        "objectType": "Activity"
185
      }
186
    ];
187
  }
188
};
189
 
190
/**
191
 * Set the actor. Email and name will be added automatically.
192
 */
193
H5P.XAPIEvent.prototype.setActor = function () {
194
  if (H5PIntegration.user !== undefined) {
195
    this.data.statement.actor = {
196
      'name': H5PIntegration.user.name,
197
      'mbox': 'mailto:' + H5PIntegration.user.mail,
198
      'objectType': 'Agent'
199
    };
200
  }
201
  else {
202
    var uuid;
203
    try {
204
      if (localStorage.H5PUserUUID) {
205
        uuid = localStorage.H5PUserUUID;
206
      }
207
      else {
208
        uuid = H5P.createUUID();
209
        localStorage.H5PUserUUID = uuid;
210
      }
211
    }
212
    catch (err) {
213
      // LocalStorage and Cookies are probably disabled. Do not track the user.
214
      uuid = 'not-trackable-' + H5P.createUUID();
215
    }
216
    this.data.statement.actor = {
217
      'account': {
218
        'name': uuid,
219
        'homePage': H5PIntegration.siteUrl
220
      },
221
      'objectType': 'Agent'
222
    };
223
  }
224
};
225
 
226
/**
227
 * Get the max value of the result - score part of the statement
228
 *
229
 * @returns {number}
230
 *   The max score, or null if not defined
231
 */
232
H5P.XAPIEvent.prototype.getMaxScore = function () {
233
  return this.getVerifiedStatementValue(['result', 'score', 'max']);
234
};
235
 
236
/**
237
 * Get the raw value of the result - score part of the statement
238
 *
239
 * @returns {number}
240
 *   The score, or null if not defined
241
 */
242
H5P.XAPIEvent.prototype.getScore = function () {
243
  return this.getVerifiedStatementValue(['result', 'score', 'raw']);
244
};
245
 
246
/**
247
 * Get content xAPI ID.
248
 *
249
 * @param {Object} instance
250
 *   The H5P instance
251
 */
252
H5P.XAPIEvent.prototype.getContentXAPIId = function (instance) {
253
  var xAPIId;
254
  if (instance.contentId && H5PIntegration && H5PIntegration.contents && H5PIntegration.contents['cid-' + instance.contentId]) {
255
    xAPIId =  H5PIntegration.contents['cid-' + instance.contentId].url;
256
    if (instance.subContentId) {
257
      xAPIId += '?subContentId=' +  instance.subContentId;
258
    }
259
  }
260
  return xAPIId;
261
};
262
 
263
/**
264
 * Check if this event is sent from a child (i.e not from grandchild)
265
 *
266
 * @return {Boolean}
267
 */
268
H5P.XAPIEvent.prototype.isFromChild = function () {
269
  var parentId = this.getVerifiedStatementValue(['context', 'contextActivities', 'parent', 0, 'id']);
270
  return !parentId || parentId.indexOf('subContentId') === -1;
271
};
272
 
273
/**
274
 * Figure out if a property exists in the statement and return it
275
 *
276
 * @param {string[]} keys
277
 *   List describing the property we're looking for. For instance
278
 *   ['result', 'score', 'raw'] for result.score.raw
279
 * @returns {*}
280
 *   The value of the property if it is set, null otherwise.
281
 */
282
H5P.XAPIEvent.prototype.getVerifiedStatementValue = function (keys) {
283
  var val = this.data.statement;
284
  for (var i = 0; i < keys.length; i++) {
285
    if (val[keys[i]] === undefined) {
286
      return null;
287
    }
288
    val = val[keys[i]];
289
  }
290
  return val;
291
};
292
 
293
/**
294
 * List of verbs defined at {@link http://adlnet.gov/expapi/verbs/|ADL xAPI Vocabulary}
295
 *
296
 * @type Array
297
 */
298
H5P.XAPIEvent.allowedXAPIVerbs = [
299
  'answered',
300
  'asked',
301
  'attempted',
302
  'attended',
303
  'commented',
304
  'completed',
305
  'exited',
306
  'experienced',
307
  'failed',
308
  'imported',
309
  'initialized',
310
  'interacted',
311
  'launched',
312
  'mastered',
313
  'passed',
314
  'preferred',
315
  'progressed',
316
  'registered',
317
  'responded',
318
  'resumed',
319
  'scored',
320
  'shared',
321
  'suspended',
322
  'terminated',
323
  'voided',
324
 
325
  // Custom verbs used for action toolbar below content
326
  'downloaded',
327
  'copied',
328
  'accessed-reuse',
329
  'accessed-embed',
330
  'accessed-copyright'
331
];