There are multiple valid approaches to mirroring a tree using Mutation Observers. TreeMirror trades off a small amount of memory so it can be fast to process changes. It maintains a mapping from local node to remote node, so that when it processes the added
, removed
, reparented
& reordered
node arrays, it can efficiently find the corresponding remote node by simply looking it up in the map.
The general approach is this:
- Maintain a mapping from localNode -> remoteNode. To do this, it uses the
MutationSummary.NodeMap
class, which exposes a simpleget()
,has()
,set()
,delete()
API. For the rest of this API, I'll represent a corresponding remote node like this:remoteNode(localNode)
.
For each summary of changes:
- For each
node
inremoved
nodes- Remove
remoteNode(node)
from its remote parent - Remove
node
->remoteNode(node)
from the mapping
- Remove
- For each
node
inadded
- Create a new
remoteNode
and addnode
->remoteNode
to the mapping
- Create a new
- For each
node
inreparented
&reordered
- Remove
remoteNode(node)
from its remote parent
- Remove
- Create an array of
insertions
by concatenatingadded
,reparented
&reordered
.- Sort insertions first by
node.parentNode
, then by ascending order ofnode.previousSibling
- For each
node
ininsertion
- insert
remoteNode(node)
as a child ofremoteNode(node.parentNode)
immediately afterremoteNode(node.previousSibling)
.
- Sort insertions first by
That's it. There's one non-obvious step here that's worth pointing out: it's necessary to remove all reparented
& reordered
nodes before inserting all added
, reparented
& reordered
nodes to the new location because otherwise it's possible to create a cycle in the HTML structure (which is, of course, disallowed).