Fooling with XUL - Part 2
March 15, 2000
Table of Contents |
•The Finished
Product |
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:
<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('<?xmlhack?>',
'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 RDFI 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 applicationsThe 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 supportMicrosoft'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:
- 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.