Categories
Technology

Digital Play Dough: Designing Applications with XUL

Originally published in Web Techniques

The XML-Based User Interface Language (XUL) made its first appearance with the release of Mozilla, the Open Source browser used as the foundation for Netscape 6. Pronounced “zool,” the language gives developers and designers an easy way to describe the design and layout of application windows in Web browsers. By modifying a few files, you can change the entire look of your Web browser or of the windows that pop open while a visitor browses your site. Prior to XUL, this was only possible by modifying and re-compiling the browser’s underlying source code. And in that case, you would have to distribute the modified browser to all your site’s visitors — an unlikely event. Fortunately, all you need to change the look and feel of a Web browser today is an understanding of the XML and CSS specifications and a little ingenuity.

Architecture

XUL applications consist of XML files created with .xul extensions. The files define the content of the application. Additional application data is located in Resource Description Framework (RDF) files. CSS files provide formatting, style, and some behavior, for the application. JavaScript files provide scripting support. Multimedia files, such as PNG images and other audio/visual files, might also be needed for additional user interface information. All of the file types are specifications recommended by the W3C, and collectively are referred to as the XUL application’s “chrome” — the contents, behavior, and appearance of the application’s user interface.

The Mozilla browser is itself designed as an XUL application. To manage the chrome for your browser, both Mozilla and Navigator have subdirectories labeled chrome, located off each browser’s main directory. Within the chrome directory, separate XUL applications are packaged into separate subdirectories. Within each application directory, subdirectories further divide the application into content (containing the XUL, JS, and RDF files), skin (CSS files), and locale (DTD files).

To deploy your own XUL application on the Web, you can either place all of the files within the same subdirectory on a Web server, or use the suggested chrome directory structure on the server. Note though that you may lose some functionality, such as localization, when your application is not using the chrome directory structure. Also, all files should be local to the URL of the main XUL file, otherwise the application may not work due to violations of built-in security.

A Simple Application

To demonstrate the structure of an XUL implementation, I created an application that is essentially a window with two panes — one on the left with a menu of hypertext links, and one on the right where a Web page can be viewed. Figure 1 shows the application.

To understand how I created this application, look at the sample XUL file shown in Listing 1. The first line of an XUL file is the XML declaration, which includes a reference to the version of XML used. Following that, the file must include a reference to a CSS file, to provide formatting for the XUL contents. The file then defines the application window and sets several properties — namely, the title, width, and height. Namespaces are provided for the application’s elements. By default, all elements in the application are XUL elements, identified by the following namespace (required for all XUL files):

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

When completed, the application will use some standard HTML elements, and these are identified with the html namespace. Additionally, the application will have a few elements unique to the specific application, and these are identified by the Webtechniques namespace WT.

Widgets

The different sections of a XUL application are contained in widgets known as “boxes.” Boxes don’t have any visual appearance themselves; their only purpose is to encapsulate several widgets as a whole, and to provide layout orientation for their contents. The orientation is defined with the orient attribute, and other attributes can be used to set the box width and height.

To demonstrate the use of boxes and page layout, Figure 1 shows a first version of the application, with buttons on the left, and a space to display the content on the right. The XUL file for this page is found in Listing 2.

In the listing, I added a box to the window contents and gave it an orientation value of vertical. This orientation forces all of the content to be positioned vertically in the pane. Additionally, the box is given a flex value of 1. The flex attribute can be applied to several different types of XUL elements. It’s used to help the layout engine determine how to expand an element to fill available space. For the outermost box in the page, the contents expand to fill the entire window.

In Listing 2, the outer box contains a toolbar and another, nested box. The toolbar and this new box are layered vertically inside the outermost box.

The nested box is given a horizontal orientation and contains two more nested boxes. These boxes are displayed left to right, and form the main panes of the application. Each of these boxes is given a vertical orientation, which means their contents will be aligned from top to bottom. A XUL splitter is used to separate the contents of the two boxes. This allows the user to resize either side of the application page by dragging the splitter either to the left or to the right.

Notice in the code that the first content box doesn’t have a set flex value. This means the box will be sized according to the width and height of its contents. The second box has a flex value of 1, and it expands to fill the remaining horizontal space.

The first box contains several XUL buttons, surrounded by widgets called springs. The spring element is used to help position elements, and has no visual characteristic of its own other than to occupy space. In this example, a spring is used on either side of the page buttons, to center the buttons within the box.

Also notice in the listing that the second box contains an HTML IFRAME element. As each listing for an article is accessed, the contents of the listing (a Web page) are opened in this IFRAME element. Because the element is an HTML element and not a defined XUL widget, the html namespace must precede the element tag.

More Widgets

The application terminates when the user clicks on the Close Window button in the application’s toolbar. To add a button widget to a page, you’d use the button element as follows:

<button value="Close Window" onclick="window.close();" />

The default appearance for the button is provided by CSS files that are included with Mozilla/Navigator.

To provide feedback to the user whenever a page is being loaded in the right pane, I have decided to extend the code by adding a progressmeter widget (see Figure 2). The progressmeter widget can have a mode of determined or undetermined. A determined meter is one in which the developer knows the exact length of time of an operation, and controls the meter accordingly. The undeterminedmeter is used when the length of time for an operation is unknown. Accessing a Web page falls into the undetermined category.

To support the use of the meter, I add JavaScript code to activate the meter. To do this, I put my code in a JavaScript .js file, and save the file in the XUL application’s contents directory. The code is shown in Listing 3.

I then create a reference to the JavaScript file in the XUL document. When doing this, I have to modify the onclick event handlers for the menu buttons so that they call the JavaScript loadItem()function instead of jumping directly to the URL. Listing 4 contains the contents of the second version of the XUL application. Now, when the application loads a Web page, the meter signals that a page is loading.

Integrating RDF Files

In the previous versions of the XUL application, the URLs of the target Web sites were hard coded into the page. A better approach would be to add the URLs as application data from RDF files. RDF files are used with XML to define application specific data, and can be altered easily without the need to modify the main XUL application pages.

As shown in Listing 5, many of the pages in an RDF list can be from the same site, and are nested by URL location.

To facilitate working with RDF data, XUL has a template engine that integrates external data with the XUL application. The template engine is activated when the layout engine finds opening and closing template elements, and all of the contents contained within the tags then form the template pattern. This pattern is used to determine how to lay out repeating values found in the RDF file.

We’ll add a template to the XUL application and set the pattern to be one button for every listed item in the RDF file. To do this, the RDF data source file must first be attached to the XUL file, and this is done in the box surrounding the template with the following command:

<box orient="vertical" flex="1" datasources="sites.rdf" ref="urn:source:data" >

The datasources attribute specifies the RDF file, and the ref attribute refers to the location in the RDF file to pull in the sequence of data.

The template, given in Listing 6, contains a button widget with the attribute of uri="rdf:*", which indicates where in the RDF file to begin the template matching. An application specific attribute (with the WT namespace) is added to the button to capture the URL associated with the Web page. The page’s title will be shown as the button’s display value.

The JavaScript loadItem() function from Listing 3 must be modified to pull the URL for the Web site as an attribute of the item passed in from the event handler. The new function is given inListing 7.

Figure 3 shows the page that results from using the RDF file and the XUL template. Note that each nested item from the RDF file is actually embedded within the button of its containing parent. So, you see a top button containing two other buttons, and so on.

Trees

Buttons aren’t necessarily the best widget to use when designing an application that uses a repeating template. Other widgets that are better are menus and trees. An XUL tree is similar to an HTML table in that the tree is delimited with one tag (tree), the rows with another (treerow), and the tree contents with yet another (treecell). The treehead tag defines a header for the tree, and the treeitem tag is used to allow users to click and select tree items.

Unlike an HTML table, though, XUL trees provide sophisticated processing for nested items. By default nested items aren’t displayed until the user clicks on an item’s containing parent.

In Listing 8, I’ve replaced the buttons with an XUL tree structure. Individual tree cells hold each hypertext link, and nested data items are displayed as nested tree items. Clicking on the graphic associated with the top-level tree items (known as the “twisty”) displays the contained items. Clicking on any contained item opens the associated Web page in the right pane of the application, as displayed in Figure 4.

Skinning

One of the more controversial aspects of XUL is skinning — the ability to change the appearance of any of the application’s chrome, including the frame, the buttons, the toolbars, menus, and so on. You can change the entire look and feel of Mozilla and Navigator 6 just by downloading new chrome packages and installing their contents. With XUL, the only limit to skin design is the designer’s imagination.

So why is giving Web developers the ability to design different interface skins so controversial? Imagine for a moment that Salvador Dali or Picasso painted frames rather than the canvases. Now, try to visualize what painting could hold its own within these frames. Not many could. Application designers argue that well-designed user interfaces could be ruined by a third party’s poorly-designed skins. The other side of this argument is that being able to create a custom user interface is an attractive concept for developers and designers who don’t want to have to work within the rigid confines of the widgets defined by current operating systems.

To create a new skin for a XUL application, you provide a custom CSS file that defines the styles for the widgets in your application. If you wish to have access to the default appearance and behaviors for the widgets, you must import the global styles into your new CSS file with the following command:

@import url(chrome://global/skin/);

You can then add styles for the widgets used in your application.

Listing 9 shows the CSS file for the XUL application used in this article. In the file, I changed the style of the splitter so that it has a maroon background when inactive, and a teal one when active. I also changed the appearance of the button on the splitter (called the “grippy”). I modified the meter to have a gold background, and did the same for the selection highlight on the tree. I even added new GIF images for the toolbar grippy (the little downward arrow that’s used to hide or show the toolbar).

In this example, I modified the styles for XUL widgets directly in the CSS file. However, the preferred approach is to add new widget classes, and use them in your application as follows:

button.wt_button { ... }
<button class="wt_button".../>

With this approach, you still have access to the default appearance and behavior for each widget.

Once I modified the widgets, I opened my main XUL application file and replaced the reference to the global CSS file with a reference to the new CSS file, using the following line:

<?xml-stylesheet href="wt.css" type="text/css"?>

To access the completed application, create a page that has the following link on it, and load that page in Mozilla or Navigator 6:

<a href="#" onclick="window.open('wt.xul','example','chrome');">test</a>

If you use PR 1 of Navigator 6, note that the toolbar won’t show properly due to changes in the XUL schema that occurred after Navigator 6 PR 1 was released. It should work correctly with PR 2, and works with Mozilla build M16 (and up, hopefully).

One more thing to note is that you may have to add the XUL MIME type to your server’s configuration in order to make sure the application XUL page downloads correctly. The MIME type is simple text/xul.

Conclusion

You’ll find the complete application with all necessary files in the wt.zip file. With just a few changes of the XML file associated with the XUL application — adding a meter and using a tree instead of buttons — I changed application functionality and provided better user feedback and a better design. With a few adjustments to the CSS file for the application, I was able to create a new and different look to go with my application’s functionality. XUL promises to be a powerful tool for Web application development and deployment. I look forward to seeing future iterations and refinements of the technology in future browser versions.