mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-22 23:50:19 +00:00
LibWeb: Remove shadow roots from elements that are removed from the DOM
We currently create a shadow tree once for each DOM element that renders with a shadow tree (e.g. <input>, <details>). If such an element is removed from the DOM, we must remove its shadow tree. Otherwise, the shadow tree will refer to the old document in perpetuity. If the node is added back to a DOM, then recreate the shadow tree.
This commit is contained in:
parent
3cde479416
commit
ff48b7333c
Notes:
sideshowbarker
2024-07-16 18:26:46 +09:00
Author: https://github.com/trflynn89 Commit: https://github.com/SerenityOS/serenity/commit/ff48b7333c Pull-request: https://github.com/SerenityOS/serenity/pull/22094 Reviewed-by: https://github.com/AtkinsSJ ✅
12 changed files with 67 additions and 3 deletions
|
@ -0,0 +1 @@
|
|||
<details><summary></summary></details>
|
1
Tests/LibWeb/Text/expected/HTML/set-innerHTML-input.txt
Normal file
1
Tests/LibWeb/Text/expected/HTML/set-innerHTML-input.txt
Normal file
|
@ -0,0 +1 @@
|
|||
<input>
|
|
@ -0,0 +1 @@
|
|||
<textarea></textarea>
|
9
Tests/LibWeb/Text/input/HTML/set-innerHTML-details.html
Normal file
9
Tests/LibWeb/Text/input/HTML/set-innerHTML-details.html
Normal file
|
@ -0,0 +1,9 @@
|
|||
<div id=test></div>
|
||||
<script src="../include.js"></script>
|
||||
<script>
|
||||
test(() => {
|
||||
let element = document.getElementById('test');
|
||||
element.innerHTML = "<details><summary></summary></details>";
|
||||
println(element.innerHTML);
|
||||
});
|
||||
</script>
|
9
Tests/LibWeb/Text/input/HTML/set-innerHTML-input.html
Normal file
9
Tests/LibWeb/Text/input/HTML/set-innerHTML-input.html
Normal file
|
@ -0,0 +1,9 @@
|
|||
<div id=test></div>
|
||||
<script src="../include.js"></script>
|
||||
<script>
|
||||
test(() => {
|
||||
let element = document.getElementById('test');
|
||||
element.innerHTML = "<input>";
|
||||
println(element.innerHTML);
|
||||
});
|
||||
</script>
|
9
Tests/LibWeb/Text/input/HTML/set-innerHTML-textarea.html
Normal file
9
Tests/LibWeb/Text/input/HTML/set-innerHTML-textarea.html
Normal file
|
@ -0,0 +1,9 @@
|
|||
<div id=test></div>
|
||||
<script src="../include.js"></script>
|
||||
<script>
|
||||
test(() => {
|
||||
let element = document.getElementById('test');
|
||||
element.innerHTML = "<textarea></textarea>";
|
||||
println(element.innerHTML);
|
||||
});
|
||||
</script>
|
|
@ -39,8 +39,17 @@ void HTMLDetailsElement::initialize(JS::Realm& realm)
|
|||
{
|
||||
Base::initialize(realm);
|
||||
set_prototype(&Bindings::ensure_web_prototype<Bindings::HTMLDetailsElementPrototype>(realm, "HTMLDetailsElement"_fly_string));
|
||||
}
|
||||
|
||||
create_shadow_tree(realm).release_value_but_fixme_should_propagate_errors();
|
||||
void HTMLDetailsElement::inserted()
|
||||
{
|
||||
create_shadow_tree_if_needed().release_value_but_fixme_should_propagate_errors();
|
||||
update_shadow_tree_slots();
|
||||
}
|
||||
|
||||
void HTMLDetailsElement::removed_from(DOM::Node*)
|
||||
{
|
||||
set_shadow_root(nullptr);
|
||||
}
|
||||
|
||||
void HTMLDetailsElement::attribute_changed(FlyString const& name, Optional<String> const& value)
|
||||
|
@ -107,8 +116,13 @@ void HTMLDetailsElement::queue_a_details_toggle_event_task(String old_state, Str
|
|||
}
|
||||
|
||||
// https://html.spec.whatwg.org/#the-details-and-summary-elements
|
||||
WebIDL::ExceptionOr<void> HTMLDetailsElement::create_shadow_tree(JS::Realm& realm)
|
||||
WebIDL::ExceptionOr<void> HTMLDetailsElement::create_shadow_tree_if_needed()
|
||||
{
|
||||
if (shadow_root_internal())
|
||||
return {};
|
||||
|
||||
auto& realm = this->realm();
|
||||
|
||||
// The element is also expected to have an internal shadow tree with two slots.
|
||||
auto shadow_root = heap().allocate<DOM::ShadowRoot>(realm, document(), *this, Bindings::ShadowRootMode::Closed);
|
||||
shadow_root->set_slot_assignment(Bindings::SlotAssignmentMode::Manual);
|
||||
|
@ -130,6 +144,9 @@ WebIDL::ExceptionOr<void> HTMLDetailsElement::create_shadow_tree(JS::Realm& real
|
|||
|
||||
void HTMLDetailsElement::update_shadow_tree_slots()
|
||||
{
|
||||
if (!shadow_root_internal())
|
||||
return;
|
||||
|
||||
Vector<HTMLSlotElement::SlottableHandle> summary_assignment;
|
||||
Vector<HTMLSlotElement::SlottableHandle> descendants_assignment;
|
||||
|
||||
|
@ -159,6 +176,9 @@ void HTMLDetailsElement::update_shadow_tree_slots()
|
|||
// https://html.spec.whatwg.org/#the-details-and-summary-elements:the-details-element-6
|
||||
void HTMLDetailsElement::update_shadow_tree_style()
|
||||
{
|
||||
if (!shadow_root_internal())
|
||||
return;
|
||||
|
||||
if (has_attribute(HTML::AttributeNames::open)) {
|
||||
MUST(m_descendants_slot->set_attribute(HTML::AttributeNames::style, R"~~~(
|
||||
display: block;
|
||||
|
|
|
@ -31,12 +31,14 @@ private:
|
|||
virtual void initialize(JS::Realm&) override;
|
||||
virtual void visit_edges(Cell::Visitor&) override;
|
||||
|
||||
virtual void inserted() override;
|
||||
virtual void removed_from(DOM::Node*) override;
|
||||
virtual void children_changed() override;
|
||||
virtual void attribute_changed(FlyString const& name, Optional<String> const& value) override;
|
||||
|
||||
void queue_a_details_toggle_event_task(String old_state, String new_state);
|
||||
|
||||
WebIDL::ExceptionOr<void> create_shadow_tree(JS::Realm&);
|
||||
WebIDL::ExceptionOr<void> create_shadow_tree_if_needed();
|
||||
void update_shadow_tree_slots();
|
||||
void update_shadow_tree_style();
|
||||
|
||||
|
|
|
@ -1003,6 +1003,11 @@ void HTMLInputElement::form_associated_element_was_inserted()
|
|||
create_shadow_tree_if_needed();
|
||||
}
|
||||
|
||||
void HTMLInputElement::form_associated_element_was_removed(DOM::Node*)
|
||||
{
|
||||
set_shadow_root(nullptr);
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/input.html#radio-button-group
|
||||
static bool is_in_same_radio_button_group(HTML::HTMLInputElement const& a, HTML::HTMLInputElement const& b)
|
||||
{
|
||||
|
|
|
@ -139,6 +139,7 @@ public:
|
|||
virtual void reset_algorithm() override;
|
||||
|
||||
virtual void form_associated_element_was_inserted() override;
|
||||
virtual void form_associated_element_was_removed(DOM::Node*) override;
|
||||
|
||||
// ^HTMLElement
|
||||
// https://html.spec.whatwg.org/multipage/forms.html#category-label
|
||||
|
|
|
@ -91,6 +91,11 @@ void HTMLTextAreaElement::form_associated_element_was_inserted()
|
|||
create_shadow_tree_if_needed();
|
||||
}
|
||||
|
||||
void HTMLTextAreaElement::form_associated_element_was_removed(DOM::Node*)
|
||||
{
|
||||
set_shadow_root(nullptr);
|
||||
}
|
||||
|
||||
void HTMLTextAreaElement::create_shadow_tree_if_needed()
|
||||
{
|
||||
if (shadow_root_internal())
|
||||
|
|
|
@ -62,6 +62,7 @@ public:
|
|||
virtual void reset_algorithm() override;
|
||||
|
||||
virtual void form_associated_element_was_inserted() override;
|
||||
virtual void form_associated_element_was_removed(DOM::Node*) override;
|
||||
|
||||
virtual void children_changed() override;
|
||||
|
||||
|
|
Loading…
Reference in a new issue