LibWeb: Set inertness of HTMLElement when inert attribute is changed

This commit is contained in:
Tim Ledbetter 2025-02-05 23:24:47 +00:00 committed by Sam Atkins
parent 893e9e3eac
commit a9ffc6359a
Notes: github-actions[bot] 2025-02-21 12:43:40 +00:00
4 changed files with 49 additions and 0 deletions

View file

@ -2110,6 +2110,17 @@ bool Node::is_default_namespace(Optional<String> namespace_) const
return default_namespace == namespace_;
}
bool Node::is_inert() const
{
if (auto* html_element = as_if<HTML::HTMLElement>(*this))
return html_element->is_inert();
if (auto* enclosing_html_element = this->enclosing_html_element())
return enclosing_html_element->is_inert();
return false;
}
// https://dom.spec.whatwg.org/#in-a-document-tree
bool Node::in_a_document_tree() const
{

View file

@ -499,6 +499,8 @@ public:
Optional<String> lookup_prefix(Optional<String> namespace_) const;
bool is_default_namespace(Optional<String> namespace_) const;
bool is_inert() const;
protected:
Node(JS::Realm&, Document&, NodeType);
Node(Document&, NodeType);

View file

@ -639,6 +639,12 @@ void HTMLElement::attribute_changed(FlyString const& name, Optional<String> cons
// Having an invalid value maps to the "inherit" state.
m_content_editable_state = ContentEditableState::Inherit;
}
} else if (name == HTML::AttributeNames::inert) {
// https://html.spec.whatwg.org/multipage/interaction.html#the-inert-attribute
// The inert attribute is a boolean attribute that indicates, by its presence, that the element and all its flat tree descendants which don't otherwise escape inertness
// (such as modal dialogs) are to be made inert by the user agent.
auto is_inert = value.has_value();
set_subtree_inertness(is_inert);
}
// 1. If namespace is not null, or localName is not the name of an event handler content attribute on element, then return.
@ -673,6 +679,18 @@ void HTMLElement::attribute_changed(FlyString const& name, Optional<String> cons
}();
}
void HTMLElement::set_subtree_inertness(bool is_inert)
{
set_inert(is_inert);
for_each_in_subtree_of_type<HTMLElement>([&](auto& html_element) {
if (html_element.has_attribute(HTML::AttributeNames::inert))
return TraversalDecision::SkipChildrenAndContinue;
// FIXME: Exclude elements that should escape inertness.
html_element.set_inert(is_inert);
return TraversalDecision::Continue;
});
}
WebIDL::ExceptionOr<void> HTMLElement::cloned(Web::DOM::Node& copy, bool clone_children) const
{
TRY(Base::cloned(copy, clone_children));
@ -684,6 +702,9 @@ void HTMLElement::inserted()
{
Base::inserted();
HTMLOrSVGElement::inserted();
if (auto* parent_html_element = first_ancestor_of_type<HTMLElement>(); parent_html_element && parent_html_element->is_inert() && !has_attribute(HTML::AttributeNames::inert))
set_subtree_inertness(true);
}
// https://html.spec.whatwg.org/multipage/webappapis.html#fire-a-synthetic-pointer-event
@ -1826,6 +1847,14 @@ void HTMLElement::removed_from(Node* old_parent, Node& old_root)
// If removedNode's popover attribute is not in the no popover state, then run the hide popover algorithm given removedNode, false, false, false, and true.
if (popover().has_value())
MUST(hide_popover(FocusPreviousElement::No, FireEvents::No, ThrowExceptions::No, IgnoreDomState::Yes));
if (old_parent) {
auto* parent_html_element = as_if<HTMLElement>(old_parent);
if (!parent_html_element)
parent_html_element = old_parent->first_ancestor_of_type<HTMLElement>();
if (parent_html_element && parent_html_element->is_inert() && !has_attribute(HTML::AttributeNames::inert))
set_subtree_inertness(false);
}
}
// https://html.spec.whatwg.org/multipage/interaction.html#dom-accesskeylabel

View file

@ -149,6 +149,8 @@ public:
static void hide_all_popovers_until(Variant<GC::Ptr<HTMLElement>, GC::Ptr<DOM::Document>> endpoint, FocusPreviousElement focus_previous_element, FireEvents fire_events);
static GC::Ptr<HTMLElement> topmost_popover_ancestor(GC::Ptr<DOM::Node> new_popover_or_top_layer_element, Vector<GC::Ref<HTMLElement>> const& popover_list, GC::Ptr<HTMLElement> invoker, IsPopover is_popover);
bool is_inert() const { return m_inert; }
protected:
HTMLElement(DOM::Document&, DOM::QualifiedName);
@ -169,6 +171,9 @@ protected:
// https://html.spec.whatwg.org/multipage/urls-and-fetching.html#implicitly-potentially-render-blocking
virtual bool is_implicitly_potentially_render_blocking() const { return false; }
void set_inert(bool inert) { m_inert = inert; }
void set_subtree_inertness(bool is_inert);
private:
virtual bool is_html_element() const final { return true; }
@ -200,6 +205,8 @@ private:
// https://html.spec.whatwg.org/multipage/interaction.html#click-in-progress-flag
bool m_click_in_progress { false };
bool m_inert { false };
// Popover API
// https://html.spec.whatwg.org/multipage/popover.html#popover-visibility-state