mirror of
https://github.com/lightpanda-io/browser.git
synced 2025-10-29 15:13:28 +00:00
Merge pull request #234 from lightpanda-io/html-anchor
dom: add target and href accessors to anchor
This commit is contained in:
@@ -15,11 +15,17 @@
|
|||||||
//
|
//
|
||||||
// You should have received a copy of the GNU Affero General Public License
|
// You should have received a copy of the GNU Affero General Public License
|
||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
const std = @import("std");
|
||||||
|
|
||||||
const parser = @import("../netsurf.zig");
|
const parser = @import("../netsurf.zig");
|
||||||
const generate = @import("../generate.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;
|
const Element = @import("../dom/element.zig").Element;
|
||||||
|
const URL = @import("../url/url.zig").URL;
|
||||||
|
|
||||||
// HTMLElement interfaces
|
// HTMLElement interfaces
|
||||||
pub const Interfaces = .{
|
pub const Interfaces = .{
|
||||||
@@ -126,10 +132,270 @@ pub const HTMLUnknownElement = struct {
|
|||||||
pub const mem_guarantied = true;
|
pub const mem_guarantied = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// https://html.spec.whatwg.org/#the-a-element
|
||||||
pub const HTMLAnchorElement = struct {
|
pub const HTMLAnchorElement = struct {
|
||||||
pub const Self = parser.Anchor;
|
pub const Self = parser.Anchor;
|
||||||
pub const prototype = *HTMLElement;
|
pub const prototype = *HTMLElement;
|
||||||
pub const mem_guarantied = true;
|
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.anchorSetHref(self, href);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_hreflang(self: *parser.Anchor) ![]const u8 {
|
||||||
|
return try parser.anchorGetHrefLang(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_hreflang(self: *parser.Anchor, href: []const u8) !void {
|
||||||
|
return try parser.anchorSetHrefLang(self, href);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_type(self: *parser.Anchor) ![]const u8 {
|
||||||
|
return try parser.anchorGetType(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_type(self: *parser.Anchor, t: []const u8) !void {
|
||||||
|
return try parser.anchorSetType(self, t);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_rel(self: *parser.Anchor) ![]const u8 {
|
||||||
|
return try parser.anchorGetRel(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_rel(self: *parser.Anchor, t: []const u8) !void {
|
||||||
|
return try parser.anchorSetRel(self, t);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_text(self: *parser.Anchor) !?[]const u8 {
|
||||||
|
return try parser.nodeTextContent(parser.anchorToNode(self));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_text(self: *parser.Anchor, v: []const u8) !void {
|
||||||
|
return try parser.nodeSetTextContent(parser.anchorToNode(self), v);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fn url(self: *parser.Anchor, alloc: std.mem.Allocator) !URL {
|
||||||
|
const href = try parser.anchorGetHref(self);
|
||||||
|
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 u.get_host(alloc);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_host(self: *parser.Anchor, alloc: std.mem.Allocator, v: []const u8) !void {
|
||||||
|
// search : separator
|
||||||
|
var p: ?u16 = null;
|
||||||
|
var h: []const u8 = undefined;
|
||||||
|
for (v, 0..) |c, i| {
|
||||||
|
if (c == ':') {
|
||||||
|
h = v[0..i];
|
||||||
|
p = try std.fmt.parseInt(u16, v[i + 1 ..], 10);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var u = try url(self, alloc);
|
||||||
|
defer u.deinit(alloc);
|
||||||
|
|
||||||
|
if (p) |pp| {
|
||||||
|
u.uri.host = h;
|
||||||
|
u.uri.port = pp;
|
||||||
|
} else {
|
||||||
|
u.uri.host = v;
|
||||||
|
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_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.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);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deinit(_: *parser.Anchor, _: std.mem.Allocator) void {}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const HTMLAppletElement = struct {
|
pub const HTMLAppletElement = struct {
|
||||||
@@ -408,10 +674,120 @@ pub const HTMLQuoteElement = struct {
|
|||||||
pub const mem_guarantied = true;
|
pub const mem_guarantied = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// https://html.spec.whatwg.org/#the-script-element
|
||||||
pub const HTMLScriptElement = struct {
|
pub const HTMLScriptElement = struct {
|
||||||
pub const Self = parser.Script;
|
pub const Self = parser.Script;
|
||||||
pub const prototype = *HTMLElement;
|
pub const prototype = *HTMLElement;
|
||||||
pub const mem_guarantied = true;
|
pub const mem_guarantied = true;
|
||||||
|
|
||||||
|
pub fn get_src(self: *parser.Script) !?[]const u8 {
|
||||||
|
return try parser.elementGetAttribute(
|
||||||
|
parser.scriptToElt(self),
|
||||||
|
"src",
|
||||||
|
) orelse "";
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_src(self: *parser.Script, v: []const u8) !void {
|
||||||
|
return try parser.elementSetAttribute(
|
||||||
|
parser.scriptToElt(self),
|
||||||
|
"src",
|
||||||
|
v,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_type(self: *parser.Script) !?[]const u8 {
|
||||||
|
return try parser.elementGetAttribute(
|
||||||
|
parser.scriptToElt(self),
|
||||||
|
"type",
|
||||||
|
) orelse "";
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_type(self: *parser.Script, v: []const u8) !void {
|
||||||
|
return try parser.elementSetAttribute(
|
||||||
|
parser.scriptToElt(self),
|
||||||
|
"type",
|
||||||
|
v,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_text(self: *parser.Script) !?[]const u8 {
|
||||||
|
return try parser.elementGetAttribute(
|
||||||
|
parser.scriptToElt(self),
|
||||||
|
"text",
|
||||||
|
) orelse "";
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_text(self: *parser.Script, v: []const u8) !void {
|
||||||
|
return try parser.elementSetAttribute(
|
||||||
|
parser.scriptToElt(self),
|
||||||
|
"text",
|
||||||
|
v,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_integrity(self: *parser.Script) !?[]const u8 {
|
||||||
|
return try parser.elementGetAttribute(
|
||||||
|
parser.scriptToElt(self),
|
||||||
|
"integrity",
|
||||||
|
) orelse "";
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_integrity(self: *parser.Script, v: []const u8) !void {
|
||||||
|
return try parser.elementSetAttribute(
|
||||||
|
parser.scriptToElt(self),
|
||||||
|
"integrity",
|
||||||
|
v,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_async(self: *parser.Script) !bool {
|
||||||
|
_ = try parser.elementGetAttribute(
|
||||||
|
parser.scriptToElt(self),
|
||||||
|
"async",
|
||||||
|
) orelse return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_async(self: *parser.Script, v: bool) !void {
|
||||||
|
if (v) {
|
||||||
|
return try parser.elementSetAttribute(parser.scriptToElt(self), "async", "");
|
||||||
|
}
|
||||||
|
|
||||||
|
return try parser.elementRemoveAttribute(parser.scriptToElt(self), "async");
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_defer(self: *parser.Script) !bool {
|
||||||
|
_ = try parser.elementGetAttribute(
|
||||||
|
parser.scriptToElt(self),
|
||||||
|
"defer",
|
||||||
|
) orelse false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_defer(self: *parser.Script, v: bool) !void {
|
||||||
|
if (v) {
|
||||||
|
return try parser.elementSetAttribute(parser.scriptToElt(self), "defer", "");
|
||||||
|
}
|
||||||
|
|
||||||
|
return try parser.elementRemoveAttribute(parser.scriptToElt(self), "defer");
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_noModule(self: *parser.Script) !bool {
|
||||||
|
_ = try parser.elementGetAttribute(
|
||||||
|
parser.scriptToElt(self),
|
||||||
|
"nomodule",
|
||||||
|
) orelse false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_noModule(self: *parser.Script, v: bool) !void {
|
||||||
|
if (v) {
|
||||||
|
return try parser.elementSetAttribute(parser.scriptToElt(self), "nomodule", "");
|
||||||
|
}
|
||||||
|
|
||||||
|
return try parser.elementRemoveAttribute(parser.scriptToElt(self), "nomodule");
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const HTMLSelectElement = struct {
|
pub const HTMLSelectElement = struct {
|
||||||
@@ -589,3 +965,82 @@ pub fn toInterface(comptime T: type, e: *parser.Element) !T {
|
|||||||
.undef => .{ .HTMLUnknownElement = @as(*parser.Unknown, @ptrCast(elem)) },
|
.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.target", .ex = "_blank" },
|
||||||
|
.{ .src = "a.target = ''", .ex = "" },
|
||||||
|
|
||||||
|
.{ .src = "a.href", .ex = "foo" },
|
||||||
|
.{ .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 = 'lightpanda.io:443'", .ex = "lightpanda.io:443" },
|
||||||
|
.{ .src = "a.host", .ex = "lightpanda.io:443" },
|
||||||
|
.{ .src = "a.port", .ex = "443" },
|
||||||
|
.{ .src = "a.hostname", .ex = "lightpanda.io" },
|
||||||
|
|
||||||
|
.{ .src = "a.host = 'lightpanda.io'", .ex = "lightpanda.io" },
|
||||||
|
.{ .src = "a.host", .ex = "lightpanda.io" },
|
||||||
|
.{ .src = "a.port", .ex = "" },
|
||||||
|
.{ .src = "a.hostname", .ex = "lightpanda.io" },
|
||||||
|
|
||||||
|
.{ .src = "a.host", .ex = "lightpanda.io" },
|
||||||
|
.{ .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 = "" },
|
||||||
|
.{ .src = "a.type = 'text/html'", .ex = "text/html" },
|
||||||
|
.{ .src = "a.type", .ex = "text/html" },
|
||||||
|
.{ .src = "a.type = ''", .ex = "" },
|
||||||
|
|
||||||
|
.{ .src = "a.text", .ex = "OK" },
|
||||||
|
.{ .src = "a.text = 'foo'", .ex = "foo" },
|
||||||
|
.{ .src = "a.text", .ex = "foo" },
|
||||||
|
.{ .src = "a.text = 'OK'", .ex = "OK" },
|
||||||
|
};
|
||||||
|
try checkCases(js_env, &anchor);
|
||||||
|
|
||||||
|
var script = [_]Case{
|
||||||
|
.{ .src = "let script = document.createElement('script')", .ex = "undefined" },
|
||||||
|
.{ .src = "script.src = 'foo.bar'", .ex = "foo.bar" },
|
||||||
|
|
||||||
|
.{ .src = "script.async = true", .ex = "true" },
|
||||||
|
.{ .src = "script.async", .ex = "true" },
|
||||||
|
.{ .src = "script.async = false", .ex = "false" },
|
||||||
|
.{ .src = "script.async", .ex = "false" },
|
||||||
|
};
|
||||||
|
try checkCases(js_env, &script);
|
||||||
|
}
|
||||||
|
|||||||
@@ -1513,6 +1513,85 @@ pub fn elementHTMLGetTagType(elem_html: *ElementHTML) !Tag {
|
|||||||
return @as(Tag, @enumFromInt(tag_type));
|
return @as(Tag, @enumFromInt(tag_type));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// HTMLScriptElement
|
||||||
|
|
||||||
|
// scriptToElt is an helper to convert an script to an element.
|
||||||
|
pub inline fn scriptToElt(s: *Script) *Element {
|
||||||
|
return @as(*Element, @ptrCast(s));
|
||||||
|
}
|
||||||
|
|
||||||
|
// HTMLAnchorElement
|
||||||
|
|
||||||
|
// anchorToNode is an helper to convert an anchor to a node.
|
||||||
|
pub inline fn anchorToNode(a: *Anchor) *Node {
|
||||||
|
return @as(*Node, @ptrCast(a));
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn anchorGetHrefLang(a: *Anchor) ![]const u8 {
|
||||||
|
var res: ?*String = undefined;
|
||||||
|
const err = c.dom_html_anchor_element_get_hreflang(a, &res);
|
||||||
|
try DOMErr(err);
|
||||||
|
if (res == null) return "";
|
||||||
|
return strToData(res.?);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn anchorSetHrefLang(a: *Anchor, href: []const u8) !void {
|
||||||
|
const err = c.dom_html_anchor_element_set_hreflang(a, try strFromData(href));
|
||||||
|
try DOMErr(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn anchorGetType(a: *Anchor) ![]const u8 {
|
||||||
|
var res: ?*String = undefined;
|
||||||
|
const err = c.dom_html_anchor_element_get_type(a, &res);
|
||||||
|
try DOMErr(err);
|
||||||
|
if (res == null) return "";
|
||||||
|
return strToData(res.?);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn anchorSetType(a: *Anchor, t: []const u8) !void {
|
||||||
|
const err = c.dom_html_anchor_element_set_type(a, try strFromData(t));
|
||||||
|
try DOMErr(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn anchorGetRel(a: *Anchor) ![]const u8 {
|
||||||
|
var res: ?*String = undefined;
|
||||||
|
const err = c.dom_html_anchor_element_get_rel(a, &res);
|
||||||
|
try DOMErr(err);
|
||||||
|
if (res == null) return "";
|
||||||
|
return strToData(res.?);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn anchorSetRel(a: *Anchor, rel: []const u8) !void {
|
||||||
|
const err = c.dom_html_anchor_element_set_rel(a, try strFromData(rel));
|
||||||
|
try DOMErr(err);
|
||||||
|
}
|
||||||
|
|
||||||
// ElementsHTML
|
// ElementsHTML
|
||||||
|
|
||||||
pub const MediaElement = struct { base: *c.dom_html_element };
|
pub const MediaElement = struct { base: *c.dom_html_element };
|
||||||
|
|||||||
@@ -51,6 +51,7 @@ const XHRTestExecFn = xhr.testExecFn;
|
|||||||
const ProgressEventTestExecFn = @import("xhr/progress_event.zig").testExecFn;
|
const ProgressEventTestExecFn = @import("xhr/progress_event.zig").testExecFn;
|
||||||
const StorageTestExecFn = storage.testExecFn;
|
const StorageTestExecFn = storage.testExecFn;
|
||||||
const URLTestExecFn = url.testExecFn;
|
const URLTestExecFn = url.testExecFn;
|
||||||
|
const HTMLElementTestExecFn = @import("html/elements.zig").testExecFn;
|
||||||
|
|
||||||
pub const Types = jsruntime.reflect(apiweb.Interfaces);
|
pub const Types = jsruntime.reflect(apiweb.Interfaces);
|
||||||
|
|
||||||
@@ -117,6 +118,7 @@ fn testsAllExecFn(
|
|||||||
ProcessingInstructionTestExecFn,
|
ProcessingInstructionTestExecFn,
|
||||||
StorageTestExecFn,
|
StorageTestExecFn,
|
||||||
URLTestExecFn,
|
URLTestExecFn,
|
||||||
|
HTMLElementTestExecFn,
|
||||||
};
|
};
|
||||||
|
|
||||||
inline for (testFns) |testFn| {
|
inline for (testFns) |testFn| {
|
||||||
|
|||||||
@@ -67,17 +67,35 @@ pub const URL = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(self: *URL, alloc: std.mem.Allocator) void {
|
pub fn deinit(self: *URL, alloc: std.mem.Allocator) void {
|
||||||
self.search_params.deinit();
|
self.search_params.deinit(alloc);
|
||||||
alloc.free(self.rawuri);
|
alloc.free(self.rawuri);
|
||||||
}
|
}
|
||||||
|
|
||||||
// the caller must free the returned string.
|
// the caller must free the returned string.
|
||||||
// TODO return a disposable string
|
// TODO return a disposable string
|
||||||
// https://github.com/lightpanda-io/jsruntime-lib/issues/195
|
// https://github.com/lightpanda-io/jsruntime-lib/issues/195
|
||||||
pub fn get_href(self: *URL, alloc: std.mem.Allocator) ![]const u8 {
|
pub fn get_origin(self: *URL, alloc: std.mem.Allocator) ![]const u8 {
|
||||||
var buf = std.ArrayList(u8).init(alloc);
|
var buf = std.ArrayList(u8).init(alloc);
|
||||||
defer buf.deinit();
|
defer buf.deinit();
|
||||||
|
|
||||||
|
try self.uri.writeToStream(.{
|
||||||
|
.scheme = true,
|
||||||
|
.authentication = false,
|
||||||
|
.authority = true,
|
||||||
|
.path = false,
|
||||||
|
.query = false,
|
||||||
|
.fragment = false,
|
||||||
|
}, buf.writer());
|
||||||
|
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 {
|
||||||
// retrieve the query search from search_params.
|
// retrieve the query search from search_params.
|
||||||
const cur = self.uri.query;
|
const cur = self.uri.query;
|
||||||
defer self.uri.query = cur;
|
defer self.uri.query = cur;
|
||||||
@@ -86,13 +104,21 @@ pub const URL = struct {
|
|||||||
try self.search_params.values.encode(q.writer());
|
try self.search_params.values.encode(q.writer());
|
||||||
self.uri.query = q.items;
|
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(.{
|
try self.uri.writeToStream(.{
|
||||||
.scheme = true,
|
.scheme = true,
|
||||||
.authentication = true,
|
.authentication = true,
|
||||||
.authority = true,
|
.authority = true,
|
||||||
.path = true,
|
.path = self.uri.path.len > 0,
|
||||||
.query = true,
|
.query = self.uri.query != null and self.uri.query.?.len > 0,
|
||||||
.fragment = true,
|
.fragment = self.uri.fragment != null and self.uri.fragment.?.len > 0,
|
||||||
}, buf.writer());
|
}, buf.writer());
|
||||||
return try buf.toOwnedSlice();
|
return try buf.toOwnedSlice();
|
||||||
}
|
}
|
||||||
@@ -112,8 +138,22 @@ pub const URL = struct {
|
|||||||
return self.uri.password orelse "";
|
return self.uri.password orelse "";
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_host(self: *URL) []const u8 {
|
// the caller must free the returned string.
|
||||||
return self.uri.host orelse "";
|
// 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 {
|
pub fn get_hostname(self: *URL) []const u8 {
|
||||||
@@ -223,6 +263,7 @@ pub fn testExecFn(
|
|||||||
) anyerror!void {
|
) anyerror!void {
|
||||||
var url = [_]Case{
|
var url = [_]Case{
|
||||||
.{ .src = "var url = new URL('https://foo.bar/path?query#fragment')", .ex = "undefined" },
|
.{ .src = "var url = new URL('https://foo.bar/path?query#fragment')", .ex = "undefined" },
|
||||||
|
.{ .src = "url.origin", .ex = "https://foo.bar" },
|
||||||
.{ .src = "url.href", .ex = "https://foo.bar/path?query#fragment" },
|
.{ .src = "url.href", .ex = "https://foo.bar/path?query#fragment" },
|
||||||
.{ .src = "url.protocol", .ex = "https:" },
|
.{ .src = "url.protocol", .ex = "https:" },
|
||||||
.{ .src = "url.username", .ex = "" },
|
.{ .src = "url.username", .ex = "" },
|
||||||
|
|||||||
Reference in New Issue
Block a user