mirror of
https://github.com/lightpanda-io/browser.git
synced 2025-10-29 07:03:29 +00:00
Merge pull request #740 from lightpanda-io/fix_anchor_href
Fix anchor href
This commit is contained in:
@@ -194,8 +194,10 @@ pub const HTMLAnchorElement = struct {
|
|||||||
return try parser.anchorGetHref(self);
|
return try parser.anchorGetHref(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_href(self: *parser.Anchor, href: []const u8) !void {
|
pub fn set_href(self: *parser.Anchor, href: []const u8, page: *const Page) !void {
|
||||||
return try parser.anchorSetHref(self, href);
|
const stitch = @import("../../url.zig").stitch;
|
||||||
|
const full = try stitch(page.call_arena, href, page.url.raw, .{});
|
||||||
|
return try parser.anchorSetHref(self, full);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_hreflang(self: *parser.Anchor) ![]const u8 {
|
pub fn get_hreflang(self: *parser.Anchor) ![]const u8 {
|
||||||
@@ -289,10 +291,9 @@ pub const HTMLAnchorElement = struct {
|
|||||||
try parser.anchorSetHref(self, href);
|
try parser.anchorSetHref(self, href);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO return a disposable string
|
|
||||||
pub fn get_hostname(self: *parser.Anchor, page: *Page) ![]const u8 {
|
pub fn get_hostname(self: *parser.Anchor, page: *Page) ![]const u8 {
|
||||||
var u = try url(self, page);
|
var u = try url(self, page);
|
||||||
return try page.arena.dupe(u8, u.get_hostname());
|
return u.get_hostname();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_hostname(self: *parser.Anchor, v: []const u8, page: *Page) !void {
|
pub fn set_hostname(self: *parser.Anchor, v: []const u8, page: *Page) !void {
|
||||||
@@ -326,7 +327,7 @@ pub const HTMLAnchorElement = struct {
|
|||||||
// TODO return a disposable string
|
// TODO return a disposable string
|
||||||
pub fn get_username(self: *parser.Anchor, page: *Page) ![]const u8 {
|
pub fn get_username(self: *parser.Anchor, page: *Page) ![]const u8 {
|
||||||
var u = try url(self, page);
|
var u = try url(self, page);
|
||||||
return try page.arena.dupe(u8, u.get_username());
|
return u.get_username();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_username(self: *parser.Anchor, v: ?[]const u8, page: *Page) !void {
|
pub fn set_username(self: *parser.Anchor, v: ?[]const u8, page: *Page) !void {
|
||||||
@@ -366,7 +367,7 @@ pub const HTMLAnchorElement = struct {
|
|||||||
// TODO return a disposable string
|
// TODO return a disposable string
|
||||||
pub fn get_pathname(self: *parser.Anchor, page: *Page) ![]const u8 {
|
pub fn get_pathname(self: *parser.Anchor, page: *Page) ![]const u8 {
|
||||||
var u = try url(self, page);
|
var u = try url(self, page);
|
||||||
return try page.arena.dupe(u8, u.get_pathname());
|
return u.get_pathname();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_pathname(self: *parser.Anchor, v: []const u8, page: *Page) !void {
|
pub fn set_pathname(self: *parser.Anchor, v: []const u8, page: *Page) !void {
|
||||||
@@ -1056,62 +1057,62 @@ test "Browser.HTML.Element" {
|
|||||||
defer runner.deinit();
|
defer runner.deinit();
|
||||||
|
|
||||||
try runner.testCases(&.{
|
try runner.testCases(&.{
|
||||||
.{ "let a = document.getElementById('link')", "undefined" },
|
.{ "let link = document.getElementById('link')", "undefined" },
|
||||||
.{ "a.target", "" },
|
.{ "link.target", "" },
|
||||||
.{ "a.target = '_blank'", "_blank" },
|
.{ "link.target = '_blank'", "_blank" },
|
||||||
.{ "a.target", "_blank" },
|
.{ "link.target", "_blank" },
|
||||||
.{ "a.target = ''", "" },
|
.{ "link.target = ''", "" },
|
||||||
|
|
||||||
.{ "a.href", "foo" },
|
.{ "link.href", "foo" },
|
||||||
.{ "a.href = 'https://lightpanda.io/'", "https://lightpanda.io/" },
|
.{ "link.href = 'https://lightpanda.io/'", "https://lightpanda.io/" },
|
||||||
.{ "a.href", "https://lightpanda.io/" },
|
.{ "link.href", "https://lightpanda.io/" },
|
||||||
|
|
||||||
.{ "a.origin", "https://lightpanda.io" },
|
.{ "link.origin", "https://lightpanda.io" },
|
||||||
|
|
||||||
.{ "a.host = 'lightpanda.io:443'", "lightpanda.io:443" },
|
.{ "link.host = 'lightpanda.io:443'", "lightpanda.io:443" },
|
||||||
.{ "a.host", "lightpanda.io:443" },
|
.{ "link.host", "lightpanda.io:443" },
|
||||||
.{ "a.port", "443" },
|
.{ "link.port", "443" },
|
||||||
.{ "a.hostname", "lightpanda.io" },
|
.{ "link.hostname", "lightpanda.io" },
|
||||||
|
|
||||||
.{ "a.host = 'lightpanda.io'", "lightpanda.io" },
|
.{ "link.host = 'lightpanda.io'", "lightpanda.io" },
|
||||||
.{ "a.host", "lightpanda.io" },
|
.{ "link.host", "lightpanda.io" },
|
||||||
.{ "a.port", "" },
|
.{ "link.port", "" },
|
||||||
.{ "a.hostname", "lightpanda.io" },
|
.{ "link.hostname", "lightpanda.io" },
|
||||||
|
|
||||||
.{ "a.host", "lightpanda.io" },
|
.{ "link.host", "lightpanda.io" },
|
||||||
.{ "a.hostname", "lightpanda.io" },
|
.{ "link.hostname", "lightpanda.io" },
|
||||||
.{ "a.hostname = 'foo.bar'", "foo.bar" },
|
.{ "link.hostname = 'foo.bar'", "foo.bar" },
|
||||||
.{ "a.href", "https://foo.bar/" },
|
.{ "link.href", "https://foo.bar/" },
|
||||||
|
|
||||||
.{ "a.search", "" },
|
.{ "link.search", "" },
|
||||||
.{ "a.search = 'q=bar'", "q=bar" },
|
.{ "link.search = 'q=bar'", "q=bar" },
|
||||||
.{ "a.search", "?q=bar" },
|
.{ "link.search", "?q=bar" },
|
||||||
.{ "a.href", "https://foo.bar/?q=bar" },
|
.{ "link.href", "https://foo.bar/?q=bar" },
|
||||||
|
|
||||||
.{ "a.hash", "" },
|
.{ "link.hash", "" },
|
||||||
.{ "a.hash = 'frag'", "frag" },
|
.{ "link.hash = 'frag'", "frag" },
|
||||||
.{ "a.hash", "#frag" },
|
.{ "link.hash", "#frag" },
|
||||||
.{ "a.href", "https://foo.bar/?q=bar#frag" },
|
.{ "link.href", "https://foo.bar/?q=bar#frag" },
|
||||||
|
|
||||||
.{ "a.port", "" },
|
.{ "link.port", "" },
|
||||||
.{ "a.port = '443'", "443" },
|
.{ "link.port = '443'", "443" },
|
||||||
.{ "a.host", "foo.bar:443" },
|
.{ "link.host", "foo.bar:443" },
|
||||||
.{ "a.hostname", "foo.bar" },
|
.{ "link.hostname", "foo.bar" },
|
||||||
.{ "a.href", "https://foo.bar:443/?q=bar#frag" },
|
.{ "link.href", "https://foo.bar:443/?q=bar#frag" },
|
||||||
.{ "a.port = null", "null" },
|
.{ "link.port = null", "null" },
|
||||||
.{ "a.href", "https://foo.bar/?q=bar#frag" },
|
.{ "link.href", "https://foo.bar/?q=bar#frag" },
|
||||||
|
|
||||||
.{ "a.href = 'foo'", "foo" },
|
.{ "link.href = 'foo'", "foo" },
|
||||||
|
|
||||||
.{ "a.type", "" },
|
.{ "link.type", "" },
|
||||||
.{ "a.type = 'text/html'", "text/html" },
|
.{ "link.type = 'text/html'", "text/html" },
|
||||||
.{ "a.type", "text/html" },
|
.{ "link.type", "text/html" },
|
||||||
.{ "a.type = ''", "" },
|
.{ "link.type = ''", "" },
|
||||||
|
|
||||||
.{ "a.text", "OK" },
|
.{ "link.text", "OK" },
|
||||||
.{ "a.text = 'foo'", "foo" },
|
.{ "link.text = 'foo'", "foo" },
|
||||||
.{ "a.text", "foo" },
|
.{ "link.text", "foo" },
|
||||||
.{ "a.text = 'OK'", "OK" },
|
.{ "link.text = 'OK'", "OK" },
|
||||||
}, .{});
|
}, .{});
|
||||||
|
|
||||||
try runner.testCases(&.{
|
try runner.testCases(&.{
|
||||||
@@ -1174,4 +1175,10 @@ test "Browser.HTML.Element" {
|
|||||||
.{ "lyric.src = 15", "15" },
|
.{ "lyric.src = 15", "15" },
|
||||||
.{ "lyric.src", "15" },
|
.{ "lyric.src", "15" },
|
||||||
}, .{});
|
}, .{});
|
||||||
|
|
||||||
|
try runner.testCases(&.{
|
||||||
|
.{ "let a = document.createElement('a');", null },
|
||||||
|
.{ "a.href = 'about'", null },
|
||||||
|
.{ "a.href", "https://lightpanda.io/opensource-browser/about" },
|
||||||
|
}, .{});
|
||||||
}
|
}
|
||||||
|
|||||||
52
src/url.zig
52
src/url.zig
@@ -4,6 +4,8 @@ const Uri = std.Uri;
|
|||||||
const Allocator = std.mem.Allocator;
|
const Allocator = std.mem.Allocator;
|
||||||
const WebApiURL = @import("browser/url/url.zig").URL;
|
const WebApiURL = @import("browser/url/url.zig").URL;
|
||||||
|
|
||||||
|
pub const stitch = URL.stitch;
|
||||||
|
|
||||||
pub const URL = struct {
|
pub const URL = struct {
|
||||||
uri: Uri,
|
uri: Uri,
|
||||||
raw: []const u8,
|
raw: []const u8,
|
||||||
@@ -91,6 +93,7 @@ pub const URL = struct {
|
|||||||
if_needed,
|
if_needed,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Properly stitches two URL fragments together.
|
/// Properly stitches two URL fragments together.
|
||||||
///
|
///
|
||||||
/// For URLs with a path, it will replace the last entry with the src.
|
/// For URLs with a path, it will replace the last entry with the src.
|
||||||
@@ -101,7 +104,7 @@ pub const URL = struct {
|
|||||||
base: []const u8,
|
base: []const u8,
|
||||||
opts: StitchOpts,
|
opts: StitchOpts,
|
||||||
) ![]const u8 {
|
) ![]const u8 {
|
||||||
if (base.len == 0) {
|
if (base.len == 0 or isURL(src)) {
|
||||||
if (opts.alloc == .always) {
|
if (opts.alloc == .always) {
|
||||||
return allocator.dupe(u8, src);
|
return allocator.dupe(u8, src);
|
||||||
}
|
}
|
||||||
@@ -154,7 +157,41 @@ pub const URL = struct {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
test "Url resolve size" {
|
fn isURL(url: []const u8) bool {
|
||||||
|
if (std.mem.startsWith(u8, url, "://")) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (url.len < 8) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!std.ascii.startsWithIgnoreCase(url, "http")) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var pos: usize = 4;
|
||||||
|
if (url[4] == 's' or url[4] == 'S') {
|
||||||
|
pos = 5;
|
||||||
|
}
|
||||||
|
return std.mem.startsWith(u8, url[pos..], "://");
|
||||||
|
}
|
||||||
|
|
||||||
|
const testing = @import("testing.zig");
|
||||||
|
test "URL: isURL" {
|
||||||
|
try testing.expectEqual(true, isURL("://lightpanda.io"));
|
||||||
|
try testing.expectEqual(true, isURL("://lightpanda.io/about"));
|
||||||
|
try testing.expectEqual(true, isURL("http://lightpanda.io/about"));
|
||||||
|
try testing.expectEqual(true, isURL("HttP://lightpanda.io/about"));
|
||||||
|
try testing.expectEqual(true, isURL("httpS://lightpanda.io/about"));
|
||||||
|
try testing.expectEqual(true, isURL("HTTPs://lightpanda.io/about"));
|
||||||
|
|
||||||
|
try testing.expectEqual(false, isURL("/lightpanda.io"));
|
||||||
|
try testing.expectEqual(false, isURL("../../about"));
|
||||||
|
try testing.expectEqual(false, isURL("about"));
|
||||||
|
}
|
||||||
|
|
||||||
|
test "URL: resolve size" {
|
||||||
const base = "https://www.lightpande.io";
|
const base = "https://www.lightpande.io";
|
||||||
const url = try URL.parse(base, null);
|
const url = try URL.parse(base, null);
|
||||||
|
|
||||||
@@ -170,8 +207,6 @@ test "Url resolve size" {
|
|||||||
try std.testing.expectEqualStrings(out_url.raw[26..], &url_string);
|
try std.testing.expectEqualStrings(out_url.raw[26..], &url_string);
|
||||||
}
|
}
|
||||||
|
|
||||||
const testing = @import("testing.zig");
|
|
||||||
|
|
||||||
test "URL: Stitching Base & Src URLs (Basic)" {
|
test "URL: Stitching Base & Src URLs (Basic)" {
|
||||||
const allocator = testing.allocator;
|
const allocator = testing.allocator;
|
||||||
|
|
||||||
@@ -212,6 +247,15 @@ test "URL: Stiching Base & Src URLs (Both Local)" {
|
|||||||
try testing.expectString("./abcdef/something.js", result);
|
try testing.expectString("./abcdef/something.js", result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test "URL: Stiching src as full path" {
|
||||||
|
const allocator = testing.allocator;
|
||||||
|
|
||||||
|
const base = "https://www.lightpanda.io/";
|
||||||
|
const src = "https://lightpanda.io/something.js";
|
||||||
|
const result = try URL.stitch(allocator, src, base, .{});
|
||||||
|
try testing.expectString("https://lightpanda.io/something.js", result);
|
||||||
|
}
|
||||||
|
|
||||||
test "URL: concatQueryString" {
|
test "URL: concatQueryString" {
|
||||||
defer testing.reset();
|
defer testing.reset();
|
||||||
const arena = testing.arena_allocator;
|
const arena = testing.arena_allocator;
|
||||||
|
|||||||
Reference in New Issue
Block a user