oreilly.comSafari Books Online.Conferences.


AddThis Social Bookmark Button

Extending the Dashboard Virtual Earth Widget
Pages: 1, 2, 3, 4

Coding the Preference Pane

Quite a bit of the code for the preference pane is shoveled out of Apple's developer documentation, but we shall walk through the implementation I have used here.

Recall that we declared a new div with id="back" earlier on. This div represents what you'll see displayed when the widget is rotated. Let's take a quick look at the HTML again:

<div id="back">
    <div id="back_contents">
        VirtualEarth Dashboard Widget v1.5<br/>
        Luke Burton, 2006<br/>
        <span class="link" onclick="widget.openURL('');"></span><br/>
        Visit <span class="link" onclick="widget.openURL('')">Luke's website</span> for more info and new versions.<br/>
    <div id="doneButton"></div>

There really isn't much unusual going on here, we're just declaring what we'd like the back of our widget to look like. Inside a div called back_contents, I declare a bit of text and some hyperlinks to inform people about my widget. I then add a doneButton div which I'll explain right now.

To get the widget rotating, we'll need to set up a button to flip from front to back, and another button to do the reverse. In Widget terminology, the button that shows you the preference pane (the back) is called the Info button, and the button that does the opposite is called the Done button. You'll see these on most widgets as a little glowing "i" on the front and a glassy-looking Done button on the back. Hence we have placeholders for both these buttons in our HTML code: divs called doneButton andinfoButton.

Let's take a look at our revised setup() function to see how these buttons are declared in JavaScript. Both buttons are of types declared in the Apple Classes included previously.

Note that the first thing we do is declare some global variables. Along with map and growboxInset which we've already encountered, we have two variables representing the Done and Info buttons.

var growboxInset;
var map;
var gDoneButton;
var gInfoButton;

Our setup code has a few small additions:

function setup()
    // set up the map object
    map = VE_MapSearchControl.Create(37.3189139456153,-122.029211560580, 
            12, 'r', "absolute", 0, 0, 515, 410, 
            "", "");

    // attach it to the correct div

    // set our default window size
    window.resizeTo(555, 450);

    // organise some button objects
    gDoneButton = new AppleGlassButton(document.getElementById("doneButton"), "Done", hideBack);
    gInfoButton = new AppleInfoButton(document.getElementById("infoButton"), document.getElementById("front"), "black", "black", showBack);


After declaring the map control and appending it to the inner_contents div, we then set a starting size for our widget. I found this necessary to avoid an unusual flicker when the resize handle is first grabbed. We then declare the JavaScript objects that will take care of rendering our buttons.

The Apple Classes documentation explains these constructors.

But briefly, for the Done button we pass in our target div, the label we'd like on the button, and the JavaScript function to be called when the button is clicked. For the Info button, we pass the target div, the id of the front of our widget, two attributes detailing the color scheme for the glowing "i" button, and the JavaScript function we'd like called upon a click.

Let's now examine the JavaScript functions that are invoked when you show the back, and hide the back.

function showBack()
    var front = document.getElementById("front");
    var back = document.getElementById("back");

    if (window.widget)

    if (window.widget)
        setTimeout ('widget.performTransition();', 0);  

function hideBack()
    var front = document.getElementById("front");
    var back = document.getElementById("back");

    if (window.widget)

    if (window.widget)
        setTimeout ('widget.performTransition();', 0);

These two functions are going to be pretty much the same in almost all widgets, unless you have some setup routines you'd like to perform before displaying the preference pane.

The general gist is that we grab handles to our front and back divs. We then prepare the widget for transition with widget.prepareForTransition, but only if we're running as a widget (as opposed to running in Safari, for instance). We then switch the display styles of our front and back appropriately. Finally, we call widget.performTransition. This is called in a special manner using setTimeout, as the Apple docs say, to ensure the front and back display styles have already been swapped before the transition occurs.

What Have We Covered?

Well, it feels like we've come a long way, but my explanation of how it happened is far longer than the code itself. In summary, we:

  • Redesigned the look and feel of our widget to accommodate resizing
  • Changed the HTML to enable dynamic resizing and include a preference pane with some basic text
  • Changed the CSS code to render our widget appropriately
  • Introduced new JavaScript code to handle resize events, and to handle the preference pane transitions

But once again, we have barely scratched the surface of what's possible with Dashboard Widgets. Your imagination really is your only limit with this technology. You can even include your own Quartz effects designed in Quartz Composer for stunning visual effects. Hmm, I wonder what kind of gratuitous visual effects we could include in our Virtual Earth Widget ...

Luke Burton chipped his teeth on C++, and has lately sought refuge in the beautiful world of scripting languages like Ruby and Perl.

Return to the Mac DevCenter