blob: 4f0e44909a67a279d9dd73b9239fbbb3f75d5e15 [file] [log] [blame]
<!doctype html>
<html id="html">
<head>
<script src="../../resources/js-test-pre.js"></script>
<style id="style">
* {
background-color: white;
}
:focus-within {
background-color: rgb(1, 2, 3);
}
</style>
</head>
<body id="body">
<div id="webkit-test">
<div id="container1">
<div id="sibling1"></div>
<div id="sibling2">
<input id="target1">
</div>
<div id="sibling3"></div>
</div>
<div id="container2">
<div id="sibling4"></div>
<div id="sibling5">
<textarea id="target2"></textarea>
</div>
<div id="sibling6"></div>
</div>
</div>
</body>
<script>
"use strict";
description('Check the basic features of the :focus-within pseudo class');
function elementsStyledWithFocusWithinSelector() {
let elements = [];
for (let element of document.querySelectorAll("*")) {
if (getComputedStyle(element).backgroundColor === 'rgb(1, 2, 3)') {
elements.push(element.id);
}
}
return elements;
}
function elementsMatchingFocusWithinSelector() {
let elements = [];
for (let element of document.querySelectorAll(":focus-within")) {
elements.push(element.id);
}
return elements;
}
debug("Initial State");
shouldBe('elementsStyledWithFocusWithinSelector()', '[]');
shouldBe('elementsMatchingFocusWithinSelector()', '[]');
debug("Focus target1");
var target1 = document.getElementById("target1");
target1.focus();
shouldBe('elementsStyledWithFocusWithinSelector()', '["html", "body", "webkit-test", "container1", "sibling2", "target1"]');
shouldBe('elementsMatchingFocusWithinSelector()', '["html", "body", "webkit-test", "container1", "sibling2", "target1"]');
debug("Focus target2");
var target2 = document.getElementById("target2");
target2.focus();
shouldBe('elementsStyledWithFocusWithinSelector()', '["html", "body", "webkit-test", "container2", "sibling5", "target2"]');
shouldBe('elementsMatchingFocusWithinSelector()', '["html", "body", "webkit-test", "container2", "sibling5", "target2"]');
debug("Set display none on target2");
target2.style.display = "none";
// NOTE: At the time of this writing, it is is critical that this behavior, keeping focus even if display is set to "none"
// does *not* change, despite the fact that the HTML standard currently mandates a change. In 2014, an attempt to change
// this broke the facebook.com website, which depended on the behavior. See <https://bugs.webkit.org/show_bug.cgi?id=29241>.
shouldBe('elementsStyledWithFocusWithinSelector()', '["html", "body", "webkit-test", "container2", "sibling5", "target2"]');
shouldBe('elementsMatchingFocusWithinSelector()', '["html", "body", "webkit-test", "container2", "sibling5", "target2"]');
shouldBeTrue('target2.matches(":focus")');
debug("Focus target1");
target1.focus();
shouldBe('elementsStyledWithFocusWithinSelector()', '["html", "body", "webkit-test", "container1", "sibling2", "target1"]');
shouldBe('elementsMatchingFocusWithinSelector()', '["html", "body", "webkit-test", "container1", "sibling2", "target1"]');
debug("Try to focus target2");
target2.focus();
shouldBe('elementsStyledWithFocusWithinSelector()', '["html", "body", "webkit-test", "container1", "sibling2", "target1"]');
shouldBe('elementsMatchingFocusWithinSelector()', '["html", "body", "webkit-test", "container1", "sibling2", "target1"]');
shouldBeTrue('target1.matches(":focus")');
shouldBeFalse('target2.matches(":focus")');
debug("Set display back on target2");
target2.style.display = "revert";
shouldBe('elementsStyledWithFocusWithinSelector()', '["html", "body", "webkit-test", "container1", "sibling2", "target1"]');
shouldBe('elementsMatchingFocusWithinSelector()', '["html", "body", "webkit-test", "container1", "sibling2", "target1"]');
debug("Focus target2");
target2.focus();
shouldBe('elementsStyledWithFocusWithinSelector()', '["html", "body", "webkit-test", "container2", "sibling5", "target2"]');
shouldBe('elementsMatchingFocusWithinSelector()', '["html", "body", "webkit-test", "container2", "sibling5", "target2"]');
debug("Set display none on container2");
var container2 = document.getElementById("container2");
container2.style.display = "none";
shouldBe('elementsStyledWithFocusWithinSelector()', '["html", "body", "webkit-test", "container2", "sibling5", "target2"]');
shouldBe('elementsMatchingFocusWithinSelector()', '["html", "body", "webkit-test", "container2", "sibling5", "target2"]');
shouldBeTrue('target2.matches(":focus")');
debug("Focus target1");
target1.focus();
shouldBe('elementsStyledWithFocusWithinSelector()', '["html", "body", "webkit-test", "container1", "sibling2", "target1"]');
shouldBe('elementsMatchingFocusWithinSelector()', '["html", "body", "webkit-test", "container1", "sibling2", "target1"]');
debug("Try to focus target2");
target2.focus();
shouldBe('elementsStyledWithFocusWithinSelector()', '["html", "body", "webkit-test", "container1", "sibling2", "target1"]');
shouldBe('elementsMatchingFocusWithinSelector()', '["html", "body", "webkit-test", "container1", "sibling2", "target1"]');
shouldBeTrue('target1.matches(":focus")');
shouldBeFalse('target2.matches(":focus")');
debug("Set display back on container2");
var container2 = document.getElementById("container2");
container2.style.display = "revert";
shouldBe('elementsStyledWithFocusWithinSelector()', '["html", "body", "webkit-test", "container1", "sibling2", "target1"]');
shouldBe('elementsMatchingFocusWithinSelector()', '["html", "body", "webkit-test", "container1", "sibling2", "target1"]');
debug("Detach container1 from the document");
var container1 = document.getElementById("container1");
container1.parentElement.removeChild(container1);
shouldBe('elementsStyledWithFocusWithinSelector()', '[]');
shouldBe('elementsMatchingFocusWithinSelector()', '[]');
shouldBe('container1.querySelectorAll(":focus-within").length', '0');
shouldBeFalse('target1.matches(":focus")');
shouldBeFalse('target2.matches(":focus")');
debug("Try to focus target1");
target1.focus();
shouldBe('elementsStyledWithFocusWithinSelector()', '[]');
shouldBe('elementsMatchingFocusWithinSelector()', '[]');
shouldBe('container1.querySelectorAll(":focus-within").length', '0');
shouldBeFalse('target1.matches(":focus")');
shouldBeFalse('target2.matches(":focus")');
debug("Focus target2");
target2.focus();
shouldBe('elementsStyledWithFocusWithinSelector()', '["html", "body", "webkit-test", "container2", "sibling5", "target2"]');
shouldBe('elementsMatchingFocusWithinSelector()', '["html", "body", "webkit-test", "container2", "sibling5", "target2"]');
debug("Attach container1 in container2");
container2.appendChild(container1);
shouldBe('elementsStyledWithFocusWithinSelector()', '["html", "body", "webkit-test", "container2", "sibling5", "target2"]');
shouldBe('elementsMatchingFocusWithinSelector()', '["html", "body", "webkit-test", "container2", "sibling5", "target2"]');
debug("Focus target1");
target1.focus();
shouldBe('elementsStyledWithFocusWithinSelector()', '["html", "body", "webkit-test", "container2", "container1", "sibling2", "target1"]');
shouldBe('elementsMatchingFocusWithinSelector()', '["html", "body", "webkit-test", "container2", "container1", "sibling2", "target1"]');
debug("Move target1 in container2");
container2.appendChild(target1);
shouldBe('elementsStyledWithFocusWithinSelector()', '[]');
shouldBe('elementsMatchingFocusWithinSelector()', '[]');
shouldBeFalse('target1.matches(":focus")');
shouldBeFalse('target2.matches(":focus")');
gc();
// Clean up the test.
document.getElementById("webkit-test").style.display = "none";
document.getElementById("style").innerHTML = "";
</script>
<script src="../../resources/js-test-post.js"></script>
</html>