Skip to content

Commit 1177032

Browse files
mfreed7moz-wptsync-bot
authored andcommitted
Bug 1870961 [wpt PR 43737] - Update popover=hint behavior to allow a stack of hints, a=testonly
Automatic update from web-platform-tests Update popover=hint behavior to allow a stack of hints The previous implementation only allowed one popover=hint to be open at a time. Per conversation at [1], developers feel that it should be possible to nest popover=hint popovers. This CL implements that capability. There are now two popover stacks in Document: PopoverAutoStack and PopoverHintStack. Since it is possible to nest hints within autos, the PopoverAutoStack can contain hints. However, there are a few constraints: - The PopoverHintStack only ever contains hints. - Once the PopoverAutoStack contains a hint, all subsequent popovers in the stack must also be hints. - A popover=hint can never be the ancestor of a popover=auto. The light dismiss behavior is roughly the same as before, with a slight tweak that simplifies behavior: closing anything in the PopoverAutoStack will always close everything in the PopoverHintStack. That was not the case before, but it was a bit of a weird corner case. Note that I found a crasher (happens in stable, with just auto popovers) that I added a test for here. The bug for that is crbug.com/1513282. I'll fix that in a followup. [1] whatwg/html#9776 (comment) Bug: 1416284,1513282 Change-Id: Ic064ecf1377bb8abfc812654c85016e6d1cbbdaf Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5133909 Reviewed-by: Joey Arhar <[email protected]> Commit-Queue: Mason Freed <[email protected]> Auto-Submit: Mason Freed <[email protected]> Cr-Commit-Position: refs/heads/main@{#1246573} -- wpt-commits: 51c87dc4c5d4a61caef22344e4dba6f5f233ffc3 wpt-pr: 43737
1 parent fb439c7 commit 1177032

File tree

4 files changed

+195
-119
lines changed

4 files changed

+195
-119
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
<!DOCTYPE html>
2+
<meta charset="utf-8" />
3+
<title>Popover light dismiss behavior for hints</title>
4+
<meta name="timeout" content="long">
5+
<link rel="author" href="mailto:[email protected]">
6+
<link rel=help href="https://open-ui.org/components/popover-hint.research.explainer">
7+
<script src="/resources/testharness.js"></script>
8+
<script src="/resources/testharnessreport.js"></script>
9+
<script src="/resources/testdriver.js"></script>
10+
<script src="/resources/testdriver-actions.js"></script>
11+
<script src="/resources/testdriver-vendor.js"></script>
12+
<script src="resources/popover-utils.js"></script>
13+
14+
<div id=outside></div>
15+
<div popover id=auto1>auto 1
16+
<div popover id=auto2>auto 2
17+
<div popover=hint id=innerhint1>inner hint 1
18+
<div popover=hint id=innerhint2>inner hint 2
19+
<div popover id=invalidauto1>Improperly nested auto 1</div>
20+
</div>
21+
</div>
22+
</div>
23+
</div>
24+
<div popover=hint id=hint1>hint 1
25+
<div popover=hint id=hint2>hint 2
26+
<div popover id=invalidauto2>Improperly nested auto 2</div>
27+
</div>
28+
</div>
29+
<div popover=manual id=manual1>Manual</div>
30+
31+
<style>
32+
[popover] {right:auto;bottom:auto;}
33+
#auto1 {left:100px; top:100px;}
34+
#auto2 {left:100px; top:200px;}
35+
#innerhint1 {left:100px; top:300px;}
36+
#innerhint2 {left:100px; top:400px;}
37+
#invalidauto1 {left:100px; top:500px;}
38+
#hint1 {left:200px; top:100px;}
39+
#hint2 {left:200px; top:200px;}
40+
#invalidauto1 {left:200px; top:400px;}
41+
#manual1 {left:300px; top:100px;}
42+
#outside {width:25px;height:25px}
43+
</style>
44+
45+
<script>
46+
const popovers = [
47+
document.querySelector('#auto1'),
48+
document.querySelector('#auto2'),
49+
document.querySelector('#innerhint1'),
50+
document.querySelector('#innerhint2'),
51+
document.querySelector('#hint1'),
52+
document.querySelector('#hint2'),
53+
document.querySelector('#manual1'),
54+
];
55+
function assertState(expectedState,description) {
56+
description = description || 'Error';
57+
const n = popovers.length;
58+
assert_equals(expectedState.length,n,'Invalid');
59+
for(let i=0;i<n;++i) {
60+
assert_equals(popovers[i].matches(':popover-open'),expectedState[i],`${description}, index ${i} (${popovers[i].id})`);
61+
}
62+
}
63+
function openall(t) {
64+
// All popovers can be open at once, if shown in order:
65+
popovers.forEach((p) => p.hidePopover());
66+
popovers.forEach((p) => p.showPopover());
67+
assertState(Array(popovers.length).fill(true),'All popovers should be able to be open at once');
68+
t.add_cleanup(() => popovers.forEach((p) => p.hidePopover()));
69+
}
70+
function nvals(n,val) {
71+
return new Array(n).fill(val);
72+
}
73+
for(let i=0;i<(popovers.length-1);++i) {
74+
promise_test(async (t) => {
75+
openall(t);
76+
await clickOn(popovers[i]);
77+
let expectedState = [...nvals(i+1,true),...nvals(popovers.length-i-2,false),true];
78+
assertState(expectedState);
79+
},`Mixed auto/hint light dismiss behavior, click on ${popovers[i].id}`);
80+
}
81+
82+
promise_test(async (t) => {
83+
openall(t);
84+
await clickOn(outside);
85+
assertState([false,false,false,false,false,false,true]);
86+
},'Clicking outside closes all');
87+
88+
promise_test(async (t) => {
89+
openall(t);
90+
invalidauto1.showPopover();
91+
assertState([true,true,false,false,false,false,true],'auto inside hint ignores the hints and gets nested within auto2');
92+
assert_true(invalidauto1.matches(':popover-open'),'the inner nested auto should be open');
93+
invalidauto1.hidePopover();
94+
assertState([true,true,false,false,false,false,true]);
95+
assert_false(invalidauto1.matches(':popover-open'));
96+
},'Auto cannot be nested inside hint (invalidauto1)');
97+
98+
promise_test(async (t) => {
99+
openall(t);
100+
invalidauto2.showPopover();
101+
assertState([false,false,false,false,false,false,true],'auto inside hint works as an independent (non-nested) auto');
102+
assert_true(invalidauto2.matches(':popover-open'),'the inner nested auto should be open');
103+
invalidauto2.hidePopover();
104+
assertState([false,false,false,false,false,false,true]);
105+
assert_false(invalidauto2.matches(':popover-open'));
106+
},'Auto cannot be nested inside hint (invalidauto2)');
107+
</script>

testing/web-platform/tests/html/semantics/popovers/popover-light-dismiss.html

-46
Original file line numberDiff line numberDiff line change
@@ -449,52 +449,6 @@
449449
},'Ensure circular/convoluted ancestral relationships are functional, with a direct showPopover()');
450450
</script>
451451

452-
<div popover id=p10>Popover</div>
453-
<div popover=hint id=p11>Hint</div>
454-
<div popover=manual id=p12>Manual</div>
455-
<style>
456-
#p10 {top:100px;}
457-
#p11 {top:200px;}
458-
#p12 {top:300px;}
459-
</style>
460-
<script>
461-
if (popoverHintSupported()) {
462-
promise_test(async () => {
463-
const auto = document.querySelector('#p10');
464-
const hint = document.querySelector('#p11');
465-
const manual = document.querySelector('#p12');
466-
// All three can be open at once, if shown in this order:
467-
auto.showPopover();
468-
hint.showPopover();
469-
manual.showPopover();
470-
assert_true(auto.matches(':popover-open'));
471-
assert_true(hint.matches(':popover-open'));
472-
assert_true(manual.matches(':popover-open'));
473-
// Clicking the hint will close the auto, but not the manual.
474-
await clickOn(hint);
475-
assert_false(auto.matches(':popover-open'),'auto should be hidden');
476-
assert_true(hint.matches(':popover-open'),'hint should stay open');
477-
assert_true(manual.matches(':popover-open'),'manual does not light dismiss');
478-
// Clicking outside should close the hint, but not the manual:
479-
await clickOn(outside);
480-
assert_false(auto.matches(':popover-open'));
481-
assert_false(hint.matches(':popover-open'),'hint should close');
482-
assert_true(manual.matches(':popover-open'),'manual does not light dismiss');
483-
manual.hidePopover();
484-
assert_false(manual.matches(':popover-open'));
485-
auto.showPopover();
486-
hint.showPopover();
487-
assert_true(auto.matches(':popover-open'));
488-
assert_true(hint.matches(':popover-open'));
489-
// Clicking on the auto should close the hint:
490-
await clickOn(auto);
491-
assert_true(auto.matches(':popover-open'),'auto should stay open');
492-
assert_false(hint.matches(':popover-open'),'hint should light dismiss');
493-
auto.hidePopover();
494-
assert_false(auto.matches(':popover-open'));
495-
},'Light dismiss of mixed popover types including hints');
496-
}
497-
</script>
498452
<div popover id=p13>Popover 1
499453
<div popover id=p14>Popover 2
500454
<div popover id=p15>Popover 3</div>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<!DOCTYPE html>
2+
<meta charset="utf-8" />
3+
<link rel="author" href="mailto:[email protected]">
4+
<link rel=help href="https://html.spec.whatwg.org/multipage/popover.html#attr-popover">
5+
6+
<div popover id=p1>Popover 1
7+
<div popover id=p2>Popover 2</div>
8+
</div>
9+
<script>
10+
const p1 = document.querySelector('#p1');
11+
const p2 = document.querySelector('#p2');
12+
p1.addEventListener('beforetoggle',e => {
13+
if (e.newState === "closed") {
14+
p2.showPopover();
15+
}
16+
})
17+
p1.showPopover();
18+
p1.hidePopover();
19+
// This test passes if it does not crash
20+
</script>

0 commit comments

Comments
 (0)