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| {