This document describes concepts and tasks that are fundamental to the gadget development process. For an introduction to using the gadgets API, see Getting Started.
One of the first decisions you make when you're developing a gadget is which content type to use. For example:
<Content type="html">
The content type determines:
The following table describes the available content types and when you should use them:
| Content Type | Description | When to Use |
|---|---|---|
html |
With an html content
type, all of the content typically resides in
the gadget spec. A type="html" gadget contains
HTML, possibly with embedded JavaScript, Flash,
ActiveX, or other browser objects. This is the
default type. |
The most flexible, versatile content type is
html. When in doubt, choose the html content
type. |
url |
With a url content
type, the gadget content lives on a remote web
page referenced by a URL in the gadget spec.
The remote web page is where all of the HTML
markup and JavaScript resides. You can NOT put
any HTML markup or JavaScript code in the gadget
spec itself. |
There are some restrictions on
using the gadgets JavaScript libraries
in a type="url" gadget.
Another restriction is that you cannot use the _IG_Fetch... functions
in a type="url" gadget. The url content
type may be the best choice if you are turning
an existing application or webpage into a gadget.
It is also usually the best choice for gadgets
that require login.
The url type is well-suited to professionals
who prefer to use a scripting language other
than JavaScript. |
With the html content type,
all of the code typically resides in the gadget spec.
This includes the gadget XML, and any HTML markup and
JavaScript. Almost all of the examples in this Developer
Guide use the html content
type. It is the most flexible, versatile type, and it
should usually be your choice unless you are writing
a gadget that has particular requirements.
The following example is a gadget implementation of ROT13. ROT13 encrypts text by replacing each letter with the letter 13 positions to the the right in the alphabet. Then when you reapply ROT13, it rotates each letter again, which restores the original text.
Here is the running gadget. Try it out! After you encode your message, paste the encoded message into the text box and click "Transform" again. Your original message will be restored.
This is the gadget spec:
<?xml version="1.0" encoding="UTF-8" ?>
<Module>
<ModulePrefs title="Magic Decoder"/>
<Content type="html">
<![CDATA[
<script type="text/javascript">
// The gadget version of ROT13.
// Encodes/decodes text strings by replacing each letter with the letter
// 13 positions to the right in the alphabet.
function decodeMessage (form) {
var alpha = "abcdefghijklmnopqrstuvwxyz";
var input = form.inputbox.value;
var aChar;
var message = "";
for (var i = 0; i <input.length; i++)
{
aChar = input.charAt(i);
var index = alpha.indexOf(aChar.toLowerCase());
// if a non-alphabetic character, just append to string
if (index==-1)
{
message += aChar;
}
// if you have to wrap around the end of the alphabet
else if(index > 12) { // compensate for 0-based index
index = 25 - index; // last item in array is at [25]
index = 12 - index; // because array starts with 0
aChar = alpha.charAt(index);
message += aChar;
}
// if you don't have to wrap
else {
aChar = alpha.charAt(index+13);
message += aChar;
}
}
_gel('content_div').innerHTML = "<b>Your message: </b>" + message;
}
</script>
<FORM NAME="myform" ACTION="" METHOD="GET">Message: <BR>
<INPUT TYPE="text" NAME="inputbox" VALUE=""><P>
<INPUT TYPE="button" NAME="button" Value="Transform" onClick="decodeMessage(this.form)">
</FORM>
<div id="content_div"></div>
]]>
</Content>
</Module>
The rules for a type="html" gadget
are as follows:
type="html" gadget
must include a CDATA section, and any HTML must go
within that section:<Content type="html">
<![CDATA[ HTML here... ]]>
CDATA sections are used to escape blocks of text containing characters that would otherwise be regarded as markup. The only delimiter that is recognized in a CDATA section is the "]]>" string that ends the CDATA section.
<html>, <head>, or <body> tags.
Gadgets are generated with their own <html>, <head>, and <body> tags.
Just include the content that would normally go inside
the <body> tag.A gadget with an html content
type can also reference an external JavaScript file:
<Module>
<ModulePrefs ... />
<Content type="html"><![CDATA[
<script src="http://www.example.com/gadgets/clock/clock.js" type="text/javascript"></script>
]]></Content>
</Module>
When a gadget has a type="url" content
type, the href= attribute
provides a URL, and any other content in the
gadget spec is ignored. With a url content
type, the assumption is that all information relating
to the gadget's user interface and programmatic logic
resides in the file referenced by the URL. You do not
put any HTML markup or JavaScript within the gadget itself. For
example:
<Module> <ModulePrefs ... /> <Content type="url" href="http://www/cgi-bin/example/gadgets/mystats.cgi" /> </Module>
For a description of the steps you need to take to use
the gadgets JavaScript libraries in a type="url" gadget,
see Using the JavaScript Libraries
with type="url" Gadgets.
Note that you must properly escape special characters
in the URL of a type="url" gadget,
as described in Escaping Special Characters.
You cannot use the _IG_Fetch... functions in a type="url" gadget.
By default, gadgets are displayed in iframes. Iframes
include a transparent margin if you don't put
in code to specify otherwise. Gadgets
with the content type html are
automatically generated with the appropriate
code to remove margins. However, when your content
type is type="url",
you are responsible for managing how your gadget
is displayed. To remove margins, include the
following text in the HTML file referenced by
your gadget:
<style type="text/css"> body {margin: 0px;} </style>
This example illustrates how you can extract the parameter
key-value pairs passed in the URL of a type="url" gadget
and use them in your target script or page.
When the gadget URL is requested
from an iGoogle
page, parameters are
appended to the request, which is a GET method.
This only applies when your content type is set to url.
These parameters can be read by a gadget using JavaScript,
or by a server-side web application.
The parameters that are passed are listed in the Reference.
In this example, the gadget contains a reference to a target PHP script, params.php:
<?xml version="1.0" encoding="UTF-8" ?>
<Module>
<ModulePrefs title="Preferences for __UP_myname__" height="250" /> <UserPref name="mychoice" display_name="List Params?" datatype="bool"/> <UserPref name="myname" display_name="Name" required="true"/> <UserPref name="mycolor" display_name="Color" default_value="Blue" datatype="enum"> <EnumValue value="Red"/> <EnumValue value="Blue"/> <EnumValue value="Green"/> <EnumValue value="Yellow"/> <EnumValue value="Pink"/> <EnumValue value="Orange"/> <EnumValue value="White"/> </UserPref> <Content type="url" href="http://www.example.com/params.php"/> </Module>
The target page uses JavaScript to process the parameters that the gadget passes to it in the URL.
Here is an example of the running gadget with the user preferences edit box open. Users are given the option of listing the parameters passed to the target HTML page. If they don't check the "List Params" checkbox, a personal greeting is displayed instead.
The gadget passes its parameters as key-value pairs in a GET request. User preferences are passed as parameters with the format &up_userpref=value.
For example, this sample gadget has a user preference named
mycolor. If, for example, the setting is “Pink”, it is passed in the URL as &up_mycolor=Pink. The URL passed for this gadget might resemble the following:
http://www.example.com/~rowan/gadgets/index.html?up_mychoice=1&up_myname=Foster&up_mycolor=Pink&.lang=en&.country=us
This is the file params.php that is referenced
in the gadget spec. The PHP code strips the libraries out of
the URL passed into the gadget and adds them to the gadget,
as described in Using the JavaScript
Libraries with type="url" Gadgets. The JavaScript
code uses the _args() function to get the
URL parameters as an associative array.
JavaScript on the target HTML page puts the parameters into an array and modifies the gadget settings according to the preferences the user specified.
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<style type="text/css"> </style>
<TITLE> Userprefs Params Example </TITLE>
</HEAD>
<BODY>
<div id="content_div" style="font-size:12pt; padding:5px;"></div>
<?php
// Parse gadget URL and emit <script src=...</script> statements into the HTML output.
// The <script src=...</script> statements will load the libraries passed in via the URL.
$libraries = split(",", $_GET["libs"]);
foreach ($libraries as $script) {
if (preg_match('@^[a-z0-9/._-]+$@i', $script)
&& !preg_match('@([.][.])|([.]/)|(//)@', $script)) {
print "<script src='http://www.google.com/ig/f/$script'></script>";
}
}
?>
<script type="text/javascript">
// Set background color according to user choice.
var element = document.getElementById('content_div');
element.style.backgroundColor = _args()["up_mycolor"];
// Build HTML string used to display content
var html = "";
// If checkbox ("List KVPs") is not checked, display personal welcome message. // Use _args() function to access the parameter name-value pairs. if (_args()["up_mychoice"]==0) { element.style.height=200; html += "<br><br><br><br><FONT SIZE=6>Welcome, " + _args()["up_myname"] + "!!!<br> </FONT>"; } // Otherwise, if box is checked, list KVPs. else { html += "<br><B>Params Passed in URL: </B><br><br>"; // Iterate through the _args() associative array to print out all of the parameter key-value // pairs passed in the URL. for(var param in _args()) { var value = _args()[param]; html +=param +"="+ value + "<br>"; } } _gel("content_div").innerHTML = html; </script> </BODY> </HTML>
The gadgets API has two different kinds of JavaScript libraries: the core library, and the feature-specific libraries for features such as tabs, dynamic height, and setprefs. The core library provides generic functions. The feature-specific libraries provide functions for particular features.
The following table summarizes what each type of gadget has to do to use the gadgets JavaScript libraries:
| Content Type | Restrictions on Using JavaScript Libraries | Steps to Use JavaScript Core Library | Steps to Use JavaScript Feature-Specific Libraries |
|---|---|---|---|
html |
None. | Can use the core library functions without doing anything special. | The gadget spec must include a <Require
feature="[feature]"/> statement
to include the appropriate library. |
url |
The gadget href must reference a server-side
script (such as a PHP, Python, Java, or CGI script).
The href can't point to a plain HTML/JavaScript
file. |
The core library is always passed in the URL
for type="url" gadgets. The gadget
must parse the URL to extract the library and
construct a <script src=...</script> statement
for it to be included in the emitted HTML. This
statement tells the gadget to load the library. |
The gadget spec must include a <Require
feature="[feature]"/> statement
to include the appropriate library.The gadget
must parse the URL to extract the library and
construct a <script src=...</script> statement
for it to be included in the emitted HTML. This
statement tells the gadget to load the library. |
To use the gadgets JavaScript
API in a type="url" gadget,
you must follow these guidelines:
href must
reference a server-side script, such as a PHP, Python,
Java, or CGI script. <script
src=...</script> statements for them.
The <script src=...</script> statements
are included in the emitted gadget HTML. For example,
this URL parameter:http://...&libs=2dhyBXfcpQ8/lib/libcore.js...
is extracted from the URL and used to construct the following statement, which gets added to the emitted HTML. This statement says "load the gadgets core JavaScript library:"
<script src='http://www.google.com/ig/f/2dhyBXfcpQ8/lib/libcore.js'></script>
See the setprefs.php example
below for the PHP code used to construct this statement.
The string "2dhyBXfcpQ8" is
a fingerprint made from the contents of the .js file
that forces the browser to use the correct version of
the file.
Here is an example of the HTML-type setprefs example gadget converted into a type="url" gadget.
This is the gadget spec:
<?xml version="1.0" encoding="UTF-8" ?>
<Module>
<ModulePrefs
title="PHP Userprefs" height="50" >
<Require feature="setprefs" />
</ModulePrefs>
<UserPref
name="counter"
default_value="0"
datatype="hidden"/>
<Content type="url" href="http://www.example.com/mygadgets/setprefs.php"/>
</Module>
Here is the setprefs.php file that is referenced in the gadget spec:
<html> <head> <?php // Parse gadget URL and emit <script src=...</script> statements into the HTML output. // The <script src=...</script> statements will load the libraries passed in via the URL. $libraries = split(",", $_GET["libs"]);
foreach ($libraries as $script) {
if (preg_match('@^[a-z0-9/._-]+$@i', $script)
&& !preg_match('@([.][.])|([.]/)|(//)@', $script)) {
print "<script src='http://www.google.com/ig/f/$script'></script>";
}
} ?> <script type="text/javascript"> // Get user preferences var prefs = new _IG_Prefs(); // Increment value of "counter" user preference function incrementCounter() { var count = prefs.getInt("counter"); alert("The count is " + count + "."); // Increment "counter" userpref prefs.set("counter", count + 1); } // Reset value of "counter" userpref to 0 function resetCounter(){ prefs.set("counter", 0); alert("Count reset to " + prefs.getInt("counter") + "."); } </script> </head> <body> <input type=button value="Count" name="count" onClick="incrementCounter()"> <input type=button value="Reset" name="reset" onClick="resetCounter()"> </body> </html>
You can turn an existing web page or application into a gadget by following these guidelines:
<html>, <head>,
and <body> tags
(in other words, just provide the HTML content itself).
This guideline only applies to type="html" gadgets.
It does not apply to type="url" gadgets. _IG_RegisterOnloadHandler()._IG_FetchContent() can
be used to proxy the content. For commercially developed
gadgets, we recommend simply creating a new, small
page and using type="url" to
point to it.Within the gadget spec, every user
preference has a data
type. The datatype is an
optional string that specifies the data type of the attribute.
The possible values for datatype are string, bool, enum, hidden (a
non-visible string that is not user editable), and list.
The default data type is string.
See the reference for detailed information about user preference data types and functions.
This section describes one of the more specialized data
types: list.
You can find examples of how to use the the other data types
throughout the documentation (for example, enum,
hidden, and bool).
A user preference with the list data
type is an array of values that are dynamically
supplied by users at run time. As users type values into
the user preferences edit box, these values are added
to the list. The list can be programmatically accessed
by the gadget at run-time, just like any other userpref.
You can use the list data
type any time you want to allow users to dynamically
supply an arbitrary list of values. For example, a weather
gadget might allow users to enter a list of postal
codes.
Consider the following sample gadget. It displays links for the Google News Sci/Tech feed. In the user preferences edit box, users can add words to the list via the Add Search Terms text field. The gadget searches for instances of the search terms in the titles of the feed entries. If it finds a match, it changes the color of the link for the entry to red. In this example, the list contains three words: "abc", "Google", and "MACWORLD". The links that contain those words are highlighted in red. Users can delete a list item by clicking its associated X.
You declare that a userpref has the list data type by
using datatype="list". For example:
<UserPref name="mylist" display_name="Add Search Terms" datatype="list" required="true"/>
The gadget accesses the values in the list using the _IG_Prefs function
getArray(),
for example:
var search_terms = prefs.getArray("mylist");
Within the array, items are stored as a pipe-delimited
list. You can use the _IG_Prefs function getString() to
return this list as a single string in which the values
are separated by the pipe (|) character, for example:
// For the sample gadget shown above, returns the string "abc|Google|MACWORLD"
prefs.getString("mylist");
You can also use a pipe-delimited string to set default
values for a list type:
<UserPref name="mylist" display_name="Add Search Terms" datatype="list" default_value="zdnet|pc|Apple Insider"/>
You can use the _IG_Prefs function setArray(name,
val) to
programmatically add values to the list. To use this
function, your gadget must include <Require
feature="setprefs"/> under <ModulePrefs>.
For example, the following excerpt adds the values "Nokia"
and "CNET" to the list:
... <ModulePrefs title="Feed Searcher" scrolling="true"> <Require feature="setprefs" />
</ModulePrefs> ... prefs.setArray("mylist", ["Nokia","CNET"]);
Here is the code for the sample gadget. For more discussion on writing gadgets that display feeds, see Working with Feeds.
<?xml version="1.0" encoding="UTF-8" ?>
<Module> <ModulePrefs title="Feed Searcher" scrolling="true"/> <UserPref name="mylist"
display_name="Add Search Terms"
datatype="list"
required="true"/> <Content type="html"> <![CDATA[ <style type="text/css"> .special-link { color:red; background-color:#BFE4FF; } </style> <style> #content_div { font-size: 80%; margin: 5px; background-color: #80C9FF;} </style> <div id=content_div></div> <script type="text/javascript"> // Get userprefs var prefs = new _IG_Prefs(); // Get the array of search terms entered by the user var search_terms = prefs.getArray("mylist"); // Use the _IG_FetchFeedAsJSON() function to retrieve core feed data from // the specified URL. Then combine the data with HTML markup for display in // the gadget. _IG_FetchFeedAsJSON( "http://news.google.com/?ned=us&topic=t&output=rss", function(feed) { if (feed == null){ alert("There is no data."); return; } // Start building HTML string that will be displayed in gadget. var html = ""; // Display the feed title html += "<div><b>" + feed.Title + "</b></div>"; // Access the data for a given entry if (feed.Entry) { for (var i = 0; i < feed.Entry.length; i++) { // flag used to indicate whether an entry title matches a search term var flag = 0; // Iterate through array of search terms to see if any of them matches // entry title for (var j = 0; j < search_terms.length ; j++) { // Do case-insensitive comparison var titletxt = (feed.Entry[i].Title).toLowerCase(); var term = (search_terms[j]).toLowerCase(); html += "<div>"; // Set flag to 1 if entry title matches one of search terms if ((titletxt.indexOf(term)) != -1){ flag = 1; } } // If the entry title matches one of the search terms, display the entry // link in red text. if (flag!=0){ html += "<a class='special-link' target='_blank' href='" + _hesc(feed.Entry[i].Link) + "'>"; } else { html += "<a target='_blank' href='" + _hesc(feed.Entry[i].Link) + "'>"; } html += _hesc(feed.Entry[i].Title) + "</a> "
+ "</div>"; } } _gel("content_div").innerHTML = html; }, 9); </script> ]]> </Content>
</Module>
To write a gadget that lets users specify a geographical location, you use the Google Maps API geocoder. For a more general discussion of using the Maps API in gadgets, see the Google Mapplets API documentation.
Note: Previously, gadget developers used the location userpref data
type to let users specify a geographical location. This data type has been deprecated.
For example, the following gadget displays a map for a user-specified address. It includes a user preference named loc that has the default data type "string." When the gadget runs, the user enters an address for loc, which is passed as a string to the GClientGeocoder getLatLng method. The getLatLng method sends a request to Google servers to geocode the specified address, and invokes the specified callback function (in this example, showMap) with a GLatLng point:
<?xml version="1.0" encoding="UTF-8" ?>
<Module>
<ModulePrefs title="Map of __UP_loc__" height="300"
author="Jane Smith"
author_email="xxx@google.com" />
<UserPref name="loc"
display_name="Location"
required="true" />
<Content type="html">
<![CDATA[
<script src="http://maps.google.com/maps?file=js" type="text/javascript"></script>
<div id="map" style="width: 100%; height: 100%;"></div>
<script type="text/javascript">
var prefs = new _IG_Prefs();
var map = new GMap(document.getElementById("map"));
map.addControl(new GSmallMapControl());
map.addControl(new GMapTypeControl());
var geocoder = new GClientGeocoder();
geocoder.getLatLng(prefs.getString('loc'), showMap)
function showMap(point) {
if (point!=null) {
map.centerAndZoom(point, 6);
}
};
</script>
]]>
</Content>
</Module>
It's common to let users set their user preferences explicitly, using the edit box. But sometimes it's useful to set the values for user preferences programmatically, without the user's direct participation. For example, for a game gadget, you might want to persistently store the user's highest score. You could do this by programmatically setting the value of a "high_score" user preference.
To use the setprefs feature,
your gadget should include the following:
<Require feature="setprefs"/> tag
(under <ModulePrefs>)
to tell the gadget to load the setprefs library.hidden. set() for
the userpref whose value you want to save.Note that preference size is currently constrained by URL limitations, which is 2K.
The following sample gadget consists of two buttons: one
that increments the value of a counter, and another that
resets the value of the counter to 0. In this example, "counter" is
a user preference. It has a datatype of hidden,
meaning that users are not permitted to directly modify
its value.
This is the gadget spec:
<?xml version="1.0" encoding="UTF-8" ?>
<Module>
<ModulePrefs
title="Set Userprefs Demo">
<Require feature="setprefs" />
</ModulePrefs>
<UserPref
name="counter"
default_value="0"
datatype="hidden"/>
<Content type="html">
<![CDATA[
<script type="text/javascript"> // Get user preferences var prefs = new _IG_Prefs();
// Increment value of "counter" user preference function incrementCounter() {
var count = prefs.getInt("counter");
alert("The count is " + count + ".");
prefs.set("counter", count + 1);
}
// Reset value of "counter" userpref to 0 function resetCounter(){ prefs.set("counter", 0); alert("Count reset to " + prefs.getInt("counter") + "."); } </script> <input type=button value="Count" name="count" onClick="incrementCounter()"> <input type=button value="Reset" name="reset" onClick="resetCounter()"> ]]> </Content> </Module>
Note: If you need to store multiple values, we recommend saving the values into a JSON string. For an example of how to do this, see todo.xml. There's also an open source JSON script at http://www.json.org/json.js that contains methods to easily convert JavaScript objects to and from JSON strings.
Within the XML attributes in a gadget spec, you must escape certain special characters. Note that only ASCII entities can be used in the gadget spec. For example, you cannot use ISO 8859-1 symbol entities. Here is a list of the special characters that are supported:
| Character | Escape Code |
|---|---|
& |
& |
< |
< |
> |
> |
" |
" |
' |
' |
For example:
href="http://www.foo.com/bar?x=a&y=b" href="http://www.foo.com/bar?x=a&y=b"description="this
is a "sexy" gadget"description="this
is a "sexy" gadget"Note that this type of escaping is not required in the CDATA block. However, it is still good practice to do it there.
Within your JavaScript code, you can use the _hesc(str) function
to return the HTML string str with
the the following characters escaped: <>'".
You can use this gadget to escape these characters: &<>'".
The default privacy policies of Microsoft Internet Explorer and Apple Safari do not permit third-party sites to set cookies. Hence some gadgets may not work correctly. In particular, sites that uses cookies for logins may not work correctly inside an iframe from the iGoogle page. Here are possible solutions:
<?php header("P3P: CP=\"CAO PSA OUR\""); ?>This must be called before any output is displayed on the page.
YOU WILL NEED TO CHECK YOUR PRIVACY POLICY CAREFULLY TO SEE WHAT HEADERS CAN BE USED FOR YOUR SITE. WE ENCOURAGE YOU TO CHECK WITH YOUR ATTORNEY.
Your browser is incompatible with this site as configured. If you are using Microsoft Internet Explorer, you can change your security settings by choosing Tools > Internet Options. Open the Privacy tab, click Advanced, and then check Override automatic cookie handling. Under Third-party Cookies, click Accept. Alternatively, you can try another web browser, such as Firefox.