Send Captivate Quiz Data to JavaScript

Adobe Captivate 3 doesn’t have a built-in mechanism for sending quiz results to JavaScript.  Here’s a workaround you may find useful.

The plan

The basic premise of this workaround is to hijack Captivate’s ‘email report’ functionality, replacing the original email-centered JavaScript with new JavaScript.  This approach was also used in an Adobe article named Storing Captivate Test Scores in a Database and Exporting Them To Excel with ColdFusion.

My goals for this project were to:

  • Get all available quiz data from Captivate
  • Put the data into an easy-to-access JavaScript object
  • Remove as much of the original Captivate JavaScript as possible, leaving a cleaner global space
  • Use SWFObject (currently SWFObject 2.1) to embed the Captivate SWF

Here’s a working example.  There is a link to a ZIP containing the source files (including a template) at the end of this article.

What data can I get from Captivate?

Captivate is a fickle friend, and only gives us a few pieces of data: status, location, raw score, max score, min score, and time.

Here’s a sample of what Captivate sends to JavaScript when using the email reporting option:

Core Data|”Status”,”Location”,”Raw Score”,”Max Score”,”Min Score”,”Time”|”passed”,”3″,”30″,”30″,”0″,”00:00:17″||Interaction Data|”Date”,”Time”,”Interaction ID”,”Objective ID”,”Interaction Type”,”Correct Response”,”Student Response”,”Result”,”Weight”,”Latency”

This string contains two primary elements: the Core Data element, and the Interaction Data element.  These elements are separated by two vertical bars (||). The Core Data portion of the string is:

“Status”,”Location”,”Raw Score”,”Max Score”,”Min Score”,”Time”|”passed”,”3″,”30″,”30″,”0″,”00:00:17″

Notice how the Core Data portion contains headers to the left of the vertical bar (|) and data to the right of the bar.  Now look at the Interaction Data portion of the string:

“Date”,”Time”,”Interaction ID”,”Objective ID”,”Interaction Type”,”Correct Response”,”Student Response”,”Result”,”Weight”,”Latency”

Notice there is no interaction data, only interaction headers. Although Captivate can track interactions, for some reason the interaction data was not coming across in my tests.  The headers were coming across, but the data wasn’t.  If any of you figure out why, drop me a line.

For now, we’ll just focus on the Core Data.

Step 1: Create and configure your Captivate file

Create a Captivate quiz containing a few questions (you can also use my example contained in the ’source files’ ZIP). Make sure all of your questions have the “report answers” option checked.

There are a few important settings to change in your quiz preferences.  First of all, go to Quiz > Quiz Preferences. Change your Reporting settings to match the screenshot: “Enable reporting” is checked, “E-mail” is checked, an email address is entered (Captivate checks to see if a well-formed email is found when using this option; you could probably use something fake such as 123@abc.com), “Quiz results only” is checked, and “Report score” is checked.

Captivate 3 Quiz preferences: Reporting (screenshot)

Captivate 3 Quiz preferences: Reporting

Next go to the Settings preferences. For this example, I unchecked “Allow backward movement” and “Allow user to review quiz.”  This is up to you, it doesn’t affect the JavaScript; I just wanted my quiz to be as simple as possible from a UI standpoint.

Captivate 3 Quiz preferences: settings

Captivate 3 Quiz preferences: Settings

While on the Settings screen, click the Quiz Result Messages button. A popup will appear; change “Email button text” to whatever you like. For this example, I changed it to “Send quiz results to JavaScript.”  You might choose to use something such as “Submit quiz results.” It’s important to note that the quiz results are only sent to JavaScript when the user clicks this button, so make sure your instructions are clear.

Captivate Quiz preferences: Result messages (screenshot)

Captivate Quiz preferences: Result messages

In the Pass or Fail settings, I set the passing and failing actions to “No Action.” Remember, the quiz results are only sent to JavaScript when the user clicks the “Send quiz results to JavaScript” button.

Captivate 3 Quiz preferences: Pass or Fail (screenshot)

Captivate 3 Quiz preferences: Pass or Fail

By default, Captivate inserts a “Continue” button on the results page at the end of a quiz.  Clicking “Continue” will cause the movie to resume playing (un-pause). Since we don’t want the user to click “Continue” before clicking the “Send quiz results to JavaScript” button, we should get rid of the “Continue” button.  However, due to  Captivate’s typical quirkiness, it appears you can’t simply delete the “Continue” button.  My solution was to make the button transparent with white text, then shrink it as small as possible and stick it off in a corner where no one will click it.

The end result looks like this:

Captivate quiz results screen (screenshot)

Captivate quiz results screen (screenshot)

Publish the Captivate file. You can uncheck the “Export HTML” options since we’re going to use our own HTML.

Step 2: Prepare the HTML file

Create a blank HTML page.  Give it whatever title you like.  Embed your SWF using your embed method of choice; I use SWFObject. My Captivate-generated SWF is named “quiz_report-score-only.swf”.  Your HTML code should look something like this:

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
   <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
   <title>Captivate score in JavaScript</title>
   <script type="text/javascript" src="swfobject.js"></script>
   <script type="text/javascript">
      //Embed the SWF in the HTML
      swfobject.embedSWF("quiz_report-score-only.swf", "capQuiz", "640", "480", "7");
   </script>
</head>
<body>
   <h1>Captivate score in JavaScript</h1>
   <div id="capQuiz">
     <p>If you're seeing this message, you need to install or update your Flash Player</p>
   </div>
</body>
</html>

Your code may look different if you use a different embed method, but the point is to have a clean HTML file with no extraneous JavaScript and no unnecessary markup.

Once you’ve tested your file to make sure the SWF loads and plays correctly, move on to step 3.

Step 3: Add the custom JavaScript

Converter function

I’ve prepared a function (pipwerks.UTILS.convertCaptivateEmailData) that converts Captivate’s ‘email’ string to an object. This function has been saved in a compressed (<1kb) external file named pipwerks.UTILS.convertCaptivateEmailData.js. Without getting into the boring details, the function splits the string into arrays then merges the arrays into an object.  It contains error-checking, and also does a little housecleaning along the way, such as removing quotes and converting property names to lowercase.

Let’s add a link to pipwerks.UTILS.convertCaptivateEmailData.js in our HTML file so we can take advantage of this function later on:

<head>
   <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
   <title>Captivate score in JavaScript</title>
   <script type="text/javascript" src="pipwerks.UTILS.convertCaptivateEmailData.js"></script>
   <script type="text/javascript" src="swfobject.js"></script>
   <script type="text/javascript">
      //Embed the SWF in the HTML
      swfobject.embedSWF("quiz_report-score-only.swf", "capQuiz", "640", "480", "7");
   </script>
</head>

Replacements for Captivate’s email functions

Next, we’ll replace the ‘report via email’ JavaScript functions invoked by the Captivate SWF. We’ll place these functions in the <head>, just before the SWFObject embed.

<head>
   <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
   <title>Captivate score in JavaScript</title>
   <script type="text/javascript" src="pipwerks.UTILS.convertCaptivateEmailData.js"></script>
   <script type="text/javascript" src="swfobject.js"></script>
   <script type="text/javascript">

      function appendEmailBody(){} //nothing to see here, move along!
      function sendMail(){}        //nothing to see here, move along!

      function padMail(strAddress, strSubject, strBody) {
         //The important stuff will go here
      }

      //Embed the SWF in the HTML
      swfobject.embedSWF("quiz_report-score-only.swf", "capQuiz", "640", "480", "7");
   </script>
</head>

As you can see, there are three Captivate-generated JavaScript functions;  while we don’t need the first two functions (appendEmailBody and sendMail), they’re included here to ensure the Captivate SWF doesn’t throw any errors by invoking a function that doesn’t exist.

The star of the show is the padMail function.  It accepts three parameters, of which we only need the third parameter: strBody. This string was meant to be inserted into the body of the email message, and contains all the important quiz information.

To get the data into a useable JavaScript object, just pass the strBody parameter along to our helper function pipwerks.UTILS.convertCaptivateEmailData; the function will return an object you can use in your course.

function padMail(strAddress, strSubject, strBody) {

   //Forward parameter strBody to our custom function.
   var quiz = pipwerks.UTILS.convertCaptivateEmailData(strBody);

   //Do something with 'quiz' object
   alert("score: " +quiz.rawscore);

}

The quiz object

While I’m using the name ‘quiz’ for this example, you can name the object whatever you prefer; I’m just calling it ‘quiz’ for demonstration purposes.

Object properties

The object contains all of the reporting values that were sent from Captivate. pipwerks.UTILS.convertCaptivateEmailData also creates a new property named accuracy, which is a percentage created using the formula (rawscore/maxscore) * 100. Our final list of properties is:

  • status
  • location
  • rawscore
  • maxscore
  • minscore
  • time
  • accuracy

Remember, these are all of the properties sent by Captivate and were not chosen by me!  I didn’t leave anything out; reportable data such as ‘number of attempts’ are not sent over, and I have no idea why.

Accessing the data

Now that we’ve converted the Captivate email string to an object, you can simply access the properties by using the dot syntax.  For example, if your object name is captivatedata, you’d access the data like so:

var captivatedata = pipwerks.UTILS.convertCaptivateEmailData(strBody);
alert("score: " +captivatedata.rawscore);

And that’s all there is to it! Here’s another look at the final product, and you can download the source files (including pipwerks.UTILS.convertCaptivateEmailData.js) here.

Possibly related journal entries:

9 Responses to “Send Captivate Quiz Data to JavaScript”

  1. William Peterson

    Thanks very much! This tweak seems wonderful and easy to do with JavaScript. Some of us don’t have Adobe Connect Server or Questionmark Perception to handle test scores. And if we just need a simple report like the one in email, other than complete results management in a server, this tip with JavaScript would be definitely what we need.

    I suggest that Captivate may offer the simple quiz report feature as samples like wondershare quizcreator does, which includes free ASP/PHP samples within application help to enable users to build Web database to receive a simple test report.

    And more than JavaScript, PHP/ASP might be used more popular, as avoiding some unknown issues for JS/browser, I think.

    William Peterson

  2. Philip Hutchison

    @William

    Thanks… I think. Your post is bordering on spammy, but I’ll let it slide. :)

  3. Dave

    Thanks for this excellent blog post.

    Only thing is, I cannot get your demo to work. The Flash quiz works fine, but the “Send Quiz results to javascript” button does not seem to do anything at all.

    Would you have any idea why? I’ve used IE6 and Firefox, and both do the same thing. Could it be a security thing?

  4. Philip Hutchison

    @dave

    yup… if you’re testing locally (not on a server), you’ll need to adjust your flash player security settings to allow files on your hard drive to run scripts/communicate.

  5. Bill Kirke

    I have hundreds of users taking a quiz that we’ve created, and for most of them the email reporting that we’ve built works fine.

    However for a small handful (less than a dozen), padMail() is never called. sendMail() is being called, but not padMail().

    The machines that don’t work are very consistent. We’ve tried upgrading the flash player, but that didn’t help.

    Any ideas why this would be, and how we can get those machines to report their quiz results?

  6. Philip Hutchison

    @Bill

    That’s an interesting issue; I haven’t encountered it myself. Maybe it’s a configuration issue?

  7. Neil

    Thanks for this, I can comfortably get the captivate data into javascript objects. I am having issues sending those objects to an ASP page to insert them into access.

    Any help would be greatly appreciated.
    There is an an article on Adobe’s site but that only works with Captivate version 2.

  8. Philip Hutchison

    @Neil

    Once the data is in JavaScript, you’d need to submit it as a form to your ASP page. One popular approach is xmlhttprequest (ajax). There are a ton of resources for that online, just google it. :)

  9. Philip Hutchison

    I recently received this message in an email:

    Thanks for this post.

    About your issue with interaction headers coming through only with no data…uh, forgive me if I’m stating the obvious..but you have to choose “Interactions and score” in the Reporting options for it to transmit that data. From your screenshot, it doesn’t seem that you’re checking that.

    As I wrote in the top of the entry, I tried publishing with the “Interactions and score” option checked, and it didn’t work.

    The headers were coming across, but the data wasn’t. If any of you figure out why, drop me a line. For now, we’ll just focus on the Core Data.

    Thus, the screenshots I took use the simplified approach which reports only the score.

    But thanks for the heads-up. ;)