155 lines
6.4 KiB
HTML
155 lines
6.4 KiB
HTML
<!DOCTYPE html>
|
|
<meta charset="utf-8">
|
|
<title>Popover combined with dialog/fullscreen behavior</title>
|
|
<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>
|
|
<script src="/resources/testdriver.js"></script>
|
|
<script src="/resources/testdriver-actions.js"></script>
|
|
<script src="/resources/testdriver-vendor.js"></script>
|
|
<script src="/common/top-layer.js"></script>
|
|
<script src="resources/popover-utils.js"></script>
|
|
|
|
<button id=visible>Visible button</button>
|
|
<div id=examples>
|
|
<dialog popover>Popover Dialog</dialog>
|
|
<dialog popover open style="top:50px;">Open Non-modal Popover Dialog</dialog>
|
|
<div popover class=fullscreen>Fullscreen Popover</div>
|
|
<dialog popover class=fullscreen>Fullscreen Popover Dialog</dialog>
|
|
<dialog popover open class=fullscreen style="top:200px;">Fullscreen Open Non-modal Popover Dialog</dialog>
|
|
</div>
|
|
|
|
<style>
|
|
[popover] {
|
|
inset:auto;
|
|
top:0;
|
|
left:0;
|
|
}
|
|
[popover].fullscreen.visible {
|
|
display:block;
|
|
}
|
|
</style>
|
|
|
|
<script>
|
|
const isDialog = (ex) => ex instanceof HTMLDialogElement;
|
|
const isFullscreen = (ex) => ex.classList.contains('fullscreen');
|
|
function ensureIsOpenPopover(ex,message) {
|
|
// Because :popover-open will eventually support <dialog>, this does extra work to
|
|
// verify we're dealing with an :popover-open Popover. Note that this will also throw
|
|
// if this is an element with the `popover` attribute that has been made
|
|
// visible via an explicit `display:block` style rule.
|
|
message = message || 'Error';
|
|
assert_true(ex.matches(':popover-open'),`${message}: Popover doesn\'t match :popover-open`);
|
|
ex.hidePopover(); // Shouldn't throw if this is a showing popover
|
|
ex.showPopover(); // Show it again to avoid state change
|
|
assert_true(ex.matches(':popover-open'),`${message}: Sanity`);
|
|
}
|
|
window.onload = () => requestAnimationFrame(() => requestAnimationFrame(() => {
|
|
const examples = Array.from(document.querySelectorAll('#examples>*'));
|
|
examples.forEach(ex => {
|
|
promise_test(async (t) => {
|
|
t.add_cleanup(() => ex.remove());
|
|
// Test initial conditions
|
|
if (ex.hasAttribute('open')) {
|
|
assert_true(isDialog(ex));
|
|
assert_true(isElementVisible(ex),'Open dialog should be visible by default');
|
|
ex.showPopover(); // Should not throw
|
|
ex.removeAttribute('open');
|
|
ex.hidePopover();
|
|
assert_false(isElementVisible(ex),'Removing the open attribute should hide the dialog');
|
|
} else {
|
|
ex.showPopover(); // Should not throw
|
|
ensureIsOpenPopover(ex,'showPopover should work');
|
|
ex.hidePopover(); // Should not throw
|
|
assert_false(ex.matches(':popover-open'),'hidePopover should work');
|
|
}
|
|
assert_false(isElementVisible(ex));
|
|
|
|
// Start with popover, try the other API
|
|
ex.showPopover();
|
|
ensureIsOpenPopover(ex);
|
|
let tested_something=false;
|
|
if (isDialog(ex)) {
|
|
tested_something=true;
|
|
assert_throws_dom("InvalidStateError",() => ex.showModal(),'Calling showModal() on an already-showing Popover should throw InvalidStateError');
|
|
ex.show(); // Should not throw
|
|
ex.close();
|
|
ex.showPopover();
|
|
}
|
|
if (isFullscreen(ex)) {
|
|
tested_something=true;
|
|
let requestSucceeded = false;
|
|
await blessTopLayer(ex);
|
|
await ex.requestFullscreen()
|
|
.then(() => {requestSucceeded = true;}) // We should not hit this.
|
|
.catch((exception) => {
|
|
// This exception is expected.
|
|
assert_equals(exception.name,'TypeError',`Invalid exception from requestFullscreen() (${exception.message})`);
|
|
});
|
|
assert_false(requestSucceeded,'requestFullscreen() should not succeed when the element is an already-showing Popover');
|
|
}
|
|
assert_true(tested_something);
|
|
ensureIsOpenPopover(ex);
|
|
ex.hidePopover();
|
|
|
|
// Start with the other API, then try popover
|
|
if (isDialog(ex)) {
|
|
ex.show();
|
|
assert_true(ex.hasAttribute('open'));
|
|
ex.showPopover(); // Should not throw
|
|
ex.close();
|
|
assert_false(ex.hasAttribute('open'));
|
|
ex.hidePopover();
|
|
ex.showModal();
|
|
assert_true(ex.hasAttribute('open'));
|
|
assert_throws_dom("InvalidStateError",() => ex.showPopover(),'Calling showPopover() on an already-showing modal dialog should throw InvalidStateError');
|
|
ex.close();
|
|
assert_false(ex.hasAttribute('open'));
|
|
ex.hidePopover();
|
|
} else if (isFullscreen(ex)) {
|
|
let requestSucceeded = false;
|
|
await blessTopLayer(visible);
|
|
await ex.requestFullscreen()
|
|
.then(() => {
|
|
assert_throws_dom("InvalidStateError",() => ex.showPopover(),'Calling showPopover() on an already-fullscreen element should throw InvalidStateError');
|
|
});
|
|
await document.exitFullscreen()
|
|
.then(() => assert_true(true));
|
|
}
|
|
|
|
// Finally, try invoking these combined popovers via a declarative invoker
|
|
const button = document.createElement('button');
|
|
t.add_cleanup(() => button.remove());
|
|
document.body.appendChild(button);
|
|
button.popoverTargetElement = ex;
|
|
button.popoverTargetAction = "toggle";
|
|
assert_false(ex.matches(':popover-open'));
|
|
await clickOn(button);
|
|
ensureIsOpenPopover(ex,'Invoking element should be able to invoke all popovers');
|
|
ex.hidePopover();
|
|
if (isDialog(ex)) {
|
|
ex.showModal();
|
|
assert_true(ex.hasAttribute('open'));
|
|
} else if (isFullscreen(ex)) {
|
|
// Popover fullscreen isn't visible by default, so explicitly add
|
|
// display:block, so that calls to "clickOn" can succeed.
|
|
ex.classList.add('visible');
|
|
await blessTopLayer(ex);
|
|
await ex.requestFullscreen();
|
|
} else {
|
|
assert_unreached('Not a dialog or fullscreen');
|
|
}
|
|
ex.appendChild(button); // Add button to the element, so it's visible to click
|
|
await clickOn(button);
|
|
assert_false(ex.matches(':popover-open'),'The invoker click should have failed on the already-open dialog/fullscreen');
|
|
if (isDialog(ex)) {
|
|
ex.close();
|
|
} else {
|
|
await document.exitFullscreen()
|
|
}
|
|
}, `Popover combination: ${ex.textContent}`);
|
|
});
|
|
}));
|
|
</script>
|