Difference between revisions of "The AdditionExample Applet"

From WeBWorK_wiki
Jump to navigation Jump to search
Line 62: Line 62:
 
Click on the applet and press '''<Ctrl>-<Shift>-D'''. The debug box should become invisible. Pressing the same key combination again should make the box appear again.
 
Click on the applet and press '''<Ctrl>-<Shift>-D'''. The debug box should become invisible. Pressing the same key combination again should make the box appear again.
 
== Initializing the Interface ==
 
== Initializing the Interface ==
  +
Before we go on, add the following imports under the <code>package</code> declaration:
  +
<nowiki>import flash.events.MouseEvent;
  +
import flash.events.Event;
  +
import flash.display.Shape;
  +
import flash.external.ExternalInterface;
  +
import flash.utils.Timer;
  +
import flash.events.TimerEvent;</nowiki>
  +
  +
Now add the following declarations to the <code>AdditionExample</code> class:
  +
<nowiki>private const appletName:String = "AdditionExample";
  +
private const DELAY:uint = 100;
  +
private var maxTrials:uint;
  +
private var interfaceTimer:Timer;</nowiki>
  +
  +
and modify the constructor as follows:
  +
  +
<nowiki>public function AdditionExample(maxTrials:uint=5, debugLevel:uint=2) {
  +
this.maxTrials = maxTrials;
  +
setDebug(debugLevel);
  +
addEventListener(Event.ADDED_TO_STAGE, addedToStage);
  +
}</nowiki>
  +
  +
Add the following code to the class:
  +
<nowiki>private function setUpInterface():void {
  +
if (debugLevel == 2) {
  +
dbBox.add("setUpInterface called.");
  +
}
  +
ExternalInterface.addCallback("getXML", getXML);
  +
ExternalInterface.addCallback("setXML", setXML);
  +
ExternalInterface.addCallback("setConfig", setConfig);
  +
ExternalInterface.addCallback("isActive", isActive);
  +
ExternalInterface.addCallback("getAnswer", getAnswer);
  +
ExternalInterface.addCallback("debug", setDebug);
  +
// Call applet_loaded to notify JavaScript that the
  +
// applet is ready to go.
  +
ExternalInterface.call("applet_loaded", appletName, 1);
  +
}
  +
  +
private function addedToStage(evt:Event):void {
  +
if (debugLevel == 2) {
  +
dbBox.add("Event ADDED_TO_STAGE received, will try to set" +
  +
"up communication with JavaScript");
  +
}
  +
//Set up communication with JavaScript
  +
if (ExternalInterface.available) {
  +
try {
  +
setUpInterface();
  +
} catch (err:Error) {
  +
if (debugLevel > 0) {
  +
dbBox.add("Exception caught calling applet_loaded." +
  +
"Setting up timer for further calls.", DebugBox.severityWarning);
  +
interfaceTimer = new Timer(DELAY, maxTrials);
  +
interfaceTimer.addEventListener(TimerEvent.TIMER, timerListener);
  +
interfaceTimer.addEventListener(TimerEvent.TIMER_COMPLETE, timerCompleteListener);
  +
interfaceTimer.start();
  +
return;
  +
}
  +
}
  +
if (debugLevel == 2) {
  +
dbBox.add("Interface with JavaScript apparently established.");
  +
}
  +
} else {
  +
if (debugLevel > 0) {
  +
dbBox.add("External interface not available", DebugBox.severityError);
  +
}
  +
}
  +
}
  +
  +
private function timerListener(evt:TimerEvent):void {
  +
if (debugLevel == 2) {
  +
dbBox.add("Retrying to set up communication with Javascript. " +
  +
"Number of trials: " + interfaceTimer.repeatCount.toString());
  +
}
  +
try {
  +
setUpInterface();
  +
} catch (err:Error) {
  +
if (debugLevel > 0) {
  +
dbBox.add("Exception caught in timerListener. Will try again in " +
  +
DELAY.toString() + " milliseconds (unless maximum number " +
  +
"of trials has been exceeded).");
  +
}
  +
}
  +
if (debugLevel == 2) {
  +
dbBox.add("Interface with JavaScript apparently established.");
  +
}
  +
interfaceTimer.stop()
  +
interfaceTimer = null;
  +
}
  +
  +
private function timerCompleteListener(evt:TimerEvent):void {
  +
if (debugLevel > 0) {
  +
dbBox.add("Unable to establish interface with JavaScript after " +
  +
maxTrials.toString() + " attempts",
  +
DebugBox.severityCritical);
  +
}
  +
interfaceTimer = null;
  +
}</nowiki>

Revision as of 15:06, 29 June 2011

Introduction

In this example, it is shown how to set up a simple applet for use in a WeBWork problem. The complete code for the applet, together with the corresponding PG file and debugging tools, can be downloaded from (add download site). The applet, shown below, asks for the sum of two integers. Notice that there are no buttons for checking the answer in the applet, since this will be handled by WeBWork.

AdditionExampleStart.jpg

Initial Setup

The initial code for the applet can be downloaded from (add download site), or it can be created by the following steps.

  1. Create a new applet in Flash and draw the controls as shown in the picture above. The first two text fields are of type Dynamic Text, and the rightmost one is of type Input Text
  2. Name the text fields, respectively, txtFirstNumber, txtSecondNumber and txtResult.
  3. Click anywhere on the stage outside of the controls and, in the properties pane, set the Class field to AdditionExample.
  4. Create a new ActionScript 3.0 class file and add the code below and save the file as AdditionExample.as.
package {
        import flash.display.MovieClip;

 	public class AdditionExample extends MovieClip {
 		public function AdditionExample() {
 			txtFirstNumber.text = "9";
 			txtSecondNumber.text = "7";
 		}
 	}
 }

At this point, the movie can be tested in Flash. It should display the applet with the numbers "9" and "7" in the first two text fields.

Debugging Tools

The interface between the applet and WeBWork cannot be tested inside the Flash environment. To simplify debugging, included in the downloaded package are two files:

  • DebugBox.as, an ActionScript class that displays a text area where debug messages can be sent.
  • ww_minimal.html, which contains JavaScript code that simulates the interaction between JavaScript and the applet without having to upload it to WeBWork. This makes it much easier to test the interface functions.

Copy these two files to the directory where the applet is located.

Important notice: in order to test the applet interface, the Flash player must be authorized to access local content. To do this, open ww_minimal.html in your browser. Right-click on the applet and select Global settings.... Click the Advanced tab and the Trusted Location Settings... button. Add the folder where your applet is located to the trusted sites.

Add the following two variables to the AdditionExample class:

private var debugLevel:uint = 0;
private var dbBox:DebugBox;

Change the constructor of the class as follows:

public function AdditionExample(debugLevel:uint=2) {
	setDebug(debugLevel);
}

Finally, add the following function to the class:

public function setDebug(debugLevel:uint):void {
	if (debugLevel > 0 && dbBox == null) {
		dbBox = new DebugBox(400, 200, 50, 10, 1);
		addChild(dbBox);
	}
	if (debugLevel == 0 && dbBox != null) {
		removeChild(dbBox);
		dbBox = null;
	}
	this.debugLevel = debugLevel;
	if (this.debugLevel > 0) {
		dbBox.add("setDebug called. debugLevel set to " + this.debugLevel.toString());
	}
}

Save the file and run it in Flash. The applet should now also display a text area with debug messages. Close the applet and open ww_minimal.html in your browser. The modified version of the applet should appear (if it does not, try clearing the cache in the browser).

Click on the applet and press <Ctrl>-<Shift>-D. The debug box should become invisible. Pressing the same key combination again should make the box appear again.

Initializing the Interface

Before we go on, add the following imports under the package declaration:

import flash.events.MouseEvent;
import flash.events.Event;
import flash.display.Shape;
import flash.external.ExternalInterface;
import flash.utils.Timer;
import flash.events.TimerEvent;

Now add the following declarations to the AdditionExample class:

private const appletName:String = "AdditionExample";
private const DELAY:uint = 100;
private var maxTrials:uint;
private var interfaceTimer:Timer;

and modify the constructor as follows:

public function AdditionExample(maxTrials:uint=5, debugLevel:uint=2) {
	this.maxTrials = maxTrials;
	setDebug(debugLevel);
	addEventListener(Event.ADDED_TO_STAGE, addedToStage);
}

Add the following code to the class:

private function setUpInterface():void {
	if (debugLevel == 2) {
		dbBox.add("setUpInterface called.");
	}
	ExternalInterface.addCallback("getXML", getXML);
	ExternalInterface.addCallback("setXML", setXML);
	ExternalInterface.addCallback("setConfig", setConfig);
	ExternalInterface.addCallback("isActive", isActive);
	ExternalInterface.addCallback("getAnswer", getAnswer);
	ExternalInterface.addCallback("debug", setDebug);
	// Call applet_loaded to notify JavaScript that the
	// applet is ready to go.
	ExternalInterface.call("applet_loaded", appletName, 1);
}

private function addedToStage(evt:Event):void {
	if (debugLevel == 2) {
		dbBox.add("Event ADDED_TO_STAGE received, will try to set" + 
				  "up communication with JavaScript");
	}
	//Set up communication with JavaScript
	if (ExternalInterface.available) {
		try {
			setUpInterface();
		} catch (err:Error) {
			if (debugLevel > 0) {
				dbBox.add("Exception caught calling applet_loaded." +
						  "Setting up timer for further calls.", DebugBox.severityWarning);
				interfaceTimer = new Timer(DELAY, maxTrials);
				interfaceTimer.addEventListener(TimerEvent.TIMER, timerListener);
				interfaceTimer.addEventListener(TimerEvent.TIMER_COMPLETE, timerCompleteListener);
				interfaceTimer.start();
				return;
			}
		}
		if (debugLevel == 2) {
			dbBox.add("Interface with JavaScript apparently established.");
		}
	} else {
		if (debugLevel > 0) {
			dbBox.add("External interface not available", DebugBox.severityError);
		}
	}
}
		
private function timerListener(evt:TimerEvent):void {
	if (debugLevel == 2) {
		dbBox.add("Retrying to set up communication with Javascript. " +
			  "Number of trials: " + interfaceTimer.repeatCount.toString());
	}
	try {
		setUpInterface();
	} catch (err:Error) {
		if (debugLevel > 0) {
			dbBox.add("Exception caught in timerListener. Will try again in " +
				   DELAY.toString() + " milliseconds (unless maximum number " +
				   "of trials has been exceeded).");
		}
	}
	if (debugLevel == 2) {
		dbBox.add("Interface with JavaScript apparently established.");
	}
	interfaceTimer.stop()
	interfaceTimer = null;
}
		
private function timerCompleteListener(evt:TimerEvent):void {
	if (debugLevel > 0) {
		dbBox.add("Unable to establish interface with JavaScript after " +
				  maxTrials.toString() + " attempts",
				  DebugBox.severityCritical);
	}
	interfaceTimer = null;
}