fix(js): implement DOM parentNode() traversal in TreeWalker (#475)
parentNode() inspected only the immediate parent, which caused three spec deviations: - With currentNode at root, the `parent !== this.root` guard did not fire (parent is root's OWN parent), so a node OUTSIDE the walker's subtree was returned — createTreeWalker(root).parentNode() yielded <body>. A TreeWalker must never surface a node above its root. - The same guard excluded root as a *result*, so when currentNode's accepted ancestor was root itself, parentNode() returned null instead of root. - A skipped (or otherwise non-accepted) immediate parent ended the search rather than continuing up to the first accepted ancestor. Replaced with the DOM 6.1 algorithm: climb from currentNode, returning the first ancestor that filters to FILTER_ACCEPT, with the loop's `node !== this.root` guard keeping the walk inside root while still letting root be returned. Reuses the three-valued `_filter` from #461. Last of the TreeWalker mover deviations, after nextNode (#461), previousNode (#462) and the child/sibling movers (#469).
This commit is contained in:
1 parent
485497393d
commit
845abb96f7
2 files changed
+79
-4
No files matched your search
Vendored
+10
-4
@@ -2713,11 +2713,17 @@ class Document extends Node {
|
||||
}
|
||||
return null;
|
||||
},
|
||||
// DOM 6.1 "parentNode" (issue #475). The old version looked only at the
|
||||
// immediate parent, so it couldn't climb past a skipped ancestor; it also
|
||||
// excluded `root` as a result yet stepped to root's own parent when
|
||||
// currentNode was root — returning a node OUTSIDE the walker's subtree.
|
||||
// The loop's `node !== this.root` guard is what keeps the walk inside
|
||||
// root while still allowing root itself to be returned.
|
||||
parentNode() {
|
||||
let parent = this.currentNode.parentNode;
|
||||
if (parent && parent !== this.root && this._accept(parent)) {
|
||||
this.currentNode = parent;
|
||||
return parent;
|
||||
let node = this.currentNode;
|
||||
while (node && node !== this.root) {
|
||||
node = node.parentNode;
|
||||
if (node && this._accept(node)) { this.currentNode = node; return node; }
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
Reference in new issue
Block a user