An Introduction to XUL Part 4

Learn about XUL, a subset of XML used to describe user interfaces, that helps you to make rich user interfaces with nothing more complicated than a text editor. In the fourth part of this series you will learn about dialog boxes and wizards.

Aside from some other, more advanced elements which will be discussed later on, the elements looked at so far are pretty much all of the elements that actually draw the various things that make up an interface on the screen. There are, however, a couple of advanced elements that not only render objects on the screen, but also include built in functionality. These elements are used in place of the window element and create different types of window. 

They are of course, dialog boxes and wizards. Using these alternative windows is not as simple as the other elements we have looked at so far; simply creating them and executing them via the command line will not make them work correctly. In order to use these advanced elements, you will need to create an RDF file that describes them and register them with Mozilla.

RDF, as mentioned previously, stands for Resource Description Framework, and is used, of course, to describe resources. Those resources are defined using URIs and may be Web locations or file system locations. The basic building block of RDF is the triple, a three part description comprising an object, a subject and the relationship between them. The concept of triples has been around for some time; if you’ve ever used the <meta> tag in an HTML document you’ve authored to add your name as the author or creator of the document, you’ve used a triple. You have the object, which is the HTML document; you have the subject, namely yourself; and you have a piece of information (called a predicate) that describes your relationship to the Web page –- the meta name value that says author (or creator).  Graphs can be displayed visually using an arc-node diagram with the predicate pointing towards the object:

 
This very basic arc-node graph example contains two literals or actual values, something that should never happen in RDF; I have drawn it in this way purely as an example. Instead, the object or subject (or both) should be described as a resource by using a URI:


To show that the object is a literal, I have placed its value into a rectangular rather than oval container. It is worth noting at this point that predicates can also be expressed as resources using a URI.  Almost anything can be described using RDF, provided it is something that has some kind of relationship with something else and can be expressed via a unique URI. This is just the very basics of RDF, a brief overview if you like, which I have included simply because you’ll need an RDF file to produce working wizards and dialogue boxes. There are some excellent resources out there if you want to learn more. A good place to start is the W3C site (www.w3.org), or the Mozilla site (www.mozilla.org).

{mospagebreak title=Using the RDF/XML Syntax} 

To store RDF in a file that applications are able to use, you need to use the RDF/XML syntax. There are other implementations, such as N3, but RDF/XML works very well with Mozilla and may appeal to those of you that have some XML experience. As we’ve been discussing RDF already, we will begin by creating the RDF/XML file, although in reality, it would probably be the XUL file that you would create first. Nevertheless, in a text editor, begin again with the XML declaration:

<?xml version=”1.0″?>

This is not strictly necessary, but should be included for well-formedness. Next, you need to add the RDF container with some namespace properties and the RDF and chrome namespaces:

<RDF:RDF xmlns:RDF=”http://www.w3.org/1999/
         02/22-rdf-syntax-ns#”
         xmlns:chrome=”http://www.mozilla.org/rdf/chrome#”>

Next you need to tell Mozilla that you’re describing a list of your applications:

<RDF:Bag about=”urn:mozilla:package:root”>

I have placed this in a bag container, which is standard RDF syntax for an unordered list. If I wanted to create an ordered list, it would be an <RDF:Seq> sequence.  Your application is then defined as an item of the list:

<RDF:li resource=”urn:mozilla:package:mywizard”/>
</RDF:Bag>

You now need to provide a description of your application:

<RDF:Description about=”urn:mozilla:package:mywizard”
          chrome:displayName=”Wizard”
          chrome:author=”Dan Wellman”
          chrome:name=”mywizard”
          chrome:version=”1.0″/>

Once this has been added, you need to close off the RDF container:

</RDF:RDF>

And save the file as contents.rdf in the same folder that your wizard application will reside in. This can be any folder, but I would recommend creating a chrome folder in your XUL folder and saving both the RDF and the wizard files in that. 

You might be wondering how you could use this file to describe two XUL files. No? Well I’ll tell you how anyway, because sooner or later, you will want to know.  It’s simple; all you do is add a second block of code similar to the first, but with the filename of your second XUL file. Then whole file would look like this:

<?xml version=”1.0″?>
<RDF:RDF xmlns:RDF=”http://www.w3.org/1999/
         02/22-rdf-syntax-ns#”
         xmlns:chrome=”http://www.mozilla.org/rdf/chrome#”>

<RDF:Bag about=”urn:mozilla:package:root”>
  <RDF:li RDF:resource=”urn:mozilla:package:fredswizard”/>
</RDF:Bag>

<RDF:Description about=”urn:mozilla:package:fredswizard”
          chrome:displayName=”Freds Wizard”
          chrome:author=”Fred”
          chrome:name=”fredswizard”
          chrome:extension=”false”/>

<RDF:Bag about=”urn:mozilla:package:root”>
  <RDF:li RDF:resource=”urn:mozilla:package:danswizard”/>
</RDF:Bag>

<RDF:Description about=”urn:mozilla:package:danswizard”
          chrome:displayName=”Dans Wizard”
          chrome:author=”Dan”
          chrome:name=”Danswizard”
          chrome:extension=”false”/>
</RDF:RDF>

It’s not elegant, and you would think that being a list you could just add the second RDF:Resource statement to the first bag, but doing this will simply not work.

{mospagebreak title=Creating the Wizard}

Now that you have your RDF file in place, you need to create the wizard and save it in the same directory. The syntax for this is really easy; just exchange the <window> element for a <wizard> element, and then define each of the pages of the wizard as a <wizardpage>.  You can use almost all of the elements we have discussed so far in a wizard, including all of the form controls.  Create this basic wizard:

<?xml version=”1.0″?>

<wizard id=”danswizard” title=”The ‘Create a
 Wizard’ Wizard” xmlns=”http://www.mozilla.org/keymaster/
 gatekeeper/there.is.only.xul”>

 <wizardpage description=”Create the XUL file”>
   <description>This page will help you create a 
     XUL wizard</description>
   <spacer height=”10″/>
   <description>First set the XML declaration in the 
     normal way:</description>
   <spacer height=”10″/>
   <description><![CDATA[<]]>?xml version=”1.0″?>
     </description>
   <spacer height=”10″/>
   <description>Then add the wizard tag with title and
     namespace attributes:</description>
 
 <spacer height=”10″/>
   <description><![CDATA[<]]>wizard id=”danswizard”
     title=”The ‘Create a Wizard’ Wizard”
     xmlns=”http://www.mozilla.org/keymaster/gatekeeper/
     there.is.only.xul”></description>
  
<spacer height=”10″/>
   <description>Next, add the first page of the wizard with
     the wizardpage tag:</description>
   <spacer height=”10″/>
   <description><![CDATA[<]]>wizardpage description=”Create
     the XUL file”></description>
  
<spacer height=”10″/>
  
<description>Add your page content using the normal XUL
     element tags:</description>
  
<spacer height=”10″/>

   <description><![CDATA[<]]>description>Content…
     <![CDATA[<]]>/description></description>
   <spacer height=”10″/>
   <description>When the page is ready, close off the
     wizard page tag and repeat the process for as many
     pages as necessary</description>
  
<spacer height=”10″/>
  
<description><![CDATA[<]]>/wizardpage></description>
   <spacer height=”10″/>
   <description><![CDATA[<]]>wizardpage>Page 2
     content…etc
<![CDATA[<]]>/wizardpage></description>
   <spacer height=”10″/>
   <description>When the wizard is finished, close off the
     wizard tag and save your file in a folder, preferably
     one called chrome</description>
   <spacer height=”10″/>
   <description><![CDATA[<]]>/wizard></description>
 </wizardpage>

 <wizardpage description=”Create the RDF file”>
   <description>This page will help you create the RDF
     file</description>
  
<spacer height=”10″/>
   <description>Once again, begin with the XML declaration:
     </description>
   <spacer height=”10″/>
   <description><![CDATA[<]]>?xml
     version=”1.0″?></description>
  
<spacer height=”10″/>
   <description>Now add the RDF container and include the
     necessary namespaces:</description>
   <spacer height=”10″/>
   <description><![CDATA[<]]>RDF:RDF
     xmlns:RDF=”http://www.w3.org/1999/
     02/22-rdf-syntax-ns#”
     xmlns:chrome=”http://www.mozilla.org/
     rdf/chrome#”></description>
   <spacer height=”10″/>
   <description>Add your bag baby, and tell Mozilla the
     name of your wizard:</description>
   <spacer height=”10″/>
   <description><![CDATA[<]]>RDF:Bag
     about=”urn:mozilla:package:root”></description>
   <description><![CDATA[<]]>RDF:li
     RDF:resource=”urn:mozilla:package:yourfilenamehere“/>
     </description>
  
<description><![CDATA[<]]>/RDF:Bag></description>
   <spacer height=”10″/>
   <description>Then create an RDF description code block
     giving the program the various bits of information. 
     Remember to change the filename and details to your
     own:</description>
   <spacer height=”10″/>
   <description><![CDATA[<]]>RDF:Description
     about=”urn:mozilla:package:yourfilenamehere
     </description>
   <description>chrome:displayName=”yournamehere’s Wizard”
     </description>
  
<description>chrome:author=”yournamehere“</description>
   <description>chrome:name=”yourfilenamehere
     </description>
   <description>chrome:extension=”false”/></description>
   <spacer height=”10″/>
   <description>Finaly, close off the RDF container:
    
</description>
  
<spacer height=”10″/>
   <description><![CDATA[<]]>/RDF:RDF></description>
   <spacer height=”10″/>
   <description>Save this file as contents.rdf in the same
     folder as your wizard</description>
 </wizardpage>

 <wizardpage description=”Register the wizard with
   Mozilla”>
 
<description>This page will help you register your
    file</description>
   <spacer height=”10″/>
   <description>Look in the main Mozilla program directory,
     there will be two files of use to you here, chrome.rdf
     and installed-chrome.txt</description>
   <spacer height=”10″/>
   <description>First of all, delete the chrome.rdf file.
     This is a file that is automatically generated by
     Mozilla each time the program is launched.
    
</description>
   <spacer height=”10″/>
   <description>Now open the installed-chrome text file.
     You might want to use something a little better that
     Windows Notepad here because unfortunately it can’t
     seem to read this file property.  I use nPad2, a
     perfectly adequate free text editor</description>
   <spacer height=”10″/>
   <description>At the very end of the file, you’ll need to
     add some code that tells Mozilla where your wizard is
     located  I have put my file in a folder called chrome,
     that sits in a folder called XUL on my C drive, so the
     code I would add is:</description>
   <spacer height=”10″/>
   <description>content,install,url,file:///C|/XUL/chrome/
     </description>
   <spacer height=”10″/>
   <description>Make sure you press return after adding the
     above line of code to the file and then save
     it.</description>
 
</wizardpage> 

 <wizardpage description=”Veiwing the wizard”>
   <description>This page will help you run the
     wizard</description>
   <spacer height=”10″/>
   <description>Open Mozilla and in the address bar type
     the following command:</description>
   <spacer height=”10″/>
   <description>chrome://yourfilenamehere/content/
</description>
   <spacer height=”10″/>
   <description>Your wizard should now be displayed and
     should have a title at the top and working buttons at
     the bottom.  Additionally, the final page of the
     wizard (this one) will have an appropriate ending
     title</description>
   <spacer height=”10″/>
   <description>All you have done is provide the basic
     containers and the content itself, Mozilla and XUL do
     the rest!</description>
   <spacer height=”10″/>
   <description>Go back to the Mozilla directory and open
     the chrome.rdf file that you deleted earlier with a
     text editor, do a find for your wizards name and there
     should be several references to it</description>
   <spacer height=”10″/>
 </wizardpage> 

</wizard>

You’ll notice that it’s an awful lot of code, 97 lines to be exact, but it is easy code and I’m sure you’ll agree that it’s a lot less than it would be if you have to script the page change and button behaviors manually.   You’ll notice that the lines of text in the wizard that represent code have had the first angle bracket enclosed within a <![CDATA[]]> element. This is to ensure that Mozilla treats part of the text as character data and doesn’t try to parse it. Try getting the wizard to display the text <?xml version=”1.0”?> without using the CDATA method. Normally this information would go into a DTD file to keep the wizard file cleaner; in fact, all of the string information could go into a DTD file and all of the wizard text could be read in using references to it instead, but for this example, we needn’t worry too much about separating content from presentation.

{mospagebreak title=Adding to the installed-chrome.txt file}

So that’s the RDF file, and the wizard file is in place, but before the wizard can be accessed via chrome, you still need to add some code to another file — the installed-chrome.txt file. This file lives in the default install directory of Mozilla. Open it up and add the location of your XUL file to the bottom (for clarity, the path to mine is C:/XUL/Chrome/mywizard.xul)

content,install,url,file:///C|/XUL/chrome/

You must add a hard return after this.  Now save the installed-chrome file, and from the same folder (the Mozilla chrome folder), delete the file called contents.rdf. Open Mozilla, and this file will be regenerated.  Open this file in a text editor, and you should be able to find the name of XUL wizard you have just created in there. To access your wizard, in the Mozilla address bar, type the following URL:

chrome://yourfilenamehere/content/

When the cancel or finish buttons are clicked Mozilla will close; this isn’t because you’re doing something wrong, but because the wizard is not being opened from another XUL window. Also, there is no functionality behind this example wizard that would pass any values back to a calling window. 

Looking at the wizard through Mozilla, you might also agree that the example code in the wizard is a little difficult to distinguish from the narrative text of the wizard.  I mentioned in the first article that XUL is compatible with CSS, so what you might want to do is create the following CSS file:

.codetext {

  font-weight:bold;
  font-size:12pt;
  text-indent:20pt;
  background-color:#5B7693;
  padding:10pt;

}

I have called mine dansStyle.css but feel free to call it whatever you like. Save it in the same directory as your XUL and RDF files and add a stylesheet reference to the top of the wizard file:

<?xml-stylesheet href=”dansStyle.css” type=”text/css”?>

This needs to appear directly after the XML declaration.  Once that is in place, simply add a class=”codetext” attribute to each of the opening description tags that enclose a CDATA element. Run the wizard once more and see your code highlighted, emboldened and indented to facilitate easy distinguishing of the example code.  

Wizards are often used to capture more complex input from a user than a simple yes or no (when a dialog window would be more appropriate).  Form controls can be placed inside wizards so that if, for example, a menu item was selected, the user could be guided through a series of questions or options. Once these questions had been answered, or the options selected, the results would be passed back to the window that the menu item that originally prompted the wizard resides in. In these cases, Mozilla would remain open. 

The next article will look at the creation of dialog boxes and discuss some of the more complex issues of these types of windows, such as opening or saving dialog boxes.

[gp-comments width="770" linklove="off" ]

chat