A better way to create a custom PDF of lesson variables from captivate

I’ve seen a number of cases where people have tried to use the eLearningBrothers “print.html” technique to create a custom PDF of information gathered during a lesson.   Inevitably it has led to frustration.   In one case,  the administrator forgot to include this custom file in the course module,  and in another,  the amount of text was larger than that allowed in a URL and broke the call.

The following gets past both of these problems

1.  the entire capability is packed into the course source file and will not be inadvertently lost

2. there are no limits on the number or length of variable names

Here’s a simple alternative

1. Add the following code to “On Enter, execute JavaScript”

var printWindow

function writeHeader(txt) {
printWindow.document.write("<H1>"+txt+"</H1> <hr>")
}

function writeName(txt) {
printWindow.document.write("<h3>"+txt+"</h3>")
}

function writeValue(txt) {
printWindow.document.write("<p>"+txt+"</p>")
}

function openPrint() {
printWindow.print()
}

function printVars() {

printWindow=window.open("", "_blank");

sty=` <style type="text/css">
        body {
          font-family: Sans-Serif;
          padding-top: 10px;
          padding-left: 10px;
        }
        #title{overflow:auto;}
        #logo{float:right;}
        #date{
            float:left;
            display:inline-block;
            position:absolute;
            z-index:: 1;
          font-family: Sans-Serif;
            color: #666666;
            padding-left: 22px;
        }
        h1 {
            font-size:26px;
            font-family: Sans-Serif;
            padding-left: 19px;
            margin-top: 27px;
            }
        h3 {
            font-size:18px;
          font-family: Sans-Serif;
            font-weight:600;
            color: #444444;
          padding-left: 20px;
        }
        p {
            font-size:14px;
            -webkit-margin-before: 0.0em;
            -webkit-margin-after: 0.0em;
          font-family: Sans-Serif;
            color: #666666;
            padding-left: 20px;
        }
        hr {
            display: block;
            -webkit-margin-before: 0.5em;
            -webkit-margin-after: 0.5em;
            -webkit-margin-start: auto;
            -webkit-margin-end: auto;
            border-style: inset;
            border-width: 1px;
        }       
    </style>`
printWindow.document.write(sty);
var d = new Date();
var curr_date = d.getDate();
var curr_month = d.getMonth() +1;
var curr_year = d.getFullYear();
printWindow.document.write('<div id="date">'+curr_month+"-"+curr_date+"-"+curr_year+'</div>');
fillWindow();
}

2. On the slide you want to create the PDF, add the following code to “on enter, execute javascript”

function fillWindow() {
  writeHeader("any text for your header")

  writeName("any text here for a name")
  writeValue("any text here for a value")

  writeName("variablename1")
  writeValue(window.cpAPIInterface.getVariableValue("variablename1"))

  writeName("variablename2")
  writeValue(window.cpAPIInterface.getVariableValue("variablename2"))

// add more name/value pairs here
// this is the last line in the function
  openPrint()

}

Just fill in the variable names and values as you need to and create this function

finally,

3. On the slide you want to create the PDF, create a button that has an action “on success, execute javascript”

the code for the button is simply:

printVars();

That’s it.

When you press your “print variables” button,  another window will open with a simple format, already set to print.  you can set the print function to save as PDF and you’re on your way.

Note  – this solution uses a quoting capability only available in the latest versions of Javascript, so if you need to support IE11,  some small changes need to be made.

Create a List of All Your Slide Titles (Exporting a Table of Contents)

Earlier today, I saw this discussion:

https://elearning.adobe.com/discussion/2358002/

In essence, ruthg84 needs to get a list of all the slide titles in several of her files. I responded on that thread but am showing my solution here too because I can include screen shots here.


I took a quick stab at this and have created a solution that works, though it takes a couple of steps. I hope others of you may find a quicker way, but this works and doesn’t take long.

  • In the first slide of your Captivate file, set the On Enter action to Execute JavaScript and enter this in the JavaScript window:

2017-07-15 19_55_17-Get slide titles.cptx_ 2017-07-15 19_55_25-JavaScript

var titles = ”;
var title = ”;
window.cpAPIEventEmitter.addEventListener(‘CPAPI_SLIDEENTER’,
     function() {
           titles = titles + ‘Slide ‘ + window.cpAPIInterface.getVariableValue(‘cpInfoCurrentSlide’) + ‘: ‘;
           title = window.cpAPIInterface.getVariableValue(‘cpInfoCurrentSlideLabel’);
           if (title == ”) { titles += ‘(No slide title)’} else {titles += title };
           titles += ”;
           console.log(titles);
      }
);

  • Make sure in your Skin Editor that your playbar is turned on and the Next button is available.

    2017-07-15 19_56_36- 2017-07-15 19_56_55-

  • Publish your file (Preview won’t work). I tried it in HTML5 but Flash should work too.
  • Launch your published file in the browser.
  • Turn on your Development Tools in your browser. In Chrome, you can do this by hitting Ctrl+Shift+I or going to the browser’s options and turning it on there.
    2017-07-15 19_58_41-
  • In your Development Tools, go to the Console. Here you will see at least the first slide’s title listed.

2017-07-15 20_03_23-INDEX~1.HTM

  • Use your Playbar Next button and go to each screen, quickly if you like, just as most learners do (haha). There is no need to wait for the slide to finish.
  • Each time you hit the Next button, you’ll see in the Console the current slide title added. If a slide does not have a title, the words (No slide title) are added.
  • When you get to the last slide, copy the last console line and paste it into a text editor or into Word.
    2017-07-15 20_04_33-INDEX~1.HTM
  • Find and replace each occurrence of @@ with a carriage return.
  • Now you have a complete list.

Example: I tried this with a file I created in which there are six slides. After I got to the sixth slide after publishing, I copied this out of the Console window:

Slide 1: Introduction@@Slide 2: Hello There@@Slide 3: (No slide title)@@Slide 4: Slide Four@@Slide 5: Test@@Slide 6: Summary@@

I copied the line into a text editor (Word would work too) and after replacing all @@ with a carriage return, now have a nice list:

Slide 1: Introduction
Slide 2: Hello There
Slide 3: (No slide title)
Slide 4: Slide Four
Slide 5: Test
Slide 6: Summary

I hope this helps anyone who needs to make a quick list of all slide titles.

Captivate popup manager with 508 accessibility support

A common e-learning interaction is a set of buttons that activate the display of a particular set of images and text. Often, the items are displayed as an overlay on top of the button set, and a semitransparent grey background is added to de-emphasize the selection buttons. When the learner is done with the displayed information, they click on either the background or a specific “close” button. This is commonly referred to as a “Lightbox.”

Captivate has all of the functionality needed to implement these kinds of interactions through the use of Advanced Actions but the process used to create and manage the popup can be cumbersome and brittle. As an alternative, we have developed a JavaScript popup manger that simplifies the process of display, and state management given certain shape naming conventions. Our popup manager also addresses a key navigation issue for the visually impaired, which is discussed at the end of the article.

The complete Captivate 10 source and the published version of this interaction are available here.

Creating a popup: Naming conventions

The Captivate timeline gives a very compact way of describing all of the elements on the page.

  • The buttons are specifically named to help with tab ordering (discussed later)
  • All elements associated with the popup are given ID names that start with a prefix that identifies the particular popup interaction, in this case “animal”. Elements that are part of the popup start out hidden, which is done for each element in the property tab by clicking on the eye next to the element name to add the red strikeout:

The popup manager

Our popup manager is added to the slide using the “on enter, execute Javascript” function. The code is provided below:

var currentButton
function popupManager(popupID, stateName) {
console.log(popupID, stateName);
let clearMarker = (stateName == "clear") || 
                  (stateName == "close") || 
                  (stateName == "hide")
if (!clearMarker) {
  currentButton = document.activeElement
 }
// get elements
popupElements = $("[id^='" + popupID + "'].cp-frameset").map(function (i, j) {
   return j.id
  }).get();
// hide all popup elements to start
for (element in popupElements) {
  elemID = popupElements[element]
   cp.hide(elemID);
 };
// set popup state
 if (clearMarker) {
  currentButton.focus()
  return;
 }
for (element in popupElements) {
  elemID = popupElements[element]
  cp.changeState(elemID, stateName);
  cp.show(elemID);
 };
$("[id^='" + popupID + "_Text']").focus()
}

The popup manager is called using the function:

function(popup_ID, desired_state) 

where the popup_ID is the prefix used on each popup element’s ID (in this case “animal”) and the “desired state” is the state name you have used when creating each element’s visual states.

The popup manager performs the following:

  • Show all elements that are associated with the popup
  • Set the element state
  • Set focus to the popup element designated as “Text” (discussed later)

When called with “hide”, “close”, or “clear” as the desired state:

  • Close the popup and set focus back to the button that initiated the interaction (discussed later)

Opening a popup

The buttons use the following JavaScript to open the popup:

popupManager("animal","dog")

where “animal” is the popup shape prefix as seen in the timeline and “dog” is the desired state of shapes in the popup. This is added to the button as the action “on success, execute Javascript”. We typically disable the “continue playing project” option on our buttons.

Configuring popup shapes

In our case, we have five shapes associated with the popup. All will be shown and hidden together since they all have the same prefix on their name.

After we construct these shapes, they are hidden and locked.

Two of the shapes have visual states, the “animal_Text” and “animal_image” shapes. We name the states so that the image of the dog and text associated with the dog have the same state name ( um, “dog” ).

Any shape with the popup name prefix and the designated state name will be set before being displayed.

Two other shapes, animal_exit and animal_grey will enable the learner to close the popup. They are both smartshapes that are set to be buttons.

  • The animal_grey shape is really just a black rectangle that covers the entire screen. It is set with an opacity of 70% to create the grey transparency effect. Since it is also a button, it initially is created with to other states, “Rollover” and “Down”. We set these states to have the same image as the Normal state: Black with 70% opacity. It is also set to display behind the other elements in the popup.
  • The animal_exit shape is always set to display on top of all other elements. You can place this anywhere on the page, but it will be required to have such a shape to support our 508 accessibility needs (discussed below)

Both of these shapes use the following JavaScript to close the popup, added under the action “on success, execute JavaScript”:

popupManager("animals","hide")

In both cases, we disable the “continue playing the project” option.

The use of JavaScript and the popup manger gives a lot of flexibility when developing popups. Adding additional elements to the popup, and adding/removing additional buttons is very simple. Entire popup interactions can be copied with a few modifications to prefixes.

Accessibility and 508 compliance

Designing courses that are accessible to individuals with disabilities is a complex topic, and a complete explanation is beyond the scope of this article. The fundamental needs for folks that visually impaired include the ability to use a text-to-voice screen reader to understand what is on the page, and a rational structure to the page so that keyboard-based navigation can be used to tab through the elements on the page.

As you might imagine, popups are really a problem when it comes to keyboard navigation, as there is a natural concept of navigating through buttons in a menu, but the jump to and back from the popup is not “linear” and there is no inherent support in Captivate for this capability.

There are a set of Internet standards that have been developed to help screen readers deal with these concepts, called the “ARIA” standards. However, Captivate does not provide any support for these, and there is no simple way to post-process the captivate published file to integrate ARIA tagging.

We have addressed the issue of 508 compliance in popups by controlling “focus”. One element in the popup has a special designation as “Text”. When the popup is opened, the browser’s focus is shifted to this element. Screen readers will then read the text within that element.

The Text element is designated by creating a shape that has the popup prefix followed by the characters “_Text”. In the above case, the shape is “animal_Text”. If for some reason additional characters are added to the end of this ID, it doesn’t matter. We tend to avoid using text caption elements, as we have found that screen readers seem to have problems with those. Smartshapes with text seem to work best.

The “exit” element in the popup is always defined last, and is set to display on top of all other elements in the popup. After the screen reader is done with the text element, the next element in the tab order will be the exit element. The popup manger is designed such that when the popup is closed, focus then shifts back to the button that initiated the action, enabling further navigation though the buttons.

Building for 508

Building for accessibility can tremendously complicate the creation of course material, nearly doubling the development time in some cases. The following are key steps needed to make the popup interaction more 508 friendly:

  • Tab order: Once the buttons are built, it is necessary to select the entire slide and set the tab order for the buttons. Giving the buttons named IDs makes this a lot easier!
  • Exit button accessibility text: The popup exit button is typically just a symbol, like an “X”. Accessibility text will be read when the shape is in focus. Something like “Return to list” is used.

Testing Accessibility Compliance

For folks that do not do accessibility-enabled projects very often, it is possible to get a relatively good assessment of the basic compliance with tab-order and accessibility text availability using just Microsoft Windows 10. The built-in browser, Microsoft “Edge” is actually excellent at displaying the tab focus information, and Microsoft’s built-in screen reader “Narrator” can be used to test pages in Edge for accessibility text.

For more information on Narrator, you can see

Using Narrator is easier than you think. The most important commands are:

  • ctrl-win-enter start and stop narrator
  • caps lock + F1 narrator help
  • caps lock + left/right arrow keys move between items and read

In Edge, the current tab location will be visible with dashed lines around the item.

 —

For more information, contact sdwarwick <at> eLearningOcean <dot> com

Goto slide by slide name & goto slide containing shape with name in javascript

There are many cases where you have interactions that require jumping to another slide in the module.  The classic case is a “menu” slide with a number of options, where selecting an option transfers the learner to a particular lesson or detail slide.  This is also the basis of how adaptive learning is actually implemented.

Captivate provides you a way to jump to a particular slide using advanced actions.  Once you point to a particular slide, the advanced action jump will follow that slide even if it is moved or other slides are added before or after.  This is a well known capability that has been part of captivate for a long time.

There are some cases where having  the ability to perform these kinds of jumping functions in javascript is an advantage.

  •  It is sometimes easier to develop more complex branching decisions in javascript than directly in advanced actions
  •  There are cases where one wants to use a named object rather than a slide name to identify which slide to go to
  •  If slides are deleted, captivate removes the “jump to slide” action and replaces it with a “continue”  action.

Jump to slide by slide name

The following shows how to implement jump functions in Javascript.  First, we  define a Javascript function that gets added to the menu  slide,   and then each button is set up to call this function with the name of the slide that it wants to have the user jump to.

The javascript function is:

function gotoSlideNamed(aName) {
   var cpObjectList = Object.getOwnPropertyNames(cp.D);   // get all of the captivate-defined objects
   var findSlideLabels = function ( acc, val ) {   //  extract objects that have slide names 
         if ( typeof cp.D[val].lb == "undefined" || cp.D[val].lb == "" ) return acc;
          acc[cp.D[val].lb ] = cp.D[val].from ;   // pick up the frame number 
          return acc
          }
   var cpSlideObjects = cpObjectList.reduce ( findSlideLabels , {} )   // run the function on all of the captivate objects
   cpCmndGotoFrameAndResume = cpSlideObjects[aName];  // set the "next frame" variable to the start frame of the object
   return ;
}
This script  is  added to the menu slide using the “on entry execute Javascript” slide-level action.
Now, for each button,  you simply add the following “on success execute Javascript” action:
gotoSlideNamed("action_1")   // action_1 is just a made-up name,  you put the name of your desired slide there..
Now, any change in the module will not impact where you jump to.
It is common that once a learner completes a subsection, they are taken back to the menu.   In that case, we use the same function to make sure that the return jump is also robust.   Naming the menu slide “top_menu”   we add a “go back” button with the javascript:
gotoSlideNamed("top_menu")
Note that we tend not to use names with spaces in them just for safety.

Jump to slide by name of shape

There are some cases where you’d rather jump to a slide that happens to have an element on it with a specific name.   In this case,  there is another function we use that works for named elements rather than slide names:

function gotoSlideWithShapeName(aName) {
  var theSlide = cp.D[aName].apsn;    // get parent slide name
  cpCmndGotoFrameAndResume = cp.D[theSlide].from   // set next frame to the start frame number of that slide 
  return
 }

If you have a shape on the target slide with the id “section_3”  you can have a button that simply calls the javascript function:

gotoSlideWithShapeName("section_3")

With these two functions,  branching paths can be accomplished in Javascript, which can be an advantage in cases where you have complex branching scenarios.

For more information,  contact sdwarwick@elearningocean.com

( edited 6/11)

Capture Adobe Captivate Data in Real Time

This demo course and post explains how to use a free Firebase account to collect and display all user data live in real time.

Play with the live example here (click the launch course button, upper right): http://elbrotherscustom.com/jk/blogs/cp_fb/

Watch a video of how I made it here:

Read more and get the JavaScript here:  http://elearningbrothers.com/capture-adobe-captivate-data-real-time/

I will be presenting a similar concept on how to use Google (and other) Analytics as free LMSs at Learning DevCamp June 6th.

How to play background music continuously throughout the course in Articulate Storyline 2.

Articulate Storyline 2 provides the flexibility to customize interactivity to the max with minimal efforts. This web based authoring tool gives feasibility to add JavaScript which can be of great help to take your eLearning courses to the next level. It’s fairly easy to extend and enhance the functionality of the built-in features in Storyline…

Creating a custom question slide with True/False options

There are probably millions of different quiz-type interactions that we can imagine,  of which only a few Captivate can provide as pre-formed quiz slide types.   Captivate tries to provide a sufficiently flexible environment to create unique quiz interactions but it is really easy to get lost in the user interface trying to find just the right combination of functions.   In this short article,  we’ll go through the process of creating a quiz slide with the following characteristics:

snip7

The desired characteristics are that the student gets points for selecting the correct answers,   true or false,   and that only one of true/false can be active at a time for a given question.    These are two separate requirements.   Another,  perhaps less obvious requirement might be that there are no other question types in the module.   We’ll deal with that as well.

As a bonus,  we will introduce an undocumented javascript function that enables you to create a scoring event,  similar to clicking a scored checkbox by hand.

Activate the quizzing functions

First,  you need to actually create a question slide from one of Captivate’s canned types to get the needed quiz functionality and potential reporting.   On the toolbar,  selecting Quiz -> Question Slide -> (any question type)  will create both a question slide and a reporting slide.    Since this question slide will be unused,  mark it hidden by going to toolbar View -> Hide Slide

The great thing is that hidden questions do not impact the quiz results,  so this is an easy solution.

Creating the questions

First, we add regular empty slide after the hidden question slide where we will make our custom quiz.

Question text is simply placed in a smart-shape rectangles.

The true/false buttons is where things get more interesting.  We will create three buttons – the true/false buttons and a third button that will be hidden and will be used to tell Captivate that the answer is correct.  All the buttons will look the same, so we make one and then just duplicate them.

Create the button as follows:

– create a circular “smart shape”

– select “Use as Button” on the shape’s properties tab

– create a new “state” for the button by opening up the “state view” and adding a “new state.”  I name this state “selected”

– format both your new “selected” and the system-provided  “Down”  state to look the same.   then exit the state editor.

– change the name of the shape to “Question_T_1”      You’ll see why in a minute.

This shape will be used for all the buttons in the quiz.   We create the extra state “selected” as this is one that we can directly control.   Captivate manages the system states, which makes them harder to control.  The format of the shape name is important.  We will be using a short javascript routine to control the toggling function, and with a unique format for the shape names,  you can create a general routine that can find these shapes rather than identifying each button individually in the code.

Next,  duplicate the shape you just created to fill in each of your questions with the needed true/false buttons, and a third button that we will use to signal that the answer is actually correct.   You will see that Captivate automatically changes the number from _1 to _2, _3, _4 as you duplicate the shapes.

Next,  go through and edit the shape names to have the same name patterns as shown below. The names should look like this:

snip6

Dealing with scoring

At this point, we need to active scoring on the answer buttons, which we will use in our javascript routine to mark when a correct answer has been selected. Add the following to all of the answer buttons shape properties tab:

Actions -> Reporting -> Include in Quiz

also check “Add to Total” and “Report answers”

Toggling true/false

I prefer using JavaScript over using advanced actions as I find it more flexible and faster to program, but there are many good reasons not to as well.   In this case,  the JavaScript enables us to create a very small routine that deals with the toggling problem for all the buttons based on how they are named.     Add the following code to your page by using Actions -> On Enter -> Execute JavaScript  and adding the following to the script screen:

$('div[id^="Question"].cp-frameset').on("click", manageButtons );

function manageButtons(e) {
  var target = e.target.id ;
   
  var trueind = /_T_/;
  var falseind = /_F_/;
 
  var invTarget = (target.match(trueind) && target.replace(trueind,"_F_") ) || (target.match(falseind) && target.replace(falseind,"_T_") );

  cp.changeState(target, "selected"); 
  cp.changeState(invTarget, "Normal");
 
 }

As an overall explanation of what this does,  first we find all shapes that have an ID that starts with “Question” and hook on a function to run when these shapes are clicked.   Then we change the shape state to “selected” and the state of the other related shape to “Normal”      As it turns out,  Captivate appears to only add a success score when the shape state is something other than Normal..

Submit

The submit button performs the heavy lifting for checking if the answers are correct and relaying that information to Captivate to pass the score on to the LMS.   We create a shape to be the button,  then mark it to Use as Button in the properties.

To get the needed functionality,  the submit button will call a javascript function we define.   This is done under

Properties -> Action -> Execute Javascript

the javascript is as follows:

theAnswers = { 
 "Answer_1" : "Question_T_1",
 "Answer_2" : "Question_F_2",
 "Answer_3" : "Question_T_3",
 "Answer_4" : "Question_F_4",
 "Answer_5" : "Question_T_5"
 }

for ( answer in theAnswers) {
rightAnswer = theAnswers[answer]
theState = cp.getCurrentStateNameForSlideItem(rightAnswer);
if (theState != “Normal” ) { cp.SubmitInteractions(answer, cp.QuestionStatusEnum.CORRECT, 0) }
}

cpCmndNextSlide = 1;

also,  uncheck the box “Continue Playing the Project”  as we will control the player.

The way this works is that first, we define which of the true/false buttons needs to be selected to indicate a correct answer.  We then loop through each of these buttons to see if it was actually selected.   The magic is in the function “cp.SubmitInteractions”  which enables us to essentially click the answer button in javascript, indicating a correct response. Note that neither this or the function “cp.getCurrentStatementForSlideItem”  are documented.

Hiding the Answer Buttons

The answer buttons are not for the user,  so we just hide them under a smart shape that has the same color as the background where they cannot be clicked.

Timing

In general,  for question slides, we eliminate as much of Captivate’s built in timing control as possible.   All shapes timing are set to “Display for rest of slide” and start at time 0 (zero).  The Submit button is set to pause at 0.1 second.   That’s it.

Conculsion

Using the Quiz summary slide, you can see that scores are correctly summed for the complete interaction.

There is a lot of flexibility on quiz formats once some basic aspects of how scoring works in Captivate are clarified.  The strategy outlined here creates tremendous flexibility in developing custom user interactions, with the actual scoring and reporting performed by a simple JavaScript routine associated with a submit button.

There are numerous great tutorials on line that address all kinds of aspects of quizzes.  This approach is one of many alternatives.

For further information, contact sdwarwick (at) healthdecisions (dot) us

That’s Not Possible in Captivate! Oh, wait…maybe I can get by with a little help from JavaScript!

Case Study: I Get By With a Little Help from JavaScript… with Amazing Results

A while ago, I was asked if I could put together a set of addition problems for children in Captivate. However, the requirements were a bit daunting:

  1. The learner could continue solving problems, one after the other, all day. In essence, the number of problems to solve would need to be in the hundreds.

    Thoughts: Wouldn’t that mean creating hundreds of Captivate slides? Should they be quiz slides or content slides?

  2. The learner should be able to choose the lowest number and the highest number to add. For instance, the learner could choose to solve only one-digit numbers or to solve numbers that range between 134 and 189.

    Thoughts: Oh-oh. Now I’m looking at possibly thousands of slides, and choosing to jump to a certain section of slides depending on what range of numbers the learner chooses. But, really, I could maybe set up different quiz pools in which one pool is single digits, another is double-digit numbers, etc., and then randomly select from the proper pools.

    Three problems with this:
    1) I’d still have to create thousands of questions slides for those pools to work right.
    2) Every question in every pool must be part of the published files because questions are chosen randomly at run-time, so that’s going to make for a very big project.
    3) There’s still no way I could guarantee that I would show only numbers between an arbitrary range the learner chooses, such as only numbers between 43 and 65.

  3. The learner should be able to change the range at any time.

    Thoughts: Know what? I’m sorry, this isn’t going to work. Unless…wait a minute…

I started to think about how JavaScript could help. The next thing I knew, I had created:

  1. One slide in Captivate capable of presenting an infinite number of sum problems, in which…
  2. …the learner can choose the range, any range, at any time.

Yes! A little bit of JavaScript here will go a long way to making this a simple project.

How does this work?

First, I put three text entry boxes on the stage as you can see in the image. They are nothing special. The only thing I did to them was to:

  1. Set each to accept numbers only so that learners wouldn’t accidentally input other characters.1
  2. Set each text entry box to a variable name of my choosing:
    _rangeButton, _rangeTop, _learnerAnswer

Below you can see both the playback and the source stages. It’s important to run this off a web server, and not locally.

  1. Try the HTML5 version: http://www.elearningjoe.com/tools/captivate/jscpmath/index.html
  2. Try the Flash version:   http://www.elearningjoe.com/tools/captivate/jscpmath/CP-JS_MathProblems.htm

MORE NOTES ARE BELOW THE IMAGES.

2

3

Each of the two buttons executes JavaScript in Captivate.

Here is the JavaScript I wrote for Show Me a Problem. I’ve added line numbers here for easier referencing.

  1. var lowNum = window.cpAPIInterface.getVariableValue(‘_rangeBottom’);
  2. var highNum = window.cpAPIInterface.getVariableValue(‘_rangeTop’);
  3. var rand1 = Math.floor(Math.random() * (highNum – lowNum)) + lowNum;
  4. var rand2 = Math.floor(Math.random() * (highNum – lowNum)) + lowNum;
  5. cpAPIInterface.setVariableValue(‘_rand1’, rand1);
  6. cpAPIInterface.setVariableValue(‘_rand2’, rand2);

Lines 1 and 2 grab the values for the variables in Captivate _rangeBottom and _rangeTop, which start by default at 1 and 10 but that the learner can change at any time. It places them into two new declared I declared called lowNum and highNum.

Lines 3 and 4 each calculate a random integer within the defined range and puts them into the variables I declared called rand1 and rand2.

Lines 5 and 6 then put the random integer values into the Captivate variables called ­_rand1 and _rand2.

Pretty simple, right?

Here is the JavaScript for Am I Right?

  1. var rand1 = window.cpAPIInterface.getVariableValue(‘_rand1’);
  2. var rand2 = window.cpAPIInterface.getVariableValue(‘_rand2’);
  3. var sum = window.cpAPIInterface.getVariableValue(‘_learnerAnswer’);
  4. var sumFeedback;
  5. var corrSum = rand1 + rand2;
  6. if (sum == corrSum ) { sumFeedback = ‘That is correct!’; }
  7. else { sumFeedback = ‘Sorry, the answer is ‘ + corrSum + ‘.’; }
  8. cpAPIInterface.setVariableValue(‘_sumFeedback’, sumFeedback);

The first three lines grab the values for the variables in Captivate _rand1, _rand2 and _learnerAnswer and I place them into three variables I declare called rand1, rand2 and sum.

You might be wondering why we have to load the random values from Captivate. Wouldn’t it remember the values for the JavaScript variables rand1 and rand2 from the script we attached to Show Me a Problem? Didn’t I declare the JavaScript variables rand1 and rand2 in that script?

Yes, that is true, but there’s no guarantee that the learner will click the Show Me a Problem button first, so that script may not execute before the learner attempts to answer the first problem.

In fact, I set the starting values for the Captivate variables I created, _rangeBottom and _rangeTop, to 1 and 10 so that those two fields won’t start out empty. This means the learner could attempt to answer the problem 1 + 10 before entering new values and pressing Show Me a Problem. Therefore, I must declare them and load their values in this script in case the learner’s first step is to answer the problem on the screen, answering 1 + 10.

Line 4 declares the variable for our feedback.

Line 5 declares the variable corrSum and immediately sets it to be the addition of my two random numbers.

Lines 6 and 7 then checks whether the learner’s answer (sum) is equal to the value we just calculated (corrSum). If so, I set the feedback variable to That is correct! If not, we set it to Sorry, the answer is followed by the correct answer and a period.

Finally, Line 8 puts the value of our feedback variable into the Captivate variable _sumFeedback.

Let me know if you have any questions.