diff --git a/src/html/elements.zig b/src/html/elements.zig
index f7548d2f..9e77e7bb 100644
--- a/src/html/elements.zig
+++ b/src/html/elements.zig
@@ -15,10 +15,15 @@
//
// 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 parser = @import("../netsurf.zig");
const generate = @import("../generate.zig");
+const jsruntime = @import("jsruntime");
+const Case = jsruntime.test_utils.Case;
+const checkCases = jsruntime.test_utils.checkCases;
+
const Element = @import("../dom/element.zig").Element;
// HTMLElement interfaces
@@ -126,10 +131,31 @@ pub const HTMLUnknownElement = struct {
pub const mem_guarantied = true;
};
+// https://html.spec.whatwg.org/#the-a-element
pub const HTMLAnchorElement = struct {
pub const Self = parser.Anchor;
pub const prototype = *HTMLElement;
pub const mem_guarantied = true;
+
+ pub fn get_target(self: *parser.Anchor) ![]const u8 {
+ return try parser.anchorGetTarget(self);
+ }
+
+ pub fn set_target(self: *parser.Anchor, href: []const u8) !void {
+ return try parser.anchorSetTarget(self, href);
+ }
+
+ pub fn get_download(_: *parser.Anchor) ![]const u8 {
+ return ""; // TODO
+ }
+
+ pub fn get_href(self: *parser.Anchor) ![]const u8 {
+ return try parser.anchorGetHref(self);
+ }
+
+ pub fn set_href(self: *parser.Anchor, href: []const u8) !void {
+ return try parser.anchorSetTarget(self, href);
+ }
};
pub const HTMLAppletElement = struct {
@@ -589,3 +615,20 @@ pub fn toInterface(comptime T: type, e: *parser.Element) !T {
.undef => .{ .HTMLUnknownElement = @as(*parser.Unknown, @ptrCast(elem)) },
};
}
+
+// Tests
+// -----
+
+pub fn testExecFn(
+ _: std.mem.Allocator,
+ js_env: *jsruntime.Env,
+) anyerror!void {
+ var anchor = [_]Case{
+ .{ .src = "let a = document.getElementById('link')", .ex = "undefined" },
+ .{ .src = "a.target", .ex = "" },
+ .{ .src = "a.target = '_blank'", .ex = "_blank" },
+ .{ .src = "a.href", .ex = "foo" },
+ .{ .src = "a.href = 'https://lightpanda.io/'", .ex = "https://lightpanda.io/" },
+ };
+ try checkCases(js_env, &anchor);
+}
diff --git a/src/netsurf.zig b/src/netsurf.zig
index 7f225fe7..0d49de0a 100644
--- a/src/netsurf.zig
+++ b/src/netsurf.zig
@@ -1513,6 +1513,33 @@ pub fn elementHTMLGetTagType(elem_html: *ElementHTML) !Tag {
return @as(Tag, @enumFromInt(tag_type));
}
+// HTMLAnchorElement
+pub fn anchorGetTarget(a: *Anchor) ![]const u8 {
+ var res: ?*String = undefined;
+ const err = c.dom_html_anchor_element_get_target(a, &res);
+ try DOMErr(err);
+ if (res == null) return "";
+ return strToData(res.?);
+}
+
+pub fn anchorSetTarget(a: *Anchor, target: []const u8) !void {
+ const err = c.dom_html_anchor_element_set_target(a, try strFromData(target));
+ try DOMErr(err);
+}
+
+pub fn anchorGetHref(a: *Anchor) ![]const u8 {
+ var res: ?*String = undefined;
+ const err = c.dom_html_anchor_element_get_href(a, &res);
+ try DOMErr(err);
+ if (res == null) return "";
+ return strToData(res.?);
+}
+
+pub fn anchorSetHref(a: *Anchor, href: []const u8) !void {
+ const err = c.dom_html_anchor_element_set_href(a, try strFromData(href));
+ try DOMErr(err);
+}
+
// ElementsHTML
pub const MediaElement = struct { base: *c.dom_html_element };
diff --git a/src/run_tests.zig b/src/run_tests.zig
index 1d1583a7..3fe20b3f 100644
--- a/src/run_tests.zig
+++ b/src/run_tests.zig
@@ -51,6 +51,7 @@ const XHRTestExecFn = xhr.testExecFn;
const ProgressEventTestExecFn = @import("xhr/progress_event.zig").testExecFn;
const StorageTestExecFn = storage.testExecFn;
const URLTestExecFn = url.testExecFn;
+const HTMLElementTestExecFn = @import("html/elements.zig").testExecFn;
pub const Types = jsruntime.reflect(apiweb.Interfaces);
@@ -117,6 +118,7 @@ fn testsAllExecFn(
ProcessingInstructionTestExecFn,
StorageTestExecFn,
URLTestExecFn,
+ HTMLElementTestExecFn,
};
inline for (testFns) |testFn| {