Menu

Fooling with XUL

March 15, 2000

Edd Dumbill


Table of Contents

The Finished Product
Creating the User Interface
Layout Mechanism
Adding Behavior
Adding Data to the Interface
Datasources and Templates
Making it Work
Conclusions

With the interest and excitement surrounding Mozilla's approaching beta release, I decided it was time to put it through its paces. For a while now we have heard and seen presentations of XUL, the Extensible User Interface Language, which forms an integral part of Mozilla. Delegates at XTech 2000 were clearly excited by the project and its promise for delivering a richer user interface on the Web.

As far as buzzword-compliance goes, Mozilla boasts a host of W3C specifications, including XML, DOM, CSS, and RDF. I wanted to find out how all these bits fit together in reality, and how practical client-side development with Mozilla actually is. I attacked the problem in my favorite way, by just jumping in with an idea I wanted to implement.

One of the fun parts of the Mozilla browser is the sidebar. Working in a similar way to the so-called "Explorer" bars in Microsoft's browser, the sidebar allows for handy access to components such as bookmarks, search, and "What's Related?" I decided that a shortcut interface to the XMLhack site would be a reasonable-sized learning project to undertake.

The Finished Product

The XMLhack Sidebar Component Working from back to front, I'll show the finished product and then demonstrate how I got there. The image on the right shows a list of articles with icons, which when double-clicked, cause the browser to navigate to the complete article on the web site.

The first step was to learn how to construct the user interface. Of course, I could have done this in straight HTML rather than using XUL, but I wanted to use the experience to learn about the Mozilla browser, and also for the user to feel that the component was more tightly integrated with the sidebar. Fortunately, XUL is one of the better-documented parts of the Mozilla browser, and I used Neil Deakin's XUL Tutorial as my starting point. This is an excellent document, although still a work in progress.

It is beyond the scope of this article to present a XUL tutorial, but I will mention the key concepts that are required. User interface descriptions in XUL usually span four files: the layout (.xul) file, the CSS style sheet, scripts, and localization information. For my experiments, I simply used the default styles and omitted localization, so I only had to consider two files: the .xul file itself, and a file for my JavaScript.

Creating the User Interface

Working through the XUL tutorial, I grasped the fundamentals of creating an interface in XUL. Each .xul file describes a window that contains widgets. The minimal XUL file looks like this:

<?xml version="1.0"?>

<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>

<window id="xmlhack-window" title="XMLhack Headlines"

    xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"

   >

</window>

Mozilla makes extensive use of XML Namespaces, hence the somewhat baroque URI denoting that window and its contents have the XUL default namespace. The browser can interpret elements from other vocabularies (such as HTML and RDF) within XUL documents. These can be included in XUL descriptions by using namespace-qualified names.

Another thing of note to point out is the chrome:// URL scheme. This scheme allows Mozilla to find localized resources for its user interface. If you look in your Mozilla install directory, you will find the chrome directory, beneath which are the XUL descriptions for the user interface. Mozilla interprets the chrome URL to find the actual file it wants, adjusting for such things as the current locale.

So, to get going, I added some simple widgets to my skeleton user interface, following the "Find Files" example from the XUL tutorial. I placed the XUL file on my web server, pointed Mozilla at http://localhost/test.xul and got back the text contents of the file in the browser, rather than a cool user interface. Oh dear.

It turns out that a little bit of configuration to your web server is required in order to get Mozilla to recognise XUL files. In particular, XUL currently uses the Internet Media Type text/xul. I simply added this line to my Apache's mime.types file, which fixed the problem:

text/xul                xul

That issue resolved, I continued with the tutorial and had soon created a pleasing user interface. Not everything worked quite as smoothly in the browser as it did in the tutorial though! Some of the widgets aren't properly implemented yet in Mozilla, and it can vary from platform to platform. For instance, I was able to get context pop-up menus ("right-click" menus) working on Windows, but not on Linux.

Layout Mechanism

Arrangement of widgets in a XUL interface is done primarily by use of boxes. Readers au fait with the TeX typesetting system (or many other layout systems) will already be familiar with the box method. Boxes can have their contents stacked either horizontally or vertically. Layouts can be constructed by a combination of these boxes.

Each UI element has a flex attribute, which governs how it will stretch to fill the space available. There is also a spring element, which is an empty box you can use to put space in between other UI elements. This example shows how two pushbutton widgets and a spacer would be written:


<titledbutton class="push" value="OK" 

  style="min-width: 100px;" flex="1"/>

<spring flex="1"/>

<titledbutton class="push" value="Cancel" 

  style="min-width: 100px;" flex="1"/>

As the window containing these elements was expanded, each button and the spring would all enlarge to consume the new space in equal measure, owing to their having identical flex values. Note the use of CSS styles to specify minimum widget dimensions.

It's much more interesting to play with this for yourself than to have me recount all the ins and outs, so I recommend pursuing the exercises in the XUL Tutorial.

Adding Behavior

A collection of widgets is all very well, but not very useful without something actually happening when they are activated. This is achieved through the use of JavaScript. In a similar way to HTML, a XUL document is exposed to the browser via a DOM, which can be scripted. Event handlers such as onClick can be specified as attributes of interface elements, much as in HTML.

Although script can be included inline in XUL with the <html:script> element, the documentation advises against it. Instead, script should be stored in a separate file, and referenced like this:


<html:script src="myScript.js"/>

It is relatively simple to get started with writing scripts. Here's a quick example. Imagine a window with this button inside:


<titledbutton class="push" value="Hello"

    onclick="sayHello();"/>

... and this JavaScript:


function sayHello() {

  alert("Hello, World!");

}

More complex operations can be achieved through the use of the DOM. XUL provides two extension functions to the XML DOM: getElementById and getElementsByAttribute (see Introduction to XUL on Mozilla.org). Extensive use of the ID attribute on user interface elements is made within interface descriptions, in order to facilitate easy scripting and modification of the interface. The interface's DOM can be modified by scripts, enabling such things as the dynamic alteration of style and content of widgets.


Table of Contents

The Finished Product
Creating the User Interface
Layout Mechanism
Adding Behavior
Adding Data to the Interface
Datasources and Templates
Making it Work
Conclusions

Adding Data to the Interface

I had reached the point of defining what I wanted my interface to look like. I needed to use the tree widget to show my list of headlines and so roughed out an interface description. You can download the full XUL file here, but here's an extract demonstrating the tree widget:

Interface mockup

<tree style="height: 100%; width: 100%" flex="2">

  <treehead>

    <treerow>

      <treecell value="Headlines"/>

    </treerow>

  </treehead>



  <treecol/>



  <treechildren>

    <treeitem>

      <treerow>

        <treecell 

          src="chrome://bookmarks/skin/bookmark-item.gif" 

          value="Story 1"/>

      </treerow>

    </treeitem>



   ...



  </treechildren>

</tree>

Notice that I used the browser's bookmark icon at this point instead of my own. This is one of the big advantages of Mozilla's open approach: the actual interface components themselves can be used for learning. In particular the chrome/bookmarks/content/default/bm-panel.xul file proved a great source of information in my experiment. This is the interface description for the sidebar bookmarks panel.

However, I did not want to create the .xul file each time with different contents; rather I wanted to be able to merge a data file with the XUL layout, in much the same way I would merge XML with XSLT to generate HTML. The way Mozilla handles this is to use RDF datasources. Arbitrary data, described in RDF, can be used to populate user interface elements.

Yes, I said "RDF." For one reason or another this specification has acquired a reputation as being unwieldy and difficult to understand. The good news is, you don't need to understand everything in order to be able to use it. I started from the point of an example RDF file, and with a little RDF knowledge, created what I needed for my purposes.

So here's the RDF primer: RDF is basically a way of describing things. The "things" are known as resources. A resource is associated with a URI. Here's an example description of me:


<RDF:RDF xmlns:RDF="http://www.w3.org/1999/02/22-rdf-syntax-ns#"

         xmlns:ORN="http://www.oreillynet.com/rdf#">

  <RDF:Description about="urn:oreillynet:editors:edd">

    <ORN:Email>edd@xml.com</ORN:Email>

    <ORN:Site>http://xml.com/</ORN:Site>

  </RDF:Description>

</RDF:RDF>

RDF provides constructs such as Description, Seq (sequence), and Alt (alternatives) to make describing resources easier and more portable. In the above example, I simply invented the http://www.oreillynet.com/rdf namespace to contain my Email and Site properties. In practice there are some established vocabularies for metadata, such as Dublin Core, which you can use to improve the interoperability of your descriptions (see also Using the Dublin Core with RDF).

For my XMLhack project, the next task was to create an RDF description of all the headlines on the front of the web site. I constructed a small vocabulary to describe each story. Here's an extract for one story:


<RDF:RDF xmlns:RDF="http://www.w3.org/1999/02/22-rdf-syntax-ns#"

         xmlns:s="http://xmlhack.com/stories/rdf#">

  <RDF:Description about="urn:xmlhack:story:207">

    <s:title>Oracle adds new functionality to XSQL Pages</s:title>

    <s:time>08:00, 10 Jan 2000</s:time>

    <s:author>Edd Dumbill</s:author>

    <s:url>http://xmlhack.com/read.php?item=207</s:url>

    <s:icon>http://xmlhack.com/images/s_tools.gif</s:icon>

  </RDF:Description>

  ...

</RDF:RDF>

You will note again that I could have profitably used elements from the Dublin Core to describe things such as "title," but as the sole intention of this particular RDF is to populate my user interface I preferred to take the simplest route.

Having described each story, I also wanted to describe a resource that would be my "headlines" list. For this, I used an RDF sequence I gave the ID headlines:


<RDF:Seq ID="headlines">

  <RDF:li resource="urn:xmlhack:story:207"/>

  <RDF:li resource="urn:xmlhack:story:206"/>

  ...

</RDF:Seq>

XMLhack is based on PHP and MySQL, so I had little difficulty writing the PHP script to generate this RDF. The remaining problem was inserting the data into the XUL.

Datasources and Templates

From within a XUL file, you can associate an RDF data source with a user interface item:


<tree id="xmlhack-tree"

  datasources="http://myserver.com/headlines.rdf"

  ref="http://myserver.com/headlines.rdf#headlines"

  style="height: 100%; width: 100%">

The datasources attribute signifies the source of the data, and ref says where in the data source I want to get data from. Here I indicate I want to read the sequence of headlines.

The template and rule elements are then used to merge the data with the interface:


<template>

 <rule>

  <treechildren>

   <treeitem uri="rdf:*">

    <treerow>

     <treecell

       src="rdf:http://xmlhack.com/stories/rdf#icon"

       value="rdf:http://xmlhack.com/stories/rdf#title"

       s:url="rdf:http://xmlhack.com/stories/rdf#url"/>

    </treerow>

   </treeitem>

  </treechildren>

 </rule>

</template>

This code replaces everything below the <treecol/> from my interface mockup above. Its purpose is quite self explanatory: the uri attribute matches each resource URI in the headlines list, making that the starting point. Thereafter, the rdf:-style attribute values select properties of the resource: we described these properties in the individual story descriptions earlier. Deeper understanding of what is going on can be gleaned from reading the RDF Syntax Recommendation from the W3C.

One subtlety here that I didn't find explicitly stated in the XUL documentation is the security model. Much as with Java applets, you can only retrieve data sources served from the same place as the XUL. For instance, this means you can't have a filesystem data source in a XUL description served by a web server. I found this out the hard way.

Making it Work

From studying the template above, you will note I added the s:url attribute to my tree cell. As the full XUL file shows, I earlier bound the s: prefix to another namespace of my own. This is so I could communicate to my JavaScript the URL to which the browser ought to navigate when it is double-clicked. To tie in the script, I added this attribute to the tree element:

onclick="return clicked(event, event.target);"

Again, I must acknowledge the value of the existing browser chrome files for providing me with shortcuts to write this script. Here's the definition of clicked():

function clicked(event, item) {

  if (event.clickCount == 2 && event.button == 1) {

    var tURL=item.getAttribute('s:url');

    if (window.content == null) {

      window.openDialog(

        "chrome://navigator/content/navigator.xul",

        "_blank", "chrome,all,dialog=no", tURL ); 

    } else {

      window.content.location = tURL;

    }

    return(true);

  }

  return(false);

}

On a double-click from the left mouse button, this script navigates to the destination URL, opening a new window if needed.

The final piece of the jigsaw is to allow the user to add the XMLhack panel to their sidebar. A short piece of Mozilla-specific JavaScript suffices:

<a href="javascript:sidebar.addPanel('&lt;?xmlhack?&gt;',

  'http://xmlhack.com/mozPanel.xul','')">Add XMLhack 

   Panel To Sidebar</a>

Here's the link for you to try yourself: Add XMLhack Panel To Sidebar. I've tested this in M14 and later nightly builds of Mozilla. On Windows you may need to open and close the sidebar to get it to display properly.

Conclusions

Apart from having a lot of fun, what did I discover playing with Mozilla? (I will lay aside the obvious fact that there are numerous bugs, as the browser has not even reached beta release stage yet.)

Mozilla could mean widespread RDF

I am of the opinion that what RDF needs is a "killer-app." Although lauded by many (especially Tim Berners-Lee), it has failed to break through in the same way XML has. Arbitrary data can be integrated into Mozilla interfaces via RDF with ease: the smallest part of my project was writing the RDF serialization of the data. Mozilla could well turn out to be a huge popularizer of RDF, leading to many sources of RDF information on the Web.

Mozilla provides a richer interface to online applications

The richer widget set provided by XUL compares well with those available for years in desktop applications. HTML has historically been woefully poor in its user interface elements, contributing to a Web in which "read" is much more common than "write." Mozilla could provide a truly cross-platform, network-aware framework for applications.

One proof of this is that the browser user interface itself is largely written in XUL and Javascript (and consequently the source code is a good place to explore how this stuff works!).

Having been involved in constructing online applications for several years, mainly in web content management, I'm excited by the prospect of more efficient web-enabled interfaces that are truly integrated with the browser. XUL delivers where Java never quite managed to.

Mozilla needs support

Microsoft's Internet Explorer is still ahead of Mozilla in terms of functionality, and way ahead in terms of adoption. Several otherwise free-spirited developers tell me that they use IE5 simply because it is the better browser and their altruism has run out of steam. Mozilla certainly faces tough challenges. However, it's important that it get the support of the XML and open source communities, for these reasons among others:

Resources

Mozilla Developer Docs
Cross-Platform Front End Project
Neil Deakin's XUL Tutorial
Mozilla Source Tree
XUL Reference Manual
RDF Syntax Recommendation
Guidance on expressing the Dublin Core within the Resource Description Framework (RDF)

  • Faithful standards implementation: Mozilla provides the opportunity for 100% implementations of W3C standards in a production environment. While not a "crowd-puller," this is important to ensure the long term openness of client-side web technologies.
  • Keeping the web open in a world of online applications: such applications are on the increase, and represent the future in both Internet and intranet situations. Current HTML can barely support the required flexibility in the user interface. Unless an open alternative is available, online applications will increasingly become browser or platform-specific.
  • Encouraging the "semantic web": more widespread use of RDF will enhance the prospects of a more "intelligent" web, where automated processes can be used to aid users in finding and processing information.

Details on participating in the Mozilla project can be found at Mozilla.org.

Related Stories