blob: ddcb3ccb0d2c851fe3f1d07169de839465d12354 [file] [log] [blame]
<!DOCTYPE html>
<html>
<head>
<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>
button#foreground,
button#background {
position: absolute;
top: 75px;
left: 50px;
width: 100px;
height: 20px;
}
button#background {
left: 75px;
width: 150px;
height: 40px;
top: 125px;
line-height: 53px;
}
.clicked {
background-color: red;
}
#ancestorContainer.clicked {
background-color: green;
}
#ancestorContainer {
position: relative;
width: 300px;
height: 300px;
background-color: blue;
}
#displacedAncestor {
position: absolute;
top: 13px;
left: 240px;
width: 300px;
height: 250px;
background-color: #ff89;
}
#displacedAncestor.clicked {
background-color: #f009;
}
#inertContainer {
background-color: #fff9;
position: absolute;
top: 35px;
left: -192px;
width: 200px;
height: 200px;
}
fieldset {
margin: 0;
padding: 0;
border: 1px solid black;
}
legend {
background-color: white;
border: 1px solid black;
margin-left: 5px;
}
button.clicked::after {
content: " (clicked)";
}
.clicked > legend::after {
content: " (clicked)";
}
</style>
</head>
<body>
<p>Click on "Inert button".</p>
<ul>
<li>The blue square ("Non-inert ancestor container") should turn green.</li>
<li>The yellow, semi-transparent square ("Non-inert, displaced container") should not turn red.</li>
<li>"Non-inert button" should not turn red.</li>
</ul>
<p>(The full test suite checks a range of events.)</p>
<fieldset id="ancestorContainer">
<legend>Non-inert ancestor container</legend>
<iframe id="background" src="frame/button.html"></iframe>
<fieldset id="displacedAncestor">
<legend>Non-inert, displaced ancestor</legend>
<fieldset id="inertContainer" inert>
<legend>Inert container</legend>
<button id="foreground">foreground</button>
</fieldset>
</fieldset>
</fieldset>
<script>
document.body.addEventListener('click', (e) => {
e.target.classList.add('clicked');
});
function clickOn(element) {
return new test_driver.Actions()
.pointerMove(0, 0, {origin: element})
.pointerDown({button: test_driver.Actions.prototype.ButtonType.LEFT})
.pointerUp({button: test_driver.Actions.prototype.ButtonType.LEFT})
.send();
}
function auxClickOn(element) {
return new test_driver.Actions()
.pointerMove(0, 0, {origin: element})
.pointerDown({button: test_driver.Actions.prototype.ButtonType.RIGHT})
.pointerUp({button: test_driver.Actions.prototype.ButtonType.RIGHT})
.send();
}
function dblClickOn(element) {
return new test_driver.Actions()
.pointerMove(0, 0, {origin: element})
.pointerDown({button: test_driver.Actions.prototype.ButtonType.LEFT})
.pointerUp({button: test_driver.Actions.prototype.ButtonType.LEFT})
.pointerDown({button: test_driver.Actions.prototype.ButtonType.LEFT})
.pointerUp({button: test_driver.Actions.prototype.ButtonType.LEFT})
.send();
}
function movePointerOver(element) {
let rect = element.getBoundingClientRect();
return new test_driver.Actions()
.pointerMove(0, 0, { origin: element })
.send();
}
function movePointerTo(x, y) {
return new test_driver.Actions()
.pointerMove(x, y, { origin: "viewport" })
.send();
}
function expectEventsOn(events, element) {
let promises = [];
for (event of events) {
((event, element) => {
var promise = new Promise((resolve, reject) => {
let f = (e) => {
assert_equals(e.type, event);
assert_equals(e.target, element);
resolve();
}
element.addEventListener(event, f, { capture: true, once: true });
step_timeout(() => {
element.removeEventListener(event, f, { capture: true });
reject("did not get " + event + " on " + element.id);
}, 1000);
});
promises.push(promise);
})(event, element);
}
return promises;
}
function unexpectEventsOn(events, element) {
let promises = [];
for (event of events) {
((event, element) => {
var promise = new Promise((resolve, reject) => {
let f = (e) => {
assert_equals(e.type, event);
assert_equals(e.target, element);
reject("got " + e.type + " on " + e.target.id);
}
element.addEventListener(event, f, { capture: true, once: true });
step_timeout(() => {
element.removeEventListener(event, f, { capture: true });
resolve();
}, 1000);
});
promises.push(promise);
})(event, element);
}
return promises;
}
test(() => {
let rect = foreground.getBoundingClientRect();
let center_x = rect.left + (rect.width / 2);
let center_y = rect.top + (rect.height / 2);
assert_equals(document.elementsFromPoint(center_x, center_y)[0], foreground);
}, "elementsFromPoint returns inert element");
promise_test(async () => {
// Test mouse events on non-inert element - events should go to "foreground"
inertContainer.inert = false;
await movePointerTo(0, 0);
let promises = expectEventsOn(["mouseover", "mouseenter", "mousemove", "mousedown",
"mouseup", "click", "auxclick", "mouseout",
"mouseleave"],
foreground);
await clickOn(foreground);
await auxClickOn(foreground);
await dblClickOn(foreground);
let ancestorBox = ancestorContainer.getBoundingClientRect();
let inertBox = inertContainer.getBoundingClientRect();
let x = ancestorBox.left + (ancestorBox.width / 2);
let y = inertBox.bottom + ((ancestorBox.bottom - inertBox.bottom) / 2);
await movePointerTo(x, y);
await Promise.all(promises);
}, "Tests that any mouse event on a non-inert element is correctly targeted to that element");
promise_test(async () => {
// Make the containing element inert - now events should go to "container"
// which is the non-inert ancestor at the same position
inertContainer.inert = true;
await movePointerTo(0, 0);
let promises = expectEventsOn(["mouseover", "mouseenter", "mousemove", "mousedown",
"mouseup", "click", "auxclick"],
ancestorContainer);
promises = promises.concat(unexpectEventsOn(["mouseout", "mouseleave"],
ancestorContainer));
await clickOn(foreground);
await auxClickOn(foreground);
await dblClickOn(foreground);
let ancestorBox = ancestorContainer.getBoundingClientRect();
let inertBox = inertContainer.getBoundingClientRect();
let x = ancestorBox.left + (ancestorBox.width / 2);
let y = inertBox.bottom + ((ancestorBox.bottom - inertBox.bottom) / 2);
await movePointerTo(x, y);
await Promise.all(promises);
}, 'Tests that any mouse event on an inert element is targeted to the nearest non-inert ancestor at the same coordinates');
promise_test(async () => {
// Test pointer events on non-inert element - events should go to "foreground"
inertContainer.inert = false;
await movePointerTo(0, 0);
let promises = expectEventsOn(["pointerover", "pointerenter", "pointermove",
"pointerdown", "pointerup", "pointerout",
"pointerleave"],
foreground);
await clickOn(foreground);
let ancestorBox = ancestorContainer.getBoundingClientRect();
let inertBox = inertContainer.getBoundingClientRect();
let x = ancestorBox.left + (ancestorBox.width / 2);
let y = inertBox.bottom + ((ancestorBox.bottom - inertBox.bottom) / 2);
await movePointerTo(x, y);
await Promise.all(promises);
}, "Tests that any pointer event on a non-inert element is correctly targeted to that element");
promise_test(async () => {
// Make the containing element inert - now events should go to "container"
// which is the non-inert ancestor at the same position
inertContainer.inert = true;
await movePointerTo(0, 0);
let promises = expectEventsOn(["pointerover", "pointerenter", "pointermove",
"pointerdown", "pointerup" ],
ancestorContainer);
promises = promises.concat(unexpectEventsOn(["pointerout", "pointerleave"],
ancestorContainer));
await clickOn(foreground);
let ancestorBox = ancestorContainer.getBoundingClientRect();
let inertBox = inertContainer.getBoundingClientRect();
let x = ancestorBox.left + (ancestorBox.width / 2);
let y = inertBox.bottom + ((ancestorBox.bottom - inertBox.bottom) / 2);
await movePointerTo(x, y);
await Promise.all(promises);
}, 'Tests that any pointer event on an inert element is targeted to the nearest non-inert ancestor at the same coordinates');
</script>
</body>
</html>