Tải bản đầy đủ (.pdf) (17 trang)

Tài liệu Creating Applications with Mozilla-Chapter 7. Extending the UI with XBL- P1 pptx

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (2.83 MB, 17 trang )

Chapter 7. Extending the UI with XBL- P1
You now know that XUL is the basic tool set for creating your application
interface, but even it has limitations. It is just a finite set of widgets that your
programming needs may transcend. If you find that you reimplement many
of the same groups of widgets in different applications, or if you want to
extend your application's interface in some other way, you will find the
eXtensible Binding Language (XBL) an invaluable tool.
This chapter describes what XBL is and how it is used. Basically, XBL
provides a way to attach new content or behavior to your application by
using XBL bindings. XBL can extend, add to, and reorganize user interfaces.
XBL can also help you organize scattered XUL code into a set of selfcontained widgets that make building and maintaining your Mozilla
application much easier. Appendix C provides a reference for the XBL
element set, with which new elements can be created.
7.1. What Is XBL?
XBL is an XML markup language invented specifically for creating widgets.
XBL looks similar to XUL, and may even contain XUL or HTML and other
markup (see the Section 7.1.3 section later in this chapter for more
information about how other markup is used in XBL bindings), but its
purpose is different. Flexibility and interoperability are the point of XBL.
If the XUL textbox is inadequate, for example, you can use XBL to create
and attach a new widget called <datafield/>, possibly based on
textbox, that provides special attributes and functionality for validating
input data against a database.


A binding is a single XBL language entity that can contain content as other
markup (such as XUL) behavior that is represented as methods and
properties, and event-handling capabilities. Bindings can be anything from
small widget objects to large, complex blocks of code with extensive
functionality. Figure 7-1 shows the different components that make up a
binding: fields, properties, functions, event handlers, and content. The


section Section 7.2, later in this chapter, provides more detail about a
binding's structure.
Figure 7-1. Mozilla XBL binding structure

Bindings differ from XUL overlays because they are fully self-contained,
reusable, and generally have no dependencies outside of the binding itself.
Although XUL is used most often as content in an XBL binding, XBL can
also bind to and from HTML and XML. If you have worked with Java or
C#, you may recognize some parallels between XBL bindings and Java
objects.
7.1.1. XBL Terminology
The following terms are used to describe XBL and its use in the XPFE:
XBL


An acronym for the eXtensible Binding Language. In some contexts,
the term XBL refers to actual code (e.g., "the XBL in this example . . .
"). XBL is an XML syntax.
Binding
A single unit of the XBL language, one or more of which is contained
in a binding document. Most bindings are made up of content and
implementation, although each are mutually exclusive; if you add
event handlers to that list, each one can appear on its own in a
binding.
Binding document
An XBL file with an .xml extension that contains one or more
bindings.
Bound document
A XUL (or HTML) document that has one or more bindings attached
to it as content.

Bound element
A bound element is a widget or element that uses a particular binding.
It can be an existing element in the XUL or HTML set or a newly
invented one.
Anonymous content
Content (e.g., XUL elements) contained in a binding that is hidden
from the document object (DOM). Refer to the section Section 7.4,
later in this chapter, for a more detailed discussion of its


characteristics and how to programmatically gain access to the
content.
Attachment and detachment
Attachment is the process through which a binding is associated with
a bound element. It is essentially a way of telling the element which
binding to use. Detachment is the process of removing that link and
with it, the binding display.
Insertion point
The point in anonymous content at which children of the bound
element are inserted. The section Section 7.4.4, later in this chapter,
details the insertion process.
Inheritance
During inheritance, characteristics of one object are passed on to
another object. In XBL, this process is multifaceted. Bindings can
inherit from other bindings, anonymous content can inherit attributes
from the bound element, and a binding implementation can inherit the
behavior of another widget. All concepts are explained in the section
Section 7.5, later in this chapter.
7.1.2. An XBL Document
XBL documents are files saved with an .xml filename extension. Most

bindings implement XUL content and behavior with script, so XBL files
reside in your XUL application's chrome content area and have full access to
XPConnect-wrapped XPCOM objects.


Several bindings often reside inside the same XBL file. Performance
benefits from this arrangement, if you have multiple related bindings,
because only one XBL document needs to be loaded, rather than multiple
documents. Organization is another factor. Mozilla has dozens of bindings
that are interrelated by either inheritance or filename identifiers. Individual
pieces to a menu widget reside in a file called menu.xml, button bindings
are in button.xml, and so forth. Keeping these bindings together is wise.
The XBL document's root container is the <bindings> tag. Inside this
element is one or more individual child bindings, defined by the
<binding> tag. A simple XBL document is as follows:
<?xml version="1.0"?>
<bindings id="dataBindings" ...>
<binding />
<binding />
</bindings>
An XBL document is a valid XML document. The XML preamble you are
used to seeing in XUL files is present. It also contains the single root
element (in this case, <bindings>) and the child nodes that define the
bindings (empty).
Bindings are the atomic units of an XBL document. An XBL document may
define any number of individual bindings, each of which is bound (i.e.,
associated with other XML/XUL elements by way of CSS class definitions)
somewhere in the interface. In other words, an XBL document may be a set
of unrelated or barely related bindings that are picked up by the XUL
interface.



7.1.3. Namespaces and XBL
Because XBL is a binding language for other markup, remember to
distinguish between the XBL markup (such as <binding> and
<handler>) and markup from another language (such as XUL).
Namespaces are a feature of the XML language that was invented to handle
this separation of intermingled markup, and XBL uses namespaces. For
more information on namespaces, refer to the W3C at
/>Namespaces are declared in the root element of an XML document. The
most common implementation is the declaration of two namespaces: a
default namespace for XBL and a namespace for the other markup. This
code shows the root of a bindings document in which the XUL namespace
declaration (xmlns:xul) and the XBL default namespace are declared:
xmlns= />xmlns:xul=

/>s.only.xul>
An NCName is the part of a namespace declaration that qualifies the markup
type for that particular namespace. It is placed after a colon, and in many
XPFE documents, is the markup language name (xul, xbl, or rdf). The
XBL namespace is the default in this instance because it does not declare a
namespace prefix (NCName).


You can choose to namespace your document in a different way. For
example, if you have a large mass of XUL code in your binding and do not
wish to use the xul: prefix repeatedly, you can declare the XBL namespace
as xmlns:xbl; you won't need to use prefixes on the XUL content since it
is set as the default. Another option is to namespace a parent element:

xmlns=" />there.is.only.xul">
This code enables all children inside the <box> to be in the scope of the
XUL namespace; therefore the explicit xul: tag prefix declaration is not
necessary.
7.1.4. XBL and HTML
Although XUL usually makes up the content of an XBL binding in Mozilla,
HTML is another valid and popular binding format. Using the XBL with
HTML combination can be advantageous. With it, web pages (rendered in
Mozilla) can be more feature-rich and move beyond the limitations of the
HTML specification's finite element set. It means a possible mingling of one
or many markup languages, including HTML, XUL, and RDF.
The following snippet, in which a simple binding defines the name of the
browser in an HTML div, gives you a feel for its potential:
<binding id="browser">
<content>
<html:div>Mozilla 1.0</html:div>
<children />


</content>
</binding>
The bound element in HTML is called browser_name and is attached to
the anonymous content in the HTML document's inline style.
<head>
<title>Browser Information</title>
<style>
browser_name

{


-moz-binding: url("brand.xml#browser");
}
</style>
</head>
<body>

Guide


...
Although the element is not a valid HTML element,
one of XBL's great capabilities is that Mozilla finds the binding, reads the
content there, and makes the substitution. The browser name can be included
in several places in the HTML document. Like a poor man's DTD, the
binding lets you change the definition of browser_name in one place and
propagate that change to every instance of its use. This feature is useful
because it requires the touching of fewer files during code maintenance.
7.2. Anatomy of a Binding


The best way to understand a binding is to watch one evolve from start to
finish. This section examines a binding from its inception, into the
construction of the binding, and through its use in a XUL document. At the
end of the section, you should be able to take the pieces and construct your
own binding, so try to follow it like a step-by-step guide.
Design is important in XBL. The implementation can sometimes be tricky;
for example, when you intend to reuse the binding elsewhere or when others
use it in a way you don't foresee. Ideally, a binding should be as small as
possible to facilitate reuse. And it's a good idea to separate your binding into
smaller pieces -- perhaps smaller "subbindings" -- so you can recombine
when necessary. You could design the <datafield/> widget mentioned
in the introduction -- for example, as a combination of the XUL

<textfield/> widget and your own new binding, <validator/>,
which you could then use elsewhere.
The widget constructed in this section is a good example of a small, reusable
binding. It is a special text input widget called inputfield -- a selfcontained extension to a XUL textbox that can be used on its own or as part
of another binding. The binding combines a <label> and a <textbox>,
allows child elements, and offers functions that work with the data and style
of the <textbox>.
7.2.1. CSS Attachment
Attachment is the process through which the binding is connected to the
bound document that uses it. This process is most commonly achieved
through CSS, but can also be done by using the DOM. The section Section
7.4, later in this chapter, details the interaction between XBL and the


document object model. The CSS connection begins where the bound
element is placed in the XUL file:
<inputfield/>
Remember that XML ignores elements it doesn't recognize, so this new
element won't be rendered until you add information to the stylesheet; a
binding is attached with the special -moz-binding attribute. The style
selector must be associated with the bound element in the XUL file. In the
following example, the binding is attached to every <inputfield> tag
because the element name itself is used as the style selector. However, moz-binding can also be inside a class selector, an ID selector, or any
other CSS selector you wish to use:
inputfield {
-moz-binding: url("inputfield.xml#inputfield");
}
It also can be from an inline style:
id="ifd"

style="-moz-binding:
url("inputfield.xml#inputfield")"/>
The constituent parts of this style rule are the -moz-binding property,
the url binding locator that takes the bindings file (and possibly the path to
it) as a parameter, and the id of the binding denoted with the # notation. For
the binding to take, the XBL file must contain a binding with the same id.
<binding id="inputfield">


<!-- binding content / behavior / handlers -->
</binding>
The ID of inputfield matches the value specified in the URL after the #
symbol. When the UI is drawn in Mozilla, the binding content, behavior, and
handlers are applied to the bound document at the point where the
<inputfield> element appears in the document. Figure 7-2 shows a
visual representation of the constituent parts of a binding attachment
occurring via CSS.
Figure 7-2. CSS binding attachment components


In this example, we use our own new element name called
<inputfield>, but you can also extend existing XUL widgets by
including:
<box id="inputfield" flex="1"/>
Because they are bound through CSS, bindings cannot be guaranteed to be
loaded until the whole document is loaded, which means that any inline
scripts accessing bindings should be considered incorrect because you
cannot guarantee that the binding is loaded.
XBL content is considered "invisible" in the context of the document object
because it is not contained directly in the XUL document. Refer to the later

section Section 7.4 for more information on this concept.
Because a document binding can have multiple instances, something
must happen to make the content unique in each one. When a binding is
attached to a document, its content is automatically cloned in memory.
Every instance of a binding shares the same fields, properties, methods,
and event handlers because separate copies of those are simply not
necessary. These elements cannot be changed dynamically, but the
content document model can.
7.2.2. The XBL Content Element
The <binding> element requires an id attribute to make the binding
unique within the entire document. In the general XML specification, there
can only be one element in a document that has a certain ID string. As in
XUL, if you use an ID twice, the last one parsed is the only one seen. This


situation can lead to unexpected behavior. Figure 7-3 shows the appearance
of an inputfield binding.
Figure 7-3. The inputfield alone in the XUL document

An <inputfield> has a <label> attached to it, shown here as "Input
Field." It also has a regular <textbox>. The "Eric's" label is not part of the
binding, but is still displayed inside of it as a child. Child content is
discussed later in the section "Extra Binding Content and Insertion Points."
The binding content is defined as:
<content>
<children/>
<xul:label xbl:inherits="value=label"/>
<xul:textbox anonid="input" flex="1"/>
</content>
<children/>, the first element in the binding, lets any elements that

existed in the original XUL document pass through the binding's display if it
exists inside the <inputfield> tag.
<inputfield id="ifd" label="Input Field">
<label value="Eric's"/>
</inputfield>


In this case, the XUL label is inserted into the anonymous content at the
point of the <children/> element when the binding is rendered. This
ability is useful for changing the ordering of content and adding extra
content within a binding.
You can limit which tags are displayed as child content by using
something like:
<children includes="treehead|treechildren"/>
These filtering capabilities open the possibility of multiple
<children/> in your binding.
The next content element is <xul:label/>. Notice how the XML
namespace of xul is used in the content. Using this notation is the most
common way to apply namespace XUL elements in bindings.
The label element has an XBL-namespaced inherits attribute. This
code translates an attribute used on the original bounded tag into something
usable by a content element:
<inputfield id="ifd" label="Input Field">
The final element in the content is a typical XUL textbox that has a
namespace like the label. The anonid attribute on the textbox is fabricated
and used here to avoid bugs and scope issues with the id attribute in
content. The id attribute should be used only on the <binding> and
<bindings> tags, but anonid works well as direct DOM access to this
element and is shown in the next section.
7.2.3. The Implementation Element



The next part of the binding, and also the most complex, is the behavior. The
<implementation> element contains the <constructor>,
<destructor>, <field>, , and <method> -- all of
which handle the binding's implementation features.
All elements can contain JavaScript, which changes the binding into a
dynamic widget that does more than display content on the screen. The
binding implementation accepts user input, dynamically changes the UI,
interacts with remote sites through web protocols, and surfaces Mozilla
library functions in widgets.
7.2.3.1. Constructor
In the example binding, some variables and style rules are set up for access
by the rest of the binding to make the code cleaner. These rules are set up by
using the constructor:
<constructor>
this.input=document.getAnonymousElementByAttribute
(this,"anonid","input");
// Initialize color and backgroundColor to
something besides a "" value

this.input.inputField.style.backgroundColor="white"
;
this.input.inputField.style.color="black";


this.input.inputField.setAttribute("onchange","");
]]></constructor>
The first JavaScript command accesses the <textbox> with the anonid

label and puts it into the this.input variable.
getAnonymousElementByAttribute is a custom DOM method used
to access anonymous content. The section Section 7.4.1, later in this chapter,
talks more about the XBL DOM methods.
The use of the this keyword and the "dot notation" comes from Java. If
you have programmed in Java, these bindings can be considered similar to
Java classes. They are self-contained and can be extended. Using this is
not necessary but it's common practice and clarifies that the variable or
property is a member of the binding, especially if you define elements in the
binding's constructor.
In the next two commands, an object called inputField contains the
style object property. You may be familiar with this structure in HTML
elements, and in fact, this inputField is a version of the HTML
<input> textbox. The <textbox> in XUL derives from that HTML
element.
The color and backgroundColor are set here manually to return
something other than the initial value of a blank string when they are
accessed. The last line in the <constructor> sets up the onchange
event handler for the textbox. This event handler is also used in a property
for this binding.
7.2.3.2. Destructor


This section of a binding executes anything that needs to be done
immediately before a binding is unloaded. Here is an example:
<destructor>
this.input=null;
</destructor>




×