Every once in a while I have to wrap something in SCORM. Its not terribly often but it happens maybe about twice a year. This time around it was a Flash-based training module for a local hospital. Applying the SCORM wrapper has become rather blasé; I apply the wrapper, tell the devs what JS functions to call, tell them how to get data out of the LMS, test and then deploy.

Well, this latest training module contained unique features such as mini-games, related data, and user-selectable items. We needed to be able to save all of this data into the LMS and then retrieve the data and hand it off to the SCO so that not only would it resume from where it left off but that the previous game state would also be reflected within its UI.

The plan here was to convert the data to JSON and then store it in cmi.suspend_data. In SCORM 1.2 the suspend_data element has a maximum capacity of 4,096 characters – plenty for our needs.

Storing the data

My function for receiving the JSON payload from Flash and storing it looked similar to this:

// The data is already stringified within the Flash movie and then passed to this function
function storeSuspendData(str){
     LMSSetValue('cmi.suspend_data',str);
}

Immediately this caused an issue which turns out is due to the double-quotes that are part of JSON formatting. In order to be able to successfully insert JSON into the LMS I had to replace all the double-quotes with some other character. I chose to use an asterisk.

My function then turned into something like this:

// The data is already stringified within the Flash movie and then passed to this function
function storeSuspendData(str){
    LMSSetValue('cmi.suspend_data',str.replace(/\"/g,'*'));
}

Here’s some sample JSON:

{"icon":"car","color":"red",{"quizzes":[{"quiz":1,"score":75},{"quiz":2,"score":85},{"quiz":3,"score":95}]}}

And here’s the psuedo-JSON after the search and replace:

{*icon*:*car*,*color*:*red*,{*quizzes*:[{*quiz*:1,*score*:75},{*quiz*:2,*score*:85},{*quiz*:3,*score*:95}]}}

This allowed me to store the data within cmi.suspend_data without issue.

Retrieving the data

Somewhere in all of this an extra set of double quotes were added to the JSON – to the beginning and to the end of the string so that in reality the psuedo-JSON looked like this in the LMS:

*{*icon*:*car*,*color*:*red*,{*quizzes*:[{*quiz*:1,*score*:75},{*quiz*:2,*score*:85},{*quiz*:3,*score*:95}]}}*

My function to get the data out of the LMS at first didn’t account for the beginning and trailing asterisk:

function getSuspendData(str){
    var val = LMSGetValue('cmi.suspend_data').replace(/\*/g,'"");
    return val;
}

Which gave me some bad JSON (note the leading and trailing double-quotes):

"{"icon":"car","color":"red",{"quizzes":[{"quiz":1,"score":75},{"quiz":2,"score":85},{"quiz":3,"score":95}]}}"

So I had to clean that up:

function getSuspendData(str){
    var val = LMSGetValue('cmi.suspend_data').replace(/\*/g,'"');
    val = val.substr(1,val.length);
    val = val.substr(0,val.length - 1);
    return val;
}

When I ran a JSON.parse on my now valid JSON and logged it to the console I could see a bonafide JS object.

Passing the JSON to Flash

The next step was to provide the JSON to flash and we decided to use FlashVars but that came with a problem. Flash vars is simply HTML and HTML attributes use double-quotes. In the sample below you can see the problem right away when the HTML for the Flash object was written to the page:

<param name="FlashVars" value="gameData="{"icon":"car","color":"red",{"quizes":[{"quiz":1,"score":75},{"quiz":2,"score":85},{"quiz":3,"score":95}]}}"" />

Obviously JSON’s double quotes are breaking the HTML. The solution was to not do the search/replace of the previous asterisks – I changed things so that Flash would receive the pusedo-JSON via the FlashVar which meant that the string clean-up would have to happen within Flash.

My updated “get” function looked similar to this:

function getSuspendData(str){
    var val = LMSGetValue('cmi.suspend_data');
    val = val.substr(1,val.length);
    val = val.substr(0,val.length - 1);
    return val;
}

And the FlashVar became valid HTML:

<param name="FlashVars" value="gameData=*{*icon*:*car*,*color*:*red*,{*quizes*:[{*quiz*:1,*score*:75},{*quiz*:2,*score*:85},{*quiz*:3,*score*:95}]}}*" />

And then finally in Flash I simply did the search and replace on the asterisk back to double-quotes and then did a JSON.parse to transform the string into a useful object.