diff --git a/src/Config.zig b/src/Config.zig index ddef91be..2fb59dfc 100644 --- a/src/Config.zig +++ b/src/Config.zig @@ -191,7 +191,8 @@ pub const Fetch = struct { url: [:0]const u8, dump_mode: ?DumpFormat = null, common: Common = .{}, - withbase: bool = false, + with_base: bool = false, + with_frames: bool = false, strip: dump.Opts.Strip = .{}, }; @@ -342,6 +343,8 @@ pub fn printUsageAndExit(self: *const Config, success: bool) void { \\ \\--with_base Add a tag in dump. Defaults to false. \\ + \\--with_frames Includes the contents of iframes. Defaults to false. + \\ ++ common_options ++ \\ \\serve command @@ -440,6 +443,10 @@ fn inferMode(opt: []const u8) ?RunMode { return .fetch; } + if (std.mem.eql(u8, opt, "--with_frames")) { + return .fetch; + } + if (std.mem.eql(u8, opt, "--host")) { return .serve; } @@ -539,7 +546,8 @@ fn parseFetchArgs( args: *std.process.ArgIterator, ) !Fetch { var dump_mode: ?DumpFormat = null; - var withbase: bool = false; + var with_base: bool = false; + var with_frames: bool = false; var url: ?[:0]const u8 = null; var common: Common = .{}; var strip: dump.Opts.Strip = .{}; @@ -570,7 +578,12 @@ fn parseFetchArgs( } if (std.mem.eql(u8, "--with_base", opt)) { - withbase = true; + with_base = true; + continue; + } + + if (std.mem.eql(u8, "--with_frames", opt)) { + with_frames = true; continue; } @@ -626,7 +639,8 @@ fn parseFetchArgs( .dump_mode = dump_mode, .strip = strip, .common = common, - .withbase = withbase, + .with_base = with_base, + .with_frames = with_frames, }; } diff --git a/src/browser/Page.zig b/src/browser/Page.zig index b6734627..390ba84d 100644 --- a/src/browser/Page.zig +++ b/src/browser/Page.zig @@ -309,6 +309,8 @@ pub fn init(self: *Page, id: u32, session: *Session, parent: ?*Page) !void { self.js = try browser.env.createContext(self); errdefer self.js.deinit(); + document._page = self; + if (comptime builtin.is_test == false) { // HTML test runner manually calls these as necessary try self.js.scheduler.add(session.browser, struct { diff --git a/src/browser/dump.zig b/src/browser/dump.zig index e4d0fa05..6c58eb26 100644 --- a/src/browser/dump.zig +++ b/src/browser/dump.zig @@ -20,16 +20,15 @@ const std = @import("std"); const Page = @import("Page.zig"); const Node = @import("webapi/Node.zig"); const Slot = @import("webapi/element/html/Slot.zig"); +const IFrame = @import("webapi/element/html/IFrame.zig"); -pub const RootOpts = struct { - with_base: bool = false, - strip: Opts.Strip = .{}, - shadow: Opts.Shadow = .rendered, -}; +const IS_DEBUG = @import("builtin").mode == .Debug; pub const Opts = struct { - strip: Strip = .{}, - shadow: Shadow = .rendered, + with_base: bool = false, + with_frames: bool = false, + strip: Opts.Strip = .{}, + shadow: Opts.Shadow = .rendered, pub const Strip = struct { js: bool = false, @@ -49,7 +48,7 @@ pub const Opts = struct { }; }; -pub fn root(doc: *Node.Document, opts: RootOpts, writer: *std.Io.Writer, page: *Page) !void { +pub fn root(doc: *Node.Document, opts: Opts, writer: *std.Io.Writer, page: *Page) !void { if (doc.is(Node.Document.HTMLDocument)) |html_doc| { blk: { // Ideally we just render the doctype which is part of the document @@ -71,7 +70,7 @@ pub fn root(doc: *Node.Document, opts: RootOpts, writer: *std.Io.Writer, page: * } } - return deep(doc.asNode(), .{ .strip = opts.strip, .shadow = opts.shadow }, writer, page); + return deep(doc.asNode(), opts, writer, page); } pub fn deep(node: *Node, opts: Opts, writer: *std.Io.Writer, page: *Page) error{WriteFailed}!void { @@ -140,7 +139,24 @@ fn _deep(node: *Node, opts: Opts, comptime force_slot: bool, writer: *std.Io.Wri } } - try children(node, opts, writer, page); + if (opts.with_frames and el.is(IFrame) != null) { + const frame = el.as(IFrame); + if (frame.getContentDocument()) |doc| { + // A frame's document should always ahave a page, but + // I'm not willing to crash a release build on that assertion. + if (comptime IS_DEBUG) { + std.debug.assert(doc._page != null); + } + if (doc._page) |frame_page| { + try writer.writeByte('\n'); + root(doc, opts, writer, frame_page) catch return error.WriteFailed; + try writer.writeByte('\n'); + } + } + } else { + try children(node, opts, writer, page); + } + if (!isVoidElement(el)) { try writer.writeAll("