diff --git a/src/browser/tests/document/element_from_point.html b/src/browser/tests/document/element_from_point.html
new file mode 100644
index 00000000..d3ea7da9
--- /dev/null
+++ b/src/browser/tests/document/element_from_point.html
@@ -0,0 +1,233 @@
+
+
+
+
+ Div 1
+ Div 2
+ Hidden
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/browser/tests/legacy/html/document.html b/src/browser/tests/legacy/html/document.html
index 003ee820..7abb0b03 100644
--- a/src/browser/tests/legacy/html/document.html
+++ b/src/browser/tests/legacy/html/document.html
@@ -52,13 +52,6 @@
let div1 = document.createElement('div');
document.body.appendChild(div1);
div1.getClientRects(); // clal this to position it
- testing.expectEqual('[object HTMLDivElement]', document.elementFromPoint(2.5, 2.5).toString());
-
- let elems = document.elementsFromPoint(2.5, 2.5);
- testing.expectEqual(3, elems.length);
- testing.expectEqual('[object HTMLDivElement]', elems[0].toString());
- testing.expectEqual('[object HTMLBodyElement]', elems[1].toString());
- testing.expectEqual('[object HTMLHtmlElement]', elems[2].toString());
let a = document.createElement('a');
a.href = "https://lightpanda.io";
@@ -66,20 +59,11 @@
// Note this will be placed after the div of previous test
a.getClientRects();
- let a_again = document.elementFromPoint(7.5, 0.5);
- testing.expectEqual('[object HTMLAnchorElement]', a_again.toString());
- testing.expectEqual('https://lightpanda.io', a_again.href);
-
- let a_agains = document.elementsFromPoint(7.5, 0.5);
- testing.expectEqual('https://lightpanda.io', a_agains[0].href);
-
-
testing.expectEqual(true, !document.all);
testing.expectEqual(false, !!document.all);
- testing.expectEqual('[object HTMLScriptElement]', document.all(5).toString());
+ testing.expectEqual('[object HTMLScriptElement]', document.all(6).toString());
testing.expectEqual('[object HTMLDivElement]', document.all('content').toString());
-
testing.expectEqual(document, document.defaultView.document );
testing.expectEqual('loading', document.readyState);
diff --git a/src/browser/tests/legacy/html/image.html b/src/browser/tests/legacy/html/image.html
index 1e3f6aff..053b2cfa 100644
--- a/src/browser/tests/legacy/html/image.html
+++ b/src/browser/tests/legacy/html/image.html
@@ -26,7 +26,7 @@
let lyric = new Image
testing.expectEqual('', lyric.src);
lyric.src = 'okay';
- testing.expectEqual('okay', lyric.src);
+ testing.expectEqual('http://localhost:9589/html/okay', lyric.src);
lyric.src = 15;
- testing.expectEqual('15', lyric.src);
+ testing.expectEqual('http://localhost:9589/html/15', lyric.src);
diff --git a/src/browser/tests/legacy/html/link.html b/src/browser/tests/legacy/html/link.html
index 15da6461..95869052 100644
--- a/src/browser/tests/legacy/html/link.html
+++ b/src/browser/tests/legacy/html/link.html
@@ -9,7 +9,7 @@
testing.expectEqual('_blank', link.target);
link.target = '';
- testing.expectEqual('foo', link.href);
+ testing.expectEqual('http://localhost:9589/html/foo', link.href);
link.href = 'https://lightpanda.io/';
testing.expectEqual('https://lightpanda.io/', link.href);
diff --git a/src/browser/tests/window/navigator.html b/src/browser/tests/window/navigator.html
index e00f429b..11ad9ade 100644
--- a/src/browser/tests/window/navigator.html
+++ b/src/browser/tests/window/navigator.html
@@ -4,67 +4,26 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/browser/webapi/Document.zig b/src/browser/webapi/Document.zig
index a665849f..87019a54 100644
--- a/src/browser/webapi/Document.zig
+++ b/src/browser/webapi/Document.zig
@@ -345,6 +345,48 @@ pub fn prepend(self: *Document, nodes: []const Node.NodeOrText, page: *Page) !vo
}
}
+pub fn elementFromPoint(self: *Document, x: f64, y: f64, page: *Page) !?*Element {
+ // Traverse document in depth-first order to find the topmost (last in document order)
+ // element that contains the point (x, y)
+ var topmost: ?*Element = null;
+
+ const root = self.asNode();
+ var stack: std.ArrayList(*Node) = .empty;
+ try stack.append(page.call_arena, root);
+
+ while (stack.items.len > 0) {
+ const node = stack.pop() orelse break;
+ if (node.is(Element)) |element| {
+ if (try element.checkVisibility(page)) {
+ const rect = try element.getBoundingClientRect(page);
+ if (x >= rect._left and x <= rect._right and y >= rect._top and y <= rect._bottom) {
+ topmost = element;
+ }
+ }
+ }
+
+ // Add children to stack in reverse order so we process them in document order
+ var child = node.lastChild();
+ while (child) |c| {
+ try stack.append(page.call_arena, c);
+ child = c.previousSibling();
+ }
+ }
+
+ return topmost;
+}
+
+pub fn elementsFromPoint(self: *Document, x: f64, y: f64, page: *Page) ![]const *Element {
+ // Get topmost element
+ var current: ?*Element = (try self.elementFromPoint(x, y, page)) orelse return &.{};
+ var result: std.ArrayList(*Element) = .empty;
+ while (current) |el| {
+ try result.append(page.call_arena, el);
+ current = el.parentElement();
+ }
+ return result.items;
+}
+
const ReadyState = enum {
loading,
interactive,
@@ -404,6 +446,8 @@ pub const JsApi = struct {
pub const importNode = bridge.function(Document.importNode, .{ .dom_exception = true });
pub const append = bridge.function(Document.append, .{});
pub const prepend = bridge.function(Document.prepend, .{});
+ pub const elementFromPoint = bridge.function(Document.elementFromPoint, .{});
+ pub const elementsFromPoint = bridge.function(Document.elementsFromPoint, .{});
pub const defaultView = bridge.accessor(struct {
fn defaultView(_: *const Document, page: *Page) *@import("Window.zig") {
diff --git a/src/browser/webapi/Navigator.zig b/src/browser/webapi/Navigator.zig
index 23efd49f..b38d1093 100644
--- a/src/browser/webapi/Navigator.zig
+++ b/src/browser/webapi/Navigator.zig
@@ -25,15 +25,19 @@ _pad: bool = false,
pub const init: Navigator = .{};
pub fn getUserAgent(_: *const Navigator) []const u8 {
- return "Mozilla/5.0 (compatible; LiteFetch/0.1)";
+ return "Lightpanda/1.0";
}
pub fn getAppName(_: *const Navigator) []const u8 {
- return "LiteFetch";
+ return "Netscape";
+}
+
+pub fn getAppCodeName(_: *const Navigator) []const u8 {
+ return "Netscape";
}
pub fn getAppVersion(_: *const Navigator) []const u8 {
- return "0.1";
+ return "1.0";
}
pub fn getPlatform(_: *const Navigator) []const u8 {
@@ -73,7 +77,7 @@ pub fn getMaxTouchPoints(_: *const Navigator) u32 {
/// Returns the vendor name
pub fn getVendor(_: *const Navigator) []const u8 {
- return "LiteFetch";
+ return "";
}
/// Returns the product name (typically "Gecko" for compatibility)
@@ -104,6 +108,7 @@ pub const JsApi = struct {
// Read-only properties
pub const userAgent = bridge.accessor(Navigator.getUserAgent, null, .{});
pub const appName = bridge.accessor(Navigator.getAppName, null, .{});
+ pub const appCodeName = bridge.accessor(Navigator.getAppCodeName, null, .{});
pub const appVersion = bridge.accessor(Navigator.getAppVersion, null, .{});
pub const platform = bridge.accessor(Navigator.getPlatform, null, .{});
pub const language = bridge.accessor(Navigator.getLanguage, null, .{});
diff --git a/src/browser/webapi/collections/HTMLOptionsCollection.zig b/src/browser/webapi/collections/HTMLOptionsCollection.zig
index 6a0cadc9..4474cb76 100644
--- a/src/browser/webapi/collections/HTMLOptionsCollection.zig
+++ b/src/browser/webapi/collections/HTMLOptionsCollection.zig
@@ -30,11 +30,6 @@ const HTMLOptionsCollection = @This();
_proto: *HTMLCollection,
_select: *@import("../element/html/Select.zig"),
-pub fn deinit(self: *HTMLOptionsCollection) void {
- const page = Page.current;
- page._factory.destroy(self);
-}
-
// Forward length to HTMLCollection
pub fn length(self: *HTMLOptionsCollection, page: *Page) u32 {
return self._proto.length(page);
@@ -102,7 +97,6 @@ pub const JsApi = struct {
pub const name = "HTMLOptionsCollection";
pub const prototype_chain = bridge.prototypeChain();
pub var class_id: bridge.ClassId = undefined;
- pub const finalizer = HTMLOptionsCollection.deinit;
pub const manage = false;
};
diff --git a/src/browser/webapi/element/Html.zig b/src/browser/webapi/element/Html.zig
index 341fbc94..e0220504 100644
--- a/src/browser/webapi/element/Html.zig
+++ b/src/browser/webapi/element/Html.zig
@@ -120,11 +120,11 @@ pub fn is(self: *HtmlElement, comptime T: type) ?*T {
pub fn className(self: *const HtmlElement) []const u8 {
return switch (self._type) {
- .anchor => "[object HtmlAnchorElement]",
- .div => "[object HtmlDivElement]",
- .embed => "[object HtmlEmbedElement]",
+ .anchor => "[object HTMLAnchorElement]",
+ .div => "[object HTMLDivElement]",
+ .embed => "[object HTMLEmbedElement]",
.form => "[object HTMLFormElement]",
- .p => "[object HtmlParagraphElement]",
+ .p => "[object HTMLParagraphElement]",
.custom => "[object CUSTOM-TODO]",
.data => "[object HTMLDataElement]",
.dialog => "[object HTMLDialogElement]",
@@ -137,22 +137,22 @@ pub fn className(self: *const HtmlElement) []const u8 {
.ul => "[object HTMLULElement]",
.ol => "[object HTMLOLElement]",
.generic => "[object HTMLElement]",
- .script => "[object HtmlScriptElement]",
+ .script => "[object HTMLScriptElement]",
.select => "[object HTMLSelectElement]",
.slot => "[object HTMLSlotElement]",
.template => "[object HTMLTemplateElement]",
.option => "[object HTMLOptionElement]",
- .text_area => "[object HtmlTextAreaElement]",
- .input => "[object HtmlInputElement]",
- .link => "[object HtmlLinkElement]",
- .meta => "[object HtmlMetaElement]",
- .hr => "[object HtmlHRElement]",
- .style => "[object HtmlSyleElement]",
- .title => "[object HtmlTitleElement]",
- .body => "[object HtmlBodyElement]",
- .html => "[object HtmlHtmlElement]",
- .head => "[object HtmlHeadElement]",
- .unknown => "[object HtmlUnknownElement]",
+ .text_area => "[object HTMLTextAreaElement]",
+ .input => "[object HTMLInputElement]",
+ .link => "[object HTMLLinkElement]",
+ .meta => "[object HTMLMetaElement]",
+ .hr => "[object HTMLHRElement]",
+ .style => "[object HTMLSyleElement]",
+ .title => "[object HTMLTitleElement]",
+ .body => "[object HTMLBodyElement]",
+ .html => "[object HTMLHtmlElement]",
+ .head => "[object HTMLHeadElement]",
+ .unknown => "[object HTMLUnknownElement]",
};
}
diff --git a/src/browser/webapi/selector/List.zig b/src/browser/webapi/selector/List.zig
index 06d2045e..5b1eb632 100644
--- a/src/browser/webapi/selector/List.zig
+++ b/src/browser/webapi/selector/List.zig
@@ -77,12 +77,6 @@ pub fn initOne(root: *Node, selector: Selector.Selector, page: *Page) ?*Node {
return null;
}
-pub fn deinit(self: *List) void {
- const page = Page.current;
- page._mem.releaseArena(self._arena);
- page._factory.destroy(self);
-}
-
const OptimizeResult = struct {
root: *Node,
exclude_root: bool,