diff --git a/Libraries/LibWeb/HTML/HTMLElement.cpp b/Libraries/LibWeb/HTML/HTMLElement.cpp index 93207f6f4f1..52ac5b37481 100644 --- a/Libraries/LibWeb/HTML/HTMLElement.cpp +++ b/Libraries/LibWeb/HTML/HTMLElement.cpp @@ -619,6 +619,27 @@ void HTMLElement::attribute_changed(FlyString const& name, Optional cons } ENUMERATE_GLOBAL_EVENT_HANDLERS(__ENUMERATE) #undef __ENUMERATE + + [&]() { + // https://html.spec.whatwg.org/multipage/popover.html#the-popover-attribute:concept-element-attributes-change-ext + // https://whatpr.org/html/9457/popover.html#the-popover-attribute:concept-element-attributes-change-ext + // The following attribute change steps, given element, localName, oldValue, value, and namespace, are used for all HTML elements: + + // 1. If namespace is not null, then return. + if (namespace_.has_value()) + return; + + // 2. If localName is not popover, then return. + if (name != HTML::AttributeNames::popover) + return; + + // 3. If element's popover visibility state is in the showing state + // and oldValue and value are in different states, + // then run the hide popover algorithm given element, true, true, false, and true. + if (m_popover_visibility_state == PopoverVisibilityState::Showing + && popover_value_to_state(old_value) != popover_value_to_state(value)) + MUST(hide_popover(FocusPreviousElement::Yes, FireEvents::Yes, ThrowExceptions::No, IgnoreDomState::Yes)); + }(); } WebIDL::ExceptionOr HTMLElement::cloned(Web::DOM::Node& copy, bool clone_children) const @@ -957,13 +978,8 @@ WebIDL::ExceptionOr> HTMLElement::attach_internals() return { internals }; } -// https://html.spec.whatwg.org/multipage/popover.html#dom-popover -Optional HTMLElement::popover() const +Optional HTMLElement::popover_value_to_state(Optional value) { - // FIXME: This should probably be `Reflect` in the IDL. - // The popover IDL attribute must reflect the popover attribute, limited to only known values. - auto value = get_attribute(HTML::AttributeNames::popover); - if (!value.has_value()) return {}; @@ -975,6 +991,15 @@ Optional HTMLElement::popover() const return "manual"_string; } +// https://html.spec.whatwg.org/multipage/popover.html#dom-popover +Optional HTMLElement::popover() const +{ + // FIXME: This should probably be `Reflect` in the IDL. + // The popover IDL attribute must reflect the popover attribute, limited to only known values. + auto value = get_attribute(HTML::AttributeNames::popover); + return popover_value_to_state(value); +} + // https://html.spec.whatwg.org/multipage/popover.html#dom-popover WebIDL::ExceptionOr HTMLElement::set_popover(Optional value) { diff --git a/Libraries/LibWeb/HTML/HTMLElement.h b/Libraries/LibWeb/HTML/HTMLElement.h index 05073a971e6..e373f84ac56 100644 --- a/Libraries/LibWeb/HTML/HTMLElement.h +++ b/Libraries/LibWeb/HTML/HTMLElement.h @@ -168,6 +168,8 @@ private: void queue_a_popover_toggle_event_task(String old_state, String new_state); + static Optional popover_value_to_state(Optional value); + // https://html.spec.whatwg.org/multipage/custom-elements.html#attached-internals GC::Ptr m_attached_internals; diff --git a/Tests/LibWeb/Text/expected/popover-crashes.txt b/Tests/LibWeb/Text/expected/popover-crashes.txt index e358a96903c..52f2729b493 100644 --- a/Tests/LibWeb/Text/expected/popover-crashes.txt +++ b/Tests/LibWeb/Text/expected/popover-crashes.txt @@ -1,2 +1,3 @@ Didn't crash when showing recently hidden popover Didn't crash when removing visible popover +Didn't crash when removing popover with changed attribute diff --git a/Tests/LibWeb/Text/input/popover-crashes.html b/Tests/LibWeb/Text/input/popover-crashes.html index 4df1906348e..7e268cb13d6 100644 --- a/Tests/LibWeb/Text/input/popover-crashes.html +++ b/Tests/LibWeb/Text/input/popover-crashes.html @@ -1,6 +1,7 @@
+