From 095413c6c5c95705451cb157e88a2f101099037b Mon Sep 17 00:00:00 2001 From: Karl Seguin Date: Fri, 21 Nov 2025 14:35:52 +0800 Subject: [PATCH] Element.toggleAttribute and InteresectionObserver init param overload --- src/browser/tests/element/attributes.html | 33 +++++++++++++++++++++ src/browser/webapi/Element.zig | 17 +++++++++++ src/browser/webapi/IntersectionObserver.zig | 18 +++++++++-- 3 files changed, 66 insertions(+), 2 deletions(-) diff --git a/src/browser/tests/element/attributes.html b/src/browser/tests/element/attributes.html index d4d416f6..c1ce0767 100644 --- a/src/browser/tests/element/attributes.html +++ b/src/browser/tests/element/attributes.html @@ -102,3 +102,36 @@ testing.expectEqual(false, el1.hasAttribute('data-test')); } + + diff --git a/src/browser/webapi/Element.zig b/src/browser/webapi/Element.zig index c4e3bf1d..023da510 100644 --- a/src/browser/webapi/Element.zig +++ b/src/browser/webapi/Element.zig @@ -354,6 +354,22 @@ pub fn removeAttribute(self: *Element, name: []const u8, page: *Page) !void { return attributes.delete(name, self, page); } +pub fn toggleAttribute(self: *Element, name: []const u8, force: ?bool, page: *Page) !bool { + const has = try self.hasAttribute(name, page); + + const should_add = force orelse !has; + + if (should_add and !has) { + try self.setAttribute(name, "", page); + return true; + } else if (!should_add and has) { + try self.removeAttribute(name, page); + return false; + } + + return should_add; +} + pub fn removeAttributeNode(self: *Element, attr: *Attribute, page: *Page) !*Attribute { if (attr._element == null or attr._element.? != self) { return error.NotFound; @@ -909,6 +925,7 @@ pub const JsApi = struct { pub const setAttribute = bridge.function(Element.setAttribute, .{}); pub const setAttributeNode = bridge.function(Element.setAttributeNode, .{}); pub const removeAttribute = bridge.function(Element.removeAttribute, .{}); + pub const toggleAttribute = bridge.function(Element.toggleAttribute, .{}); pub const getAttributeNames = bridge.function(Element.getAttributeNames, .{}); pub const removeAttributeNode = bridge.function(Element.removeAttributeNode, .{ .dom_exception = true }); pub const shadowRoot = bridge.accessor(Element.getShadowRoot, null, .{}); diff --git a/src/browser/webapi/IntersectionObserver.zig b/src/browser/webapi/IntersectionObserver.zig index 7198dfa7..d9722be7 100644 --- a/src/browser/webapi/IntersectionObserver.zig +++ b/src/browser/webapi/IntersectionObserver.zig @@ -53,18 +53,32 @@ var zero_rect: DOMRect = .{ pub const ObserverInit = struct { root: ?*Element = null, rootMargin: ?[]const u8 = null, - threshold: []const f64 = &.{0.0}, + threshold: Threshold = .{.scalar = 0.0}, + + const Threshold = union(enum) { + scalar: f64, + array: []const f64, + }; }; pub fn init(callback: js.Function, options: ?ObserverInit, page: *Page) !*IntersectionObserver { const opts = options orelse ObserverInit{}; const root_margin = if (opts.rootMargin) |rm| try page.arena.dupe(u8, rm) else "0px"; + const threshold = switch (opts.threshold) { + .scalar => |s| blk: { + const arr = try page.arena.alloc(f64, 1); + arr[0] = s; + break :blk arr; + }, + .array => |arr| try page.arena.dupe(f64, arr), + }; + return page._factory.create(IntersectionObserver{ ._callback = callback, ._root = opts.root, ._root_margin = root_margin, - ._threshold = try page.arena.dupe(f64, opts.threshold), + ._threshold = threshold }); }