1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173
|
<!DOCTYPE html>
<meta charset="utf-8">
<link rel="author" href="mailto:masonf@chromium.org">
<link rel=help href="https://open-ui.org/components/popover.research.explainer">
<link rel=help href="https://html.spec.whatwg.org/multipage/popover.html">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<!-- Enumerate all the ways of creating an ancestor popover relationship -->
<div class="example">
<p>Direct DOM children</p>
<div popover class=ancestor><p>Ancestor popover</p>
<div popover class=child><p>Child popover</p></div>
</div>
</div>
<div class="example">
<p>Grandchildren</p>
<div popover class=ancestor><p>Ancestor popover</p>
<div>
<div>
<div popover class=child><p>Child popover</p></div>
</div>
</div>
</div>
</div>
<div class="example">
<p>popovertarget attribute relationship</p>
<div popover class=ancestor><p>Ancestor popover</p>
<button popovertarget=trigger1 class=clickme>Button</button>
</div>
<div id=trigger1 popover class=child><p>Child popover</p></div>
</div>
<div class="example">
<p>nested popovertarget attribute relationship</p>
<div popover class=ancestor><p>Ancestor popover</p>
<div>
<div>
<button popovertarget=trigger2 class=clickme>Button</button>
</div>
</div>
</div>
<div id=trigger2 popover class=child><p>Child popover</p></div>
</div>
<div class="example">
<p>anchor attribute relationship</p>
<div id=anchor1 popover class=ancestor><p>Ancestor popover</p></div>
<div anchor=anchor1 popover class=child><p>Child popover</p></div>
</div>
<div class="example">
<p>indirect anchor attribute relationship</p>
<div popover class=ancestor>
<p>Ancestor popover</p>
<div>
<div>
<span id=anchor2>Anchor</span>
</div>
</div>
</div>
<div anchor=anchor2 popover class=child><p>Child popover</p></div>
</div>
<!-- Other examples -->
<div popover id=p1 anchor=b1><p>This is popover #1</p>
<button id=b2 onclick='p2.showPopover()'>Popover 2</button>
<button id=b4 onclick='p4.showPopover()'>Popover 4</button>
</div>
<div popover id=p2 anchor=b2><p>This is popover #2</p>
<button id=b3 onclick='p3.showPopover()'>Popover 3</button>
</div>
<div popover id=p3 anchor=b3><p>This is popover #3</p></div>
<div popover id=p4 anchor=b4><p>This is popover #4</p></div>
<button id=b1 onclick='p1.showPopover()'>Popover 1</button>
<dialog id=d1>This is a dialog<button onclick='this.parentElement.close()'>Close</button></dialog>
<button id=b5 onclick='d1.showPopover()'>Dialog</button>
<script>
// Test basic ancestor relationships
for(let example of document.querySelectorAll('.example')) {
const descr = example.querySelector('p').textContent;
const ancestor = example.querySelector('[popover].ancestor');
const child = example.querySelector('[popover].child');
const clickToActivate = example.querySelector('.clickme');
test(function() {
assert_true(!!descr && !!ancestor && !!child);
assert_false(ancestor.matches(':popover-open'));
assert_false(child.matches(':popover-open'));
ancestor.showPopover();
if (clickToActivate)
clickToActivate.click();
else
child.showPopover();
assert_true(child.matches(':popover-open'));
assert_true(ancestor.matches(':popover-open'));
ancestor.hidePopover();
assert_false(ancestor.matches(':popover-open'));
assert_false(child.matches(':popover-open'));
},descr);
}
const popovers = [p1, p2, p3, p4];
function assertState(...states) {
assert_equals(popovers.length,states.length);
for(let i=0;i<popovers.length;++i) {
assert_equals(popovers[i].matches(':popover-open'),states[i],`Popover #${i+1} incorrect state`);
}
}
test(function() {
assertState(false,false,false,false);
p1.showPopover();
assertState(true,false,false,false);
p2.showPopover();
assertState(true,true,false,false);
p3.showPopover();
assertState(true,true,true,false);
// P4 is a sibling of P2, so showing it should
// close P2 and P3.
p4.showPopover();
assertState(true,false,false,true);
// P2 should close P4 now.
p2.showPopover();
assertState(true,true,false,false);
// Hiding P1 should hide all.
p1.hidePopover();
assertState(false,false,false,false);
}, "more complex nesting, all using anchor ancestry")
test(function() {
function openManyPopovers() {
p1.showPopover();
p2.showPopover();
p3.showPopover();
assertState(true,true,true,false);
}
openManyPopovers();
d1.show(); // Dialog.show() should hide all popovers.
assertState(false,false,false,false);
d1.close();
openManyPopovers();
d1.showModal(); // Dialog.showModal() should also hide all popovers.
assertState(false,false,false,false);
d1.close();
}, "popovers should be closed by dialogs")
test(function() {
// Note: d1 is a <dialog> element, not a popover.
assert_false(d1.open);
d1.show();
assert_true(d1.open);
p1.showPopover();
assertState(true,false,false,false);
assert_true(d1.open);
p1.hidePopover();
assert_true(d1.open);
d1.close();
assert_false(d1.open);
}, "dialogs should not be closed by popovers")
</script>
<style>
#p1 { top:350px; }
#p2 { top:350px; left:200px; }
#p3 { top:500px; }
#p4 { top:500px;left:200px; }
</style>
|