From 7835f133fedfc40522ed7867838ec6f4921f36de Mon Sep 17 00:00:00 2001
From: Rohit <71192000+rohitsux@users.noreply.github.com>
Date: Fri, 12 Jun 2026 11:04:21 +0530
Subject: [PATCH] feat(webapi): reflect attributes on HTMLSourceElement
Add the reflected IDL attributes to the existing HTMLSourceElement,
which previously reflected none: src (resolved as a URL like
HTMLEmbedElement.src), srcset, sizes, media, type, width and height.
Mirrors the reflection idiom used by HTMLEmbedElement. width and height
are reflected as strings, matching the sibling HTMLEmbedElement
accessors. Adds element/html/source.html covering parse-from-markup,
property/attribute round-trips and src URL resolution.
---
src/browser/tests/element/html/source.html | 77 +++++++++++++++++++++
src/browser/webapi/element/html/Source.zig | 78 ++++++++++++++++++++++
2 files changed, 155 insertions(+)
create mode 100644 src/browser/tests/element/html/source.html
diff --git a/src/browser/tests/element/html/source.html b/src/browser/tests/element/html/source.html
new file mode 100644
index 000000000..29c93c343
--- /dev/null
+++ b/src/browser/tests/element/html/source.html
@@ -0,0 +1,77 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/browser/webapi/element/html/Source.zig b/src/browser/webapi/element/html/Source.zig
index 8bb43fb02..f654959d7 100644
--- a/src/browser/webapi/element/html/Source.zig
+++ b/src/browser/webapi/element/html/Source.zig
@@ -1,4 +1,5 @@
const js = @import("../../../js/js.zig");
+const Frame = @import("../../../Frame.zig");
const Node = @import("../../Node.zig");
const Element = @import("../../Element.zig");
const HtmlElement = @import("../Html.zig");
@@ -10,10 +11,74 @@ _proto: *HtmlElement,
pub fn asElement(self: *Source) *Element {
return self._proto._proto;
}
+pub fn asConstElement(self: *const Source) *const Element {
+ return self._proto._proto;
+}
pub fn asNode(self: *Source) *Node {
return self.asElement().asNode();
}
+pub fn getSrc(self: *const Source, frame: *Frame) ![]const u8 {
+ const element = self.asConstElement();
+ const src = element.getAttributeSafe(comptime .wrap("src")) orelse return "";
+ if (src.len == 0) {
+ return "";
+ }
+ return element.asConstNode().resolveURL(src, frame, .{});
+}
+
+pub fn setSrc(self: *Source, value: []const u8, frame: *Frame) !void {
+ try self.asElement().setAttributeSafe(comptime .wrap("src"), .wrap(value), frame);
+}
+
+pub fn getSrcset(self: *const Source) []const u8 {
+ return self.asConstElement().getAttributeSafe(comptime .wrap("srcset")) orelse "";
+}
+
+pub fn setSrcset(self: *Source, value: []const u8, frame: *Frame) !void {
+ try self.asElement().setAttributeSafe(comptime .wrap("srcset"), .wrap(value), frame);
+}
+
+pub fn getSizes(self: *const Source) []const u8 {
+ return self.asConstElement().getAttributeSafe(comptime .wrap("sizes")) orelse "";
+}
+
+pub fn setSizes(self: *Source, value: []const u8, frame: *Frame) !void {
+ try self.asElement().setAttributeSafe(comptime .wrap("sizes"), .wrap(value), frame);
+}
+
+pub fn getMedia(self: *const Source) []const u8 {
+ return self.asConstElement().getAttributeSafe(comptime .wrap("media")) orelse "";
+}
+
+pub fn setMedia(self: *Source, value: []const u8, frame: *Frame) !void {
+ try self.asElement().setAttributeSafe(comptime .wrap("media"), .wrap(value), frame);
+}
+
+pub fn getType(self: *const Source) []const u8 {
+ return self.asConstElement().getAttributeSafe(comptime .wrap("type")) orelse "";
+}
+
+pub fn setType(self: *Source, value: []const u8, frame: *Frame) !void {
+ try self.asElement().setAttributeSafe(comptime .wrap("type"), .wrap(value), frame);
+}
+
+pub fn getWidth(self: *const Source) []const u8 {
+ return self.asConstElement().getAttributeSafe(comptime .wrap("width")) orelse "";
+}
+
+pub fn setWidth(self: *Source, value: []const u8, frame: *Frame) !void {
+ try self.asElement().setAttributeSafe(comptime .wrap("width"), .wrap(value), frame);
+}
+
+pub fn getHeight(self: *const Source) []const u8 {
+ return self.asConstElement().getAttributeSafe(comptime .wrap("height")) orelse "";
+}
+
+pub fn setHeight(self: *Source, value: []const u8, frame: *Frame) !void {
+ try self.asElement().setAttributeSafe(comptime .wrap("height"), .wrap(value), frame);
+}
+
pub const JsApi = struct {
pub const bridge = js.Bridge(Source);
@@ -22,4 +87,17 @@ pub const JsApi = struct {
pub const prototype_chain = bridge.prototypeChain();
pub var class_id: bridge.ClassId = undefined;
};
+
+ pub const height = bridge.accessor(Source.getHeight, Source.setHeight, .{ .ce_reactions = true });
+ pub const media = bridge.accessor(Source.getMedia, Source.setMedia, .{ .ce_reactions = true });
+ pub const sizes = bridge.accessor(Source.getSizes, Source.setSizes, .{ .ce_reactions = true });
+ pub const src = bridge.accessor(Source.getSrc, Source.setSrc, .{ .ce_reactions = true });
+ pub const srcset = bridge.accessor(Source.getSrcset, Source.setSrcset, .{ .ce_reactions = true });
+ pub const @"type" = bridge.accessor(Source.getType, Source.setType, .{ .ce_reactions = true });
+ pub const width = bridge.accessor(Source.getWidth, Source.setWidth, .{ .ce_reactions = true });
};
+
+const testing = @import("../../../../testing.zig");
+test "WebApi: HTML.Source" {
+ try testing.htmlRunner("element/html/source.html", .{});
+}