SCORM and Flash: Getting started

This is the JavaScript for the the alms_sco.js file. This is part of the full tutorial available from Alpha LMS' Briefings page.

//these four variables, along with the two functions ScanForAPI and

var nFindAPITries = 0;
var API = null;
var maxTries = 500;
var APIVersion = "";

//some string variables to avoid repeat typing of text in the code

var STR_SETTING = "setting ";
var STR_SCORERAW = "cmi.core.score.raw";
var STR_SCOREMAX = "cmi.core.score.max";
var STR_LESSONSTATUS= "cmi.core.lesson_status";
var STR_EXIT = "cmi.core.exit";
var STR_WITHVALUE = " with value ";

//GetAPI are given in then SCORM documentation as the recommended
//way of locating the API in either an opener or parent window

function ScanForAPI(win) {

while ((win.API == null)
&& (win.parent != null)
&& (win.parent != win)) {

nFindAPITries++;
if (nFindAPITries > maxTries) {

alert("Error in finding API instance -- too deeply nested.");
return null;

}
win = win.parent;

}
return win.API;

}

function GetAPI() {

if ((window.parent != null) && (window.parent != window)) {


API = ScanForAPI(window.parent);

}
if ((API == null) && (window.opener != null)) {

API = ScanForAPI(window.opener);

}

}

//Here are two utilities: one to handle error-checking and one to
//find whether the LMS supports a particular data field. This
//function should be called after every call to the API

function scormCheckError(context) {

var errorCode = API.LMSGetLastError();
if (errorCode != 0) {

alert("Error " + context + ": " + API.LMSGetErrorString(errorCode));

}

}

//scormFindChild is a utility which checks to see whether the value
//child exists within the comma-separated list of children. Some data
//fields do not have to be supported by an LMS. This is the way of
//checking whether a feature is supported before using it.
//See scormClose() for the use of this function.

function scormFindChild(childElement, child) {

var isFound = false;
var children = API.LMSGetValue(childElement);
var childArray = new Array();
childArray = children.split(",");
scormCheckError("getting children for " + children);
for (var i=0; (i<childArray.length); i++) {

if (childArray[i] == child) {

isFound = true;
break;

}

}
return isFound;

}


//here is code to support our assessment model. If an API object is
//found, LMSInitialize must be called first and LMSFinish last. You
//will normally call LMSCommit before LMSFinish to ensure that all
//values are persisted. In between these, we may call LMSSetValue,
//to pass data back to the LMS, LMSGetValue to read data from the
//LMSGetLastError and LMSGetErrorString if things go wrong. We will
//use three functions: ScormInitialize to get things going, ScormCommand to
//deal with the fscommand events occurring in the Flash animation, and
//ScormClose to tidy up at the end.

//ScormClose might be called in one of two ways: (a) when the Flash
//movie finishes and issues an fscommand("finish", ""); or if the student
//closes the browser window before finishing. To avoid calling ScormClose
//twice, we need to track whether our scorm session is active.

var scormActive = false;

//these variables will keep track of the student's progress through the SCO
var marksTotal; //will be set in the SCO's html
var marksDone = 0;
var marksScored = 0;
var scormStatus = "not attempted";
var marksReturned = false;

//scormStart() will get called whenever our html page loads
function scormStart() {

GetAPI();
if (API != null) {

API.LMSInitialize("");
scormCheckError("initializing API");
scormActive = true;
//we might load bookmarking information here, but we'll leave that for
//next time

}

}

//scormClose will get called at the end, either when the movie finishes or
//when the student closes the window without finishing the movie. We will
//return some minimum information: score, status, exit and marksDone. These
//fields are all mandatory fields for the LMS, except for core.score.max,
//Before returning core.score.max we need to find whether this is supported
//by the LMS
function scormClose() {

if (scormActive) {

//prevent closing twice
scormActive = false;
//return normalized score
if (marksTotal > 0) {

//under SCORM 1.2, raw score is always returned as a
//normalized percentage

alert("Setting scoreRaw: marksScored = " + marksScored + "; marksTotal = " + marksTotal);
var scoreRaw = (marksScored / marksTotal) * 100;
alert("ScoreRaw = " + scoreRaw);
API.LMSSetValue(STR_SCORERAW, scoreRaw);
scormCheckError(STR_SETTING + STR_SCORERAW + STR_WITHVALUE + scoreRaw);

}
//return max score (what the student could have scored if he got all
//questions presented right

if ((marksTotal > 0) && (scormFindChild("cmi.core.score._children", "max"))) {

var maxScore = (marksScored / marksTotal) * 100;
alert("maxScore = " + maxScore);
API.LMSSetValue(STR_SCOREMAX, maxScore);
scormCheckError(STR_SETTING + STR_SCOREMAX + STR_WITHVALUE + maxScore);

}
//set lesson_status
if (marksReturned) {

if (marksDone = marksTotal) {

scormStatus = "completed";

} else {

scormStatus = "incomplete";

}

} else {

scormStatus = "browsed";

}
API.LMSSetValue(STR_LESSONSTATUS, scormStatus);
scormCheckError(STR_SETTING + STR_LESSONSTATUS + STR_WITHVALUE + scormStatus);
//set normal exit
API.LMSSetValue("cmi.core.exit", "");
scormCheckError(STR_SETTING + STR_EXIT + STR_WITHVALUE);
//commit and finish

API.LMSCommit("");
scormCheckError("committing to API");
API.LMSFinish("");
scormCheckError("finishing SCORM session");

}

}

//scormCommand will deal with the fscommand messages from the movie
//we will not pass this data to the LMS, but just keep tote of the score
//in local JavaScript variables until the time comes to finish the unit
function scormCommand(command, params) {

if (command == "mark") {


marksReturned = true;
var paramArray = new Array();
paramArray = params.split(",");
if (paramArray.length != 3) {

alert("Error: mark command must have three parameters");

} else {

if (paramArray[1] > paramArray[2]) {

alert("Error: cannot score more than total marks available");

} else {

//we will ignore question numbers for the time being
var newMarksDone = marksDone + eval(paramArray[2]);
if (newMarksDone > marksTotal) {

alert("Error: marks done cannot be more than total marks");

} else {

marksDone = newMarksDone;
marksScored += eval(paramArray[1]);

}

}

}

} else {

if (command == "finish") {

scormClose();

}

}

}

Home