Skip to content

Instantly share code, notes, and snippets.

@dcollien
Last active May 5, 2020 12:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dcollien/3747293f5dc451d7c78ccdc2d6d081c8 to your computer and use it in GitHub Desktop.
Save dcollien/3747293f5dc451d7c78ccdc2d6d081c8 to your computer and use it in GitHub Desktop.
xAPI iFrame Example
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>xAPI Form Example</title>
<!-- xAPI base functionality, from: https://github.com/RusticiSoftware/TinCanJS/blob/master/build/tincan-min.js -->
<script src="tincan-min.js"></script>
<!-- Setting up the xAPI connection from launch data -->
<script src="xapi-interface.js"></script>
<!-- Functionality for enabling form submission over xAPI -->
<script src="xapi-form-submit.js"></script>
</head>
<body>
<form id="dataform" >
<input type="text" name="testInput"/>
<input type="submit" value="Submit" id="submit-button">
</div>
<divid="status-message">
Form has been submitted.
</div>
</form>
<!-- Initialise functionality -->
<script>
// Find the status box labelled with the id "status"
var statusBox = document.getElementById("status-message");
// Hide this box
statusBox.style.display = "none";
// Find the form element labelled with the id "dataform"
var form = document.getElementById("dataform");
// Find the submit button
var submitButton = document.getElementById("submit-button");
// Function to run when the form is about to be submitted
var onSubmitStart = function(formData) {
// Hide the status box
statusBox.style.display = "none";
// Disable the submit button
submitButton.disabled = true;
};
// Function to run when the form has been submitted
var onSubmitComplete = function(error, formData, response) {
if (error) {
// Submission couldn't complete
// Show error message
alert("Unable to submit form. Try again later.");
console.log(error, formData, response);
} else {
// Submission succeeded
// Show the status box
statusBox.style.display = "";
}
// Re-enable the submit button
submitButton.disabled = false;
};
// Initialise the xAPI functionality and submit the data
// over xAPI when this form is submitted
initXApiForm(form, onSubmitStart, onSubmitComplete);
</script>
</body>
</html>
var ADL_VERBS_ROOT = "http://adlnet.gov/expapi/verbs/";
var OL_EXTENSIONS_ROOT = "https://xapi.openlearning.com/extensions/";
var LRS_CONFIG = initLrs();
function completedStatement(config, formData) {
var ol_extensions = {};
ol_extensions[OL_EXTENSIONS_ROOT + "submission-data"] = formData;
return new TinCan.Statement({
actor: config.actor, // the actor data sent by OpenLearning
object: {
id: config.activity_id, // the activity_id sent by OpenLearning
objectType: "Activity"
},
context: {
registration: config.registration // the registration sent by OpenLearning
},
verb: {
id: ADL_VERBS_ROOT + "completed",
display: {
"de-DE" : "beendete",
"en-US" : "completed",
"fr-FR" : "a terminé",
"es-ES" : "completó"
},
},
result: {
completion: true,
extensions: ol_extensions
}
});
}
function formToObject(form) {
var formData = new FormData(form);
var object = {};
formData.forEach(function(value, key) {
if (!object.hasOwnProperty(key)) {
object[key] = value;
return;
}
if (!Array.isArray(object[key])) {
object[key] = [object[key]];
}
object[key].push(value);
});
return object;
}
function submitFormObject(formObject) {
if (!LRS_CONFIG) {
return new Promise(function(resolve, reject) {
return reject({
error: 'No LRS configured in the URL.',
xhr: null
});
});
}
var lrs = LRS_CONFIG.lrs;
var statement = completedStatement(LRS_CONFIG, formObject);
return saveStatement(lrs, statement);
}
function submitForm(form, startCallback, completeCallback) {
var formObject = formToObject(form);
startCallback(formObject);
submitFormObject(formObject).then(
function(xhr) {
completeCallback(null, formObject, xhr);
},
function(errorResult) {
completeCallback(errorResult.error, formObject, errorResult.xhr);
}
);
}
function xApiFormSubmit(startCallback, completeCallback) {
return function(event) {
event.preventDefault();
submitForm(event.currentTarget, startCallback, completeCallback);
};
}
function initXApiForm(form, onSubmitStart, onSubmitComplete) {
form.addEventListener("submit", xApiFormSubmit(onSubmitStart, onSubmitComplete));
}
function initLrs() {
// xAPI configuration is sent in the URL query string parameters
var urlParams = new URLSearchParams(window.location.search);
var endpoint = urlParams.get('endpoint');
var auth = urlParams.get('auth');
var actor = JSON.parse(urlParams.get('actor')); // this needs to be JSON decoded
var activity_id = urlParams.get('activity_id');
var registration = urlParams.get('registration');
if (!endpoint) {
return null;
}
var lrs = new TinCan.LRS({
endpoint: endpoint,
auth: auth
});
return {
"lrs": lrs,
"actor": actor,
"activity_id": activity_id,
"registration": registration
};
}
function saveStatement(lrs, statement) {
return new Promise(function(resolve, reject) {
lrs.saveStatement(statement, {
callback: function(error, xhr) {
if (error) {
reject({
error: error,
xhr: xhr
});
} else {
resolve(xhr);
}
}
});
});
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment