Skip to content

Commit f4a34ff

Browse files
committed
[popover] Implement "check and possibly close popover stack" algorithm
https://bugs.webkit.org/show_bug.cgi?id=254382 Reviewed by Tim Nguyen. Implement "check and possibly close popover stack" algorithm as specified here: whatwg/html#9048 This patch also imports the latest version of popover-target-element-disabled.html. * LayoutTests/imported/w3c/web-platform-tests/html/semantics/popovers/popover-target-element-disabled-expected.txt: * LayoutTests/imported/w3c/web-platform-tests/html/semantics/popovers/popover-target-element-disabled.html: * Source/WebCore/html/HTMLElement.cpp: (WebCore::HTMLElement::checkAndPossiblyClosePopoverStackInternal): * Source/WebCore/html/HTMLElement.h: (WebCore::HTMLElement::checkAndPossiblyClosePopoverStack): * Source/WebCore/html/HTMLFormControlElement.cpp: (WebCore::HTMLFormControlElement::removedFromAncestor): (WebCore::HTMLFormControlElement::parseAttribute): (WebCore::HTMLFormControlElement::disabledStateChanged): (WebCore::HTMLFormControlElement::didChangeForm): * Source/WebCore/html/HTMLFormControlElement.h: * Source/WebCore/html/HTMLInputElement.cpp: (WebCore::HTMLInputElement::updateType): Canonical link: https://commits.webkit.org/262440@main
1 parent 6555fc3 commit f4a34ff

File tree

6 files changed

+48
-8
lines changed

6 files changed

+48
-8
lines changed

LayoutTests/imported/w3c/web-platform-tests/html/semantics/popovers/popover-target-element-disabled-expected.txt

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@ form
22
helloother button
33

44
PASS Disabled popover*target buttons should not affect the popover heirarchy.
5-
FAIL Disabling popover*target buttons when popovers are open should still cause all popovers to be closed when the formerly outer popover is closed. assert_false: The inner popover should be closed when the hierarchy is broken. expected false got true
6-
FAIL Disabling popover*target buttons when popovers are open should still cause all popovers to be closed when the formerly inner popover is closed. assert_false: The inner popover be should be closed when the hierarchy is broken. expected false got true
7-
FAIL Setting the form attribute on popover*target buttons when popovers are open should close all popovers. assert_false: The inner popover be should be closed when the hierarchy is broken. expected false got true
8-
FAIL Changing the input type on a popover*target button when popovers are open should close all popovers. assert_false: The inner popover be should be closed when the hierarchy is broken. expected false got true
9-
FAIL Disconnecting popover*target buttons when popovers are open should close all popovers. assert_false: The inner popover be should be closed when the hierarchy is broken. expected false got true
10-
FAIL Changing the popovertarget attribute to break the chain should close all popovers. assert_false: The inner popover be should be closed when the hierarchy is broken. expected false got true
5+
PASS Disabling popover*target buttons when popovers are open should still cause all popovers to be closed when the formerly outer popover is closed.
6+
PASS Disabling popover*target buttons when popovers are open should still cause all popovers to be closed when the formerly inner popover is closed.
7+
PASS Setting the form attribute on popover*target buttons when popovers are open should close all popovers.
8+
PASS Changing the input type on a popover*target button when popovers are open should close all popovers.
9+
PASS Disconnecting popover*target buttons when popovers are open should close all popovers.
10+
PASS Changing the popovertarget attribute to break the chain should close all popovers.
1111
PASS Modifying popovertarget on a button which doesn't break the chain shouldn't close any popovers.
1212

Source/WebCore/html/HTMLElement.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1284,6 +1284,23 @@ static HTMLElement* topmostPopoverAncestor(Element& newPopover)
12841284
return topmostAncestor.get();
12851285
}
12861286

1287+
void HTMLElement::checkAndPossiblyClosePopoverStackInternal()
1288+
{
1289+
Vector<RefPtr<Element>> autoPopoverList;
1290+
for (auto& element : document().topLayerElements()) {
1291+
if (!is<HTMLElement>(element) || downcast<HTMLElement>(element.get()).popoverState() != PopoverState::Auto)
1292+
continue;
1293+
autoPopoverList.append(element.ptr());
1294+
}
1295+
1296+
for (size_t i = autoPopoverList.size(); i-- > 1;) {
1297+
if (topmostPopoverAncestor(*autoPopoverList[i]) != autoPopoverList[i - 1]) {
1298+
document().hideAllPopoversUntil(nullptr, FocusPreviousElement::No, FireEvents::No);
1299+
return;
1300+
}
1301+
}
1302+
}
1303+
12871304
// https://html.spec.whatwg.org/#popover-focusing-steps
12881305
static void runPopoverFocusingSteps(HTMLElement& popover)
12891306
{

Source/WebCore/html/HTMLElement.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#pragma once
2424

2525
#include "ColorTypes.h"
26+
#include "Document.h"
2627
#include "HTMLNames.h"
2728
#include "InputMode.h"
2829
#include "StyledElement.h"
@@ -191,6 +192,13 @@ class HTMLElement : public StyledElement {
191192
void childrenChanged(const ChildChange&) override;
192193
void updateEffectiveDirectionalityOfDirAuto();
193194

195+
void checkAndPossiblyClosePopoverStack()
196+
{
197+
if (!document().settings().popoverAttributeEnabled() || !document().hasTopLayerElement())
198+
return;
199+
checkAndPossiblyClosePopoverStackInternal();
200+
}
201+
194202
using EventHandlerNameMap = HashMap<AtomStringImpl*, AtomString>;
195203
static const AtomString& eventNameForEventHandlerAttribute(const QualifiedName& attributeName, const EventHandlerNameMap&);
196204

@@ -214,6 +222,7 @@ class HTMLElement : public StyledElement {
214222
enum class UseCSSPXAsUnitType : bool { No, Yes };
215223
enum class IsMultiLength : bool { No, Yes };
216224
void addHTMLLengthToStyle(MutableStyleProperties&, CSSPropertyID, StringView value, AllowPercentage, UseCSSPXAsUnitType, IsMultiLength, AllowZeroValue = AllowZeroValue::Yes);
225+
void checkAndPossiblyClosePopoverStackInternal();
217226
};
218227

219228
inline HTMLElement::HTMLElement(const QualifiedName& tagName, Document& document, ConstructionType type = CreateHTMLElement)

Source/WebCore/html/HTMLFormControlElement.cpp

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,7 @@ void HTMLFormControlElement::removedFromAncestor(RemovalType removalType, Contai
141141
{
142142
HTMLElement::removedFromAncestor(removalType, oldParentOfRemovedTree);
143143
ValidatedFormListedElement::removedFromAncestor(removalType, oldParentOfRemovedTree);
144+
checkAndPossiblyClosePopoverStack();
144145
}
145146

146147
void HTMLFormControlElement::parseAttribute(const QualifiedName& name, const AtomString& value)
@@ -152,7 +153,9 @@ void HTMLFormControlElement::parseAttribute(const QualifiedName& name, const Ato
152153
m_isRequired = newRequired;
153154
requiredStateChanged();
154155
}
155-
} else {
156+
} else if (name == popovertargetAttr)
157+
checkAndPossiblyClosePopoverStack();
158+
else {
156159
HTMLElement::parseAttribute(name, value);
157160
ValidatedFormListedElement::parseAttribute(name, value);
158161
}
@@ -170,6 +173,7 @@ void HTMLFormControlElement::disabledStateChanged()
170173
ValidatedFormListedElement::disabledStateChanged();
171174
if (renderer() && renderer()->style().hasEffectiveAppearance())
172175
renderer()->theme().stateChanged(*renderer(), ControlStates::States::Enabled);
176+
checkAndPossiblyClosePopoverStack();
173177
}
174178

175179
void HTMLFormControlElement::readOnlyStateChanged()
@@ -407,4 +411,10 @@ bool HTMLFormControlElement::needsMouseFocusableQuirk() const
407411
return document().quirks().needsFormControlToBeMouseFocusable();
408412
}
409413

410-
} // namespace WebCore
414+
void HTMLFormControlElement::didChangeForm()
415+
{
416+
ValidatedFormListedElement::didChangeForm();
417+
checkAndPossiblyClosePopoverStack();
418+
}
419+
420+
} // namespace Webcore

Source/WebCore/html/HTMLFormControlElement.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,8 @@ class HTMLFormControlElement : public HTMLElement, public ValidatedFormListedEle
127127

128128
void handlePopoverTargetAction() const;
129129

130+
void didChangeForm() override;
131+
130132
private:
131133
void refFormAssociatedElement() const final { ref(); }
132134
void derefFormAssociatedElement() const final { deref(); }

Source/WebCore/html/HTMLInputElement.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -586,6 +586,8 @@ void HTMLInputElement::updateType()
586586
}
587587

588588
updateValidity();
589+
590+
checkAndPossiblyClosePopoverStack();
589591
}
590592

591593
inline void HTMLInputElement::runPostTypeUpdateTasks()

0 commit comments

Comments
 (0)