tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

focus-method-delegatesFocus.html (10908B)


      1 <!DOCTYPE html>
      2 <meta charset="utf-8">
      3 <title>HTML Test: focus() on shadow host with delegatesFocus</title>
      4 <script src="/resources/testharness.js"></script>
      5 <script src="/resources/testharnessreport.js"></script>
      6 <script src="/resources/testdriver.js"></script>
      7 <script src="/resources/testdriver-vendor.js"></script>
      8 <script src="resources/shadow-utils.js"></script>
      9 
     10 <body>
     11 <div id="host">
     12  <div id="slottedToSecondSlot" slot="secondSlot">slottedToSecondSlot</div>
     13  <div id="slottedToFirstSlot" slot="firstSlot">slottedToFirstSlot</div>
     14 </div>
     15 <div id="outside">outside</div>
     16 </body>
     17 
     18 <script>
     19 const host = document.getElementById("host");
     20 const slottedToSecondSlot = document.getElementById("slottedToSecondSlot");
     21 const slottedToFirstSlot = document.getElementById("slottedToFirstSlot");
     22 const outside = document.getElementById("outside");
     23 
     24 const shadowRoot = host.attachShadow({ mode: "open", delegatesFocus: true });
     25 const aboveSlots = document.createElement("div");
     26 aboveSlots.innerText = "aboveSlots";
     27 const firstSlot = document.createElement("slot");
     28 firstSlot.name = "firstSlot";
     29 const secondSlot = document.createElement("slot");
     30 secondSlot.name = "secondSlot";
     31 const belowSlots = document.createElement("div");
     32 belowSlots.innerText = "belowSlots";
     33 shadowRoot.appendChild(aboveSlots);
     34 shadowRoot.appendChild(firstSlot);
     35 shadowRoot.appendChild(secondSlot);
     36 shadowRoot.appendChild(belowSlots);
     37 
     38 const elementsInFlatTreeOrder = [host, aboveSlots, firstSlot,
     39  slottedToFirstSlot, secondSlot, slottedToSecondSlot, belowSlots, outside];
     40 
     41 // Final structure:
     42 // <div #host> (delegatesFocus=true)
     43 //    #shadowRoot
     44 //      <div #aboveSlots>
     45 //      <slot #firstSlot>
     46 //        (slotted) <div #slottedToFirstSlot>
     47 //      <slot #secondSlot>
     48 //        (slotted) <div #slottedToSecondSlot>
     49 //      <div #belowSlots>
     50 // <div #outside>
     51 
     52 
     53 function setAllTabIndex(value) {
     54  setTabIndex(elementsInFlatTreeOrder, value);
     55 }
     56 
     57 function removeAllTabIndex() {
     58  removeTabIndex(elementsInFlatTreeOrder);
     59 }
     60 
     61 function resetTabIndexAndFocus() {
     62  removeAllTabIndex();
     63  resetFocus(document);
     64  resetFocus(shadowRoot);
     65 }
     66 
     67 test(() => {
     68  resetTabIndexAndFocus();
     69  setAllTabIndex(0);
     70  // Structure:
     71  // <div #host> (delegatesFocus=true) tabindex=0
     72  //    #shadowRoot
     73  //      <div #aboveSlots> tabindex=0
     74  //      <slot #firstSlot> tabindex=0
     75  //        (slotted) <div #slottedToFirstSlot> tabindex=0
     76  //      <slot #secondSlot> tabindex=0
     77  //        (slotted) <div #slottedToSecondSlot> tabindex=0
     78  //      <div #belowSlots> tabindex=0
     79  // <div #outside> tabindex=0
     80  // First focusable = #aboveSlots
     81  host.focus();
     82  assert_equals(shadowRoot.activeElement, aboveSlots);
     83  assert_equals(document.activeElement, host);
     84 }, "focus() on host with delegatesFocus, all tabindex=0");
     85 
     86 test(() => {
     87  resetTabIndexAndFocus();
     88  setAllTabIndex(0);
     89  setTabIndex([host], -1);
     90  // First focusable = #aboveSlots
     91  host.focus();
     92  assert_equals(shadowRoot.activeElement, aboveSlots);
     93  assert_equals(document.activeElement, host);
     94 }, "focus() on host with delegatesFocus & tabindex =-1, all other tabindex=0");
     95 
     96 test(() => {
     97  resetTabIndexAndFocus();
     98  setTabIndex([aboveSlots, slottedToFirstSlot, slottedToSecondSlot, belowSlots], 0);
     99  // First focusable = #aboveSlots
    100  host.focus();
    101  assert_equals(shadowRoot.activeElement, aboveSlots);
    102  assert_equals(document.activeElement, host);
    103 }, "focus() on host with delegatesFocus & no tabindex, all other tabindex=0");
    104 
    105 test(() => {
    106  resetTabIndexAndFocus();
    107  setAllTabIndex(-1);
    108  setTabIndex([host], 0);
    109  // First focusable = #aboveSlots
    110  host.focus();
    111  assert_equals(shadowRoot.activeElement, aboveSlots);
    112  assert_equals(document.activeElement, host);
    113 }, "focus() on host with delegatesFocus & tabindex = 0, all other tabindex=-1");
    114 
    115 test(() => {
    116  resetTabIndexAndFocus();
    117  removeAllTabIndex();
    118  // No focusable element under #host in the flat tree.
    119  host.focus();
    120  assert_equals(shadowRoot.activeElement, null);
    121  assert_equals(document.activeElement, document.body);
    122 }, "focus() on host with delegatesFocus, all without tabindex");
    123 
    124 test(() => {
    125  resetTabIndexAndFocus();
    126  // First focusable = #aboveSlots
    127  setAllTabIndex(-1);
    128  host.focus();
    129  assert_equals(shadowRoot.activeElement, aboveSlots);
    130  assert_equals(document.activeElement, host);
    131 }, "focus() on host with delegatesFocus, all tabindex=-1");
    132 
    133 test(() => {
    134  resetTabIndexAndFocus();
    135  removeAllTabIndex();
    136  setTabIndex([host, belowSlots], 0);
    137  // Structure:
    138  // <div #host> (delegatesFocus=true) tabindex=0
    139  //    #shadowRoot
    140  //      <div #aboveSlots>
    141  //      <slot #firstSlot>
    142  //        (slotted) <div #slottedToFirstSlot>
    143  //      <slot #secondSlot>
    144  //        (slotted) <div #slottedToSecondSlot>
    145  //      <div #belowSlots> tabindex=0
    146  // <div #outside>
    147  // First focusable = #belowSlots
    148  host.focus();
    149  assert_equals(shadowRoot.activeElement, belowSlots);
    150  assert_equals(document.activeElement, host);
    151 }, "focus() on host with delegatesFocus & tabindex=0, #belowSlots with tabindex=0");
    152 
    153 test(() => {
    154  resetTabIndexAndFocus();
    155  removeAllTabIndex();
    156  setTabIndex([host, outside], 0);
    157  // Structure:
    158  // <div #host> (delegatesFocus=true) tabindex=0
    159  //    #shadowRoot
    160  //      <div #aboveSlots>
    161  //      <slot #firstSlot>
    162  //        (slotted) <div #slottedToFirstSlot>
    163  //      <slot #secondSlot>
    164  //        (slotted) <div #slottedToSecondSlot>
    165  //      <div #belowSlots>
    166  // <div #outside> tabindex=0
    167  // No focusable element under #host in the flat tree.
    168  host.focus();
    169  assert_equals(shadowRoot.activeElement, null);
    170  assert_equals(document.activeElement, document.body);
    171 }, "focus() on host with delegatesFocus & tabindex=0, #outside with tabindex=0");
    172 
    173 test(() => {
    174  resetTabIndexAndFocus();
    175  setTabIndex([host, aboveSlots, belowSlots], 0);
    176  // Structure:
    177  // <div #host> (delegatesFocus=true) tabindex=0
    178  //    #shadowRoot
    179  //      <div #aboveSlots> tabindex=0
    180  //      <slot #firstSlot>
    181  //        (slotted) <div #slottedToFirstSlot>
    182  //      <slot #secondSlot>
    183  //        (slotted) <div #slottedToSecondSlot>
    184  //      <div #belowSlots> tabindex=0
    185  // <div #outside>
    186  // First focusable = #aboveSlots
    187  host.focus();
    188  assert_equals(shadowRoot.activeElement, aboveSlots);
    189  assert_equals(document.activeElement, host);
    190 }, "focus() on host with delegatesFocus & tabindex=0, #aboveSlots and #belowSlots with tabindex=0");
    191 
    192 test(() => {
    193  resetTabIndexAndFocus();
    194  setTabIndex([host, aboveSlots], 0);
    195  setTabIndex([belowSlots], 1);
    196  // Structure:
    197  // <div #host> (delegatesFocus=true) tabindex=0
    198  //    #shadowRoot
    199  //      <div #aboveSlots> tabindex=0
    200  //      <slot #firstSlot>
    201  //        (slotted) <div #slottedToFirstSlot>
    202  //      <slot #secondSlot>
    203  //        (slotted) <div #slottedToSecondSlot>
    204  //      <div #belowSlots> tabindex=1
    205  // <div #outside>
    206  // First focusable = #aboveSlots
    207  host.focus();
    208  assert_equals(shadowRoot.activeElement, aboveSlots);
    209  assert_equals(document.activeElement, host);
    210 }, "focus() on host with delegatesFocus & tabindex=0, #aboveSlots with tabindex=0 and #belowSlots with tabindex=1");
    211 
    212 test(() => {
    213  resetTabIndexAndFocus();
    214  setTabIndex([host, slottedToFirstSlot, slottedToSecondSlot, belowSlots], 0);
    215  // Structure:
    216  // <div #host> (delegatesFocus=true) tabindex=0
    217  //    #shadowRoot
    218  //      <div #aboveSlots>
    219  //      <slot #firstSlot>
    220  //        (slotted) <div #slottedToFirstSlot> tabindex=0
    221  //      <slot #secondSlot>
    222  //        (slotted) <div #slottedToSecondSlot> tabindex=0
    223  //      <div #belowSlots> tabindex=0
    224  // <div #outside>
    225  // First focusable = #slottedToFirstSlot
    226  host.focus();
    227  assert_equals(shadowRoot.activeElement, belowSlots);
    228  assert_equals(document.activeElement, host);
    229 }, "focus() on host with delegatesFocus & tabindex=0, #slottedToFirstSlot, #slottedToSecondSlot, #belowSlots  with tabindex=0");
    230 
    231 test(() => {
    232  resetTabIndexAndFocus();
    233  setTabIndex([aboveSlots, belowSlots], 0);
    234  belowSlots.focus();
    235  host.focus();
    236  assert_equals(shadowRoot.activeElement, belowSlots);
    237 }, "focus() on host with delegatesFocus and already-focused non-first shadow descendant");
    238 
    239 function createNestedHosts(innerDelegatesFocus) {
    240  // Structure:
    241  // <div> outerHost
    242  //   <input> outerLightChild
    243  //   #shadowRoot outerShadow delegatesFocus=true
    244  //     <span> innerHost
    245  //       #shadowRoot inneShadow delegatesFocus=true/false
    246  //         <input> innerShadowChild
    247  //     <input> outerShadowChild
    248  const outerHost = document.createElement('div');
    249  const outerLightChild = document.createElement('input');
    250  outerHost.appendChild(outerLightChild);
    251  const innerHost = document.createElement('span');
    252  const outerShadow = outerHost.attachShadow({mode: 'closed', delegatesFocus:true});
    253  outerShadow.appendChild(innerHost);
    254  const outerShadowChild = document.createElement('input');
    255  outerShadow.appendChild(outerShadowChild);
    256 
    257  const innerShadow = innerHost.attachShadow({mode: 'closed', delegatesFocus:innerDelegatesFocus});
    258  const innerShadowChild = document.createElement('input');
    259  innerShadow.appendChild(innerShadowChild);
    260 
    261  document.body.insertBefore(outerHost, document.body.firstChild);
    262  return {outerHost: outerHost,
    263      outerLightChild: outerLightChild,
    264      outerShadow: outerShadow,
    265      outerShadowChild: outerShadowChild,
    266      innerHost: innerHost,
    267      innerShadow: innerShadow,
    268      innerShadowChild: innerShadowChild};
    269 }
    270 
    271 test(() => {
    272  const dom = createNestedHosts(false);
    273  dom.outerHost.focus();
    274  assert_equals(document.activeElement, dom.outerHost);
    275  assert_equals(dom.outerShadow.activeElement, dom.outerShadowChild);
    276 }, 'focus() on host with delegatesFocus with another host with no delegatesFocus and a focusable child');
    277 
    278 test(() => {
    279  const dom = createNestedHosts(true);
    280  dom.outerHost.focus();
    281  assert_equals(document.activeElement, dom.outerHost);
    282  assert_equals(dom.outerShadow.activeElement, dom.innerHost);
    283  assert_equals(dom.innerShadow.activeElement, dom.innerShadowChild);
    284 }, 'focus() on host with delegatesFocus with another host with delegatesFocus and a focusable child');
    285 
    286 test(() => {
    287  // Structure:
    288  // <div> host
    289  //   #shadowRoot root delegatesFocus=true
    290  //    <slot>
    291  //      (slotted) <div>
    292  //        <input>
    293  //    <input #firstFocusable>
    294  const host = document.createElement("div");
    295  const slotted = document.createElement("div");
    296  slotted.appendChild(document.createElement("input"));
    297  host.appendChild(slotted);
    298 
    299  const root = host.attachShadow({mode: "open", delegatesFocus: true});
    300 
    301  const firstFocusable = document.createElement("input");
    302  root.innerHTML = "<slot>";
    303  root.appendChild(firstFocusable);
    304 
    305  document.body.appendChild(host);
    306 
    307  host.focus();
    308  assert_equals(document.activeElement, host);
    309  assert_equals(root.activeElement, firstFocusable);
    310 }, "focus() on host with delegatesFocus and slotted focusable children");
    311 </script>