mirror of
https://github.com/servo/servo.git
synced 2025-08-06 22:15:33 +01:00
Update web-platform-tests to revision b'b728032f59a396243864b0f8584e7211e3632005'
This commit is contained in:
parent
ace9b32b1c
commit
df68c4e5d1
15632 changed files with 514865 additions and 155000 deletions
|
@ -0,0 +1,16 @@
|
|||
<!DOCTYPE html>
|
||||
<link rel=author href="mailto:vmpstr@chromium.org">
|
||||
<link rel=help href="https://bugs.chromium.org/p/chromium/issues/detail?id=1334983">
|
||||
|
||||
<canvas>
|
||||
<details>
|
||||
<card card>
|
||||
|
||||
<script>
|
||||
async function trigger() {
|
||||
document.querySelector("canvas").style.setProperty("container-type", "size");
|
||||
document.querySelector("canvas").style.setProperty("column-span", "all");
|
||||
document.querySelector("card").setAttribute("contenteditable", "true");
|
||||
}
|
||||
onload = requestAnimationFrame(() => requestAnimationFrame(trigger));
|
||||
</script>
|
|
@ -0,0 +1,52 @@
|
|||
<!doctype html>
|
||||
<meta charset="utf-8">
|
||||
<title>Details activation with space bar</title>
|
||||
<link rel="author" href="mailto:emilio@crisal.io" title="Emilio Cobos Álvarez">
|
||||
<link rel="author" href="https://mozilla.org" title="Mozilla">
|
||||
<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1726454">
|
||||
<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>
|
||||
<style>
|
||||
:root {
|
||||
scroll-behavior: instant;
|
||||
}
|
||||
.spacer {
|
||||
height: 200vh;
|
||||
}
|
||||
</style>
|
||||
<details>
|
||||
<summary>Activate me with the <kbd>Space</kbd> key</summary>
|
||||
<p>Summary</p>
|
||||
</details>
|
||||
<div class="spacer"></div>
|
||||
<script>
|
||||
function tick() {
|
||||
return new Promise(resolve => requestAnimationFrame(() => requestAnimationFrame(resolve)));
|
||||
}
|
||||
|
||||
promise_test(async t => {
|
||||
const details = document.querySelector("details");
|
||||
const summary = details.querySelector("summary");
|
||||
|
||||
summary.focus();
|
||||
assert_equals(document.activeElement, summary, "Summary should be focusable");
|
||||
assert_false(details.open, "Details should be closed");
|
||||
|
||||
const oldScrollY = window.scrollY;
|
||||
assert_equals(oldScrollY, 0, "Should be at top");
|
||||
|
||||
window.addEventListener("scroll", t.unreached_func("Unexpected scroll event"));
|
||||
|
||||
await test_driver.send_keys(summary, " ");
|
||||
|
||||
assert_true(details.open, "Space bar on summary should open details");
|
||||
assert_equals(window.scrollY, oldScrollY, "Scroll position shouldn't change");
|
||||
|
||||
await tick();
|
||||
|
||||
assert_equals(window.scrollY, oldScrollY, "Scroll position shouldn't change");
|
||||
});
|
||||
</script>
|
|
@ -32,7 +32,12 @@
|
|||
<summary>Lorem ipsum</summary>
|
||||
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
|
||||
</details>
|
||||
<details id=details9 open>
|
||||
<script>
|
||||
window.details9TogglePromise = new Promise(resolve => {
|
||||
window.details9TogglePromiseResolver = resolve;
|
||||
});
|
||||
</script>
|
||||
<details id=details9 ontoggle="window.details9TogglePromiseResolver()" open>
|
||||
<summary>Lorem ipsum</summary>
|
||||
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
|
||||
</details>
|
||||
|
@ -128,22 +133,20 @@
|
|||
});
|
||||
details8.removeAttribute('open'); // closes details8
|
||||
|
||||
var toggleFiredOnDetails9 = false;
|
||||
details9.ontoggle = t9.step_func_done(function(evt) {
|
||||
if (toggleFiredOnDetails9) {
|
||||
window.details9TogglePromise.then(t9.step_func(() => {
|
||||
// The toggle event should be fired once when declaring details9 with open
|
||||
// attribute.
|
||||
details9.ontoggle = t9.step_func(() => {
|
||||
assert_unreached("toggle event fired twice on opened details element");
|
||||
} else {
|
||||
toggleFiredOnDetails9 = true;
|
||||
}
|
||||
});
|
||||
// The toggle event should be fired once when declaring details9 with open
|
||||
// attribute.
|
||||
details9.open = true; // opens details9
|
||||
t9.step_timeout(function() {
|
||||
assert_true(details9.open);
|
||||
assert_true(toggleFiredOnDetails9);
|
||||
t9.done();
|
||||
}, 0);
|
||||
});
|
||||
// setting open=true on details9 should not fire another event since it is
|
||||
// already open.
|
||||
details9.open = true;
|
||||
t9.step_timeout(() => {
|
||||
assert_true(details9.open);
|
||||
t9.done();
|
||||
});
|
||||
}));
|
||||
|
||||
details10.ontoggle = t10.step_func_done(function(evt) {
|
||||
assert_unreached("toggle event fired on closed details element");
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
<!doctype html>
|
||||
<meta charset=utf-8>
|
||||
<title>Test for dialog element colors</title>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<style>
|
||||
:root { background-color: Canvas; color: CanvasText; }
|
||||
#light { color-scheme: light }
|
||||
#dark { color-scheme: dark }
|
||||
</style>
|
||||
<dialog id="dialog" open>
|
||||
This is a dialog
|
||||
</dialog>
|
||||
<dialog id="light" open>
|
||||
This is a dialog
|
||||
</dialog>
|
||||
<dialog id="dark" open>
|
||||
This is a dialog
|
||||
</dialog>
|
||||
<script>
|
||||
test(function() {
|
||||
let dialog = document.getElementById("dialog");
|
||||
let cs = getComputedStyle(dialog);
|
||||
let rootCs = getComputedStyle(document.documentElement);
|
||||
assert_equals(cs.color, rootCs.color, "Dialog color should match CanvasText");
|
||||
assert_equals(cs.backgroundColor, rootCs.backgroundColor, "Dialog background should match Canvas");
|
||||
}, "<dialog> color and background match default")
|
||||
|
||||
test(function() {
|
||||
let lightCs = getComputedStyle(document.getElementById("light"));
|
||||
let darkCs = getComputedStyle(document.getElementById("dark"));
|
||||
assert_not_equals(lightCs.color, darkCs.color, "Dialog color should react to color-scheme");
|
||||
assert_not_equals(lightCs.backgroundColor, darkCs.backgroundColor, "Dialog background should react to color-scheme");
|
||||
}, "<dialog> colors react to dark mode")
|
||||
</script>
|
|
@ -0,0 +1,55 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test cancel event is fired when the dialog is closed by user interaction</title>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="/resources/testdriver.js"></script>
|
||||
<script src="/resources/testdriver-vendor.js"></script>
|
||||
<link rel="help" href="https://bugs.webkit.org/show_bug.cgi?id=227534">
|
||||
<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1322947">
|
||||
</head>
|
||||
<body>
|
||||
<p>Test cancel event is fired when the dialog is closed by user interaction</p>
|
||||
<dialog>
|
||||
<p>Hello World</p>
|
||||
<button>user activation button</button>
|
||||
</dialog>
|
||||
<script>
|
||||
setup({ single_test: true });
|
||||
|
||||
var hasCancelEventFired = false;
|
||||
var hasCloseEventFired = false;
|
||||
|
||||
const dialog = document.querySelector("dialog");
|
||||
|
||||
dialog.addEventListener("cancel", function(event) {
|
||||
assert_true(true, "cancel event is fired");
|
||||
assert_true(event.cancelable, "cancel event should be cancelable");
|
||||
assert_false(hasCancelEventFired, "cancel event should only be fired once");
|
||||
assert_false(hasCloseEventFired, "close event should be fired after cancel event");
|
||||
hasCancelEventFired = true;
|
||||
});
|
||||
|
||||
dialog.addEventListener("close", function() {
|
||||
assert_true(true, "close event is fired");
|
||||
assert_false(hasCloseEventFired, "close event should only be fired once");
|
||||
assert_true(hasCancelEventFired, "cancel event should be fired before close event");
|
||||
hasCloseEventFired = true;
|
||||
done();
|
||||
});
|
||||
|
||||
dialog.showModal();
|
||||
|
||||
(async () => {
|
||||
// Pressing escape on the dialog needs user activation or else the cancel event won't be fired.
|
||||
const button = dialog.querySelector('button');
|
||||
const buttonClickPromise = new Promise(resolve => button.onclick = resolve);
|
||||
await test_driver.click(button);
|
||||
await buttonClickPromise;
|
||||
|
||||
test_driver.send_keys(document.documentElement, "\uE00C"); // ESC key
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,55 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test cancel event with preventDefault on cancel event for dialog element</title>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="/resources/testdriver.js"></script>
|
||||
<script src="/resources/testdriver-vendor.js"></script>
|
||||
<link rel="help" href="https://bugs.webkit.org/show_bug.cgi?id=227534">
|
||||
<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1322947">
|
||||
</head>
|
||||
<body>
|
||||
<p>Test cancel event with preventDefault on cancel event for dialog element</p>
|
||||
<dialog>
|
||||
<p>Hello World</p>
|
||||
<button>user activation button</button>
|
||||
</dialog>
|
||||
<script>
|
||||
setup({ single_test: true });
|
||||
|
||||
var hasCancelEventFired = false;
|
||||
|
||||
const dialog = document.querySelector("dialog");
|
||||
|
||||
const verify = () => {
|
||||
assert_true(hasCancelEventFired, "cancel is fired");
|
||||
done();
|
||||
};
|
||||
|
||||
dialog.addEventListener("cancel", function(event) {
|
||||
hasCancelEventFired = true;
|
||||
event.preventDefault();
|
||||
step_timeout(function() {
|
||||
verify();
|
||||
}, 0)
|
||||
});
|
||||
|
||||
dialog.addEventListener("close", function() {
|
||||
assert_true(false, "close event should not be fired");
|
||||
});
|
||||
|
||||
dialog.showModal();
|
||||
|
||||
(async () => {
|
||||
// Pressing escape on the dialog needs user activation or else the cancel event won't be fired.
|
||||
const button = dialog.querySelector('button');
|
||||
const buttonClickPromise = new Promise(resolve => button.onclick = resolve);
|
||||
await test_driver.click(button);
|
||||
await buttonClickPromise;
|
||||
|
||||
test_driver.send_keys(document.documentElement, "\uE00C"); // ESC key
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -1,12 +1,12 @@
|
|||
<!DOCTYPE html>
|
||||
<meta charset="utf-8">
|
||||
<title>dialog focusing delegation with autofocus plus delegatesFocus inside the dialog</title>
|
||||
<title>dialog focusing delegation: with two nested shadow trees</title>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<body>
|
||||
|
||||
<dialog>
|
||||
<template class="turn-into-shadow-tree">
|
||||
<template class="turn-into-shadow-tree delegates-focus">
|
||||
<button disabled>Non-focusable</button>
|
||||
<template class="turn-into-shadow-tree delegates-focus">
|
||||
<button tabindex="-1">Focusable</button>
|
|
@ -1,62 +1,256 @@
|
|||
<!DOCTYPE html>
|
||||
<meta charset="utf-8">
|
||||
<title>dialog focus delegation</title>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<body>
|
||||
|
||||
<dialog data-description="When autofocus is not present, the first focusable shadow-including descendant must be focused">
|
||||
<template class="turn-into-shadow-tree">
|
||||
<button disabled>Non-focusable</button>
|
||||
<button tabindex="-1" class="focus-me">Focusable</button>
|
||||
<button disabled>Non-focusable</button>
|
||||
</template>
|
||||
</dialog>
|
||||
<!--
|
||||
We focus this one between each test, to ensure that for non-modal dialogs,
|
||||
if there is no focus delegate, it stays focused (instead of causing focus to reset to the body).
|
||||
-->
|
||||
<button tabindex="-1" id="focus-between-tests">Focus between tests</button>
|
||||
|
||||
<dialog data-description="autofocus outside a shadow tree must take precedence over earlier in-shadow-tree focusable elements">
|
||||
<button disabled>Non-focusable</button>
|
||||
<dialog data-description="No autofocus, no delegatesFocus, no siblings">
|
||||
<template class="turn-into-shadow-tree">
|
||||
<button disabled>Non-focusable</button>
|
||||
<button tabindex="-1">Focusable</button>
|
||||
<button disabled>Non-focusable</button>
|
||||
</template>
|
||||
<button tabindex="-1" autofocus>Focusable</button>
|
||||
</dialog>
|
||||
|
||||
<dialog data-description="autofocus inside a shadow tree must be ignored: no focusable elements outside the shadow tree">
|
||||
<dialog data-description="No autofocus, no delegatesFocus, sibling before">
|
||||
<button tabindex="-1" class="focus-me">Focusable</button>
|
||||
<template class="turn-into-shadow-tree">
|
||||
<button disabled>Non-focusable</button>
|
||||
<button tabindex="-1">Focusable</button>
|
||||
<button disabled>Non-focusable</button>
|
||||
</template>
|
||||
</dialog>
|
||||
|
||||
<dialog data-description="No autofocus, no delegatesFocus, sibling after">
|
||||
<template class="turn-into-shadow-tree">
|
||||
<button disabled>Non-focusable</button>
|
||||
<button tabindex="-1">Focusable</button>
|
||||
<button disabled>Non-focusable</button>
|
||||
</template>
|
||||
<button tabindex="-1" class="focus-me">Focusable</button>
|
||||
</dialog>
|
||||
|
||||
<dialog data-description="No autofocus, yes delegatesFocus, no siblings">
|
||||
<template class="turn-into-shadow-tree delegates-focus">
|
||||
<button disabled>Non-focusable</button>
|
||||
<button tabindex="-1" class="focus-me">Focusable</button>
|
||||
<button disabled>Non-focusable</button>
|
||||
</template>
|
||||
</dialog>
|
||||
|
||||
<dialog data-description="No autofocus, yes delegatesFocus, sibling before">
|
||||
<button tabindex="-1" class="focus-me">Focusable</button>
|
||||
<template class="turn-into-shadow-tree delegates-focus">
|
||||
<button disabled>Non-focusable</button>
|
||||
<button tabindex="-1">Focusable</button>
|
||||
<button disabled>Non-focusable</button>
|
||||
</template>
|
||||
</dialog>
|
||||
|
||||
<dialog data-description="No autofocus, yes delegatesFocus, sibling after">
|
||||
<template class="turn-into-shadow-tree delegates-focus">
|
||||
<button disabled>Non-focusable</button>
|
||||
<button tabindex="-1" class="focus-me">Focusable</button>
|
||||
<button disabled>Non-focusable</button>
|
||||
</template>
|
||||
<button tabindex="-1">Focusable</button>
|
||||
</dialog>
|
||||
|
||||
<dialog data-description="Autofocus before, no delegatesFocus">
|
||||
<button tabindex="-1" autofocus class="focus-me">Focusable</button>
|
||||
<template class="turn-into-shadow-tree">
|
||||
<button disabled>Non-focusable</button>
|
||||
<button tabindex="-1">Focusable</button>
|
||||
<button disabled>Non-focusable</button>
|
||||
</template>
|
||||
</dialog>
|
||||
|
||||
<dialog data-description="Autofocus before, yes delegatesFocus">
|
||||
<button tabindex="-1" autofocus class="focus-me">Focusable</button>
|
||||
<template class="turn-into-shadow-tree delegates-focus">
|
||||
<button disabled>Non-focusable</button>
|
||||
<button tabindex="-1">Focusable</button>
|
||||
<button disabled>Non-focusable</button>
|
||||
</template>
|
||||
</dialog>
|
||||
|
||||
<dialog data-description="Autofocus after, no delegatesFocus">
|
||||
<template class="turn-into-shadow-tree">
|
||||
<button disabled>Non-focusable</button>
|
||||
<button tabindex="-1">Focusable</button>
|
||||
<button disabled>Non-focusable</button>
|
||||
</template>
|
||||
<button tabindex="-1" autofocus class="focus-me">Focusable</button>
|
||||
</dialog>
|
||||
|
||||
<dialog data-description="Autofocus after, yes delegatesFocus">
|
||||
<template class="turn-into-shadow-tree delegates-focus">
|
||||
<button disabled>Non-focusable</button>
|
||||
<button tabindex="-1">Focusable</button>
|
||||
<button disabled>Non-focusable</button>
|
||||
</template>
|
||||
<button tabindex="-1" autofocus class="focus-me">Focusable</button>
|
||||
</dialog>
|
||||
|
||||
<dialog data-description="Autofocus on shadow host, yes delegatesFocus, no siblings">
|
||||
<template class="turn-into-shadow-tree delegates-focus autofocus">
|
||||
<button disabled>Non-focusable</button>
|
||||
<button tabindex="-1" class="focus-me">Focusable</button>
|
||||
<button disabled>Non-focusable</button>
|
||||
</template>
|
||||
</dialog>
|
||||
|
||||
<dialog data-description="Autofocus on shadow host, yes delegatesFocus, sibling before">
|
||||
<button tabindex="-1">Focusable</button>
|
||||
<template class="turn-into-shadow-tree delegates-focus autofocus">
|
||||
<button disabled>Non-focusable</button>
|
||||
<button tabindex="-1" class="focus-me">Focusable</button>
|
||||
<button disabled>Non-focusable</button>
|
||||
</template>
|
||||
</dialog>
|
||||
|
||||
<dialog data-description="Autofocus on shadow host, yes delegatesFocus, sibling after">
|
||||
<template class="turn-into-shadow-tree delegates-focus autofocus">
|
||||
<button disabled>Non-focusable</button>
|
||||
<button tabindex="-1" class="focus-me">Focusable</button>
|
||||
<button disabled>Non-focusable</button>
|
||||
</template>
|
||||
<button tabindex="-1">Focusable</button>
|
||||
</dialog>
|
||||
|
||||
<dialog data-description="Autofocus on shadow host, no delegatesFocus, no siblings">
|
||||
<template class="turn-into-shadow-tree autofocus">
|
||||
<button disabled>Non-focusable</button>
|
||||
<button tabindex="-1">Focusable</button>
|
||||
<button disabled>Non-focusable</button>
|
||||
</template>
|
||||
</dialog>
|
||||
|
||||
<dialog data-description="Autofocus on shadow host, no delegatesFocus, sibling before">
|
||||
<button tabindex="-1" class="focus-me">Focusable</button>
|
||||
<template class="turn-into-shadow-tree autofocus">
|
||||
<button disabled>Non-focusable</button>
|
||||
<button tabindex="-1">Focusable</button>
|
||||
<button disabled>Non-focusable</button>
|
||||
</template>
|
||||
</dialog>
|
||||
|
||||
<dialog data-description="Autofocus on shadow host, no delegatesFocus, sibling after">
|
||||
<template class="turn-into-shadow-tree autofocus">
|
||||
<button disabled>Non-focusable</button>
|
||||
<button tabindex="-1">Focusable</button>
|
||||
<button disabled>Non-focusable</button>
|
||||
</template>
|
||||
<button tabindex="-1" class="focus-me">Focusable</button>
|
||||
</dialog>
|
||||
|
||||
<dialog data-description="Autofocus inside shadow tree, yes delegatesFocus, no siblings">
|
||||
<template class="turn-into-shadow-tree delegates-focus">
|
||||
<button tabindex="-1">Focusable</button>
|
||||
<button tabindex="-1" autofocus class="focus-me">Focusable</button>
|
||||
<button disabled>Non-focusable</button>
|
||||
</template>
|
||||
</dialog>
|
||||
|
||||
<dialog data-description="Autofocus inside shadow tree, yes delegatesFocus, sibling before">
|
||||
<button tabindex="-1" class="focus-me">Focusable</button>
|
||||
<template class="turn-into-shadow-tree delegates-focus">
|
||||
<button tabindex="-1">Focusable</button>
|
||||
<button tabindex="-1" autofocus>Focusable</button>
|
||||
<button tabindex="-1">Focusable</button>
|
||||
<button disabled>Non-focusable</button>
|
||||
</template>
|
||||
</dialog>
|
||||
|
||||
<dialog data-description="autofocus inside a shadow tree must be ignored: focusable element before the shadow tree">
|
||||
<dialog data-description="Autofocus inside shadow tree, yes delegatesFocus, sibling after">
|
||||
<template class="turn-into-shadow-tree delegates-focus">
|
||||
<button tabindex="-1">Focusable</button>
|
||||
<button tabindex="-1" autofocus class="focus-me">Focusable</button>
|
||||
<button disabled>Non-focusable</button>
|
||||
</template>
|
||||
<button tabindex="-1">Focusable</button>
|
||||
</dialog>
|
||||
|
||||
<dialog data-description="Autofocus inside shadow tree, no delegatesFocus, no siblings">
|
||||
<template class="turn-into-shadow-tree">
|
||||
<button tabindex="-1">Focusable</button>
|
||||
<button tabindex="-1" autofocus>Focusable</button>
|
||||
<button disabled>Non-focusable</button>
|
||||
</template>
|
||||
</dialog>
|
||||
|
||||
<dialog data-description="Autofocus inside shadow tree, no delegatesFocus, sibling before">
|
||||
<button tabindex="-1" class="focus-me">Focusable</button>
|
||||
<template class="turn-into-shadow-tree">
|
||||
<button tabindex="-1">Focusable</button>
|
||||
<button tabindex="-1" autofocus>Focusable</button>
|
||||
<button tabindex="-1">Focusable</button>
|
||||
<button disabled>Non-focusable</button>
|
||||
</template>
|
||||
</dialog>
|
||||
|
||||
<dialog data-description="autofocus inside a shadow tree must be ignored: focusable element after the shadow tree">
|
||||
<dialog data-description="Autofocus inside shadow tree, no delegatesFocus, sibling after">
|
||||
<template class="turn-into-shadow-tree">
|
||||
<button tabindex="-1">Focusable</button>
|
||||
<button tabindex="-1" autofocus>Focusable</button>
|
||||
<button disabled>Non-focusable</button>
|
||||
</template>
|
||||
<button tabindex="-1" class="focus-me">Focusable</button>
|
||||
</dialog>
|
||||
|
||||
<dialog data-description="Two shadow trees, both delegatesFocus, first tree doesn't have autofocus element, second does">
|
||||
<template class="turn-into-shadow-tree delegates-focus">
|
||||
<button disabled>Non-focusable</button>
|
||||
<button tabindex="-1" class="focus-me">Focusable</button>
|
||||
<button disabled>Non-focusable</button>
|
||||
</template>
|
||||
<template class="turn-into-shadow-tree delegates-focus">
|
||||
<button tabindex="-1" autofocus>Focusable</button>
|
||||
</template>
|
||||
</dialog>
|
||||
|
||||
<dialog data-description="No autofocus, no delegatesFocus, slotted target">
|
||||
<template class="turn-into-shadow-tree">
|
||||
<button tabindex="-1">Focusable</button>
|
||||
<slot></slot>
|
||||
<button tabindex="-1">Focusable</button>
|
||||
</template>
|
||||
<button tabindex="-1" class="focus-me">Focusable</button>
|
||||
</dialog>
|
||||
|
||||
<dialog data-description="Shadowroot on child, no autofocus, no delegatesFocus">
|
||||
<div>
|
||||
<template class="turn-into-shadow-tree">
|
||||
<button tabindex="-1">Focusable</button>
|
||||
</template>
|
||||
</div>
|
||||
<button tabindex="-1" class="focus-me">Focusable</button>
|
||||
</dialog>
|
||||
|
||||
<script>
|
||||
for (const template of document.querySelectorAll(".turn-into-shadow-tree")) {
|
||||
const div = document.createElement("div");
|
||||
div.attachShadow({ mode: "open" });
|
||||
div.attachShadow({ mode: "open", delegatesFocus: template.classList.contains("delegates-focus") });
|
||||
|
||||
if (template.classList.contains("autofocus")) {
|
||||
div.setAttribute("autofocus", true);
|
||||
}
|
||||
div.shadowRoot.append(template.content);
|
||||
template.replaceWith(div);
|
||||
}
|
||||
|
||||
const focusBetweenTests = document.querySelector("#focus-between-tests");
|
||||
|
||||
for (const dialog of document.querySelectorAll("dialog")) {
|
||||
for (const method of ["show", "showModal"]) {
|
||||
test(t => {
|
||||
focusBetweenTests.focus();
|
||||
|
||||
dialog[method]();
|
||||
t.add_cleanup(() => dialog.close());
|
||||
|
||||
|
@ -66,10 +260,17 @@ for (const dialog of document.querySelectorAll("dialog")) {
|
|||
} else {
|
||||
const shadowHost = dialog.querySelector("div");
|
||||
const expectedFocusInsideShadowTree = shadowHost.shadowRoot.querySelector(".focus-me");
|
||||
assert_not_equals(expectedFocusInsideShadowTree, "Precondition check: the test was set up to expect a focused element, either outside the shadow tree or inside");
|
||||
|
||||
assert_equals(document.activeElement, shadowHost);
|
||||
assert_equals(shadowHost.shadowRoot.activeElement, expectedFocusInsideShadowTree);
|
||||
if (expectedFocusInsideShadowTree) {
|
||||
assert_equals(document.activeElement, shadowHost);
|
||||
assert_equals(shadowHost.shadowRoot.activeElement, expectedFocusInsideShadowTree);
|
||||
} else {
|
||||
// There is no focus delegate. Expected result depends on show() vs. showModal().
|
||||
if (method === "show") {
|
||||
assert_equals(document.activeElement, focusBetweenTests);
|
||||
} else {
|
||||
assert_equals(document.activeElement, document.body);
|
||||
}
|
||||
}
|
||||
}
|
||||
}, `${method}: ${dialog.dataset.description}`);
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ test(function() {
|
|||
|
||||
const dialog = document.createElement("dialog");
|
||||
assert_false(dialog.open, "Dialog should initially be closed");
|
||||
assert_false(dialog.hasAttribute('open'), "Dialog should initially be closed");
|
||||
|
||||
const innerInput = document.createElement("input");
|
||||
innerInput.autofocus = true;
|
||||
|
@ -23,6 +24,8 @@ test(function() {
|
|||
|
||||
dialog.show();
|
||||
this.add_cleanup(() => { dialog.close(); });
|
||||
assert_true(dialog.open, "Disconnected dialog can still be open");
|
||||
|
||||
|
||||
assert_equals(document.activeElement, outerInput, "Focusing steps should not change focus");
|
||||
}, "dialog.show(): focusing steps should not change focus on disconnected <dialog>");
|
||||
|
|
|
@ -1,35 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<link rel=author href="mailto:jarhar@chromium.org">
|
||||
<link rel=author href="mailto:falken@chromium.org">
|
||||
<link rel=help href="https://html.spec.whatwg.org/multipage/interactive-elements.html#the-dialog-element">
|
||||
<link rel=help href="https://bugs.webkit.org/show_bug.cgi?id=97425">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
|
||||
<dialog id="mydialog">It's my dialog.</dialog>
|
||||
|
||||
<script>
|
||||
test(() => {
|
||||
const dialog = document.getElementById('mydialog');
|
||||
const computedStyle = window.getComputedStyle(dialog, null);
|
||||
assert_equals(computedStyle.display, 'none');
|
||||
|
||||
dialog.showModal();
|
||||
assert_equals(computedStyle.display, 'block');
|
||||
|
||||
// The quoted texts output below are from <http://www.whatwg.org/specs/web-apps/current-work/multipage/commands.html#dom-dialog-showmodal>.
|
||||
assert_throws_dom('InvalidStateError', () => dialog.showModal());
|
||||
|
||||
dialog.close();
|
||||
assert_equals(computedStyle.display, 'none');
|
||||
|
||||
dialog.parentNode.removeChild(dialog);
|
||||
assert_throws_dom('InvalidStateError', () => dialog.showModal());
|
||||
|
||||
const doc = document.implementation.createHTMLDocument();
|
||||
doc.body.appendChild(dialog);
|
||||
assert_false(dialog.open);
|
||||
dialog.showModal();
|
||||
assert_true(dialog.open, 'Although the document is not attached to any pages, showModal() should execute as normal.');
|
||||
}, 'Tests that showModal() performs the steps specified in the HTML spec.');
|
||||
</script>
|
|
@ -62,10 +62,12 @@
|
|||
test(function(){
|
||||
assert_false(d1.open);
|
||||
assert_false(d1.hasAttribute("open"));
|
||||
assert_equals(getComputedStyle(d1).display, "none");
|
||||
d1.showModal();
|
||||
this.add_cleanup(function() { d1.close(); });
|
||||
assert_true(d1.open);
|
||||
assert_equals(d1.getAttribute("open"), "");
|
||||
assert_equals(getComputedStyle(d1).display, "block");
|
||||
assert_equals(document.activeElement, b1);
|
||||
});
|
||||
|
||||
|
@ -169,4 +171,18 @@
|
|||
d11.close();
|
||||
assert_equals(topElement(), d10);
|
||||
}, "when opening multiple dialogs, the most recently opened is rendered on top");
|
||||
|
||||
test(function() {
|
||||
assert_false(d11.open);
|
||||
d11.parentNode.removeChild(d11);
|
||||
assert_throws_dom("INVALID_STATE_ERR", () => d11.showModal());
|
||||
|
||||
const doc = document.implementation.createHTMLDocument();
|
||||
doc.body.appendChild(d11);
|
||||
this.add_cleanup(() => document.body.append(d11));
|
||||
assert_false(d11.open);
|
||||
d11.showModal();
|
||||
assert_true(d11.open);
|
||||
this.add_cleanup(() => d11.close());
|
||||
}, "Although the document is not attached to any pages, showModal() should execute as normal.");
|
||||
</script>
|
||||
|
|
|
@ -160,13 +160,17 @@ function test_move_to_shadow_host(showModal) {
|
|||
}
|
||||
|
||||
// Test moving the focus doesn't scroll the viewport
|
||||
function test_move_focus_dont_scroll_viewport(showModal) {
|
||||
async function test_move_focus_dont_scroll_viewport(showModal) {
|
||||
const outViewPortButton = document.createElement("button");
|
||||
outViewPortButton.style.top = (window.innerHeight + 10).toString() + "px";
|
||||
outViewPortButton.style.position = "absolute";
|
||||
document.body.appendChild(outViewPortButton);
|
||||
|
||||
outViewPortButton.focus();
|
||||
await new Promise(resolve => {
|
||||
document.addEventListener("scroll", () => step_timeout(resolve, 0));
|
||||
outViewPortButton.focus();
|
||||
});
|
||||
|
||||
// Since the outViewPortButton is focused, so the viewport should be
|
||||
// scrolled to it
|
||||
assert_true(document.documentElement.scrollTop > 0 );
|
||||
|
@ -217,9 +221,9 @@ test(() => {
|
|||
test_move_to_shadow_host(false);
|
||||
}, "Focus should be moved to the shadow DOM host if the previouly focused element is a shadow DOM node");
|
||||
|
||||
test(() => {
|
||||
test_move_focus_dont_scroll_viewport(true);
|
||||
test_move_focus_dont_scroll_viewport(false);
|
||||
promise_test(async () => {
|
||||
await test_move_focus_dont_scroll_viewport(true);
|
||||
await test_move_focus_dont_scroll_viewport(false);
|
||||
}, "Focus should not scroll if the previously focused element is outside the viewport");
|
||||
</script>
|
||||
</body>
|
||||
|
|
|
@ -37,7 +37,11 @@ promise_test(async () => {
|
|||
let focusedElement = null;
|
||||
element.addEventListener('focus', function() { focusedElement = element; }, false);
|
||||
element.focus();
|
||||
assert_equals(focusedElement === element, expectFocus, element.id);
|
||||
if (expectFocus) {
|
||||
assert_equals(focusedElement, element, element.id);
|
||||
} else {
|
||||
assert_not_equals(focusedElement, element, element.id);
|
||||
}
|
||||
}
|
||||
|
||||
// Opening a modal dialog in frame1. It blocks other nodes in its document.
|
||||
|
@ -46,7 +50,7 @@ promise_test(async () => {
|
|||
|
||||
testFocus(frame1.querySelector('.target'), false);
|
||||
const iframe = frame1.querySelector('#iframe1').contentDocument;
|
||||
testFocus(iframe.querySelector('.target'), false);
|
||||
testFocus(iframe.querySelector('.target'), true);
|
||||
|
||||
// Even a modal dialog in the iframe is blocked by the modal dialog in the parent frame1.
|
||||
iframe.querySelector('dialog').showModal();
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
<!DOCTYPE html>
|
||||
<meta charset="utf-8">
|
||||
<title>Hit-testing with SVG made inert by modal dialog</title>
|
||||
<link rel="author" title="Tim Nguyen" href="https://github.com/nt1m">
|
||||
<link rel="help" href="https://html.spec.whatwg.org/multipage/interaction.html#inert">
|
||||
<meta assert="assert" content="SVG made inert by modal dialog should be unreachable with hit-testing">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="/resources/testdriver.js"></script>
|
||||
<script src="/resources/testdriver-vendor.js"></script>
|
||||
<script src="/resources/testdriver-actions.js"></script>
|
||||
|
||||
<div id="wrapper">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500 500">
|
||||
<rect width="500" height="500" id="target" fill="red">
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
<dialog id="dialog">Content behind the open modal dialog should not be clickable</dialog>
|
||||
|
||||
<style>
|
||||
dialog::backdrop {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
const dialog = document.getElementById("dialog");
|
||||
const wrapper = document.getElementById("wrapper");
|
||||
const target = document.getElementById("target");
|
||||
|
||||
promise_test(async function() {
|
||||
dialog.showModal();
|
||||
this.add_cleanup(() => dialog.close());
|
||||
|
||||
let reachedTarget = false;
|
||||
target.addEventListener("mousedown", () => {
|
||||
reachedTarget = true;
|
||||
}, { once: true });
|
||||
|
||||
let wrapperRect = wrapper.getBoundingClientRect();
|
||||
await new test_driver.Actions()
|
||||
.pointerMove(wrapperRect.x + 1, wrapperRect.y + 1, { origin: "viewport" })
|
||||
.pointerDown()
|
||||
.send();
|
||||
|
||||
assert_false(target.matches(":active"), "target is not active");
|
||||
assert_false(target.matches(":hover"), "target is not hovered");
|
||||
assert_false(reachedTarget, "target didn't get event");
|
||||
}, "Hit-testing doesn't reach contents of an inert SVG");
|
||||
|
||||
promise_test(async function() {
|
||||
assert_false(dialog.open, "dialog is closed");
|
||||
|
||||
let reachedTarget = false;
|
||||
target.addEventListener("mousedown", () => {
|
||||
reachedTarget = true;
|
||||
}, { once: true });
|
||||
|
||||
await new test_driver.Actions()
|
||||
.pointerMove(0, 0, { origin: wrapper })
|
||||
.pointerDown()
|
||||
.send();
|
||||
|
||||
assert_true(target.matches(":active"), "target is active");
|
||||
assert_true(reachedTarget, "target got event");
|
||||
}, "Hit-testing can reach contents of a no longer inert SVG");
|
||||
</script>
|
|
@ -4,9 +4,8 @@
|
|||
<link rel="author" title="Oriol Brufau" href="mailto:obrufau@igalia.com">
|
||||
<link rel="help" href="https://html.spec.whatwg.org/multipage/interaction.html#inert">
|
||||
<meta name="assert" content="Checks that a modal dialog marks outer nodes as inert,
|
||||
but only in its document, not in the parent browsing context.
|
||||
Also, when an iframe is marked as inert by a modal dialog,
|
||||
all contents in the nested browsing context are marked as inert too.">
|
||||
but only in its document, not in the parent browsing context,
|
||||
nor in nested browsing contexts.">
|
||||
<div id="log"></div>
|
||||
<div id="wrapper">
|
||||
(main document: outer text)
|
||||
|
@ -103,30 +102,30 @@ promise_test(async function() {
|
|||
|
||||
checkSelection(window, "(main document: dialog)");
|
||||
checkSelection(innerIframeWindow, "(inner iframe: outer text)(inner iframe: dialog)");
|
||||
checkSelection(outerIframeWindow, "");
|
||||
}, "Modal dialog in the main document marks outer nodes as inert. All contents of the outer iframe are also marked as inert.");
|
||||
checkSelection(outerIframeWindow, "(outer iframe: outer text)(outer iframe: dialog)");
|
||||
}, "Modal dialog in the main document marks outer nodes as inert. Contents of the outer iframe aren't marked as inert.");
|
||||
|
||||
promise_test(async function() {
|
||||
showModals(this, [innerIframeWindow, window]);
|
||||
|
||||
checkSelection(window, "(main document: dialog)");
|
||||
checkSelection(innerIframeWindow, "(inner iframe: dialog)");
|
||||
checkSelection(outerIframeWindow, "");
|
||||
}, "Modal dialogs in the main document and inner iframe mark outer nodes as inert. All contents of the outer iframe are also marked as inert.");
|
||||
checkSelection(outerIframeWindow, "(outer iframe: outer text)(outer iframe: dialog)");
|
||||
}, "Modal dialogs in the main document and inner iframe mark outer nodes as inert. Contents of the outer iframe aren't marked as inert.");
|
||||
|
||||
promise_test(async function() {
|
||||
showModals(this, [outerIframeWindow, window]);
|
||||
|
||||
checkSelection(window, "(main document: dialog)");
|
||||
checkSelection(innerIframeWindow, "(inner iframe: outer text)(inner iframe: dialog)");
|
||||
checkSelection(outerIframeWindow, "");
|
||||
}, "Modal dialogs in the main document and outer iframe mark outer nodes as inert. All contents of the outer iframe are also marked as inert.");
|
||||
checkSelection(outerIframeWindow, "(outer iframe: dialog)");
|
||||
}, "Modal dialogs in the main document and outer iframe mark outer nodes as inert. Contents of the outer iframe aren't marked as inert.");
|
||||
|
||||
promise_test(async function() {
|
||||
showModals(this, [innerIframeWindow, outerIframeWindow, window]);
|
||||
|
||||
checkSelection(window, "(main document: dialog)");
|
||||
checkSelection(innerIframeWindow, "(inner iframe: dialog)");
|
||||
checkSelection(outerIframeWindow, "");
|
||||
}, "Modal dialogs in the main document and both iframes mark outer nodes as inert. All contents of the outer iframe are also marked as inert.");
|
||||
checkSelection(outerIframeWindow, "(outer iframe: dialog)");
|
||||
}, "Modal dialogs in the main document and both iframes mark outer nodes as inert. Contents of the outer iframe aren't marked as inert.");
|
||||
</script>
|
||||
|
|
|
@ -47,7 +47,9 @@ promise_test(async () => {
|
|||
async function clickOn(element) {
|
||||
const rect = element.getBoundingClientRect();
|
||||
const actions = new test_driver.Actions()
|
||||
.pointerMove(rect.left + rect.width / 2, rect.top + rect.height / 2)
|
||||
.pointerMove(
|
||||
Math.floor(rect.left + rect.width / 2),
|
||||
Math.floor(rect.top + rect.height / 2))
|
||||
.pointerDown()
|
||||
.pointerUp()
|
||||
.pointerMove(0, 0);
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
<!DOCTYPE html>
|
||||
<iframe></iframe>
|
|
@ -0,0 +1,18 @@
|
|||
<!DOCTYPE html>
|
||||
<title>Modal dialog inside iframe should not generate box</title>
|
||||
<link rel=match href="modal-dialog-in-iframe-ref.html">
|
||||
<link rel=help href="https://github.com/w3c/csswg-drafts/issues/6939">
|
||||
<link rel=help href="https://fullscreen.spec.whatwg.org/#new-stacking-layer">
|
||||
<style>
|
||||
dialog {
|
||||
background: red;
|
||||
border-color: red;
|
||||
}
|
||||
</style>
|
||||
<iframe></iframe>
|
||||
<script>
|
||||
const iframe = document.querySelector('iframe');
|
||||
const dialog = document.createElement('dialog');
|
||||
iframe.appendChild(dialog);
|
||||
dialog.showModal();
|
||||
</script>
|
|
@ -0,0 +1,2 @@
|
|||
<!DOCTYPE html>
|
||||
<object width="200" type="image/svg+xml" data="../../../../images/100px-green-rect.svg"></object>
|
|
@ -0,0 +1,17 @@
|
|||
<!DOCTYPE html>
|
||||
<title>Modal dialog inside object should not generate box</title>
|
||||
<link rel=match href="modal-dialog-in-object-ref.html">
|
||||
<link rel=help href="https://github.com/w3c/csswg-drafts/issues/6939">
|
||||
<link rel=help href="https://fullscreen.spec.whatwg.org/#new-stacking-layer">
|
||||
<style>
|
||||
dialog {
|
||||
background: green;
|
||||
border-color: green;
|
||||
}
|
||||
</style>
|
||||
<object width="200" type="image/svg+xml" data="../../../../images/100px-green-rect.svg">
|
||||
<dialog id="dialog"></dialog>
|
||||
</object>
|
||||
<script>
|
||||
document.getElementById('dialog').showModal();
|
||||
</script>
|
|
@ -12,13 +12,7 @@ div {
|
|||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<p>Bug <a href="http://webkit.org/b/103477">103477</a>: Make
|
||||
NodeRenderingContext::parentRenderer and nextRenderer top layer aware
|
||||
<p>The test passes if you see a green square near the top and green rectangle in the center of the viewport.
|
||||
<p>The test passes if you see a green square near the top of the viewport.
|
||||
<div></div>
|
||||
<dialog id="dialog"></dialog>
|
||||
<script>
|
||||
document.getElementById('dialog').showModal();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Modal dialog inside replaced renderer should not generate box</title>
|
||||
<link rel="match" href="modal-dialog-in-replaced-renderer-ref.html">
|
||||
<link rel="help" href="https://fullscreen.spec.whatwg.org/#new-stacking-layer">
|
||||
<style>
|
||||
|
@ -14,9 +15,7 @@ div {
|
|||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<p>Bug <a href="http://webkit.org/b/103477">103477</a>: Make
|
||||
NodeRenderingContext::parentRenderer and nextRenderer top layer aware
|
||||
<p>The test passes if you see a green square near the top and green rectangle in the center of the viewport.
|
||||
<p>The test passes if you see a green square near the top of the viewport.
|
||||
<div>
|
||||
<dialog id="dialog"></dialog>
|
||||
</div>
|
||||
|
|
|
@ -9,12 +9,6 @@ dialog {
|
|||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<p>Bug <a href="http://webkit.org/b/103477">103477</a>: Make
|
||||
NodeRenderingContext::parentRenderer and nextRenderer top layer aware
|
||||
<p>The test passes if you see a green rectangle in the center of the viewport.
|
||||
<dialog id="dialog"></dialog>
|
||||
<script>
|
||||
document.getElementById('dialog').showModal();
|
||||
</script>
|
||||
<p>The test passes if you see no green rectangle.
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Modal dialog inside display: table-column should not generate box</title>
|
||||
<link rel="match" href="modal-dialog-in-table-column-ref.html">
|
||||
<link rel="help" href="https://fullscreen.spec.whatwg.org/#new-stacking-layer">
|
||||
<style>
|
||||
|
@ -14,9 +15,7 @@ div {
|
|||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<p>Bug <a href="http://webkit.org/b/103477">103477</a>: Make
|
||||
NodeRenderingContext::parentRenderer and nextRenderer top layer aware
|
||||
<p>The test passes if you see a green rectangle in the center of the viewport.
|
||||
<p>The test passes if you see no green rectangle.
|
||||
<div>
|
||||
<dialog id="dialog"></dialog>
|
||||
</div>
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
<!DOCTYPE html>
|
||||
<meta charset="utf-8" />
|
||||
<title>Content selection in modal dialog</title>
|
||||
<link rel="author" title="Oriol Brufau" href="mailto:obrufau@igalia.com">
|
||||
<link rel="help" href="https://drafts.csswg.org/css-ui-4/#content-selection">
|
||||
<meta name="assert" content="Checks that text can be selected in a modal dialog, except with 'user-select: none'.">
|
||||
|
||||
<link rel="stylesheet" href="/fonts/ahem.css">
|
||||
<style>
|
||||
dialog {
|
||||
font: 10px/1 Ahem;
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
|
||||
<dialog>123456789A</dialog>
|
||||
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="/resources/testdriver.js"></script>
|
||||
<script src="/resources/testdriver-vendor.js"></script>
|
||||
<script src="/resources/testdriver-actions.js"></script>
|
||||
<script>
|
||||
const dialog = document.querySelector("dialog");
|
||||
dialog.showModal();
|
||||
|
||||
function selectSomeText() {
|
||||
// Clear existing selection.
|
||||
getSelection().removeAllRanges();
|
||||
|
||||
// The dialog contains 10 characters. Select the 6 ones at the center.
|
||||
return new test_driver.Actions()
|
||||
.pointerMove(-3e1, 0, {origin: dialog})
|
||||
.pointerDown()
|
||||
.pointerMove(+3e1, 0, {origin: dialog})
|
||||
.pointerUp()
|
||||
.send();
|
||||
}
|
||||
|
||||
function clickOnBackdrop() {
|
||||
getSelection().removeAllRanges();
|
||||
|
||||
return new test_driver.Actions()
|
||||
.pointerMove(10, 10)
|
||||
.pointerDown()
|
||||
.pointerUp()
|
||||
.send();
|
||||
}
|
||||
|
||||
promise_test(async function() {
|
||||
await selectSomeText();
|
||||
assert_equals(getSelection().toString(), "345678");
|
||||
}, "By default, text inside a modal dialog can be selected");
|
||||
|
||||
promise_test(async function() {
|
||||
await clickOnBackdrop();
|
||||
assert_equals(getSelection().toString(), "");
|
||||
}, "Clicking on backdrop doesn't select text");
|
||||
|
||||
promise_test(async function() {
|
||||
dialog.style.userSelect = "none";
|
||||
|
||||
await selectSomeText();
|
||||
assert_equals(getSelection().toString(), "");
|
||||
|
||||
dialog.style.userSelect = "";
|
||||
}, "'user-select: none' prevents text from being selected");
|
||||
</script>
|
|
@ -28,14 +28,32 @@ dialog {
|
|||
|
||||
<script>
|
||||
test(() => {
|
||||
function documentHeight() {
|
||||
// clientHeight is an integer, but we want the correct floating point
|
||||
// value. Start a binary search at clientHeight-1 and clientHeight+1.
|
||||
let min = document.documentElement.clientHeight;
|
||||
let max = min + 1;
|
||||
--min;
|
||||
|
||||
// binary search with media queries to find the correct height
|
||||
for (let iter = 0; iter < 10; ++iter) {
|
||||
let test = (min + max) / 2;
|
||||
if (window.matchMedia(`(min-height: ${test}px)`).matches)
|
||||
min = test;
|
||||
else
|
||||
max = test;
|
||||
}
|
||||
return min;
|
||||
}
|
||||
function expectedTop(dialog) {
|
||||
return Math.floor((document.documentElement.clientHeight - dialog.offsetHeight) / 2);
|
||||
let height = documentHeight();
|
||||
return (height - dialog.getBoundingClientRect().height) / 2;
|
||||
}
|
||||
|
||||
function showAndTest(id) {
|
||||
dialog = document.getElementById(id);
|
||||
dialog.showModal();
|
||||
assert_equals(dialog.offsetTop, expectedTop(dialog), id);
|
||||
assert_approx_equals(dialog.getBoundingClientRect().top, expectedTop(dialog), 0.05, id);
|
||||
}
|
||||
|
||||
showAndTest('top-dialog');
|
||||
|
|
|
@ -1,16 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<meta charset="utf-8">
|
||||
<link rel="author" href="mailto:masonf@chromium.org">
|
||||
<link rel=help href="https://open-ui.org/components/popup.research.explainer">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
|
||||
<button id=b1>This is an anchor button</button>
|
||||
<popup id=p1 anchor=b1>This is a popup</popup>
|
||||
<button id=b2 popup=p1>This button invokes the popup but isn't an anchor</button>
|
||||
|
||||
<script>
|
||||
test(function() {
|
||||
assert_equals(p1.anchor,b1);
|
||||
}, "popup anchor IDL property returns the anchor element");
|
||||
</script>
|
|
@ -1,61 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<meta charset="utf-8" />
|
||||
<title>Popup anchor nesting</title>
|
||||
<link rel="author" href="mailto:masonf@chromium.org">
|
||||
<link rel=help href="https://open-ui.org/components/popup.research.explainer">
|
||||
<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>
|
||||
|
||||
<body>
|
||||
|
||||
<!-- This example has the anchor (b1) for one popup (p1)
|
||||
which contains a separate popup (p2) which is anchored
|
||||
by a separate anchor (b2). -->
|
||||
<button id=b1 onclick='p1.show()'>Popup 1
|
||||
<popup id=p2 anchor=b2>
|
||||
<span id=inside2>Inside popup 2</span>
|
||||
</popup>
|
||||
</button>
|
||||
<popup id=p1 anchor=b1>This is popup 1</popup>
|
||||
<button id=b2 onclick='p2.show()'>Popup 2</button>
|
||||
|
||||
<style>
|
||||
#p1 { top:50px; }
|
||||
#p2 { top:50px; left:250px; }
|
||||
popup { border: 5px solid red; }
|
||||
</style>
|
||||
|
||||
|
||||
<script>
|
||||
function clickOn(element) {
|
||||
const actions = new test_driver.Actions();
|
||||
return actions.pointerMove(0, 0, {origin: element})
|
||||
.pointerDown({button: actions.ButtonType.LEFT})
|
||||
.pointerUp({button: actions.ButtonType.LEFT})
|
||||
.send();
|
||||
}
|
||||
|
||||
const popup1 = document.querySelector('#p1');
|
||||
const button1 = document.querySelector('#b1');
|
||||
const popup2 = document.querySelector('#p2');
|
||||
|
||||
(async function() {
|
||||
setup({ explicit_done: true });
|
||||
|
||||
popup2.show();
|
||||
assert_false(popup1.open);
|
||||
assert_true(popup2.open);
|
||||
await clickOn(button1);
|
||||
test(t => {
|
||||
// Button1 is the anchor for popup1, and an ancestor of popup2.
|
||||
// Since popup2 is open, but not popup1, button1 should not be
|
||||
// the anchor of any open popup. So popup2 should be closed.
|
||||
assert_false(popup2.open);
|
||||
},'Nested popups (inside anchor elements) do not affect light dismiss');
|
||||
|
||||
done();
|
||||
})();
|
||||
</script>
|
|
@ -1,50 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<meta charset="utf-8">
|
||||
<link rel="author" href="mailto:masonf@chromium.org">
|
||||
<link rel=help href="https://open-ui.org/components/popup.research.explainer">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
|
||||
<popup id=p1>This is a popup</popup>
|
||||
<popup id=p2 open>This is another popup, with an unused "open" attribute</popup>
|
||||
|
||||
<script>
|
||||
test(function() {
|
||||
assert_true(document.createElement('popup') instanceof HTMLPopupElement);
|
||||
}, "popup element exists")
|
||||
|
||||
const popup1 = document.getElementById('p1');
|
||||
const popup2 = document.getElementById('p2');
|
||||
|
||||
function popupVisible(popup) {
|
||||
return !!(popup.offsetWidth || popup.offsetHeight || popup.getClientRects().length);
|
||||
}
|
||||
|
||||
test(function(){
|
||||
assert_false(popup1.open);
|
||||
assert_false(popup2.open);
|
||||
}, 'The IDL "open" content attribute must have no effect, and must not be reflected to the WebIDL.');
|
||||
|
||||
test(function(){
|
||||
assert_false(popup1.open);
|
||||
assert_false(popup1.hasAttribute("open"));
|
||||
assert_false(popupVisible(popup1));
|
||||
popup1.open = true; // Should have no effect
|
||||
assert_false(popup1.open);
|
||||
assert_false(popupVisible(popup1));
|
||||
popup1.show();
|
||||
assert_true(popup1.open);
|
||||
assert_false(popup1.hasAttribute("open"));
|
||||
assert_true(popupVisible(popup1));
|
||||
popup1.open = false; // Should have no effect
|
||||
assert_true(popup1.open);
|
||||
popup1.hide();
|
||||
assert_false(popup1.open);
|
||||
assert_false(popup1.hasAttribute("open"));
|
||||
assert_false(popupVisible(popup1));
|
||||
popup1.setAttribute("open","");
|
||||
assert_false(popup1.open,'Setting open attribute should not reflect to the WebIDL');
|
||||
assert_true(popup1.hasAttribute("open"));
|
||||
assert_false(popupVisible(popup1));
|
||||
}, "The only visibility control for <popup> is through .show() and .hide().");
|
||||
</script>
|
|
@ -1,44 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<meta charset="utf-8" />
|
||||
<title>Popup keyboard focus behaviors</title>
|
||||
<link rel="author" href="mailto:masonf@chromium.org">
|
||||
<link rel=help href="https://open-ui.org/components/popup.research.explainer">
|
||||
<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>
|
||||
|
||||
<button id=firstfocus>Button 1</button>
|
||||
<popup>
|
||||
<p>This is a popup without a focusable element</p>
|
||||
</popup>
|
||||
<button id=secondfocus>Button 2</button>
|
||||
|
||||
<script>
|
||||
promise_test(async () => {
|
||||
const b1 = document.getElementById('firstfocus');
|
||||
const b2 = document.getElementById('secondfocus');
|
||||
const popup = document.querySelector('popup');
|
||||
b1.focus();
|
||||
assert_equals(document.activeElement,b1);
|
||||
popup.show();
|
||||
assert_true(popup.open);
|
||||
assert_equals(document.activeElement,b1);
|
||||
// Tab once
|
||||
await new test_driver.send_keys(document.body,'\uE004'); // Tab
|
||||
assert_equals(document.activeElement, b2, 'Keyboard focus should skip the open popup');
|
||||
popup.hide();
|
||||
|
||||
// Add a focusable button to the popup and make sure we can focus that
|
||||
const button = document.createElement('button');
|
||||
popup.appendChild(button);
|
||||
b1.focus();
|
||||
popup.show();
|
||||
assert_equals(document.activeElement,b1);
|
||||
// Tab once
|
||||
await new test_driver.send_keys(document.body,'\uE004'); // Tab
|
||||
assert_equals(document.activeElement, button, 'Keyboard focus should go to the contained button');
|
||||
popup.hide();
|
||||
}, "Popup should not be keyboard focusable");
|
||||
</script>
|
|
@ -1,28 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<meta charset="utf-8" />
|
||||
<title>Popup document removal behavior</title>
|
||||
<link rel="author" href="mailto:masonf@chromium.org">
|
||||
<link rel=help href="https://open-ui.org/components/popup.research.explainer">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
|
||||
<iframe id=frame1 srcdoc="<popup id=popup>Popup</popup>"></iframe>
|
||||
<iframe id=frame2></iframe>
|
||||
|
||||
<script>
|
||||
window.onload = () => {
|
||||
test(t => {
|
||||
const frame1Doc = document.getElementById('frame1').contentDocument;
|
||||
const frame2Doc = document.getElementById('frame2').contentDocument;
|
||||
const popup = frame1Doc.querySelector('popup');
|
||||
assert_true(!!popup);
|
||||
assert_false(popup.open);
|
||||
popup.show();
|
||||
assert_true(popup.open);
|
||||
frame2Doc.body.appendChild(popup);
|
||||
assert_false(popup.open);
|
||||
popup.show();
|
||||
assert_true(popup.open);
|
||||
}, 'Moving popup between documents shouldn\'t cause issues');
|
||||
};
|
||||
</script>
|
|
@ -1,27 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<meta charset="utf-8" />
|
||||
<title>Popup document removal behavior</title>
|
||||
<link rel="author" href="mailto:masonf@chromium.org">
|
||||
<link rel=help href="https://open-ui.org/components/popup.research.explainer">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
|
||||
<popup id=popup>Popup</popup>
|
||||
|
||||
<script>
|
||||
promise_test(async t => {
|
||||
function loadCompleted() {
|
||||
return new Promise(resolve => {
|
||||
window.addEventListener('load', resolve);
|
||||
});
|
||||
}
|
||||
const popup = document.querySelector('popup');
|
||||
assert_false(popup.open);
|
||||
popup.show();
|
||||
assert_true(popup.open);
|
||||
popup.remove(); // Shouldn't cause any issues
|
||||
document.body.click(); // Shouldn't cause light dismiss problems
|
||||
await loadCompleted(); // The document should finish loading
|
||||
}, 'Removal from the document shouldn\'t cause issues');
|
||||
|
||||
</script>
|
|
@ -1,145 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<meta charset="utf-8" />
|
||||
<title>Popup focus behaviors</title>
|
||||
<link rel="author" href="mailto:masonf@chromium.org">
|
||||
<link rel=help href="https://open-ui.org/components/popup.research.explainer">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
|
||||
<popup data-test='default behavior - popup is not focused' data-no-focus>
|
||||
<p>This is a popup</p>
|
||||
<button>first button</button>
|
||||
</popup>
|
||||
|
||||
<popup data-test='autofocus popup' autofocus class=should-be-focused>
|
||||
<p>This is a popup</p>
|
||||
</popup>
|
||||
|
||||
<popup data-test='autofocus empty popup' autofocus class=should-be-focused></popup>
|
||||
|
||||
<popup data-test='autofocus popup with button' autofocus class=should-be-focused>
|
||||
<p>This is a popup</p>
|
||||
<button>button</button>
|
||||
</popup>
|
||||
|
||||
<popup data-test='autofocus child'>
|
||||
<p>This is a popup</p>
|
||||
<button autofocus class=should-be-focused>autofocus button</button>
|
||||
</popup>
|
||||
|
||||
<popup data-test='autofocus on tabindex=0 element'>
|
||||
<p autofocus tabindex=0 class=should-be-focused>This is a popup with autofocus on a tabindex=0 element</p>
|
||||
<button>button</button>
|
||||
</popup>
|
||||
|
||||
<popup data-test='autofocus multiple children'>
|
||||
<p>This is a popup</p>
|
||||
<button autofocus class=should-be-focused>autofocus button</button>
|
||||
<button autofocus>second autofocus button</button>
|
||||
</popup>
|
||||
|
||||
<popup autofocus data-test='autofocus popup and multiple autofocus children' class=should-be-focused>
|
||||
<p>This is a popup</p>
|
||||
<button autofocus>autofocus button</button>
|
||||
<button autofocus>second autofocus button</button>
|
||||
</popup>
|
||||
|
||||
<popup delegatesfocus data-test='delegatesfocus popup'>
|
||||
<p>This is a popup</p>
|
||||
<button class=should-be-focused>first button should be focused</button>
|
||||
<button>second button</button>
|
||||
</popup>
|
||||
|
||||
<popup delegatesfocus data-test='delegatesfocus takes precedence over autofocus'>
|
||||
<p>This is a popup</p>
|
||||
<button class=should-be-focused>first button</button>
|
||||
<button autofocus>autofocus button should NOT be focused</button>
|
||||
</popup>
|
||||
|
||||
<popup delegatesfocus autofocus data-test='delegatesfocus takes precedence over autofocus 2'>
|
||||
<p>This is a popup</p>
|
||||
<button class=should-be-focused>first button</button>
|
||||
<button>autofocus button should NOT be focused</button>
|
||||
</popup>
|
||||
|
||||
<popup delegatesfocus data-test='delegatesfocus on empty popup has no effect' data-no-focus></popup>
|
||||
|
||||
<popup data-test='delegatesfocus on child has no effect' data-no-focus>
|
||||
<p>This is a popup</p>
|
||||
<button delegatesfocus>first button</button>
|
||||
</popup>
|
||||
|
||||
<popup delegatesfocus data-test='delegatesfocus skips contained popups'>
|
||||
<p>This is a popup</p>
|
||||
<popup>
|
||||
<button>Contained popup button</button>
|
||||
</popup>
|
||||
<button class=should-be-focused>first button</button>
|
||||
<button>autofocus button should NOT be focused</button>
|
||||
</popup>
|
||||
|
||||
<popup delegatesfocus data-test='delegatesfocus skips contained dialogs'>
|
||||
<p>This is a popup</p>
|
||||
<dialog>
|
||||
<button>Contained dialog button</button>
|
||||
</dialog>
|
||||
<button class=should-be-focused>first button</button>
|
||||
<button>autofocus button should NOT be focused</button>
|
||||
</popup>
|
||||
|
||||
<style>
|
||||
popup {
|
||||
border: 2px solid black;
|
||||
top:150px;
|
||||
left:150px;
|
||||
}
|
||||
:focus-within { border: 5px dashed red; }
|
||||
:focus { border: 5px solid lime; }
|
||||
</style>
|
||||
|
||||
<script>
|
||||
function activateAndVerify(popup) {
|
||||
const testName = popup.getAttribute('data-test');
|
||||
const priorFocus = document.createElement('button');
|
||||
priorFocus.id = 'prior-focus';
|
||||
document.body.appendChild(priorFocus);
|
||||
let expectedFocusedElement = popup.matches('.should-be-focused') ? popup : popup.querySelector('.should-be-focused');
|
||||
if (popup.hasAttribute('data-no-focus')) {
|
||||
expectedFocusedElement = priorFocus;
|
||||
}
|
||||
test(t => {
|
||||
t.add_cleanup(() => priorFocus.remove());
|
||||
assert_true(!!expectedFocusedElement);
|
||||
assert_false(popup.open);
|
||||
priorFocus.focus();
|
||||
assert_equals(document.activeElement,priorFocus);
|
||||
|
||||
// Directly show the popup:
|
||||
popup.show();
|
||||
assert_equals(document.activeElement, expectedFocusedElement, `${testName} activated by popup.show()`);
|
||||
popup.hide();
|
||||
|
||||
// Use an activating element:
|
||||
const button = document.createElement('button');
|
||||
const popupId = 'popup-id';
|
||||
assert_equals(document.querySelectorAll('#' + popupId).length,0);
|
||||
document.body.appendChild(button);
|
||||
t.add_cleanup(function() {
|
||||
popup.removeAttribute('id');
|
||||
button.remove();
|
||||
});
|
||||
popup.id = popupId;
|
||||
button.setAttribute('popup', popupId);
|
||||
priorFocus.focus();
|
||||
button.click();
|
||||
assert_equals(document.activeElement, expectedFocusedElement, `${testName} activated by button.click()`);
|
||||
|
||||
// Make sure we can directly focus the (already open) popup:
|
||||
popup.focus();
|
||||
assert_equals(document.activeElement, popup.hasAttribute('delegatesfocus') ? expectedFocusedElement : popup, `${testName} directly focus with popup.focus()`);
|
||||
popup.hide();
|
||||
}, "Popup focus test: " + testName);
|
||||
}
|
||||
|
||||
document.querySelectorAll('body > popup').forEach(popup => activateAndVerify(popup));
|
||||
</script>
|
|
@ -1,5 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<meta charset="utf-8">
|
||||
<link rel=author href="mailto:masonf@chromium.org">
|
||||
|
||||
No popup should be displayed here.<p>
|
|
@ -1,22 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<meta charset="utf-8">
|
||||
<link rel=author href="mailto:masonf@chromium.org">
|
||||
<link rel=help href="https://open-ui.org/components/popup.research.explainer">
|
||||
<link rel=match href="popup-hidden-display-ref.tentative.html">
|
||||
|
||||
No popup should be displayed here.<p>
|
||||
|
||||
<popup>This content should be hidden</popup>
|
||||
|
||||
<style>
|
||||
popup {
|
||||
display: block; /* This should have no effect */
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 300px;
|
||||
height: 200px;
|
||||
border: 1px solid;
|
||||
background: white;
|
||||
color: black;
|
||||
}
|
||||
</style>
|
|
@ -1,24 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<meta charset="utf-8">
|
||||
<link rel=author href="mailto:masonf@chromium.org">
|
||||
<link rel=help href="https://open-ui.org/components/popup.research.explainer">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
|
||||
<popup id=p1 initiallyopen>
|
||||
Outer popup
|
||||
<popup id=p2 initiallyopen>
|
||||
Inner popup
|
||||
</popup>
|
||||
</popup>
|
||||
|
||||
<script>
|
||||
requestAnimationFrame(() => {
|
||||
requestAnimationFrame(() => {
|
||||
test(function(){
|
||||
assert_true(p1.open,'The first (outermost) popup should be the one that opens in this case');
|
||||
assert_false(p2.open,'The inner popup should not be open');
|
||||
}, "The initiallyopen attribute should cause only the first popup to open");
|
||||
});
|
||||
});
|
||||
</script>
|
|
@ -1,22 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<meta charset="utf-8">
|
||||
<link rel=author href="mailto:masonf@chromium.org">
|
||||
|
||||
<div>This is a popup, which should be open upon load</div>
|
||||
|
||||
<style>
|
||||
div {
|
||||
/* Per spec: */
|
||||
display: block;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
/* Per settings in test file: */
|
||||
width: fit-content;
|
||||
height: fit-content;
|
||||
border: 1px solid;
|
||||
padding: 1em;
|
||||
background: -internal-light-dark(white, black);
|
||||
color: -internal-light-dark(black, white);
|
||||
}
|
||||
</style>
|
|
@ -1,26 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<meta charset="utf-8">
|
||||
<link rel=author href="mailto:masonf@chromium.org">
|
||||
<link rel=help href="https://open-ui.org/components/popup.research.explainer">
|
||||
<link rel=match href="popup-initiallyopen-display-ref.tentative.html">
|
||||
|
||||
<popup id=p1 initiallyopen>This is a popup, which should be open upon load</popup>
|
||||
<popup id=p2 initiallyopen>This is a second popup with initiallyopen, which should NOT be open upon load</popup>
|
||||
|
||||
<style>
|
||||
popup {
|
||||
width: fit-content;
|
||||
height: fit-content;
|
||||
border: 1px solid;
|
||||
padding: 1em;
|
||||
background: white;
|
||||
color: black;
|
||||
}
|
||||
#p1 {
|
||||
top:0;
|
||||
}
|
||||
#p2 {
|
||||
top:100px;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,38 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<meta charset="utf-8">
|
||||
<link rel=author href="mailto:masonf@chromium.org">
|
||||
<link rel=help href="https://open-ui.org/components/popup.research.explainer">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
|
||||
<popup id=p1 initiallyopen>This is a popup, which should be open upon load</popup>
|
||||
<script></script> <!-- Possibly yield the parser, just to double-check -->
|
||||
<popup id=p2 initiallyopen>This is a second popup with initiallyopen, which should NOT be open upon load</popup>
|
||||
<popup id=p3>Also not visible</popup>
|
||||
|
||||
<script>
|
||||
requestAnimationFrame(() => {
|
||||
requestAnimationFrame(() => {
|
||||
test(function(){
|
||||
assert_true(p1.open,'initiallyopen should open the popup');
|
||||
assert_true(p1.hasAttribute('initiallyopen'));
|
||||
assert_true(p1.initiallyOpen,'initiallyopen should be reflected in the IDL attribute');
|
||||
assert_false(p2.open, 'Only the first popup with initiallyopen should be open on load');
|
||||
assert_true(p2.hasAttribute('initiallyopen'),'initiallyopen should be present/true, even if not opened');
|
||||
assert_true(p2.initiallyOpen,'initiallyopen should be present/true, even if not opened');
|
||||
|
||||
assert_false(p3.open);
|
||||
p3.setAttribute('initiallyopen','');
|
||||
assert_false(p3.open, 'Changing initiallyopen should not affect open status');
|
||||
assert_true(p3.hasAttribute('initiallyopen'));
|
||||
assert_true(p3.initiallyOpen,'initiallyopen should still reflect to IDL');
|
||||
|
||||
p1.removeAttribute('initiallyopen');
|
||||
assert_true(p1.open,'removing initiallyopen should not close the popup');
|
||||
assert_false(p1.hasAttribute('initiallyopen'),'...but it should reflect to IDL');
|
||||
|
||||
p1.hide();
|
||||
}, "The initiallyopen attribute should affect page load only");
|
||||
});
|
||||
});
|
||||
</script>
|
|
@ -1,18 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<meta charset="utf-8">
|
||||
<link rel=author href="mailto:masonf@chromium.org">
|
||||
<link rel=help href="https://open-ui.org/components/popup.research.explainer">
|
||||
<link rel=match href="popup-hidden-display-ref.tentative.html">
|
||||
|
||||
No popup should be displayed here.<p>
|
||||
|
||||
<div style="display:none">
|
||||
<popup>This content should be hidden</popup>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const popup = document.querySelector('popup');
|
||||
popup.show();
|
||||
if (!popup.open)
|
||||
document.body.appendChild(document.createTextNode('FAIL'));
|
||||
</script>
|
|
@ -1,40 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<meta charset="utf-8" />
|
||||
<title>Popup invoking attribute</title>
|
||||
<link rel="author" href="mailto:masonf@chromium.org">
|
||||
<link rel=help href="https://open-ui.org/components/popup.research.explainer">
|
||||
<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>
|
||||
|
||||
<button id=b1 popup=p1>Open Popup 1</button>
|
||||
<popup id=p1 anchor=b1><p>This is popup #1</p></popup>
|
||||
|
||||
<style>
|
||||
popup { border: 5px solid red; }
|
||||
</style>
|
||||
|
||||
<script>
|
||||
function clickOn(element) {
|
||||
const actions = new test_driver.Actions();
|
||||
return actions.pointerMove(0, 0, {origin: element})
|
||||
.pointerDown({button: actions.ButtonType.LEFT})
|
||||
.pointerUp({button: actions.ButtonType.LEFT})
|
||||
.send();
|
||||
}
|
||||
|
||||
const popup1 = document.querySelector('#p1');
|
||||
const button1 = document.querySelector('#b1');
|
||||
|
||||
promise_test(async () => {
|
||||
assert_false(popup1.open);
|
||||
await clickOn(button1);
|
||||
assert_true(popup1.open);
|
||||
popup1.hide();
|
||||
assert_false(popup1.open);
|
||||
button1.click();
|
||||
assert_true(popup1.open);
|
||||
}, "Basic test of the 'popup' attribute on a button");
|
||||
</script>
|
|
@ -1,47 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<meta charset="utf-8" />
|
||||
<title>Popup light dismiss on scroll</title>
|
||||
<link rel="author" href="mailto:masonf@chromium.org">
|
||||
<link rel=help href="https://open-ui.org/components/popup.research.explainer">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
|
||||
<div id=scroller>
|
||||
Scroll me<br><br>
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt
|
||||
ut labore et dolore magna aliqua. Enim ut sem viverra aliquet eget sit amet tellus. Massa
|
||||
sed elementum tempus egestas sed sed risus pretium. Felis bibendum ut tristique et egestas
|
||||
quis. Tortor dignissim convallis aenean et. Eu mi bibendum neque egestas congue quisque
|
||||
</div>
|
||||
|
||||
<popup id=popup1>This is popup 1<div id=anchor></div></popup>
|
||||
<popup id=popup2 anchor=anchor>This is popup 2</popup>
|
||||
<button onclick='popup1.show();popup2.show();'>Open popups</button>
|
||||
|
||||
<style>
|
||||
#popup1 { top:50px; left: 50px; }
|
||||
#popup2 { top:150px; left: 50px; }
|
||||
#scroller {
|
||||
height: 150px;
|
||||
width: 150px;
|
||||
overflow-y: scroll;
|
||||
border: 1px solid black;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
async_test(t => {
|
||||
popup1.addEventListener('hide',e => {
|
||||
assert_false(popup2.open);
|
||||
t.done();
|
||||
})
|
||||
assert_false(popup1.open);
|
||||
assert_false(popup2.open);
|
||||
popup1.show();
|
||||
popup2.show();
|
||||
assert_true(popup1.open);
|
||||
assert_true(popup2.open);
|
||||
scroller.scrollTo(0, 100);
|
||||
},'Scrolling light-dismisses all popups');
|
||||
</script>
|
|
@ -1,189 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<meta charset="utf-8" />
|
||||
<title>Popup light dismiss behavior</title>
|
||||
<link rel="author" href="mailto:masonf@chromium.org">
|
||||
<link rel=help href="https://open-ui.org/components/popup.research.explainer">
|
||||
<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>
|
||||
|
||||
<button id=b1 onclick='p1.show()'>Popup 1</button>
|
||||
<span id=outside>Outside all popups</span>
|
||||
<popup id=p1 anchor=b1>
|
||||
<span id=inside1>Inside popup 1</span>
|
||||
<button id=b2 onclick='p2.show()'>Popup 2</button>
|
||||
</popup>
|
||||
<popup id=p2 anchor=b2>
|
||||
<span id=inside2>Inside popup 2</span>
|
||||
</popup>
|
||||
|
||||
<button id=b3 popup=p3>Popup 3 - button 3
|
||||
<popup id=p4>Inside popup 4</popup>
|
||||
</button>
|
||||
<popup id=p3>Inside popup 3</popup>
|
||||
<button id=b4 popup=p3>Popup 3 - button 4
|
||||
<popup id=p5>Inside popup 5</popup>
|
||||
</button>
|
||||
|
||||
<popup id=p6>Inside popup 6
|
||||
<div style="height:2000px;background:lightgreen"></div>
|
||||
Bottom of popup6
|
||||
</popup>
|
||||
<button popup=p6>Popup 6</button>
|
||||
|
||||
<style>
|
||||
#p1 { top:50px; }
|
||||
#p2 { top:50px; left:250px; }
|
||||
#p3 { top:150px;}
|
||||
#p4 { top:150px; left:250px;}
|
||||
#p5 { top:250px;}
|
||||
#p6 {
|
||||
top: 50px;
|
||||
left:150px;
|
||||
width: 300px;
|
||||
height: 300px;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
popup { border: 5px solid red; }
|
||||
</style>
|
||||
|
||||
|
||||
<script>
|
||||
function clickOn(element) {
|
||||
const actions = new test_driver.Actions();
|
||||
return actions.pointerMove(0, 0, {origin: element})
|
||||
.pointerDown({button: actions.ButtonType.LEFT})
|
||||
.pointerUp({button: actions.ButtonType.LEFT})
|
||||
.send();
|
||||
}
|
||||
|
||||
const popup1 = document.querySelector('#p1');
|
||||
const button1 = document.querySelector('#b1');
|
||||
const popup2 = document.querySelector('#p2');
|
||||
const outside = document.querySelector('#outside');
|
||||
const inside1 = document.querySelector('#inside1');
|
||||
const inside2 = document.querySelector('#inside2');
|
||||
const button3 = document.querySelector('#b3');
|
||||
const button4 = document.querySelector('#b4');
|
||||
const popup3 = document.querySelector('#p3');
|
||||
const popup4 = document.querySelector('#p4');
|
||||
const popup5 = document.querySelector('#p5');
|
||||
const popup6 = document.querySelector('#p6');
|
||||
|
||||
(async function() {
|
||||
setup({ explicit_done: true });
|
||||
|
||||
let popup1HideCount = 0;
|
||||
popup1.addEventListener('hide',(e) => {
|
||||
++popup1HideCount;
|
||||
e.preventDefault(); // 'hide' should not be cancellable.
|
||||
});
|
||||
let popup2HideCount = 0;
|
||||
popup2.addEventListener('hide',(e) => {
|
||||
++popup2HideCount;
|
||||
e.preventDefault(); // 'hide' should not be cancellable.
|
||||
});
|
||||
|
||||
assert_false(popup1.open);
|
||||
popup1.show();
|
||||
let p1HideCount = popup1HideCount;
|
||||
assert_true(popup1.open);
|
||||
await clickOn(outside);
|
||||
test(t => {
|
||||
assert_false(popup1.open);
|
||||
assert_equals(popup1HideCount,p1HideCount+1);
|
||||
},'Clicking outside a popup will dismiss the popup');
|
||||
|
||||
assert_false(popup1.open);
|
||||
popup1.show();
|
||||
p1HideCount = popup1HideCount;
|
||||
await clickOn(inside1);
|
||||
test(t => {
|
||||
assert_true(popup1.open);
|
||||
assert_equals(popup1HideCount,p1HideCount);
|
||||
},'Clicking inside a popup does not close that popup');
|
||||
|
||||
popup2.show();
|
||||
p1HideCount = popup1HideCount;
|
||||
let p2HideCount = popup2HideCount;
|
||||
await clickOn(inside2);
|
||||
test(t => {
|
||||
assert_true(popup1.open);
|
||||
assert_true(popup2.open);
|
||||
assert_equals(popup1HideCount,p1HideCount,'popup1');
|
||||
assert_equals(popup2HideCount,p2HideCount,'popup2');
|
||||
},'Clicking inside a child popup shouldn\'t close either popup');
|
||||
|
||||
popup2.show();
|
||||
p1HideCount = popup1HideCount;
|
||||
p2HideCount = popup2HideCount;
|
||||
await clickOn(inside1);
|
||||
test(t => {
|
||||
assert_true(popup1.open);
|
||||
assert_equals(popup1HideCount,p1HideCount);
|
||||
assert_false(popup2.open);
|
||||
assert_equals(popup2HideCount,p2HideCount+1);
|
||||
},'Clicking inside a parent popup should close child popup');
|
||||
|
||||
assert_true(popup1.open);
|
||||
p1HideCount = popup1HideCount;
|
||||
await clickOn(button1);
|
||||
test(t => {
|
||||
assert_true(popup1.open,'popup1 not open');
|
||||
assert_equals(popup1HideCount,p1HideCount);
|
||||
popup1.hide(); // Cleanup
|
||||
assert_false(popup1.open);
|
||||
},'Clicking on anchor element shouldn\'t close its popup');
|
||||
|
||||
await clickOn(button3);
|
||||
test(t => {
|
||||
assert_true(popup3.open,'invoking element should open popup');
|
||||
popup4.show();
|
||||
assert_true(popup4.open);
|
||||
assert_true(popup3.open);
|
||||
},'An invoking element should be part of the ancestor chain');
|
||||
|
||||
await clickOn(button3);
|
||||
assert_true(popup3.open);
|
||||
assert_false(popup4.open);
|
||||
assert_false(popup5.open);
|
||||
popup5.show();
|
||||
test(t => {
|
||||
assert_true(popup5.open);
|
||||
assert_false(popup3.open);
|
||||
},'An invoking element that was not used to invoke the popup should NOT be part of the ancestor chain');
|
||||
|
||||
popup1.show();
|
||||
popup2.show(); // Popup1 is an ancestral element for popup2.
|
||||
assert_true(popup1.open);
|
||||
assert_true(popup2.open);
|
||||
const drag_actions = new test_driver.Actions();
|
||||
// Drag *from* popup2 *to* popup1 (its ancestor).
|
||||
await drag_actions.pointerMove(0,0,{origin: popup2})
|
||||
.pointerDown({button: drag_actions.ButtonType.LEFT})
|
||||
.pointerMove(0,0,{origin: popup1})
|
||||
.pointerUp({button: drag_actions.ButtonType.LEFT})
|
||||
.send();
|
||||
test(t => {
|
||||
assert_true(popup1.open,'popup1 should be open');
|
||||
assert_true(popup2.open,'popup1 should be open');
|
||||
popup1.hide();
|
||||
assert_false(popup2.open);
|
||||
},'Dragging from an open popup outside an open popup should leave the popup open');
|
||||
|
||||
popup6.show();
|
||||
assert_equals(popup6.scrollTop,0,'popup6 should start non-scrolled');
|
||||
await new test_driver.Actions()
|
||||
.scroll(0, 0, 0, 50, {origin: popup6})
|
||||
.send();
|
||||
test(t => {
|
||||
assert_true(popup6.open,'popup6 should stay open');
|
||||
assert_equals(popup6.scrollTop,50,'popup6 should be scrolled');
|
||||
popup6.hide();
|
||||
},'Scrolling within a popup should not close the popup');
|
||||
|
||||
done();
|
||||
})();
|
||||
</script>
|
|
@ -1,22 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<meta charset="utf-8">
|
||||
<link rel=author href="mailto:masonf@chromium.org">
|
||||
|
||||
<div>This is a popup</div>
|
||||
|
||||
<style>
|
||||
div {
|
||||
/* Per spec: */
|
||||
display: block;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
/* Per settings in test file: */
|
||||
width: fit-content;
|
||||
height: fit-content;
|
||||
border: 1px solid;
|
||||
padding: 1em;
|
||||
background: white;
|
||||
color: black;
|
||||
}
|
||||
</style>
|
|
@ -1,22 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<meta charset="utf-8">
|
||||
<link rel=author href="mailto:masonf@chromium.org">
|
||||
<link rel=help href="https://open-ui.org/components/popup.research.explainer">
|
||||
<link rel=match href="popup-open-display-ref.tentative.html">
|
||||
|
||||
<popup>This is a popup</popup>
|
||||
|
||||
<style>
|
||||
popup {
|
||||
width: fit-content;
|
||||
height: fit-content;
|
||||
border: 1px solid;
|
||||
padding: 1em;
|
||||
background: white;
|
||||
color: black;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
document.querySelector('popup').show();
|
||||
</script>
|
|
@ -1,30 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<meta charset="utf-8">
|
||||
<link rel=author href="mailto:masonf@chromium.org">
|
||||
|
||||
<popup id=p1>This is popup 1<div id=anchor2></div></popup>
|
||||
<popup id=p2 anchor=anchor2>This is popup 2<div id=anchor3></div></popup>
|
||||
<popup id=p3 anchor=anchor3>This is popup 3</popup>
|
||||
|
||||
<style>
|
||||
popup#p2 {
|
||||
top: 100px;
|
||||
}
|
||||
popup#p3 {
|
||||
top:200px;
|
||||
}
|
||||
popup {
|
||||
width: fit-content;
|
||||
height: fit-content;
|
||||
border: 1px solid;
|
||||
padding: 1em;
|
||||
background: white;
|
||||
color: black;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
document.querySelector('#p1').show();
|
||||
document.querySelector('#p2').show();
|
||||
document.querySelector('#p3').show();
|
||||
</script>
|
|
@ -1,44 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<meta charset="utf-8">
|
||||
<link rel=author href="mailto:masonf@chromium.org">
|
||||
<link rel=help href="https://open-ui.org/components/popup.research.explainer">
|
||||
<link rel=match href="popup-open-overflow-display-ref.tentative.html">
|
||||
|
||||
<div id=container>
|
||||
<popup id=p1>This is popup 1<div id=anchor2></div></popup>
|
||||
<popup id=p2 anchor=anchor2>This is popup 2<div id=anchor3></div></popup>
|
||||
<popup id=p3 anchor=anchor3>This is popup 3</popup>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
#container {
|
||||
overflow:hidden;
|
||||
position: absolute;
|
||||
top: 100px;
|
||||
left: 50px;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
}
|
||||
popup#p2 {
|
||||
position: absolute;
|
||||
top: 100px;
|
||||
}
|
||||
popup#p3 {
|
||||
position: relative;
|
||||
top:200px;
|
||||
}
|
||||
popup {
|
||||
width: fit-content;
|
||||
height: fit-content;
|
||||
border: 1px solid;
|
||||
padding: 1em;
|
||||
background: white;
|
||||
color: black;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
document.querySelector('#p1').show();
|
||||
document.querySelector('#p2').show();
|
||||
document.querySelector('#p3').show();
|
||||
</script>
|
|
@ -1,162 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<meta charset="utf-8">
|
||||
<link rel="author" href="mailto:masonf@chromium.org">
|
||||
<link rel=help href="https://open-ui.org/components/popup.research.explainer">
|
||||
<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>
|
||||
</popup>
|
||||
<my-element>
|
||||
<template shadowroot=open>
|
||||
<popup anchor=t2b2 style="top: 400px;">
|
||||
<p>Hiding this popup will hide *all* open popups,</p>
|
||||
<p>because t2b2 doesn't exist in this context.</p>
|
||||
</popup>
|
||||
</template>
|
||||
</my-element>
|
||||
</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, 'popup1 open'); // P1 was closed by P2
|
||||
assert_false(popupVisible(popup1), 'popup1 visible');
|
||||
assert_true(popup2.open, 'popup2 open'); // P2 is open
|
||||
assert_true(popupVisible(popup2), 'popup2 visible');
|
||||
}, "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 stay open 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 should not close popup1, since it is a flat
|
||||
// tree ancestor of popup2's anchor button.
|
||||
popup2.show();
|
||||
assert_true(popup2.open);
|
||||
assert_true(popupVisible(popup2));
|
||||
assert_true(popup1.open);
|
||||
assert_true(popupVisible(popup1));
|
||||
popup1.hide();
|
||||
assert_false(popup2.open);
|
||||
assert_false(popup1.open);
|
||||
}, "anchor references use the flat tree not the DOM 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, 'popup1 not open');
|
||||
assert_true(popupVisible(popup1));
|
||||
assert_true(popup2.open, 'popup2 not 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>
|
|
@ -1,37 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<meta charset="utf-8">
|
||||
<link rel="author" href="mailto:masonf@chromium.org">
|
||||
|
||||
<div id=popup>
|
||||
Inside popup
|
||||
<div class=z style="z-index: 2; background:lightgreen">z-index 2
|
||||
<div class=z style="z-index: 3; background:lightblue; left: 20px;">z-index 3</div>
|
||||
<div class=z style="z-index: 1; background:pink; top:-20px; left: 10px;">z-index 1</div>
|
||||
</div>
|
||||
<div class=z style="background:green; top:-100px; left: 250px; width: 100px;">Outside</div>
|
||||
Bottom of popup
|
||||
</div>
|
||||
|
||||
<style>
|
||||
#popup {
|
||||
/* Per spec: */
|
||||
display: block;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
/* Per settings in test file: */
|
||||
width: 200px;
|
||||
height: 230px;
|
||||
border: 1px solid red;
|
||||
padding: 1em;
|
||||
background: white;
|
||||
color: black;
|
||||
top:50px;
|
||||
left:50px;
|
||||
}
|
||||
.z {
|
||||
position: relative;
|
||||
border: 1px solid black;
|
||||
padding: 1em;
|
||||
}
|
||||
</style>
|
|
@ -1,37 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<meta charset="utf-8">
|
||||
<link rel="author" href="mailto:masonf@chromium.org">
|
||||
<link rel=help href="https://open-ui.org/components/popup.research.explainer">
|
||||
<link rel=match href="popup-stacking-context-ref.tentative.html">
|
||||
|
||||
<popup>
|
||||
Inside popup
|
||||
<div class=z style="z-index: 2; background:lightgreen">z-index 2
|
||||
<div class=z style="z-index: 3; background:lightblue; left: 20px;">z-index 3</div>
|
||||
<div class=z style="z-index: 1; background:pink; top:-20px; left: 10px;">z-index 1</div>
|
||||
</div>
|
||||
<div class=z style="background:green; top:-100px; left: 250px; width: 100px;">Outside</div>
|
||||
Bottom of popup
|
||||
</popup>
|
||||
|
||||
<style>
|
||||
popup {
|
||||
width: 200px;
|
||||
height: 230px;
|
||||
border: 1px solid red;
|
||||
padding: 1em;
|
||||
background: white;
|
||||
color: black;
|
||||
top:50px;
|
||||
left:50px;
|
||||
}
|
||||
.z {
|
||||
position: relative;
|
||||
border: 1px solid black;
|
||||
padding: 1em;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
document.querySelector('popup').show();
|
||||
</script>
|
|
@ -1,85 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<meta charset="utf-8">
|
||||
<link rel="author" href="mailto:masonf@chromium.org">
|
||||
<link rel=help href="https://open-ui.org/components/popup.research.explainer">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
|
||||
<popup id=p1 anchor=b1><p>This is popup #1</p>
|
||||
<button id=b2 onclick='p2.show()'>Popup 2</button>
|
||||
<button id=b4 onclick='p4.show()'>Popup 4</button>
|
||||
</popup>
|
||||
<popup id=p2 anchor=b2><p>This is popup #2</p>
|
||||
<button id=b3 onclick='p3.show()'>Popup 3</button>
|
||||
</popup>
|
||||
<popup id=p3 anchor=b3><p>This is popup #3</p></popup>
|
||||
<popup id=p4 anchor=b4><p>This is popup #4</p></popup>
|
||||
<button id=b1 onclick='p1.show()'>Popup 1</button>
|
||||
|
||||
<dialog id=d1>This is a dialog<button onclick='this.parentElement.close()'>Close</button></dialog>
|
||||
<button id=b5 onclick='d1.show()'>Dialog</button>
|
||||
|
||||
<script>
|
||||
const popups = [p1, p2, p3, p4];
|
||||
|
||||
function assertState(...states) {
|
||||
assert_equals(popups.length,states.length);
|
||||
for(let i=0;i<popups.length;++i) {
|
||||
assert_equals(popups[i].open,states[i],`Popup #${i+1} incorrect state`);
|
||||
}
|
||||
}
|
||||
test(function() {
|
||||
assertState(false,false,false,false);
|
||||
p1.show();
|
||||
assertState(true,false,false,false);
|
||||
p2.show();
|
||||
assertState(true,true,false,false);
|
||||
p3.show();
|
||||
assertState(true,true,true,false);
|
||||
// P4 is a sibling of P2, so showing it should
|
||||
// close P2 and P3.
|
||||
p4.show();
|
||||
assertState(true,false,false,true);
|
||||
// P2 should close P4 now.
|
||||
p2.show();
|
||||
assertState(true,true,false,false);
|
||||
// Hiding P1 should hide all.
|
||||
p1.hide();
|
||||
assertState(false,false,false,false);
|
||||
}, "popup stacking behavior")
|
||||
|
||||
test(function() {
|
||||
function openManyPopups() {
|
||||
p1.show();
|
||||
p2.show();
|
||||
p3.show();
|
||||
assertState(true,true,true,false);
|
||||
}
|
||||
openManyPopups();
|
||||
d1.show(); // Dialog.show() should hide all popups.
|
||||
assertState(false,false,false,false);
|
||||
d1.close();
|
||||
openManyPopups();
|
||||
d1.showModal(); // Dialog.showModal() should also hide all popups.
|
||||
assertState(false,false,false,false);
|
||||
d1.close();
|
||||
}, "popups should be closed by dialogs")
|
||||
|
||||
test(function() {
|
||||
d1.show();
|
||||
assert_true(d1.open);
|
||||
p1.show();
|
||||
assertState(true,false,false,false);
|
||||
assert_true(d1.open);
|
||||
p1.hide();
|
||||
assert_true(d1.open);
|
||||
d1.close();
|
||||
}, "dialogs should not be closed by popups")
|
||||
</script>
|
||||
|
||||
<style>
|
||||
#p1 { top:350px; }
|
||||
#p2 { top:350px; left:200px; }
|
||||
#p3 { top:500px; }
|
||||
#p4 { top:500px;left:200px; }
|
||||
</style>
|
|
@ -0,0 +1,40 @@
|
|||
<!DOCTYPE html>
|
||||
<meta charset="utf-8">
|
||||
<title>summary element: clicking on anchor without link</title>
|
||||
<link rel="author" title="Di Zhang" href="mailto:dizhangg@chromium.org">
|
||||
<link rel="help" href="https://html.spec.whatwg.org/C/#the-summary-element">
|
||||
<link rel="help" href="https://html.spec.whatwg.org/multipage/text-level-semantics.html#the-a-element">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
|
||||
<details id="details">
|
||||
<summary><a id="no_inline">Details</a></summary>
|
||||
<p>Text</p>
|
||||
</details>
|
||||
|
||||
<details id="details_inline">
|
||||
<summary><a><i id="has_inline">Details</i></a></summary>
|
||||
<p>Text</p>
|
||||
</details>
|
||||
|
||||
|
||||
<script>
|
||||
|
||||
async function testClickingOnAnchorWithoutLink (detailsId, targetId) {
|
||||
const details = document.getElementById(detailsId);
|
||||
const target = document.getElementById(targetId);
|
||||
const initialLoc = location.hash;
|
||||
|
||||
assert_false(details.open);
|
||||
target.click();
|
||||
assert_true(details.open);
|
||||
assert_equals(location.hash, initialLoc);
|
||||
}
|
||||
|
||||
promise_test(() => testClickingOnAnchorWithoutLink('details', 'no_inline'),
|
||||
"clicking on anchor without link should open details and not navigate.");
|
||||
|
||||
promise_test(() => testClickingOnAnchorWithoutLink('details_inline', 'has_inline'),
|
||||
"clicking on anchor without link, with embedded inline element should open details and not navigate.");
|
||||
|
||||
</script>
|
|
@ -0,0 +1,104 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Summary</title>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="log"></div>
|
||||
<details>
|
||||
<summary>Summary</summary>
|
||||
Details
|
||||
</details>
|
||||
<script type="module">
|
||||
const details = document.querySelector("details");
|
||||
details.addEventListener("toggle",
|
||||
(e) => assert_true(false, 'details should not be toggled'));
|
||||
|
||||
const summary = document.querySelector("summary");
|
||||
summary.addEventListener("click",
|
||||
(e) => assert_true(false, `summary should not be clicked`));
|
||||
|
||||
test(() => {
|
||||
// keyCode: Enter
|
||||
summary.dispatchEvent(
|
||||
new KeyboardEvent("keypress", {
|
||||
keyCode: 13,
|
||||
})
|
||||
);
|
||||
|
||||
// key: Enter
|
||||
summary.dispatchEvent(
|
||||
new KeyboardEvent("keypress", {
|
||||
key: "Enter",
|
||||
})
|
||||
);
|
||||
|
||||
// keyCode: Space
|
||||
summary.dispatchEvent(
|
||||
new KeyboardEvent("keypress", {
|
||||
keyCode: 32,
|
||||
})
|
||||
);
|
||||
|
||||
// key: Space
|
||||
summary.dispatchEvent(
|
||||
new KeyboardEvent("keypress", {
|
||||
key: " ",
|
||||
})
|
||||
);
|
||||
}, `Dispatching untrusted keypress events to summary should not cause click event`);
|
||||
|
||||
test(() => {
|
||||
// keyCode: Enter
|
||||
summary.dispatchEvent(
|
||||
new KeyboardEvent("keydown", {
|
||||
keyCode: 13,
|
||||
})
|
||||
);
|
||||
summary.dispatchEvent(
|
||||
new KeyboardEvent("keyup", {
|
||||
keyCode: 13,
|
||||
})
|
||||
);
|
||||
|
||||
// key: Enter
|
||||
summary.dispatchEvent(
|
||||
new KeyboardEvent("keydown", {
|
||||
key: "Enter",
|
||||
})
|
||||
);
|
||||
summary.dispatchEvent(
|
||||
new KeyboardEvent("keyup", {
|
||||
key: "Enter",
|
||||
})
|
||||
);
|
||||
|
||||
// keyCode: Space
|
||||
summary.dispatchEvent(
|
||||
new KeyboardEvent("keydown", {
|
||||
keyCode: 32,
|
||||
})
|
||||
);
|
||||
summary.dispatchEvent(
|
||||
new KeyboardEvent("keyup", {
|
||||
keyCode: 32,
|
||||
})
|
||||
);
|
||||
|
||||
// key: Space
|
||||
summary.dispatchEvent(
|
||||
new KeyboardEvent("keydown", {
|
||||
key: " ",
|
||||
})
|
||||
);
|
||||
summary.dispatchEvent(
|
||||
new KeyboardEvent("keyup", {
|
||||
key: " ",
|
||||
})
|
||||
);
|
||||
}, `Dispatching untrusted keyup/keydown events to summary should not cause click event`);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
Loading…
Add table
Add a link
Reference in a new issue