Normal is a variable. Bitching is a constant.

Google Gadgets 101

Monday, July 3rd, 2006

Categorized as JavaScript and XML

Google Home Page, one of Google's many beta projects, offers programmers the opportunity to create gadgets that users can add to their personalized Home Page. Since a simple gadget can be created using only HTML, gadgets create an easy entry point for novice programmers.

Yet programmers can also create gadgets that use cutting-edge Ajax interfaces. Ajax is a protocol that combines JavaScript running on the user's browser with information retrieved from a server that passes XML data files. Well-written Ajax can provide a user experience that's more like using a software package than a web browser.

Support for this huge range in programming ability and experience makes learning how to write Google gadgets very interesting.

Google has written its own gadgets, of course. For example, you can use Home Page as an RSS feed reader. Google also offers Google Reader for this, but Google Reader requires a Google account. Home Page works both with and without a Google account.

Without an account, Home Page saves information about the gadgets you've selected in a cookie on your computer, which means if you switch machines or even browsers, your personalized page isn't available.

With a Google account, on the other hand, Home Page saves your gadget selections on Google's computers, so that you can bring up your personal home page from any computer/browser combination by logging into your account.

Getting started writing Google gadgets

Here's how to get started. Go to Google Home Page. If you have a Google account and are logged in, click the Sign out link at the upper right - you'll see why in a moment.

(If you'd like to get a Google account - they're free - click on the Sign in link at the upper right, then, on the page that appears, on the Create an account now link at the lower right, but make sure you're logged out of your account for the rest of this article.)

At the upper left there's a link called Add content. Click that. On the page that comes up, click on the Add by URL link that's just to the right of the Search Homepage Content button at the top of the screen.

Copy/paste this URL into the Add by URL box:

http://www.google.com/ig/modules/developer.xml

This will add Google's Developer Module gadget to your personalized home page. You need this if you're going to learn how to program gadgets. Among other things, it gives you a box for entering new gadget URLs without all that rigmarole.

Use the box now to add this test gadget:

http://www.jasoose.com/gadgets/hello-url.xml

Now add this one - in fact, add this one twice:

http://www.jasoose.com/gadgets/hello-cdata.xml

Now play with what you have a minute. Note that you can grab any of the gadgets by its title and reposition it on the page. Note that when you put the cursor on the name of a gadget in the developer module, its title lights up, making it easy to find on the page.

In the developer module, find the two versions of hello-cdata.xml that you loaded and click the inlined box for one of them. You can click the inlined box for the hello-url.xml box too, but note that after the warning alert, it will be unchecked again. Your screen should end up looking something like this:

Inlined and iframed gadgets

Since you can't keep the inlined box checked on the hello-url.xml gadget, you're left with three possible types of gadgets, inlined-cdata, iframed-cdata, and iframed-url.

First let's talk about the difference between inlined and iframed gadgets. An inline gadget is added to the page in a way that makes it part of the page itself. If you use your browser's view source feature, near the bottom you'll find the source code for the inlined gadget (it's just a short JavaScript and a single <div>). It's part of the page's HTML source. But note that the source code for the other two gadgets isn't there.

Instead, for the other two, search for the <iframe> and </iframe> codes. An iframe is the equivalent of a new frame or window inside an existing window. From the perspective of code running in an iframe, it has its own browser window. Code can't tell from inside an iframe that it's running in an iframe. It has no access to information in its parent window. It can't even tell whether there is a parent window.

This has to do with security issues. Code running in an iframe is safe because it can't get at any cookies or other information other than its own.

Inlined gadgets, on the other hand, are part of the parent window and have complete access to all of its information, including your Google cookies, one of which holds information for accessing your Google account.

Consequently, Google won't let third-party gadgets run inlined rather than in an iframe. To get them to run that way you have to use the developer module. I had you log out of your Google account earlier so you wouldn't have to worry the inlined demo code on this page was a trick to get your Google info!

So there's a lesson here - don't click the inlined box on any gadget that you didn't write yourself or get from a source you trust.

The Google gadget XML file

Whether a gadget is inlined or iframed, it starts out as an XML file that follows the Google gadget specification. You can see the underlying XML file for a gadget by clicking on its name in the Developer Module.

Take a look now at the XML for the hello-cdata.xml and hello-url.xml gadgets. You'll see that they are very simple and very similar, except for the section that begins with the <Content> tag.

The CDATA file says the content type is html and holds the source code for the gadget. In the actual file, the source code starts and ends with CDATA markers, which may get eaten by your browser when it shows you the file.

The URL file, on the other hand, says the content type is url and rather than holding source code, has a URL that points to an HTML file that holds the source code.

Documentation on how the XML file has to be structured is in the Google Gadgets API Reference.

CDATA gadgets and URL gadgets

Now let's take a closer look at what the gadgets are doing. In each case, they say Hello from: and give a URL. The URL comes from the JavaScript document.location property, which holds the URL of the data that was loaded into the window the gadget is running in. Note that each of the three gadgets shows a different URL.

The inlined gadget shows the same URL as your browser's address bar. This is the URL of Google Home Page and again demonstrates that the inline gadget is part of the page itself.

In the case of the iframed hello-cdata.xml gadget, the URL points to Google's gmodules.com domain; for the hello-url.xml gadget, the domain points to my own jasoose.com web server.

But when you added these gadgets using the Developer Module, you used two URLs from the jasoose.com domain. Moreover, both URLs use essentially the same code. The only difference is that the data file for hello-url.xml, which is named hello-url.html, has HTML, HEAD, and BODY tags that aren't included in hello-cdata.xml

Now right-click on these two gadgets and view the source for the iframes they're running in. The exact method for doing this varies from browser to browser; in Firefox, look for a menu item called This Frame; in the menu that pops out from it pick View Frame Source.

You'll see a few differences in the code for the two gadgets. First, the URL gadget is shorter and has __MODULE_ID__ in a whole bunch of places. In the CDATA gadget, __MODULE_ID__ has been replaced with a zero (in the inlined gadget, it's replaced with the actual ID number that Google's software has assigned to the module/gadget). Secondly, in the CDATA gadget, there are additional JavaScripts that the URL gadget doesn't have.

Google gadget JavaScript functions

What happens is that Google loads the CDATA gadget from my web site, does a search/replace on __MODULE_ID__, adds the JavaScripts, then presents the gadget to the page from the gmodules.com domain. The most important line of JavaScript it adds is this one, which gives the gadget access to the Google gadget JavaScript functions, even though the gadget is running in an iframe:

<script src="/ig/f/cizdrmyfJpg/ig.js"></script>

On the other hand, when Google loads the URL-type gadget into Home Page, it does none of that. Consequently, URL-type gadgets don't have access to the Google gadget JavaScript functions, but as of right now, the Google gadget documentation neglects to mention that.

With URL-type gadgets, appending __MODULE_ID__ to everything as suggested in the documenation is a waste of time because Google doesn't actually replace it with your module's ID. You can add a URL-type gadget multiple times on a home page and the gadgets won't conflict with each other because they can't - even if they wanted to.

However, you could cause difficulties for the home page itself if you gave an element in your gadget an ID that's already used by one of its elements. The __MODULE_ID__ trick that Google enacts with inlined and CDATA gadgets is meant to avoid these kinds of conflicts.

In theory, you could add the Google gadget JavaScript functions to your URL-type gadget by including the following as a single line in your code:

<script src="http://www.google.com
   /ig/f/cizdrmyfJpg/ig.js"></script>

However, if Google ever changes that funky URL, your code will break.

Use an onLoad handler

If your gadget consists of nothing but HTML, you have enough information now to get started. The trick is to make an HTML page that will fit in the size of iframe the Google home page gives you. You can control the height of the iframe by using an attribute in your XML file, but the user controls the width.

If your gadget includes JavaScript, it's pretty much impossible to get the JavaScript to work without an onLoad handler. This means that when your JavaScript runs, you tell the browser to come back and run your main routine after the page has completed loading. You can borrow the code my test gadgets are using for doing this if you want.

For the most part my code is borrowed from The JavaScript Anthology: 101 Essential Tips, Tricks & Hacks by James Edwards and Cameron Adams.

In addition to the test gadgets on this page, I've written a real gadget that calculates the value of U.S. Savings Bonds.

2 Comments

On July 5th, 2006 rolandog said:

Great writeup. If only I had been able to learn from your article instead of by trial and error!

On November 2nd, 2006 Tom Weishaar said:

Google has now made it possible for URL-type gadgets to access Google's Javascript functions.

It's a little convoluted. When Google calls your URL, it adds an &lib= with a partial URL pointing to their Javascript library. Your gadget's URL has to then respond by converting the passed information into a <script…> statement, which it inserts into the code of your gadget before passing it back to Google. Obviously this means your gadget's URL can't be a plain HTML page, but has to be something that you can program, like PHP.

Google's docs, fortunately, include the PHP code to do this.

Leave a Comment

HTML: <p> and <br> are automatic. Cite with <blockquote>. You can also use: <a href=''>, <b>, <i>, and <code>.