| <!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> |