1 |
efrain |
1 |
/**
|
|
|
2 |
* Collect results from xAPI events
|
|
|
3 |
*/
|
|
|
4 |
(function($) {
|
|
|
5 |
|
|
|
6 |
/**
|
|
|
7 |
* Finds a H5P library instance in an array based on the content ID
|
|
|
8 |
*
|
|
|
9 |
* @param {Array} instances
|
|
|
10 |
* @param {number} contentId
|
|
|
11 |
* @returns {Object|undefined} Content instance
|
|
|
12 |
*/
|
|
|
13 |
function findInstanceInArray(instances, contentId) {
|
|
|
14 |
if (instances !== undefined && contentId !== undefined) {
|
|
|
15 |
for (var i = 0; i < instances.length; i++) {
|
|
|
16 |
if (instances[i].contentId === contentId) {
|
|
|
17 |
return instances[i];
|
|
|
18 |
}
|
|
|
19 |
}
|
|
|
20 |
}
|
|
|
21 |
return undefined;
|
|
|
22 |
}
|
|
|
23 |
|
|
|
24 |
/**
|
|
|
25 |
* Finds the global instance from content id by looking through the DOM
|
|
|
26 |
*
|
|
|
27 |
* @param {number} [contentId] Content identifier
|
|
|
28 |
* @returns {Object} Content instance
|
|
|
29 |
*/
|
|
|
30 |
function getH5PInstance(contentId) {
|
|
|
31 |
var iframes;
|
|
|
32 |
var instance = null; // Returning null means no instance is found.
|
|
|
33 |
|
|
|
34 |
// No content id given, search for instance.
|
|
|
35 |
if (!contentId) {
|
|
|
36 |
instance = H5P.instances[0];
|
|
|
37 |
if (!instance) {
|
|
|
38 |
iframes = document.getElementsByClassName('h5p-iframe');
|
|
|
39 |
// Assume first iframe.
|
|
|
40 |
instance = iframes[0].contentWindow.H5P.instances[0];
|
|
|
41 |
}
|
|
|
42 |
} else {
|
|
|
43 |
// Try this documents instances.
|
|
|
44 |
instance = findInstanceInArray(H5P.instances, contentId);
|
|
|
45 |
if (!instance) {
|
|
|
46 |
// Locate iframes.
|
|
|
47 |
iframes = document.getElementsByClassName('h5p-iframe');
|
|
|
48 |
for (var i = 0; i < iframes.length; i++) {
|
|
|
49 |
// Search through each iframe for content.
|
|
|
50 |
instance = findInstanceInArray(iframes[i].contentWindow.H5P.instances, contentId);
|
|
|
51 |
if (instance) {
|
|
|
52 |
break;
|
|
|
53 |
}
|
|
|
54 |
}
|
|
|
55 |
}
|
|
|
56 |
}
|
|
|
57 |
|
|
|
58 |
return instance;
|
|
|
59 |
}
|
|
|
60 |
|
|
|
61 |
function getIframe(contentId) {
|
|
|
62 |
let iFrames;
|
|
|
63 |
|
|
|
64 |
// No content id given.
|
|
|
65 |
if (!contentId) {
|
|
|
66 |
iFrames = document.getElementsByClassName('h5p-iframe');
|
|
|
67 |
// Assume first iframe.
|
|
|
68 |
return iFrames[0];
|
|
|
69 |
}
|
|
|
70 |
|
|
|
71 |
// Locate iFrames.
|
|
|
72 |
iFrames = document.getElementsByClassName('h5p-iframe');
|
|
|
73 |
for (let i = 0; i < iFrames.length; i++) {
|
|
|
74 |
// Search through each iframe for content.
|
|
|
75 |
if (findInstanceInArray(iFrames[i].contentWindow.H5P.instances, contentId)) {
|
|
|
76 |
return iFrames[i];
|
|
|
77 |
}
|
|
|
78 |
}
|
|
|
79 |
|
|
|
80 |
return null;
|
|
|
81 |
}
|
|
|
82 |
|
|
|
83 |
/**
|
|
|
84 |
* Get xAPI data for content type and send off.
|
|
|
85 |
*
|
|
|
86 |
* @param {number} contentId Content id
|
|
|
87 |
* @param {Object} event Original xAPI event
|
|
|
88 |
*/
|
|
|
89 |
function storeXAPIData(contentId, event) {
|
|
|
90 |
var xAPIData;
|
|
|
91 |
var instance = getH5PInstance(contentId);
|
|
|
92 |
|
|
|
93 |
// Use getXAPIData contract, needed to get children.
|
|
|
94 |
if (instance && instance.getXAPIData) {
|
|
|
95 |
xAPIData = instance.getXAPIData();
|
|
|
96 |
} else {
|
|
|
97 |
// Fallback to event data.
|
|
|
98 |
xAPIData = {
|
|
|
99 |
statement: event.data.statement
|
|
|
100 |
};
|
|
|
101 |
}
|
|
|
102 |
|
|
|
103 |
// Ship the xAPI result.
|
|
|
104 |
var data = {
|
|
|
105 |
contentId: contentId,
|
|
|
106 |
xAPIResult: JSON.stringify(xAPIData)
|
|
|
107 |
};
|
|
|
108 |
$.post(H5PIntegration.ajax.xAPIResult, data).done(function (data) {
|
|
|
109 |
if (data.error) {
|
|
|
110 |
console.error('Storing xAPI results failed with error message:', data);
|
|
|
111 |
}
|
|
|
112 |
}).fail(function () {
|
|
|
113 |
if (H5P.offlineRequestQueue) {
|
|
|
114 |
H5P.offlineRequestQueue.add(H5PIntegration.ajax.xAPIResult, data);
|
|
|
115 |
return;
|
|
|
116 |
}
|
|
|
117 |
|
|
|
118 |
// Let H5P iframe know that we want to queue the request for late transmission.
|
|
|
119 |
const iframe = getIframe(contentId);
|
|
|
120 |
if (!iframe) {
|
|
|
121 |
return;
|
|
|
122 |
}
|
|
|
123 |
iframe.contentWindow.postMessage( {
|
|
|
124 |
url: H5PIntegration.ajax.xAPIResult,
|
|
|
125 |
data: data,
|
|
|
126 |
context: 'h5p',
|
|
|
127 |
action: 'queueRequest',
|
|
|
128 |
});
|
|
|
129 |
});
|
|
|
130 |
}
|
|
|
131 |
|
|
|
132 |
$(document).ready(function() {
|
|
|
133 |
// No external dispatcher.
|
|
|
134 |
if (!(window.H5P && H5P.externalDispatcher)) {
|
|
|
135 |
console.error('External dispatcher not found');
|
|
|
136 |
return;
|
|
|
137 |
}
|
|
|
138 |
|
|
|
139 |
// No ajax path.
|
|
|
140 |
if (!(window.H5PIntegration && H5PIntegration.ajax && H5PIntegration.ajax.xAPIResult)) {
|
|
|
141 |
console.error('No ajax path found');
|
|
|
142 |
return;
|
|
|
143 |
}
|
|
|
144 |
|
|
|
145 |
// Get emitted xAPI data.
|
|
|
146 |
H5P.externalDispatcher.on('xAPI', function(event) {
|
|
|
147 |
// Skip malformed events.
|
|
|
148 |
var hasStatement = event && event.data && event.data.statement;
|
|
|
149 |
if (!hasStatement) {
|
|
|
150 |
return;
|
|
|
151 |
}
|
|
|
152 |
|
|
|
153 |
var statement = event.data.statement;
|
|
|
154 |
var validVerb = statement.verb && statement.verb.display && statement.verb.display['en-US'];
|
|
|
155 |
if (!validVerb) {
|
|
|
156 |
return;
|
|
|
157 |
}
|
|
|
158 |
|
|
|
159 |
var isCompleted = statement.verb.display['en-US'] === 'answered' ||
|
|
|
160 |
statement.verb.display['en-US'] === 'completed';
|
|
|
161 |
var isChild = statement.context && statement.context.contextActivities &&
|
|
|
162 |
statement.context.contextActivities.parent &&
|
|
|
163 |
statement.context.contextActivities.parent[0] &&
|
|
|
164 |
statement.context.contextActivities.parent[0].id;
|
|
|
165 |
|
|
|
166 |
// Store only completed root events.
|
|
|
167 |
if (isCompleted && !isChild) {
|
|
|
168 |
// Get xAPI data with children if possible.
|
|
|
169 |
storeXAPIData(this.contentId, event);
|
|
|
170 |
}
|
|
|
171 |
});
|
|
|
172 |
});
|
|
|
173 |
})(H5P.jQuery);
|