Andrew's Widgets | Developing Dashboard Widgets | Debugging Widget JavaScript

Apple Dashboard Debugging Widget JavaScript

A simple technique for debugging JavaScript in Dashboard widgets.

Andrew's Widgets
Jump to:

Introduction

Update: I swear I didn’t see it before I posted my article, but Apple has an excellent Technical Note about debugging widgets that includes a very similar technique to the one I describe below (and more!). Check it out, it’s definately worth a read!

I think I read somewhere that debugging JavaScript requires zen-like patience. If that’s true, debugging JavaScript inside a widget requires double. For those of us who lack monastic virtues, we can make up for it by using the following, brute-force method. Dump them variables!

The following works best if your widget developement process is like mine. I start by building a regular web page and previewing it in Safari. Once I’m confident I have most of the bugs worked out, I convert it into a widget and test it from within Dashboard. The script below is useful for writing debugging information to the page in Safari, but it will also write to the console once your work is widget-ized.

How to set it up

Include the following bits in the appropriate places in your code:

HTML

<div id="debug"></div>

CSS

div#debug {
   /* we hide the debug div by default */
   display: none;
   position: absolute;
   top: 10px;
   right: 10px;
   padding: 10px;
   width: 300px;
   background: #ccc;
   color: white;
   border: solid 1px black;
}

JavaScript

var debug = true;
// var debug = false;

// writes the string passed to it to the page
function writeDebug(s) {
   if (window.widget) {
      alert(s);
   } else {
      document.getElementById("debug").innerHTML += s + "<br\/>";
   }
}

// writes all of the properties of the object passed to it
function revealObject(o) {
   for (p in o) {
      writeDebug(p);
   }
}

// if debug is set to true, this will show the debug div
function init() {
   if (debug) document.getElementById("debug").style.display = "block";
}

window.onload = init;

How to use it

This is probably best explained by example. Say you’re developing a widget and the JavaScript console in Safari gives you a message like this:

Undefined value
file:///Users/andrew/Desktop/ExampleWidget/default.html                          Line: 278

Looking at line 278, you see this in your JavaScript:

photo_div.src = photos[idx].src;

You could guess as to the problem, or you could add the following to just before the above statement:

if (debug) {
   revalObject(photo_div);
   writeDebug("photos["+idx+"].src = "+photos[idx].src);
}

Now, when you reload the page, you will get a long list of properties of the photo div, including something like the following:

...
height
align
src
border
y
name
hspace
alt
longDesc
...

Notice that “src” is listed as a property, so we can probably rule out the left side of our statement as being the problem. In our example, our JavaScript now throws an error on the line where we try to write the value for photos[idx].src. Aha! This narrows down the problem!

We know the problem is in photos[idx].src, so let’s change our debugging statement to the following:

if (debug) {
   writeDebug("idx = "+idx);
}

This time, when we reload, we see that the variable idx somehow got set to a value out of the expected range for that array. We’ve found our culprit! It’s up to you what you do with the varmint, but I think in Texas this is when they’d say “Get a rope.”

Conclusion

This technique isn’t a magic bullet that will solve all of your JavaScript woes, but hopefully you will find it useful for helping identify the cause of any errors in your scripts. Enjoy!