Captivate SCORM 2004 Output, preventing redundant GetLastError calls
/*global CaptivateSWF */ | |
var SCORM_API = null, | |
unloaded = false, | |
isInitialized = false, | |
isTerminated = false, | |
courseStatus, | |
value_store = [], | |
lastCommand, | |
setValueWasSuccessful = true; | |
/* | |
cmiCache(property, value) | |
Caches CMI value to help prevent sending duplicate data to LMS | |
Parameters: property (CMI property name), value (CMI value, normally a string) | |
Returns: property value if cached version found, false if not cached. | |
*/ | |
var cmiCache = function(property, value){ | |
//Ensure we have a valid property to work with | |
if(typeof property === "undefined"){ return false; } | |
//Replace all periods in CMI property names so we don't run into JS errors | |
property = property.replace(/\./g,'_'); | |
//If cached value exists, return it | |
if(typeof value_store[property] !== "undefined"){ | |
return value_store[property]; | |
} | |
//Otherwise add to cache | |
if(typeof value !== "undefined"){ | |
value_store[property] = value; | |
} | |
return false; | |
}; | |
/* | |
findAPI(window) | |
Adapted from pipwerks SCORM wrapper | |
https://github.com/pipwerks/scorm-api-wrapper | |
Looks for an object named API in parent and opener windows | |
Parameters: window (the browser window object). | |
Returns: Object if API is found, null if no API found | |
*/ | |
var findAPI = function(win){ | |
var API, | |
findAttempts = 0, | |
findAttemptLimit = 500; | |
while (!win.API_1484_11 && win.parent && win.parent != win && findAttempts <= findAttemptLimit){ | |
findAttempts++; | |
win = win.parent; | |
} | |
API = win.API_1484_11 || null; | |
/* | |
if(!API){ | |
alert("Error finding API. \nFind attempts: " +findAttempts +". \nFind attempt limit: " +findAttemptLimit); | |
} | |
*/ | |
return API; | |
}; | |
/* | |
getAPI() | |
Adapted from pipwerks SCORM wrapper | |
https://github.com/pipwerks/scorm-api-wrapper | |
Looks for an object named API_1484_11, first in the current window's frame | |
hierarchy and then, if necessary, in the current window's opener window | |
hierarchy (if there is an opener window). | |
Parameters: None. | |
Returns: Object if API found, null if no API found | |
*/ | |
var getAPI = function(){ | |
var API = null, | |
win = window; | |
//Look in parent windows first | |
if(win.parent && win.parent != win){ | |
API = findAPI(win.parent); | |
} | |
//Look in opener windows next | |
if(!API && win.top.opener){ | |
API = findAPI(win.top.opener); | |
} | |
//Plateau LMS needs special hand-holding | |
if(!API && win.top.opener && win.top.opener.document) { | |
API = findAPI(win.top.opener.document); | |
} | |
//if(!API){ alert("getAPI failed: Can't find the API!"); } | |
return API; | |
}; | |
var Captivate_DoExternalInterface = function (command, parameter, value, variable) { | |
console.log("Captivate_DoExternalInterface: " +command +", " +parameter +", " +value); | |
var strErr = "true", | |
intercept = false; | |
//Ensure SCORM API was initialized | |
if(!isInitialized){ return; } | |
if(command === "Initialize"){ | |
//We already initialized, just nod politely | |
//and tell the SWF everything is okay! | |
} else if(command === "SetValue"){ | |
if(parameter === "completion_status"){ courseStatus = value; } | |
//Check to see if value is already cached | |
var cached_value = cmiCache(parameter, value); | |
//Only send value to LMS if it hasn't already been sent; | |
//If value is cached and matches what is about to be sent | |
//to the LMS, prevent value from being sent a second time. | |
if(!cached_value || cached_value !== value){ | |
console.log(parameter +"(" +value +") is not cached. Sending to LMS."); | |
strErr = SCORM_API.SetValue(parameter, value); | |
setValueWasSuccessful = (strErr === "true"); | |
} else { | |
console.log(parameter +"(" +value +") has already been sent. Preventing redundant LMS communication."); | |
//Fakin' it for Captivate's sake. | |
setValueWasSuccessful = true; | |
} | |
} else if(command === "Terminate"){ | |
strErr = SCORM_API.Terminate(""); | |
isTerminated = (strErr === "true"); | |
} else if(command === "Commit"){ | |
strErr = SCORM_API.Commit(""); | |
} else if(command === "GetLastError"){ | |
if(lastCommand === "SetValue" && setValueWasSuccessful){ | |
strErr = ""; | |
console.log("Last Get/Set was successful. Preventing pointless GetLastError invocation."); | |
} else { | |
strErr = SCORM_API.GetLastError(); | |
} | |
} else if(value && value.length > 0){ | |
strErr = SCORM_API[command](parameter); | |
} | |
CaptivateSWF.SetScormVariable(variable, strErr); | |
lastCommand = command; | |
return strErr; | |
}; | |
var initializeSCORM = function (){ | |
isInitialized = SCORM_API.Initialize(""); | |
if(isInitialized){ | |
console.log("SCORM initialized. Ready to go!"); | |
courseStatus = SCORM_API.GetValue("cmi.completion_status"); | |
if(courseStatus === "not attempted"){ | |
SCORM_API.SetValue("cmi.completion_status", "incomplete"); | |
} | |
} | |
}; | |
var unloadHandler = function (){ | |
if(!unloaded && isInitialized && !isTerminated){ | |
var exit_status = (courseStatus === "incomplete") ? "suspend" : "normal"; | |
SCORM_API.SetValue("cmi.exit", exit_status); //Set exit to whatever is needed | |
SCORM_API.Commit(""); //Ensure that LMS saves all data | |
isTerminated = (SCORM_API.Terminate("") === "true"); //close the SCORM API connection properly | |
unloaded = true; //Ensure we don't invoke unloadHandler more than once. | |
} | |
}; | |
window.onbeforeunload = unloadHandler; | |
window.onunload = unloadHandler; | |
//Initialize SCORM API | |
SCORM_API = getAPI(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment