When implementing a rich text editor in javascript, I need to apply some changes to every text node in selected range. Range object provides interface to get startContainer
, endContainer
, startOffset
, endOffset
for the selected range. How can I iterate over every DOM node in between?
var selection = window.getSelection();
var range = selection.getRange(0);
// How can I iterate over every node within the range?
As suggested, you can use NodeIterator
to walk inside range.commonAncestorContainer
.
Here's a snippet:
var _iterator = document.createNodeIterator(
range.commonAncestorContainer,
NodeFilter.SHOW_ALL, // pre-filter
{
// custom filter
acceptNode: function (node) {
return NodeFilter.FILTER_ACCEPT;
}
}
);
var _nodes = [];
while (_iterator.nextNode()) {
if (_nodes.length === 0 && _iterator.referenceNode !== range.startContainer) continue;
_nodes.push(_iterator.referenceNode);
if (_iterator.referenceNode === range.endContainer) break;
}
You should use NodeFilter.SHOW_ALL
because your range can contain multiple nodeTypes. If you know what you are selecting, you can check this reference to properly choose NodeFilter
.
Edit: I also want to point out document.createTreeWalker().
The key difference is that document.createTreeWalker()
allow your acceptNode
filter to return both NodeFilter.FILTER_REJECT
and NodeFilter.FILTER_SKIP
with real differences.
Quote from NodeFilter docs:
FILTER_REJECT:
Value to be returned by the NodeFilter.acceptNode() method when a node should be rejected. For TreeWalker, child nodes are also rejected. For NodeIterator, this flag is synonymous with FILTER_SKIP.
Ps: the NodeFilter.acceptNode() documentation for NodeFilter.FILTER_REJECT
is incorrect.
range.commonAncestorContainer
will give you the node that encompasses the range. If it gives you a text node, then that's the only node in your range.
If it gives you an element, you can use NodeIterator
, or el.querySelectorAll('*')
to get the nodes within.
Not all of these will be inside your range, so use range.intersectsNode(el)
to confirm.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With