In order to keep the Part
objects up to date with the DOM, the browser needs to keep some extra data on nodes and run a few extra steps on Node
addition or removal.
For each node there should be a few extra fields:
- A
nodePart
link to aNodePart
, if any. This is used to locatePart
objects when aPartRoot
needs to update its parts. - A
childNodePartPreviousSibling
link to aChildNodePart
. This is theNode
that begins, but is not included in, aChildNodePart
range. This is used to locatePart
objects and to determine whether twoChildNodePart
ranges overlap. - A
childNodePartNextSibling
link to aChildNodePart
. This is theNode
that ends, but is not included in, aChildNodePart
range. This is used to locatePart
objects and to determine whether twoChildNodePart
ranges overlap. - A
childNodePartOwned
link to aChildNodePart
. This is the siblings in betweenpreviousSibling
andnextSibling
nodes that are not in between some otherpreviousSibling
andnextSibling
nodes. This is useful to locate thePartRoot
of a node, when iterating up through the DOM. Otherwise a newNode
may not locate theChildNodePart
that it belongs to. It is only present on the top-level siblings of aChildNodePart
. - A
childNodePartParentDirty
bit that determines whether a parent ofChildNodePart
objects has had those objects validated since a child was added or removed. - A link to a
DocumentPart
for aDocument
orDocumentFragment
.
getParts()
is a cached DOM-order list of parts that can be marked as dirty whenever a node is inserted with a Part
object whose relative location in its PartRoot
parent is unknown. The PartRoot
has to do a full subtree walk of any nodes that have Part
fields.
.partRoot
is a dynamic parent walk to locate the parent PartRoot
. It's expected that most operations will do child part walks rather than parent walks. To search for a parent PartRoot
, walk the nodes looking for either a childNodePartOwned
link to a valid ChildNodePart
or a node with a DocumentPart
.
ChildNodePart
objects have various validity requirements:
previousSibling
andnextSibling
are connected nodes.previousSibling
andnextSibling
have the same parent node.previousSibling
precedesnextSibling
.- The
ChildNodePart
does not intersect with any otherChildNodePart
range.
Given a parent, it's possible to do validity checking by iterating over all child nodes.
The process of checking validity and updating nodes is as follows:
- Iterate over all children, looking for
childNodePartPreviousSibling
andchildNodePartNextSibling
links. - For each
childNodePartPreviousSibling
link, push thatChildNodePart
onto theChildNodePart
stack. - If any
ChildNodePart
ends prematurely (before a childChildNodePart
ends), this and allChildNodePart
objects after it on the stack are marked as invalid. - If a
childNodePartNextSibling
is found before itschildNodePartPreviousSibling
, mark theChildNodePart
as invalid. - If the iteration reaches the end of the children list and some
ChildNodePart
is still on the stack, it is invalid. - Visit all children again updating the
childNodePartOwned
links to the newly validatedChildNodePart
objects. - Set
childNodePartParentDirty
bit to false. - If the validation resulted in any changes, set the child parts dirty bit to true for all valid
ChildNodePart
objects. - For all invalid
ChildNodePart
, set all parts to empty lists.
In all, this visits every child of a parent with some ChildNodePart
twice - once for validity, and once to populate the childNodePartOwned
link.
For every node being disconnected, check whether it has one of the above extra Node
fields.
- If it has a
NodePart
, disconnect theNodePart
which removes it from the parentPartRoot
parts. The parts list is still correct because there are no additions. Mark theNodePart
as invalid. - If it has a
previousSibling
ornextSibling
link to aChildNodePart
and theChildNodePart
, disconnect theChildNodePart
which removes it from the parentPartRoot
parts. Mark the parentPartRoot
parts list as dirty, as there may now be arbitrary new children orChildNodePart
objects that are newly valid. Mark the parent node'schildNodePartParentDirty
bit to true. - If it has a
childNodePartOwned
link, remove thechildNodePartOwned
link.
For every node being connected, check whether it has one of the above extra Node
fields.
- If it has a
NodePart
and that part is currently disconnected, connect theNodePart
which adds it to thePartRoot
parts. Mark thePartRoot
parts list as dirty. - If it has a
previousSibling
ornextSibling
link to aChildNodePart
, connect theChildNodePart
which adds it to thePartRoot
parts. Mark thePartRoot
parts list as dirty. Mark the parent node'schldNodePartParentDirty
bit to true.
Part
construction runs the same Node
addition algorithm, except that for ChildNodePart
it validates the parent and its children and throws if they are invalid.
replaceChildren
can be a bit more smart about Parts in the added children because the children are adopted in order and the ChildNodePart
is replaced in totality, as long as all the Part
objects being added are valid.