delegate Range rect methods to container element

Instead of always returning zeros, delegate getBoundingClientRect and
getClientRects to the common ancestor container element. Return zeros
only when the range is collapsed or has no element ancestor.
This commit is contained in:
egrs
2026-03-09 10:09:11 +01:00
parent 4586fb1d13
commit e239f69f69
2 changed files with 52 additions and 7 deletions

View File

@@ -1023,7 +1023,7 @@
} }
</script> </script>
<script id=getBoundingClientRect> <script id=getBoundingClientRect_collapsed>
{ {
const range = new Range(); const range = new Range();
const rect = range.getBoundingClientRect(); const rect = range.getBoundingClientRect();
@@ -1035,10 +1035,37 @@
} }
</script> </script>
<script id=getClientRects> <script id=getBoundingClientRect_element>
{
const range = new Range();
const p = document.getElementById('p1');
range.selectNodeContents(p);
const rect = range.getBoundingClientRect();
testing.expectTrue(rect instanceof DOMRect);
// Non-collapsed range delegates to the container element
const elemRect = p.getBoundingClientRect();
testing.expectEqual(elemRect.x, rect.x);
testing.expectEqual(elemRect.y, rect.y);
testing.expectEqual(elemRect.width, rect.width);
testing.expectEqual(elemRect.height, rect.height);
}
</script>
<script id=getClientRects_collapsed>
{ {
const range = new Range(); const range = new Range();
const rects = range.getClientRects(); const rects = range.getClientRects();
testing.expectEqual(0, rects.length); testing.expectEqual(0, rects.length);
} }
</script> </script>
<script id=getClientRects_element>
{
const range = new Range();
const p = document.getElementById('p1');
range.selectNodeContents(p);
const rects = range.getClientRects();
const elemRects = p.getClientRects();
testing.expectEqual(elemRects.length, rects.length);
}
</script>

View File

@@ -644,13 +644,31 @@ fn nextAfterSubtree(node: *Node, root: *Node) ?*Node {
return null; return null;
} }
// Headless browser has no layout — return a zero-valued DOMRect. pub fn getBoundingClientRect(self: *const Range, page: *Page) DOMRect {
pub fn getBoundingClientRect(_: *const Range) DOMRect { if (self._proto.getCollapsed()) {
return .{ ._x = 0, ._y = 0, ._width = 0, ._height = 0 }; return .{ ._x = 0, ._y = 0, ._width = 0, ._height = 0 };
}
const element = self.getContainerElement() orelse {
return .{ ._x = 0, ._y = 0, ._width = 0, ._height = 0 };
};
return element.getBoundingClientRect(page);
} }
pub fn getClientRects(_: *const Range) []DOMRect { pub fn getClientRects(self: *const Range, page: *Page) ![]DOMRect {
return &.{}; if (self._proto.getCollapsed()) {
return &.{};
}
const element = self.getContainerElement() orelse {
return &.{};
};
return element.getClientRects(page);
}
fn getContainerElement(self: *const Range) ?*Node.Element {
const container = self._proto.getCommonAncestorContainer();
if (container.is(Node.Element)) |el| return el;
const parent = container.parentNode() orelse return null;
return parent.is(Node.Element);
} }
pub const JsApi = struct { pub const JsApi = struct {