My favorites | English | Sign in

Faster apps faster - GWT 2.0 with Speed Tracer New!

Legacy Gadgets API (Deprecated)

Creating a User Interface

This document describes how to add different user interface elements to your gadget.

Contents

  1. Managing Gadget Height
  2. Setting a Gadget's Title
  3. Tabs
    1. Anatomy of a Tabs Object
    2. How It Works
    3. Generating Dynamic Content
    4. Manipulating Tabs By Index
    5. Customizing Tab Display
  4. Drag
    1. Adding and Removing Sources and Targets
  5. MiniMessages
    1. How It Works
    2. Creating Messages in Different Locations
    3. Creating Messages Using DOM Methods
    4. Creating a Timer Message
    5. Creating a Static Message
    6. Customizing MiniMessage Display
  6. Grid
    1. How It Works
    2. Simple Grid Example
    3. Beyond the Basics
  7. Flash
    1. Flash Example

Managing Gadget Height

By default, gadgets are 200 pixels high. You can use the <ModulePrefs> attribute height="nn" to specify a static height that is bigger or smaller than the default. You can use the <ModulePrefs> attribute scrolling="true" to cause your gadget to have a vertical scroll bar if the content height causes your gadget to exceed its designated height.

But some gadgets need to be able to dynamically change their height. For example, suppose you have a list gadget whose height needs to expand and contract depending on the contents of the list. As users add items to the list, the gadget grows. When they clear the list, the gadget returns to its original height. Here is what the running gadget might look like:

Grocery List Gadget

To give your gadget the ability to resize itself, you need to add the following things to your gadget spec:

  • A <Require feature="dynamic-height"/> tag (under <ModulePrefs>) to tell the gadget to load the dynamic-height library.
  • A call to the JavaScript function _IG_AdjustIFrameHeight() whenever there is a change in content, or another event occurs that requires the gadget to resize itself.

Note: The dynamic height feature only works on iGoogle, not in syndication or when a gadget is added to other Google properties.

For example, here is the gadget spec for the grocery list gadget:

<?xml version="1.0" encoding="UTF-8" ?> 
<Module>
  <ModulePrefs title="My Grocery List" 
    height="100"> 
    <Require feature="dynamic-height"/>
</ModulePrefs> <Content type="html"> <![CDATA[ <script type="text/javascript"> // This example lets users add items to a grocery list and then clear the list. // When items are added or cleared, the gadget resizes itself. var mylist = ""; var flag = 0; // Function that is invoked whenever user clicks the Add button to add an // item to the list. function addToList (form) { var input = _trim(form.inputbox.value); if (input == "") { return; } // Make alternating lines green/white, depending on value of flag variable. if(flag == 0){ mylist += "<div style='padding-left: 5px;background-color: #E6FFE6; font-family:Arial, Helvetica;'>" +input + "</div>"; flag = 1; } else { mylist += "<div style='padding-left: 5px;font-family:Arial, Helvetica;'>" +input + "</div>"; flag = 0; } // Call setContent to output HTML to div and resize gadget setContent(mylist); } // Clear the list function clearList(form) { // Call setContent to remove all items from the list and resize the gadget setContent(""); } // Outputs content to the div and resizes the gadget function setContent(html) { _gel('content_div').innerHTML = html; // Tells gadget to resize itself _IG_AdjustIFrameHeight(); } </script> <FORM NAME="myform" ACTION="" METHOD="GET"><BR> <INPUT TYPE="text" NAME="inputbox" VALUE=""> <INPUT TYPE="button" NAME="button" Value="Add" onClick="addToList(this.form)"> <INPUT TYPE="button" NAME="button2" Value="Clear" onClick="clearList(this.form)"> </FORM> <div id="content_div"></div> ]]> </Content> </Module>

For guidelines on testing a gadget's width and height, see Testing Width and Height.

Setting a Gadget's Title

You can use the _IG_SetTitle() function to programmatically set your gadget's title. To use this function, your gadget spec must include the following:

  • Under <ModulePrefs>, a <Require feature="settitle"/> tag to tell the gadget to load the settitle library.
  • A call to _IG_SetTitle()to set the gadget's title.

Note: The settitle feature only works on iGoogle, not in syndication or when a gadget is added to other Google properties.

The settitle library includes the following constructor:

Function Description
_IG_SetTitle(title) Changes the title of a gadget to title.

The following example sets the gadget's title in a variety of ways:

  • The gadget spec provides the default title "Original Title".
  • When the gadget loads, the _IG_SetTitle() function sets the title to "Set Title Demo Gadget".
  • When the user enters a new title, the _IG_SetTitle() function displays the title "Loading your new title...." one character at a time. Then it displays the new title set by the user.

Here is the gadget spec:

<?xml version="1.0" encoding="UTF-8" ?>
<Module> <ModulePrefs title="Original Title" > <Require feature="settitle" /> </ModulePrefs> <Content type="html"> <![CDATA[ <script language="JavaScript"> // Displays 'animated' message function animation(iteration, title) { var message = "Loading your new title...."; if (iteration < message.length) { iteration++; _IG_SetTitle(message.substr(0, iteration)); setTimeout('animation(' + iteration + ',"' + title + '");', 100); } else { _IG_SetTitle(title); } } // Changes gadget title to user input function changeTitle() { var title = _gel("submit_title").value; if (!_gel("cb").checked) { animation(0, title); } else { _IG_SetTitle(title); } } // Overwrites default gadget title when gadget loads _IG_SetTitle("Set Title Demo Gadget"); </script> The above title should say "Set Title Demo Gadget".<BR /> <font size=-1> <table> <TR><TD><BR /> Title Text: </TD><TD><BR /> <input type=text style='width:100%' value="Test Title" id="submit_title"> </TD></TR> </table><BR /> <input type=submit value="Change Title" onClick="changeTitle()"> <input type=checkbox id="cb"> Turn off loading animation </font> ]]> </Content> </Module>

Tabs

You can use the tabs library to add a tabbed user interface to your gadget. To use tabs, your gadget spec must minimally include the following:

  • Under <ModulePrefs>, a <Require feature="tabs"/> tag to tell the gadget to load the tabs library.
  • JavaScript for constructing your tabs and populating them with content. See How It Works for details. See the reference for a complete list of the functions in the tabs library.

It is also common to include the setprefs library so that the gadget can persistently store the user's last selected tab. Then if the user leaves the page and comes back, your gadget loads the remembered tab. To take advantage of this feature, embed two lines of code in your gadget spec:

<Require feature="setprefs"/>
...
<UserPref name="selectedTab" datatype="hidden"/>

Anatomy of a Tabs Object

The tabs library provides functions and CSS to operate on the following objects:

  • Tabs object. The tabs object is the parent container around all of the tabs. Programmatically, the tabs object is an array of individual tab objects. The underlying HTML implementation is typically a <table> element, referred to in the API as the "header container." You access this HTML through the getHeaderContainer() function. For a complete list of the functions you can call on the tabs object, see the reference.
  • Tab object. A tab object is a single tab within an array of indexed tabs. The underlying HTML implementation is typically a <td> element, referred to in the API as a "name container." You access this HTML through the getNameContainer() function. For a complete list of the functions you can call on an individual tab object, see the reference.
  • Content container. A content container holds the content for an individual tab object. The underlying HTML implementation is typically a <div> element, referred to in the API as a "content container." You access this HTML through the getContentContainer() function.

How It Works

You create a tabs object (that is, an object that contains a set of indexed tabs) using the _IG_Tabs() constructor. For example:

// Initialize tabs, designate the tab named "Two" as 
// the tab selected by default. 
var tabs = new _IG_Tabs(__MODULE_ID__, "Two"); 

Once you have a tabs object, you can add individual tabs to it using one of the addTab(...) functions. An individual tab has three major components: an index, a name, and a unique ID that matches the ID of a corresponding <div>. The <div> is where the tab's content gets placed. If you don't provide the <div> container yourself, the tabs library generates one for you.

You can add a tab to a tabs object and populate it with content in any of the following ways:

Technique #1: Capture the tab's ID when you create it, and use the ID to add content to the tab's corresponding <div>:

var one_Id = tabs.addTab("One"); 
_gel(one_Id).innerHTML = "Content for tab One.";

A variation on this approach is to define the tab name in HTML. For example:

var one_Id = tabs.addTab('<div style="color: red; font-weight: bold; background-color:#ccf;">Cool Tab</div>');
_gel(one_Id).innerHTML = "Content for tab One.";

Technique #2: Create the tab and add a corresponding <div> to the HTML portion of the gadget; place static content in the <div>:

tabs.addTab("Two", "two_id");
...
</script>     
<div id="two_id" style="display:none">Content for tab Two.</div>

Technique #3: Create the tab and add a corresponding <div> to the HTML portion of the gadget; place static content in the <div>. Use a callback function to add dynamic content to the static content:

tabs.addTab("Three", "three_id", callback); 
...
function callback(tabId) {
var p = document.createElement("p");
p.innerHTML = "This is dynamic content generated in callback.";
_gel(tabId).appendChild(p);
} ...
</script>
<div id="three_id" style="display:none">This is static content for tab Three.</div>

Technique #4: Use the addTab(tabName, opt_params) function to add a tab by name. The parameter opt_params can include any of the following:

  • contentContainer: Specifies an existing HTML element to be used as the tab content container. If the <div> doesn't exist, the tabs library creates one.
  • callback: Specifies a callback function to be executed whenever the tab is selected.
  • tooltip: Adds a tooltip description to the tab. When users mouseover the tab, the tooltip description pops up.
  • index: The index at which to insert this tab. If omitted, the tab is appended to the end by default.

For example:

tabs.addTab("Tab", { 
     contentContainer: _gel("domId"), 
     callback: func, 
     tooltip: "Popup description" 

}); 

This function is the preferred way of adding tabs since it is the most general and flexible. See the Gadget Preview Browser for an example of using this function.

Technique #5: Use the addDynamicTab() function to add a tab by name, and provide a callback function to generate dynamic content for it. In this scenario the tabs library creates the <div> for you:

tabs.addDynamicTab("My_Tab", callback); 
...
function callback(tabId)
{
// do something
_gel(tabId).innerHTML = [something];
}

For an example of the fifth technique, using a callback to generate dynamic content, see Generating Dynamic Content.

Here is a sample gadget that includes the first four ways of adding tabs and filling them with content:

Here is the gadget spec:

<?xml version="1.0" encoding="UTF-8" ?> 
<Module>

  <ModulePrefs title="Simple Tabs" height="140" scrolling="true" > 
    <Require feature="tabs" /> 
  </ModulePrefs>

  <Content type="html">
  <![CDATA[ 

    <script type="text/javascript">

    // Initialize tabs, designate the tab named "Two" as
    // the tab selected by default.
    var tabs = new _IG_Tabs(__MODULE_ID__, "Two");

    function init() {


        // Technique #1: Capture the tab's ID when you create it, and use the ID 
        // to add content to the tab's corresponding <div>.        
        var one_Id = tabs.addTab("One");       
        _gel(one_Id).innerHTML = "Content for tab One.";

        // Technique #2: Create the tab and define a corresponding <div> in the
        // HTML portion of the gadget. Add static content to the <div>.        
        tabs.addTab("Two", "two_id");


        // Technique #3: Create the tab and define a corresponding <div> in the
        // HTML portion of the gadget. Add static content to the <div>.
        // Use a callback function to add dynamic content to the static content.
        tabs.addTab("Three", "three_id", callback);

        // Technique #4: Create the tab with a tooltip message. Since the specified 
        // <div> doesn't exist, tabs library creates one.   
        // Invoke callback function.        
        tabs.addTab("Four", {            
           contentContainer: _gel("four_id"),
           callback: callback,            
           tooltip: "I'm special"          
        });
    }

    // Callback that provides content to tabs Three and Four
    function callback(tabId) {
      var p = document.createElement("p");
      // Get selected tab
      var selectedTab = tabs.getSelectedTab();
      p.innerHTML = "This is dynamic content generated in callback for tab " + selectedTab.getName();
      _gel(tabId).appendChild(p);
    }

    // Call init function to initialize and display tabs.
    _IG_RegisterOnloadHandler(init);
    </script>

   <div id="two_id" style="display:none">Content for tab Two.</div>
   <div id="three_id" style="display:none">This is static content for tab Three.</div>

  ]]>
  </Content>
</Module>

Generating Dynamic Content

The above example uses a callback function to add static content to a tab. But callbacks are more commonly used to provide dynamic content.

For example, in this sample gadget the callback function provides fresh content every time the user clicks a different tab. The callback displays the current date-time, down to the second. Consequently, the value changes each time a different tab is selected.

The gadget uses the function addDynamicTab(tab_name, callback_function). This function tells the tabs library "create a tab called tab_name, and use callback_function to fill the tab's associated <div> with content."

This is what the running gadget looks like:

This is the gadget spec:

<?xml version="1.0" encoding="UTF-8" ?> 

<Module>
  <ModulePrefs title="Dynamic Tabs"> 
    <Require feature="tabs" /> 
  </ModulePrefs>
  <Content type="html">

  <![CDATA[ 
    
    <script type="text/javascript"> 
    function init() {
        // Initialize tabs.
        var tabs = new _IG_Tabs(__MODULE_ID__); 

        // Technique #5: When you use addDynamicTab, the tab's content 
        // is dynamically generated through the callback function.
        tabs.addDynamicTab("One", callback);
        tabs.addDynamicTab("Two", callback); 
        tabs.addDynamicTab("Three", callback);
    }
    // Callback that displays the current date-time whenever a
    // new tab is clicked.
    function callback(tabId) {
        var date = new Date(); 
        _gel(tabId).innerHTML = date.toLocaleString();
    }

    // Call init function to initialize and display tabs.
    _IG_RegisterOnloadHandler(init);
    </script>

  ]]>
</Content> </Module>

Here is a more complex real-world example:

Manipulating Tabs By Index

The tabs API also includes functions that let you manipulate tabs by index. Tabs are indexed 0 through n, with 0 being the first tab. For example, if you have 3 tabs, their indices are 0, 1, and 2. You can use the indices to select a tab programmatically, and to switch the position of two tabs.

Note that while a tab's ID stays constant, its index does not. If you move the third tab into the first position, for example, its index changes from 2 to 0.

Here is an example of selecting a tab programmatically. This snippet creates a link. When the user clicks on the link, the second tab is selected, as if the user clicked on the tab itself:

<script>
...
function selectTab() {
tabs.setSelectedTab(1);
}
</script> <a href="javascript:void(0)" onclick="selectTab()">Select Second Tab</a>

Here is an example of moving a tab programmatically. This snippet creates a link. When the user clicks on the link, the gadget switches the positions of the first and second tabs:

<script>
...
function switchTabs() {
tabs.moveTab(0, 1);
} </script> <a href="javascript:void(0)" onclick="switchTabs()">Switch Tabs</a>

Customizing Tab Display

This section describes how you can customize the appearance of your tabs with CSS or JavaScript.

Here is an example of a gadget in which the tab display has been customized:

Customizing Tabs with CSS

The tabs CSS defines the classes that are applied to the HTML elements that lay out the tabs.

You can use the following CSS classes to override the default settings and modify the look and feel of your tabs.

CSS Class Description
.tablib_table Applies to the HTML table containing the tabs.
.tablib_selected Applies to the selected tab.
.tablib_unselected Applies to all unselected tabs.
.tablib_spacerTab Applies to the spacer elements between each tab.
.tablib_emptyTab Controls the beginning and end spacers around the tabs.
.tablib_navContainer Applies to parent container, which contains all tab-related content (that is, tab headers and all individual content containers).

Here are the default CSS classes and settings you can override:

.tablib_table {
width: 100%;
border-collapse: separate;
border-spacing: 0px;
empty-cells: show;
font-size: 11px;
text-align: center;
}
.tablib_emptyTab {
border-bottom: 1px solid #676767;
padding: 0px 1px;
}
.tablib_spacerTab {
border-bottom: 1px solid #676767;
padding: 0px 1px;
width: 1px;
}
.tablib_selected {
padding: 2px 0px;
background-color: #ffffff;
border: 1px solid #676767;
border-bottom-width: 0px;
color: #3366cc;
font-weight: bold;
width: 80px;
cursor: default;
}
.tablib_unselected {
padding: 2px 0px;
background-color: #dddddd;
border: 1px solid #aaaaaa;
border-bottom-color: #676767;
color: #000000;
width: 80px;
cursor: pointer;
}
.tablib_navContainer {
width: 10px;
vertical-align: middle;
}
.tablib_navContainer a:link, .tablib_navContainer a:visited, .tablib_navContainer a:hover {
color: #3366aa;
text-decoration: none;
}

For example:

<![CDATA[ 
  <style type="text/css"> 
   .tablib_selected { color: #FF0000; }
   .tablib_unselected { color: #660099; }
   .tablib_table { font-size:20px; }
   .tablib_emptyTab { padding:2px 5px; }
   .tablib_spacerTab { padding:0px 5px; }
</style>
<script...>

You can also use JavaScript to apply CSS styles to the tabs header container. The function getHeaderContainer()returns the tabs HTML table, which you can then modify as desired.

For example, this snippet changes the font size and adds some margin at the top:

var tabs = new _IG_Tabs();
...

var table = tabs.getHeaderContainer();
table.style.fontSize = "10px";
table.style.marginTop = "15px";

You can customize the style for individual tab headers by getting the individual tab elements and modifying their properties. Here's an example that makes the first tab's style unique:

var tabs = new _IG_Tabs();
tabs.addTab("Unique");
...
var firstTab = tabs.getTabs()[0].getNameContainer();
firstTab.style.backgroundColor = "#999999";
firstTab.style.color = "#ffffff";

Changing Tab Alignment

By default, tabs are centered as they're added. But if you have less than 3 or 4 tabs, you may want to align them to the left or right. You can do this using the alignTabs() function. It takes one parameter with the value left, right, or center. If you're aligning tabs to the left or right, there's an additional optional parameter that you can pass in to indicate the offset width from the left or right side.The default size is 3px.

For example:

var tabs = new _IG_Tabs();
...
// Align tabs to the left and offset it by 10 pixels
tabs.alignTabs("left", 10);

Hiding Tabs

You can use the displayTabs() function to toggle the display of tabs and their contents. This function takes a boolean value of either true or false.

Here's an example that creates a button that shows or hides the tabs:

<input onclick="toggleTabs()" type="button" value="Show/Hide"/>
<script>
var tabs = new _IG_Tabs();
...
var showTabs = true;
function toggleTabs() {
showTabs = !showTabs;
tabs.displayTabs(showTabs);
}
</script>

Drag

You use the drag library to add the drag feature to your gadget. To use drag, your gadget spec must include the following:

  • Under <ModulePrefs>, a <Require feature="drag"/> tag to tell the gadget to load the drag library.
  • JavaScript functions that describe your drag behavior. See the reference for a complete list of the functions in the drag library.

You use the drag library to make it possible for users users to drag and drop HTML elements in your gadget interface. For example, try dragging and dropping the different text elements onto the photo in this sample gadget:

This example illustrates the basic concepts in the drag library:

  • Source. Any DOM-enabled HTML element can be set to be a source, which is something that the user can click down on and drag.
  • Target. Any DOM-enabled HTML element can be set to be a target, which is something that a user can drop a source object onto. An object can be both a source and a target.
  • Surrogate. A surrogate is a blank object that impersonates whatever object is being dragged. As part of creating a source object, you can specify an HTML element to use as the source's surrogate (for example, <b>Dragging...</b>). By default, the surrogate is made to look like a clone of the source, and it follows the mouse cursor around as long as the mouse button is held down.

While the mouse button is held down, your gadget can keep track of which targets the user is passing the mouse over. You can also find out when the user lets go of the mouse button, and you can respond to that event by changing the HTML as needed.

The drag library centers around the callback functions listed in the following table:

Callback Function Description
onDragStart = function(newSource) {} Called when dragging starts.
onDragTargetHit = function(newTarget, lastTarget) {} Called when dragging is under way and a target has been hit.
onDragTargetLost = function(lastTarget) {} Called when dragging is under way and the user is no longer on a target.
onDragEnd = function(source, target) {} Called when dragging has ended (the user has let go of the mouse button).
onDragClick = function(source) {} Called when the user never moved the mouse, but had a mouse down and mouse up on a source.

For a summary of the functions in the drag library, see the reference

Here is the gadget spec for the above example. To use the drag library, you must include a <Require feature="drag"/> tag in the <ModulePrefs> section. Note that each HTML element is assigned a unique DOM ID. For more discussion of IDs and the different ways of adding sources and targets, see Adding and Removing Sources and Targets:

<?xml version="1.0" encoding="UTF-8" ?> 
<Module>
<ModulePrefs title="Special Effects" scrolling="true" height="320">
<Require feature="drag" />
</ModulePrefs>
<Content type="html">
<![CDATA[
<table border=0>
<tr>
<td>
<p id="id1" style="font-weight:bold;">original</p>
<p id="id2" style="color:brown; font-weight:bold;">sepia</p>
<p id="id3" style="color:red; font-weight:bold;">red</p>
<p id="id4" style="color:green; font-weight:bold;">green</p>
</td>
<td id="id5" style="padding-left:60;">
<img src="http://doc.examples.googlepages.com/Rowan-small.gif" alt="Rowan"/>
</td>
</tr>
</table>
<script type="text/javascript">
// Preload the images
var images = new Object();
images["id1"] = new Image();
images["id1"].src = "http://doc.examples.googlepages.com/Rowan-small.gif";
images["id2"] = new Image();
images["id2"].src = "http://doc.examples.googlepages.com/Rowan-small-sepia.gif";
images["id3"] = new Image();
images["id3"].src = "http://doc.examples.googlepages.com/Rowan-small-red.gif";
images["id4"] = new Image();
images["id4"].src = "http://doc.examples.googlepages.com/Rowan-small-green.gif";
// drag constructor
var drag_obj = new _IG_Drag();
// Add sources and target. In this example, there is one target: the photo.
drag_obj.addSource("original", _gel("id1"), "<p style=color:orange;>Restore original...</p>");
drag_obj.addSource("sepia", _gel("id2"), "<p style=color:orange;>Change to sepia...</p>");
drag_obj.addSource("red", _gel("id3"), "<p style=color:orange;>Change to red...</p>");
drag_obj.addSource("green", _gel("id4"), "<p style=color:orange;>Change to green...</p>");
drag_obj.addTarget("image", _gel("id5"));
// When user drags source onto target and releases it,
// display appropriate photo.
drag_obj.onDragEnd = function(source, target) {
if (target == null) return;
target.innerHTML = "<img src='" + images[source.id].src + "'/>";
}
</script>
]]>
</Content>
</Module>

Here is a more complex example, which lets you swap the locations of the different HTML elements:

Here is the gadget spec for the above example. It illustrates how to use all of the callback functions, as well as the _IG_Drag_surrogateOffset... properties, which let you specify where the surrogate should be when the drag starts. Because this example lets you swap the location of different HTML elements, each element is both a source and a target:

<?xml version="1.0" encoding="UTF-8" ?> 

<Module>
  <ModulePrefs title="Drag Example" scrolling="true">
    <Require feature="drag" /> 
  </ModulePrefs>

  <Content type="html">
  <![CDATA[ 
    <table border=0><tr>
        <td id="demo1">
          Try dragging these 
        </td><td id="demo2">

          <img src="http://doc.examples.googlepages.com/different.gif" alt="different"/>
        </td>
     </tr><tr>
        <td id="demo3">

          <ul>
            <li>HTML
            <li>elements
            <li>around
          </ul>
        </td><td id="demo4">

          <table border=1><tr>
            <td>on</td>
            <td>this</td>
            <td>page.</td>

          </tr></table>
        </td>
    </tr></table>
 
    <script type="text/javascript">
    // drag constructor
    var demo = new _IG_Drag();

    // Add sources and targets, and assign them id's.
    demo.addSource("demo1");
    demo.addSource("demo2");
    demo.addSource("demo3");
    demo.addSource("demo4");
    demo.addTarget("demo1");
    demo.addTarget("demo2");
    demo.addTarget("demo3");
    demo.addTarget("demo4");

    // Set location of where each surrogate is at the start of a drag.
    _gel("demo1")._IG_Drag_surrogateOffsetY = 20;
    _gel("demo2")._IG_Drag_surrogateOffsetY = 0;
    _gel("demo3")._IG_Drag_surrogateOffsetY = -10;
    _gel("demo4")._IG_Drag_surrogateOffsetY = 20;

    // Render initial display of HTML elements
    var data = new Array();
    data[0] = "<B>(swap with this)</B>"

    data[1] = _gel("demo1").innerHTML;
    data[2] = _gel("demo2").innerHTML;
    data[3] = _gel("demo3").innerHTML;
    data[4] = _gel("demo4").innerHTML;
    var currentSource = null;

    // When drag starts, selected source HTML element is passed in callback;
    // here is is assigned as value to currentSource.
    demo.onDragStart = function (object) {
        currentSource = object;
    }

    // When user drags source object onto a target object, display text 
    // "swap with this"
    demo.onDragTargetHit = function (object, old_object) {
        demo.onDragTargetLost(old_object);
        if (object != currentSource)
          object.innerHTML = data[0];
    }

    // Called when drag is underway and user isn't on a target
    demo.onDragTargetLost = function (object) {
        if (object == null) return;
        if (object.id == "demo1") object.innerHTML = data[1];
        if (object.id == "demo2") object.innerHTML = data[2];
        if (object.id == "demo3") object.innerHTML = data[3];
        if (object.id == "demo4") object.innerHTML = data[4];
    }

    // When user drags source onto target and releases it, swap objects.
    // Update surrogate positions.
    demo.onDragEnd = function(source, target) {
        if (target == null) return;
        var src; var trg;
        for (var i=1; i!=5; ++i) {
          if (source.id == "demo" + i) src = i; 
          if (target.id == "demo" + i) trg = i; 
        }
        var temp = data[src];
        data[src] = data[trg];
        data[trg] = temp;
        _gel("demo" + src).innerHTML = data[src];
        _gel("demo" + trg).innerHTML = data[trg];
        temp = _gel("demo" + src)._IG_Drag_surrogateOffsetY;
        _gel("demo" + src)._IG_Drag_surrogateOffsetY = _gel("demo" + trg)._IG_Drag_surrogateOffsetY;
        _gel("demo" + trg)._IG_Drag_surrogateOffsetY = temp;
    }
    </script>

  ]]> 
  </Content>
</Module> 

Adding and Removing Sources and Targets

As the above examples demonstrate, you create a drag object using the _IG_Drag() constructor:

var drag_obj = new _IG_Drag(); 

From the examples, you can see that there are multiple ways to create sources and targets. Sources and targets are HTML elements that have both a drag ID (the ID by which the drag API refers to them) and a DOM ID (the ID by which JavaScript refers to them). If you do not specify a drag ID when you add a source or target, the DOM ID gets used as the drag ID. For example, consider this HTML element declaration, in which the <h2> element is assigned the JavaScript ID "js-id1":

<h2 id="dom-id1">My First Element</h2>

This HTML element could be added as a source in any of the following ways:

// DOM ID becomes the drag ID 
drag_obj.addSource("dom_id1");
// Here the element is given a drag ID "first" which is different from the DOM ID.
drag_obj.addSource("first", _gel("dom_id1")); // A custom surrogate is included drag_obj.addSource("first", _gel("dom_id1"), "<b>This is my surrogate</b>");

For a list of the functions for adding and removing source and targets, see the reference.

MiniMessages

A MiniMessage is a temporary message displayed to users from within a gadget. MiniMessages are designed to be dismissed, either programmatically or by the user. The basic types of MiniMessages are as follows:

  • Dismissable messages that users can remove by clicking an [x].
  • Timer messages that disappear after a specified number of seconds have elapsed.
  • Static messages that must be programmatically dismissed.

To use MiniMessages, your gadget spec must include the following:

  • Under <ModulePrefs>, a <Require feature="minimessage"/> tag to tell the gadget to load the MiniMessage library.
  • JavaScript functions that describe your MiniMessage behavior. See the reference for a complete list of the functions in the MiniMessage library.

Some of the reasons you might want to use MiniMessages are as follows:

  • Promotion: You can use MiniMessages to display a promotional message in your gadget.
  • Status: Many gadgets fetch and load data behind the scenes. You can use MiniMessages to display "Loading..." or other status-related messages.
  • Debug/Error: If a gadget encounters an error, it can use MiniMessages to notify the user instead of silently failing.
  • Other: Depending on the type of gadget (for example, calendar, eBay), you may want to display notifications to users. Because MiniMessages are small and dismissible, you can use them to communicate special information.

Here is an example of a MiniMessage gadget that illustrates many of the techniques discussed in this section:

For examples of real-life gadgets that use the MiniMessage library, see Google Video and the Developer Gadget.

How it Works

The basic steps for adding a MiniMessage to your gadget are simple:

1. Import the minimessage library:

<Require feature="minimessage"/>

2. Instantiate a new MiniMessage object using the _IG_MiniMessage() constructor:

var msg = new _IG_MiniMessage(__MODULE_ID__);

In most cases, you'll want to make this a single global object that can be accessed from all scopes.

3. Create a new MiniMessage with some text:

msg.createDismissibleMessage("Please close me when you're done reading me.");

This adds a dismissable preformatted message with an associated [x] to the top of your gadget. When users click the [x], the message closes.

You're done! You've created one of the many types of dismissible messages.

Creating Messages in Different Locations

By default, messages are placed inside a container HTML element at the very top of the gadget. Each successive message is appended as a child to the container, in top-down order. But you can modify this behavior for either all messages or just a single message.

Setting a Location for All Messages

You can override the default location of the message container element by passing an HTML element, preferably a <div>, to the constructor. This element becomes the message container where messages are inserted and displayed.

For example, in this snippet the <h3> message "I'm on top now!" appears at the top of the gadget. The MiniMessages are displayed beneath it in the messageBox <div> in the order in which the messages were added.

<div>
<h3>I'm on top now!</h3>
</div>
<div id="messageBox"></div>
<script type="text/javascript"> // In the constructor, state that messages should be be displayed // in the messageBox <div> rather than at the top of the gadget. var msg = new _IG_MiniMessage(__MODULE_ID__, _gel("messageBox")); msg.createDismissibleMessage("I'm the first message."); msg.createDismissibleMessage("I'm the second message."); msg.createDismissibleMessage("I'm at the bottom."); </script>

Setting a Location for a Single Message

You can create a dismissible message in a designated location instead of appending it in the message container. You do this by marking up the message within the HTML portion of the gadget, and then passing the HTML element (preferably a <div>) as the first parameter to createDismissibleMessage().

For example, in this snippet the message is displayed within the status <div>:

<div id="status" style="color:#B30000;">
<b>Check out our new API documentation!</b> -- <a href="http://www.google.com/apis/gadgets" target="_blank">Read</a>
</div>
<script type="text/javascript"> var msg = new _IG_MiniMessage(__MODULE_ID__); // Pass the HTML element to createDismissableMessage() to indicate // where the message should be displayed. msg.createDismissibleMessage(_gel("status")); </script>

Creating Messages Using DOM Methods

There may be cases where you'll want to generate the dismissible message using HTML DOM methods. Since the message doesn't exist in the DOM, it is appended by default in the message container.

For example:

<script type="text/javascript"> 
  var msg = new _IG_MiniMessage(__MODULE_ID__);
  // Generate the message using DOM methods
  var div = document.createElement("div");
  div.innerHTML = "New message created by W3C DOM methods.";
  // Set some DOM properties
  div.onmouseover = function() {
    div.style.backgroundColor = "green";
  };
  div.onmouseout = function() {
    div.style.backgroundColor = "";
  };
  msg.createDismissibleMessage(div);

</script>

Creating a Timer Message

A timer message is a preformatted message that disappears after the specified amount of time has elapsed. The function createTimerMessage() takes two parameters: a message string, and a number indicating for how many seconds the message should be displayed. For example:

var msg = new _IG_MiniMessage(__MODULE_ID__);
msg.createTimerMessage("I'm going to disappear in 5 seconds.", 5);

Creating a Static Message

A static message is a preformatted message that displays until the message is programmatically dismissed by the dismissMessage() function. This is useful for displaying notification messages to keep the user informed while the gadget is executing background tasks, such as fetching content.

In this example, a static message is displayed to inform the user that a fetch is underway. When the fetch completes, the message is dismissed:

<div id="loading">Fetching content...</div>

<script type="text/javascript">
  var msg = new _IG_MiniMessage(__MODULE_ID__);
  var loadMessage = msg.createStaticMessage(_gel("loading"));

  _IG_FetchXmlContent('http://www.google.com/', function(responseText)
  {
    alert(responseText.substr(0,400));
    msg.dismissMessage(loadMessage);
  });

</script>

Customizing MiniMessage Display

There are two different ways to change the default appearance of MiniMessages:

  • Change the appearance of individual messages.
  • Globally change the appearance of all messages.

Changing the Style of Individual Messages

You use DOM functions to change a message's style. When you create a new dismissible message, an HTML element is returned. You can modify the appearance of a message by setting the style properties of the returned HTML element. For example:

<script>
  var msg = _IG_MiniMessage(__MODULE_ID__);
  var statusMsg = msg.createDismissibleMessage("This is a critical error!");
  // Change the message's background color to red
  statusMsg.style.backgroundColor = "red";
  statusMsg.style.color = "white";
</script>

Note: Notice that this example shows the correct way to change the entire background color of a message. Setting the background color of the <div> that contains the message doesn't change the entire background color.

Changing the Style of All Messages

You use CSS to globally change the style for all messages. The CSS defines the classes that are applied to the HTML elements that define MiniMessages.

You can use the following CSS classes to override the default settings and modify the look and feel of your messages.

CSS Class Description
.mmlib_table Applies to the HTML table containing the message.
.mmlib_xlink Applies to the [x] link used to dismiss a message. The setting applies to dismissible message only.

For example, this changes the background to navy blue and the foreground to white:

<![CDATA[
   <style>
     .mmlib_table__MODULE_ID__ {
       background-color: #000066;
       color: #ffffff;
     }
   </style>
<script...>

Here are the default CSS classes and settings you can override:

.mmlib_table {
  width: 100%;
  font: bold 9px arial,sans-serif;
  background-color: #fff4c2;
  border-collapse: separate;
  border-spacing: 0px;
  padding: 1px 0px;
  }
.mmlib_xlink {
  font: normal 1.1em arial,sans-serif;
  font-weight: bold;
  color: #0000cc;
  cursor: pointer;
  }

Grid

You use the grid library to add the grid feature to your gadget. To use the grid library, your gadget spec must include the following:

  • Under <ModulePrefs>, a <Require feature="grid"/> tag to tell the gadget to load the grid library.
  • JavaScript functions that describe your grid behavior. See the reference for a complete list of the functions in the grid library.

The grid library works with the drag library to provide a grid-based user interface. This example illustrates the basic concepts in the grid library. You can play tic-tac-toe by dragging the X and O on the right into the desired location on the grid.

How It Works

A grid typically consists of the following components:

  • An HTML table used to display content in a grid layout in your gadget. Each cell gets an index, numbered from 0 to height*width-1, in left-to-right, top-to-bottom order. You use these indices to refer to individual cells in the grid.
  • A backend object that dynamically manages the content displayed in the grid, and often stores it. You use the drag API to drag and drop cell contents within the grid.

The basic steps for using the grid library are as follows:

1. Import the grid library:

<Require feature="grid"/>

2. Create a backend object, and optionally initialize it with some data:

var ttt_backend = new Object();
    ttt_backend.data = new Array(".",".","."," ","X",
".",".","."," ","O",
".",".","."," "," ");

The backend object is responsible for managing the content displayed in the grid. The backend object minimally needs to know when items in the grid are sources and when they are targets, and what they look like. A grid typically displays data, and often this data is stored in the backend object.

3. Create a new _IG_Grid object:

var ttt_grid = new _IG_Grid(ttt_backend, "tictactoegrid", 3, 5);

The _IG_Grid constructor takes the backend object as its first parameter. The second parameter is a unique identifier for the grid that is prefixed in the ID field of all DOM objects used by the grid. Make sure you don't name anything with that string as a prefix. The third and fourth parameters are the height and width of the grid, respectively.

4. Display the contents of the grid:

grid.getTable().border = 2; 
grid.getTable().cellPadding = 5;
_gel("grid_table").appendChild(grid.getTable());

grid.getTable() returns the DOM object that contains the HTML table for the grid. You can change its settings just like any other DOM HTML table. To display it in your gadget, you use the appendChild() function.

5. Make the grid sensitive to dragging:

grid.initDragging(); 

6. Implement required backend functions.

As part of using the grid library, you must implement the following backend functions. See the example for sample implementations:

Function Description
_IGG_getNormalView(index) Returns the default HTML content of the cell at index to be displayed when the user is not dragging.
_IGG_isDragSource(index) Returns a boolean value to indicate whether the element at index is a drag source.
_IGG_isDragTarget(index, sourceIndex) Returns a boolean value to indicate whether the element at index is a drag target when sourceIndex is a drag source.

For a complete list of the functions in the grid library, see the reference.

Simple Grid Example

Here is the gadget spec for the tic-tac-toe example shown above:

<?xml version="1.0" encoding="UTF-8" ?>
<Module> <ModulePrefs title="Grid Test" > <Require feature="grid"/> </ModulePrefs> <Content type="html"> <![CDATA[ <span id="ttt_table"></span> <script type="text/javascript"> var ttt_backend = new Object(); ttt_backend.data = new Array(".",".","."," ","X",
".",".","."," ","O",
".",".","."," "," "); // Required backend function. Returns the default HTML content of the cell at index // to be displayed when the user is not dragging. ttt_backend._IGG_getNormalView = function(index) { return this.data[index]; } // Required backend function. Returns a boolean value to indicate whether the element // at index is a drag source. ttt_backend._IGG_isDragSource = function(index) { return (index == 4 /* X */ || index == 9 /* O */); } // Required backend function. Returns a boolean value to indicate whether the element // at index is a drag target when sourceIndex is a drag source. ttt_backend._IGG_isDragTarget = function(index, sourceIndex) { return (index % 5 == 0 || index % 5 == 1 || index % 5 == 2); } ttt_backend._IGG_handleDrag = function(source, target) { this.data[target] = this.data[source]; this._IGG_refreshCell(source); this._IGG_refreshCell(target); this.checkWin(); } ttt_backend.check_three_in_a_row = function(p1, p2, p3) { /* if p1 p2 p3 are all the same and not empty, change the win display. */ if (this.data[p1] == ".") return; if (this.data[p1] != this.data[p2]) return; if (this.data[p1] != this.data[p3]) return; this.data[14] = this.data[p1] + " wins!"; this._IGG_refreshCell(14); } ttt_backend.checkWin = function() { this.check_three_in_a_row(0,1,2); this.check_three_in_a_row(0,5,10); this.check_three_in_a_row(0,6,12); this.check_three_in_a_row(1,6,11); this.check_three_in_a_row(2,6,10); this.check_three_in_a_row(2,7,12); this.check_three_in_a_row(5,6,7); this.check_three_in_a_row(10,11,12); } // Create a new grid object var ttt_grid = new _IG_Grid(ttt_backend, "tictactoegrid", 3, 5); // The function grid.getTable() returns the DOM object that contains the // HTML table for the grid. You can change its settings just like any other // DOM HTML table. ttt_grid.getTable().border = 2; ttt_grid.getTable().cellPadding = 5; // Displays the table in your gadget. _gel("ttt_table").appendChild(ttt_grid.getTable()); // Makes the grid sensitive to dragging. ttt_grid.initDragging(); </script> <div id="content_div"></div> ]]> </Content>
</Module>

Beyond the Basics

The above example illustrates how to create a basic grid that displays dynamic content and responds to dragging actions. This section describes the grid library functions that let you add more complex behavior to a grid.

Grid Backend Display Functions

By default, the grid library calls getNormalView() whenever it wants to display the contents of a cell. However, you may want the contents of a cell to react and be displayed differently based on how the user is dragging. For those cases, you can implement the following optional functions for your backend object. For a demonstration of how to use these functions, see Advanced Grid Example.

Function Description
_IGG_getSurrogateView(index) Returns the HTML content of the surrogate view (visible under the mouse cursor) when the content at index is being dragged.
_IGG_getSourceView(source, target) Returns the HTML contents of the cell that is the source when the user is dragging. If the mouse cursor is over a target, then target contains the index of the target; otherwise, it contains -1.
_IGG_getTargetView(target, source) Returns the HTML content of the cell when it is the target and the user is dragging. The source is the index of the source.
_IGG_getPossibleTargetView(potential_target, source) Returns the HTML content of the cell when it is a potential_target (but not the target) and the user is dragging. The source is the index of the source.
_IGG_getDragView(index, source) Returns the HTML content of the cell at index when it is neither a potential target nor the source, and the user is dragging. The source is the index of the source.

Grid Backend Reaction Functions

The grid library provides the following functions to let your gadget respond to mouse clicking and dragging. For a demonstration of how to use these functions, see Advanced Grid Example.

Function Description
_IGG_handleClick(source) Called when the user has clicked the source (that is, when the user has performed a mouseDown and mouseUp without dragging the mouse).
_IGG_handleDragStart(source) Called when the user has done a mouseDown on the source and has started the drag process.
_IGG_handleDrag(source, target) Called when the user has finished dragging. If the user ended on a valid target, then target contains the target's index. Otherwise, it has the value -1.
Note that if _IGG_handleClick() is called, _IGG_handleDrag() is called too. So, depending on the application, it may make more sense to just use _IGG_handleDrag().

Grid Backend Callbacks

Backend callback functions are automatically created in your backend object. The grid library calls them as necessary, but you can also call them yourself, such as when your data is changing through a processes other than user dragging. The grid library includes the following backend callbacks:

Function Description
_IGG_refreshCell(index) Refreshes the display of the cell at index.
_IGG_refreshAll() Refreshes the display of all cells. Note that this can be a time-consuming operation, particularly if you have a large, complex grid.
When are Cells Refreshed?

After the user's drag has ended, the following cells are refreshed:

  • The source cell is refreshed if _IGG_handleDrag()is not defined.
  • The target cell is refreshed if _IGG_handleDrag()is not defined.
  • The potential target cells are refreshed if _IGG_getPossibleTargetView() is defined.
  • The non-potential target cells are refreshed if _IGG_getDragView() is defined.

What this means is that if you don't have the advanced views defined, but you do have _IGG_handleDrag() defined (and you almost certainly will), you need to call the _IGG_refreshCell() callback in it if you want the user to see the effects of the drag.

Advanced Grid Example

This example illustrates how to use the functions described above, in the Beyond the Basics section.

This grid has the following behaviors:

  • When you click and release on a cell without dragging, the value in that cell is incremented by 1.
  • When you begin a drag, all cells that are legitimate targets for the drag operation display text in green. Cells that are not legitimate targets display text in red. To be a legitimate target, a cell's value must not match the source value.
  • When you perform a drag, the surrogate (that is, the text that appears under the cursor) shows the source value, bolded.
  • When you are in mid-drag and the cursor is over a legitimate target for the source cell, the source cell displays source-value → target-value in gray, and the target cell displays source-value + target-value in green.
  • When you either click on a cell or initiate a drag in it, its value is displayed underneath the grid.
  • When you successfully complete a drag operation, the source value is added to the target value, the sum of the values is displayed in the target cell, and the source cell contains 0.

This is the gadget spec for the example:

<?xml version="1.0" encoding="UTF-8" ?>
<Module>
<ModulePrefs title="Advanced Grid Demo"
height="250" > <Require feature="grid"/> </ModulePrefs> <Content type="html"> <![CDATA[ <span id="grid_table"></span> Dragging: <span id="sdat">??</span> <script language="JavaScript"> // Create backend object, initialize with data var backend = new Object(); backend.data = new Array(1,2,3,4,5,6,7,2,1,7,4,5,6,3,5,7,3,6,4,1,2,7,6,5,4,3,2,1); // Default for cell content display backend._IGG_getNormalView = function(index) { var value = this.data[index]; return '<span style="font-size:24pt">' + value + '</span>'; } backend._IGG_isDragSource = function(index) { return true; } backend._IGG_isDragTarget = function(index, sourceIndex) { return this.data[index] != this.data[sourceIndex]; } // Returns the HTML content to be displayed under the cursor during a drag.
// In this example the surrogate view is the source value, bolded. backend._IGG_getSurrogateView = function(index) { var value = this.data[index]; return '<span style="font-size:24pt"><b>' + value + '</b></span>'; } // If the cursor is over a target, returns "source-value → target-value"
// in gray font for display in the source cell. Otherwise, returns source value. backend._IGG_getSourceView = function(source, target) { var s_value = this.data[source]; if (target == -1) { return '<span style="font-size:24pt;color:#888888">' + s_value + '</b></span>'; } else { var t_value = this.data[target]; return '<span style="font-size:10pt;color:#888888">' + s_value + '→' + t_value + '</b></span>'; } } // Returns the HTML content of cells that are legitimate targets for a drag operation. // In this example, a cell is a legitimate target if its value doesn't match the source value. // Cells that are legitimate targets display text in green. Cells that are not legitimate targets // display text in red, via the _IGG_getDragView() function below. backend._IGG_getPossibleTargetView = function(target, source) { var t_value = this.data[target]; // If a cell is a legal target, display its contents in a green font. return '<span style="font-size:24pt;color:#00A000">' + t_value + '</b></span>'; } // Returns the HTML content of cells that are NOT legitimate targets for a drag operation. // Cells that are not legitimate targets display text in red. // Cells that are legitimate targets display text in green via the _IGG_getPossibleTargetView() // function, above. backend._IGG_getDragView = function(target, source) { var t_value = this.data[target]; // If a cell is NOT a legal target, display its contents in a red font. return '<span style="font-size:24pt;color:#FF0000">' + t_value + '</b></span>'; } // If the cursor is over a target, returns "source-value + target-value"
// in green font for display in the target cell. backend._IGG_getTargetView = function(target, source) { var t_value = this.data[target]; var s_value = this.data[source]; return '<span style="font-size:12pt;color:#00A000">' + t_value + '+' + s_value + '</b></span>'; } // Clicking on a cell without dragging increments the value of the // cell's contents by 1. backend._IGG_handleClick = function(source) { this.data[source]++; // Callback on the backend object to force refresh this._IGG_refreshCell(source); } // When the user starts dragging, changes the message underneath the grid to show // the number that is being dragged. backend._IGG_handleDragStart = function(source) { document.getElementById("sdat").innerHTML = this.data[source]; } // If the user didn't drag to a legal target, don't change the data, but refresh the source // cell. Otherwise, adjust the numbers, and refresh the changed cells.
backend._IGG_handleDrag = function(source, target) { if (target == -1) { this._IGG_refreshCell(source); } else { this.data[target] += this.data[source]; this.data[source] = 0; // Callback on the backend object to force refresh this._IGG_refreshCell(source); this._IGG_refreshCell(target); } document.getElementById("sdat").innerHTML = '??'; } var grid = new _IG_Grid(backend, "mygrid", 4, 7); grid.getTable().border = 2; grid.getTable().cellPadding = 5; _gel("grid_table").appendChild(grid.getTable()); grid.initDragging(); </script> ]]>
</Content>
</Module>

See the reference for a complete list of the functions in the grid library.

Flash

You can use the flash library to embed a Flash movie (specifically, a .swf file) in your gadget. To embed Flash content, your gadget spec must minimally include the following:

  • Under <ModulePrefs>, a <Require feature="flash"/> tag to tell the gadget to load the flash library.
  • A call to _IG_EmbedFlash() to embed a .swf file in your gadget and display it in a designated location. Note that to use this feature, all resources must be bundled in a .swf file.

The flash library includes the following functions:

Function Description
_IG_EmbedFlash(swf_url, swf_container, opt_params) Embeds the .swf file specified by swf_url, and displays it in the gadget at the location specified by swf_container. The parameter opt_params is an object that optionally includes the following:
  • .swf_version : numeric | string (default = 0) Minimal Flash Player version required.
  • .width, .height : numeric | string (default = "100%"). Preferred width and height.
  • You can also define other fields such as .quality and .id and pass them to the Flash movie on creation.
_IG_EmbedFlash() returns true if successful, or false if not.

Note: If you experience performance problems or if the caret does not display (sometimes an issue in Firefox 2.0), try explicitly setting wmode to "window" as follows: _IG_EmbedFlash("example.swf", "wrapper", {wmode: "window"});
_IG_GetFlashMajorVersion() Returns the Flash Player's major version or zero if Flash Player is not detected.

Flash Example

When you click a button in this sample gadget, it plays the corresponding .swf file. When you click Stop, the gadget displays a still photograph.

Here is the gadget spec for the example:

<?xml version="1.0" encoding="UTF-8" ?> 
<Module> 
<ModulePrefs title="Trevor Does Tricks" height="300" scrolling="true">

  <Require feature="flash" />
  </ModulePrefs>
<Content type="html">
<![CDATA[

<style type="text/css">
  input.mybutton
  {
     background-color:#FFCC99;
     border-style:solid;
     border-color:#000000;
     font-family:Comic Sans MS,sans-serif;
     font-size:14px;
  }

</style>

<div id="flashcontainer" style="text-align: center;"></div> 

<script type="text/javascript">

  // Display still photo.
  function showPhoto() {
    _gel("flashcontainer").innerHTML = "<img src='http://doc.examples.googlepages.com/Trevor.JPG' />";
  }

  // Play .swf file for specified trick.
  function doTrick(trick) {

    // The URL for the .swf file that shows the specified trick.
    var url = "http://doc.examples.googlepages.com/Trevor-"+trick+".swf";

    // Play .swf file.
    _IG_EmbedFlash(url, "flashcontainer", {
      swf_version: 6,
      id: "flashid",
      width: 300,
      height: 250
    })
  }

  // When gadget first loads, display still photo.
  _IG_RegisterOnloadHandler(showPhoto);
  </script>

  <br />
  <div style="text-align: center;"> 
    <input type=submit class="mybutton" value="Spin" onClick="doTrick('spin')">

    <input type=submit class="mybutton" value="Speak" onClick="doTrick('speak')">
    <input type=submit class="mybutton" value="Sit" onClick="doTrick('sit')">

    <input type=submit class="mybutton" value="Down" onClick="doTrick('down')">
    <input type=submit class="mybutton" value="Stop" onClick="showPhoto()">

  </div>
  ]]>
</Content>
</Module>

Back to top