JavaScript and jQuery in Training Studio

The new version of Training Studio is completely HTML and JavaScript. Rather than using ActionScript to create interactions as in past versions, we now use JavaScript. In particular, we take advantage of the jQuery library to make it even easier than in past versions. Let’s look at an example. The script below is the entire JavaScript for the buttonClickLeftShowContentImageMediatemplate. The interaction is “buttonClick” on hotspots. In response to the click, the template shows content (text), an associated image, and/or plays associated media. I will make some comments/explanations in-line.

var lastHotspot = null;
var completionArray = [];
var numHotspots = 0;

Since these variables are declared outside a function block, they are effectively global to the page. They are used to keep track of completion and the “last” hotspot accessed (in order to set its style to HotspotCompleted).

$(function () {
	var pageArrayLocal = parent.pageArray; // associative array
	var keyId;
	var keyString;
	var keyValue;
	var objectSelector;
	var objectId;
	var hotspotNum;

The $ refers to jQuery. This function is called once the page completely loads. The reference to parent is to the index.htm page. Since it references TrainingStudioSupport.js, the parent.pageArray means that we are reading the global variable from that file. This pageArrayLocal variable is basically a dictionary that represents the current training page. The key matches up to the node or column in the database. They are title, subtitle, content_0, etc.


As with the pageArray variable, the line above calls the showTransition function in TrainingStudioSupport.js. This just shows the iFrame holding the template.

	for (keyId in pageArrayLocal) {
		keyString = keyId.toString();
		keyValue = pageArrayLocal[keyId];

		// handle unique ones here. Handle the rest in PopulateTemplate (TrainingStudioSupport.js)

We loop through each of the keys (content_0, media_0, etc.) and only handle the ones that need special handling by this template.

		switch (keyString) {
			// let "media_0" get handled by template       
			case "media_1":
			case "media_2":
			case "media_3":
			case "media_4":
			case "media_5":
			case "media_6":
			case "media_7":
			case "media_8":
			case "media_9":
			case "media_10":
				// let graphic_0 be handled by template   
			case "graphic_1":
			case "graphic_2":
			case "graphic_3":
			case "graphic_4":
			case "graphic_5":
			case "graphic_6":
			case "graphic_7":
			case "graphic_8":
			case "graphic_9":
			case "graphic_10":

We let standard PopulateTemplate (see below) method handle media_0 and graphic_0, since we want any initial sound, video, or animation to play and any initial graphic to display. The rest of the media (media_1 – media_10) and graphics (graphic_0 – graphic_10are only played/displayed in response to the hotspot interaction. So we don’t do anything except break when we encounter them.

			case "hotspot_1":
			case "hotspot_2":
			case "hotspot_3":
			case "hotspot_4":
			case "hotspot_5":
			case "hotspot_6":
			case "hotspot_7":
			case "hotspot_8":
			case "hotspot_9":
			case "hotspot_10":
				var contentId = parent.formatHotspot(keyValue);

				objectName = "#" + keyString;
				objectId = $(objectName);

				hotspotNum = parent.getFieldNum(keyString);
				numHotspots = Math.max(hotspotNum, numHotspots);


We first build a reference to the associated span object using jQuery. A jQuery reference to an object with an id of “hotspot_1” looks like this: $(“#hotspot_1”); In jQuery terms, the “#hotspot_1” is the selector. We call the formatHotspot() method of the TrainingStudioSupport.js using parent once again. This method looks for special bullet and hyperlink characters and returns the proper HTML. After creating our jQuery object reference, we strip the number (1, 2, 3, etc.) from the name of the object and use it to populate our hotspotNum variable. We keep a running total of the numHotspots as well. We use this to determine when all the hotspots have been selected. Finally, we associate the control’s click event with our hotspotClickHandlerfunction. This is what makes something happen when the user clicks on the hotspot.

				objectName = "#" + keyString;
				objectId = $(objectName);
				parent.PopulateTemplate(objectId, keyString, keyValue);

This line is where all the keys that we didn’t specifically handle are sent to PopulateTemplateinstead. This avoids duplicate code in every template.

	// bind keyboard events

This line associates the keydown event with the ImplementKeyDown function in TrainingStudioSupport.js. This allows us to go forward with the PageDown key and backwards with the PageUp key. It also shows the Comment Editor if the reviewOnvariable is true and the user presses Ctrl + Shift + M.


function hotspotClickHandler(e) {
	var targetId = $(this);

We use the jQuery selector, $(this), to figure out which hotspot (span) the user interacted with.

	var displayFieldId = $("#displayField");

Similarly, we make a reference to our “display field” object. We use this to set its text based on a naming scheme. When the user clicks on hotspot_1, we want to display any text in content_1.

	var hotspotName = targetId.attr("id");
	var hotspotNum = parent.getFieldNum(hotspotName);

We grab the id using the jQuery attr() function. We then find the associated number in order to work our naming scheme. hotspot_1 goes with media_1, graphic_1, and content_1and so on.

	if (lastHotspot != null) {
		lastHotspot.attr("class", "HotspotCompleted");

The first time through, the lastHotspot variable will be null. After that, it will refer to the hotspot previous to this interaction. In that case, we set its class to “HotspotCompleted.” This is how we get it to turn blue or otherwise show completion.

	lastHotspot = targetId;

We set the lastHotspot variable so we’ll be able to change its class the nexttime through.

	targetId.attr("class", "HotspotCurrent");

We change the class of this hotspot to “HotspotCurrent” to denote which one we are currently looking at.

	completionArray[hotspotNum - 1] = true;

We set the associated element (subtracting 1 since the array is zero-based) of our completionArrayto true. Once all the elements are “true,” the page is completed.

	parent.showTextImageMedia(displayFieldId, hotspotName, $("#graphic_0"), $("#media_0"), true); // include media

We call the showTextImageMedia method to display the associated content, play any associated media, and display any associated graphic. Note that we pass the object references to display the content (displayFieldId), show the graphic ($(“#graphic_0”)), or play the media ($(“#media_0”)). The parameter at the end determines whether to include media.

	parent.getHotspotCompleted(completionArray, numHotspots);

We pass our completionArray and the numHotspots variable to the getHotspotCompletedmethod. This will show a “completion” image if all the interactions are completed.


Adding a Paint Object Programmatically

For the ToolBook 11 version of Learning & Mastering ToolBook 11, we wanted to add the “Configuring LiveXtensions” button and associated graphic to a training page. However, the page was programmed to show and hide paint objects. Starting with ToolBook 10.5, however, the option to import paint objects was taken out. Instead, inserting a graphic now creates a bitmap resource and image object. We COULD have converted the other paint objects to resources and image objects, but why do that when we can still get a paint object via OpenScript using the code to below. The only slight snag is that the graphic was originally a .png. That wouldn’t import but the .bmp version worked fine.

importgraphic "C:\Users\Jeff\ToolBookProducts\ICBT110\training\resources\icbt2\update\LiveXtensionsConfiguration.bmp"