XUL files and XUL overlays
Overlays are XUL files used to describe extra content in the UI. Though overlays often define UI elements that have been added as a result of an update or enhancement of some kind, they can be used in many different ways. Overlays provide a general mechanism for:
- Adding UI for additional components, as described in the example above
- Overriding small pieces of a XUL file without having to resupply the whole UI
- Reusing particular pieces of the UI
XUL files and overlays work together to describe a single master document. Though there is no formal restriction on what kind of XUL content is located in "base" XUL files and what kind should be put in overlays, XUL overlays generally define items that are not present in the basic versions of the UI, such as additional components. When plug-ins, browser extensions, or other applications provide new UI elements to the browser, these elements should be defined in overlay files. The installation of a media plug-in, for example, may add new icons and menu items to the interface:
In the navigatorOverlay.xul
file or in a separate navigatorSSPOverlay.xul
file (where navigator.xul
defines the basic UI for the navigator package), these new plug-in elements would be defined as a collection of elements or subtrees:
<menuitem name="Super Stream Player"/> <menupopup name="SS Favorites"> <menuitem name="Wave" src="mavericks.ssp"/> <menuitem name="Soccer" src="brazil_soccer.ssp"/> </menupopup> <titledbutton id="SSP" crop="right" flex="1" value="&SSButton.label;" onclick="FireSSP()"/>
Overlays and ID attributes
Bases and overlays are merged when they share the same ID attribute.
Thus, given the following base:
... <menu id="file-menu"> <menupopup id="menu_FilePopup"> <menuitem name="New"/> <menuitem name="Open"/> <menuitem name="Save"/> <menuitem name="Close"/> </menupopup> </menu> ...
And given the following overlay:
<?xml version="1.0"?> <overlay id="singleItemEx" xmlns:html="https://www.w3.org/1999/xhtml" xmlns="https://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> <menupopup id="menu_FilePopup"> <menu id="file_menu"> <menuitem name="Super Stream Player"/> </menu> </menupopup> </overlay>
The result will be:
... <menu id="file-menu"> <menupopup id="menu_FilePopup"> <menuitem name="New"/> <menuitem name="Open"/> <menuitem name="Save"/> <menuitem name="Close"/> <menuitem name="Super Stream Player"/> </menupopup> </menu> ...
If you are developing a Mozilla extension, note that the ID namespace is shared by all the extensions. So, in order to avoid unpredicted behaviors you will probably benefit from using a unique prefix for the IDs of the XUL elements of your extension. For instance, you can use the name of your extension, or an abbreviation of it.
Loading overlays
Overlays can be loaded explicitly or dynamically. When you load an overlay explicitly, it means that you intend to make it available every time the base file is loaded. Since one of the main purposes of overlays is to provide UI for additions or components to the basic package, explicit loading can be somewhat problematic when the overlay defines optional UI elements.
Loading overlays explicitly
A processing instruction is used to load overlay files explicitly into the master document. Inserting the following processing instruction before the DOCTYPE declaration in a base file tells the layout engine to load the named overlay file:
<?xul-overlay href="chrome://component/content/componentOverlay.xul"?>
where component is the name of the package being overlayed (e.g., chrome://navigator/content/navigatorOverlay.xul
).
The layout engine loads any overlay files and then flows the resulting XUL document, so problems associated with incremental insertion in menus, boxes, tables, and forms are avoided. Any number of overlays can be loaded into a master document, and an overlay can also load other overlays. Because an overlay is superimposed on the master document, there are no ambiguities relating to scoping of style sheets or scripts. Style sheets and scripts loaded by the overlay simply apply to the entire master document.
Loading overlays dynamically
The chrome registry makes it possible to load XUL overlays dynamically -- or only when necessary. The chrome registry, which is a special RDF datasource into which user-specific information is persisted, or stored, contains information about the components or additional packages that have been installed with the browser. When a component such as the "Super Stream Player" from the examples above is registered there, overlays associated with that component are loaded automatically. When the component is not present, only the base files are loaded.
Loading overlays at runtime
Firefox 1.5 and other Gecko 1.8-based applications also support loading overlays on-the-fly via the document.loadOverlay()
function. TODO: elaborate
Overlays and skins
Unlike base files, overlays should never load the master skin file for a package. The navigatorOverlay.xul
file, for example, does not and should never load the navigator.css
file that defines the master skin for the navigator package. Since the purpose of an overlay is to define new UI elements for a package within the context of that package's skin, the overlay should add structure but not new style. Any skins that are loaded by an overlay destructively replace the master skin for the base file, and can change the basic appearance of the package's skin in unfortunate ways.
bookmarks.css
, and is located in the skin/default subdirectory.Overlaying attributes
In addition to new elements and subtrees, you can also overlay attributes into existing elements. In XUL, attributes control important features of the skin like image sources, as in the following example, where an overlay destructively overwrites the image source in the base file with a replacement. In the base file, the HTML image element points to a Netscape GIF icon:
<html:img id="foo" src="netscapeImage.gif"/>
In the overlay, an element with the same ID attribute specifies a different image, and that image is superimposed on top of the original Netscape image as part of the merge process:
<html:img id="foo" src="mozillaImage.gif"/>
When the base file references an overlay file which contains the html image element above, the new src attribute is superimposed over the original, and the Mozilla icon replaces the Netscape icon.
Overlay positioning
XUL overlays also support positioning of nodes. You can specify a position
attribute on a node in the overlay to provide a hint for insertion into the master document. In the following example, the last menu item, Example Four, will be placed just after the "New" menu item instead of being appended to the end of the menu like the other kids.
<overlay id="main-overlay" xmlns:html="https://www.w3.org/1999/xhtml" xmlns:rdf="https://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="https://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> <menu id="file_menu"> <menuitem name="Example One"/> <menuitem name="Example Two"/> <menuitem name="Example Three"/> <menuitem name="Example Four" position="1"/> </menu> </overlay>
The node with the position
attribute orders itself to the top of the menu. The position
can also be given for nodes in overlay files that will be ordered in a group of similar items in the base file. For example, if only the last menuitem above had been in an overlay and the other items were defined in the base file, the overlayed menuitem would still appear at the top of the parent menu.
Attaching a script to an overlay
To execute a script when an overlay is applied, use a <script> element:
<script src="overlay.js"/>
If you need to set the version of JavaScript, you can set the type attribute:
<script type="application/x-javascript;version=1.8" src="overlay.js"/>
UI reuse with overlays
One of the biggest benefits of using overlays is that it allows you to reuse groups of elements that appear frequently in the UI. The overlay mechanism allows you to merge elements into existing subtrees, but it also allows you to store common UI elements in overlay files and merge them into any base files that use them. Using the ID attribute on an otherwise empty node in the base file, you can essentially reference a subtree defined in an overlay file and merge it in wherever it's needed.
For example, the buttons that appear at the bottom of common dialogs, the OK and Cancel buttons, may be used in dozens of places in the UI. Rather than redefining this set of buttons each time they are necessary in a particular dialog, base XUL files can overlay the XUL file in which these buttons are defined, dialogOverlay.xul
. (Actually, the implementation is one step more complicated than this: base files overlay dialogOverlay.xul
from the global component directory, which in turn overlays a platform-specific XUL file such as platformDialogOverlay.xul
. The mechanism is the same, however.)
Any dialog that wants to overlay these buttons just declares the overlay at the top:
<?xul-overlay href="chrome://global/content/dialogOverlay.xul"?>
And includes an empty box
with an ID of okCancelButtons
in the UI. The following snippet shows a dialog with custom UI elements at the top and a reference to the overlay's OK and Cancel buttons at the bottom:
<box align="horizontal" id="bx1" flex="100%" style="margin-bottom: 1em; width: 100%;"> <html:input type="checkbox" id="dialog.newWindow"/> <html:label for="dialog.newWindow">&openWin.label;</html:label> <spring flex="100%"/> </box> <box id="okCancelButtons"/>
For more detail, see the OK and Cancel button definitions being referenced here in the global component file platformDialogOverlay.xul
. Toolbars, submenus, boxes, and any other subtrees that appear in multiple places can be defined in overlays files in this way and referenced for reuse wherever necessary.