Skip to content

Commit bede244

Browse files
authored
Merge pull request #934 from lightpanda-io/with-base
add a --with_base option to fetch
2 parents 4df48c9 + dc23a74 commit bede244

File tree

3 files changed

+61
-5
lines changed

3 files changed

+61
-5
lines changed

src/browser/dom/node.zig

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,9 @@ pub const Node = struct {
111111
// --------
112112

113113
// Read-only attributes
114+
pub fn get_baseURI(_: *parser.Node, page: *Page) ![]const u8 {
115+
return page.url.raw;
116+
}
114117

115118
pub fn get_firstChild(self: *parser.Node) !?Union {
116119
const res = try parser.nodeFirstChild(self);
@@ -737,6 +740,10 @@ test "Browser.DOM.node" {
737740
.{ "link.normalize()", "undefined" },
738741
}, .{});
739742

743+
try runner.testCases(&.{
744+
.{ "link.baseURI", "https://lightpanda.io/opensource-browser/" },
745+
}, .{});
746+
740747
try runner.testCases(&.{
741748
.{ "content.removeChild(append) !== undefined", "true" },
742749
.{ "last_child.__proto__.constructor.name !== 'HTMLHeadingElement'", "true" },

src/browser/page.zig

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -141,16 +141,47 @@ pub const Page = struct {
141141
repeat_delay.* = 100 * std.time.ns_per_ms;
142142
}
143143

144+
pub const DumpOpts = struct {
145+
exclude_scripts: bool = false,
146+
with_base: bool = false,
147+
};
148+
144149
// dump writes the page content into the given file.
145-
pub fn dump(self: *const Page, opts: Dump.Opts, out: std.fs.File) !void {
150+
pub fn dump(self: *const Page, opts: DumpOpts, out: std.fs.File) !void {
146151
if (self.raw_data) |raw_data| {
147152
// raw_data was set if the document was not HTML, dump the data content only.
148153
return try out.writeAll(raw_data);
149154
}
150155

151156
// if the page has a pointer to a document, dumps the HTML.
152157
const doc = parser.documentHTMLToDocument(self.window.document);
153-
try Dump.writeHTML(doc, opts, out);
158+
159+
// if the base si requested, add the base's node in the document's headers.
160+
if (opts.with_base) {
161+
try self.addDOMTreeBase();
162+
}
163+
164+
try Dump.writeHTML(doc, .{
165+
.exclude_scripts = opts.exclude_scripts,
166+
}, out);
167+
}
168+
169+
// addDOMTreeBase modifies the page's document to add a <base> tag after
170+
// <head>.
171+
// If <head> is missing, the function returns silently.
172+
fn addDOMTreeBase(self: *const Page) !void {
173+
const doc = parser.documentHTMLToDocument(self.window.document);
174+
std.debug.assert(doc.is_html);
175+
176+
// find <head> tag
177+
const list = try parser.documentGetElementsByTagName(doc, "head");
178+
const head = try parser.nodeListItem(list, 0) orelse return;
179+
180+
const base = try parser.documentCreateElement(doc, "base");
181+
try parser.elementSetAttribute(base, "href", self.url.raw);
182+
183+
const Node = @import("dom/node.zig").Node;
184+
try Node.prepend(head, &[_]Node.NodeOrText{.{ .node = parser.elementToNode(base) }});
154185
}
155186

156187
pub fn fetchModuleSource(ctx: *anyopaque, src: []const u8) !?[]const u8 {

src/main.zig

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,10 @@ fn run(alloc: Allocator) !void {
134134

135135
// dump
136136
if (opts.dump) {
137-
try page.dump(.{ .exclude_scripts = opts.noscript }, std.io.getStdOut());
137+
try page.dump(.{
138+
.exclude_scripts = opts.noscript,
139+
.with_base = opts.withbase,
140+
}, std.io.getStdOut());
138141
}
139142
},
140143
else => unreachable,
@@ -213,6 +216,7 @@ const Command = struct {
213216
dump: bool = false,
214217
common: Common,
215218
noscript: bool = false,
219+
withbase: bool = false,
216220
};
217221

218222
const Common = struct {
@@ -277,6 +281,7 @@ const Command = struct {
277281
\\--dump Dumps document to stdout.
278282
\\ Defaults to false.
279283
\\--noscript Exclude <script> tags in dump. Defaults to false.
284+
\\--with_base Add a <base> tag in dump. Defaults to false.
280285
\\
281286
++ common_options ++
282287
\\
@@ -351,13 +356,19 @@ fn inferMode(opt: []const u8) ?App.RunMode {
351356
return .serve;
352357
}
353358

359+
if (std.mem.startsWith(u8, opt, "--") == false) {
360+
return .fetch;
361+
}
362+
354363
if (std.mem.eql(u8, opt, "--dump")) {
355364
return .fetch;
356365
}
366+
357367
if (std.mem.eql(u8, opt, "--noscript")) {
358368
return .fetch;
359369
}
360-
if (std.mem.startsWith(u8, opt, "--") == false) {
370+
371+
if (std.mem.eql(u8, opt, "--with_base")) {
361372
return .fetch;
362373
}
363374

@@ -442,7 +453,8 @@ fn parseFetchArgs(
442453
args: *std.process.ArgIterator,
443454
) !Command.Fetch {
444455
var dump: bool = false;
445-
var noscript: bool = true;
456+
var noscript: bool = false;
457+
var withbase: bool = false;
446458
var url: ?[]const u8 = null;
447459
var common: Command.Common = .{};
448460

@@ -457,6 +469,11 @@ fn parseFetchArgs(
457469
continue;
458470
}
459471

472+
if (std.mem.eql(u8, "--with_base", opt)) {
473+
withbase = true;
474+
continue;
475+
}
476+
460477
if (try parseCommonArg(allocator, opt, args, &common)) {
461478
continue;
462479
}
@@ -483,6 +500,7 @@ fn parseFetchArgs(
483500
.dump = dump,
484501
.common = common,
485502
.noscript = noscript,
503+
.withbase = withbase,
486504
};
487505
}
488506

0 commit comments

Comments
 (0)