Building Trees

The most common element to use with a template is the tree.

You can use a template with a tree just like any other template. However, since templates are often used with trees—especially with large amounts of data—the template system supports a special builder just for creating trees. Rather than generate content for every row in the tree, the results are stored in a list inside the builder. This means that DOM nodes are not constructed for any of the items. This is much more efficient; creating large numbers of DOM nodes adds a lot of overhead. The performance advantage is possible since trees only display text. As a result, the builder only has a few pieces of information to keep track of.

To use the tree builder, you need to add a flags attribute to the root node:

<tree datasources="template-guide-streets.rdf"
      ref="http://www.xulplanet.com/rdf/myneighbourhood"
      flags="dont-build-content">

The dont-build-content flag causes no content to be built for the template. But moreover, it uses a subtype of the main builder called the tree builder. Without this flag, the template will be handled by the content builder.

Note: While a tree builder can only be used with trees, a content builder can be used with any type of content. If you wish, you can also use the content builder for a tree. There may be situations that call for this, typically when handling smaller amounts of data. However, the content builder becomes slower as the amount of data increases.

Apart from the flags attribute, the template syntax for the tree builder and the content builder are identical. However, the tree builder requires a very specific form to the action body. Specifically, the action body should be a single treeitem with its rows and cells.

Here is an example (using an RDF source):

<tree id="photosList" flex="1" datasources="template-guide-photos5.rdf"
      ref="http://www.xulplanet.com/rdf/myphotos" flags="dont-build-content">
  <treecols>
    <treecol id="name" label="Name" flex="1"/>
    <treecol id="date" label="Date" flex="1"/>
  </treecols>
  <template>
    <treechildren>
      <treeitem uri="rdf:*">
        <treerow>
          <treecell label="rdf:http://purl.org/dc/elements/1.1/title"/>
          <treecell label="rdf:http://purl.org/dc/elements/1.1/date"/>
        </treerow>
      </treeitem>
    </treechildren>
  </template>
</tree>
Note: The tree columns (treecols) are declared outside the template as static content, since they only need to be declared once.

This template uses the simple rule syntax. The extended syntax could also be used. When using the tree builder, the uri attribute must be declared on the treeitem element.

Here, the simple RDF query syntax is used, so the member variable is rdf:*. The remaining tags have a similar syntax to a tree, but have only a single row. This row is used as the template data by the tree builder. Instead of generating content, the builder uses the cell attributes to determine what to display. The tree builder implements the nsITreeView interface, so it becomes the treeā€™s view—in other words, the treeā€™s view and the treeā€™s builder are the same object. When the tree is displayed, it asks the view for the contents of each cell. The builder looks at the label for the corresponding cell, translates any variables or predicates into values, and returns the value.

In the example above, the first cell should display the title. The builder doesnā€™t compute any labels until the view asks for them. When the view requests a label for the first cell, the builder looks up the ā€˜http://purl.org/dc/elements/1.1/titleā€™ predicate for the row in question and returns it.

The content builder generates content in the template body and substitutes data from the datasource right away. However, it will generate the same result on screen to the user as with the tree builder. Compare the example with a tree builder and the same example using a content builder.

Here is an example of a tree using an SQLite datasource:

<tree datasources="profile:messages.sqlite" ref="*"
      querytype="storage" flags="dont-build-content">
  <treecols>
    <treecol id="subject" label="Subject" flex="3"/>
    <treecol id="sender" label="Sender" flex="2"/>
    <treecol id="date" label="Date" flex="1"/>
  </treecols>
  <template>
    <query>
      select subject, sender, date from messages
    </query>
    <action>
      <treechildren>
        <treeitem uri="?">
          <treerow>
            <treecell label="?subject"/>
            <treecell label="?sender"/>
            <treecell label="?date"/>
          </treerow>
        </treeitem>
      </treechildren>
    </action>
  </template>
</tree>

Features of the Tree Builder

Besides the label of a cell, there are several other cell properties you can set when using the tree builder. The supported properties are: label, mode, properties, src and value. The label attribute is used to set the label for a cell. The mode is used for progress meter columns. It may be set to either ā€œnormalā€ for a normal progress meter or ā€œundeterminedā€ for an undetermined progress meter. The value attribute is used to set the current progress value for normal progress meters. The value attribute may also be used for checkbox columns by setting it to either true or false. Whether a cell is a normal labeled value, a progress meter or a checkbox is determined by the type attribute on the column the cell is in.

For cells in normal columns, you can use the value attribute to store some other value and you can use the viewā€™s getCellValue() method to retrieve it. Naturally, this will retrieve the value after any variables have been substituted.

Besides the attributes mentioned above, any other attributes specified on the tree rows and cells are ignored. Since no elements are generated, you wonā€™t be able to retrieve the values for them either. Thus, the value attribute may be useful to associate an additional value with a row since it will be easier to retrieve.

The src attribute may be used to set an image to appear in a cell. For example:

<tree id="photosList" flex="1" datasources="template-guide-photos5.rdf"
      ref="http://www.xulplanet.com/rdf/myphotos" flags="dont-build-content">
  <treecols>
    <treecol id="photo" label="Photo" flex="1"/>
  </treecols>
  <template>
    <treechildren>
      <treeitem uri="rdf:*">
        <treerow>
          <treecell src="rdf:*"/>
        </treerow>
      </treeitem>
    </treechildren>
  </template>
</tree>

This tree displays each photo in the tree cells. In this case, the member resource is used since that holds the photoā€™s URL. However, it could be any other variable, a static value, or a combination of both.

Image:Template-guide-p31.png

Of course, we canā€™t really see the photos, since the treeā€™s rows are too small! Itā€™s not normal to put photos in a tree like this—instead, the images would be used for icons. On the other hand, you could use a stylesheet to change the default height of the tree rows. You cannot make each row a different height, but you can change the height of all rows with some CSS:

treechildren::-moz-tree-row {
  height: 150px;
}

Since no elements are constructed by the tree builder, you cannot use the style or class attributes to change the style of a cell (This is the case with all trees). You must use syntax like that above to change the appearance. In the example above, it changes the height of a row to 150 pixels. You may want to change the syntax to refer to a specific treechildren element rather than all of them. Once the row height is changed, we can see the full photos.

Note: If you want to have the state of the disclosure triangles ("twisties") be persistent, be sure to give each node a unique "id" attribute. These are used to track the current state of the disclosure triangles. Support for this was introduced in Gecko 7.0 (Firefox 7.0 / Thunderbird 7.0 / SeaMonkey 2.4).

Using Tree Properties

Since we need to use special CSS for trees, the properties attribute on a cell becomes extremely useful. It can be used to define extra properties for reference later in a stylesheet.

For example, if the properties attribute was set to the value "?creator", you could style the photos created by different people differently. Alternatively, you could also use static values (in addition to variables) in the properties attribute. For instance, consider the following CSS:

treechildren::-moz-tree-cell(Dave) {
  background-color: lightgreen;
}

This would set the background color of a cell to green for any cell with the ā€œDaveā€ property. You can also use the properties attribute on the treerow to change the style for an entire row. This example sets the country associated with a photo as a property of a treeā€™s rows. We can use that property to change the appearance of each row.

<rule>
  <query>
    <content uri="?start"/>
    <member container="?start" child="?photo"/>
    <triple subject="?photo"
            predicate="http://www.xulplanet.com/rdf/country"
            object="?country"/>
    <triple subject="?country"
            predicate="http://purl.org/dc/elements/1.1/title"
            object="?countrytitle"/>
  </query>
  <action>
    <treechildren>
      <treeitem uri="?photo">
        <treerow properties="?countrytitle">
          <treecell src="?photo"/>
        </treerow>
      </treeitem>
    </treechildren>
  </action>
</rule>

You might use the following CSS to change the border around rows listing a particular country:

treechildren::-moz-tree-row(Netherlands) {
  border: green 1px solid;
}

The result of this example is a tree where one row has a green border around it.