Can I loop through slides with javascript?
Copy link to clipboard
Copied
What I would like to do is to jump to a slide (perhaps using cpCmndGotoSlide) using a slide label string rather than a number. e.g. cpCmndGotoSlide('Demo Slide 6')
Because the slide label string will be determined in runtime, my idea was to loop through the slide javascript objects, if they exist, looking for the slide with this slide label (e.g. slide5.slideLabel) , and then geting the corresponding slide number (e.g. slide5.slideNumber) so that I can use that number to jump to the correct slide....
Thanks for any help / ideas!
Copy link to clipboard
Copied
Can you explain how you mean by 'slide label string will be determined in runtime'? And also what you mean by "loop" because in my understanding looping means that slides will be played in sequence without user actions, which is exactly what Captivate does when you do not pause any slide.
If you use a shared action with the slide label as parameter, could that not work?
Copy link to clipboard
Copied
Hi Lilybiri,
I have a button on a master slide.
Here is what I want to have happen when the user clicks on it:
- determine the name of the current slide --> You can do this with cpInfoCurrentSlideLabel --> e.g. "4 Intro"
- get the number from that label --> You can do this with JavaScript --> e.g. "4"
- with this number create a new string --> You can do this with JS --> e.g. 4 + " Content" --> "4 Content"
- jump to the slide with this new string as a slide label using cpCmndGotoSlide --> as far as I know you need an integer to pass into cpCmndGotoSlide; a string wont work. So I need to find what slide has this string as a label so I can find its number
By loop, I mean a Javascript "for" loop --> for (var i=0; slides.length; i++) {if(slides.label=="4 Content") var slideNumber=slides.slideNumber}, something like this... I just want to somehow find the slide with "4 Content" as a slide name so that I can jump to it.
Copy link to clipboard
Copied
That first number is the slide number, must miss something but you cannot have '4 Intro' and '4 Content' in the same file? Slide 4 will have one name, it is possible that another slide has the same name (bad practice) but never the same number.
Copy link to clipboard
Copied
This function will do the trick. call the function with the argument as the slide label you are looking for.
function jumpToSlideLabel( which )
{
var getSlides = cp.model.data.project_main.slides.split( ',' );
for ( var i = 0; i < getSlides.length; i++ )
{
if (cp.model.data[ getSlides[ i ] ].lb == which )
{
window.cpAPIInterface.setVariableValue( 'cpCmndGotoSlide', i );
break;
}
}
}
jumpToSlideLabel("4 Content")
Copy link to clipboard
Copied
This looks amazing, but unfortunately, I am having the problem that Captivate will not let me save this as part of a script. (The script is part of an advanced action I want executed when a button is clicked.) I copy and past the code into the script window, click OK, and it at first seems ok. If I go back into the script window,though, the code isn't there. After some trial and error, it seems that you cannot save code with for loops. When I remove your for loop, it saves. I tested with my own for loop and that didn't save either.
I was thinking I could just add this script to the js after export, and add an event listener to the button, but I haven't figured out how to select the button in the DOM with "document.querySelector". The ids of the DOM elements seem to be dynamic.
Let me know if you have any ideas!
Ryan
Copy link to clipboard
Copied
Update : The for loops work when the script is not part of an advanced action.
Copy link to clipboard
Copied
I hope David pops in as well, but this is a common issue: more complicated Javascripts, including functions, should better be embedded in the JS file that is published with the folder, not in advanced actions. You can call the function in the advanced action JS command.
Copy link to clipboard
Copied
The id's are not dynamic (unless a smartshape on a master slide) and can easily have event listeners added to them. The id will be the name you give the button.
I generally use the CPAPI_INTERACTIVEITEMSUBMIT listener. You can then query the event to see what was clicked. THis won't work for passing arguments though.
If you were to set up a js file and include it in the Captivate template used for HTML5 publishing you can always just call the JavaScript function in the JS Window. The files/locations are here:
C:\Program Files\Adobe\Adobe Captivate 8 x64\HTML\index.htm
Add:
<script src="assets/js/yourfilename.js"></script>
just above:
<script>
function initializeCP()
Then drop the JS file here:
C:\Program Files\Adobe\Adobe Captivate 8 x64\HTML\assets\js\
It will be there every time you publish. You can keep adding functions to the file.
Just call: jumpToSlideLabel("4 Content") in the JavaScript window.
Copy link to clipboard
Copied
Hey there,
Thank you. I didn't realize that buttons on non-master slides have static IDs. That is great to know. You mentioned buttons on master slides and how they are dynamic -- is there a way to get the IDs of those in runtime?
The thing about setting up your own "permanent" javascript file was also great to know. I had to give myself admin rights for some of the folders, but it worked.
What is the target you attach the listener to when you listen for the CPAPI_INTERACTIVEITEMSUBMIT event?
e.g. document.getElementById(whatIsThis?).addEventListener('CPAPI_INTERACTIVEITEMSUBMIT',callback)
I also found a bug I think: In the Javascript window in Captivate this returns an error: "chapter 25".match(/\d+/g)[0]
, but this doesn't "chapter 25".match(/[0-9]+/g)[0]
. My interpretation is that it doesn't accept escape characters, at least in regular expressions.
- Ryan
Copy link to clipboard
Copied
It is attached to the eventEmitterObj object, in this example I logged e.Data which will show you the properties that are passed in the event.
var interfaceObj, eventEmitterObj;
window.addEventListener( 'moduleReadyEvent', function ( e )
{
interfaceObj = e.Data;
eventEmitterObj = interfaceObj.getEventEmitter();
initializeEventListeners();
});
function initializeEventListeners()
{
if ( interfaceObj )
{
if ( eventEmitterObj )
{
eventEmitterObj.addEventListener( 'CPAPI_INTERACTIVEITEMSUBMIT', interactionFunction, false )
function interactionFunction( e )
{
console.log( e.Data );
}
}
}
}
I know of no way the get the objects on the master slide. There may be a way, but I haven't looked at it too deeply. If CP would let you give them instance names, it would be great. I put my navigation buttons on the first slide and display for the rest of the project to get around this.
As far as the "bug" my advice is not to put "scripts" in the JS Window. Keep the scripts in a js file and call the functions/variables that way. Because CP has to try and escape all of the characters in the JS Window, it sometimes doesn't do it correctly.
Copy link to clipboard
Copied
+1000 to have instance names for objects on Master slides, a request I entered several times. The drawback with buttons timed for the rest of the project (my approach if I want to control them), is that you cannot have the automatic pausing at the end of each slide whatever its duration.
Copy link to clipboard
Copied
That is true Lieve. I usually run a variable change listener for cpInfoCurrentFrame and pause the slide automatically 5 frames from the end of the slide.
I guess you could put a smartshape button on the master, set it to be transparent and use it to pause the slides.
Copy link to clipboard
Copied
That means another object, whereas if you could control the objects on the
master slide it would be unnecessary. Another reason to prefer shape
buttons timed for the rest of the project is that they have states. In CP9
states do not work on master slide, a still not fixed bug.
Copy link to clipboard
Copied
Hi,
Thanks for the tips!
Copy link to clipboard
Copied
Hello,
Do you know of an efficient way to listen for a jump to a different slide?
Here is my issue:
I built my own play / pause button on a master slide. When the user clicks on it in the project, it does its job - it either pauses or plays and its appearance changes accordingly. The problem is that when the user jumps to a new slide while the project is paused, the project automatically starts playing again, but the button's appearance doesnt change. It stays in its paused state.
So I would like to listen for this jump to a new slide and change the appearance of my play/pause button to "Play" when the event occurs.
Thanks for any help!
Copy link to clipboard
Copied
Or even listen for the "continue" event would work.
Copy link to clipboard
Copied
You can add event listeners for the pause and resume events. This is how I control my pause/play button.
window.cpAPIEventEmitter.addEventListener( 'CPAPI_MOVIEPAUSE', function ( e )
{
if ( e.Data == 8 )//pause from cpCmndPause
{
cp.hide( 'pause_btn' );
}
else if ( e.Data == 1 && !inVideo )
{
cp.disable ( 'pause_btn' );
document.getElementById( 'pause_btn' ).style.cursor = 'default';
}
});
window.cpAPIEventEmitter.addEventListener( 'CPAPI_MOVIERESUME', function ( e )
{
if ( e.Data == 0 || e.Data == undefined || e.Data == 'undefined' )
{
cp.show( 'pause_btn' );
cp.enable ( 'pause_btn' );
document.getElementById( 'pause_btn' ).style.cursor = 'pointer';
}
});
You could also use the enter slide event.

