document.loadBindingDocument'chrome://package/cont ent/myBindings.xml'; getBindingParentelement For use only within a binding, this method returns the bound element -- i.e., the top--lev
Trang 1Chapter 7 Extending the UI with XBL- P3
Although it is most commonly used just for getting and setting values on the property, nothing stops you from putting more code in the <properties> element that carries out other actions on the binding One scenario shown in Example 7-3 is if you have a property that holds a search value, you can send that text to the Google [1] API, and fill another widget in the UI with the results every time the value is updated [2]
Example 7-3 Performing a Google search when setting a property
<property name="searchString">
<setter>
<![CDATA[
var s = new SOAPCall( );
var q = val;
if (!s)
return "Error creating SOAPCall object";
var soapversion = 0;
var method = "doGoogleSearch";
var object = "urn:GoogleSearch";
var headers = [ ];
var params = [
new SOAPParameter(this.googleKey, "key"),
new SOAPParameter(q, "q"),
Trang 2new SOAPParameter(this.start, "start"),
new SOAPParameter(this.maxResults,
"maxResults"),
new SOAPParameter(this.filter, "filter"),
new SOAPParameter(this.restrict,
"restrict"),
new SOAPParameter(this.safeSearch,
"safeSearch"),
new SOAPParameter(this.lr, "lr"),
new SOAPParameter("utf8", "ie"),
new SOAPParameter("utf8", "oe")
];
s.encode(soapversion, method, object,
headers.length, headers,
params.length, params);
s.transportURI =
"http://api.google.com/search/beta2"
var response = s.invoke( );
if (response.fault)
return { msg : "SOAP call error", fault : response.fault };
// At this point you would pass the results back to the UI
Trang 3return response.message;
]]>
</setter>
</property>
The value of the search string is set to the value that has been given to the
property: var q = val This value is then added to the parameter list
(SOAPParameter) for the SOAP call, along with other parameters that are
obtained from other properties in the binding (e.g., this.maxResults)
Notes
[1] This example is modified code taken from
http://www.segment7.net/mozilla/GoogleAPI/GoogleAPI.html, and is covered by a three-clause BSD license More on SOAP and the SOAP API in Mozilla can be found at
http://lxr.mozilla.org/mozilla/source/extensions/xmlextras/docs/Soap_Scripts_in_Mozilla
[2] The Google API requires a Google Key, and more information can be found at
http://www.google.com/apis/
7.4 XBL and the DOM
This section introduces the DOM interfaces in XBL, illustrates how they
work, and explains the core concepts involved in XBL interaction with the
DOM, such as scope characteristics and insertion points
7.4.1 The XBL DOM Interfaces
XBL has two core DOM interfaces, DocumentXBL and ElementXBL
These extensions to the Document and Element interfaces are not part of the
Trang 4formal DOM specifications All methods can be accessed and used from JavaScript Here is a list of these interface methods
7.4.1.1 DocumentXBL methods
The DocumentXBL interface gains access to and interacts with an XBL
document The methods of this interface are as follows:
loadBindingDocument(URL)
XBL documents are loaded only the first time a bound document uses
a binding from it You can get around this problem and load the
binding documents synchronously by using this method It returns an XBL document for use within a bound document If your document is large and you need to optimize performance, this method may provide better performance
document.loadBindingDocument('chrome://package/cont ent/myBindings.xml');
getBindingParent(element)
For use only within a binding, this method returns the bound element
i.e., the top level node of the binding, when passed an element
within a binding
var listbox = document.getBindingParent(this);
var cellValue =
listbox.childNodes[3].firstChild.label;
getAnonymousNodes(element)
Trang 5Returns an array with the input binding's top-level content nodes Refer to the section Section 7.4.3, later in this chapter, for more
details
getAnonymousElementByAttribute(element, attribute, value)
Returns a single anonymous element when passed an element, an attribute from that element, and its value Refer to the section Section 7.4.3 for more details
7.4.1.2 ElementXBL methods
The ElementXBL interface adds and removes bindings from a bound
element The methods of this interface are as follows:
addBinding(element, URL)
Dynamically attaches a binding, given as a parameter, to an element Refer to the following sections for more details
removeBinding(element, URL)
Dynamically removes the given binding Refer to the following
sections for more details
7.4.1.3 Dynamically adding a binding
The section Section 7.2 covered the attachment of a binding to a bound element using CSS This technique is the most common method, but you can also attach bindings with the addBinding method
Using this method as an alternative to CSS attachment is useful when you do not want to attach a binding in all circumstances In an application based on user input, you may not want to load a binding until certain values are
entered For example, in a membership database, the information that
Trang 6appears on screen may depend on the user's level of membership The
following snippets show how it is used
<mybinding id="myNewWidget" class="attached" />
To load a binding, add these two lines in your script
var binding =
document.getElementById("myNewWidget");
document.addBinding(binding,
"chrome://mypackage/content/myBindings.xml#super");
Notice that the URL used to access the binding takes the same format as in the CSS property i.e., the path to the file and the id of the binding
qualified by #
Neither addBinding nor removeBinding are implemented at the time of writing They are covered because they are part of the XBL 1.0 specification When implemented, they offer crucial alternatives for attaching and detaching bindings, making XBL a more interactive
technology
7.4.1.4 Removing bindings
The best way to remove a binding attached via CSS is to change the style rule for that element You can change the class to one that does not have a different or null binding reference, for example Then a stylesheet can be set
up to provide binding references for both an attached and unattached
element
This example shows how to remove a reference to a binding by resetting it
to an empty reference:
Trang 7mybinding.attached {
-moz-binding : url("mybindings.xml#my-binding");
}
mybinding.unattached {
-moz-binding : url("");
}
When you want to detach the binding from an element, you can do this:
var mywidget = document.getElementById("binding1");
mywidget.setAttribute("class","unattached");
An element can have only one binding attached at a time, so this is a
programmatic trick for knocking the "real" binding out of its place with an empty one, rather than actually removing it
-moz-binding:url("") can be used at this time as a hack around the -moz-binding:none binding The later binding does not
currently work in Mozilla
The other method used to detach a binding, which is more intuitive from a DOM perspective, uses the removeBinding method:
var binding =
document.getElementById("myNewWidget");
document.removeBinding(binding,
"chrome://mypackage/content/myBindings.xml#super");
This method ensures that other style information is not lost if you have it attached to a particular class
Trang 8When a binding is removed, the anonymous content is destroyed and the methods, properties, and event handlers no longer apply
In the case of an inheritance chain (see the Section 7.5 section later in this chapter for more details), the bindings are destroyed from the bottom
upwards This means that if there is tear-down code in the form of a
destructor, it is executed last on the base binding
7.4.2 Binding Parents
Although a document cannot access the content of bindings attached to it, a binding can access the document it is attached to (bound document) This gives bindings the ability to provide more than just additional content to the document It also means that you can find information about the context of bound element in a document and provide information about it from within the binding
From the perspective of nodes inside the anonymous content, you can use DOM properties to find a higher-level node and then in turn use that to get to other nodes:
parentNode
This property is the bound element for the top-most element in the anonymous content This bound element resides in the document that the binding is attached to
ownerDocument
For all elements in the anonymous content, this is the document the bound element resides in
Trang 9While higher-level nodes can be accessed from anonymous content, parents do not have explicit access to their anonymous children using the DOM childNodes property Using firstChild or
nextSibling will also not work
Example 7-4 illustrates both properties in use
Example 7-4 Accessing a bound document from a binding
<binding id="my-binding">
<content>
<xul:vbox>
<xul:button label="A" id="button1"
oncommand="alert(this.parentNode.parentNode.nodeNam e)"/>
<xul:button label="B" id="button2"
oncommand="alert(this.ownerDocument.firstChild.node Name)"/>
</xul:vbox>
</content>
</binding>
Example 7-4 is a binding with two buttons, each of which brings up an alert when activated The alert simply shows the name of an element that is accessed in the code attached to the button In Button A, the parent node is
Trang 10the containing box One level further is the bound element, <mybinding> the parent node of the box parent The alert dialog raised by the alert shows "mybinding." Once a binding is applied, the binding's owner
(ownerDocument) is the bound document Assuming that Button B is a XUL window, the alert, when activated, shows "window." This property can
be used to access properties of the document object
7.4.3 Accessing Anonymous Nodes
Content bound to a document can introduce different levels of scope Some
of the scope is available at the document level, and some is at the binding level With content in different scopes, there are limits to which standard DOM methods can be used to access other elements and objects in and above a binding XBL contains some special methods to help work around some of the limitations caused by these barriers, such as not being able to change binding content dynamically or access certain property values
The two XBL-specific interfaces that exist on the document to get a handle
on this content are getAnonymousNodes and
getAnonymousElementByAttribute The advantage of using these interfaces
is that they provide a bridge between behavior and content Use them when you want to dynamically manipulate content or get a value for example, when accessing a particular textbox contained in binding, reminiscent of the one used earlier in the chapter when you were introduced to the
<inputfield /> binding
7.4.3.1 getAnonymousNodes
The method getAnonymousNodes(element) takes a node as a
parameter and returns a list of nodes that are in the anonymous content The
Trang 11following code uses script in the <getter> to access the anonymous node and return a value contained in it
<getter>
<![CDATA[
var list = document.getAnonymousNodes(this)[0];
return list.selectedItem.getAttribute('label');
]]>
</getter>
If we assume that this binding's content is a XUL menu list, then this code gets the label attribute of the menu item that is currently selected in that list (list.selectedItem) The list variable contains the value returned
by the getAnonymousNodes function, which is passed the binding node (this) The method returns an array, so the item is accessed via the first index of 0
7.4.3.2 getAnonymousElementByAttribute
The method getAnonymousElementByAttribute(element, attr, value) returns a single anonymous node rather than a list This node is qualified by an element name, a particular attribute, and the value of that attribute, and returns this specific node This retrieval provides faster access to anonymous content elements when you know an attribute's value
<property name="emailID" onget="return
document.getAnonymousElementByAttribute(this, 'id', 'emailAddressNode');" readonly="true"/>
Trang 12This example uses an id attribute to retrieve a specific node You can use this method when multiple elements of the same type exist and you need to get access to a particular one for example, a particular field on a database entry submission form like an email address or a telephone number
Although these two functions (getAnonymousNodes and
getAnonymousElementsByAttribute) were probably designed to
be used within a binding scope, they can be used both inside and outside a binding to access anonymous content Bindings are meant to be
self-contained, and getting anonymous nodes outside a binding breaks this philosophy However, these functions can act as a bridge between scopes if you are careful