Generic Ajax Widget

As part of this article, I've included a generic Ajax widget that simply grabs a URL and parses out a small section of the DOM that I'm interested in.
It’s a good jumping off point to get going with an Ajaxified widget.




Getting Dashcode

If you've got a recent version of Leopard or Tiger, the system Disks will contain Dashcode in the developer kit (it may be installed already in your /Developer/Applications directory).
Apple did have Dashcode available for download, but since it expired in July (when Leopard was to come out) it’s no longer there.
You can hunt around the Internet for a old mirror if you don't have the CDs.
Once installed, it'll say it’s expired: just get Dashcode working again.

Stability

Broken Dashcode RenderDashcode is particularly ropy with Safari 3.
With Safari 2 it’s much more stable. Since there is the occasional crash from Dashcode,
I would recommend constantly saving your project as you're coding.
I found more than 10% of the time, Dashcode would crash and result in a total loss of my code from the last save point.

Also, I've noticed that dumping a lot to the run log, when viewing the log, can cause Dashcode to slow right down to almost hanging.
Best to avoid dumping large amounts of HTML to the log.
However - and this is a big one - the upside of programming with Dashcode is worth the risk of the crash, because it’s takes most work out of the design process.
Since you're using it’s GUI to drag and drop your design and how the user will interact with it, rather than having to code the look and feel by hand.



Designing Widgets

The interface and the library component of Dashcode makes it possibly the strongest app for developing widgets. It’s 2 minutes work to create a glass effect on your widget, or to place the elements on the window and get going.
I would strongly recommend studying other widgets, and reading through the Dashcode design recommendations as it’s easy to design a widget that works, but twice the work to design a widget that’s usable and works well.
You'll find you can place widget-type objects on your widget, like scroll areas or gauges - but to handle them in the code isn't entirely intuitive, which is why the best source of understand how these interface elements work, is by opening up other widgets that already make use of the element.




Controls

Dashcode offers the easy integration of bespoke elements such as the scrollarea, gauges and other such sexy components.
They're pretty easy to drop on to the widget from Dashcode, but until you're coding, they're not immediately obvious how they work.
The help is limited, so I would recommend to develop by tutorial, in particular, look for the 'refresh()' methods - as this seems to be a fairly standard way to redraw objects.
Full documentation for the Apple classes API is available, but it’s pretty clinical.




Effects

Although effects are available within the Apple classes, you'll need to implement them yourself.
This is fairly limited to dynamic resizing of the widget, which is achieved using:

window.resizeTo(x, y);

If you are going to resize the widget dynamically, check out the Apple resizing examples too.
I used this technique in my HTML entities widget to keep the widget small when it’s dropped in to the Dashboard, but to allow it to grow dynamically when the user searched for a particular HTML entity.
You should be able to find easing effects code and examples if the built in Apple animation class doesn't suite your needs.



Running system commands


This is one of the few areas that’s well documented in the provided API.
You can run system commands using the following type of command:

widget.system('ps -auxww | grep ' + myCommand, null);
What you should keep in mind, is that you can run any command through the system method. This includes Perl, Ruby, AppleScript and anything else that suits your needs.
Using these commands I've recently been able to create a widget that queries Mail’s SQLite’s database via Perl.
It was a case of running the system method and capturing the output (and in my case, eval'ing it from a JSON output).




Ajax in the widget


You widget supports a variation of the Ajax object (or rather xmlhttprequest object).
This version isn't bound by the usual security constraints of a browser - most importantly, it can request content from any domain.

To execute any Ajax requests from your widget, ensure you have the Allow Network Access attribute turned on - otherwise the Ajax will fail without any given reason.

For example, you could use Ajax to pull your film page from IMDb and then parse the XML for the elements of interest.

However, if you do want to pull some data from a web page and process it using the DOM returned you have to fiddle the request - in particular the responseXML will be null because the page being returned isn't text/xml - it’s text/html. You can do it using the following (in jQuery syntax):

$.ajax({
url: 'http://remysharp.com/example_page', // doesn't really exist!
dataType: 'html', // important
success: function (xml) {
// convert the HTML to an XML DOM object
var dom = getDOMfromXML(xml);
alert(dom.getElementsByTagName('h1').length);
}
});

function getDOMfromXML(xml) {
var d = document.createElement('div');
xml = xml.substring(xml.indexOf('<body') + xml.substring(xml.indexOf('<body')).indexOf('>')+1);
xml = xml.substring(0, xml.indexOf('</body>'));
d.innerHTML = xml;
return d;
}

This getDOM function is pretty horrible - but it works. I tried using DOMParser and tried using Ajax local data trick and I tried using an iframe to inject the XLM - but neither would load the XML properly (in fact it would be blank).
The iframe would not load properly because it was still loading the entire frame while I was trying to access it.

You can see this in use in the generic Ajax widget or download the source Dashcode project.



Widget Attributes


The widget attributes are fairly self explanatory, but it’s worth knowing:
  • Allow Network Access is required for Ajax requests
  • Allow Command Line Access is required for running external programs, i.e. if you have a Perl script executing some arbitrary task

If you intend to make your widget available in different languages, then this is the place to enter the different strings.

The Inspector

  • Hide items from the default image to present a better widget when it’s installing. It can to keep the preview of your app looking clean.

Debugging


Dashcode comes with a log that can be viewed during run time.

You have following debugging tools:
  • Breakpoints
  • Live stack traces
  • Evaluate window - to test commands

To write to the log, you need to use alert("My debug message");.