In XBL, inheritance is the process in which one object included in another object is allowed to use properties from that parent object. These properties can be many things, depending on the implementation, ranging from methods to attribute property values. Inheritance is a concept familiar in programming languages, most notably object-oriented ones. It's not something alien to markup, however, and it is deployed effectively in XBL. This section examines three forms of XBL inheritance: binding, attribute, and implementation. As you will see, inheritance promotes self-contained (modular) and flexible bindings that permit shared content across and within XBL documents.
Binding inheritance occurs when one binding is linked to another binding or XUL element and uses some or all properties of it, whether they are content or behavior. A binding can inherit from another binding that exists in the same or different file. In one way, this useful feature makes a binding like a class, with content and methods that can be used elsewhere. Bindings become modules, which prevents code duplication, makes maintenance easier, and gets slotted in and out of documents.
Linkage or inheritance is enabled by the extends attribute on the <binding> element. This attribute contains the URL of the binding that you inherit from. This URL is made up of the location and name of the file that contains the binding (the # symbol), and the id of the specific binding being used. In this way, it is similar to the access method used in CSS attachment.
Although it is in the XBL 1.0 specification, Mozilla hasn't fully implemented type="inherits" on the children tag yet, so the best way to work with binding inheritance is to use the extends attribute. Example 7-6 shows a few bindings used in the implementation of the listbox cell in the Mozilla tree. It illustrates how extends is used to inherit from another binding.
Example 7-6. Binding inheritance
<binding id="listbox-base"> <resources> <stylesheet src="chrome://global/skin/listbox.css"/> </resources> </binding> <binding id="listcell" extends="chrome://global/content/bindings/listbox.xml#listbox-base"> <content> <children> <xul:label class="listcell-label" xbl:inherits="value=label,flex=flexlabel,crop,disabled" flex="1" crop="right"/> </children> </content> </binding> <binding id="listcell-iconic" extends="chrome://global/content/bindings/listbox.xml#listcell"> <content> <children> <xul:image class="listcell-icon" xbl:inherits="src=image"/> <xul:label class="listcell-label" xbl:inherits="value=label,flex=flexlabel,crop,disabled" flex="1" crop="right"/> </children> </content> </binding>
In Example 7-6, listcell-iconic inherits listcell. In turn, listcell inherits list-box-base, which holds resources. The listcell binding is a cell with text only and the listcell-iconic binding has text and an image. Thus, the user has a choice of using a list cell binding with an icon or no icon. Yet both of these bindings have access to the stylesheet resource declared in the base binding. If listcell-iconic is used, the duplicate xul:label is ignored in the inherited binding and the stylesheet inherited from the base binding via the inherited binding is used. We've used this technique to illustrate how resources in multiple bindings are shared.
With binding extensions that use the extends attribute, you can also extend a XUL element as a model, using extensions as a proxy to mimic that XUL element. The element may not be included directly in the anonymous content, but its characteristics are still present on the bound element. If you use the XUL namespace xul: in the same way you use it for XUL content in a binding, you can inherit the XUL element properties as illustrated in Example 7-7.
Example 7-7. Inheriting XUL widget characteristics using extends
<binding id="Widget1" extends="xul:vbox"> <content> <xul:description value="Top" /> <children includes="image" /> <xul:description value="Bottom" /> </content> </binding>
In Example 7-7, the binding has all of the attributes and behavior of a XUL box. Because you extend a box element, the base widget <mybinding> is now a vertical box. The anonymous content is laid out according to the box model, and all attributes that are recognized on the bound element are applied to the box.
Also known as "attribute forwarding," attribute inheritance is a way for anonymous content to link to the attributes from the bound element. When the bound element attribute is changed, this modification filters down to the binding attribute list. The code in Example 7-8 shows anonymous content where multiple attributes are picked up by the xbl:inherits attribute, with each one separated by a comma.
Example 7-8. XBL attribute inheritance
<xul:box class="insideBox" xbl:inherits="orient, flex, align"> <xul:description value="Top" /> <xul:box> <children includes="image" /> </xul:box> <xul:description value="Bottom" /> </xul:box> </xul:box>
The element that inherits the attributes can be anywhere in the chain of anonymous content. In this case, it is on the top-level box. It assumes the value given to these attributes in the bound element. Here is the XUL that uses the binding content from Example 7-8:
<mywidget orient="vertical" flex="1" align="center" />
The xul:box element inherits the attribute values vertical, 1, and middle, respectively, from the bound element (mywidget). The box in the anonymous content contains three children: two text (description) elements and an image contained in another box. The default orientation for a box is horizontal, but these child elements are now positioned vertically.
You may notice that the inherits attribute is preceded with the xbl: prefix, unlike other attributes in the XBL element set. Why is this unique? It guarantees that the effect is on the binding and not directly on the element that uses it. This ensures that the element can have an inherits attribute of its own if needed. This scenerio is unlikely and you might wonder why this rule does not apply to other attributes used on XBL elements. To achieve correct binding, the XBL namespace must be declared on an element at a higher level than the element using it, most commonly the <bindings> container, as explained earlier. Here is what the code will look like:
<binding id="my-bindings" xmlns="http://www.mozilla.org/xbl" xmlns:html="http://www.w3.org/1999/xhtsml" xmlns:xbl="http://www.mozilla.org/xbl">
The third type of inheritance, inheritance of behavior, is also achieved by using the extends attribute and is useful when you want to use methods or properties in another binding. Example 7-9 shows how one binding inherits implementation from another in the same file.
Example 7-9. Inheritance of behavior between bindings
<binding id="Widget1" extends="test.xml#Widget2"> <content> <xul:box class="insideBox"> <xul:description value="Top" /> <xul:box> <children includes="image" /> </xul:box> <xul:description value="Bottom" /> </xul:box> </content> </binding> <binding id="Widget2"> <implementation> <constructor> this.init( ); </constructor> <method name="init"> <body> <![CDATA[ dump("This is Widget2");]]> </body> </method> </implementation> </binding>
The Widget1 binding in Example 7-9 pulls in Widget2 using extends. Widget2 has implemented a constructor that dumps some text to output. When Widget1 is bound and it does not find any implementation to initiate, it looks to the inherited binding and, in this case, dumps "This is Widget2" to output.
In a bindings inheritance tree, more than one implementation could have a method with the same name. In this case, the most derived binding -- the one nested deepest in the inheritance chain -- is the one used. It is even possible for some common DOM functions used on the bound element outside of the anonymous content to find imitators when implementing the attached bindings.
<method name="getElementById"> <parameter name="id" /> <body> <!-- implementation here --> </body> </method>
If you glance through the source code for the Mozilla chrome, you may notice that many of the standard XUL widgets used were extended by using XBL. The button is a good example.
On its own, the button can display text with the value attribute and an image with the src attribute. Usually, this is sufficient, and you can color the button and change the text font with CSS. But you may want to take advantage of inherent behaviors in other elements or inherit from other bindings. Mozilla buttons are a mix of <box>, <text>, and <image> elements, and they take on the characteristics of each.