In this section we'll look at creating content with XBL.
XBL Content
XBL can be used to automatically add a set of elements inside another element. The XUL file only needs to specify the outer element while the inner elements are described in the XBL. This is useful for creating a single widget that is made up of a set of other widgets, but can be referred to as only a single widget. Mechanisms are provided for adding attributes to the inner elements that were specified on the outer element.
Declaring Scrollbar Example
The example below shows how a scrollbar might be declared (It has been simplified a bit from the real thing):
<bindings xmlns="http://www.mozilla.org/xbl" xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> <binding id="scrollbarBinding"> <content> <xul:scrollbarbutton type="decrement"/> <xul:slider flex="1"> <xul:thumb/> </xul:slider> <xul:scrollbarbutton type="increment"/> </content> </binding> </bindings>
This file contains a single binding, declared with the
element. The binding
id
attribute should be set to the identifier of the binding. This way it can be referred to through the CSS -moz-binding
property.
The
tag is used to declare anonymous content that will be added to the scroll bar. All of the elements inside the content
tag will be added inside the element that the binding is bound to. Presumably this binding would be bound to a scroll bar, although it doesn't have to be. Any element that has its CSS content
-moz-binding
property set to the URI of the binding will use it.
The result of using the above binding is that the line of XUL below will be expanded as follows, assuming that the scrollbar is bound to the XBL above:
<scrollbar/> expands to: <scrollbar> <xul:scrollbarbutton type="decrement"/> <xul:slider flex="1"> <xul:thumb/> </xul:slider> <xul:scrollbarbutton type="increment"/> </scrollbar>
The elements within the
tag are added to the scroll bar anonymously. Although anonymous content is displayed on screen, you cannot get to it through a script in the normal way. To the XUL, it's as if there was only one single element, even though it is really made up of a number of elements.content
If you look at a scroll bar in a Mozilla window, you will see that it is made up of an arrow button, a slider, a thumb inside it and a second arrow button at the end, which are the elements that appear in the XBL above. These elements would in turn be bound to other bindings that use the base XUL elements. Notice that the content elements need the XUL namespace (they appear preceded with xul:
), because they are XUL elements and aren't valid in XBL. This namespace was declared on the
tag. If you don't use the namespace on XUL elements, Mozilla will assume that the elements are XBL, not understand them, and your elements won't work correctly.bindings
Filename Input Field Example
Another example, this time for a field for entering a filename:
<binding id="fileentry"> <content> <textbox/> <button label="Browse..."/> </content> </binding>
Attaching this binding to an element will cause it to contain a field for entering text, followed by a Browse button. This inner content is created anonymously and cannot be seen using the DOM.
Override the Bound Element
The anonymous content is created automatically whenever a binding is attached to an element. If you place child elements inside the XUL, they will override the elements provided by the binding. For example, take this XUL fragment, assuming it is bound to the scrollbar XBL earlier:
<scrollbar/> <scrollbar> <button label="Overridden"/> </scrollbar>
The first scroll bar, because it has no content of its own, will have its content generated from a binding definition declared in an XBL file. The second scroll bar has its own content so it will use that instead of the XBL content, resulting in something that isn't much of a scroll bar at all. Note that the built-in elements such as scroll bars get their XBL from the files in the bindings directory in the toolkit package.
This only applies to the elements defined within the
tag. Properties, methods and other aspects of XBL are still available whether the content is from XBL or whether the XUL provides its own content.content
Using the Children Element
There may be times when you want both the XBL content and the content provided by the XUL file to be displayed. You can do this by using the
element. The children added in the XUL are added in place of the children
element. This is handy when creating custom menu widgets. For example, a simplified version of an editable children
element, might be created as follows:menulist
XUL: <menu class="dropbox"> <menupopup> <menuitem label="1000"/> <menuitem label="2000"/> </menupopup> </menu> CSS: menu.dropbox { -moz-binding: url('chrome://example/skin/example.xml#dropbox'); } XBL: <binding id="dropbox"> <content> <children/> <xul:textbox flex="1"/> <xul:button src="chrome://global/skin/images/dropbox.jpg"/> </content> </binding>
This example creates an input field with a button beside it. The
will be added to the content in the location specified by the menupopup
element. Note that to DOM functions, the content will appear as it was in the XUL file, so the menupopup will be a child of the menu. The XBL content is hidden away so the XUL developer doesn't need to even know it is there.children
The resulting content would be:
<menu class="dropbox"> <menupopup> <menuitem label="1000"/> <menuitem label="2000"/> </menupopup> <textbox flex="1"/> <button src="chrome://global/skin/images/dropbox.jpg"/> </menu>
includes
Attribute
In some cases, you may wish to only include specific types of content and not others. Or, you may wish to place different types of content in different places. The includes
attribute can be used to allow only certain elements to appear in the content. Its value should be set to a single tag name, or to a list of tags separated by vertical bars (the |
symbol).
<children includes="button"/>
This line will add all buttons that are children of the bound element in place of the
tag. Other elements will not match this tag. You can place multiple children
elements in a binding to place different types of content in different places. If an element in the XUL does not match any of the children
elements, that element (and any others that don't match) will be used instead of the bound content.children
Here is another example. Let's say that we wanted to create a widget that displayed an image with a zoom in and zoom out button on each side of it. This would be created with a box to hold the image and two buttons. The image element has to be placed outside the XBL as it will differ with each use.
XUL: <box class="zoombox"> <image src="images/happy.jpg"/> <image src="images/angry.jpg"/> </box> XBL: <binding id="zoombox"> <content> <xul:box flex="1"> <xul:button label="Zoom In"/> <xul:box flex="1" style="border: 1px solid black"> <children includes="image"/> </xul:box> <xul:button label="Zoom Out"/> </xul:box> </content> </binding>
The explicit children in the XUL file will be placed at the location of the
tag. There are two images, so both will be added next to each other. This results in a display that is equivalent to the following:children
<binding id="zoombox"> <content> <xul:box flex="1"> <xul:button label="Zoom In"/> <xul:box flex="1" style="border: 1px solid black"> <xul:image src="images/happy.jpg"/> <xul:image src="images/angry.jpg"/> </xul:box> <xul:button label="Zoom Out"/> </xul:box> </content> </binding>
From the DOM's perspective, the child elements are still in their original location. That is, the outer XUL box has two children, which are the two images. The inner box with the border has one child, the
tag. This is an important distinction when using the DOM with XBL. This also applies to CSS selector rules.children
Multiple Children Elements
You can also use multiple
elements and have certain elements be placed in one location and other elements placed in another. By adding a children
includes
attribute and setting it to a vertical bar-separated list of tags, you can make only elements in that list be placed at that location. For example, the following XBL will cause text labels and buttons to appear in a different location than other elements:
<binding id="navbox"> <content> <xul:vbox> <xul:label value="Labels and Buttons"/> <children includes="label|button"/> </xul:vbox> <xul:vbox> <xul:label value="Other Elements"/> <children/> </xul:vbox> </content> </binding>
The first
element only grabs the label and button elements, as indicated by its children
includes
attribute. The second
element, because it has no children
includes
attribute, grabs all of the remaining elements.
See also Anonymous Content section of the XBL reference.
In the next section, we'll look at how attributes can be inherited into the anonymous content.