From 221274b473e53f448a24c99474b50bbc47d68553 Mon Sep 17 00:00:00 2001 From: Pierre Tachoire Date: Wed, 6 Aug 2025 13:24:07 +0200 Subject: [PATCH 1/5] first change to start support frames --- src/browser/html/window.zig | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/browser/html/window.zig b/src/browser/html/window.zig index b1aedf51..1d5f8064 100644 --- a/src/browser/html/window.zig +++ b/src/browser/html/window.zig @@ -127,7 +127,18 @@ pub const Window = struct { return self; } + // 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; + } // TODO: frames + pub fn get_length(_: *Window) u32 { + return 0; + } + pub fn get_top(self: *Window) *Window { return self; } @@ -504,6 +515,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" }, From b98bdeaae7a08a8d6ffbdfeee4b9b094275514d5 Mon Sep 17 00:00:00 2001 From: Pierre Tachoire Date: Wed, 6 Aug 2025 16:19:23 +0200 Subject: [PATCH 2/5] window.length dynamically --- src/browser/dom/nodelist.zig | 2 +- src/browser/html/window.zig | 14 +++++++++++--- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/browser/dom/nodelist.zig b/src/browser/dom/nodelist.zig index 56194c2f..22e8708f 100644 --- a/src/browser/dom/nodelist.zig +++ b/src/browser/dom/nodelist.zig @@ -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); } diff --git a/src/browser/html/window.zig b/src/browser/html/window.zig index 1d5f8064..7bc31831 100644 --- a/src/browser/html/window.zig +++ b/src/browser/html/window.zig @@ -34,6 +34,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; @@ -134,9 +135,16 @@ pub const Window = struct { pub fn get_frames(self: *Window) *Window { return self; } - // TODO: frames - pub fn get_length(_: *Window) u32 { - return 0; + + // 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), + "frame,iframe", + ); + + return frames.get_length(); } pub fn get_top(self: *Window) *Window { From 1b7abf9972cf8ddbba595fabe923fc2c72755775 Mon Sep 17 00:00:00 2001 From: Pierre Tachoire Date: Wed, 6 Aug 2025 18:28:53 +0200 Subject: [PATCH 3/5] window: partial implementation for indexed_get --- src/browser/html/window.zig | 41 +++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/src/browser/html/window.zig b/src/browser/html/window.zig index 7bc31831..705c8682 100644 --- a/src/browser/html/window.zig +++ b/src/browser/html/window.zig @@ -136,6 +136,24 @@ pub const Window = struct { 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), + "frame,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( @@ -553,3 +571,26 @@ test "Browser.HTML.Window" { }, .{}); } } + +test "Browser.HTML.Window.frames" { + var runner = try testing.jsRunner(testing.tracking_allocator, .{ .html = + \\ + \\ + \\ + \\ + }); + + defer runner.deinit(); + + try runner.testCases(&.{ + .{ "frames.length", "2" }, + .{ "try { frames[1] } catch (e) { e }", "Error: TODO" }, // TODO fixme + .{ "frames[3]", "undefined" }, + }, .{}); +} From 28397bf9d0ccffde00062808044e847b9a189448 Mon Sep 17 00:00:00 2001 From: Pierre Tachoire Date: Thu, 7 Aug 2025 10:04:24 +0200 Subject: [PATCH 4/5] window: frame is obsolete, ignore them from frames list --- src/browser/html/window.zig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/browser/html/window.zig b/src/browser/html/window.zig index 705c8682..d85269da 100644 --- a/src/browser/html/window.zig +++ b/src/browser/html/window.zig @@ -140,7 +140,7 @@ pub const Window = struct { const frames = try domcss.querySelectorAll( page.call_arena, parser.documentHTMLToNode(self.document), - "frame,iframe", + "iframe", ); if (index >= frames.nodes.items.len) { @@ -159,7 +159,7 @@ pub const Window = struct { const frames = try domcss.querySelectorAll( page.call_arena, parser.documentHTMLToNode(self.document), - "frame,iframe", + "iframe", ); return frames.get_length(); From b199925f918232fb6b86c962bca8b296dde1e120 Mon Sep 17 00:00:00 2001 From: Pierre Tachoire Date: Thu, 7 Aug 2025 10:35:04 +0200 Subject: [PATCH 5/5] iframe: move HTMLIFrameElement in its own file --- src/browser/html/elements.zig | 8 +------- src/browser/html/iframe.zig | 30 ++++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 7 deletions(-) create mode 100644 src/browser/html/iframe.zig diff --git a/src/browser/html/elements.zig b/src/browser/html/elements.zig index 5be01a1e..57d2fa29 100644 --- a/src/browser/html/elements.zig +++ b/src/browser/html/elements.zig @@ -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; diff --git a/src/browser/html/iframe.zig b/src/browser/html/iframe.zig new file mode 100644 index 00000000..f8edf508 --- /dev/null +++ b/src/browser/html/iframe.zig @@ -0,0 +1,30 @@ +// Copyright (C) 2023-2025 Lightpanda (Selecy SAS) +// +// Francis Bouvier +// Pierre Tachoire +// +// 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 . +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; +};