-
Notifications
You must be signed in to change notification settings - Fork 317
Description
What problem are you trying to solve?
It's very common in modern framework code to have to work with ranges of nodes as a unit, where a range is a sequence of sibling nodes. The operations include:
- Clear a range of nodes
- Move a range of nodes
- Extract a range of nodes into a fragment
Two of the APIs are available on Range as deleteContents(), extractContents(), but using Range, even StaticRange, is slower than implementing these operations in JS. The move operation doesn't exist in any form, since moveBefore() is brand new.
While the JS code for implementing these operations is relatively simple, native methods would still reduce the amount of required utility code needed in some libraries and frameworks. Higher-level methods would also help reduce the number of wrapper JS objects created during traversal, and the total number of calls like .remove() and .nextSibling. The operations are often on the very hottest paths of rendering code, so any perf improvement is beneficial.
What solutions exist today?
Today frameworks implement these using traversal and individual node removal and insertion.
How would you solve it?
Add these methods to ParentNode:
/**
* Removes the nodes between startNode and endNode exclusively.
* - startNode and endNode must be children of the receiver, or nullish.
* - If startNode is nullish, then start removing nodes at the first child of the receiver.
* - If endNode is nullsih, then remove nodes until the last child of the receiver.
*/
deleteRange(startNode?: ChildNode, endNode?: ChildNode): void;
/**
* Moves the nodes between startNode and endNode exclusively to a new DocumentFragment.
*/
extractRange(startNode?: ChildNode, endNode?: ChildNode): DocumentFragment;
/**
* Atomically moves the nodes between startNode and endNode exclusively to the receiver, inserted
* before refNode or the end of the container.
*/
moveRangeBefore(fromParent: ParentNode, startNode?: ChildNode, endNode?: ChildNode, refNode?: ChildNode): void
/**
* Moves the nodes between startNode and endNode exclusively to the receiver, inserted
* before refNode or the end of the container.
*
* This is the same as moveRangeBefore() without the atomic operation guarantees and without
* throwing in cases where moveRangeBefore() throws (the same as in moveBefore()).
*/
insertRangeBefore(fromParent: ParentNode, startNode?: ChildNode, endNode?: ChildNode, refNode?: ChildNode): voidAnything else?
This is an alternative to #736 that is smaller in scope. It helps with the bulk mutation operations, but doesn't deal with DOM serialization and how start and end nodes are represented.