DocumentationUp until this point, the applications you’ve created have been fairly static. While they display information to the user, they really don’t do anything.
In this chapter, you will learn how to use scripting and event handling to make an application functional.
To get started, let’s take a relatively simple scenario. Suppose you want to create an application that displays a pop-up dialog window when a gadget is clicked, as shown in the following images.
Table 4.1. Displaying a pop-up dialog window using a script
![]() |
![]() |
|
Main Application Window |
Main Application Window with Pop-up Window |
To program this type of functionality, you must:
Create the content: a .box file that describes the main application window (which contains the "Click Here" user-defined gadget) and a second .box file that describes the pop-up window.
Create a JavaScript file with functions that enable the user-defined gadget to open the pop-up window.
Associate the JavaScript file with the user-defined gadget.
Use event handling to invoke the appropriate JavaScript function when the gadget is clicked.
The following code samples demonstrate how it works.
The code below describes the main application window. It is contained within its own .box file.
<?xml version="1.0" encoding="utf-8" ?>
<?import href="box://ocpToolkit/content/inputPack/inputGadgets.box"?>
<?import href="box://ocpToolkit/content/core/coreGadgets.box"?>
<?import href="box://ocpToolkit/theme/default/toolkit.box"?>
<window xmlns="http://www.aol.com/boxely/box.xsd"
xmlns:s="http://www.aol.com/boxely/style.xsd"
xmlns:on="http://www.aol.com/boxely/reaction.xsd"
s:fill="white"
title="My Application"
s:height="200"
s:width="275" >
<library xmlns="http://www.aol.com/boxely/resource.xsd"
xmlns:box="http://www.aol.com/boxely/box.xsd"
xmlns:s="http://www.aol.com/boxely/style.xsd"
xmlns:on="http://www.aol.com/boxely/reaction.xsd" >
<gadget id="myGadget" >
<parts>
<box:text id="buttonLabel" value="Click Here" />
</parts>
</gadget>
<style tag="myGadget" stroke="black" strokeWidth="1" strokeCornerRadius="4"
fill="#dddddd" fillCornerRadius="4" padding="1 4 2 4" margin="10"
vAlign="center" hAlign="center">
<part name="buttonLabel" textColor="black"/>
</style>
</library>
<vbox>
<multilineLabel value="This application demonstrates how to program a
gadget to perform a task. The following button is a custom, user-defined
gadget. When clicked, it displays a pop-up window."
s:margin="40 10 10 10" />
<box s:height="10" />
<myGadget/>
</vbox>
</window>
This code represents the pop-up window. It is contained within its own .box file.
<?xml version="1.0" encoding="utf-8" ?>
<?import href="box://ocpToolkit/content/inputPack/inputGadgets.box"?>
<?import href="box://ocpToolkit/content/core/coreGadgets.box"?>
<?import href="box://ocpToolkit/theme/default/toolkit.box"?>
<window xmlns="http://www.aol.com/boxely/box.xsd"
xmlns:s="http://www.aol.com/boxely/style.xsd"
xmlns:on="http://www.aol.com/boxely/reaction.xsd"
s:fill="white"
s:minHeight="100"
s:maxHeight="100"
s:minWidth="200"
s:maxWidth="200"
title="My Pop-up Window">
<library xmlns="http://www.aol.com/boxely/resource.xsd"
xmlns:box="http://www.aol.com/boxely/box.xsd"
xmlns:s="http://www.aol.com/boxely/style.xsd">
<gadget id="informationArea">
<parts>
<box:multilineLabel value="This is the pop-up window." />
</parts>
</gadget>
<style tag="informationArea" flex="1" hAlign="center" vAlign="center"/>
</library>
<informationArea id="dialog" dragMode="window"/>
</window>
In the above code, when the informationArea gadget is instantiated, notice that the dragMode attribute is set to "window". By including this attribute and setting it equal to "window", when the user attempts to drag the gadget, the entire window is dragged.
Once your content is in place, you can write JavaScript functions to perform the desired task: opening a new window.
In the Boxley UI Toolkit, there are several ways to incorporate JavaScript functions into an application. The most common method is through the association of a JavaScript file with a user-defined gadget. When you use this method, the JavaScript file must contain an object that represents the user-defined gadget, as well as the properties and functions required to perform the desired task. The following code, which is contained in its own .js file, demonstrates this method.
// The component function is called when the gadget is instantiated
function component (_gadget) { }
// The displayPopupWindow is called when myGadget is clicked
component.prototype.displayPopupWindow = function ()
{
shell.openScene("popupwindow.box",
this.scene, "PopupWindow", null, null, true);
}
From the developer’s perspective, the process for creating JavaScript functions associated with a gadget involves these steps:
First, you must create a JavaScript object named component. The Boxely UI Toolkit creates an instance of the component object when the gadget is first instantiated. Within its scope, you can include any code required to initialize the gadget.
Following the component declaration, attach one or more functions to the component object to carry out some action. When attaching a function to the component object, the prototype notation should be used (rather than attaching the function to the object in the object’s constructor), as it reduces the amount of memory used when multiple instances of the gadget are created.
To reference the gadget’s box, you can use this._gadget within any function included in the gadget’s script code.
In this example, the developer has attached the displayPopupWindow function to the component object using the prototype notation. It calls the shell.openScene method, which creates a new window object from the resource specified in the first parameter. The second parameter passed to the openScene method specifies the parent window for the pop-up window, and the third parameter specifies the pop-up window’s name. The fourth parameter can optionally take a dictionary object, if you wish to pass parameters to the new scene, and the fifth parameter takes a sceneListener parameter, which is used as a callback object to inform the caller when the scene has loaded. The last parameter indicates whether or not the pop-up window is modal.
When creating a JavaScript object that represents a user-defined gadget, you must always define a JavaScript object named component, as shown above. The component object is required if you plan to invoke any of the attached functions using the "gadget:functionName();" syntax from within the gadget’s XML markup. (You’ll learn how to call attached functions using this syntax in the next section.)
To associate JavaScript functions with their corresponding gadget, you must edit the gadget’s definition, as shown in the following code:
<library xmlns="http://www.aol.com/boxely/resource.xsd" xmlns:box="http://www.aol.com/boxely/box.xsd" xmlns:s="http://www.aol.com/boxely/style.xsd" xmlns:on="http://www.aol.com/boxely/reaction.xsd" > <gadget id="myGadget" language="jscript" code="myGadget.js" > <parts> <box:text id="buttonLabel" value="Click Here" /> </parts> <behavior> <reaction event="click" action="gadget:displayPopupWindow();"/> </behavior> </gadget> <style tag="myGadget" stroke="black" strokeWidth="1" strokeCornerRadius="4" fill="#dddddd" fillCornerRadius="4" padding="1 4 2 4" margin="10" vAlign="center" hAlign="center"> <part name="buttonLabel" textColor="black"/> </style> </library>
This is how it works:
In the library start-tag, the xmlns:on attribute declares the on namespace. This declaration is required for event handling, which we will discuss in more detail in the next section, More on Event Handling.
The language and code attributes included in the gadget start-tag associate the specified JavaScript file with the gadget, making its functions available to the gadget. (At runtime, the script will be loaded when the gadget is first instantiated in a scene. )
The behavior and reaction elements make up the event handler; it tells the OCP Toolkit to call the gadget’s displayPopupWindow function when the "click" event occurs.
In the event handler’s action attribute, notice the use of the "gadget:" scope. When calling a JavaScript function from within a gadget, you must use the "gadget:" prefix in front of the function name when you want to invoke a function attached to the gadget’s JavaScript. If you omit the "gadget:" prefix, the OCP Toolkit looks for a global function.
Once you’ve associated JavaScript functions with a gadget, you can test your work by running the .box file that controls the application.
If you’ve programmed the application correctly, the main application window displays and, when you press the "click here" gadget, a pop-up window opens.

If you are unsuccessful running your program, refer to the Appendix D: Troubleshooting Reference section of this guide.
When running a Boxely application, several singleton objects are available to you: shell, scene, and appUtils. These objects, and some of the methods available to them, are described in this section.
A shell is a singleton and is, essentially, the master of all scenes. It parses, creates, and destroys scenes. The shell also contains anything else that is at the global (across all scenes) level.
A partial list of methods defined for this class follows.
getCurrentEvent - This method returns the current event being dispatched.
getSceneAt -- The method returns the Scene object with the specified name.
openScene - This method creates and opens a new scene object from a specified URL (which references a .box file) that is passed as a parameter to the method.
closeScene - This method closes and disposes of the specified scene.
A scene is an entity containing a tree of gadgets or components (the DOM) and other supporting resources such as behaviors and themes. The scene is what makes up a single viewable region.
A partial list of methods defined for this class follows.
alert - This method pops a modal alert window with the given "message" and "title".
confirm - This method pops a modal confirm window with the given "message" and "title".
createBox - This method creates a box of a certain type (such as vbox, hbox, or your own custom gadget). Once created, you can insert it into your scene using the addChild or insertChildAt methods.
getBoxById - This method returns the "Box" object associated with the given ID.
The AppUtils class provides a number of mechanisms for interacting with other Boxely objects.
A partial list of methods defined for this class follows.
boxURLToPath - This method returns the absolute path of the "boxURL" parameter.
browseFolderDialog - Presents a system dialog chooser. Returns current selection as a string. If the dialog is canceled, the string will be null.
playSound - This function plays a sound file specified by a path and file name, which are passed as a parameter to the function.
saveFileDialog - Presents a system file save chooser. Returns current selection as a string.
In the previous section, you were introduced to the overall process for incorporating program logic into an application using scripting and event handling. In this section, we’ll take a closer look at event handling.
To be of use to us, an application must be able to respond to events that take place during its runtime, such as movement of the mouse, the initialization of a scene, or even the completion of an animation.
Some of the events to which a Boxely application can respond are:
Animation events - events relating to animations, such as "play", "stop", "firstFrame", "frame", "lastFrame", "pause", and "cancel". (Animations are explained in detail in Chapter 8: Using Animation.)
DOM events - events relating to objects in your application, such as "constructed", "initialized", "activated", "deactivated", "focus", and "blur".
Drag events - events relating to the drag-and-drop operation, such as "dragDrop", "dragMove", "dragOut", "dragOver", and "dragStart". (The drag-and-drop operation is explained in detail in Chapter 5: Drag-and-Drop.)
Keyboard events - events relating to the key-press operation, such as "keyDown", "keyPress", "keyUp".
Mouse events - events relating to mouse operations, such as "click", "mouseDown", "mouseMove", "mouseOut", "mouseOver", "doubleClick", and so on.
Mutation events - events relating to the mutation (or modification) of objects in an application, such as "attributeSet".
As the developer, it’s your job to program an application to listen for and respond to events, using one (or both) of the following methods:
Event handling using behaviors and reactions.
Event handling using the on namespace.
To program a gadget to listen for and respond to an event, you can use the behavior and reaction elements. The reaction element listens for an event; when the event occurs, it calls a corresponding action. The behavior element serves as a container for the reaction elements defined for the gadget.
Let’s look at an example. Suppose you want to program a gadget to call a specific function when the user places his or her mouse over the gadget and another function when the user clicks the gadget. To do so, you would add a behavior element and two contained reaction elements to the gadget’s definition, as shown below in bold:
<gadget id="myGadget" language="jscript" code="4a_eventHandling.js" >
<parts>
<box:text id="myPart" value="Change Gadget Fill" />
</parts>
<behavior>
<reaction event="mouseOver" action="gadget:changeFill();" />
<reaction event="click" action="gadget:oneNewWindow();" />
</behavior>
</gadget>
In this example, functions are invoked when an event occurs in any part of the gadget, as shown in the images below:
Upon loading, the gadget displays in its initial state. When the mouse is placed over any part of the gadget, the changeFill function is invoked.
The following code demonstrates how to program a box within the gadget to respond to events:
<gadget id="myGadget" language="jscript"
code="../../content/appendix/4a_eventHandling.js" >
<parts>
<box:text id="myPart" value="Change Gadget Fill" >
<box:reaction event="mouseOver" action="gadget:changeFill();" />
<box:reaction event="click" action="gadget:oneNewWindow();" />
</box:text>
</parts>
</gadget>
In this example, functions are invoked when an event occurs in the myPart box. If the user interacts with any part of the gadget that is outside the myPart box, nothing happens.
Upon loading, the gadget displays in its initial state. When the mouse is placed over the gadget, but not over the box within it, nothing happens. When the mouse is placed over the box within the gadget, the changeFill function is invoked.
As an alternative to using behaviors and reactions to create event handlers, you may use the on namespace by:
Declaring the on namespace in your XML code.
Adding the on:eventName attribute to the box that must respond to an event.
To declare the on namespace:
Before you can use the on namespace in your application, you must declare it. If you intend to apply on namespace attributes to window UI elements, declare the on namespace in the window start-tag, as shown below in bold.
<window xmlns="http://www.aol.com/boxely/box.xsd"
xmlns:s="http://www.aol.com/boxely/style.xsd"
xmlns:on="http://www.aol.com/boxely/reaction.xsd"
title="My Application" ... >
</window>
If you intend to apply on namespace attributes to objects defined in a library node (and the on namespace has not been declared in its parent node), declare it in the library start-tag, as shown here:
<window xmlns="http://www.aol.com/boxely/box.xsd"
title="My Application" ... >
<library xmlns="http://www.aol.com/boxely/resource.xsd"
xmlns:box="http://www.aol.com/boxely/box.xsd"
xmlns:s="http://www.aol.com/boxely/style.xsd"
xmlns:on="http://www.aol.com/boxely/reaction.xsd" >
...
</library>
</window>
To add the on:eventName attribute to a box:
Once you’ve declared the on namespace, you may use the on:eventName attribute to program a box to respond to an event. The on:eventName attribute is specified using this syntax:
on:eventName="someFunction();"
In this syntax, "eventName" is the name of the Boxely event to which the box must respond and "someFunction" is the name of a JavaScript function available to the gadget.
An example follows:
<gadget id="myGadget" script="someJavaScript.js" >
<parts>
<box:box on:mouseOver="gadget:changeFill()"
on:click="gadget:openNewWindow();" >
<box:text id="myPart" value="Change Gadget Fill" />
</box:box>
</parts>
</gadget>
In the code above, when the user places his or her mouse over the box, the changeFill function is called. When the user clicks the box, the openNewWindow function is called.
If you are unsuccessful running a Boxely application, refer to the Troubleshooting Reference for general debugging and troubleshooting tips.
Now that you’ve been introduced to the steps involved in programming a gadget, let’s try it out with the "To-Do List" application.
The first area that requires programming is the titleArea gadget. Up until this point, the date and time value shown within the titleArea gadget has been a static value of "00/00/00 12:00:00 PM." In this exercise, you’ll learn how to program the gadget to retrieve and display the current system time, as shown in the image on the right.
Table 4.4. A titleArea gadget with and without programming
![]() |
![]() |
|
titleArea Gadget (without programming) |
titleArea Gadget (with programming) |
Follow these steps to complete the exercise:
Step 1: Creating common JavaScript functions - Create a JavaScript file with common functions that can be used by any gadget in your application. This file will include the getDate function, which retrieves and formats the current system date and time.
Step 2: Creating JavaScript functions for the titleArea gadget - Create a second JavaScript file with functions specific to the titleArea gadget. In addition to the component function, this file will include an onInitialize function that sets the gadget’s dateTime part equal to the current system date and time returned by the getDate function.
Step 3: Associating JavaScript functions with the titleArea gadget - Associate the titleArea JavaScript file with the titleArea gadget and then modify the gadget’s definition to include a reaction that invokes the onInitialized function when the initialized event occurs.
Step 4: Testing your application - Run your application and verify that the current system date and time display.
Step 1: Creating common JavaScript functions
The first function needed in this exercise is the getDate function, a function that retrieves and formats the current system date. Because this function is potentially of use to many gadgets, it should reside in a common file with global scope.
You can create the getDate function on your own by writing a JavaScript function that returns a string representing the current system date and time. To save time, you can use the getDate function provided in the common.js exercise file, which is located in the ToDoList/common directory.
If you have not yet downloaded the "To-Do List" exercise files, refer to the Downloading Required Exercise Files section in the introduction of this guide.
Step 2: Creating JavaScript functions for the titleArea gadget
Next, you need to create JavaScript functions to represent the titleArea gadget and set the gadget’s dateTime display based on the current system date and time. These functions pertain to the titleArea gadget only, therefore the must reside in a single file named titleAreaGadgets.js.
In a text editor, create a new file named titleAreaGadgets.js and add the following code. Be sure to save the file in the same directory (/samples/TodoList) where the other "To-Do List" application files reside.
// The component function is called when the gadget is first instantiated
function component (_gadget) { }
// Declare properties for use in the gadget
component.prototype.dateTime = null;
// The onInitialized function is called when the gadget is created,
// but not yet presented (i.e. it’s called before it’s visible)
component.prototype.onInitialized = function()
{
// Get each part within the gadget based on its id attribute
this.dateTime = this._gadget.getPartById("dateTime");
// Set the value attribute of the dateTime box to the value getDate() returns
this.dateTime.setAttribute("value", getDate());
}
This is how the above code works:
The component function represents the titleArea gadget. The OCP Toolkit creates an instance of the component object when the gadget is first instantiated.
The onInitialized function uses the getPartById method to retrieve the gadget’s part identified as "dateTime". It then uses the setAttribute method to set the value of the dateTime part equal to the value returned by the getDate function. (The getDate function resides in the common.js file; in the next section, you will learn how make this function available to the gadget by including the file in your gadget’s definition.)
Step 3: Associating JavaScript functions with the titleArea gadget
Now, let’s edit the titleAreaGadgets.box file to:
Associate the titleAreaGadgets.js file with the titleArea gadget by adding the language and code attributes to the gadget’s start-tag.
Within the titleArea gadget, add a new script element to load the common.js file into the gadget.
Add a behavior and reaction element to invoke the onInitialized function when the initialized event occurs.
The initialized event occurs when your first instantiate a gadget in your .box file’s XML. When you instantiate a gadget within JavaScript using the createBox function, the initialized event is not fired. Instead, the boxCreated event is fired. As a result, if you need to add code to initialize a gadget that is created from within JavaScript, you need to listen for the boxCreated event.
The code shown below in bold demonstrates how to do this.
<gadget id="titleArea" language="jscript" code="titleAreaGadgets.js" > <script id="common" language="jscript" href="../../common/common.js" /> <parts> <box:label id="title" value="My To Do List"/> <box:label id="dateTime" value="Date/Time: 00/00/0000 12:00:00 PM" /> </parts> <behavior> <reaction event="initialized" action="gadget:onInitialized();" /> </behavior> </gadget>
Make sure you edit the script and href attribute values to address the appropriate location of the titleAreaGadgets.js and common.js files.
Step 4: Testing your application
Now that you’ve created the required JavaScript files and modified the titleArea gadget’s definition to call the appropriate function when it is first initialized, you can test your "To-Do List" application.
The current system time should display in the dateTime part of the titleArea gadget, as shown in the image below.

If you are unsuccessful running your Boxely application, refer to the Troubleshooting Reference for general debugging and troubleshooting tips.
In the "To-Do List" application, the buttonsArea gadget provides all navigational options available to the user:
Create a new To-Do List item.
Scroll through To-Do items using the "<< Prev Note" and "Next Note >>" links.
Clear a To-Do List item.
Clear the enitre To-Do List.
Let’s start with the first option: creating a new To-Do List item. The user experience should involve two phases:
Table 4.5. Creating a new To-Do List item
![]() |
![]() |
|
Select "Create To-Do Item" |
Enter item information and click "Insert Item" |
To implement this functionality, follow these steps:
Step 1: Creating JavaScript functions for the ToDoList gadget - Create a JavaScript file with functions specific to the ToDoList gadget. In addition to the component function, this file will include an onInitialized and onCreateItem function. The onCreateItem function opens a new dialog window (which is hereinafter referred to as the "Create New Item" dialog window).
Step 2: Associating JavaScript functions with the ToDoList gadget - Associate the ToDoList JavaScript file with the ToDoList gadget and then modify the gadget’s definition to invoke the onInitialized function when the initialized event occurs.
Step 3: Building the "Create New Item" dialog window - Create a .box file that represents the "Create New Item" pop-up dialog window and then create a corresponding JavaScript file with the functions needed to support the "Browse", "Insert Item", and "Cancel" buttons in the dialog window.
Step 4: Testing the "Create New Item" interface - Run the .box file that represents the "Create New Item" pop-up dialog window and press the buttons in it to ensure they work.
Step 5: Creating JavaScript functions for the buttonsArea gadget - Create a JavaScript file with functions specific to the buttonsArea gadget. In addition to the component function, this file will include an onInitialized and onCreateItem function. The onCreateItem function invokes the parent object’s function with the same name. (The parent object is the ToDoList.)
Step 6: Associating JavaScript functions with the buttonsArea gadget - Associate the buttonsArea JavaScript file with the buttonsArea gadget and then modify the gadget’s definition to invoke the onInitialized and onCreateItem functions.
Step 7: Testing your application - Run you "To-Do List" application and verify that you can click the "Create To-Do Item" button and then enter information about an item in the "Create New Item" interface. (When the main application window displays after creating the new "to-do" item, the item will not display; you’ll have to complete exercise 4.3 for this functionality.)
Step 1: Creating JavaScript functions for the ToDoList gadget
First, you need to create a JavaScript file to represent the ToDoList gadget and open the "Create New Item" dialog box.
In a text editor, create a new file named ToDoList.js and add the following code. Be sure to save the file in the same directory where other "To-Do List" application files reside.
// The component function is called when the gadget is first instantiated
function component (_gadget) { }
// Declare properties for use in gadget
component.prototype.titleArea = null;
component.prototype.noteArea = null;
component.prototype.buttonsArea = null;
component.prototype.items = Array();
component.prototype.currentItem = -1;
// The onInitialized function is called when the gadget is created,
// but not yet presented (i.e. visible)
component.prototype.onInitialized = function ()
{
// get each part of the gadget by their respective id attributes
this.titleArea = this._gadget.getPartById("titleArea");
this.noteArea = this._gadget.getPartById("noteArea");
this.buttonsArea = this._gadget.getPartById("buttonsArea");
// You now have access to the individual gadgets and can call their
// functions and access their properties
}
// The onCreateItem function is called when the ‘create to-do item’
// button is pressed.
component.prototype.onCreateItem = function ()
{
shell.print("ToDoList::onCreateItem");
var paramDictionary = shell.serviceManager.basics.dictionary;
paramDictionary.setValueForKey(this._gadget,"parentGadget");
// open a custom dialog
shell.openSceneAndWait("../../common/CreateNewItemDialog.box",
this.scene, "CreateNewItemDialog", paramDictionary);
}
component.prototype.insertItem = function (item)
{
this.items.push(item);
this.currentItem = this.items.length - 1;
}
The above code does the following:
The component function represents the ToDoList gadget. The OCP Toolkit creates an instance of the component object when the gadget is first instantiated.
The onInitialized function retrieves the parts within the ToDoList gadget and stores them in variables for later use.
The onCreateItem function first defines the paramDictionary object, a basics dictionary that can hold key-value pairs. In our case, the key is "parentGadget" and the value is a reference to the instance of the ToDoList gadget. We then call the openSceneAndWait function to open the dialog window defined by the CreateNewItemDialog.box file, passing the paramDictionary object to the dialog window. When the CreateNewItemDialog gadget’s onInitialized is called, it uses the setCallback function to store a reference to the ToDoList JavaScript object so that its insertItem function may be called when a new item has been created. This reference was obtained from the scene’s basics dictionary, which we passed through the openSceneAndWait function.
The insertItem function takes one parameter, item, which it adds to the items array. It then sets the location of the currentItem property equal to the position of the new item in the array.
Step 2: Associating JavaScript functions with the ToDoList gadget
Next, you need to edit the ToDoList.box file to:
Associate the ToDoList.js file with the ToDoList gadget by adding the language and code attributes to the gadget’s definition.
Add a behavior element to invoke the onInitialized function.
The code shown below in bold demonstrates how to do this.
<gadget id="ToDoList" language="jscript" code="ToDoList.js" > <parts> <box:titleArea id="titleArea"/> <box:noteArea id="noteArea"/> <box:buttonsArea id="buttonsArea"/> </parts> <behavior> <reaction event="initialized" action="gadget:onInitialized();" /> </behavior> </gadget>
Make sure you edit the script value to address the appropriate location of the ToDoList.js file.
Step 3: Building the "Create New Item" dialog window
The Create New Item dialog window contains the fields and buttons shown in the image below:

To create a new window within your application, you must create a new .box file that describes the window, as well as any JavaScript functions required to construct and support its layout.
To save time, the .box file that describes the "Create New Item" dialog window (createNewItemDialog.box) and its corresponding JavaScript file (createNewItemDialog.js) have been prepared for you and are available in the ToDoList/common directory.
Some of the functions in the createNewItemDialog.js that are worth noting are:
appUtils.openFileDialog - This function allows you to open a common file browser window that can be configured to accept certain file types. (In our case, we accept only Boxely-supported image file types.) At runtime, when the user selects one or more files and clicks "Open", the selected file paths and names are passed back as a return value of the openFileDialog function.
scene.close - This function closes the entire scene. In our case, we use it to close the createNewItemDialog scene when the user clicks "Insert Item" or "Cancel".
If you have not yet downloaded the "To-Do List" exercise files, refer to the Downloading Required Exercise Files section in the introduction of this guide.
Step 4: Testing the "Create New Item" interface
Once you’ve downloaded the "Create New Item" interface, you can test it by running the CreateNewItemDialog.box file.
You should see a window that looks like this:

To test the "Create New Item" interface:
Click the "Browse" button and then select an image.
Click the "Cancel" button and verify that the window closes.
Click the "Insert Item" button before you have entered an "Item Title". Make sure an appropriate data validation message displays.
If you attempt to populate all fields and then click the "Insert Item" button, you will receive an error. This is because we have not yet finishing programming the application. Do not worry about the error for now. By the end of this chapter, all functions in the ‘To-Do List" application will work.
If nothing happens when you click the buttons in the "Create New Item" interface, open the createNewItemDialog.box file and make sure its corresponding JavaScript file is referenced appropriately. For more general debugging and troubleshooting tips, refer to the Troubleshooting Reference.
Step 5: Creating JavaScript functions for the buttonsArea gadget
Now, you must create a JavaScript file to represent the buttonsArea gadget and initiate the "Create To-Do Item" function by calling the appropriate parent object function. (The parent object is the ToDoList.)
In a text editor, create a new file named buttonsAreaGadgets.js and add the following code. Be sure to save the file in the same directory where other "To-Do List" application files reside.
// The component function is called when the gadget is first instantiated
function component (_gadget) { }
// Declare properties for use in gadget
component.prototype.parent = null;
// The onInitialized function is called when the gadget is created,
// but not yet presented (i.e. visible)
component.prototype.onInitialized = function()
{
component.prototype.parent = this._gadget.gadgetParent;
}
/*
* Button Commands
* We pass off these commands to the parent gadget.
* We assume the parent gadget will know what to do.
*/
// create new item command
component.prototype.onCreateItem = function()
{
this.parent.onCreateItem();
}
This is how it works:
The component function represents the buttonsArea gadget. The OCP Toolkit creates an instance of the component object when the gadget is first instantiated.
The onInitialized function uses the gadgetParent method to retrieve the parent object and store it in the parent property. (As mentioned before, the parent object is the ToDoList.)
The onCreateItem function calls the onCreateItem method defined for the parent object. (You created the parent object’s onCreateItem function in step one.)
Step 6: Associating JavaScript functions with the buttonsArea gadget
Next, you need to edit the buttonsAreaGadgets.box file to:
Associate the buttonsAreaGadgets.js file with the buttonsArea gadget by adding the language and code attributes to the gadget’s definition.
Add the on:command attribute to the "Create To-Do Item" button to invoke the onCreateItem function.
Add a behavior element to invoke the onInitialized function when the initialized event occurs.
The code shown below in bold demonstrates how to do this.
<library xmlns="http://www.aol.com/boxely/resource.xsd" xmlns:box="http://www.aol.com/boxely/box.xsd" xmlns:s="http://www.aol.com/boxely/style.xsd" xmlns:on="http://www.aol.com/boxely/reaction.xsd" > <gadget id="buttonsArea" language="jscript" code="buttonsAreaGadgets.js" > <parts> <box:hbox id="prevNextButtons"> <box:textButton label="« Prev Note" tooltip="Go to your previous Note."/> <box:hbox s:flex="1"/> <box:textButton label="Next Note »" tooltip="Go to your next Note."/> </box:hbox> <box:button on:command="gadget:onCreateItem();" s:flex="1" defaultButton="true" icon="../../theme/images/iconWrite.png" label="Create To-Do Item" tooltip="Create new To-Do Note." /> <box:hbox> <box:button s:flex="1" icon="../../theme/images/iconClearItem.png" label="Clear To-Do Item" tooltip="Remove this Note from your list."/> <box:button s:flex="1" icon="../../theme/images/iconClearList.png" label="Clear To-Do List" tooltip="Remove all Notes from your list."/> </box:hbox> </parts> <behavior> <reaction event="initialized" action="gadget:onInitialized();" /> </behavior> </gadget> <style tag="buttonsArea" height="88" orient="vertical" > <part name="prevNextButtons" flex="1" margin="0 0 12 0"/> </style> </library>
Make sure you edit the script value to address the appropriate location of the buttonsAreaGadgets.js file.
Step 7: Testing your application
Now, when you run the "To-Do List" application, you should be able to select the "Create New Item" button and then enter information about a new item, as shown in the images here:
Table 4.6. Creating a new To-Do List item
![]() |
![]() |
|
Select "Create To-Do Item" |
Enter information about the item and click "Insert Item" |
While this is a great start, there is still a lot more to do. Proceed to the next section to learn how to program the noteArea and ToDoList gadgets to display items in the items array.
In this exercise, you will program the noteArea and ToDoList gadgets to display items in the items array. Perform the following steps to complete the exercise.
Step 1: Adding attributes to the noteArea gadget - Use the attributes element in conjunction with the inherits attribute to store and manage the data elements of a "to-do" item.
Step 2: Creating JavaScript functions for the noteArea gadget - Create a JavaScript file with functions specific to the noteArea gadget. In addition to the component function, this file will include an onInitialized, setDisplay, and blankDisplay function. The setDisplay function sets the gadget’s attributes (as defined by the attributes element) equal to the values of the current item that was passed to the function. The blankDisplay function sets the gadget’s attributes equal to static, default values.
Step 3: Associating JavaScript functions with the noteArea gadget - Associate the noteArea JavaScript file with the noteArea gadget and then modify the gadget’s definition to invoke the onInitialized function when the initialized event occurs.
Step 4: Adding JavaScript functions to the ToDoList gadget - Add functions to the ToDoList gadget to display the default item (when the application first loads) and the current item in the items array (after a new item has been created).
Step 5: Testing your application - Run your application and verify that the default item displays when the application first loads. Then, after creating a new item, verify that the new item displays.
Step 1: Adding attributes to the noteArea gadget
First, in the noteArea gadget, you will use the attributes element to define a set of default data attributes and values associated with the gadget: title, date, description, and image. (These attributes represent data elements of a "to-do" item in the items array.) Then, using the inherits attribute, you will reference these attributes from the relevant parts of the noteArea gadget.
Generally, when you have data associated with a gadget that needs to be manipulated in your application, you should use the attributes element in conjunction with the inherits attribute to manage the data. This method allows the gadget to control the data, without having to access and manipulate the parts within it.
To complete this step, edit the noteAreaGadgets.box file and:
Within the noteArea gadget element, add the attributes element to declare and initialize the following data attributes for the gadget: title, date, description, and image.
In the itemTitle, itemDate, and itemDescription parts, remove the value attribute. Then, add the inherits attribute to inherit the value defined in the corresponding data attribute.
In the itemImage part, remove the src attribute and then add the inherits attribute to inherit the value stored in its corresponding data attribute.
The code shown below in bold demonstrates how to do this.
<?xml version="1.0" encoding="utf-8" ?> <?import href="box://ocpToolkit/content/inputPack/inputGadgets.box"?> <?import href="box://ocpToolkit/content/core/coreGadgets.box"?> <?import href="box://ocpToolkit/theme/default/toolkit.box"?> <library xmlns="http://www.aol.com/boxely/resource.xsd" xmlns:box="http://www.aol.com/boxely/box.xsd" xmlns:s="http://www.aol.com/boxely/style.xsd"> <gadget id="noteArea"> <attributes title="" date="" description="" image="" /> <parts> <box:label id="itemTitle" inherits="value=title" /> <box:label id="itemDate" inherits="value=date" /> <box:vbox id="descriptionContainer"> <box:multilineLabel id="itemDescription" inherits="value=description" /> </box:vbox> <box:image id="itemImage" inherits="src=image" /> </parts> </gadget> <style tag="noteArea" orient="vertical" margin="12 0" flex="1" fill="url(#notepadImage)" hAlign="center" vAlign="top"> <part name="itemTitle" padding="0" margin="8 0 0 0" fontFamily="Arial" fontSize="22pt"/> <part name="itemDate" padding="0" margin="0" fontFamily="Arial" fontSize="12pt"/> <part name="descriptionContainer" overflow="scroll" minHeight="90" maxHeight="90" minWidth="280" maxWidth="280" hAlign="center" margin="14 0"/> <part name="itemDescription" width="240" minHeight="80" fontFamily="Brush Script" fontSize="14pt"/> <part name="itemImage" maxWidth="240" maxHeight="180"/> </style> </library>
In the parts of the noteArea gadget where you are using the "inherits" attribute, do not forget to remove the attribute that is inherited: value (for the itemTitle, itemDate, and itemDescription parts) and src (for the itemImage part).
Step 2: Creating JavaScript functions for the noteArea gadget
For the noteArea gadget, you must first create JavaScript functions to represent and initialize the gadget. Then, you need to create functions to display a default item (when the application first loads) and the current item in the items array (after a new item has been created).
In a text editor, create a new file named noteAreaGadgets.js and add the following code. Be sure to save the file in the same directory where other "To-Do List" application files reside.
// The component function is called when the gadget is first instantiated.
function component (_gadget) { }
// The onInitialized function is called when the gadget is first created,
// but not yet presented (i.e. visible)
component.prototype.onInitialized = function()
{
}
// The setDisplay function populates the noteArea gadget parts with
// the values in the element of the item array passed to the function.
component.prototype.setDisplay = function(item)
{
this._gadget.setAttribute("title", item["title"]);
this._gadget.setAttribute("date", formatDate(item["date"]));
this._gadget.setAttribute("description", item["description"]);
this._gadget.setAttribute("image", item["image"]);
}
// The blankDisplay function populates the noteArea gadget parts with
// default values.
component.prototype.blankDisplay = function()
{
this._gadget.setAttribute("title", "[no note to display]");
this._gadget.setAttribute("date", "");
this._gadget.setAttribute("description",
"Instructions: Add a note with the button 'Create To-Do Item' below.");
this._gadget.setAttribute("image", gDefaultImage);
}
This is how it works:
The component function represents the noteArea gadget. The OCP Toolkit creates an instance of the component object when the gadget is first instantiated.
The onInitialized function does nothing. (Don’t worry about it for now. In chapter nine, we’ll update this function to incorporate data binding.)
The setDisplay function sets the gadget’s data attributes (as defined in the gadget’s attributes element) equal to the values of the current item that was passed to the function.
The setAttribute method used in this function takes two parameters: the first is the name of the attribute to be set (the name must correspond to a value used in the gadget’s attributes element), the second is the value to which the attribute will be set.
The blankDisplay function sets the gadget’s attributes equal to static, default values.
Step 3: Associating JavaScript functions with the noteArea gadget
To use the noteArea JavaScript functions defined in the previous section, you must now edit the noteAreaGadgets.box file:
In the gadget start-tag, use the language and code attributes to associate the noteAreaGadgets.js file with the noteArea gadget.
In the gadget element, add a script element to load common.js. (The common.js file contains the location of the default image, gDefaultImage, used in a "to-do" item.)
In the gadget element, add a behavior element to invoke the onInitialized function.
The code shown below in bold demonstrates how to do this.
<gadget id="noteArea" language="jscript" code="noteAreaGadgets.js" > <attributes title="" date="" description="" image="" /> <script id="common" language="jscript" href="../../common/common.js" /> <parts> <box:label id="itemTitle" inherits="value=title" /> <box:label id="itemDate" inherits="value=date" /> <box:vbox id="descriptionContainer"> <box:multilineLabel id="itemDescription" inherits="value=description" /> </box:vbox> <box:image id="itemImage" inherits="src=image" /> </parts> <behavior> <reaction event="initialized" action="gadget:onInitialized();" /> </behavior> </gadget>
Important: In the above code, make sure you edit the script and href values to address the appropriate locations of the noteAreaGadgets.js and common.js files.
Step 4: Adding JavaScript functions to the ToDoList gadget
Next, you need to add JavaScript functions to the ToDoList gadget to display the default item (when the application first loads) and the current item (after a new item has been created).
Open the ToDoList.js file and add the following code shown below in bold.
// The component function is called when the gadget is first instantiated
function component (_gadget) { }
// Declare properties for use in gadget
component.prototype.titleArea = null;
component.prototype.noteArea = null;
component.prototype.buttonsArea = null;
component.prototype.items = Array();
component.prototype.currentItem = -1;
// The onInitialized function is called when the gadget is created,
// but not yet presented (i.e. visible)
component.prototype.onInitialized = function ()
{
// get each part of the gadget by their respective id attributes
this.titleArea = this._gadget.getPartById("titleArea");
this.noteArea = this._gadget.getPartById("noteArea");
this.buttonsArea = this._gadget.getPartById("buttonsArea");
// you now have access to the individual gadgets and can call their
// functions and access their properties
this.displayDefaultItem();
}
// The onCreateItem function is called when the ‘create to-do item’
// button is pressed
component.prototype.onCreateItem = function ()
{
shell.print("ToDoList::onCreateItem");
var paramDictionary = shell.serviceManager.basics.dictionary;
paramDictionary.setValueForKey(this._gadget,"parentGadget");
// open a custom dialog
shell.openSceneAndWait("../../common/CreateNewItemDialog.box",
this.scene, "CreateNewItemDialog", paramDictionary);
}
component.prototype.insertItem = function (item)
{
this.items.push(item);
this.currentItem = this.items.length - 1;
this.displayCurrentItem();
}
component.prototype.displayDefaultItem = function ()
{
this.noteArea.blankDisplay();
}
component.prototype.displayItem = function (index)
{
if (this.items.length == 0)
{
this.displayDefaultItem();
return;
}
if (index > (this.items.length - 1))
{
this.currentItem = this.items.length - 1;
}
else if (index < 0)
{
this.currentItem = 0;
}
else
{
this.currentItem = index;
}
var item = this.items[this.currentItem];
this.noteArea.setDisplay(item);
}
component.prototype.displayCurrentItem = function ()
{
this.displayItem(this.currentItem);
}
This is how the code above works:
The displayDefaultItem function calls the noteArea’s blankDisplay function, which sets the noteArea gadget attributes equal to static, default values.
The displayItem function takes one parameter, index, which represents the location of the item in the items array that is to be displayed. The function first checks if the length of the items array is zero, in which case it displays the default item and exits. If the length of the items array is not zero, the functions sets the currentItem property based on the following logic:
If the index that was passed to the function is greater than the position of the last item in the array, it sets the currentItem property equal to the position of the last item in the array.
Otherwise, if the index is less than zero, the currentItem property is set to zero.
Otherwise, if the index is not greater than that of the last item in the array and it is not less than zero, the currentItem property is set equal to the index.
Once the currentItem property it set, the noteArea’s setDisplay function is called, passing the item in the items array that has an index value equivalent to that stored in the currentItem property.
The displayCurrentItem function invokes the displayItem function, passing the currentItem as the index that represents the item to display.
Step 5: Testing your application
Now, when you first open the "To-Do List" application, you should see the default "to-do" item. When you create and insert a new item, that item should display, as shown in the images below:
Table 4.7. Inserting a new "to-do" item
![]() |
![]() | |
|
Create a new item and then select "Insert Item". |
The item displays in the main application window. |
Now that you can create and display new "to-do" items in the application, it’s time to look at the other buttons in the buttonsArea gadget: "Prev Note", "Next Note", "Clear To-Do Item", and "Clear To-Do List". Proceed to the next exercise to learn how to program these buttons.
In the final exercise of this chapter, you will program the remaining buttons in the buttonsArea gadget: Prev Note, Next Note, Clear To-Do Item, and Clear To-Do List.
Because these buttons manipulate the core data in the application, the buttonsArea functions will invoke functions defined in the parent object (the ToDoList), where the items array is stored.
To complete the exercise, follow these steps:
Step 1: Adding JavaScript functions to the ToDoList gadget - Add the following new functions to the JavaScript file associated with the ToDoList gadget: onPreviousItem, onNextItem, onClearItem, onClearAllItems, and deleteItem. These functions display and delete items in the items array.
Step 2: Adding JavaScript functions to the buttonsArea gadget - Add the following new functions to the JavaScript file associated with the buttonsArea gadget: onPreviousItem, onNextItem, onClearItem, and onClearAllItems. These functions invoke the corresponding function of the parent object (the ToDoList). Remember, the items array is a property of the ToDoList gadget; as a result, all core functions involving item data must be carried out by the ToDoList gadget.
Step 3: Associating JavaScript functions with the buttonsArea gadget - Modify the buttonsArea gadget definition to invoke the appropriate functions when the "Prev Note", "Next Note", "Clear To-Do Item", and "Clear To-Do List" buttons are clicked.
Step 4: Testing your application - Run your "To-Do List" application and verify that you can: create several "to-do" items, use the "Prev Note" and "Next Note" buttons to scroll through those items, and use the "Clear To-Do Item" and "Clear To-Do List" buttons to delete items.
Step 1: Adding JavaScript functions to the ToDoList gadget
First, you need to add JavaScript functions to the ToDoList gadget to display the previous or next item in the items array. In addition, you must define functions to clear one or all items in the items array.
Open the ToDoList.js file and add the following functions:
// navigation functions
component.prototype.onPreviousItem = function ()
{
shell.print("ToDoList::onPreviousItem");
this.displayItem(this.currentItem - 1);
}
component.prototype.onNextItem = function ()
{
shell.print("ToDoList::onNextItem");
this.displayItem(this.currentItem + 1);
}
// removal functions
component.prototype.onClearItem = function ()
{
shell.print("ToDoList::onClearItem");
// pop-up a confirm dialog
var confirmed = this.scene.confirm
("Are you sure you want to remove the item?", "Remove this item?");
if (confirmed.results)
{
// delete current item
this.deleteItem(this.currentItem);
this.displayCurrentItem();
}
}
component.prototype.onClearAllItems = function ()
{
shell.print("ToDoList::onClearAllItems");
// pop-up a confirm dialog
var confirmed = this.scene.confirm
("Are you sure you want to remove all the items?", "Remove ALL items?");
if (confirmed.results)
{
// delete all items
while (this.items.length > 0)
{
this.deleteItem(0);
}
this.displayCurrentItem();
}
}
component.prototype.deleteItem = function (index)
{
if (this.items == null || this.items[index] == null) { return; }
this.items.splice(index, 1);
}
This is how it works:
The onPreviousItem function calls the displayItem function, passing the index of the previous item in the items array to the displayItem function.
The onNextItem function calls the displayItem function, passing the index of the next item in the items array to the displayItem function.
The onClearItem function prompts the user for confirmation that she or he would like to delete the item. If the users select yes, the deleteItem function is called, passing the index of the current item in the items array to the deleteItem function. Then, the displayCurrentItem function is invoked.
The onClearAllItems function prompts the user for confirmation that she or he would like to delete all items. If the user provides confirmation, the function loops through all items in the items array, calling the deleteItem function to delete the current item at each iteration. Upon completion, it invokes the displayCurrentItem function.
The deleteItem function first checks the index value that was passed to it. If the index is null, or if an item does not exist in the items array for the specified index value, the function exits without doing anything. Otherwise, if the index is not null and the item specified by the index exists in the items array, the splice method is invoked to remove the item.
Step 2: Adding JavaScript functions to the buttonsArea gadget
Next, you need to add JavaScript functions to the buttonsArea gadget to invoke the appropriate parent object function when a button is clicked.
Open the buttonsAreaGadgets.js file and add the following code:
// navigation commands
component.prototype.onPreviousItem = function()
{
this.parent.onPreviousItem();
}
component.prototype.onNextItem = function()
{
this.parent.onNextItem();
}
// remove item or items from the note list
component.prototype.onClearItem = function()
{
this.parent.onClearItem();
}
component.prototype.onClearAllItems = function()
{
this.parent.onClearAllItems();
}
Step 3: Associating JavaScript functions with the buttonsArea gadget
To call functions when buttons are clicked, edit the buttonsAreaGadgets.box file, as shown below in bold:
<gadget id="buttonsArea" language="jscript"
code="buttonsAreaGadgets.js" >
<parts>
<box:hbox id="prevNextButtons">
<box:textButton on:command="gadget:onPreviousItem();"
label="« Prev Note" tooltip="Go to your previous Note."/>
<box:hbox s:flex="1"/>
<box:textButton on:command="gadget:onNextItem();"
label="Next Note »" tooltip="Go to your next Note."/>
</box:hbox>
<box:button on:command="gadget:onCreateItem();" s:flex="1"
defaultButton="true" icon="../../theme/images/iconWrite.png"
label="Create To-Do Item" tooltip="Create new To-Do Note." />
<box:hbox>
<box:button on:command="gadget:onClearItem();" s:flex="1"
icon="../../theme/images/iconClearItem.png"
label="Clear To-Do Item" tooltip="Remove this Note from your list."/>
<box:button on:command="gadget:onClearAllItems();" s:flex="1"
icon="../../theme/images/iconClearList.png"
label="Clear To-Do List" tooltip="Remove all Notes from your list."/>
</box:hbox>
</parts>
<behavior>
<reaction event="initialized" action="gadget:onInitialized();" />
</behavior>
</gadget>
Step 4: Testing your application
After completing the previous three steps, you should be able to run the "To-Do List" application and:
Create at least two new "to-do" items.
Navigate through the "to-do" items in your list using the "Prev Note" and "Next Note" buttons.
Clear a "to-do" item from the list.
Clear all "to-do" items from the list.
In this chapter, you learned how to use scripting and event handling to make an application functional. Specifically, you learned how to:
Create JavaScript functions that represent and manipulate objects in your application.
Associate JavaScript files with user-defined gadgets.
Invoke JavaScript functions using event handling.
To learn more advanced scripting and event-handling techniques, proceed to the next chapter, Chapter 5: Drag-and-Drop.