Control a Captivate SWF using JavaScript: The basics

Note: This post covers Captivate 2 & 3; Captivate 4 introduced new problems for JavaScript interaction. You can avoid the headache of writing your own code by using the free CaptivateController utility, works with all versions of Captivate.

JavaScript can control the playback of Captivate-generated SWFs. I posted some examples about a year ago (example one, example two), but someone recently reminded me I haven’t posted any instructions or explanations for my examples. Here’s a quickie explanation of how you can control a Captivate-generated SWF using JavaScript.

Please note that this document refers to Captivate 2 & 3, and may not be accurate when Captivate 4 is released.

What can be controlled using JavaScript?

According to the official Adobe docs, Captivate provides the following controls:

  • go previous slide
  • go to next slide
  • pause
  • resume (play/un-pause)
  • rewind to beginning and stop
  • rewind to beginning and play
  • go to a specific frame
  • exit
  • display the information window

I’ve determined there are additional unpublished parameters that can be accessed. A complete list (including the variable name) is located here.

Build a simple example

Step 1: Create the HTML file and embed the Captivate SWF

For this example, we’ll use bare-bones HTML, with SWFObject handling the embed:


<html xmlns="http://www.w3.org/1999/xhtml">
<head>
   <title>Control a Captivate SWF with JavaScript</title>
   <script type="text/javascript" src="swfobject.js"></script>
   <script type="text/javascript">
      //Embed the SWF in the HTML
      swfobject.embedSWF("captivate.swf", "captivateSample", "450", "300", "7");
   </script>
</head>
<body>
   <div id="captivateSample"></div>
</body>
</html>

Make sure the SWF you’re embedding is a SWF created using Adobe Captivate, and was published without the “border” property in the Skin settings. My example SWF is named “captivate.swf”; you should replace “captivate.swf” with your Captivate SWF’s filename.

Now place a link in the document; this link will invoke the JavaScript command. For this example, we’ll just be using Captivate’s “rewind and play” command (rdcmndRewindAndPlay), so give the link the text “Click here to rewind and play.” Since this is a fake link, the href value should just contain a hash (#).

<body>
   <p><a href="#">Click here to rewind and play</a></p>
   <div id="captivateSample"></div>
</body>

Step 2: Add the JavaScript

Now that the HTML is in place, all we need to do is add a touch of JavaScript. Add the following JavaScript function to the <head>:


   //Embed the SWF in the HTML
   swfobject.embedSWF("captivate.swf", "captivateSample", "450", "300", "7");

  function rewindAndPlay(){
      var swf = document.getElementById('captivateSample');
      swf.SetVariable('rdcmndRewindAndPlay', 1);
   }

Add a corresponding onclick event to the link in the <body>:

<body>
   <p><a href="#" onclick="rewindAndPlay(); return false;">Click here to rewind and play</a></p>
   <div id="captivateSample"></div>
</body>

Save and test your page; the link should control the Captivate SWF.

How it works

The function

The JavaScript function you just created has two elements.

var swf = document.getElementById('captivateSample');

When we embedded the SWF, we assigned it an ID of “captivateSample”. This means we can use document.getElementById('captivateSample') to ‘grab’ the SWF in the browser DOM and make the SWF an object available to JavaScript. In our case, we return the object as the variable swf. As a JavaScript object, you can now invoke any methods and get/set any properties that are available within that object.

Note: You may find old documentation warning you not to use document.getElementById to get a SWF; in my testing, document.getElementById works fine in all major browsers, including Firefox 2 & 3 (Mac & PC), Internet Explorer 6 & 7, Safari 2, Safari 3 (Mac & PC), and Opera 9.5 (Mac). Also note that I used SWFObject to embed the SWFs in all of my tests, which could have an impact on test results.

swf.SetVariable('rdcmndRewindAndPlay', 1);

Captivate SWFs can be controlled by setting the value of specific ActionScript variables contained inside the Captivate SWF. We can set the value of these ActionScript variables using Flash’s SetVariable method (SetVariable allows JavaScript to set the value of an ActionScript variable without using ExternalInterface).

In this example, we’re setting the value of the Captivate variable rdcmndRewindAndPlay to 1 (boolean, meaning true).

The onclick event

If you’re not familiar with onclick events, all that’s happening is the function rewindAndPlay(); is being invoked when the link gets clicked. The extra code return false; simply instructs the browser to ignore whatever is contained in the href attribute, effectively preventing the browser from following the link. Remember to include the semicolons!

<p><a href="#" onclick="rewindAndPlay(); return false;">Click here to rewind and play</a></p>

Border blues

When a Captivate file is published with the border option enabled, Captivate is actually publishing two SWFs: a skin SWF and the Captivate SWF itself. The skin SWF loads the Captivate SWF into a movieclip named cpSkinLoader_mc. This means we need to dig one level deeper to get to the Captivate SWF. This can be accomplished by appending the prefix cpSkinLoader_mc to the variable name. Here’s an example:


document.getElementById('captivateSample').SetVariable('cpSkinLoader_mc.rdcmndRewindAndPlay', 1);

Expanding the functionality

My older examples (example one, example two) used a custom function that was designed to make controlling Captivate easier. This demonstrated how the developer could create shortcuts that prevented writing the same code over and over, while also providing a way to use simpler syntax, such as ‘pause’ instead of ‘rdcmndPause’. Here’s a really quick overview of my example function:


//Handle the Captivate commands
function control(swfID, command, usesSkin){

   //Get SWF as an object so we can use SetVariable
   var swf = document.getElementById(swfID);

   //Error-checking is good.
   if(!swf){ return false; }

   //Declare our prefix variable in case we need it. Leave as empty string for now.
   var prefix = "";

   //If the Captivate SWF uses a skin, change prefix to include the skin's movieclip name
   if(usesSkin){ prefix = "cpSkinLoader_mc."; }

   //Which command is being invoked?
   switch (command) {
      case "pause": command = "rdcmndPause"; break;
      case "resume": command = "rdcmndResume"; break;
      case "rewindStop": command = "rdcmndRewindAndStop"; break;
      case "rewindPlay": command = "rdcmndRewindAndPlay"; break;
      case "next": command = "rdcmndNextSlide"; break;
      case "prev": command = "rdcmndPrevious"; break;
      case "info": command = "rdcmndInfo"; break;
      case "exit": command = "rdcmndExit"; break;
   }

   swf.SetVariable(prefix + command, 1);

   return false;
}

This function accepts three parameters: swfName (the ID of the Captivate SWF, which is assigned when embedding the SWF), command (what we’re telling the SWF to do), and usesSkin (boolean indicating whether or not this Captivate file uses a skin).

If the SWF doesn’t use a skin:


<a href="#" onclick="return control('captivateSample', 'pause');">Pause</a>

If the SWF does use a skin:


<a href="#" onclick="return control('captivateSample', 'pause', true);">Pause</a>

As I just mentioned, this function allows us to use simpler command names. A switch statement is used to match the simpler command name with the official command name. SetVariable does its thing, then the function returns false, which prevents the browser from following the link in the href attribute.

Everything but the kitchen sink

I’ve written a new Captivate controller utility that expands on the function shown above. It includes every known Captivate control that has been tested to work with JavaScript (there are a couple that appear to only work via ActionScript), and even combines a few existing controls to create new ones, such as combining ‘mute’ with ‘enable captions’ to automatically turn on captioning when muting the movie. I’ll be posting another entry about this new Captivate utility in the next day or two. Stay tuned!

New SCORM ebook coming soon!

I'm writing an ebook explaining how to build an HTML-based SCORM course. Subscribe to be notified when it's ready, as well as receive early bird pricing and some free goodies!

No spam, no sharing your email address, unsubscribe at any time. Powered by ConvertKit
Advertisements

5 Replies to “Control a Captivate SWF using JavaScript: The basics”

  1. hi, i like this code alot but cant figure it out in captivate 4. Actually i want to force the captivate swf file to goto last slide through javascript in html file… but cant find a way for captivate 4 swf file…
    any help 🙁

  2. Again I love this code , but is there a way to make this work without your Captivate Controller? I have tried the code above but cannot make it work on a captivate 4 swf file. I have uploaded the code to the server to test and still nothing works. Appreciate the help.

  3. Larry is right. This code would be great if he works with Captivate 4. Also appreciate the help.

  4. If you’re not interested in using the CaptivateController (which works great with Captivate 4), you can take a peek at its source code to see how to write your own.

    Captivate 4 can publish to AS3, which doesn’t work with SetVariable and requires ExternalInterface instead. If you want the code in this post to work with Captivate 4, publish to AS2.

    The point of the CaptivateController is to make it easy for people like yourself to not have to write tons of code and learn the idiosyncrasies of Captivate’s JavaScript support.

Comments are closed.