XBL Task Force Issue: Unmatched children

This version:
Version 0.1: 2004/12/08
Previous versions:
none

Abstract

This document is a working document within the XBL task force which discusses one of the outstanding issues in depth: what happens with children of the bound element which are not explicitly referenced by <content> elements. In particular, are the unmatched children are they excluded from the fully flattened tree (i.e., included in xblChildNodes) or auto-included within the fully flattened tree. This document describes the issues, lists the various proposals under consideration, and discusses pros and cons for the various proposals relative to particular examples. The overall goal with the document is to help the XBL task force make decisions at a particular moment in time. Once the XBL task force has discussed and made decisions about the given issue, this document may become obsolete and may not get updated to reflect the decisions that were made.

Table of contents


1 Introduction

The latest draft of sXBL (22Nov2004) includes the following request for public feedback:

Request for public feedback

The task force is currently split on how to handle elements that don't match any content elements.

Proposal 1: If an explicit child of the bound element does not match any of the content elements (or if there are no content elements in the shadow tree), then that child does not appear in the rendering tree.

Proposal 2: If an explicit child of the bound element does not match any of the content elements (or if there are no content elements in the shadow tree), then it shall be inserted at an implied content element at the end of the shadow tree (as if there was a content node with no attributes as the last child of every template element). (This ensures that the fully flattened tree is always a superset of the original DOM tree. Nodes that authors do not want in the rendering can always be explicitly inserted into a container that is marked display:none.)

2 Background

2.1 How Mozilla XBL does it

The Mozilla XBL spec does not appear to define what happens with unmatched children. However, the implemented behavior is that Mozilla XBL uses a binding only if all children of the bound element can be matched.

Neither active proposal on this issue matches Mozilla XBL behavior.

The Mozilla XBL behavior, if chosen, would be a conflict with how the SVG language has been constructed because the inclusion on non-renderable elements such as animation elements, defs tags, description tags, title tags, metadata tags, and even comments within a custom element would suddenly makes bindings no longer work because the new node would not match with the binding. This would be surprising behavior because in most (all?) other scenarios non-renderable elements in SVG have no rendering side-effects depending on whether they are included or not and non-renderable elements are allowed to appear in almost any place within an SVG document. One particularly important issue is that insertion of an <svg:desc> element as a child of a bound element purely to add descriptive text for accessibility reasons might break an XBL binding if the Mozilla matching rules were in place. In all other scenarios, adding an <svg:desc> element anywhere in the document has no effect on the rendered result.

2.2 How RCC did it

The description of RCC's <refContent> element did not explicitly define how unmatched children were treated, but Adobe's implementation and general agreement within the SVGWG is that unmatched children are excluded from the fully flattened tree and do not get rendered.

Proposal 1: Unmatched children are not auto-included in the fully flattened tree matches RCC's behavior.

3 Proposals

3.1 Proposal 1: Unmatched children are not auto-included in the fully flattened tree

3.1.1 Proposal

If an explicit child of the bound element does not match any of the content elements (or if there are no content elements in the shadow tree), then that child does not appear in the fully flattened tree (i.e., xblChildNodes) and does not get rendered.

XBL is used to define the presentation and interactive behavior of custom elements. A content developer includes a specific instruction (usually an <xbl:import>) within his content to use a particular set of XBL components. These XBL components will have a well-defined behavior which the content developer will know before he decides to references those components. Sometimes the defined behavior of an XBL component will be to render the custom element and all of its children, but other times the XBL component might render only a subset or even perhaps none of the children.

Here is one scenario: a scrollable table widget. Suppose you have a web application which displays a long dataset in the form of a table and that only a subset of rows (e.g., three) appears at any time. Your custom element might look like this:

<xbl:definition element="MyNS:ScrollingTable">
  <xbl:template>
    <table border="2">
      <content includes=""/>
      <content includes=""/>
      <content includes=""/>
    </table>
    <xforms:trigger><label>Scroll up</label></xforms:trigger>
    <xforms:trigger><label>Scroll down</label></xforms:trigger>
  </xbl:template>
  <xbl:handlerGroup>
    <!-- includes logic to handle bind events and user interface events -->
  </xbl:handlerGroup>
</xbl:definition>

And the bound document might look like this:

<MyNS:ScrollingTable">
  <tr><td>Region A1</td><td>33.000</td><td>22.55</td></tr>
  <tr><td>Region A2</td><td>23.000</td><td>47.65</td></tr>
  <tr><td>Region B1</td><td>31.000</td><td>24.21</td></tr>
  <tr><td>Region B2</td><td>35.000</td><td>83.65</td></tr>
  <tr><td>Region B3</td><td>43.000</td><td>19.43</td></tr>
  <tr><td>Region C1</td><td>53.000</td><td>95.64</td></tr>
  <tr><td>Region C1</td><td>18.000</td><td>36.44</td></tr>
  <tr><td>Region D1</td><td>38.000</td><td>22.55</td></tr>
  <tr><td>Region D2</td><td>22.000</td><td>57.43</td></tr>
</MyNS:ScrollingTable">

The component's event handlers would change the value of the 'includes' attribute as the end user activates the scroll buttons (the <xforms:trigger> elements) so that the 'includes' attributes would point to a different set of three <tr> elements.

The example above only shows 9 rows, but suppose the dataset instead consists of 90,000 rows. In some scenarios, it is feasible to allocate space in the Core DOM for such a large dataset, but allocating all of the extra internal memory within the user agent to support a 90,000 row table might exceed the capacity of many end user machines or result in horrible performance. The "trick" of creating a smaller size table only as large as the current view is a standard technique for achieving good user interface performance in scenarios with large datasets.

This example is trivial to implement if unmatched children do not get included in the fully flattened tree. However, if unmatched children are auto-placed at the end due to an implicit <content> element which matches all unmatched children, then all kinds of problems emerge, including memory explosion and incorrect content models (the <tr> elements would not be contained within a proper <table> ancestor).

Another usage scenario is when the XBL component delivers some sort of switching behavior between alternative element. For example, suppose the custom element is allowed to look like this:

<myNS:SkinnableWidget>
  <myNS:DropShadowSkin state="normal">...</myNS:DropShadowSkin>
  <myNS:DropShadowSkin state="hover">...</myNS:DropShadowSkin>
  <myNS:DropShadowSkin state="mousedown">...</myNS:DropShadowSkin>
  <myNS:BackgroundSkin state="normal">...</myNS:BackgroundSkin>
  <myNS:BackgroundSkin state="hover">...</myNS:BackgroundSkin>
  <myNS:BackgroundSkin state="mousedown">...</myNS:BackgroundSkin>
</myNS:SkinnableWidget>

The xblShadowTree might contain the following:

<xbl:shadowTree>
  <xbl:content includes="...ordinal reference to drop shadow skin..." />
  <xbl:content includes="...ordinal reference to background skin..." />
</xbl:shadowTree>

The component would respond to events and change the value of the 'includes' attribute based on the current interaction state for the given widget. This example is natural and easy to implement if unmatched children are ignored and more difficult and unnatural if you have to add an explicit "catch-all" <xbl:content> element at the end of component definition which is wrapped by a container with "display:none".

A third example shows that some XML grammars will just plain break in the presence of XBL if unmatched child elements are not ignored and instead auto-appended to the end of the flattened tree. The problem is that some XML grammars might not be able to handle any "garbage elements" in the rendering tree and sometimes exact positioning in the tree can be very important (MathML is like that). In some renderers there is no generic way to turn elements off, thus there is no reliable way to eliminate the content from affecting the rendering (SVG subgrammars from filters and gradients are like that). Thus it is important to have a _generic_ way _not_ to pass some elements in the flattened (rendering) tree. Here is an SVG example:

<MyNS:CustomGradient>
  <MyNS:Param>55</MyNS:Param>
</MyNS:CustomGradient>

SVG allows custom gradients using sXBL where the shadow tree contains a sequence of <stop> elements which are used to define the gradient. With the non-auto-include proposal, everything is fine. However, with the auto-include-at-end proposal, suddenly the SVG user agent encounters a <MyNS:Param> at the end of the gradient definition, which is an error because only <stop> elements are allowed. (And gradients do not offer a facility like <defs> for elements that can be ignored.) This is an SVG example, but it can be expected that the same sort of problem will be encountered in other XML grammars.

3.1.2 Arguments in favor

Arguments in favor of this proposal:

3.1.3 Arguments against

Arguments against:

3.2 Proposal 2: Unmatched nodes are auto-included at end of shadow tree

3.2.1 Proposal

Nodes that match no insertion points should be inserted at the end of the shadow tree.

3.1.2 Arguments in favor

Arguments in favor of this proposal:

3.1.3 Arguments against

Arguments against:

4 Outside Feedback

Not yet assembled.