Introducing the CaptivateController
It took me much much longer than I anticipated, but I am happy to announce the new CaptivateController utility. The CaptivateController is a JavaScript utility that helps you control Captivate SWFs using simple JavaScript commands. For example:
//Assuming your SWF is embedded using the ID "myID" var myMovie = CaptivateController("myID"); myMovie.pause(); //Pauses the Captivate SWF myMovie.mute(); //Mutes the Captivate SWF
For those of you familiar with the pipwerks.captivate.control utility, this CaptivateController is not a simple rehash of the original; it is a complete re-write that adds a number of extra features, including:
- Support for Captivate 2, Captivate 3, and Captivate 4 files
- Auto-detection for skins; you can write the exact same JavaScript whether your SWF uses a skin or not
- New query methods, including the ability to query a user-defined variable in a Captivate 4 file
The CaptivateController took a long time to develop because it deals with a number of inconsistencies between Captivate 2/3 SWFs and Captivate 4 SWFs, including the shift from using GetVariable to using Captivate 4’s proprietary cpGetValue (via ExternalInterface). It also handles inconsistencies with Flash Player in different browsers. Safari and Internet Explorer both provided their own small challenges.
There are still some inconsistencies that cannot be solved using JavaScript; for instance, Captivate 4 SWFs published using ActionScript 3 provide a richer set of system variables than Captivate 4 files published using ActionScript 2. I expected to have the same access to all system variables regardless of ActionScript version, but alas it was not meant to be.
Someday I hope to post a chart of which variables work when, but until then you can check out the Automated Test Suite, which illustrates which variables are available for each flavor of Captivate SWF.
Download
The CaptivateController weighs in at about 8kb and has been successfully tested in the following systems:
- Mac OS X (10.5): Firefox 3.0.10, Safari 3.2, Opera 9.6
- Mac OS X (10.6): Firefox 3.5.3, Safari 4.0.3
- Windows XP: Internet Explorer 6, Internet Explorer 8, Firefox 3.0.10
- Windows Vista: Internet Explorer 7
You can download the compressed version (8kb) here.
You can view the source version here (please do not hotlink).
Quickie documentation
I haven’t had the time to do a full write-up of the CaptivateController API, but the following information should be enough to get you started.
Don’t forget to check out the test suite. A list of Captivate Variables can be found on the Automated Test Suite and also in this blog post.
“Control” methods available in the API
| Method | Notes |
|---|---|
| pause() | |
| resume() | |
| next() | |
| previous() | |
| rewindAndStop() | |
| rewindAndPlay() | |
| gotoSlideAndPlay(slidenumber) | Uses 1-based numbering: gotoSlideAndPlay(3) will take you to Slide 3. If you prefer Captivate’s built in zero-based numbering, use useZeroIndex(true) to change the numbering to a zero-based index. |
| gotoSlideAndStop(slidenumber) | Uses 1-based numbering: gotoSlideAndStop(3) will take you to Slide 3. If you prefer Captivate’s built in zero-based numbering, use useZeroIndex(true) to change the numbering to a zero-based index. |
| gotoFrameAndPlay(framenumber) | |
| gotoFrameAndStop(framenumber) | |
| volume(volumelevel) |
|
| mute() | |
| unmute() | |
| muteAndShowCaptions() | |
| unmuteAndHideCaptions() | |
| showCaptions() | |
| hideCaptions() | |
| showInfoBox() | |
| hidePlaybar() | Doesn’t seem to work consistently via JavaScript |
| showPlaybar() | Doesn’t seem to work consistently via JavaScript |
| lockTOC() |
|
| unlockTOC() |
|
| exit() | |
| useZeroIndex(boolean) | Specifies whether gotoSlideAndPlay and gotoSlideAndStop should use zero-based numbering (0 = slide 1). Set to true to use zero-based numbering. The default is false. Warning: This should only be invoked if you wish to use a zero-based index for gotoSlideAndPlay and gotoSlideAndStop. |
Example:
//Assuming your SWF is embedded using the ID "myID" var myMovie = CaptivateController("myID"); myMovie.pause(); //Pauses the Captivate SWF myMovie.mute(); //Mutes the Captivate SWF
Commands can also be chained together, like so:
var myMovie = CaptivateController("myID"); myMovie.pause().mute(); //Pauses then mutes Captivate SWF
Query methods
The primary query technique is to use .query(“captivate_variable_name”). For example,
var myMovie = CaptivateController("myID"); //Retrieves the author's name, if available var author = myMovie.query("cpInfoAuthor");
You can also use this method to query user-defined variables:
var myMovie = CaptivateController("myID"); //Retrieves the variable My_custom_variable_name, if available var myUserDefinedvariable = myMovie.query("My_custom_variable_name");
I have created some additional query methods below. Some are designed to help avoid worrying which version of Captivate is being used (ie they work with both CP3 and CP4), and others provide data directly from the Flash SWF (not using CP variables).
| Method | Notes |
|---|---|
| captivateVersion() | Returns major number, currently either 2 or 4 (Captivate 3 SWFs self-identify as CP2 SWFs, nothing can be done about this.) |
| asVersion() | Returns either 2 or 3 |
| FPS() | Returns the frames per second of the SWF |
| hasSkinSWF() | Returns a boolean indicating whether the SWF is using a skin |
| hasTOC() | Returns a boolean indicating whether the movie has a Table of Contents |
| hasPlaybar() | Returns a boolean indicating whether the SWF has a playbar |
| width() | Returns a number indicating width in pixels |
| height() | Returns a number indicating height in pixels |
| volume() | Returns a number (0-100) indicating volume level. Note: volume only works in CP4+ |
| percentLoaded() | Standard Flash SWF method, not specific to Captivate. |
| getname() | Returns the SWF’s ID. Standard Flash SWF method, not specific to Captivate. |
| geturl() | Returns the SWF’s URL. Standard Flash SWF method, not specific to Captivate. |
You can also grab a reference to the SWF itself by using .swf. This is the equivalent of document.getElementById():
var myMovie = CaptivateController("myID"); myMovie.swf === document.getElementById("myID");
Does it work for you?
I’m planning on refining this controller utility over time. If you encounter any problems or have any suggestions for improvements/new features, please let me know by leaving a comment below.
DISCLAIMER: This controller is provided as-is. Use this controller at your own risk. I cannot be held responsible for any problems you may encounter while using the controller. kthxbai.
What others are saying... (16 comments so far) You can follow all responses to this entry through this post's comments feed (RSS).
Genius – the pipwerks.captivate.controller already saved my bacon on a project; I can’t wait to check out the new version.
Well done you! Captivate sucks!
I look forward to messing around with this ASAP! Thanks again, for the great work!
Very good job! This looks really interesting and will definetly come in handy.
Thanks a lot.
Philip, my hat is off to you. Well done. I’ll be sure to let you know any bugs/suggestions as I implement some test projects.
Thanks for this, it looks very powerful! I am having a hard time getting it to work though. Could you perhaps post a simple code example like you did for the previous version? I’m trying to “steal” code from your test suite pages, but not having much success. I think I just need a little help with syntax for a wrapper function and a link.
Thanks!
I’m having issues using the captivateSWF.gotoSlideAndPlay(X); return false; command. It appears to only accept a value of (1). Any other number used will navigate to that slide number, but it won’t play.
Another suggestion might be to adjust the number in your JS code, by subtracting 1 automatically, so users don’t have to remember to subtract 1 to go to the proper slide intended.
@bob i’ll try and put up a simple example sometime this week, but no promises… i’m super busy at the moment.
@kc i’ll look into it. thanks for the head’s up. good suggestion, too.
Philip,
I’ve done more experimenting, and have confirmed that the only value I can put in the gotoSlideAndPlay is “1″. I tried to peak under the hood of your JavaScript, and it’s a bit over my head. Any idea why “1″ in the only value that works?
Well, I’ve got everything working except the GotoSlideAndPlay(). I’ve tried Cap 3 and 4 with AS 2 and 3. Same results. The only command that works is captivateSWF.gotoSlideAndPlay(1). It navigates to slide 2 and resumes playing the movie. Any other number navigates the movie to the correct slide, but it does not resume playing; it’s stuck in a “pause” mode.
It’s really hard to get the controler working. I’ve just tried to get out a user-defined variable and copied the whole content from your testing site. But after entering the variable in captivate and clicking the retrieve button it returns always “false” … Any idea?
I forgot to post a link about the updates to the CaptivateController; they address issues discussed in these comments:
http://pipwerks.com/2009/09/26/captivatecontroller-updated/
@Gecco You haven’t provided enough information for me to give any guidance. If you’d like help, please post the issue to the E-Learning and Development Google Group and be sure to provide a link to your file(s).
Hey philip, thanks for the very fast reply. I’ve just saved with firefox this webpage to my computer – including all the js, css and swf files. Without any editing. I’ve just checked if the linking was ok.
When I’m starting it locally on my pc everything seems to be fine. CSS is working, SWFs are loading. But after entering the variable in CP, clicking the submit and the “Retrieve variable ‘pipwerks’” button it returns always “Captivate returned false”.
I’ve got it … after testing it on a server it works … Thanks.
Captivate 4 uses ExternalInterface for its JS-ActionScript communication. Local communication is disallowed by default in Flash player’s security settings. This means ExternalInterface will NOT work locally unless you change your Flash Player’s security settings to allow communication in that specific location. This also explains why it works on a server but not locally.
Philip, hello again, been awhile! I’ve been using your code again, and ran into two issues you might address in a future version.
Information Window
I can’t get the information toggle to work – the code that will display Captivate’s information window, that displays information about the movie, author, copyright, etc. Tried in Captivate 3 and 4, with movies that have/don’t have a playbar. No biggie there, but for some folks, info button is a big deal.
Table of Contents
Still haven’t given up on this, trying to get a button to open/close the Table of Contents in Captivate 4 movies. Another user posted this ActionScript that should work with AS2 flash movies to control the TOC, his working example seems to do the trick:
this.stop();
_parent._parent._parent.ShowHideTocLeft_mc._visible = false;
_parent._parent._parent.ShowHideTocRight_mc._visible = false;
this.but_mc.onRelease = function(){
_parent._parent._parent.TOCManager.showTOC();
_parent._parent._parent.ShowHideTocRight_mc._visible = false;
_parent._parent._parent.ShowHideTocLeft_mc._visible = false;
};
Controlling the Captivate SWF via ActionScript is much easier than JavaScript. ActionScript provides direct access to the SWF’s properties and child movieclips, whereas with JavaScript you can only access whatever the developer (in this case Adobe) has made publicly accessible via ExternalInterface or SetVariable. Unfortunately, the sample code you provided will not work in JavaScript.
Want a gravatar? They're easy and free! Just sign up at gravatar.com
Add your two cents!