Skip to content

Instantly share code, notes, and snippets.

@pipwerks
Created January 17, 2012 07:06
Show Gist options
  • Select an option

  • Save pipwerks/1625367 to your computer and use it in GitHub Desktop.

Select an option

Save pipwerks/1625367 to your computer and use it in GitHub Desktop.

Revisions

  1. pipwerks revised this gist Jan 25, 2012. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion sample.htm
    Original file line number Diff line number Diff line change
    @@ -1,6 +1,6 @@
    <!-- Copyright [2008] Adobe Systems Incorporated. All rights reserved -->
    <!-- saved from url=(0013)about:internet -->
    <!DOCTYPE HTML">
    <!DOCTYPE HTML>
    <html lang="en">
    <head>
    <meta charset="utf-8" />
  2. pipwerks revised this gist Jan 18, 2012. 1 changed file with 4 additions and 2 deletions.
    6 changes: 4 additions & 2 deletions sample.htm
    Original file line number Diff line number Diff line change
    @@ -42,8 +42,10 @@

    } else {

    //Provide a useful error message for the learner. Will only show up if SCORM API is not found!
    document.getElementById("CaptivateContent").innerHTML = "Sorry, but the course is not available at this time (SCORM API not found). Please try again. If you continue to encounter problems, please contact the course administrator.";
    //Provide a useful error message for the learner. Will only show up if SCORM API is not found!
    swfobject.addDomLoadEvent(function(){
    document.getElementById("CaptivateContent").innerHTML = "Sorry, but the course is not available at this time (SCORM API not found). Please try again. If you continue to encounter problems, please contact the course administrator.";
    });

    }

  3. pipwerks revised this gist Jan 18, 2012. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion scorm_support.js
    Original file line number Diff line number Diff line change
    @@ -105,7 +105,7 @@ var getAPI = function(){
    }

    //Plateau LMS needs special hand-holding
    if(!API && win.top.opener.document) {
    if(!API && win.top.opener && win.top.opener.document) {
    API = findAPI(win.top.opener.document);
    }

  4. pipwerks created this gist Jan 17, 2012.
    61 changes: 61 additions & 0 deletions sample.htm
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,61 @@
    <!-- Copyright [2008] Adobe Systems Incorporated. All rights reserved -->
    <!-- saved from url=(0013)about:internet -->
    <!DOCTYPE HTML">
    <html lang="en">
    <head>
    <meta charset="utf-8" />
    <title></title>
    <script src="https://ajax.googleapis.com/ajax/libs/swfobject/2.2/swfobject.js"></script>
    <script src="standard.js"></script>
    <script src="SCORM_support/scorm_support.js"></script>
    <script>

    /*global swfobject, SCORM_API, initializeSCORM */

    // set document.domain property here, if it works for your environment/SCORM implementation
    // document.domain="";
    var strURLFile = "sample.swf", // Name of the flash file
    flashvars = {},
    params = { bgcolor: "#f5f4f1", menu: "false" },
    attributes = { id: "Captivate", name: "Captivate" },
    CaptivateSWF; //Cache the reference to the SWF to avoid future lookups


    function callbackFn(e){
    //e.ref is the <object> aka SWF file. No need for getElementById
    if(e.success && e.ref){
    CaptivateSWF = e.ref;
    CaptivateSWF.tabIndex = -1; //Set tabIndex to enable focus on non-form elements
    CaptivateSWF.focus();

    //Initialze the SCORM API, don't wait for the SWF to do it.
    initializeSCORM();
    }
    }

    //Only embed SWF if SCORM API is found
    if(SCORM_API){

    //swfobject.embedSWF has a built-in domready call,
    //so it doesn't need to be wrapped in a window.onload event.
    swfobject.embedSWF(strURLFile + "?SCORM_API=1.0&SCORM_TYPE=0", "CaptivateContent", "641", "512", "10", false, flashvars, params, attributes, callbackFn);

    } else {

    //Provide a useful error message for the learner. Will only show up if SCORM API is not found!
    document.getElementById("CaptivateContent").innerHTML = "Sorry, but the course is not available at this time (SCORM API not found). Please try again. If you continue to encounter problems, please contact the course administrator.";

    }

    </script>
    <style>
    body { background: #f5f4f1; text-align: center; }
    </style>
    </head>
    <body>
    <div id="CaptivateContent"></div>
    <noscript>
    This course requires JavaScript to be enabled in your browser. Please enable JavaScript, then relaunch the course.
    </noscript>
    </body>
    </html>
    218 changes: 218 additions & 0 deletions scorm_support.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,218 @@
    /*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.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();