Anonymous Content

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.

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 binding element. The 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 content 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, altough it doesn't have to be. Any element that has its CSS -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 content 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.

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 bindings 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.

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.

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 content 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.

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 children 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 menulist element, might be created as follows:

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 menupopup will be added to the content in the location specified by the children 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.

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>

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 children 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.

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 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 children 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:

<binding id="zoombox">
  <content>
    <xul:box flex="1">
      <xul:button label="Zoom In"/>
      <xul:box flex="1" style="border: 1px solid black">
        <image src="images/happy.jpg"/>
        <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 children tag. This is an important distinction when using the DOM with XBL. This also applies to CSS selector rules.

Multiple Children Elements

You can also use multiple children elements and have certain elements be placed in one location and other elements placed in another. By adding a 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:

Example 11.2.1: Source
<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 children element only grabs the label and button elements, as indicated by its includes attribute. The second children element, because it has no includes attribute, grabs all of the remaining elements.


(Next) In the next section, we'll look at how attributes can be inherited into the anonymous content.

Examples: 11.2.1


Copyright (C) 1999 - 2004 XulPlanet.com