XUL Overlays

In short, overlays are a mechanism by which one XUL file can be inserted into another XUL file, in a controlled manner. That last bit is the key: “in a controlled manner”.

There are lots of ways to insert one file into another – we do it all the time when we inject our DTD file into the top of a XUL file at the web server. Usually, however, such insertions are “dumb” – the whole file is inserted in one big chunk, and there’s no easy way to distribute it throughout the host file.

For inserting a DTD file into the top of a page, dumb insertion is good enough. But what happens when you want to add new elements to the user interface of your application? You might need a new entry in one menu, another entry in the Help menu, a button here, a field there and a handful of labels all over the page. Dumb insertion isn’t any good when you actually want different parts of your file to target different parts of the host file.

XUL overlays get round this problem by letting you anchor the inserted elements using the ID of their parent. An example will make things clearer. Let’s start with our host file, part of which looks like this:



<menubar id="menubar-main">
 <menu label="File" id="menu-file">
  <menupopup id="menupopup-file">
   <menuitem label="Quit" oncommand="quit();" />
  </menupopup>
 </menu>
</menubar>


That’s a lovely generic menubar, the likes of which you might expect to find in any application. But suppose we also want to add some menu entries that are specific to this application – in this case a “File=>New Widget” entry and a “Help=>About Widgets” entry (noting that we don’t currently have a Help menu at all). All we need is an overlay file – which looks pretty much like a normal XUL file – which specifies where these new elements will go, relative to their parents:



<menubar id="menubar-main">
 <menu label="Help" id="menu-help">
  <menupopup id="menupopup-help">
   <menuitem label="About Widgets" oncommand="about();" />
  </menupopup>
 </menu>
</menubar>

<menupopup id="menupopup-file">
 <menuitem label="New Widget" oncommand="new_widget();" position="1" />
 <menuseparator position="2" />
</menupopup>


(sorry about the rubbish formatting – despite having a “code” tag, it seems that WordPress (with this theme, at least) doesn’t actually like showing code!)

Notice that our Help menu and its descendants are anchored within the parent menubar, by virtue of that menubar having the same ID as the menubar in our host XUL file. Notice also that the New Widget menuitem, and the menuseparator that follows it, are anchored within the File menupopup, again by virtue of the parent’s ID. The result of applying this overlay file to the original XUL host is a structure that looks something like this:



<menubar id="menubar-main">
 <menu label="File" id="menu-file">
  <menupopup id="menupopup-file">
   <menuitem label="New Widget" oncommand="new_widget();" />
   <menuseparator />
   <menuitem label="Quit" oncommand="quit();" />
  </menupopup>
 </menu>
 <menu label="Help" id="menu-help">
  <menupopup id="menupopup-help">
   <menuitem label="About Widgets" oncommand="about();" />
  </menupopup>
 </menu>
</menubar>


The browser renders the user interface as though it had been supplied in that composite format – so it shows a Help menu and the new entries in the File menu. The menuitem and menuseparator are placed before the “Quit” option due to the “position” attributes in the overlay file. It’s also possible to use “insertbefore” or “insertafter” attributes to locate the elements relative to an existing element, rather than at an absolute position amongst the parent node’s children. It’s even possible to use a “removeelement” attribute, which allows the content of an overlay file to remove elements from the final XUL document, even when those elements were originally present in the host file.

The example I’ve shown demonstrates how an overlay can be used to add special elements to a default bit of XUL code. In our framework they are most commonly used the other way round – we have a file that contains our standard UI elements (such as a “Help” menu and “File=>Log Out” menuitem) which is overlaid onto the individual application-specific XUL pages. This means that all of our applications have some common UI elements, without the individual developers having to do anything.

In our ASP.Net code – while we’re adding links to scripts, stylesheets, and our default overlay – we also check to see if there’s a page-specific overlay file for the current application. If there is, we insert a link to it at the top of the page. This means that we can maintain a standard version of each application, but if a particular customer needs it to be changed (fields removed, buttons added, and so on), we can often make those customisations in the page-specific overlay file. This makes it easier to upgrade the customer’s code in future, since the basic core files remain untouched.

As with most XUL topics, there’s far more detail (and far better examples) in the XUL Tutorial on Devmo.