XBL:Dynamically Applied Shadow Trees
One of the concerns I have with the current XBL2 specification is the way the (cloned) shadow tree is constructed and reconstructed. Instead of having a single shadow tree that is constructed from all the attached bindings, and reconstructed when a binding is attached or removed, I believe that there should be a cloned shadow content subtree for each binding which is then combined dynamically at runtime by the implementation.
There are a couple of motivating factors for this change:
- The current teardown and rebuilding of the shadow tree whenever a binding is attached or detached means that bindings which modify the shadow tree using script would need to repeat such actions every time the teardown/rebuild process completes. This case may not be uncommon in cases where a language (such as XUL) is implemented with XBL, and author bindings are also used. How would a binding such as the 2dchart binding know when to rebuild its shadow content if external activities such as attaching derived bindings could overwrite its changes?
- Keeping each binding's shadow tree separate allows for significant implementation optimizations; in particular the shadow tree could be a shared prototype until/unless it was accessed or manipulated via script. This is particularly important in terms of bindings which are part of a language and used frequently, as it has a direct impact on startup time.
There are two significant changes to the specification:
- The term "shadow tree" and the .shadowTree attribute in the ECMAScript binding refer to the cloned shadow tree of a specific binding only. The term "flattened shadow tree" is used when referring to all the shadow content inserted under a single bound element via binding inheritance.
- The assignment of explicit children to content elements has changed slightly but significantly: instead of performing a treewalk over the flattened shadow tree, explicit children are first assigned to content elements from the "most base" to the most derived binding in order.
In the terminology, replace "shadow tree" with the following definitions:
The shadow tree is a tree of nodes created by cloning the content template of a binding. (See: shadow content.) The contents of the shadow tree augment the bound element's standard presentation and interactive behaviour with alternate behaviour. One or more shadow trees are combined by the user agent using inheritance to form the flattened shadow tree for a bound element. The shadow tree is hidden from normal DOM processing (hence the name "shadow"), and is not accessible via Core DOM navigation facilities such as firstChild or nextSibling.
Section 2.4, "The template element"
If a binding does not contain a template element, the following content template shall be assumed by the implementation:
<template><inherited><content includes="*" /></inherited></template>
Section 2.5, "The content element"
Move the paragraphs from section 5.4 beginning with "Expressions specified using the includes attribute determine..." and ending with "Nodes never match..." into this section.
Section 4.4, "Binding Attachment Model"
Replace number 5 with:
5. the content template for the binding is cloned and inserted into the proper position in the final flattened tree.
6. child nodes which are not in a locked <content> element are repositioned as specified in the section "processing content elements"
7. At this point, further bindings may need to be applied, or certain bindings may need to be removed (because of CSS inheritance or because the selectors that decide which elements match which bindings can be affected by the shadow tree being associated with the bound element). [Paragraph copied from section 5.1]
Section 5 "Shadow content"
Replace "a binding can specify" with "each binding has".
Remove the paragraph that begins "If a binding element that had no template element...".
Remove everything from "The bindings in the bound element's list of bindings" through the Note.
Remove the paragraph beginning "The shadow tree is then applied".
The paragraph beginning "After this point" is moved to section 4.4
Section 5.2 should be titled "Rules for Shadow Content Removal" and contain the following text:
When shadow content is removed, any explicit children inserted in <content> nodes in the shadow content should be repositioned according to the rules in section 5.4. No mutation events are fired as shadow content is removed.
For bindings with ECMAScript implementations the shadowTree member of the private object must be set to null.
Section 5.4 should contain the following text:
XBL bindings can interleave shadow content between bound elements and their explicit children. They do so using XBL's content element. Any number of content nodes may be used in a binding's shadow content template.
[Insert the paragraph defining explicit children here, with its accompanying example.]
The explicit children of the bound element are distributed and assigned to the content elements of the shadow tree by the user agent in the following circumstances:
- Whenever a binding is attached
- Whenever a content element is added dynamically
- Whenever an explicit child is in need of distribution. can happen if a new child is added to the DOM, a binding is detached, or a <content> node is removed.
Children are positioned according to the following rules:
- The user agent shall remove any explicit children inserted into a content element which is not present in the chain of inherited content templates, for repositioning.
- Any explicit children inserted into a locked content element shall not be repositioned.
- The user agent shall attempt to insert the remaining explicit children into the first content element found according to the following rules:
- Do a pre-order, depth-first walk of the "most base binding" shadow tree, ignoring any descendents of content elements (so a content element that is the descendent of another content element must be ignored).
- Repeat this process with any derived bindings whose shadow content is included with the <inherited> element.
If there is no acceptable content node, the explicit child does not appear in the final flattened tree. For the purposes of styling the child is treated as display:none
The explicit children must in inserted such that the order of the insertion point is the same as the relative order of the children in the explicit chilren list.
After the bullet "Any content elements in shadow trees..." insert the following bullet:
- Any inherited elements in shadow trees must be replaced with the shadow tree of the derived binding, or if there is no derived binding with the content of the inherited element.