LibWeb: Only put connected elements into document's by-name-or-id cache

This fixes an issue where disconnected elements were incorrectly
accessible as named properties on the document.
This commit is contained in:
Andreas Kling 2025-03-03 20:30:18 +01:00 committed by Andreas Kling
parent 5f1a146afd
commit 12f5e9c5f8
Notes: github-actions[bot] 2025-03-03 23:52:46 +00:00
3 changed files with 95 additions and 12 deletions

View file

@ -1129,22 +1129,24 @@ void Element::inserted()
{
Base::inserted();
if (m_id.has_value())
document().element_with_id_was_added({}, *this);
if (m_name.has_value())
document().element_with_name_was_added({}, *this);
if (is_connected()) {
if (m_id.has_value())
document().element_with_id_was_added({}, *this);
if (m_name.has_value())
document().element_with_name_was_added({}, *this);
}
}
void Element::removed_from(Node* old_parent, Node& old_root)
{
Base::removed_from(old_parent, old_root);
if (m_id.has_value())
document().element_with_id_was_removed({}, *this);
if (m_name.has_value())
document().element_with_name_was_removed({}, *this);
if (old_root.is_connected()) {
if (m_id.has_value())
document().element_with_id_was_removed({}, *this);
if (m_name.has_value())
document().element_with_name_was_removed({}, *this);
}
}
void Element::children_changed(ChildrenChangedMetadata const* metadata)
@ -3530,14 +3532,16 @@ void Element::attribute_changed(FlyString const& local_name, Optional<String> co
else
m_id = value_or_empty;
document().element_id_changed({}, *this);
if (is_connected())
document().element_id_changed({}, *this);
} else if (local_name == HTML::AttributeNames::name) {
if (value_or_empty.is_empty())
m_name = {};
else
m_name = value_or_empty;
document().element_name_changed({}, *this);
if (is_connected())
document().element_name_changed({}, *this);
} else if (local_name == HTML::AttributeNames::class_) {
if (value_or_empty.is_empty()) {
m_classes.clear();

View file

@ -0,0 +1,15 @@
Testing <div> element
,,,,,,,,,,,,,,,
Testing <form> element
,,,,,,[object HTMLFormElement],,[object HTMLFormElement],,,,,,,
Testing <img> element
,,,,,,[object HTMLImageElement],,[object HTMLImageElement],,,,,,,
Testing <embed> element
,,,,,,[object HTMLEmbedElement],,[object HTMLEmbedElement],,,,,,,
Testing <object> element
,,,,,,[object HTMLObjectElement],,[object HTMLObjectElement],,[object HTMLObjectElement],[object HTMLObjectElement],,[object HTMLObjectElement],,

View file

@ -0,0 +1,64 @@
<script src="../include.js"></script>
<script>
function go(tagName) {
println("Testing <" + tagName + "> element");
let a = [];
let e = document.createElement(tagName);
a.push(document.shenanigans);
e.setAttribute("name", "shenanigans");
a.push(document.shenanigans);
e.setAttribute("name", "mischief");
a.push(document.shenanigans);
a.push(document.mischief);
e.name = "shenanigans";
a.push(document.shenanigans);
a.push(document.mischief);
document.body.appendChild(e);
a.push(document.shenanigans);
e.remove();
a.push(document.shenanigans);
document.body.appendChild(e);
a.push(document.shenanigans);
e.removeAttribute("name");
a.push(document.hijinks);
e.setAttribute("id", "hijinks");
a.push(document.hijinks);
document.body.appendChild(e);
a.push(document.hijinks);
e.remove();
a.push(document.hijinks);
document.body.appendChild(e);
a.push(document.hijinks);
e.removeAttribute("id");
a.push(document.hijinks);
e.remove();
a.push(document.hijinks);
println(a);
println("");
}
test(() => {
go("div");
go("form");
go("img");
go("embed");
go("object");
});
</script>