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, which 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.
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>
Code language: HTML, XML (xml)
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>
Code language: HTML, XML (xml)
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);
}
Code language: JavaScript (javascript)
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>
Code language: HTML, XML (xml)
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');
Code language: JavaScript (javascript)
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);
Code language: JavaScript (javascript)
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>
Code language: HTML, XML (xml)
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);
Code language: JavaScript (javascript)
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;
}
Code language: JavaScript (javascript)
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>
Code language: HTML, XML (xml)
If the SWF does use a skin:
<a href="#" onclick="return control('captivateSample', 'pause', true);">Pause</a>
Code language: HTML, XML (xml)
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!
Comments
Rizwan wrote on December 8, 2009 at 2:33 am:
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 🙁
philip wrote on December 13, 2009 at 10:02 pm:
Try my <a href="https://pipwerks.com/2009/06/07/introducing-the-captivatecontroller/" rel="nofollow ugc">CaptivateController</a>, it handles a bunch of the work for you (including dealing with some Captivate 4 quirks).
Larry wrote on January 27, 2010 at 6:07 am:
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.
feedee wrote on May 13, 2010 at 11:30 am:
Larry is right. This code would be great if he works with Captivate 4. Also appreciate the help.
philip wrote on May 13, 2010 at 11:58 am:
If you're not interested in using the <a href="https://pipwerks.com/2009/06/07/introducing-the-captivatecontroller/" rel="nofollow ugc">CaptivateController</a> (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.
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 🙁
Try my CaptivateController, it handles a bunch of the work for you (including dealing with some Captivate 4 quirks).
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.
Larry is right. This code would be great if he works with Captivate 4. Also appreciate the help.
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.