blob: eef0309a4db21cade0e0a24eff733b273b11457d [file] [log] [blame]
<!DOCTYPE html>
<meta charset="utf-8">
<link rel="author" title="Mason Freed" href="mailto:masonfreed@chromium.org">
<link rel=help href="https://github.com/MicrosoftEdge/MSEdgeExplainers/blob/main/Popup/explainer.md">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script>
function ensureShadowDom(host) {
host.querySelectorAll('my-element').forEach(host => {
if (host.shadowRoot)
return; // Declarative Shadow DOM is enabled
const template = host.firstElementChild;
assert_true(template instanceof HTMLTemplateElement);
const shadow = host.attachShadow({mode: 'open'});
shadow.appendChild(template.content);
template.remove();
})
}
function findPopups(root) {
let popups = [];
if (!root)
return popups;
if (root instanceof HTMLPopupElement)
popups.push(root);
popups.push(...findPopups(root.shadowRoot));
root.childNodes.forEach(child => {
popups.push(...findPopups(child));
})
return popups;
}
function getPopupReferences(testId) {
const testRoot = document.querySelector(`#${testId}`);
assert_true(!!testRoot);
ensureShadowDom(testRoot);
return findPopups(testRoot);
}
function popupVisible(popup) {
return !!(popup.offsetWidth || popup.offsetHeight || popup.getClientRects().length);
}
function showPopup(testId,popupNum) {
getPopupReferences(testId)[popupNum].show();
}
</script>
<div id=test1>
<button onclick='showPopup("test1",0)'>Test1 Popup</button>
<my-element>
<template shadowroot=open>
<popup>
<p>This should show, even though it is inside shadow DOM.</p>
</popup>
</template>
</my-element>
</div>
<script>
test(function() {
const popup = getPopupReferences('test1')[0];
popup.show();
assert_true(popup.open);
assert_true(popupVisible(popup));
}, "Popups located inside shadow DOM can still be shown");
</script>
<div id=test2>
<button id=t2b1 onclick='showPopup("test2",0)'>Test 2 Popup 1</button>
<popup anchor=t2b1 style="top: 400px;">
<p>Popup 1</p>
<button id=t2b2 onclick='showPopup("test2",1)'>Test 2 Popup 2</button>
<my-element>
<template shadowroot=open>
<popup anchor=t2b2 style="top: 400px;">
<p>This popup can never be visible:</p>
<p>Hiding this popup will hide *all* open popups,</p>
<p>because t2b2 doesn't exist in this context.</p>
<p>And since popup 1 is not shown, it is display:none,</p>
<p>which means no child content is shown at all.</p>
</popup>
</template>
</my-element>
</popup>
</div>
<script>
test(function() {
const [popup1,popup2] = getPopupReferences('test2');
popup1.show();
assert_true(popup1.open);
assert_true(popupVisible(popup1));
popup2.show();
assert_false(popup1.open); // P1 was closed by P2
assert_true(popup2.open); // P2 thinks it is open
assert_false(popupVisible(popup1)); // But neither is visible
assert_false(popupVisible(popup2));
}, "anchor references do not cross shadow boundaries");
</script>
<div id=test3>
<my-element>
<template shadowroot=open>
<button id=t3b1 onclick='showPopup("test3",0)'>Test 3 Popup 1</button>
<popup anchor=t3b1>
<p>This popup will be hidden when popup2 shows.</p>
<slot></slot>
</popup>
</template>
<button id=t3b2 onclick='showPopup("test3",1)'>Test 3 Popup 2</button>
</my-element>
<popup anchor=t3b2>Popup 2</popup>
</div>
<script>
test(function() {
const [popup1,popup2] = getPopupReferences('test3');
popup1.show();
assert_true(popup1.open);
assert_true(popupVisible(popup1));
// Showing popup2 will close popup1, since it is not a DOM
// tree ancestor of popup2's anchor button.
popup2.show();
assert_true(popup2.open);
assert_true(popupVisible(popup2));
assert_false(popup1.open);
assert_false(popupVisible(popup1));
popup2.hide();
}, "anchor references use the DOM tree not the flat tree");
</script>
<div id=test4>
<button id=t4b1 onclick='showPopup("test4",0)'>Test 4 Popup 1</button>
<popup anchor=t4b1>
<p>This should not get hidden when popup2 opens.</p>
<my-element>
<template shadowroot=open>
<button id=t4b2 onclick='showPopup("test4",1)'>Test 4 Popup 2</button>
<popup anchor=t4b2>
<p>This should not hide popup1.</p>
</popup>
</template>
</my-element>
</popup>
</div>
<script>
test(function() {
const [popup1,popup2] = getPopupReferences('test4');
popup1.show();
popup2.show();
// Both 1 and 2 should be open at this point.
assert_true(popup1.open);
assert_true(popupVisible(popup1));
assert_true(popup2.open);
assert_true(popupVisible(popup2));
// This should hide both of them.
popup1.hide();
assert_false(popup2.open);
assert_false(popupVisible(popup2));
}, "The popup stack is preserved across shadow-inclusive ancestors");
</script>