XUL:Template Features in 1.9
New Features of XUL Templates
This following lists the new features avialable when using new XUL templates. These features will be avilable in trunk builds (Mozilla 1.9) starting on February 14. These features will not be available in Firefox 2 or Mozilla 1.8. Note that these new features may change.
In order to support different query syntax for different datasources, the syntax for templates has been changed. The existing template syntax may also be used for backwards compatibility. That is, existing templates should still work as is.
There are three forms of the new syntax, two of them just being shorthands of the other one. The full form is as follows:
<someelement datasources="..." ref="..."> <template> <queryset> <query>...</query> <rule> <conditions>...</conditions> <bindings>...</bindings> <action>...</action> </rule> <rule>...</rule> </queryset> <queryset>...</queryset> </template> </someelement>
What used to go inside the <conditions> block now moves into the <query> block. This is a bit strange, and I may change this in the future. Effectively, the <content>, <triple> and <member> elements should be placed inside the <query> part.
The <queryset> may be used multiple times to have different queries, however many templates which used to have multiple rules, can usually get away with having multiple <rule> elements inside one <queryset>.
Confused yet? Essentially, a <queryset> consists of a single query of the datasource, and each rule consists of a filter that specifies conditions for the filter, optional bindings, and content to generate in the action body. For example, one filter might be for folders, while a second is used for non-folders.
If you use only one <queryset>, which will be most of the time, you can leave out the <queryset> tag and place it's children directly inside the <template>. This is the second form:
<someelement datasources="..." ref="..."> <template> <query>...</query> <rule> <conditions>...</conditions> <bindings>...</bindings> <action>...</action> </rule> <rule>...</rule> </template> </someelement>
And if you don't need more than one rule, you can promote the <action> directly inside the <template> as well. Here is an example of this third form:
<someelement datasources="..." ref="..."> <template> <query>...</query> <action>...</action> </template> </someelement>
Of course, all of the old syntax still works. So you can also use the simple syntax with or without rules as follows:
<someelement datasources="..." ref="..."> <template> <!-- contenttogenerate --> </template> </someelement>
The <conditions> block is now used to specify clauses for matching results. It allows a variety of comparison operators. Here is an example:
<vbox id="list" datasources="rdf:files" ref="file:///" flex="1"> <template> <query> <content uri="?uri"/> <member container="?uri" child="?child"/> <triple subject="?child" predicate="http://home.netscape.com/NC-rdf#Name" object="?name"/> </query> <rule> <conditions> <where subject="?name" rel="startswith" value="a"/> </conditions> <action> <button uri="?child" label="?name"/> </action> </rule> </template> </vbox>
The example above generates a button for each file that has a name that begins with the letter 'a'. The <where> element is used to specify conditional operators that must match in order to generate output. Naturally, you might want to use more than one rule. A result will only match the first rule with matching conditions. The <where> element above translates into a check to see whether the value of ?name startswith the value 'a'.
You can can place a variable in either the subject or value, or both. The following are all valid:
<where subject="?name" rel="startswith" value="Freddy"/> <where subject="Freddy" rel="startswith" value="?name"/> <where subject="?name" rel="startswith" value="?friend"/>
The following operators are valid as the value of the rel attribute:
- equals - compare subject and value for equality
- less - subject is less than value numerically
- greater - subject is greater than value numerically
- before - subject comes before value alphabetically
- after - subject comes after value alphabetically
- startswith - subject starts with the value
- endswith - subject ends with the value
- contains - subject contains the value as a substring
For less and greater, the values are compared by converting the subject and value to integers. That is, they don't have to be nsIRDFInts, the string "75" will be converted to the integer 75. If either value cannot be converted to a string, the condition evaluates as false.
Three boolean flags may also be used:
The negate flag may be used to match if the condition is false. That is, in the following example, match if ?name does not start with the letter 'a'.
<where subject="?name" rel="startswith" value="a" negate="true"/>
This is how you would do not equals, not less than, and so on.
The ignorecase flag may be used to ignore case when making string comparisons. The default is to do case sensitive comparisons. The following will match if, for example ?name was Fred or FRED
<where subject="?name" rel="equals" value="fred" ignorecase="true"/>
The multiple flag may be used for simple 'or' expressions:
<where subject="?name" rel="equals" value="fred,sarah,robert" multiple="true"/>
The example above will match if ?name is either fred, sarah or robert. Don't put any spaces between the commas.
You can, of course, use multiple <where> elements. All of them must match for content to be generated. If a <where> condition does not match, no content will be generated for that item and rule, although another rule may still match.
By default, a template will automatically recurse to generate child nodes. This can be disabled with a flag on the root node:
It can be used in conjuntion with trees using:
When used, the tree will only have one level, and child nodes will not appear.
Templates now mostly support queries that do not use RDF, although some work is still needed to connect them properly. This involves a custom component called a query processor which can retrieve results for non-RDF sources. Currently no other processors have been written but one can be written using a component with a contact id of the form:
where <key> is a unique string which can be referred to a template. The query processor implements the nsIXULTemplateQueryProcessor interface. To refer to a query processor, the syntax will be:
<box datasources="..." ref="..." querytype="rdf">
This would use the RDF processor, which is also the default.
Template Builder API Functionality
Some new template builder APIs of the nsIXULTemplateBuilder interface are available. This object can be retrieved using the builder property, the one that is commonly used to call rebuild. This may be used with chrome applications, although some of these may be available for non-priviledged applications in the future. To get a result that has been generated by the template:
var result = builder.getResultForId(id);
This method returns a result which implements nsIXULTemplateResult for a given id. This may be convenient instead of using the DOM or tree APIs to get information about a particular generated result.
Sorting of results may be done by using the sort and sortDirection attributes.
<listbox datasources="..." ref="..." sort="key" sortDirection="ascending"/>
The sort attribute is a key or keys to sort on. It may be a template variable like '?name'. For RDF queries using the simple syntax, it may be the full predicate prefixed with 'rdf:'. For example, 'rdf:http://home.netscape.com/NC-rdf#Name'.
Multiple sort keys may be used, seperated by spaces.
The sortDirection attribute should be set to 'ascending', 'descending' or 'natural'. This last value is the default and displays results in no particular order, although they will appear in Seq order for RDF datasources.
Trees also support sorting using a similar syntax, however the sort and sortDirection attributes should be placed on <treecol> elements instead. The sortActive attribute set to true indicates which column is actively sorted.
The XUL Sort Service may be used to sort a XUL element:
var xs = Components.classes["@mozilla.org/xul/xul-sort-service;1"]. getService(Components.interfaces.nsIXULSortService); xs.sort(element, "?name", "ascending");
where the arguments to the sort function are the element to sort, the sort key (or multiple keys separated by spaces), and the sort direction.
You may also sort non-template generated content using the sort function. In this case, the children of 'element' are sorted and the sort key is an attribute of those children to sort by.