Copyright © 2000 Mozilla.org
This note outlines the XML Binding Language. XBL is a markup language for describing bindings that can be attached to elements in other documents. Bindings can be attached to elements using either cascading stylesheets [CSS] or the document object model [DOM]. The element that the binding is attached to, called the bound element, acquires the new behavior specified by the binding.
Bindings can contain event handlers that are registered on the bound element, an implementation of new methods and properties that become accessible from the bound element, and anonymous content that is inserted underneath the bound element.
This NOTE was submitted to the World Wide Web Consortium (see Submission Request, W3C Staff Comment) on 2001-01-12 with the intention that the W3C use it as a basis for furthering the work on BECSS. For a full list of all acknowledged Submissions, please see Acknowledged Submissions to W3C.
Inquiries from the public about this submission should be directed to the mozilla.org community. The forum most appropriate for discussion of XBL and related matters in the context of Mozilla is the newsgroup netscape.public.mozilla.xbl (which may soon change to mozilla.dev.tech.xbl). The W3C forum most appropriate for discussing this submission is the www-style mailing list.
This document is a NOTE made available by the W3C for discussion only. Publication of this Note by W3C indicates no endorsement by W3C or the W3C Team, or any W3C Members. W3C has had no editorial control over the preparation of this Note. This document is a work in progress and may be updated, replaced, or rendered obsolete by other documents at any time.
A list of current W3C technical documents can be found at the Technical Reports page.
1. XBL Elements
1.1. The bindings Element
1.2. The binding Element
1.3. The content Element
1.4. The children Element
1.5. The element Element
1.6. The implementation Element
1.7. The method Element
1.8. The parameter Element
1.9. The body Element
1.10. The property Element
1.11. The getter Element
1.12. The setter Element
1.13. The handlers Element
1.14. The handler Element
1.15. The script Element
1.16. The stylesheet Element
2. Binding Attachment and Detachment
2.1. Attachment using CSS
2.2. Attachment using the DOM
2.3. The bindingattached Event
2.4. The bindingdetached Event
2.5. Binding Documents
3. DOM Interfaces
3.1. The DocumentXBL Interface
3.2. The ElementXBL Interface
4. Anonymous Content
4.1. Scoping and Access using the DOM
4.2. Content Generation
4.2.1. Rules for Generation
4.2.2. The contentgenerated Event
4.2.3. The contentdestroyed Event
4.3. Attribute Forwarding
4.4. Insertion Points
4.4.1. <children> and <element>
4.4.2. Handling DOM Changes
4.5. Event Flow and Targeting
4.5.1. Flow and Targeting Across Scopes
4.5.2. Focus and Blur Events
4.5.3. Mouseover and Mouseout Events
4.6. Anonymous Content and CSS
4.6.1. Selectors and Scopes
4.6.2. Binding Stylesheets
5. Binding Implementations
5.1. Methods
5.2. Properties
5.3. Inheritance of Implementations
6. Event Handlers
7. Example - Sticky Notes
A. References
<!ENTITY % bindings-content "(binding|script|stylesheet)*"> <!ELEMENT bindings %bindings-content;> <!ATTLIST bindings id ID #IMPLIED type CDATA #IMPLIED >
The bindings
element is the root element of an XBL
document. It contains zero or more binding
elements
as children. Each binding
child element defines a
unique binding that can be attached to elements in other documents.
The bindings
element can also contain
script
and stylesheet
elements as
children. These specify scripts and stylesheets that are used by
the bindings.
<bindings xmlns="http://www.mozilla.org/xbl"> <binding id="binding1"> ... </binding> <binding id="binding2"> ... </binding> ... </bindings>
id
attribute is a document-unique
identifier. The value of this identifier is often used to
manipulate the element through a DOM interface (e.g., using
document.getElementById).type
attribute specifies the scripting
language used by all bindings in the document. Bindings can
selectively override this default by specifying type
attributes of their own.<!ENTITY % binding-content "(content?,implementation?,handlers?)"> <!ELEMENT binding %binding-content;> <!ATTLIST binding id ID #REQUIRED extends CDATA #IMPLIED display CDATA #IMPLIED >
The binding
element describes a single XBL binding
that dynamically binds new information to XML elements in other
documents. Each binding has three optional components.
Content: A binding can specify new content that is placed under the bound element. This content is anonymous and is hidden from the bound element's DOM.
Methods and Properties: A binding can specify additional methods that can be invoked on the element. It can also specify additional properties that can be retrieved or set on the element. In this way the functionality of the bound element becomes extensible.
Behavior: A binding can specify event handlers for specific actions like key and mouse events that can make use of the new functionality applied in the binding.
id
attribute is a document-unique identifier.
For the binding
element, this attribute is required,
since it is used to uniquely identify a binding.extends
attribute is used to specify the URL
of a binding that this binding inherits from. The URL specifies a
particular binding document. The # notation must be used to point
to a specific binding id
within a binding document.
<!ELEMENT content ANY> <!ATTLIST content id ID #IMPLIED applyauthorsheets false #IMPLIED >
The content
element contains child nodes that can
be in any namespace. The subtree specified by the
content
element is referred to as the anonymous
content template. When a binding is attached and if the
conditions specified by the template are met, the
content
element's child nodes are cloned and inserted
into the bound document under the bound element. Because the nodes
are hidden from their parent and exist outside the normal document
tree, they are referred to as anonymous content.
id
attribute is a document-unique identifier.applyauthorsheets
attribute indicates whether
or not rules in author style sheets associated with the bound
element's document apply to the anonymous content generated by the
binding. If omitted, a value of false
is assumed.
See section 4.6 for more
information.<!ELEMENT children EMPTY> <!ATTLIST children id ID #IMPLIED includes CDATA #IMPLIED type (explicit|inherited) explicit applybindingsheets false #IMPLIED >
The children
element is used inside anonymous
content to specify insertion points for explicit content that might
already exist underneath the bound element or for anonymous content
generated by the base binding. As far as the presentation model is
concerned, any anonymous content the binding places between the
bound element and the insertion point is interleaved between the
bound element and its explicit children without affecting the
document model.
See section 4.4 for more information.
id
attribute is a document-unique identifier.includes
attribute can be used to indicate
that only certain content should be placed at the insertion point
specified by the children
element. Its value is an
XPath selector as described in the XPath 1.0
specification. For the purposes of the evaluation, the bound
element is treated as the context node. If the selector evaluates
to anything other than a node set, it is ignored. A child can
only be placed within the insertion point if it is matched by the
XPath selector. Only immediate children are matched against the
selector.type
attribute can be used to indicate the
type of the insertion point. There are two types of insertion
points. An explicit insertion point is for the
explicit children of the bound element only. An
inherited insertion point is used to specify that
anonymous content from the base binding can be generated and
placed at the insertion point.applybindingsheets
attribute indicates
whether or not style sheets loaded from an XBL document are
applied to a bound element's explicit children (in addition to the
bound element itself) that are inserted below this insertion
point. If omitted, a value of false
is assumed. See
section 4.6 for more
information.<!ELEMENT element ANY> <!ATTLIST element id ID #IMPLIED >
The element
tag specifies the position of the bound
element within the anonymous content of a binding. Normally
anonymous content is generated underneath the bound element. If
the element
tag is used inside anonymous content it
indicates the position at which the bound element should be placed
relative to its anonymous content. This allows anonymous content
ancestors to be generated by the binding (in addition to
children).
If no element
tag is specified, all anonymous
content is generated underneath the bound element.
id
attribute is a document-unique identifier.<!ENTITY % implementation-content "(method|property)*"> <!ELEMENT implementation %implementation-content;> <!ATTLIST implementation id ID #IMPLIED name CDATA #IMPLIED implements CDATA #IMPLIED type CDATA #IMPLIED >
The implementation
element describes a set of
methods and properties that are attached to the bound element.
Once the binding is attached, these methods and properties can be
invoked directly from the bound element.
id
attribute is a document-unique identifier.name
attribute can be used to provide a
specific name for an implementation. This name can then be used
to reference the implementation. For example, in Javascript the
value of this attribute represents the name of the corresponding
class that is constructed for the implementation. If no name
attribute is specified then the binding's document URI and id are
used to uniquely reference the binding's implementation.implements
attribute can be used to describe
a set of interfaces that are implemented by the binding. Its
value is a comma-separated list of named interfaces. If
supported, in strongly typed languages the bound element can be
referenced not only as any of the interfaces that the element
might already support (e.g., HTMLElement) but also as any of the
interfaces described by this attribute. Support of this
capability is optional.type
attribute indicates the language used to
describe the methods and properties of the implementation, e.g.,
text/javascript
.<!ENTITY % method-content "(parameter*,body?)"> <!ELEMENT method %method-content;> <!ATTLIST method id ID #IMPLIED name CDATA #REQUIRED type CDATA #IMPLIED >
The method
element is used to describe a single
method of a binding implementation.
<method name="scrollTo"> <parameter name="index"/> <body> this.setAttribute("scrollpos", index); </body> </method>
id
attribute is a document-unique
identifier.name
attribute's value is the name given to
the method when it is attached to the bound element. The method
can be invoked directly from the bound element using this
value.type
attribute indicates the language used
for the body of the method, e.g.,
text/javascript
.<!ELEMENT parameter EMPTY> <!ATTLIST parameter id ID #IMPLIED name CDATA #REQUIRED >
The parameter
element is used inside a
method
element. It represents a single parameter of a
method.
[Editor's Note: Should we support the capability to specify types? Assuming that only dynamic scripting languages are used, this may not be a requirement.]
id
attribute is a document-unique
identifier.name
attribute is used by script
within a method's body
element to reference this
parameter.<!ELEMENT body CDATA> <!ATTLIST body id ID #IMPLIED >
The body
element represents the implementation of its corresponding
method
. Its contents are the script that is executed when the method
is invoked.
id
attribute is a document-unique identifier.
<!ENTITY % property-content "(getter?,setter?)|#PCDATA"> <!ELEMENT property %property-content;> <!ATTLIST property id ID #IMPLIED name CDATA #REQUIRED readonly (true|false) #IMPLIED onget CDATA #IMPLIED onset CDATA #IMPLIED element IDREF #IMPLIED attribute CDATA #IMPLIED property CDATA #IMPLIED type CDATA #IMPLIED >
The property
element represents a single property of an
implementation. Properties come in two flavors. One type of
property consists of a pair of getter/setter
functions that can be defined using onget/onset attributes or getter/setter
elements underneath the property element. The other type of property
is a raw value whose initial value can be specified
with a script contained underneath the property element.
Like methods, once the binding is attached, the property can
be obtained directly from the bound element.
id
attribute is a document-unique identifier.
name
of the property. This is the name used to refer
to the property on the bound element.
readonly
attribute is used to designate a property as
read-only. If set to true
, the value of the property cannot be
altered. If this attribute is omitted, the property will be readable and writable.
onget
attribute's value is a script that executes when the
value of the property is requested. If this attribute is set, any initial value
contained underneath the element will be ignored.
The return value of the script represents the
value of the property that will be returned to the requestor. A property getter can
also be specified as a child of the property
element using the
getter
tag.
onset
attribute's value is a script that executes when the
value of the property is being altered.
If this attribute is set, any initial value
contained underneath the element will be ignored.
Within the script, the parameter val
represents the new value being assigned. The script should always return the
actual value assigned in order to allow for chained assignment operations. A
property setter can also be specified as a child of the property
element
using a setter
tag.
element
attribute's value is the ID of an anonymous element
generated by one of the bindings attached to the bound element. When this attribute
is set, any getters and setters defined are ignored. Instead whenever the property
is set on the bound element, a corresponding property or attribute is set on the
anonymous element. Whenever the property is retrieved, it is obtained from the
corresponding property or attribute on the anonymous element.
element
attribute, the property
attribute links the property named by the attribute to the property specifed on the
bound element. Its value is used when the bound element's property is accessed, and
its value is set when the bound element's property is set.
element
attribute, this
attribute links the specified attribute to the property specifed on the
bound element. Its value is obtained when the bound element's property is accessed, and
its value is set when the bound element's property is set.
type
attribute indicates the language used to describe the
getters/setters for the property or the initial value of the property,
e.g., text/javascript
.
<!ELEMENT getter PCDATA> <!ATTLIST getter id ID #IMPLIED type CDATA #IMPLIED >
The getter
element wraps a script for retrieving a specific property. It
is always the child of a property
element. The type
attribute on the enclosing implementation
element determines the
language of the script.
id
attribute is a document-unique identifier.
type
attribute indicates the language used to describe the
getter.
<!ELEMENT setter PCDATA> <!ATTLIST setter id ID #IMPLIED type CDATA #IMPLIED >
The setter
element wraps a script that is invoked when a specific
property is set. It
is always the child of a property
element. The type
attribute on the enclosing implementation
element determines the
language of the script. Inside the script, the parameter val
represents
the value being assigned into the property.
id
attribute is a document-unique identifier.
type
attribute indicates the language used to describe the
setter.
<!ENTITY % handlers-content "handler*"> <!ELEMENT handlers %handlers-content;> <!ATTLIST handlers id ID #IMPLIED type CDATA #IMPLIED >
The handlers
element contains event handlers that can be attached
to elements within the bound document. These handlers are installed when the
binding is attached and removed when the binding is detached.
id
attribute is a document-unique identifier.
type
attribute is the language used by all
scripts specified in the child handler
elements.
<!ENTITY % handler-content "PCDATA"> <!ELEMENT handler %handler-content;> <!ATTLIST handler id ID #IMPLIED event NMREF #REQUIRED action CDATA #IMPLIED phase (capturing|bubbling|target) #IMPLIED attachto (element|document|window) element button (1|2|3) #IMPLIED modifiers CDATA #IMPLIED keycode CDATA #IMPLIED charcode CDATA #IMPLIED type CDATA #IMPLIED >
The handler
element describes a single event handler. This handler
is attached to its target at the time the binding is attached and unhooked when
the binding is detached from the bound element. It wraps a script that is
executed when the event handler is matched.
id
attribute is a document-unique identifier.
event
attribute describes the specific event that this handler
is listening for. Its value can be any legal DOM event name (including custom
events created using the DocumentEvent interface of the DOM).
action
attribute contains script that is invoked when the
handler fires. The type
attribute on the enclosing handlers
element determines the language of the script. The handler script can also be specified
as a child of the handler
element.
capturing
, bubbling
,
and target
. If a phase is specified, the handler will only be invoked
during that phase of the event handling process. If no phase is specified, a default
of bubbling
is assumed.
attachto
attribute specifies the DOM event receiver that the
handler should be registered with. Possible values are element
,
document
, and window
.
A value of element
indicates that the handler should
be attached to the bound element. A value of document
specifies the
bound document as a target. A value of window
represents the window
that encloses the bound document. If this attribute is omitted, the handler attaches
itself to the bound element.
[Editor's Note: Should window be mentioned in the spec? The DOM makes no mention of windows.]
button
attribute imposes a filter on the handler. It
is used with mouse handlers to specify a particular button. The event handler will
only be matched if the value of the button field in the DOM mouse event object matches
the value of the attribute.
modifiers
attribute imposes a filter on key and mouse handlers.
Its value is a comma-separated list of modifier keys. Allowed keys that can be
specified are shift
, alt
, control
,
meta
, accel
and access
.
If present in the list, then the
modifier key must be set in the DOM event object in order for the handler to
be matched. If the handler is filtered and the modifier is not present in the list,
then the modifier key must not be set in the DOM event object in order for the
handler to be matched. The accel
value provides a hint to the
user agent that the platform's primary accelerator key should be used.
It is left up
to the user agent to decide which modifier key represents the primary key.
The access
value provides a hint to the user agent that the platform's
primary shortcut mnemonic key should be used.
keycode
attribute imposes a filter on key handlers. Its
value is a key identifier for a specific keycode, e.g., vk_enter
.
[Editor's Note: A forthcoming DOM events specification will presumably outline the list of valid keycode strings.]
If this attribute is
present, then its value must match the keycode
field of the DOM
key event object in order for the handler to fire.
charcode
attribute imposes a filter on key handlers. Its
value is a single character, e.g., "z"
. If this attribute is
present, then its value must match the charcode
field of the DOM
key event object in order for the handler to fire.
[Editor's Note: As DOM Events mature more attributes may be added. For example, mutation events define several new fields such as relatedTarget that could be supported in the filtering syntax.]
type
attribute is the language used for the
script specified in the handler
element.
The script
element is equivalent to its HTML counterpart. The
supported attributes and content can be found here.
The way in which the script block gets applied, however, is different.
The element defines a script that is evaluated by a given document (e.g., an HTML document)
the first time a binding in the XBL file is attached to a bound element in
the document. The script is always evaluated only once per document.
The stylesheet
element supports the same attributes as the
xml-stylesheet
processing instruction with the exception of the title
and alternate
attributes. It is used to specify a stylesheet that can be applied
to anonymous content generated by bindings and to bound elements and explicit children
in documents that use the bindings. A distinction is made in XBL between stylesheets
loaded through this tag that are intended to style elements in other documents
and the xml-stylesheet
processing instruction, which only indicates
a stylesheet that is applied should the XBL document itself be presented.
binding
property.
The value of the binding
property is a set of URLs that identify
specific bindings. An individual URL in the set
consists of the binding document's URL and the binding's
document-unique identifier.
In the following example, a binding is referenced that will be attached to all HTML checkbox elements.
input[type="checkbox"] { binding: url("http://www.mozilla.org/xbl/htmlBindings.xml#checkbox"); }
Bindings attached through CSS will only remain on the bound element as long as the element continues to match the style rule. If at any time a resolution of style on the element determines that a different binding should be attached, the old binding (and all bindings that it explicitly extends in its inheritance chain) will be detached.
Whenever an element is removed from a document, any bindings attached via CSS loaded by the document will be detached.
DocumentXBL
interface. The method addBinding
takes an element and a binding URL
and attaches the binding to the element.
var checkbox = document.getElementById("mycheckbox"); document.addBinding(checkbox, "http://www.mozilla.org/xbl/htmlBindings.xml#checkbox");
This attachment is not necessarily synchronous. Scripts that invoke this method should not assume that the binding is installed immediately after this method returns. See 2.5 Binding Documents for more information.
When a binding is attached using the DOM, it inherits from the current most derived
binding that may already be attached to the element. Any bindings attached
to an element using the addBinding
method will remain on the element
until the element is destroyed or a corresponding removeBinding
call is
made.
If a binding is attached using addBinding
and it already specifies an
inherited binding using the extends
attribute, then the base binding
at the end of the inheritance chain is the
one that will inherit from the most derived binding that is already attached.
For example, given a binding d1, with an explicit inheritance chain of
d1 -> d2 -> d3
If this element is attached to
an element using addBinding
that already has a binding chain of
s1 -> s2 -> s3
the resulting binding chain following the addition of the binding is
d1 -> d2 -> d3 -> s1 -> s2 -> s3
The inheritance between d3 and s1 is implicit,
meaning that there is no connection in the XBL documents between the two bindings.
The inheritance link has been forged dynamically through the invocation of the
addBinding
method.
load
event for the
bound document. When the load
event fires, and if all binding documents
loaded successfully, it can be assumed that all bindings are attached to all elements
in the page. For elements that are created during or after the load
event is fired, no
assumptions can be made regarding order of binding attachment.
When a binding is attached, the following events occur:
If the binding needs to execute any initialization code following its attachment
to an element, it can do so using a bindingattached
handler.
This handler contains script that executes upon completion of the binding attachment.
bindingattached
handlers
can only be attached directly to bound elements. If an attachto
attribute
is specified on a bindingattached
handler, it will be ignored.
bindingattached
handlers for bound elements constructed prior to the
completion of the bound document load will be executed before the load
event of the bound document fires.
When a binding is attached that extends another binding, the bindingattached handler
of the base binding executes first, and then the derived binding's handler executes.
For bindings attached prior to the firing of the load
event, the following
partial order applies:
for any bound element, the bindingattached handlers for all the descendants of
that element will execute before the bindingattached handler on the bound
element executes. In the script for the handler, the author can thus guarantee
that all children of the bound element are fully initialized. After the
load
event fires, however, this partial order is no longer
guaranteed.
[Editor's Note: A recent idea is to replace bindingattached (and bindingdetached) with a <constructor> (and matching <destructor>) element. That would remove the need for any special XBL-only events.]
Bindings attached through the DOM are detached when the following conditions are met:
removeBinding
is called on a specific binding
bindingdetached
handler that executes prior
to the binding detachment. Using a bindingdetached
handler,
a binding can perform any necessary cleanup before it is torn down.
Bindings in an inheritance chain are always detached from the most derived binding
to the base. Therefore the bindingdetached
handler of the derived binding
will execute, and then the base binding's handler will execute.
When bindings attached through style are detached because of a style change, they have no effect on any other bindings attached using the DOM. Those bindings will stay installed. If new bindings are attached through CSS, they are installed after the DOM bindings in the inheritance chain.
For example, given a bound element with a binding chain of
d1 -> d2 -> d3 -> s1 -> s2 -> s3
with s1 representing the binding attached via CSS. If a resolution of style on the bound element determines that a new binding t should be attached, then the following binding chain is detached:
s1 -> s2 -> s3
and the new binding is attached. The final inheritance chain is:
d1 -> d2 -> d3 -> t
When bindings are detached using removeBinding
, any base bindings that were
attached through the extends
attribute on the binding will also be
removed. In other
words, a call to removeBinding
will remove the same group of bindings
that were installed via the original call to addBinding
.
The rule for detachment can be summarized as follows. Whenever a binding is detached, all bindings that it explicitly inherits from are also detached.
A binding attached through CSS cannot be removed using removeBinding
.
Whenever a binding is attached to an element in another document, the binding document is only fetched if no binding from the binding document has been used before in the bound document. A given bound document has a unique copy of each separate binding document that it uses.
All bindings from the same binding document URL that are used in a bound document will share the same binding document. Therefore if all the bindings in a chain come from binding documents that have already been loaded by the bound document, then the attachment of a binding (either through CSS or through the DOM) is guaranteed to be synchronous.
An author can ensure that all bindings are synchronously attached by calling loadBindingDocument
to pre-fetch any XBL documents that are required. If the binding document is
loaded prior to the firing of the load
event, then any binding attachments
that are placed following the load will be synchronous if they come from one of these previously
loaded binding documents.
The document obtained from loadBindingDocument
is a copy of the binding document that
is unique to the bound document. The bindings in the binding document can be modified using
standard DOM APIs. Any subsequent binding attachments that occur on elements in the bound
document for bindings in the binding document use the modified copy. Therefore new binding
definitions can be generated dynamically or the anonymous content templates for bindings
can be altered and used by the bound document.
DocumentXBL
interface contains methods for
loading and obtaining binding documents. The
interface is implemented by DOM documents that support XBL.
interface DocumentXBL { Document loadBindingDocument(in DOMString documentURL); readonly attribute NamedNodeMap bindingDocuments; };
bindingDocuments
bindingDocuments
property is a NamedNodeMap
of all binding documents loaded by the bound document. Documents
are referenced using their URLs.
loadBindingDocument
loadBindingDocument
method can be used to
synchronously obtain the specified binding document for use within
a particular document (the one on which the loadBindingDocument
method was invoked).
The binding document can then be modified
programmatically using the DOM. Any subsequent bindings that are
attached to elements within the document will be constructed from the
modified binding document.
documentURL
of type DOMString
Document
loadBindingDocument
is the binding
document used by the calling document to attach bindings that are defined
in the binding document.
ElementXBL
interface contains methods for
accessing anonymous content and for obtaining anonymous parents
in the altered model. The
interface is implemented by DOM elements that support XBL.
interface ElementXBL { readonly attribute NodeList xblChildNodes; readonly attribute Element bindingOwner; readonly attribute Element anonymousParent; void addBinding(in DOMString bindingURL); void removeBinding(in DOMString bindingURL); };
xblChildNodes
xblChildNodes
property is a NodeList that represents
the true children of the element after insertion points and element
tags have been applied. This property
can be used to navigate the content model according to XBL
after bindings have moved explicit and anonymous
children using element
and children
tags.
bindingOwner
bindingOwner
property is used to obtain the bound element
with the binding attached that is responsible
for the generation of the specified anonymous node. This property
enables an author to determine the scope of any content node.
When
content at the document-level scope
is passed in as an argument, the property's value is null
.
See section 4.1 for more information.
anonymousParent
anonymousParent
property's value is
the anonymous parent for an
element that was placed underneath an insertion point using the children
element in XBL or for a bound element that was repositioned using the element
tag.
When an element that was not repositioned is passed
in as an argument, the property's value is null
.
addBinding
addBinding
method attaches the specified binding (and
any bindings that the binding inherits from) to an
element. This call is not necessarily synchronous. The binding may not
be attached yet when the call completes. See section
2.2 for more information.
bindingURL
of type DOMString
removeBinding
removeBinding
method detaches the specified binding (and
any bindings that the binding inherits from explicitly using the
extends
attribute) from the
element. See section
2.4 for more information.
bindingURL
of type DOMString
A binding can specify an anonymous content template
using the content
element. This
template describes a content tree that will be generated
under the bound element during binding attachment. An element declared in a
bound document using a single tag can
then be constructed out of multiple child elements, and this implementation is
hidden from the bound document.
For example, the HTML file upload control appears in most browsers as a composite widget consisting of a text field and a button. A sample XBL binding for the file widget might look as follows:
<binding id="fileupload"> <content> <html:input type="text"/> <html:input type="button"/> </content> </binding>
Because this content is not visible to its parent element, it is said to be anonymous content.
content
element
are cloned. Elements and attributes in the XBL namespace are
never cloned. For content generated underneath the bound
element, the topmost nodes' parentNode
pointers are set to the bound
element. When anonymous content elements are built above the bound element,
the topmost elements' parentNode
pointers are set to the bound
element's parentNode
.
All anonymous nodes' ownerDocument
pointers are set to the
bound document at the time of generation.
In effect the anonymous content exists in its own insulated pocket within
the document. Using
parentNode
, anonymous content nodes can refer to their explicit parents,
but explicit parents have no knowledge of their anonymous children. The anonymous
content is not accessible via the childNodes
list for the bound element,
nor is it accessible using firstChild
/nextSibling
to iterate over the children of the bound element.
Anonymous content introduces the concept of scope to nodes within a document. Because anonymous content elements can also have bindings attached that generate their own anonymous content, this scoping can be taken to an arbitrary level of nesting.
Explicit content is said to be at the document-level scope. Anonymous content nodes are in their own binding-level scopes. Binding scopes are determined by the bound element that contains the binding responsible for the generation of the anonymous nodes.
The scope of an element can be determined using the getBindingParent
method on the DocumentXBL
interface.
See section 3 for
more information. This method returns the bound element in the enclosing scope that
is responsible for the anonymous node. If invoked on an element at the document-level
scope, it returns null
.
DOM methods that can be invoked on elements (e.g., getElementsByTagName
)
will only see nodes that
are in the same scope. Methods invoked on the document (e.g., getElementById
)
only see nodes that are at the document-level scope.
Whenever bindings are attached to an element, anonymous content will potentially be generated or destroyed. When a new binding is attached, the bindings in its explicit chain are checked to see if any have anonymous content templates. The most derived binding in the chain with a template is the one used to determine if anonymous content should be generated.
Anonymous content is only generated from a template if there are insertion points defined within the template for all the explicit content found underneath the bound element at the time the check for generation is made. If the binding specifies no insertion points for explicit content, then anonymous content will only be constructed if the bound element has no explicit children.
Assuming that all explicit children have valid insertion points, the anonymous content is generated underneath the bound element. The binding responsible for the generation is referred to as the primary generating binding. Whenever the primary generating binding changes on a bound element, all anonymous nodes in the scope of the bound element are destroyed.
Whenever content is built from a binding's template, a contentgenerated
event
fires. A binding can specify a contentgenerated
handler that contains script
to be executed after the binding has generated content.
Content generation handlers fire whenever the primary generating binding changes and it is determined that the binding should generate content under the bound element. The handlers for a binding chain always fire from the base binding down to the most derived binding. No handlers fire until the content from all bindings in the chain has been generated.
Whenever the primary generating binding changes (either to another binding or to nothing at all),
and if anonymous content is already currently in place under the bound element, that content
is destroyed. Prior to the destruction of the content, a contentdestroyed
event is fired.
The handlers execute from the most derived binding up to the base binding in the chain. All handlers fire before any content is actually destroyed. At the time the handlers fire, the primary generating binding has not yet changed.
Attributes on anonymous content elements can be tied to attributes on the bound element. Whenever
the attribute is set or removed on the bound element, the corresponding attribute on the anonymous
content is also set or removed.
On any anonymous content element in a template, an inherits
attribute can be
used to specify a comma-separated list of attributes that should be inherited.
Attributes with namespaces can be defined using a namespace prefix and the
attribute name separate by a colon.
For example, on the HTML file upload control, the anonymous textfield can be set up to automatically inherit
the value
attribute from the bound element.
<xbl:binding id="fileUploadControl"> <xbl:content> <html:input type="text" xbl:inherits="value"/> <html:input type="button" value="Browse..."/> </xbl:content> </xbl:binding>
Each entry in the inherits
list can either simply list an attribute (such as
value
in the example above), or it can specify an =-separated pair consisting
of the attribute on the anonymous content that should be tied to the attribute on the
bound element. The anonymous content attribute is listed first.
The special value xbl:text
can be used in an = separated pair,
where the prefix defined is the XBL namespace.
When specified
on the left-hand side of the pair it
indicates that the attribute on the right-hand side should
be stored as text nodes underneath the anonymous element.
When used on the right-hand side,
it indicates that any raw text nodes that are explicit children of the bound element should
be coalesced and the resulting value should be stored as the attribute on the left-hand side.
The xbl:text
value cannot occur by itself in the list. It may be used only
in an = separated pair.
Note that the inherits
attribute is never cloned
when content is generated from a template.
XBL
bindings can interleave anonymous content between bound elements
and their explicit children. They do so using XBL
children
tags and the XBL element
tag.
Any number of children
tags may be used in a binding's
anonymous content template. The location at which a
children
tag occurs is called an insertion
point.
There are two types of insertion points: explicit and inherited. Explicit insertion points specify locations at which the explicit children of a bound element are inserted. Explicit insertion points are only used if they are found on the primary generating binding. Explicit insertion points on other bindings are ignored.
Inherited insertion points are used to place the anonymous content generated by the next binding in the chain that contributes anonymous content. That binding can define inherited insertion points for its base binding as well. This pattern continues all the way up the binding chain.
XPath selectors
specified using the includes
attribute determine which insertion point a given
child should be placed under. If no attribute is specified, an insertion point is considered
generic and will match on all content.
The insertion point used for a given piece of content is the first encountered with a selector whose node set matches the element when doing a depth-first walk of the content template.
Any number of <element> tags may also be present. The <element> element represents an anonymous clone of the bound element. This exists so that anonymous content can conceptually decorate the bound element as well as fill it. It also bears an inherits attribute, with a default value of "*", to indicate attribute forwarding for the anonymous copy of the element.
Under no circumstances can the element generated in place of the <element> element itself be a bound element.
Note that element
and children
elements are never cloned
when content is generated from a template.
Similarly for any attributes in the XBL namespace, such as xbl:inherits
.
[Editor's Note: A possible extension to this is that if the insertion point is empty, then default content specified under the <children> element could be cloned and placed at the insertion point.]
Insertion points continue to be used as elements are inserted or removed from the DOM. Whenever an element is inserted or appended, all insertion points are checked following all the same rules that applied when first placing explicit children during anonymous content generation. If no insertion point is found for the newly-inserted child, then the binding is no longer a fit for the bound element, and all anonymous content will be destroyed.
Whenever an element is removed, it simply disappears from its insertion point along with all anonymous content that was generated by the element.
It is possible to manipulate the anonymous content contained underneath a bound element using standard DOM APIs. If anonymous content that contains an insertion point is removed, then any explicit children found underneath the insertion point are relocated to any other insertion points that match. Again, if all the children cannot be relocated, then the anonymous content is destroyed.
[Editor's Note: Should there be an API for retrieving insertion points, for dynamically creating new insertion points, or for removing insertion points? Perhaps on ElementXBL?]
Events flow through the final transformed content model after all elements have been repositioned
through the usage of children
and element
tags.
Whenever events flow from an anonymous element in a bound element's scope to the bound element
itself, one of two actions occurs.
Either the event is retargeted so that
the bound element becomes the target, or the event is stopped and flow proceeds to the next phase.
Whenever an event is
retargeted, the target
field of the event is set to the bound element. The
original anonymous content responsible for the event can be obtained from a new field of the event
object: originalTarget
.
The action taken (retarget vs. stop) is specific to the event type. In general, UI events are retargeted and mutation events are stopped. Exceptions to the rule are noted below.
When a focus or blur event crosses a scope boundary, the bound element is checked to see if it is focusable, i.e., if the user agent would normally fire a focus or blur event on the element. If the bound element is focusable, then the event is retargeted. If not, then the event is stopped. If anonymous content underneath a focusable bound element blurs and anonymous content also underneath the bound element takes focus, then the blur and focus events are both stopped. As far as the bound element is concerned, it retains focus throughout the two events.
Anonymous content can receive focus when the user tabs through the document. The same rules apply. If the anonymous content is focusable, it can be tabbed into, but if the bound element is not focusable, the event will be stopped before it reaches the bound element.
In HTML4 the tabindex
attribute can be used to specify the tab order for focusable elements.
This attribute can be specified on anonymous content. Each scope has a unique tab order. The
tabindex values used in one scope are ignored by other scopes.
As an example, consider the HTML file upload control. It is a focusable element that in turn is made up of two focusable anonymous elements: a textfield and a button. Tab indices can be specified on the textfield and the button to dictate the order in which the components of the file control should be accessed when tabbing.
When the user tabs such that the file control should become focused, the user agent determines if any anonymous content should also become focused, using the tab order specified by the anonymous content elements. It then generates a focus event on the textfield inside the file control. As this event flows across scopes, it is retargeted to be a focus event on the file control itself.
Focus events should also be stopped if the bound element is already focused. For example, if the user has already focused the textfield within an HTML file upload control, then the file upload control is now also focused. If the user then focuses the button inside the file upload control, the focus event generated for the button is stopped before it reaches the file control, since the file control is already focused.
Because content in multiple scopes can be focused, the CSS :focus
pseudo-element
is hierarchical. Style rules can be written with the assumption that they will match
(in the above example) both the file control and the element focused inside the file
control. In other words, an arbitrary chain of elements can be in the :focus
state at the same time.
Mouseover and mouseout events are retargeted if the mouse genuinely enters or exits the bound element (in addition to entering or exiting some anonymous content). If, however, the user has simply moved the mouse from one anonymous element to another, without entering or exiting the bound element itself, then the event is stopped.
For example, if the user enters the HTML file upload control from the left, a mouseover event is generated for the anonymous textfield. Because this event also constitutes a mouseover of the file control itself, the event is retargeted when it flows across scopes. If the user then moves the mouse from the textfield to the button, a mouseout is generated for the textfield, followed by a mouseover of the button.
Since neither of these events constitutes a mouseover or mouseout of the file control itself, the events are not allowed to flow to the file control. If the user continues moving to the right and leaves the button, then the mouseout generated will be retargeted, since the file control will also have been exited.
Bindings can interleave anonymous elements between the bound element and its
explicit children. See 4.4. Insertion Points for more
information. In this situation, a new tree emerges that is different from
the explicit content node tree. In addition to having a single explicit parent (the bound element)
the explicit children also have an arbitrary set of anonymous parents (created by bindings when
child insertion points or element
tags were used).
Child, descendant and sibling selectors will match on any path of
anonymous and explicit elements.
As far as CSS is concerned, anonymous content nodes are children (or descendants) of the bound element, they are ancestors of explicit content, and they are siblings of the explicit content. Style rules using the child, descendant or sibling selectors transparently cross binding scopes and operate on the altered and original content models.
The final modified content tree determines how CSS properties (e.g., fonts and colors) are inherited. An element either ends up underneath its explicit parent (just as in the content model), or it ends up being nested through a series of insertion points. When nested, it inherits from the innermost anonymous parent.
A binding file can load stylesheets using the stylesheet
element.
By default these stylesheets apply to the bound element and to all anonymous content generated
by all bindings attached to the bound element. These sheets
have the same origin as the sheet with the rule responsible for the
binding. Stylesheets loaded by bindings that are attached using the DOM are
treated as author-level sheets.
[Editor's Note: Binding inheritance complicates this cascade, since an author-level DOM binding could inherit from a user-level binding. If both load sheets, what level do those sheets belong to in the cascade?]
Sheets are always walked from the innermost scope to the outermost scope. With this ordering a binding that defines a widget can define a default look for the widget that can then be easily overridden by a client of the widget. For multiple bindings attached to the same element, the sheets are walked from the base binding down to the most derived binding.
Bindings can fine-tune the control of the stylesheet scoping with two attributes. The first,
applyauthorsheets
, indicates whether or not author sheets defined at outer scopes
affect the anonymous content generated by the binding. For the primary generating binding only,
this attribute is checked to see if any author sheets at outer levels of scoping should be
applied to the anonymous content generated by the bindings attached to the bound element.
If this attribute is set, the rules specified in any author sheets at outer scopes are not
walked.
By default, stylesheets specified in bindings files are applied only to the bound element and
to anonymous content generated by bindings attached to the element. A second attribute,
applybindingsheets
can be used to indicate that all children of the bound element,
both anonymous and explicit, can be styled by the sheets in the binding's document.
This can be controlled on a per-insertion-point basis.
User agent sheets and user sheets are always applied to all scopes.
Bindings can define methods and properties on a bound element using the implementation
tag. A binding implementation provides a new set of methods and properties that can be invoked
directly from the bound element.
The methods and properties of an implementation can be defined declaratively using method
and property
tags in XML.
Methods are defined using the method
element. The name given on the tag using
the name
attribute is the name that can be used to invoke the method on the element.
A method
with parameters specifies those parameters and their names with
parameter
elements declared underneath the method
element.
The implementation of the method is contained inside a body
element. The parameters
specified are bound to their names in the method body.
<method name="scrollToIndex"> <parameter name="index"/> <body> <![CDATA[ if (index < 0) return; ... ]]> </body> </method>
Properties can also be defined on the bound element using property
tags. There
are two basic types of properties. The first type of property is a raw value that is set
directly on the element itself. The second type of property is one that defines functions
that are invoked when the property is either retrieved or set. These functions are
called getters and setters in XBL.
For properties with raw values, an initial value can be specified as a child of the
property
tag. The script is evaluated at the time of binding attachment and
the resulting value is stored on the element. It can be assumed that the anonymous content
of the binding has been fully constructed, although the bindingattached
event
will not have fired. Property initialization always takes place after content generation
but before the firing of a binding attachment event, since the bindingattached
handler needs to be able to assume that all properties will be accessible on the binding.
Properties with getters and setters can define them using onget
and
onset
attributes, or using the more verbose getter
and setter
elements. If both the attribute form and the element form are used to specify a getter or setter,
then the element form is ignored.
A getter contains script whose return value is handed back when the property is requested. A
setter contains a script that is invoked when a new value is assigned to the property. In
script, the word val
is used to represent the new value. A setter should also
return val
as a result in order to allow for chained assignment (e.g.,
a = this.b = c;
) operations to succeed.
Properties can be designated as constant using the readonly
attribute. When
set to true
, the property's value cannot be altered. If a property is
readonly and a setter is defined, then the setter is ignored.
Properties also support a shorthand syntax for defining getters and setters that forward
requests or assignments to an anonymous content element. The element
attribute specifies the ID of anonymous content underneath the bound element that should
be used when obtained the property or setting the property.
On the anonymous content element, the property can be obtained either from an attribute
on the element or from a property on the element.
The property
attribute's value specifies the name of a property to use
on the anonymous content element. The attribute
attribute specifies the name
of an attribute to use on the anonymous content element. If either of these attributes
is specified on the property
element, then any defined getters and setters
are ignored. A raw initial value is also ignored. If both a property and attribute are
specified, then the property takes precedence and the attribute is ignored.
When two bindings in an inheritance chain both supply implementations, the derived binding's implementation inherits from the base binding's implementation. Method and property lookups are dynamic. Without disambiguating, if two bindings define the same method or property, then the most derived binding's method or property will be used.
Because bindings extend DOM elements, they can override any built-in methods or properties
on the DOM element. For example, a binding could override the setAttribute
method on Element
or the retrieval of the value
property for
an HTMLInputElement
.
Implementations can be named using a name
attribute specified on the
implementation
element. When an implementation has a name, that name can
be used to disambiguate the desired method or property.
[Editor's Note: The following paragraphs suggest a syntax for how JavaScript might enable access to base class methods and properties. This is an open issue. Should we attempt to define a language-independent abstraction, or specify that it must be possible to access base bindings' methods and properties?]
For example, given a binding with an implementation ColorPickerGrid
that derives from an implementation ColorPicker
where the two implementations
both specify the setColor
method, a caller could invoke ColorPicker
's
method with the following syntax:
... // myElement is a ColorPickerGrid myElement.ColorPicker.setColor(); // Calls the ColorPicker method. myElement.setColor(); // Calls the ColorPickerGrid method. ...
In addition to being able to specifically name a base class, the name baseBinding
can be used to specify the method or property on the base binding without necessarily knowing
what the base class is. This situation can occur when bindings implicitly inherit, e.g., through
the use of addBinding
.
myElement.baseBinding.setColor(); // Calls the ColorPicker method.
Event handlers are defined using handler
elements. A handler specifies what
event it is listening for using the event
attribute. The handler contains
script that is executed when an event flows to the object the handler is attached to
and if that event matches all of the criteria specified by
the handler.
The most basic handler specifies the event to listen for and an action to take when
the handler fires. This action can be specified either using an action
attribute
or by specifying the script as a child of the handler
element. If both are
specified, the attribute wins.
By default handlers are attached to the bound element, and they are registered as bubbling events. This means that
<handler event="click" action="foo()"/>is analagous to
onclick="foo()"
defined on the bound element.
Event handlers can be attached to the window, the bound sdocument, or to
the bound element using the attachto
attribute. Bindings can use this
attribute to register handlers that listen for
events like load
on the bound document. The value of the attribute is
window
, document
or element
.
The phase
attribute specifies the phase of event flow that the handler
is registered for. The default value is bubbling
, which means that the
event handler will fire during the bubbling phase. The other possible values are
target
, which means the handler will only fire if event.target
is the same as the target to which the handler is attached, and capturing
,
which indicates the handler should fire during the capturing phase of event flow.
XBL event handlers always fire last, after all other event handlers at the same position in the event flow. Since XBL handlers usually constitute the default actions for a widget, this allows authors in the bound document to write events that potentially suppress the default actions taken by the XBL handlers.
Within an XBL inheritance chain, event handlers always fire first on the derived binding and then on the base binding in the chain. A derived handler then has a way of preventing the event from flowing to its base binding handlers.
Mouse and key handlers have certain additional properties that are supported by XBL. Additional attributes can be used to impose a filter on the event handler. When a filter is imposed, additional conditions must be met before the event handler will fire.
For both mouse and key events, modifier keys can be specified using the
modifiers
attribute. This attribute is a comma-separated list of
modifier keys that must be down at the time the key or mouse event occurs in order
for the handler to execute. Examples of common keys in the list are shift
and control
.
In addition, mouse events can specify the button
and the clickcount
.
This allows XBL authors to easily define handlers for right-click, or for left double-click,
without having to write script on the same handler to differentiate those cases.
Key events support the charcode
and keycode
attributes. When
set, the corresponding fields in the event
object must match for the event
to fire.
[Editor's Note: Should we have section on error-handling? Probably.]
[Warning this example is now slightly wrong since it applied to a previous version of XBL and some things that are used by it were changed.]
<html> <head> <style> body { background-color: black; color: white; font-size: 10pt; font-family: Verdana; } .board { binding: url(notes.xml#board); } </style> <title>Sticky Notes</title> <body> <h1>Demo - Sticky Notes</h1> The following demo uses XBL to create a widget that functions as a board for PostIt notes. In this example, we create a binding that enables the user to define a board and to supply notes that can be dragged around on the board. <div class="board" style="width: 600px; height: 600px;"> <div flex="1" class="note" style="left: 5; top: 5"> <div class="caption">Pre-Checkin Tests</div> <ul> <li>Compose and send mail. <li>Read and sort mail. <li>Bookmark a page. <li>Send an instant message. <p> <font face="Jokerman" size="+1"> The Ones In Charge </font> </p> </ul> </div> <div class="note" style="left: 250; top: 200;"> <div class="caption">Grocery Order</div> Apples, oranges, milk, orange juice, bread. <p> <i>Don't forget the eggs!</i> </p> <font face="Jokerman" size="+1">SWMBO</font> </div> </div> </body> </html>
<?xml version="1.0"?> <?xml-stylesheet href="notes.css"?> <bindings xmlns="http://www.mozilla.org/xbl" xmlns:html="http://www.w3.org/1999/xhtml"> <binding id="board" styleexplicitcontent="true"> <implementation> <property name="dragging"> null </property> <property name="currX"> 0 </property> <property name="currY"> 0 </property> </implementation> <handlers> <handler event="mousedown"> if (event.originalTarget.parentNode.className == 'caption') { this.dragging = event.originalTarget.parentNode.parentNode; this.currX = event.clientX; this.currY = event.clientY; } </handler> <handler event="mouseup"> this.dragging = null; </handler> <handler event="mousemove"> if (!this.dragging) return; deltaX = event.clientX - this.currX; deltaY = event.clientY - this.currY; leftV = parseInt(this.dragging.style.left); topV = parseInt(this.dragging.style.top); leftV += deltaX; topV += deltaY; if (leftV < 0) leftV = 0; if (topV < 0) topV = 0; if (leftV > 390) leftV = 390; if (topV > 390) topV = 390; this.dragging.style.left = leftV; this.dragging.style.top = topV; this.currX = event.clientX; this.currY = event.clientY; </handler> </handlers> </binding>
.board { background-color: #808080; position: relative; } .note { background-color : #FFFFCC; border : 1px outset #FFFFCC; color : #000000; font : smaller; padding : 3px; width: 200px; height: 200px; position: absolute; } .caption { cursor: pointer; font-weight: bold; background-color: #ccccaa; }
http://www.w3.org/TR/REC-CSS2/
)http://www.w3.org/TR/REC-xml
)http://www.w3.org/TR/REC-html40/
)http://www.w3.org/TR/NOTE-AS
)http://www.w3.org/TR/1999/WD-becss-19990804
)http://www.w3.org/TR/NOTE-HTMLComponents-19981023
)http://www.w3.org/TR/REC-DOM-Level-1/
)http://www.w3.org/TR/DOM-Level-2-Core/
)http://www.w3.org/TR/xpath.html
)