This section will describe overlays which can be used to separate common content.
In a simple application with only one window, you will generally have only one XUL file, along with a script file, a style sheet, a DTD file and perhaps some images. Some applications will have a number of dialogs associated with them also. These will be stored in separate XUL files. More sophisticated applications will contain many windows and dialogs.
An application that has several windows will have numerous elements or parts of the user interface that are common between each window. For example, each of Mozilla's components share some common elements. Some of the menus are similar, such as the tasks and help menus, the sidebar is similar, and each window shares some common global keyboard shortcuts.
One could handle this by re-implementing the similar elements and functions in each file that we need. However, this would be difficult to maintain. If you decide to change something, you would have to change it in numerous places. Instead, it would be better to use a mechanism that allows you to separate the common elements and have them shared between windows. You can do this with overlays.
An overlay file is a XUL file that does not describe a window but an overlay. Within the overlay, you place elements that are shared between all windows that use that overlay. Those elements are added into the window at locations determined by their ids.
For example, let's say you want to create a help menu that is shared between several windows. The help menu will be placed in an overlay, using the same XUL that you would use normally. The menu will be given an id attribute to identify it. Each window will import the overlay using a directive which will be described in a moment. To use the help menu as defined in the overlay, you only need to add a single menu element with the same value for its id attribute as used in the overlay. This menu does not need to contain any children as those will be placed in the overlay.
When a window with an overlay is opened, the elements in both the window and the overlay with the same ids are combined together. The children of matching elements are added to the end of the set of children in the window's element. Attributes that are present on the overlay's elements will be applied to the window's elements. These details will be explained in more detail later.
To import an overlay into a window, use the syntax described below. Let's add this near the top of the findfiles dialog XUL file.
<?xul-overlay href="chrome://findfile/content/helpoverlay.xul"?> |
This line should be added somewhere near the top of the file, usually just before any DTDs are declared. In the example above, the window is importing an overlay stored in the file helpoverlay.xul.
The overlay itself is a XUL file that contains an overlay element instead of a window element. Other than that, it is much the same. You can import overlays from inside other overlays. Overlays can also have their own stylesheets, DTDs and scripts. The example below shows a simple Help menu stored in an overlay.
Example 11.3.1
<?xml version="1.0"?>
<overlay id="toverlay"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<menu id="help-menu">
<menupopup id="help-popup">
<menuitem id="help-contents" value="Contents"/>
<menuitem id="help-index" value="Index"/>
<menuitem id="help-about" value="About..."/>
</menupopup>
</menu>
</overlay>
|
The overlay surrounds the overlay content. It uses the same namespace as XUL window files. Within the overlay is defined a single menu with three items on it. The id of this menu is help-menu. This means that its content will be added to the window where a similar element exists with the same id value. If such an element does not exist, that part of the overlay is ignored. The overlay can contain as many elements as necessary.
Next, we need to add the help menu to the findfiles dialog window. To do this just add a menu with the same id in the right location. The most likely place is just after the edit menu.
<menu id="edit-menu" value="Edit" accesskey="e">
<menupopup id="edit-popup">
<menuitem value="Cut" accesskey="t" key="cut_cmd" oncommand="doCut()"/>
<menuitem value="Copy" accesskey="c" key="copy_cmd" oncommand="doCopy()"/>
<menuitem value="Paste" accesskey="p" key="paste_cmd" oncommand="doPaste()"/>
</menupopup>
</menu>
<menu id="help-menu" value="Help" accesskey="h"/>
</menubar>
|
Here, the help menu element contains no content. The items from the menu are taken from the overlay because the ids match. We can then import the overlay in other windows and only have the contents of the help menu defined in one place.
We can further reduce the amount of code within the window by putting the attributes on the help menu (value and accesskey in this example) in the overlay instead. Those attributes will be inherited by the element. If both the element and the window specify the same attribute, the value in the overlay will override the element's value.
Let's change the help menu in this manner.
findfile.xul:
<menu id="edit-menu" value="Edit" accesskey="e">
<menupopup id="edit-popup">
<menuitem value="Cut" accesskey="t" key="cut_cmd" oncommand="doCut()"/>
<menuitem value="Copy" accesskey="c" key="copy_cmd" oncommand="doCopy()"/>
<menuitem value="Paste" accesskey="p" key="paste_cmd" oncommand="doPaste()"/>
</menupopup>
</menu>
<menu id="help-menu"/>
</menubar>
helpoverlay.xul:
<?xml version="1.0"?>
<overlay id="toverlay"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<menu id="help-menu" value="Help" accesskey="h">
<menupopup id="help-popup">
.
.
.
|
What would happen if there was content inside both the overlay and the window's element? In this case, the window's content will be used as is and the overlay's content will be appended to the end. This following example demonstrates this:
stopandgo.xul:
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin/global.css" type="text/css"?>
<window title="Stop and Go" id="test-window"
xmlns:html="http://www.w3.org/1999/xhtml"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<?xul-overlay href="chrome://findfile/content/toverlay.xul"?>
<box id="singlebox">
<button id="gobutton" value="Go"/>
<button id="stopbutton" value="Stop"/>
</box>
</window>
toverlay.xul:
<?xml version="1.0"?>
<overlay id="toverlay"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<box id="singlebox">
<button id="backbutton" value="Back"/>
<button id="forwardbutton" value="Forward"/>
</box>
</overlay>
|
In this example, the box with the identifier singlebox contains its own content. The elements are combined and the two buttons from the overlay are added to the end of the box. If we wanted to add them to the beginning, we could add an extra inner box and import elements inside there. Instead of placing the id on the outer box, place it on an inner box where you want the extra buttons to go. A better method will be described soon.
It gets a bit trickier with menus because of that extra menupopup element that is needed. If you put the popup in the window and in the overlay, only one will get used, because a menu can only have one popup. We can get around this easily by using the id of the popup also.
findfile.xul:
<menu id="help-menu">
<menupopup id="help-popup">
<menuitem id="help-findfiles" value="Find files help"/>
</menupopup>
</menu>
</menubar>
helpoverlay.xul:
<menu id="help-menu" value="Help" accesskey="h" />
<menupopup id="help-popup">;
<menuitem id="help-contents" value="Contents"/>
<menuitem id="help-index" value="Index"/>
<menuitem id="help-about" value="About..."/>
</menupopup>
|
Now, we overlay both the menu element, to get the attributes, and the menupopup element to get the menu contents. The result is that we get a menu with four items on it.
However, we may have wanted to have the menu items from the overlay in the previous example to be placed at the beginning of the menu instead of at the end. XUL provides a mechanism that allows you to not only place them at the beginning but put some of the items at the top and others at the bottom (or anywhere in-between). This allows you to overlay menus, toolbars and other widgets at the exact location that you wish.
To do this, use the insertbefore attribute on the menuitems. Its value should be the id of an element that you want to insert the item before. Alternatively, you can use the insertafter attribute to indicate which element to insert after. These attributes only affect the element they are on. If one element is 'inserted before', the remaining elements are still added to the end. If you want to have all the elements appear before, you must put the insertbefore attribute on all elements.
In addition, you can use the position attribute if you want to specify a specific index position. The first position is 1.
Let's say that we wanted the Contents and Index items from the overlay to appear before the Find files help item and the About item to appear after. To do this we add the insertbefore attribute to both the Contents and Index menu items. For completeness, you could add an insertafter attribute on the About menu too, but it isn't necessary since it appears at the end by default.
In the help menu example above, the id of the menu item is help-findfiles. Thus, we need to set the insertbefore attributes to this id. The example below shows the changes:
<menupopup id="help-popup"> <menuitem id="help-contents" value="Contents" insertbefore="help-findfiles"/> <menuitem id="help-index" value="Index" insertbefore="help-findfiles"/> <menuitem id="help-about" value="About..."/> </menupopup> |
Now, when a window using the help overlay (such as the find files dialog) is opened, the following will occur:
Actually, the values of insertbefore and insertafter can be comma-separated lists, in which case the first id in the list that is found in the window is used to determine the position.
(Next) Next, we'll find out to apply overlays to windows in different packages.
Examples: 11.3.1