diff --git a/src/browser/dom/nodelist.zig b/src/browser/dom/nodelist.zig index 56194c2fa..22e8708fe 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/elements.zig b/src/browser/html/elements.zig index 5be01a1e4..57d2fa298 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 000000000..f8edf5080 --- /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; +}; diff --git a/src/browser/html/window.zig b/src/browser/html/window.zig index b1aedf513..d85269da5 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; @@ -127,7 +128,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; } @@ -504,6 +541,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" }, @@ -526,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" }, + }, .{}); +}