diff --git a/src/browser/tests/element/html/label.html b/src/browser/tests/element/html/label.html index cdc3f637..b2ebc2cb 100644 --- a/src/browser/tests/element/html/label.html +++ b/src/browser/tests/element/html/label.html @@ -16,3 +16,59 @@ testing.expectEqual('', l2.htmlFor); } + + + + + + + + + + + diff --git a/src/browser/webapi/element/html/Label.zig b/src/browser/webapi/element/html/Label.zig index c08bff06..1069f2c6 100644 --- a/src/browser/webapi/element/html/Label.zig +++ b/src/browser/webapi/element/html/Label.zig @@ -3,6 +3,7 @@ const Page = @import("../../../Page.zig"); const Node = @import("../../Node.zig"); const Element = @import("../../Element.zig"); const HtmlElement = @import("../Html.zig"); +const TreeWalker = @import("../../TreeWalker.zig"); const Label = @This(); @@ -23,6 +24,33 @@ pub fn setHtmlFor(self: *Label, value: []const u8, page: *Page) !void { try self.asElement().setAttributeSafe(comptime .wrap("for"), .wrap(value), page); } +pub fn getControl(self: *Label, page: *Page) ?*Element { + if (self.asElement().getAttributeSafe(comptime .wrap("for"))) |id| { + const el = page.document.getElementById(id, page) orelse return null; + if (!isLabelable(el)) { + return null; + } + return el; + } + + var tw = TreeWalker.FullExcludeSelf.Elements.init(self.asNode(), .{}); + while (tw.next()) |el| { + if (isLabelable(el)) { + return el; + } + } + return null; +} + +fn isLabelable(el: *Element) bool { + const html = el.is(HtmlElement) orelse return false; + return switch (html._type) { + .button, .meter, .output, .progress, .select, .textarea => true, + .input => |input| input._input_type != .hidden, + else => false, + }; +} + pub const JsApi = struct { pub const bridge = js.Bridge(Label); @@ -33,6 +61,7 @@ pub const JsApi = struct { }; pub const htmlFor = bridge.accessor(Label.getHtmlFor, Label.setHtmlFor, .{}); + pub const control = bridge.accessor(Label.getControl, null, .{}); }; const testing = @import("../../../../testing.zig");