1919const std = @import ("std" );
2020const parser = @import ("../netsurf.zig" );
2121const Env = @import ("../env.zig" ).Env ;
22- const TreeWalker = @import ("tree_walker .zig" ). TreeWalker ;
22+ const NodeFilter = @import ("node_filter .zig" );
2323
2424// https://developer.mozilla.org/en-US/docs/Web/API/NodeIterator
25+ // While this is similar to TreeWalker it has it's own implementation as there are several suttle differences
26+ // For example:
27+ // - nextNode returns the reference node, whereas TreeWalker returns the next node
28+ // - Skip and reject are equivalent for NodeIterator, for TreeWalker they are different
2529pub const NodeIterator = struct {
26- walker : TreeWalker ,
30+ root : * parser.Node ,
31+ reference_node : * parser.Node ,
32+ what_to_show : u32 ,
33+ filter : ? NodeIteratorOpts ,
34+ filter_func : ? Env.Function ,
35+
2736 pointer_before_current : bool = true ,
2837
29- pub fn init (node : * parser.Node , what_to_show : ? u32 , filter : ? TreeWalker.TreeWalkerOpts ) ! NodeIterator {
30- return .{ .walker = try TreeWalker .init (node , what_to_show , filter ) };
38+ pub const NodeIteratorOpts = union (enum ) {
39+ function : Env.Function ,
40+ object : struct { acceptNode : Env .Function },
41+ };
42+
43+ pub fn init (node : * parser.Node , what_to_show : ? u32 , filter : ? NodeIteratorOpts ) ! NodeIterator {
44+ var filter_func : ? Env.Function = null ;
45+ if (filter ) | f | {
46+ filter_func = switch (f ) {
47+ .function = > | func | func ,
48+ .object = > | o | o .acceptNode ,
49+ };
50+ }
51+
52+ return .{
53+ .root = node ,
54+ .reference_node = node ,
55+ .what_to_show = what_to_show orelse NodeFilter .NodeFilter ._SHOW_ALL ,
56+ .filter = filter ,
57+ .filter_func = filter_func ,
58+ };
3159 }
3260
33- pub fn get_filter (self : * const NodeIterator ) ? Env.Function {
34- return self .walker . filter ;
61+ pub fn get_filter (self : * const NodeIterator ) ? NodeIteratorOpts {
62+ return self .filter ;
3563 }
3664
3765 pub fn get_pointerBeforeReferenceNode (self : * const NodeIterator ) bool {
3866 return self .pointer_before_current ;
3967 }
4068
4169 pub fn get_referenceNode (self : * const NodeIterator ) * parser.Node {
42- return self .walker . current_node ;
70+ return self .reference_node ;
4371 }
4472
4573 pub fn get_root (self : * const NodeIterator ) * parser.Node {
46- return self .walker . root ;
74+ return self .root ;
4775 }
4876
4977 pub fn get_whatToShow (self : * const NodeIterator ) u32 {
50- return self .walker . what_to_show ;
78+ return self .what_to_show ;
5179 }
5280
5381 pub fn _nextNode (self : * NodeIterator ) ! ? * parser.Node {
5482 if (self .pointer_before_current ) { // Unlike TreeWalker, NodeIterator starts at the first node
5583 self .pointer_before_current = false ;
56- if (.accept == try self . walker . verify (self .walker . current_node )) {
57- return self .walker . current_node ;
84+ if (.accept == try NodeFilter . verify (self .what_to_show , self . filter_func , self . reference_node )) {
85+ return self .reference_node ;
5886 }
5987 }
6088
61- if (try self .firstChild (self .walker . current_node )) | child | {
62- self .walker . current_node = child ;
89+ if (try self .firstChild (self .reference_node )) | child | {
90+ self .reference_node = child ;
6391 return child ;
6492 }
6593
66- var current = self .walker . current_node ;
67- while (current != self .walker . root ) {
68- if (try self .walker . nextSibling (current )) | sibling | {
69- self .walker . current_node = sibling ;
94+ var current = self .reference_node ;
95+ while (current != self .root ) {
96+ if (try self .nextSibling (current )) | sibling | {
97+ self .reference_node = sibling ;
7098 return sibling ;
7199 }
72100
@@ -79,41 +107,41 @@ pub const NodeIterator = struct {
79107 pub fn _previousNode (self : * NodeIterator ) ! ? * parser.Node {
80108 if (! self .pointer_before_current ) {
81109 self .pointer_before_current = true ;
82- if (.accept == try self . walker . verify (self .walker . current_node )) {
83- return self .walker . current_node ; // Still need to verify as last may be first as well
110+ if (.accept == try NodeFilter . verify (self .what_to_show , self . filter_func , self . reference_node )) {
111+ return self .reference_node ; // Still need to verify as last may be first as well
84112 }
85113 }
86- if (self .walker . current_node == self . walker .root ) return null ;
114+ if (self .reference_node == self .root ) return null ;
87115
88- var current = self .walker . current_node ;
116+ var current = self .reference_node ;
89117 while (try parser .nodePreviousSibling (current )) | previous | {
90118 current = previous ;
91119
92- switch (try self . walker . verify (current )) {
120+ switch (try NodeFilter . verify (self . what_to_show , self . filter_func , current )) {
93121 .accept = > {
94122 // Get last child if it has one.
95123 if (try self .lastChild (current )) | child | {
96- self .walker . current_node = child ;
124+ self .reference_node = child ;
97125 return child ;
98126 }
99127
100128 // Otherwise, this node is our previous one.
101- self .walker . current_node = current ;
129+ self .reference_node = current ;
102130 return current ;
103131 },
104132 .reject , .skip = > {
105133 // Get last child if it has one.
106134 if (try self .lastChild (current )) | child | {
107- self .walker . current_node = child ;
135+ self .reference_node = child ;
108136 return child ;
109137 }
110138 },
111139 }
112140 }
113141
114- if (current != self .walker . root ) {
115- if (try self .walker . parentNode (current )) | parent | {
116- self .walker . current_node = parent ;
142+ if (current != self .root ) {
143+ if (try self .parentNode (current )) | parent | {
144+ self .reference_node = parent ;
117145 return parent ;
118146 }
119147 }
@@ -129,7 +157,7 @@ pub const NodeIterator = struct {
129157 const index : u32 = @intCast (i );
130158 const child = (try parser .nodeListItem (children , index )) orelse return null ;
131159
132- switch (try self . walker . verify (child )) {
160+ switch (try NodeFilter . verify (self . what_to_show , self . filter_func , child )) {
133161 .accept = > return child , // NOTE: Skip and reject are equivalent for NodeIterator, this is different from TreeWalker
134162 .reject , .skip = > if (try self .firstChild (child )) | gchild | return gchild ,
135163 }
@@ -147,14 +175,46 @@ pub const NodeIterator = struct {
147175 index -= 1 ;
148176 const child = (try parser .nodeListItem (children , index )) orelse return null ;
149177
150- switch (try self . walker . verify (child )) {
178+ switch (try NodeFilter . verify (self . what_to_show , self . filter_func , child )) {
151179 .accept = > return child , // NOTE: Skip and reject are equivalent for NodeIterator, this is different from TreeWalker
152180 .reject , .skip = > if (try self .lastChild (child )) | gchild | return gchild ,
153181 }
154182 }
155183
156184 return null ;
157185 }
186+
187+ // This implementation is actually the same as :TreeWalker
188+ fn parentNode (self : * const NodeIterator , node : * parser.Node ) ! ? * parser.Node {
189+ if (self .root == node ) return null ;
190+
191+ var current = node ;
192+ while (true ) {
193+ if (current == self .root ) return null ;
194+ current = (try parser .nodeParentNode (current )) orelse return null ;
195+
196+ switch (try NodeFilter .verify (self .what_to_show , self .filter_func , current )) {
197+ .accept = > return current ,
198+ .reject , .skip = > continue ,
199+ }
200+ }
201+ }
202+
203+ // This implementation is actually the same as :TreeWalker
204+ fn nextSibling (self : * const NodeIterator , node : * parser.Node ) ! ? * parser.Node {
205+ var current = node ;
206+
207+ while (true ) {
208+ current = (try parser .nodeNextSibling (current )) orelse return null ;
209+
210+ switch (try NodeFilter .verify (self .what_to_show , self .filter_func , current )) {
211+ .accept = > return current ,
212+ .skip , .reject = > continue ,
213+ }
214+ }
215+
216+ return null ;
217+ }
158218};
159219
160220const testing = @import ("../../testing.zig" );
@@ -210,4 +270,19 @@ test "Browser.DOM.NodeFilter" {
210270 },
211271 .{ "notationIterator.previousNode()" , "null" },
212272 }, .{});
273+
274+ try runner .testCases (&.{
275+ .{ "nodeIterator.filter.acceptNode(document.body)" , "1" },
276+ .{ "notationIterator.filter" , "null" },
277+ .{
278+ \\ const rejectIterator = document.createNodeIterator(
279+ \\ document.body,
280+ \\ NodeFilter.SHOW_ALL,
281+ \\ (e => { return NodeFilter.FILTER_REJECT}),
282+ \\ );
283+ \\ rejectIterator.filter(document.body);
284+ ,
285+ "2" ,
286+ },
287+ }, .{});
213288}
0 commit comments