From 2e64c461c381f44027a17545afcb6459c64039ea Mon Sep 17 00:00:00 2001 From: egrs Date: Wed, 18 Feb 2026 11:36:58 +0100 Subject: [PATCH] add attribute reflections for 8 HTML element types Wire up missing IDL properties for HTMLTimeElement (dateTime), HTMLLIElement (value), HTMLOListElement (start, reversed, type), HTMLOptGroupElement (disabled, label), HTMLQuoteElement (cite), HTMLTableCellElement (colSpan, rowSpan), HTMLLabelElement (htmlFor), and HTMLFieldSetElement (disabled, name). --- src/browser/tests/element/html/fieldset.html | 35 +++++++++++++ src/browser/tests/element/html/label.html | 18 +++++++ src/browser/tests/element/html/li.html | 23 +++++++++ src/browser/tests/element/html/ol.html | 51 +++++++++++++++++++ src/browser/tests/element/html/optgroup.html | 40 +++++++++++++++ src/browser/tests/element/html/quote.html | 17 +++++++ src/browser/tests/element/html/tablecell.html | 35 +++++++++++++ src/browser/tests/element/html/time.html | 17 +++++++ src/browser/webapi/element/html/FieldSet.zig | 29 +++++++++++ src/browser/webapi/element/html/LI.zig | 19 +++++++ src/browser/webapi/element/html/Label.zig | 16 ++++++ src/browser/webapi/element/html/OL.zig | 41 +++++++++++++++ src/browser/webapi/element/html/OptGroup.zig | 29 +++++++++++ src/browser/webapi/element/html/Quote.zig | 19 +++++++ src/browser/webapi/element/html/TableCell.zig | 30 +++++++++++ src/browser/webapi/element/html/Time.zig | 16 ++++++ 16 files changed, 435 insertions(+) create mode 100644 src/browser/tests/element/html/fieldset.html create mode 100644 src/browser/tests/element/html/label.html create mode 100644 src/browser/tests/element/html/li.html create mode 100644 src/browser/tests/element/html/ol.html create mode 100644 src/browser/tests/element/html/optgroup.html create mode 100644 src/browser/tests/element/html/quote.html create mode 100644 src/browser/tests/element/html/tablecell.html create mode 100644 src/browser/tests/element/html/time.html diff --git a/src/browser/tests/element/html/fieldset.html b/src/browser/tests/element/html/fieldset.html new file mode 100644 index 00000000..76c281d5 --- /dev/null +++ b/src/browser/tests/element/html/fieldset.html @@ -0,0 +1,35 @@ + + + +
+ +
+
+ +
+ + + + diff --git a/src/browser/tests/element/html/label.html b/src/browser/tests/element/html/label.html new file mode 100644 index 00000000..cdc3f637 --- /dev/null +++ b/src/browser/tests/element/html/label.html @@ -0,0 +1,18 @@ + + + + + + + diff --git a/src/browser/tests/element/html/li.html b/src/browser/tests/element/html/li.html new file mode 100644 index 00000000..62eea5dd --- /dev/null +++ b/src/browser/tests/element/html/li.html @@ -0,0 +1,23 @@ + + + +
    +
  1. Item
  2. +
  3. Item
  4. +
+ + diff --git a/src/browser/tests/element/html/ol.html b/src/browser/tests/element/html/ol.html new file mode 100644 index 00000000..8036e470 --- /dev/null +++ b/src/browser/tests/element/html/ol.html @@ -0,0 +1,51 @@ + + + +
    +
  1. Item
  2. +
+
    +
  1. Item
  2. +
+ + + + + + diff --git a/src/browser/tests/element/html/optgroup.html b/src/browser/tests/element/html/optgroup.html new file mode 100644 index 00000000..456f3de6 --- /dev/null +++ b/src/browser/tests/element/html/optgroup.html @@ -0,0 +1,40 @@ + + + + + + + + diff --git a/src/browser/tests/element/html/quote.html b/src/browser/tests/element/html/quote.html new file mode 100644 index 00000000..72a4c3ee --- /dev/null +++ b/src/browser/tests/element/html/quote.html @@ -0,0 +1,17 @@ + + + +
Quote
+ + diff --git a/src/browser/tests/element/html/tablecell.html b/src/browser/tests/element/html/tablecell.html new file mode 100644 index 00000000..d1667288 --- /dev/null +++ b/src/browser/tests/element/html/tablecell.html @@ -0,0 +1,35 @@ + + + + + + + + +
CellCell
+ + + + diff --git a/src/browser/tests/element/html/time.html b/src/browser/tests/element/html/time.html new file mode 100644 index 00000000..b1642642 --- /dev/null +++ b/src/browser/tests/element/html/time.html @@ -0,0 +1,17 @@ + + + + + + diff --git a/src/browser/webapi/element/html/FieldSet.zig b/src/browser/webapi/element/html/FieldSet.zig index 2b966e2f..1a71c92d 100644 --- a/src/browser/webapi/element/html/FieldSet.zig +++ b/src/browser/webapi/element/html/FieldSet.zig @@ -1,4 +1,5 @@ const js = @import("../../../js/js.zig"); +const Page = @import("../../../Page.zig"); const Node = @import("../../Node.zig"); const Element = @import("../../Element.zig"); const HtmlElement = @import("../Html.zig"); @@ -14,6 +15,26 @@ pub fn asNode(self: *FieldSet) *Node { return self.asElement().asNode(); } +pub fn getDisabled(self: *FieldSet) bool { + return self.asElement().getAttributeSafe(comptime .wrap("disabled")) != null; +} + +pub fn setDisabled(self: *FieldSet, value: bool, page: *Page) !void { + if (value) { + try self.asElement().setAttributeSafe(comptime .wrap("disabled"), .wrap(""), page); + } else { + try self.asElement().removeAttribute(comptime .wrap("disabled"), page); + } +} + +pub fn getName(self: *FieldSet) []const u8 { + return self.asElement().getAttributeSafe(comptime .wrap("name")) orelse ""; +} + +pub fn setName(self: *FieldSet, value: []const u8, page: *Page) !void { + try self.asElement().setAttributeSafe(comptime .wrap("name"), .wrap(value), page); +} + pub const JsApi = struct { pub const bridge = js.Bridge(FieldSet); @@ -22,4 +43,12 @@ pub const JsApi = struct { pub const prototype_chain = bridge.prototypeChain(); pub var class_id: bridge.ClassId = undefined; }; + + pub const disabled = bridge.accessor(FieldSet.getDisabled, FieldSet.setDisabled, .{}); + pub const name = bridge.accessor(FieldSet.getName, FieldSet.setName, .{}); }; + +const testing = @import("../../../../testing.zig"); +test "WebApi: HTML.FieldSet" { + try testing.htmlRunner("element/html/fieldset.html", .{}); +} diff --git a/src/browser/webapi/element/html/LI.zig b/src/browser/webapi/element/html/LI.zig index e0213020..9c7defbe 100644 --- a/src/browser/webapi/element/html/LI.zig +++ b/src/browser/webapi/element/html/LI.zig @@ -16,7 +16,9 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . +const std = @import("std"); const js = @import("../../../js/js.zig"); +const Page = @import("../../../Page.zig"); const Node = @import("../../Node.zig"); const Element = @import("../../Element.zig"); const HtmlElement = @import("../Html.zig"); @@ -31,6 +33,16 @@ pub fn asNode(self: *LI) *Node { return self.asElement().asNode(); } +pub fn getValue(self: *LI) i32 { + const attr = self.asElement().getAttributeSafe(comptime .wrap("value")) orelse return 0; + return std.fmt.parseInt(i32, attr, 10) catch 0; +} + +pub fn setValue(self: *LI, value: i32, page: *Page) !void { + const str = try std.fmt.allocPrint(page.call_arena, "{d}", .{value}); + try self.asElement().setAttributeSafe(comptime .wrap("value"), .wrap(str), page); +} + pub const JsApi = struct { pub const bridge = js.Bridge(LI); @@ -39,4 +51,11 @@ pub const JsApi = struct { pub const prototype_chain = bridge.prototypeChain(); pub var class_id: bridge.ClassId = undefined; }; + + pub const value = bridge.accessor(LI.getValue, LI.setValue, .{}); }; + +const testing = @import("../../../../testing.zig"); +test "WebApi: HTML.LI" { + try testing.htmlRunner("element/html/li.html", .{}); +} diff --git a/src/browser/webapi/element/html/Label.zig b/src/browser/webapi/element/html/Label.zig index a9c0243f..c08bff06 100644 --- a/src/browser/webapi/element/html/Label.zig +++ b/src/browser/webapi/element/html/Label.zig @@ -1,4 +1,5 @@ const js = @import("../../../js/js.zig"); +const Page = @import("../../../Page.zig"); const Node = @import("../../Node.zig"); const Element = @import("../../Element.zig"); const HtmlElement = @import("../Html.zig"); @@ -14,6 +15,14 @@ pub fn asNode(self: *Label) *Node { return self.asElement().asNode(); } +pub fn getHtmlFor(self: *Label) []const u8 { + return self.asElement().getAttributeSafe(comptime .wrap("for")) orelse ""; +} + +pub fn setHtmlFor(self: *Label, value: []const u8, page: *Page) !void { + try self.asElement().setAttributeSafe(comptime .wrap("for"), .wrap(value), page); +} + pub const JsApi = struct { pub const bridge = js.Bridge(Label); @@ -22,4 +31,11 @@ pub const JsApi = struct { pub const prototype_chain = bridge.prototypeChain(); pub var class_id: bridge.ClassId = undefined; }; + + pub const htmlFor = bridge.accessor(Label.getHtmlFor, Label.setHtmlFor, .{}); }; + +const testing = @import("../../../../testing.zig"); +test "WebApi: HTML.Label" { + try testing.htmlRunner("element/html/label.html", .{}); +} diff --git a/src/browser/webapi/element/html/OL.zig b/src/browser/webapi/element/html/OL.zig index 09f5eeaa..7001ae24 100644 --- a/src/browser/webapi/element/html/OL.zig +++ b/src/browser/webapi/element/html/OL.zig @@ -16,7 +16,9 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . +const std = @import("std"); const js = @import("../../../js/js.zig"); +const Page = @import("../../../Page.zig"); const Node = @import("../../Node.zig"); const Element = @import("../../Element.zig"); const HtmlElement = @import("../Html.zig"); @@ -31,6 +33,36 @@ pub fn asNode(self: *OL) *Node { return self.asElement().asNode(); } +pub fn getStart(self: *OL) i32 { + const attr = self.asElement().getAttributeSafe(comptime .wrap("start")) orelse return 1; + return std.fmt.parseInt(i32, attr, 10) catch 1; +} + +pub fn setStart(self: *OL, value: i32, page: *Page) !void { + const str = try std.fmt.allocPrint(page.call_arena, "{d}", .{value}); + try self.asElement().setAttributeSafe(comptime .wrap("start"), .wrap(str), page); +} + +pub fn getReversed(self: *OL) bool { + return self.asElement().getAttributeSafe(comptime .wrap("reversed")) != null; +} + +pub fn setReversed(self: *OL, value: bool, page: *Page) !void { + if (value) { + try self.asElement().setAttributeSafe(comptime .wrap("reversed"), .wrap(""), page); + } else { + try self.asElement().removeAttribute(comptime .wrap("reversed"), page); + } +} + +pub fn getType(self: *OL) []const u8 { + return self.asElement().getAttributeSafe(comptime .wrap("type")) orelse ""; +} + +pub fn setType(self: *OL, value: []const u8, page: *Page) !void { + try self.asElement().setAttributeSafe(comptime .wrap("type"), .wrap(value), page); +} + pub const JsApi = struct { pub const bridge = js.Bridge(OL); @@ -39,4 +71,13 @@ pub const JsApi = struct { pub const prototype_chain = bridge.prototypeChain(); pub var class_id: bridge.ClassId = undefined; }; + + pub const start = bridge.accessor(OL.getStart, OL.setStart, .{}); + pub const reversed = bridge.accessor(OL.getReversed, OL.setReversed, .{}); + pub const @"type" = bridge.accessor(OL.getType, OL.setType, .{}); }; + +const testing = @import("../../../../testing.zig"); +test "WebApi: HTML.OL" { + try testing.htmlRunner("element/html/ol.html", .{}); +} diff --git a/src/browser/webapi/element/html/OptGroup.zig b/src/browser/webapi/element/html/OptGroup.zig index 2ccab870..07d99e0b 100644 --- a/src/browser/webapi/element/html/OptGroup.zig +++ b/src/browser/webapi/element/html/OptGroup.zig @@ -1,4 +1,5 @@ const js = @import("../../../js/js.zig"); +const Page = @import("../../../Page.zig"); const Node = @import("../../Node.zig"); const Element = @import("../../Element.zig"); const HtmlElement = @import("../Html.zig"); @@ -14,6 +15,26 @@ pub fn asNode(self: *OptGroup) *Node { return self.asElement().asNode(); } +pub fn getDisabled(self: *OptGroup) bool { + return self.asElement().getAttributeSafe(comptime .wrap("disabled")) != null; +} + +pub fn setDisabled(self: *OptGroup, value: bool, page: *Page) !void { + if (value) { + try self.asElement().setAttributeSafe(comptime .wrap("disabled"), .wrap(""), page); + } else { + try self.asElement().removeAttribute(comptime .wrap("disabled"), page); + } +} + +pub fn getLabel(self: *OptGroup) []const u8 { + return self.asElement().getAttributeSafe(comptime .wrap("label")) orelse ""; +} + +pub fn setLabel(self: *OptGroup, value: []const u8, page: *Page) !void { + try self.asElement().setAttributeSafe(comptime .wrap("label"), .wrap(value), page); +} + pub const JsApi = struct { pub const bridge = js.Bridge(OptGroup); @@ -22,4 +43,12 @@ pub const JsApi = struct { pub const prototype_chain = bridge.prototypeChain(); pub var class_id: bridge.ClassId = undefined; }; + + pub const disabled = bridge.accessor(OptGroup.getDisabled, OptGroup.setDisabled, .{}); + pub const label = bridge.accessor(OptGroup.getLabel, OptGroup.setLabel, .{}); }; + +const testing = @import("../../../../testing.zig"); +test "WebApi: HTML.OptGroup" { + try testing.htmlRunner("element/html/optgroup.html", .{}); +} diff --git a/src/browser/webapi/element/html/Quote.zig b/src/browser/webapi/element/html/Quote.zig index 9d1ef3af..2cd02e74 100644 --- a/src/browser/webapi/element/html/Quote.zig +++ b/src/browser/webapi/element/html/Quote.zig @@ -1,5 +1,6 @@ const String = @import("../../../../string.zig").String; const js = @import("../../../js/js.zig"); +const Page = @import("../../../Page.zig"); const Node = @import("../../Node.zig"); const Element = @import("../../Element.zig"); const HtmlElement = @import("../Html.zig"); @@ -17,6 +18,17 @@ pub fn asNode(self: *Quote) *Node { return self.asElement().asNode(); } +pub fn getCite(self: *Quote, page: *Page) ![]const u8 { + const attr = self.asElement().getAttributeSafe(comptime .wrap("cite")) orelse return ""; + if (attr.len == 0) return ""; + const URL = @import("../../URL.zig"); + return URL.resolve(page.call_arena, page.base(), attr, .{}); +} + +pub fn setCite(self: *Quote, value: []const u8, page: *Page) !void { + try self.asElement().setAttributeSafe(comptime .wrap("cite"), .wrap(value), page); +} + pub const JsApi = struct { pub const bridge = js.Bridge(Quote); @@ -25,4 +37,11 @@ pub const JsApi = struct { pub const prototype_chain = bridge.prototypeChain(); pub var class_id: bridge.ClassId = undefined; }; + + pub const cite = bridge.accessor(Quote.getCite, Quote.setCite, .{}); }; + +const testing = @import("../../../../testing.zig"); +test "WebApi: HTML.Quote" { + try testing.htmlRunner("element/html/quote.html", .{}); +} diff --git a/src/browser/webapi/element/html/TableCell.zig b/src/browser/webapi/element/html/TableCell.zig index 95ebedb0..b8ddccca 100644 --- a/src/browser/webapi/element/html/TableCell.zig +++ b/src/browser/webapi/element/html/TableCell.zig @@ -1,5 +1,7 @@ +const std = @import("std"); const String = @import("../../../../string.zig").String; const js = @import("../../../js/js.zig"); +const Page = @import("../../../Page.zig"); const Node = @import("../../Node.zig"); const Element = @import("../../Element.zig"); const HtmlElement = @import("../Html.zig"); @@ -17,6 +19,26 @@ pub fn asNode(self: *TableCell) *Node { return self.asElement().asNode(); } +pub fn getColSpan(self: *TableCell) u32 { + const attr = self.asElement().getAttributeSafe(comptime .wrap("colspan")) orelse return 1; + return std.fmt.parseUnsigned(u32, attr, 10) catch 1; +} + +pub fn setColSpan(self: *TableCell, value: u32, page: *Page) !void { + const str = try std.fmt.allocPrint(page.call_arena, "{d}", .{value}); + try self.asElement().setAttributeSafe(comptime .wrap("colspan"), .wrap(str), page); +} + +pub fn getRowSpan(self: *TableCell) u32 { + const attr = self.asElement().getAttributeSafe(comptime .wrap("rowspan")) orelse return 1; + return std.fmt.parseUnsigned(u32, attr, 10) catch 1; +} + +pub fn setRowSpan(self: *TableCell, value: u32, page: *Page) !void { + const str = try std.fmt.allocPrint(page.call_arena, "{d}", .{value}); + try self.asElement().setAttributeSafe(comptime .wrap("rowspan"), .wrap(str), page); +} + pub const JsApi = struct { pub const bridge = js.Bridge(TableCell); @@ -25,4 +47,12 @@ pub const JsApi = struct { pub const prototype_chain = bridge.prototypeChain(); pub var class_id: bridge.ClassId = undefined; }; + + pub const colSpan = bridge.accessor(TableCell.getColSpan, TableCell.setColSpan, .{}); + pub const rowSpan = bridge.accessor(TableCell.getRowSpan, TableCell.setRowSpan, .{}); }; + +const testing = @import("../../../../testing.zig"); +test "WebApi: HTML.TableCell" { + try testing.htmlRunner("element/html/tablecell.html", .{}); +} diff --git a/src/browser/webapi/element/html/Time.zig b/src/browser/webapi/element/html/Time.zig index 3f3b1ef1..eb61d955 100644 --- a/src/browser/webapi/element/html/Time.zig +++ b/src/browser/webapi/element/html/Time.zig @@ -1,4 +1,5 @@ const js = @import("../../../js/js.zig"); +const Page = @import("../../../Page.zig"); const Node = @import("../../Node.zig"); const Element = @import("../../Element.zig"); const HtmlElement = @import("../Html.zig"); @@ -14,6 +15,14 @@ pub fn asNode(self: *Time) *Node { return self.asElement().asNode(); } +pub fn getDateTime(self: *Time) []const u8 { + return self.asElement().getAttributeSafe(comptime .wrap("datetime")) orelse ""; +} + +pub fn setDateTime(self: *Time, value: []const u8, page: *Page) !void { + try self.asElement().setAttributeSafe(comptime .wrap("datetime"), .wrap(value), page); +} + pub const JsApi = struct { pub const bridge = js.Bridge(Time); @@ -22,4 +31,11 @@ pub const JsApi = struct { pub const prototype_chain = bridge.prototypeChain(); pub var class_id: bridge.ClassId = undefined; }; + + pub const dateTime = bridge.accessor(Time.getDateTime, Time.setDateTime, .{}); }; + +const testing = @import("../../../../testing.zig"); +test "WebApi: HTML.Time" { + try testing.htmlRunner("element/html/time.html", .{}); +}