mirror of
https://gh.llkk.cc/https://github.com/h5p/moodle-mod_hvp.git
synced 2026-03-04 13:36:41 +08:00
173 lines
5.7 KiB
JavaScript
173 lines
5.7 KiB
JavaScript
/**
|
|
* Collect results from xAPI events
|
|
*/
|
|
(function($) {
|
|
|
|
/**
|
|
* Finds a H5P library instance in an array based on the content ID
|
|
*
|
|
* @param {Array} instances
|
|
* @param {number} contentId
|
|
* @returns {Object|undefined} Content instance
|
|
*/
|
|
function findInstanceInArray(instances, contentId) {
|
|
if (instances !== undefined && contentId !== undefined) {
|
|
for (var i = 0; i < instances.length; i++) {
|
|
if (instances[i].contentId === contentId) {
|
|
return instances[i];
|
|
}
|
|
}
|
|
}
|
|
return undefined;
|
|
}
|
|
|
|
/**
|
|
* Finds the global instance from content id by looking through the DOM
|
|
*
|
|
* @param {number} [contentId] Content identifier
|
|
* @returns {Object} Content instance
|
|
*/
|
|
function getH5PInstance(contentId) {
|
|
var iframes;
|
|
var instance = null; // Returning null means no instance is found.
|
|
|
|
// No content id given, search for instance.
|
|
if (!contentId) {
|
|
instance = H5P.instances[0];
|
|
if (!instance) {
|
|
iframes = document.getElementsByClassName('h5p-iframe');
|
|
// Assume first iframe.
|
|
instance = iframes[0].contentWindow.H5P.instances[0];
|
|
}
|
|
} else {
|
|
// Try this documents instances.
|
|
instance = findInstanceInArray(H5P.instances, contentId);
|
|
if (!instance) {
|
|
// Locate iframes.
|
|
iframes = document.getElementsByClassName('h5p-iframe');
|
|
for (var i = 0; i < iframes.length; i++) {
|
|
// Search through each iframe for content.
|
|
instance = findInstanceInArray(iframes[i].contentWindow.H5P.instances, contentId);
|
|
if (instance) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return instance;
|
|
}
|
|
|
|
function getIframe(contentId) {
|
|
let iFrames;
|
|
|
|
// No content id given.
|
|
if (!contentId) {
|
|
iFrames = document.getElementsByClassName('h5p-iframe');
|
|
// Assume first iframe.
|
|
return iFrames[0];
|
|
}
|
|
|
|
// Locate iFrames.
|
|
iFrames = document.getElementsByClassName('h5p-iframe');
|
|
for (let i = 0; i < iFrames.length; i++) {
|
|
// Search through each iframe for content.
|
|
if (findInstanceInArray(iFrames[i].contentWindow.H5P.instances, contentId)) {
|
|
return iFrames[i];
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Get xAPI data for content type and send off.
|
|
*
|
|
* @param {number} contentId Content id
|
|
* @param {Object} event Original xAPI event
|
|
*/
|
|
function storeXAPIData(contentId, event) {
|
|
var xAPIData;
|
|
var instance = getH5PInstance(contentId);
|
|
|
|
// Use getXAPIData contract, needed to get children.
|
|
if (instance && instance.getXAPIData) {
|
|
xAPIData = instance.getXAPIData();
|
|
} else {
|
|
// Fallback to event data.
|
|
xAPIData = {
|
|
statement: event.data.statement
|
|
};
|
|
}
|
|
|
|
// Ship the xAPI result.
|
|
var data = {
|
|
contentId: contentId,
|
|
xAPIResult: JSON.stringify(xAPIData)
|
|
};
|
|
$.post(H5PIntegration.ajax.xAPIResult, data).done(function (data) {
|
|
if (data.error) {
|
|
console.error('Storing xAPI results failed with error message:', data);
|
|
}
|
|
}).fail(function () {
|
|
if (H5P.offlineRequestQueue) {
|
|
H5P.offlineRequestQueue.add(H5PIntegration.ajax.xAPIResult, data);
|
|
return;
|
|
}
|
|
|
|
// Let H5P iframe know that we want to queue the request for late transmission.
|
|
const iframe = getIframe(contentId);
|
|
if (!iframe) {
|
|
return;
|
|
}
|
|
iframe.contentWindow.postMessage( {
|
|
url: H5PIntegration.ajax.xAPIResult,
|
|
data: data,
|
|
context: 'h5p',
|
|
action: 'queueRequest',
|
|
});
|
|
});
|
|
}
|
|
|
|
$(document).ready(function() {
|
|
// No external dispatcher.
|
|
if (!(window.H5P && H5P.externalDispatcher)) {
|
|
console.error('External dispatcher not found');
|
|
return;
|
|
}
|
|
|
|
// No ajax path.
|
|
if (!(window.H5PIntegration && H5PIntegration.ajax && H5PIntegration.ajax.xAPIResult)) {
|
|
console.error('No ajax path found');
|
|
return;
|
|
}
|
|
|
|
// Get emitted xAPI data.
|
|
H5P.externalDispatcher.on('xAPI', function(event) {
|
|
// Skip malformed events.
|
|
var hasStatement = event && event.data && event.data.statement;
|
|
if (!hasStatement) {
|
|
return;
|
|
}
|
|
|
|
var statement = event.data.statement;
|
|
var validVerb = statement.verb && statement.verb.display && statement.verb.display['en-US'];
|
|
if (!validVerb) {
|
|
return;
|
|
}
|
|
|
|
var isCompleted = statement.verb.display['en-US'] === 'answered' ||
|
|
statement.verb.display['en-US'] === 'completed';
|
|
var isChild = statement.context && statement.context.contextActivities &&
|
|
statement.context.contextActivities.parent &&
|
|
statement.context.contextActivities.parent[0] &&
|
|
statement.context.contextActivities.parent[0].id;
|
|
|
|
// Store only completed root events.
|
|
if (isCompleted && !isChild) {
|
|
// Get xAPI data with children if possible.
|
|
storeXAPIData(this.contentId, event);
|
|
}
|
|
});
|
|
});
|
|
})(H5P.jQuery);
|