From 8a02dacf8e5b11135f826944889ac535264f3e41 Mon Sep 17 00:00:00 2001 From: Luke Warlow Date: Sun, 8 Dec 2024 14:33:27 -0800 Subject: [PATCH] Implement new popover inside invoker behaviour https://bugs.webkit.org/show_bug.cgi?id=283494 Reviewed by Tim Nguyen. This patch matches the new spec behaviour for when a popover is inside its invoker. See https://github.com/whatwg/html/pull/10770 * LayoutTests/imported/w3c/web-platform-tests/html/semantics/popovers/popover-nested-in-button-expected.txt: * Source/WebCore/html/HTMLButtonElement.cpp: (WebCore::HTMLButtonElement::defaultEventHandler): * Source/WebCore/html/HTMLFormControlElement.cpp: (WebCore::HTMLFormControlElement::handlePopoverTargetAction const): * Source/WebCore/html/HTMLFormControlElement.h: * Source/WebCore/html/HTMLInputElement.cpp: (WebCore::HTMLInputElement::defaultEventHandler): Canonical link: https://commits.webkit.org/287522@main --- .../popover-nested-in-button-expected.txt | 4 ++-- Source/WebCore/html/HTMLButtonElement.cpp | 2 +- .../WebCore/html/HTMLFormControlElement.cpp | 21 ++++++++++++------- Source/WebCore/html/HTMLFormControlElement.h | 2 +- Source/WebCore/html/HTMLInputElement.cpp | 2 +- 5 files changed, 18 insertions(+), 13 deletions(-) diff --git a/LayoutTests/imported/w3c/web-platform-tests/html/semantics/popovers/popover-nested-in-button-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/html/semantics/popovers/popover-nested-in-button-expected.txt index 54b765c0cbeaf..e5c2ab7e35e3d 100644 --- a/LayoutTests/imported/w3c/web-platform-tests/html/semantics/popovers/popover-nested-in-button-expected.txt +++ b/LayoutTests/imported/w3c/web-platform-tests/html/semantics/popovers/popover-nested-in-button-expected.txt @@ -1,6 +1,6 @@ Button Button -FAIL clicking a popover nested inside a button should not re-invoke the popover assert_true: Should still be open expected true got false +PASS clicking a popover nested inside a button should not re-invoke the popover PASS corner case: invoker that is also a popover -FAIL invoker inside popover still works, even with weird nesting assert_true: descendant doesn't close popover expected true got false +PASS invoker inside popover still works, even with weird nesting diff --git a/Source/WebCore/html/HTMLButtonElement.cpp b/Source/WebCore/html/HTMLButtonElement.cpp index 7c364074c2bb2..ac9678394fca5 100644 --- a/Source/WebCore/html/HTMLButtonElement.cpp +++ b/Source/WebCore/html/HTMLButtonElement.cpp @@ -172,7 +172,7 @@ void HTMLButtonElement::defaultEventHandler(Event& event) } if (!(protectedForm && m_type == SUBMIT)) - handlePopoverTargetAction(); + handlePopoverTargetAction(event.target()); } diff --git a/Source/WebCore/html/HTMLFormControlElement.cpp b/Source/WebCore/html/HTMLFormControlElement.cpp index 452f2278da9e9..767cb0911cdcd 100644 --- a/Source/WebCore/html/HTMLFormControlElement.cpp +++ b/Source/WebCore/html/HTMLFormControlElement.cpp @@ -395,24 +395,29 @@ void HTMLFormControlElement::setPopoverTargetAction(const AtomString& value) } // https://html.spec.whatwg.org/#popover-target-attribute-activation-behavior -void HTMLFormControlElement::handlePopoverTargetAction() const +void HTMLFormControlElement::handlePopoverTargetAction(const EventTarget* eventTarget) const { - RefPtr target = popoverTargetElement(); - if (!target) + RefPtr popover = popoverTargetElement(); + if (!popover) return; - ASSERT(target->popoverData()); + ASSERT(popover->popoverData()); + + if (RefPtr eventTargetNode = dynamicDowncast(eventTarget)) { + if (popover->containsIncludingShadowDOM(eventTargetNode.get()) && popover->isDescendantOrShadowDescendantOf(this)) + return; + } auto action = popoverTargetAction(); bool canHide = action == hideAtom() || action == toggleAtom(); - bool shouldHide = canHide && target->popoverData()->visibilityState() == PopoverVisibilityState::Showing; + bool shouldHide = canHide && popover->popoverData()->visibilityState() == PopoverVisibilityState::Showing; bool canShow = action == showAtom() || action == toggleAtom(); - bool shouldShow = canShow && target->popoverData()->visibilityState() == PopoverVisibilityState::Hidden; + bool shouldShow = canShow && popover->popoverData()->visibilityState() == PopoverVisibilityState::Hidden; if (shouldHide) - target->hidePopover(); + popover->hidePopover(); else if (shouldShow) - target->showPopover(this); + popover->showPopover(this); } RefPtr HTMLFormControlElement::commandForElement() const diff --git a/Source/WebCore/html/HTMLFormControlElement.h b/Source/WebCore/html/HTMLFormControlElement.h index 5d5fed4eb89be..084b1b14e734e 100644 --- a/Source/WebCore/html/HTMLFormControlElement.h +++ b/Source/WebCore/html/HTMLFormControlElement.h @@ -130,7 +130,7 @@ class HTMLFormControlElement : public HTMLElement, public ValidatedFormListedEle void dispatchBlurEvent(RefPtr&& newFocusedElement) override; - void handlePopoverTargetAction() const; + void handlePopoverTargetAction(const EventTarget*) const; CommandType commandType() const; void handleCommand(); diff --git a/Source/WebCore/html/HTMLInputElement.cpp b/Source/WebCore/html/HTMLInputElement.cpp index 47527d3de5602..faa38c3cc888a 100644 --- a/Source/WebCore/html/HTMLInputElement.cpp +++ b/Source/WebCore/html/HTMLInputElement.cpp @@ -1362,7 +1362,7 @@ void HTMLInputElement::defaultEventHandler(Event& event) if (commandForElement()) handleCommand(); else - handlePopoverTargetAction(); + handlePopoverTargetAction(event.target()); if (event.defaultHandled()) return; }