From 6b42b5abdd35f499fd75413d2c2a56e313fc9d36 Mon Sep 17 00:00:00 2001 From: Pierre Tachoire Date: Mon, 13 May 2024 17:30:08 +0200 Subject: [PATCH] anchor: implement HTMLHyperlinkElementUtils interface https://html.spec.whatwg.org/#htmlhyperlinkelementutils --- src/html/elements.zig | 189 +++++++++++++++++++++++++++++++++++++++++- src/url/url.zig | 35 ++++++-- 2 files changed, 216 insertions(+), 8 deletions(-) diff --git a/src/html/elements.zig b/src/html/elements.zig index be030f44..d9ff0ce3 100644 --- a/src/html/elements.zig +++ b/src/html/elements.zig @@ -195,20 +195,182 @@ pub const HTMLAnchorElement = struct { return URL.constructor(alloc, href, null); // TODO inject base url } + // TODO return a disposable string + pub fn get_origin(self: *parser.Anchor, alloc: std.mem.Allocator) ![]const u8 { + var u = try url(self, alloc); + defer u.deinit(alloc); + + return try u.get_origin(alloc); + } + + // TODO return a disposable string + pub fn get_protocol(self: *parser.Anchor, alloc: std.mem.Allocator) ![]const u8 { + var u = try url(self, alloc); + defer u.deinit(alloc); + + return u.get_protocol(alloc); + } + + pub fn set_protocol(self: *parser.Anchor, alloc: std.mem.Allocator, v: []const u8) !void { + var u = try url(self, alloc); + defer u.deinit(alloc); + + u.uri.scheme = v; + const href = try u.format(alloc); + defer alloc.free(href); + + try parser.anchorSetHref(self, href); + } + // TODO return a disposable string pub fn get_host(self: *parser.Anchor, alloc: std.mem.Allocator) ![]const u8 { var u = try url(self, alloc); defer u.deinit(alloc); - return try alloc.dupe(u8, u.get_host()); + return try u.get_host(alloc); } pub fn set_host(self: *parser.Anchor, alloc: std.mem.Allocator, v: []const u8) !void { + _ = self; + _ = alloc; + _ = v; + // TODO + return error.NotImplemented; + } + + // TODO return a disposable string + pub fn get_hostname(self: *parser.Anchor, alloc: std.mem.Allocator) ![]const u8 { + var u = try url(self, alloc); + defer u.deinit(alloc); + + return try alloc.dupe(u8, u.get_hostname()); + } + + pub fn set_hostname(self: *parser.Anchor, alloc: std.mem.Allocator, v: []const u8) !void { var u = try url(self, alloc); defer u.deinit(alloc); u.uri.host = v; - const href = try u.get_href(alloc); + const href = try u.format(alloc); + try parser.anchorSetHref(self, href); + } + + // TODO return a disposable string + pub fn get_port(self: *parser.Anchor, alloc: std.mem.Allocator) ![]const u8 { + var u = try url(self, alloc); + defer u.deinit(alloc); + + return try u.get_port(alloc); + } + + pub fn set_port(self: *parser.Anchor, alloc: std.mem.Allocator, v: ?[]const u8) !void { + var u = try url(self, alloc); + defer u.deinit(alloc); + + if (v != null and v.?.len > 0) { + u.uri.port = try std.fmt.parseInt(u16, v.?, 10); + } else { + u.uri.port = null; + } + + const href = try u.format(alloc); + defer alloc.free(href); + + try parser.anchorSetHref(self, href); + } + + // TODO return a disposable string + pub fn get_username(self: *parser.Anchor, alloc: std.mem.Allocator) ![]const u8 { + var u = try url(self, alloc); + defer u.deinit(alloc); + + return try alloc.dupe(u8, u.get_username()); + } + + pub fn set_username(self: *parser.Anchor, alloc: std.mem.Allocator, v: ?[]const u8) !void { + var u = try url(self, alloc); + defer u.deinit(alloc); + + u.uri.user = v; + const href = try u.format(alloc); + defer alloc.free(href); + + try parser.anchorSetHref(self, href); + } + + // TODO return a disposable string + pub fn get_password(self: *parser.Anchor, alloc: std.mem.Allocator) ![]const u8 { + var u = try url(self, alloc); + defer u.deinit(alloc); + + return try alloc.dupe(u8, u.get_password()); + } + + pub fn set_password(self: *parser.Anchor, alloc: std.mem.Allocator, v: ?[]const u8) !void { + var u = try url(self, alloc); + defer u.deinit(alloc); + + u.uri.password = v; + const href = try u.format(alloc); + defer alloc.free(href); + + try parser.anchorSetHref(self, href); + } + + // TODO return a disposable string + pub fn get_pathname(self: *parser.Anchor, alloc: std.mem.Allocator) ![]const u8 { + var u = try url(self, alloc); + defer u.deinit(alloc); + + return try alloc.dupe(u8, u.get_pathname()); + } + + pub fn set_pathname(self: *parser.Anchor, alloc: std.mem.Allocator, v: []const u8) !void { + var u = try url(self, alloc); + defer u.deinit(alloc); + + u.uri.path = v; + const href = try u.format(alloc); + defer alloc.free(href); + + try parser.anchorSetHref(self, href); + } + + // TODO return a disposable string + pub fn get_search(self: *parser.Anchor, alloc: std.mem.Allocator) ![]const u8 { + var u = try url(self, alloc); + defer u.deinit(alloc); + + return try u.get_search(alloc); + } + + pub fn set_search(self: *parser.Anchor, alloc: std.mem.Allocator, v: ?[]const u8) !void { + var u = try url(self, alloc); + defer u.deinit(alloc); + + u.uri.query = v; + const href = try u.format(alloc); + defer alloc.free(href); + + try parser.anchorSetHref(self, href); + } + + // TODO return a disposable string + pub fn get_hash(self: *parser.Anchor, alloc: std.mem.Allocator) ![]const u8 { + var u = try url(self, alloc); + defer u.deinit(alloc); + + return try u.get_hash(alloc); + } + + pub fn set_hash(self: *parser.Anchor, alloc: std.mem.Allocator, v: ?[]const u8) !void { + var u = try url(self, alloc); + defer u.deinit(alloc); + + u.uri.fragment = v; + const href = try u.format(alloc); + defer alloc.free(href); + try parser.anchorSetHref(self, href); } @@ -691,10 +853,31 @@ pub fn testExecFn( .{ .src = "a.href = 'https://lightpanda.io/'", .ex = "https://lightpanda.io/" }, .{ .src = "a.href", .ex = "https://lightpanda.io/" }, + .{ .src = "a.origin", .ex = "https://lightpanda.io" }, + .{ .src = "a.host", .ex = "lightpanda.io" }, - .{ .src = "a.host = 'foo.bar'", .ex = "foo.bar" }, + .{ .src = "a.hostname", .ex = "lightpanda.io" }, + .{ .src = "a.hostname = 'foo.bar'", .ex = "foo.bar" }, .{ .src = "a.href", .ex = "https://foo.bar/" }, + .{ .src = "a.search", .ex = "" }, + .{ .src = "a.search = 'q=bar'", .ex = "q=bar" }, + .{ .src = "a.search", .ex = "?q=bar" }, + .{ .src = "a.href", .ex = "https://foo.bar/?q=bar" }, + + .{ .src = "a.hash", .ex = "" }, + .{ .src = "a.hash = 'frag'", .ex = "frag" }, + .{ .src = "a.hash", .ex = "#frag" }, + .{ .src = "a.href", .ex = "https://foo.bar/?q=bar#frag" }, + + .{ .src = "a.port", .ex = "" }, + .{ .src = "a.port = '443'", .ex = "443" }, + .{ .src = "a.host", .ex = "foo.bar:443" }, + .{ .src = "a.hostname", .ex = "foo.bar" }, + .{ .src = "a.href", .ex = "https://foo.bar:443/?q=bar#frag" }, + .{ .src = "a.port = null", .ex = "null" }, + .{ .src = "a.href", .ex = "https://foo.bar/?q=bar#frag" }, + .{ .src = "a.href = 'foo'", .ex = "foo" }, .{ .src = "a.type", .ex = "" }, diff --git a/src/url/url.zig b/src/url/url.zig index cf3ddfb3..978a11b7 100644 --- a/src/url/url.zig +++ b/src/url/url.zig @@ -71,6 +71,9 @@ pub const URL = struct { alloc.free(self.rawuri); } + // the caller must free the returned string. + // TODO return a disposable string + // https://github.com/lightpanda-io/jsruntime-lib/issues/195 pub fn get_origin(self: *URL, alloc: std.mem.Allocator) ![]const u8 { var buf = std.ArrayList(u8).init(alloc); defer buf.deinit(); @@ -86,13 +89,13 @@ pub const URL = struct { return try buf.toOwnedSlice(); } + // get_href returns the URL by writing all its components. + // The query is replaced by a dump of search params. + // // the caller must free the returned string. // TODO return a disposable string // https://github.com/lightpanda-io/jsruntime-lib/issues/195 pub fn get_href(self: *URL, alloc: std.mem.Allocator) ![]const u8 { - var buf = std.ArrayList(u8).init(alloc); - defer buf.deinit(); - // retrieve the query search from search_params. const cur = self.uri.query; defer self.uri.query = cur; @@ -101,6 +104,14 @@ pub const URL = struct { try self.search_params.values.encode(q.writer()); self.uri.query = q.items; + return try self.format(alloc); + } + + // format the url with all its components. + pub fn format(self: *URL, alloc: std.mem.Allocator) ![]const u8 { + var buf = std.ArrayList(u8).init(alloc); + defer buf.deinit(); + try self.uri.writeToStream(.{ .scheme = true, .authentication = true, @@ -127,8 +138,22 @@ pub const URL = struct { return self.uri.password orelse ""; } - pub fn get_host(self: *URL) []const u8 { - return self.uri.host orelse ""; + // the caller must free the returned string. + // TODO return a disposable string + // https://github.com/lightpanda-io/jsruntime-lib/issues/195 + pub fn get_host(self: *URL, alloc: std.mem.Allocator) ![]const u8 { + var buf = std.ArrayList(u8).init(alloc); + defer buf.deinit(); + + try self.uri.writeToStream(.{ + .scheme = false, + .authentication = false, + .authority = true, + .path = false, + .query = false, + .fragment = false, + }, buf.writer()); + return try buf.toOwnedSlice(); } pub fn get_hostname(self: *URL) []const u8 {