Merge pull request #927 from lightpanda-io/window-frames
Some checks failed
e2e-test / zig build release (push) Has been cancelled
zig-test / zig build dev (push) Has been cancelled
zig-test / zig test (push) Has been cancelled
e2e-test / demo-scripts (push) Has been cancelled
e2e-test / cdp-and-hyperfine-bench (push) Has been cancelled
e2e-test / perf-fmt (push) Has been cancelled
zig-test / browser fetch (push) Has been cancelled
zig-test / perf-fmt (push) Has been cancelled
nightly build / build-linux-x86_64 (push) Has been cancelled
nightly build / build-linux-aarch64 (push) Has been cancelled
nightly build / build-macos-aarch64 (push) Has been cancelled
nightly build / build-macos-x86_64 (push) Has been cancelled
wpt / web platform tests json output (push) Has been cancelled
wpt / perf-fmt (push) Has been cancelled

Partial window.frames implementation
This commit is contained in:
Pierre Tachoire
2025-08-15 14:54:29 +02:00
committed by GitHub
4 changed files with 101 additions and 9 deletions

View File

@@ -110,7 +110,7 @@ pub const NodeList = struct {
try self.nodes.append(alloc, node);
}
pub fn get_length(self: *NodeList) u32 {
pub fn get_length(self: *const NodeList) u32 {
return @intCast(self.nodes.items.len);
}

View File

@@ -61,7 +61,6 @@ pub const Interfaces = .{
HTMLHeadElement,
HTMLHeadingElement,
HTMLHtmlElement,
HTMLIFrameElement,
HTMLImageElement,
HTMLImageElement.Factory,
HTMLInputElement,
@@ -102,6 +101,7 @@ pub const Interfaces = .{
HTMLVideoElement,
@import("form.zig").HTMLFormElement,
@import("iframe.zig").HTMLIFrameElement,
@import("select.zig").Interfaces,
};
@@ -584,12 +584,6 @@ pub const HTMLHtmlElement = struct {
pub const subtype = .node;
};
pub const HTMLIFrameElement = struct {
pub const Self = parser.IFrame;
pub const prototype = *HTMLElement;
pub const subtype = .node;
};
pub const HTMLImageElement = struct {
pub const Self = parser.Image;
pub const prototype = *HTMLElement;

View File

@@ -0,0 +1,30 @@
// Copyright (C) 2023-2025 Lightpanda (Selecy SAS)
//
// Francis Bouvier <francis@lightpanda.io>
// Pierre Tachoire <pierre@lightpanda.io>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// 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/>.
const std = @import("std");
const Allocator = std.mem.Allocator;
const parser = @import("../netsurf.zig");
const Page = @import("../page.zig").Page;
const HTMLElement = @import("elements.zig").HTMLElement;
// https://html.spec.whatwg.org/multipage/iframe-embed-object.html#htmliframeelement
pub const HTMLIFrameElement = struct {
pub const Self = parser.IFrame;
pub const prototype = *HTMLElement;
pub const subtype = .node;
};

View File

@@ -33,6 +33,7 @@ const MediaQueryList = @import("media_query_list.zig").MediaQueryList;
const Performance = @import("../dom/performance.zig").Performance;
const CSSStyleDeclaration = @import("../cssom/CSSStyleDeclaration.zig");
const Screen = @import("screen.zig").Screen;
const domcss = @import("../dom/css.zig");
const Css = @import("../css/css.zig").Css;
const Function = Env.Function;
@@ -126,7 +127,43 @@ pub const Window = struct {
return self;
}
// TODO: frames
// frames return the window itself, but accessing it via a pseudo
// array returns the Window object corresponding to the given frame or
// iframe.
// https://developer.mozilla.org/en-US/docs/Web/API/Window/frames
pub fn get_frames(self: *Window) *Window {
return self;
}
pub fn indexed_get(self: *Window, index: u32, has_value: *bool, page: *Page) !*Window {
const frames = try domcss.querySelectorAll(
page.call_arena,
parser.documentHTMLToNode(self.document),
"iframe",
);
if (index >= frames.nodes.items.len) {
has_value.* = false;
return undefined;
}
has_value.* = true;
// TODO return the correct frame's window
// frames.nodes.items[indexed]
return error.TODO;
}
// Retrieve the numbre of frames/iframes from the DOM dynamically.
pub fn get_length(self: *const Window, page: *Page) !u32 {
const frames = try domcss.querySelectorAll(
page.call_arena,
parser.documentHTMLToNode(self.document),
"iframe",
);
return frames.get_length();
}
pub fn get_top(self: *Window) *Window {
return self;
}
@@ -493,6 +530,14 @@ test "Browser.HTML.Window" {
.{ "scrollend", "true" },
}, .{});
try runner.testCases(&.{
.{ "window == window.self", "true" },
.{ "window == window.parent", "true" },
.{ "window == window.top", "true" },
.{ "window == window.frames", "true" },
.{ "window.frames.length", "0" },
}, .{});
try runner.testCases(&.{
.{ "var qm = false; window.queueMicrotask(() => {qm = true });", null },
.{ "qm", "true" },
@@ -515,3 +560,26 @@ test "Browser.HTML.Window" {
}, .{});
}
}
test "Browser.HTML.Window.frames" {
var runner = try testing.jsRunner(testing.tracking_allocator, .{ .html =
\\<body>
\\ <iframe
\\ src="https://httpbin.io/html"
\\ title="iframea">
\\ </iframe>
\\ <iframe
\\ src="https://httpbin.io/html"
\\ title="iframeb">
\\ </iframe>
\\</body>
});
defer runner.deinit();
try runner.testCases(&.{
.{ "frames.length", "2" },
.{ "try { frames[1] } catch (e) { e }", "Error: TODO" }, // TODO fixme
.{ "frames[3]", "undefined" },
}, .{});
}