Bug 1497969 - Add a way to emulate :focus-within pseudo-class. r=pbro
☠☠ backed out by b7fc0fb0f0e2 ☠ ☠
authorTim Nguyen <ntim.bugs@gmail.com>
Thu, 11 Oct 2018 09:23:09 +0000
changeset 489051 06f4b6597f74d01d0dce767a83ed537612cb7173
parent 489050 80b93ae22c27962c405c52328f53c49870bf4b9f
child 489052 b791c9a47d33088319ad53b32d0756ec014dfdb7
push id246
push userfmarier@mozilla.com
push dateSat, 13 Oct 2018 00:15:40 +0000
reviewerspbro
bugs1497969
milestone64.0a1
Bug 1497969 - Add a way to emulate :focus-within pseudo-class. r=pbro Differential Revision: https://phabricator.services.mozilla.com/D8275
devtools/client/inspector/index.xhtml
devtools/client/inspector/inspector.js
devtools/client/inspector/rules/rules.js
devtools/client/inspector/rules/test/browser_rules_add-rule-pseudo-class.js
devtools/client/inspector/rules/test/browser_rules_pseudo_lock_options.js
devtools/client/inspector/rules/views/rule-editor.js
devtools/client/inspector/test/browser_inspector_menu-01-sensitivity.js
devtools/client/inspector/test/browser_inspector_pseudoclass-menu.js
devtools/client/themes/rules.css
devtools/server/actors/highlighters/box-model.js
devtools/server/actors/inspector/node.js
devtools/server/actors/inspector/walker.js
devtools/server/tests/mochitest/test_inspector-pseudoclass-lock.html
--- a/devtools/client/inspector/index.xhtml
+++ b/devtools/client/inspector/index.xhtml
@@ -99,16 +99,17 @@
               <button id="pseudo-class-panel-toggle" data-localization="title=inspector.togglePseudo.tooltip" class="devtools-button"></button>
               <button id="class-panel-toggle" data-localization="title=inspector.classPanel.toggleClass.tooltip" class="devtools-button"></button>
             </div>
           </div>
           <div id="pseudo-class-panel" class="ruleview-reveal-panel" hidden="true">
             <label><input id="pseudo-hover-toggle" type="checkbox" value=":hover" tabindex="-1" />:hover</label>
             <label><input id="pseudo-active-toggle" type="checkbox" value=":active" tabindex="-1" />:active</label>
             <label><input id="pseudo-focus-toggle" type="checkbox" value=":focus" tabindex="-1" />:focus</label>
+            <label><input id="pseudo-focus-within-toggle" type="checkbox" value=":focus-within" tabindex="-1" />:focus-within</label>
           </div>
           <div id="ruleview-class-panel" class="ruleview-reveal-panel" hidden="true"></div>
         </div>
 
         <div id="ruleview-container" class="ruleview">
           <div id="ruleview-container-focusable" tabindex="-1">
           </div>
         </div>
--- a/devtools/client/inspector/inspector.js
+++ b/devtools/client/inspector/inspector.js
@@ -1580,17 +1580,17 @@ Inspector.prototype = {
       submenu: this._getAttributesSubmenu(isEditableElement),
     }));
 
     menu.append(new MenuItem({
       type: "separator",
     }));
 
     // Set the pseudo classes
-    for (const name of ["hover", "active", "focus"]) {
+    for (const name of ["hover", "active", "focus", "focus-within"]) {
       const menuitem = new MenuItem({
         id: "node-menu-pseudo-" + name,
         label: name,
         type: "checkbox",
         click: this.togglePseudoClass.bind(this, ":" + name),
       });
 
       if (isSelectionElement) {
--- a/devtools/client/inspector/rules/rules.js
+++ b/devtools/client/inspector/rules/rules.js
@@ -134,16 +134,17 @@ function CssRuleView(inspector, document
   this.searchClearButton = doc.getElementById("ruleview-searchinput-clear");
   this.pseudoClassPanel = doc.getElementById("pseudo-class-panel");
   this.pseudoClassToggle = doc.getElementById("pseudo-class-panel-toggle");
   this.classPanel = doc.getElementById("ruleview-class-panel");
   this.classToggle = doc.getElementById("class-panel-toggle");
   this.hoverCheckbox = doc.getElementById("pseudo-hover-toggle");
   this.activeCheckbox = doc.getElementById("pseudo-active-toggle");
   this.focusCheckbox = doc.getElementById("pseudo-focus-toggle");
+  this.focusWithinCheckbox = doc.getElementById("pseudo-focus-within-toggle");
 
   this.searchClearButton.hidden = true;
 
   this.shortcuts = new KeyShortcuts({ window: this.styleWindow });
   this._onShortcut = this._onShortcut.bind(this);
   this.shortcuts.on("Escape", event => this._onShortcut("Escape", event));
   this.shortcuts.on("Return", event => this._onShortcut("Return", event));
   this.shortcuts.on("Space", event => this._onShortcut("Space", event));
@@ -153,16 +154,17 @@ function CssRuleView(inspector, document
   this.addRuleButton.addEventListener("click", this._onAddRule);
   this.searchField.addEventListener("input", this._onFilterStyles);
   this.searchClearButton.addEventListener("click", this._onClearSearch);
   this.pseudoClassToggle.addEventListener("click", this._onTogglePseudoClassPanel);
   this.classToggle.addEventListener("click", this._onToggleClassPanel);
   this.hoverCheckbox.addEventListener("click", this._onTogglePseudoClass);
   this.activeCheckbox.addEventListener("click", this._onTogglePseudoClass);
   this.focusCheckbox.addEventListener("click", this._onTogglePseudoClass);
+  this.focusWithinCheckbox.addEventListener("click", this._onTogglePseudoClass);
 
   if (flags.testing) {
     // In tests, we start listening immediately to avoid having to simulate a mousemove.
     this.highlighters.addToView(this);
   } else {
     this.element.addEventListener("mousemove", () => {
       this.highlighters.addToView(this);
     }, { once: true });
@@ -773,26 +775,28 @@ CssRuleView.prototype = {
     this.addRuleButton.removeEventListener("click", this._onAddRule);
     this.searchField.removeEventListener("input", this._onFilterStyles);
     this.searchClearButton.removeEventListener("click", this._onClearSearch);
     this.pseudoClassToggle.removeEventListener("click", this._onTogglePseudoClassPanel);
     this.classToggle.removeEventListener("click", this._onToggleClassPanel);
     this.hoverCheckbox.removeEventListener("click", this._onTogglePseudoClass);
     this.activeCheckbox.removeEventListener("click", this._onTogglePseudoClass);
     this.focusCheckbox.removeEventListener("click", this._onTogglePseudoClass);
+    this.focusWithinCheckbox.removeEventListener("click", this._onTogglePseudoClass);
 
     this.searchField = null;
     this.searchClearButton = null;
     this.pseudoClassPanel = null;
     this.pseudoClassToggle = null;
     this.classPanel = null;
     this.classToggle = null;
     this.hoverCheckbox = null;
     this.activeCheckbox = null;
     this.focusCheckbox = null;
+    this.focusWithinCheckbox = null;
 
     this.inspector = null;
     this.styleDocument = null;
     this.styleWindow = null;
 
     if (this.element.parentNode) {
       this.element.remove();
     }
@@ -922,26 +926,28 @@ CssRuleView.prototype = {
   /**
    * Clear the pseudo class options panel by removing the checked and disabled
    * attributes for each checkbox.
    */
   clearPseudoClassPanel: function() {
     this.hoverCheckbox.checked = this.hoverCheckbox.disabled = false;
     this.activeCheckbox.checked = this.activeCheckbox.disabled = false;
     this.focusCheckbox.checked = this.focusCheckbox.disabled = false;
+    this.focusWithinCheckbox.checked = this.focusWithinCheckbox.disabled = false;
   },
 
   /**
    * Update the pseudo class options for the currently highlighted element.
    */
   refreshPseudoClassPanel: function() {
     if (!this._elementStyle || !this.inspector.selection.isElementNode()) {
       this.hoverCheckbox.disabled = true;
       this.activeCheckbox.disabled = true;
       this.focusCheckbox.disabled = true;
+      this.focusWithinCheckbox.disabled = true;
       return;
     }
 
     for (const pseudoClassLock of this._elementStyle.element.pseudoClassLocks) {
       switch (pseudoClassLock) {
         case ":hover": {
           this.hoverCheckbox.checked = true;
           break;
@@ -949,16 +955,20 @@ CssRuleView.prototype = {
         case ":active": {
           this.activeCheckbox.checked = true;
           break;
         }
         case ":focus": {
           this.focusCheckbox.checked = true;
           break;
         }
+        case ":focus-within": {
+          this.focusWithinCheckbox.checked = true;
+          break;
+        }
       }
     }
   },
 
   _populate: function() {
     const elementStyle = this._elementStyle;
     return this._elementStyle.populate().then(() => {
       if (this._elementStyle !== elementStyle || this.isDestroyed) {
@@ -1564,25 +1574,27 @@ CssRuleView.prototype = {
 
   showPseudoClassPanel: function() {
     this.hideClassPanel();
 
     this.pseudoClassToggle.classList.add("checked");
     this.hoverCheckbox.setAttribute("tabindex", "0");
     this.activeCheckbox.setAttribute("tabindex", "0");
     this.focusCheckbox.setAttribute("tabindex", "0");
+    this.focusWithinCheckbox.setAttribute("tabindex", "0");
 
     this.pseudoClassPanel.hidden = false;
   },
 
   hidePseudoClassPanel: function() {
     this.pseudoClassToggle.classList.remove("checked");
     this.hoverCheckbox.setAttribute("tabindex", "-1");
     this.activeCheckbox.setAttribute("tabindex", "-1");
     this.focusCheckbox.setAttribute("tabindex", "-1");
+    this.focusWithinCheckbox.setAttribute("tabindex", "-1");
 
     this.pseudoClassPanel.hidden = true;
   },
 
   /**
    * Called when a pseudo class checkbox is clicked and toggles
    * the pseudo class for the current selected element.
    */
--- a/devtools/client/inspector/rules/test/browser_rules_add-rule-pseudo-class.js
+++ b/devtools/client/inspector/rules/test/browser_rules_add-rule-pseudo-class.js
@@ -11,17 +11,20 @@ const TEST_URI = "<p id='element'>Test e
 const EXPECTED_SELECTOR = "#element";
 const TEST_DATA = [
   [],
   [":hover"],
   [":hover", ":active"],
   [":hover", ":active", ":focus"],
   [":active"],
   [":active", ":focus"],
-  [":focus"]
+  [":focus"],
+  [":focus-within"],
+  [":focus-within", ":hover"],
+  [":focus-within", ":hover", ":active"],
 ];
 
 add_task(async function() {
   await addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
   const {inspector, view} = await openRuleView();
   await selectNode("#element", inspector);
 
   for (const data of TEST_DATA) {
@@ -52,31 +55,40 @@ async function setPseudoLocks(inspector,
       case ":active":
         view.activeCheckbox.click();
         await inspector.once("rule-view-refreshed");
         break;
       case ":focus":
         view.focusCheckbox.click();
         await inspector.once("rule-view-refreshed");
         break;
+      case ":focus-within":
+        view.focusWithinCheckbox.click();
+        await inspector.once("rule-view-refreshed");
+        break;
     }
   }
 }
 
 async function resetPseudoLocks(inspector, view) {
   if (!view.hoverCheckbox.checked &&
       !view.activeCheckbox.checked &&
-      !view.focusCheckbox.checked) {
+      !view.focusCheckbox.checked &&
+      !view.focusWithinCheckbox.checked) {
     return;
   }
   if (view.hoverCheckbox.checked) {
     view.hoverCheckbox.click();
     await inspector.once("rule-view-refreshed");
   }
   if (view.activeCheckbox.checked) {
     view.activeCheckbox.click();
     await inspector.once("rule-view-refreshed");
   }
   if (view.focusCheckbox.checked) {
     view.focusCheckbox.click();
     await inspector.once("rule-view-refreshed");
   }
+  if (view.focusWithinCheckbox.checked) {
+    view.focusWithinCheckbox.click();
+    await inspector.once("rule-view-refreshed");
+  }
 }
--- a/devtools/client/inspector/rules/test/browser_rules_pseudo_lock_options.js
+++ b/devtools/client/inspector/rules/test/browser_rules_pseudo_lock_options.js
@@ -15,16 +15,19 @@ const TEST_URI = `
       color: blue;
     }
     div:active {
       color: yellow;
     }
     div:focus {
       color: green;
     }
+    div:focus-within {
+      color: papayawhip;
+    }
   </style>
   <div>test div</div>
 `;
 
 add_task(async function() {
   await addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
   const {inspector, view} = await openRuleView();
   await selectNode("div", inspector);
@@ -46,36 +49,44 @@ add_task(async function() {
   await togglePseudoClass(inspector, view.activeCheckbox);
   await assertPseudoRemoved(inspector, view, 2);
 
   await togglePseudoClass(inspector, view.focusCheckbox);
   await assertPseudoAdded(inspector, view, ":focus", 3, 1);
   await togglePseudoClass(inspector, view.focusCheckbox);
   await assertPseudoRemoved(inspector, view, 2);
 
+  await togglePseudoClass(inspector, view.focusWithinCheckbox);
+  await assertPseudoAdded(inspector, view, ":focus-within", 3, 1);
+  await togglePseudoClass(inspector, view.focusWithinCheckbox);
+  await assertPseudoRemoved(inspector, view, 2);
+
   info("Toggle all pseudo lock and check that the pseudo lock is added");
   await togglePseudoClass(inspector, view.hoverCheckbox);
   await togglePseudoClass(inspector, view.activeCheckbox);
   await togglePseudoClass(inspector, view.focusCheckbox);
-  await assertPseudoAdded(inspector, view, ":focus", 5, 1);
-  await assertPseudoAdded(inspector, view, ":active", 5, 2);
-  await assertPseudoAdded(inspector, view, ":hover", 5, 3);
+  await assertPseudoAdded(inspector, view, ":focus-within", 6, 1);
+  await assertPseudoAdded(inspector, view, ":focus", 6, 1);
+  await assertPseudoAdded(inspector, view, ":active", 6, 2);
+  await assertPseudoAdded(inspector, view, ":hover", 6, 3);
   await togglePseudoClass(inspector, view.hoverCheckbox);
   await togglePseudoClass(inspector, view.activeCheckbox);
   await togglePseudoClass(inspector, view.focusCheckbox);
   await assertPseudoRemoved(inspector, view, 2);
 
   info("Select a null element");
   await view.selectElement(null);
   ok(!view.hoverCheckbox.checked && view.hoverCheckbox.disabled,
     ":hover checkbox is unchecked and disabled");
   ok(!view.activeCheckbox.checked && view.activeCheckbox.disabled,
     ":active checkbox is unchecked and disabled");
   ok(!view.focusCheckbox.checked && view.focusCheckbox.disabled,
     ":focus checkbox is unchecked and disabled");
+  ok(!view.focusWithinCheckbox.checked && view.focusWithinCheckbox.disabled,
+    ":focus-within checkbox is unchecked and disabled");
 
   info("Toggle the pseudo class panel close");
   view.pseudoClassToggle.click();
   await assertPseudoPanelClosed(view);
 });
 
 async function togglePseudoClass(inspector, pseudoClassOption) {
   info("Toggle the pseudoclass, wait for it to be applied");
@@ -103,29 +114,34 @@ function assertPseudoRemoved(inspector, 
 
 function assertPseudoPanelOpened(view) {
   info("Check the opened state of the pseudo class panel");
 
   ok(!view.pseudoClassPanel.hidden, "Pseudo Class Panel Opened");
   ok(!view.hoverCheckbox.disabled, ":hover checkbox is not disabled");
   ok(!view.activeCheckbox.disabled, ":active checkbox is not disabled");
   ok(!view.focusCheckbox.disabled, ":focus checkbox is not disabled");
+  ok(!view.focusWithinCheckbox.disabled, ":focus-within checkbox is not disabled");
 
   is(view.hoverCheckbox.getAttribute("tabindex"), "0",
     ":hover checkbox has a tabindex of 0");
   is(view.activeCheckbox.getAttribute("tabindex"), "0",
     ":active checkbox has a tabindex of 0");
   is(view.focusCheckbox.getAttribute("tabindex"), "0",
     ":focus checkbox has a tabindex of 0");
+  is(view.focusWithinCheckbox.getAttribute("tabindex"), "0",
+    ":focus-within checkbox has a tabindex of 0");
 }
 
 function assertPseudoPanelClosed(view) {
   info("Check the closed state of the pseudo clas panel");
 
   ok(view.pseudoClassPanel.hidden, "Pseudo Class Panel Hidden");
 
   is(view.hoverCheckbox.getAttribute("tabindex"), "-1",
     ":hover checkbox has a tabindex of -1");
   is(view.activeCheckbox.getAttribute("tabindex"), "-1",
     ":active checkbox has a tabindex of -1");
   is(view.focusCheckbox.getAttribute("tabindex"), "-1",
     ":focus checkbox has a tabindex of -1");
+  is(view.focusWithinCheckbox.getAttribute("tabindex"), "-1",
+    ":focus-within checkbox has a tabindex of -1");
 }
--- a/devtools/client/inspector/rules/views/rule-editor.js
+++ b/devtools/client/inspector/rules/views/rule-editor.js
@@ -430,17 +430,17 @@ RuleEditor.prototype = {
           switch (selectorText.type) {
             case SELECTOR_ATTRIBUTE:
               selectorClass = "ruleview-selector-attribute";
               break;
             case SELECTOR_ELEMENT:
               selectorClass = "ruleview-selector";
               break;
             case SELECTOR_PSEUDO_CLASS:
-              selectorClass = [":active", ":focus", ":hover"].some(
+              selectorClass = [":active", ":focus", ":focus-within", ":hover"].some(
                   pseudo => selectorText.value === pseudo) ?
                 "ruleview-selector-pseudo-class-lock" :
                 "ruleview-selector-pseudo-class";
               break;
             default:
               break;
           }
 
--- a/devtools/client/inspector/test/browser_inspector_menu-01-sensitivity.js
+++ b/devtools/client/inspector/test/browser_inspector_menu-01-sensitivity.js
@@ -28,16 +28,17 @@ const ALL_MENU_ITEMS = [
   "node-menu-copyuniqueselector",
   "node-menu-copycsspath",
   "node-menu-copyxpath",
   "node-menu-copyimagedatauri",
   "node-menu-delete",
   "node-menu-pseudo-hover",
   "node-menu-pseudo-active",
   "node-menu-pseudo-focus",
+  "node-menu-pseudo-focus-within",
   "node-menu-scrollnodeintoview",
   "node-menu-screenshotnode",
   "node-menu-add-attribute",
   "node-menu-copy-attribute",
   "node-menu-edit-attribute",
   "node-menu-remove-attribute"
 ].concat(PASTE_MENU_ITEMS, ACTIVE_ON_DOCTYPE_ITEMS);
 
--- a/devtools/client/inspector/test/browser_inspector_pseudoclass-menu.js
+++ b/devtools/client/inspector/test/browser_inspector_pseudoclass-menu.js
@@ -4,17 +4,17 @@
 "use strict";
 
 // Test that the inspector has the correct pseudo-class locking menu items and
 // that these items actually work
 
 const TEST_URI = "data:text/html;charset=UTF-8," +
                  "pseudo-class lock node menu tests" +
                  "<div>test div</div>";
-const PSEUDOS = ["hover", "active", "focus"];
+const PSEUDOS = ["hover", "active", "focus", "focus-within"];
 
 add_task(async function() {
   const {inspector, testActor} = await openInspectorForURL(TEST_URI);
   await selectNode("div", inspector);
 
   const allMenuItems = openContextMenuAndGetAllItems(inspector);
 
   await testMenuItems(testActor, allMenuItems, inspector);
--- a/devtools/client/themes/rules.css
+++ b/devtools/client/themes/rules.css
@@ -50,16 +50,17 @@
 
 #ruleview-command-toolbar {
   display: flex;
 }
 
 .ruleview-reveal-panel {
   display: flex;
   overflow: hidden;
+  flex-wrap: wrap;
 }
 
 .ruleview-reveal-panel[hidden] {
   display: none;
 }
 
 .ruleview-reveal-panel label {
   -moz-user-select: none;
--- a/devtools/server/actors/highlighters/box-model.js
+++ b/devtools/server/actors/highlighters/box-model.js
@@ -23,17 +23,17 @@ const nodeConstants = require("devtools/
 
 // Note that the order of items in this array is important because it is used
 // for drawing the BoxModelHighlighter's path elements correctly.
 const BOX_MODEL_REGIONS = ["margin", "border", "padding", "content"];
 const BOX_MODEL_SIDES = ["top", "right", "bottom", "left"];
 // Width of boxmodelhighlighter guides
 const GUIDE_STROKE_WIDTH = 1;
 // FIXME: add ":visited" and ":link" after bug 713106 is fixed
-const PSEUDO_CLASSES = [":hover", ":active", ":focus"];
+const PSEUDO_CLASSES = [":hover", ":active", ":focus", ":focus-within"];
 
 /**
  * The BoxModelHighlighter draws the box model regions on top of a node.
  * If the node is a block box, then each region will be displayed as 1 polygon.
  * If the node is an inline box though, each region may be represented by 1 or
  * more polygons, depending on how many line boxes the inline element has.
  *
  * Usage example:
--- a/devtools/server/actors/inspector/node.js
+++ b/devtools/server/actors/inspector/node.js
@@ -29,17 +29,17 @@ loader.lazyRequireGetter(this, "Inspecto
 loader.lazyRequireGetter(this, "LongStringActor", "devtools/server/actors/string", true);
 loader.lazyRequireGetter(this, "getFontPreviewData", "devtools/server/actors/styles", true);
 loader.lazyRequireGetter(this, "CssLogic", "devtools/server/actors/inspector/css-logic", true);
 loader.lazyRequireGetter(this, "EventParsers", "devtools/server/actors/inspector/event-parsers", true);
 
 const SUBGRID_ENABLED =
   Services.prefs.getBoolPref("layout.css.grid-template-subgrid-value.enabled");
 
-const PSEUDO_CLASSES = [":hover", ":active", ":focus"];
+const PSEUDO_CLASSES = [":hover", ":active", ":focus", ":focus-within"];
 const FONT_FAMILY_PREVIEW_TEXT = "The quick brown fox jumps over the lazy dog";
 const FONT_FAMILY_PREVIEW_TEXT_SIZE = 20;
 
 /**
  * Server side of the node actor.
  */
 const NodeActor = protocol.ActorClassWithSpec(nodeSpec, {
   initialize: function(walker, node) {
--- a/devtools/server/actors/inspector/walker.js
+++ b/devtools/server/actors/inspector/walker.js
@@ -1162,17 +1162,17 @@ var WalkerActor = protocol.ActorClassWit
     };
   },
 
   /**
    * Add a pseudo-class lock to a node.
    *
    * @param NodeActor node
    * @param string pseudo
-   *    A pseudoclass: ':hover', ':active', ':focus'
+   *    A pseudoclass: ':hover', ':active', ':focus', ':focus-within'
    * @param options
    *    Options object:
    *    `parents`: True if the pseudo-class should be added
    *      to parent nodes.
    *    `enabled`: False if the pseudo-class should be locked
    *      to 'off'. Defaults to true.
    *
    * @returns An empty packet.  A "pseudoClassLock" mutation will
@@ -1242,17 +1242,17 @@ var WalkerActor = protocol.ActorClassWit
     node.rawNode.classList.remove(HIDDEN_CLASS);
   },
 
   /**
    * Remove a pseudo-class lock from a node.
    *
    * @param NodeActor node
    * @param string pseudo
-   *    A pseudoclass: ':hover', ':active', ':focus'
+   *    A pseudoclass: ':hover', ':active', ':focus', ':focus-within'
    * @param options
    *    Options object:
    *    `parents`: True if the pseudo-class should be removed
    *      from parent nodes.
    *
    * @returns An empty response.  "pseudoClassLock" mutations
    *    will be emitted for any changed nodes.
    */
--- a/devtools/server/tests/mochitest/test_inspector-pseudoclass-lock.html
+++ b/devtools/server/tests/mochitest/test_inspector-pseudoclass-lock.html
@@ -8,17 +8,17 @@ https://bugzilla.mozilla.org/show_bug.cg
   <title>Test for Bug </title>
 
   <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
   <script type="application/javascript" src="inspector-helpers.js"></script>
   <script type="application/javascript">
 "use strict";
 
-const KNOWN_PSEUDOCLASSES = [":hover", ":active", ":focus"];
+const KNOWN_PSEUDOCLASSES = [":hover", ":active", ":focus", ":focus-within"];
 
 window.onload = function() {
   SimpleTest.waitForExplicitFinish();
   runNextTest();
 };
 
 const InspectorUtils = require("InspectorUtils");