Skip to content

Commit 9db9189

Browse files
committed
Support options in observer and tests
1 parent 537a262 commit 9db9189

File tree

3 files changed

+125
-8
lines changed

3 files changed

+125
-8
lines changed

src/browser/dom/element.zig

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -508,7 +508,7 @@ test "Browser.DOM.Element" {
508508
}, .{});
509509

510510
try runner.testCases(&.{
511-
.{ "document.getElementById('para').clientWidth", "0" },
511+
.{ "document.getElementById('para').clientWidth", "1" },
512512
.{ "document.getElementById('para').clientHeight", "1" },
513513

514514
.{ "let r1 = document.getElementById('para').getBoundingClientRect()", "undefined" },
@@ -529,7 +529,7 @@ test "Browser.DOM.Element" {
529529
.{ "r3.width", "1" },
530530
.{ "r3.height", "1" },
531531

532-
.{ "document.getElementById('para').clientWidth", "2" },
532+
.{ "document.getElementById('para').clientWidth", "3" },
533533
.{ "document.getElementById('para').clientHeight", "1" },
534534
}, .{});
535535

src/browser/dom/intersection_observer.zig

Lines changed: 118 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -51,12 +51,16 @@ pub const IntersectionObserver = struct {
5151
// new IntersectionObserver(callback)
5252
// new IntersectionObserver(callback, options) [not supported yet]
5353
pub fn constructor(callback: Env.Callback, options_: ?IntersectionObserverOptions, state: *SessionState) !IntersectionObserver {
54-
if (options_ != null) return error.IntersectionObserverOptionsNotYetSupported;
55-
const options = IntersectionObserverOptions{
54+
var options = IntersectionObserverOptions{
5655
.root = parser.documentToNode(parser.documentHTMLToDocument(state.document.?)),
5756
.rootMargin = "0px 0px 0px 0px",
58-
.threshold = &[_]f32{0.0},
57+
.threshold = &default_threshold,
5958
};
59+
if (options_) |*o| {
60+
if (o.root) |root| {
61+
options.root = root;
62+
} // Other properties are not used due to the way we render
63+
}
6064

6165
return .{
6266
.callback = callback,
@@ -103,6 +107,7 @@ const IntersectionObserverOptions = struct {
103107
rootMargin: ?[]const u8,
104108
threshold: ?[]const f32,
105109
};
110+
const default_threshold = [_]f32{0.0};
106111

107112
// https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserverEntry
108113
// https://w3c.github.io/IntersectionObserver/#intersection-observer-entry
@@ -127,19 +132,126 @@ pub const IntersectionObserverEntry = struct {
127132
}
128133

129134
// A Boolean value which is true if the target element intersects with the intersection observer's root. If this is true, then, the IntersectionObserverEntry describes a transition into a state of intersection; if it's false, then you know the transition is from intersecting to not-intersecting.
130-
pub fn isIntersecting(_: *const IntersectionObserverEntry) bool {
135+
pub fn get_isIntersecting(_: *const IntersectionObserverEntry) bool {
131136
return true;
132137
}
133138

134139
// Returns a DOMRectReadOnly for the intersection observer's root.
135140
pub fn get_rootBounds(self: *const IntersectionObserverEntry) !Element.DOMRect {
136-
// TODO self.options.root can be an Element or a Document when Options are supported
137-
const element = (try parser.documentGetDocumentElement(parser.documentHTMLToDocument(self.state.document.?))).?;
141+
const root = self.options.root.?;
142+
const root_type = try parser.nodeType(root);
143+
144+
var element: *parser.Element = undefined;
145+
switch (root_type) {
146+
.element => element = parser.nodeToElement(root),
147+
.document => {
148+
const doc = parser.nodeToDocument(root);
149+
element = (try parser.documentGetDocumentElement(doc)).?;
150+
},
151+
else => return error.InvalidState,
152+
}
153+
138154
return try self.state.renderer.getRect(element);
139155
}
140156

141157
// The Element whose intersection with the root changed.
142158
pub fn get_target(self: *const IntersectionObserverEntry) *parser.Element {
143159
return self.target;
144160
}
161+
162+
// TODO: pub fn get_time(self: *const IntersectionObserverEntry)
145163
};
164+
165+
const testing = @import("../../testing.zig");
166+
test "Browser.DOM.IntersectionObserver" {
167+
var runner = try testing.jsRunner(testing.tracking_allocator, .{});
168+
defer runner.deinit();
169+
170+
try runner.testCases(&.{
171+
.{ "new IntersectionObserver(() => {}).observe(document.documentElement);", "undefined" },
172+
}, .{});
173+
174+
try runner.testCases(&.{
175+
.{ "let count_a = 0;", "undefined" },
176+
.{ "const a1 = document.createElement('div');", "undefined" },
177+
.{ "new IntersectionObserver(entries => {count_a += 1;}).observe(a1);", "undefined" },
178+
.{ "count_a;", "1" },
179+
}, .{});
180+
181+
// This test is documenting current behavior, not correct behavior.
182+
// Currently every time observe is called, the callback is called with all entries. 1 + 2 = 3
183+
try runner.testCases(&.{
184+
.{ "let count_b = 0;", "undefined" },
185+
.{ "let observer_b = new IntersectionObserver(entries => {count_b = entries.length;});", "undefined" },
186+
.{ "const b1 = document.createElement('div');", "undefined" },
187+
.{ "observer_b.observe(b1);", "undefined" },
188+
.{ "count_b;", "1" },
189+
.{ "const b2 = document.createElement('div');", "undefined" },
190+
.{ "observer_b.observe(b2);", "undefined" },
191+
.{ "count_b;", "2" },
192+
}, .{});
193+
194+
// Unobserve
195+
try runner.testCases(&.{
196+
.{ "let count_c = 0;", "undefined" },
197+
.{ "let observer_c = new IntersectionObserver(entries => { count_c = entries.length;});", "undefined" },
198+
.{ "const c1 = document.createElement('div');", "undefined" },
199+
.{ "observer_c.observe(c1);", "undefined" },
200+
.{ "count_c;", "1" },
201+
.{ "observer_c.unobserve(c1);", "undefined" },
202+
.{ "const c2 = document.createElement('div');", "undefined" },
203+
.{ "observer_c.observe(c2);", "undefined" },
204+
.{ "count_c;", "1" },
205+
}, .{});
206+
207+
// Disconnect
208+
try runner.testCases(&.{
209+
.{ "let observer_d = new IntersectionObserver(entries => {});", "undefined" },
210+
.{ "let d1 = document.createElement('div');", "undefined" },
211+
.{ "observer_d.observe(d1);", "undefined" },
212+
.{ "observer_d.disconnect();", "undefined" },
213+
.{ "observer_d.takeRecords().length;", "0" },
214+
}, .{});
215+
216+
// takeRecords
217+
try runner.testCases(&.{
218+
.{ "let observer_e = new IntersectionObserver(entries => {});", "undefined" },
219+
.{ "let e1 = document.createElement('div');", "undefined" },
220+
.{ "observer_e.observe(e1);", "undefined" },
221+
.{ "const e2 = document.createElement('div');", "undefined" },
222+
.{ "observer_e.observe(e2);", "undefined" },
223+
.{ "observer_e.takeRecords().length;", "2" },
224+
}, .{});
225+
226+
// Entry
227+
try runner.testCases(&.{
228+
.{ "let entry;", "undefined" },
229+
.{ "new IntersectionObserver(entries => { entry = entries[0]; }).observe(document.createElement('div'));", "undefined" },
230+
.{ "entry.boundingClientRect.x;", "1" },
231+
.{ "entry.intersectionRatio;", "1" },
232+
.{ "entry.intersectionRect.x;", "1" },
233+
.{ "entry.intersectionRect.y;", "0" },
234+
.{ "entry.intersectionRect.width;", "1" },
235+
.{ "entry.intersectionRect.height;", "1" },
236+
.{ "entry.isIntersecting;", "true" },
237+
.{ "entry.rootBounds.x;", "2" }, // This is not the prefered behaviour, the Window rect should wrap all elements so x -> 0
238+
.{ "entry.rootBounds.width;", "1" }, // width -> clientWidth
239+
.{ "entry.rootBounds.height;", "1" },
240+
.{ "entry.target;", "[object HTMLDivElement]" },
241+
}, .{});
242+
243+
// Options
244+
try runner.testCases(&.{
245+
.{ "const new_root = document.createElement('span');", "undefined" },
246+
.{ "let new_entry;", "undefined" },
247+
.{
248+
\\ const new_observer = new IntersectionObserver(
249+
\\ entries => { new_entry = entries[0]; },
250+
\\ {root: new_root, rootMargin: '0px 0px 0px 0px', threshold: [0]});
251+
,
252+
"undefined",
253+
},
254+
.{ "new_observer.observe(document.createElement('div'));", "undefined" },
255+
.{ "new_entry.rootBounds.x;", "3" },
256+
}, .{});
257+
}

src/browser/netsurf.zig

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1278,6 +1278,11 @@ pub inline fn nodeToElement(node: *Node) *Element {
12781278
return @as(*Element, @ptrCast(node));
12791279
}
12801280

1281+
// nodeToDocument is an helper to convert a node to an document.
1282+
pub inline fn nodeToDocument(node: *Node) *Document {
1283+
return @as(*Document, @ptrCast(node));
1284+
}
1285+
12811286
// CharacterData
12821287
pub const CharacterData = c.dom_characterdata;
12831288

0 commit comments

Comments
 (0)