mirror of
https://github.com/RGBCube/serenity
synced 2025-05-29 20:45:08 +00:00
LibWeb: Bring HTMLElement.offset{Left,Top,Parent} closer to spec
(Or rather, bring offsetLeft and offsetTop closer to spec, and implement the previously-missing offsetParent) This makes mouse inputs on https://nerget.com/fluidSim/ work properly.
This commit is contained in:
parent
43e9dc0500
commit
cfe9577b48
5 changed files with 143 additions and 14 deletions
|
@ -0,0 +1,21 @@
|
||||||
|
|
||||||
|
nodeName: CANVAS
|
||||||
|
offsetTop: 0
|
||||||
|
offsetLeft: 0
|
||||||
|
offsetParent: [object HTMLTableCellElement]
|
||||||
|
|
||||||
|
nodeName: TD
|
||||||
|
offsetTop: 2
|
||||||
|
offsetLeft: 2
|
||||||
|
offsetParent: [object HTMLTableElement]
|
||||||
|
|
||||||
|
nodeName: TABLE
|
||||||
|
offsetTop: 100
|
||||||
|
offsetLeft: 50
|
||||||
|
offsetParent: [object HTMLBodyElement]
|
||||||
|
|
||||||
|
nodeName: BODY
|
||||||
|
offsetTop: 0
|
||||||
|
offsetLeft: 0
|
||||||
|
offsetParent: null
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
<style>
|
||||||
|
* {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
table {
|
||||||
|
position: relative;
|
||||||
|
top: 100px;
|
||||||
|
left: 50px;
|
||||||
|
}
|
||||||
|
</style><table><tr><td><canvas id="c"></canvas></td></tr></table>
|
||||||
|
<script src="../include.js"></script>
|
||||||
|
<script>
|
||||||
|
test(() => {
|
||||||
|
const c = document.getElementById("c");
|
||||||
|
println("");
|
||||||
|
|
||||||
|
for (let n = c; n; n = n.offsetParent) {
|
||||||
|
println("nodeName: " + n.nodeName);
|
||||||
|
println("offsetTop: " + n.offsetTop);
|
||||||
|
println("offsetLeft: " + n.offsetLeft);
|
||||||
|
println("offsetParent: " + n.offsetParent);
|
||||||
|
println("");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
|
@ -155,30 +155,111 @@ String HTMLElement::inner_text()
|
||||||
return MUST(builder.to_string());
|
return MUST(builder.to_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
// // https://drafts.csswg.org/cssom-view/#dom-htmlelement-offsettop
|
// https://www.w3.org/TR/cssom-view-1/#dom-htmlelement-offsetparent
|
||||||
int HTMLElement::offset_top() const
|
JS::GCPtr<DOM::Element> HTMLElement::offset_parent() const
|
||||||
{
|
{
|
||||||
// NOTE: Ensure that layout is up-to-date before looking at metrics.
|
|
||||||
const_cast<DOM::Document&>(document()).update_layout();
|
const_cast<DOM::Document&>(document()).update_layout();
|
||||||
|
|
||||||
if (is<HTML::HTMLBodyElement>(this) || !layout_node() || !parent_element() || !parent_element()->layout_node())
|
// 1. If any of the following holds true return null and terminate this algorithm:
|
||||||
return 0;
|
// - The element does not have an associated CSS layout box.
|
||||||
auto position = layout_node()->box_type_agnostic_position();
|
// - The element is the root element.
|
||||||
auto parent_position = parent_element()->layout_node()->box_type_agnostic_position();
|
// - The element is the HTML body element.
|
||||||
return position.y().to_int() - parent_position.y().to_int();
|
// - The element’s computed value of the position property is fixed.
|
||||||
|
if (!layout_node())
|
||||||
|
return nullptr;
|
||||||
|
if (is_document_element())
|
||||||
|
return nullptr;
|
||||||
|
if (is<HTML::HTMLBodyElement>(*this))
|
||||||
|
return nullptr;
|
||||||
|
if (layout_node()->is_fixed_position())
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
// 2. Return the nearest ancestor element of the element for which at least one of the following is true
|
||||||
|
// and terminate this algorithm if such an ancestor is found:
|
||||||
|
// - The computed value of the position property is not static.
|
||||||
|
// - It is the HTML body element.
|
||||||
|
// - The computed value of the position property of the element is static
|
||||||
|
// and the ancestor is one of the following HTML elements: td, th, or table.
|
||||||
|
|
||||||
|
for (auto* ancestor = parent_element(); ancestor; ancestor = ancestor->parent_element()) {
|
||||||
|
if (!ancestor->layout_node())
|
||||||
|
continue;
|
||||||
|
if (ancestor->layout_node()->is_positioned())
|
||||||
|
return const_cast<Element*>(ancestor);
|
||||||
|
if (is<HTML::HTMLBodyElement>(*ancestor))
|
||||||
|
return const_cast<Element*>(ancestor);
|
||||||
|
if (!ancestor->layout_node()->is_positioned() && ancestor->local_name().is_one_of(HTML::TagNames::td, HTML::TagNames::th, HTML::TagNames::table))
|
||||||
|
return const_cast<Element*>(ancestor);
|
||||||
|
}
|
||||||
|
|
||||||
|
VERIFY_NOT_REACHED();
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://drafts.csswg.org/cssom-view/#dom-htmlelement-offsetleft
|
// https://www.w3.org/TR/cssom-view-1/#dom-htmlelement-offsettop
|
||||||
int HTMLElement::offset_left() const
|
int HTMLElement::offset_top() const
|
||||||
{
|
{
|
||||||
|
// 1. If the element is the HTML body element or does not have any associated CSS layout box
|
||||||
|
// return zero and terminate this algorithm.
|
||||||
|
if (is<HTML::HTMLBodyElement>(*this))
|
||||||
|
return 0;
|
||||||
|
|
||||||
// NOTE: Ensure that layout is up-to-date before looking at metrics.
|
// NOTE: Ensure that layout is up-to-date before looking at metrics.
|
||||||
const_cast<DOM::Document&>(document()).update_layout();
|
const_cast<DOM::Document&>(document()).update_layout();
|
||||||
|
|
||||||
if (is<HTML::HTMLBodyElement>(this) || !layout_node() || !parent_element() || !parent_element()->layout_node())
|
if (!layout_node())
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
// 2. If the offsetParent of the element is null
|
||||||
|
// return the y-coordinate of the top border edge of the first CSS layout box associated with the element,
|
||||||
|
// relative to the initial containing block origin,
|
||||||
|
// ignoring any transforms that apply to the element and its ancestors, and terminate this algorithm.
|
||||||
|
auto offset_parent = this->offset_parent();
|
||||||
|
if (!offset_parent || !offset_parent->layout_node()) {
|
||||||
|
auto position = layout_node()->box_type_agnostic_position();
|
||||||
|
return position.y().to_int();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Return the result of subtracting the y-coordinate of the top padding edge
|
||||||
|
// of the first box associated with the offsetParent of the element
|
||||||
|
// from the y-coordinate of the top border edge of the first box associated with the element,
|
||||||
|
// relative to the initial containing block origin,
|
||||||
|
// ignoring any transforms that apply to the element and its ancestors.
|
||||||
|
auto offset_parent_position = offset_parent->layout_node()->box_type_agnostic_position();
|
||||||
auto position = layout_node()->box_type_agnostic_position();
|
auto position = layout_node()->box_type_agnostic_position();
|
||||||
auto parent_position = parent_element()->layout_node()->box_type_agnostic_position();
|
return position.y().to_int() - offset_parent_position.y().to_int();
|
||||||
return position.x().to_int() - parent_position.x().to_int();
|
}
|
||||||
|
|
||||||
|
// https://www.w3.org/TR/cssom-view-1/#dom-htmlelement-offsetleft
|
||||||
|
int HTMLElement::offset_left() const
|
||||||
|
{
|
||||||
|
// 1. If the element is the HTML body element or does not have any associated CSS layout box return zero and terminate this algorithm.
|
||||||
|
if (is<HTML::HTMLBodyElement>(*this))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// NOTE: Ensure that layout is up-to-date before looking at metrics.
|
||||||
|
const_cast<DOM::Document&>(document()).update_layout();
|
||||||
|
|
||||||
|
if (!layout_node())
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// 2. If the offsetParent of the element is null
|
||||||
|
// return the x-coordinate of the left border edge of the first CSS layout box associated with the element,
|
||||||
|
// relative to the initial containing block origin,
|
||||||
|
// ignoring any transforms that apply to the element and its ancestors, and terminate this algorithm.
|
||||||
|
auto offset_parent = this->offset_parent();
|
||||||
|
if (!offset_parent || !offset_parent->layout_node()) {
|
||||||
|
auto position = layout_node()->box_type_agnostic_position();
|
||||||
|
return position.x().to_int();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Return the result of subtracting the x-coordinate of the left padding edge
|
||||||
|
// of the first CSS layout box associated with the offsetParent of the element
|
||||||
|
// from the x-coordinate of the left border edge of the first CSS layout box associated with the element,
|
||||||
|
// relative to the initial containing block origin,
|
||||||
|
// ignoring any transforms that apply to the element and its ancestors.
|
||||||
|
auto offset_parent_position = offset_parent->layout_node()->box_type_agnostic_position();
|
||||||
|
auto position = layout_node()->box_type_agnostic_position();
|
||||||
|
return position.x().to_int() - offset_parent_position.x().to_int();
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://drafts.csswg.org/cssom-view/#dom-htmlelement-offsetwidth
|
// https://drafts.csswg.org/cssom-view/#dom-htmlelement-offsetwidth
|
||||||
|
|
|
@ -44,6 +44,7 @@ public:
|
||||||
int offset_left() const;
|
int offset_left() const;
|
||||||
int offset_width() const;
|
int offset_width() const;
|
||||||
int offset_height() const;
|
int offset_height() const;
|
||||||
|
JS::GCPtr<Element> offset_parent() const;
|
||||||
|
|
||||||
bool cannot_navigate() const;
|
bool cannot_navigate() const;
|
||||||
|
|
||||||
|
|
|
@ -37,7 +37,7 @@ interface HTMLElement : Element {
|
||||||
// FIXME: [CEReactions] attribute DOMString? popover;
|
// FIXME: [CEReactions] attribute DOMString? popover;
|
||||||
|
|
||||||
// https://drafts.csswg.org/cssom-view/#extensions-to-the-htmlelement-interface
|
// https://drafts.csswg.org/cssom-view/#extensions-to-the-htmlelement-interface
|
||||||
// FIXME: readonly attribute Element? offsetParent;
|
readonly attribute Element? offsetParent;
|
||||||
readonly attribute long offsetTop;
|
readonly attribute long offsetTop;
|
||||||
readonly attribute long offsetLeft;
|
readonly attribute long offsetLeft;
|
||||||
readonly attribute long offsetWidth;
|
readonly attribute long offsetWidth;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue