tor-browser

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

focus-autofocus.html (9407B)


      1 <!DOCTYPE html>
      2 <html>
      3 <head>
      4 <meta name="author" title="Sean Feng" href="mailto:sefeng@mozilla.com">
      5 <meta name="assert" content="Elements with autofocus should have high precedence over other elements for delegates focus">
      6 <link rel="help" href="https://github.com/whatwg/html/pull/6990">
      7 <script src="/resources/testharness.js"></script>
      8 <script src="/resources/testharnessreport.js"></script>
      9 <script src="/resources/testdriver.js"></script>
     10 <script src="/resources/testdriver-vendor.js"></script>
     11 <script src="resources/shadow-utils.js"></script>
     12 </head>
     13 
     14 <body>
     15  <script>
     16  function createShadowDOMTree() {
     17    // <div #host> (delegatesFocus = true)
     18    //   #shadowRoot
     19    //     <div #firstOuterDiv>
     20    //     <div #innertHost>
     21    //       #shadowRoot
     22    //         <div #firstInnerDiv>
     23    //         <div #secondInnerDiv>
     24    //     <div #secondOuterDiv>
     25    const host = document.createElement("div");
     26    host.setAttribute("id", "host");
     27    const outerRoot = host.attachShadow({mode: "open", delegatesFocus: true});
     28 
     29    const firstOuterDiv = document.createElement("div");
     30 
     31    const innerHost = document.createElement("div");
     32    const innerRoot = innerHost.attachShadow({mode: "open"});
     33    const firstInnerDiv = document.createElement("div");
     34    const secondInnerDiv = document.createElement("div");
     35    innerRoot.appendChild(firstInnerDiv);
     36    innerRoot.appendChild(secondInnerDiv);
     37 
     38    const secondOuterDiv = document.createElement("div");
     39 
     40    outerRoot.appendChild(firstOuterDiv);
     41    outerRoot.appendChild(innerHost);
     42    outerRoot.appendChild(secondOuterDiv);
     43    document.body.appendChild(host);
     44    return [
     45      host,
     46      outerRoot,
     47      firstOuterDiv,
     48      secondOuterDiv,
     49      innerHost,
     50      innerRoot,
     51      firstInnerDiv,
     52      secondInnerDiv
     53    ]
     54  }
     55 
     56  function resetShadowDOMTree() {
     57    const host = document.getElementById("host");
     58    if (host) {
     59      host.remove();
     60    }
     61    return createShadowDOMTree();
     62  }
     63 
     64  function resetTabIndexAndFocus(
     65    firstOuterDiv,
     66    secondOuterDiv,
     67    firstInnerDiv,
     68    secondInnerDiv,
     69    outerRoot,
     70    innerRoot
     71  ) {
     72    firstOuterDiv.removeAttribute("tabindex");
     73    firstOuterDiv.removeAttribute("autofocus");
     74 
     75    secondOuterDiv.removeAttribute("tabindex");
     76    secondOuterDiv.removeAttribute("autofocus");
     77 
     78    firstInnerDiv.removeAttribute("tabindex");
     79    firstInnerDiv.removeAttribute("autofocus");
     80 
     81    secondInnerDiv.removeAttribute("tabindex");
     82    secondInnerDiv.removeAttribute("autofocus");
     83 
     84    resetFocus(document);
     85    resetFocus(outerRoot);
     86    resetFocus(innerRoot);
     87  }
     88 
     89  function setAllTabIndexTo(
     90    firstOuterDiv,
     91    secondOuterDiv,
     92    firstInnerDiv,
     93    secondInnerDiv,
     94    tabIndex
     95  ) {
     96    firstOuterDiv.tabIndex = tabIndex;
     97    secondOuterDiv.tabIndex = tabIndex;
     98    firstInnerDiv.tabIndex = tabIndex;
     99    secondInnerDiv.tabIndex = tabIndex;
    100  }
    101 
    102  test(function() {
    103    const [
    104      host,
    105      outerRoot,
    106      firstOuterDiv,
    107      secondOuterDiv,
    108      innerHost,
    109      innerRoot,
    110      firstInnerDiv,
    111      secondInnerDiv
    112    ] = resetShadowDOMTree();
    113 
    114    resetTabIndexAndFocus(
    115      firstOuterDiv,
    116      secondOuterDiv,
    117      firstInnerDiv,
    118      secondInnerDiv,
    119      outerRoot,
    120      innerRoot
    121    );
    122 
    123    setAllTabIndexTo(
    124      firstOuterDiv,
    125      secondOuterDiv,
    126      firstInnerDiv,
    127      secondInnerDiv,
    128      0
    129    );
    130 
    131    // <div #host> (delegatesFocus = true)
    132    //   #shadowRoot
    133    //     <div tabIndex=0 #firstOuterDiv>
    134    //     <div #innertHost>
    135    //       #shadowRoot
    136    //         <div tabIndex=0 #firstInnerDiv>
    137    //         <div tabIndex=0 #secondInnerDiv>
    138    //     <div tabIndex=0 autofocus #secondOuterDiv>
    139    secondOuterDiv.autofocus = true;
    140    secondOuterDiv.setAttribute("autofocus", true);
    141 
    142    host.focus();
    143 
    144    assert_equals(document.activeElement, host);
    145    assert_equals(outerRoot.activeElement, secondOuterDiv);
    146  }, "The second input should be focused since it has autofocus");
    147 
    148  test(function() {
    149    const [
    150      host,
    151      outerRoot,
    152      firstOuterDiv,
    153      secondOuterDiv,
    154      innerHost,
    155      innerRoot,
    156      firstInnerDiv,
    157      secondInnerDiv
    158    ] = resetShadowDOMTree();
    159 
    160    resetTabIndexAndFocus(
    161      firstOuterDiv,
    162      secondOuterDiv,
    163      firstInnerDiv,
    164      secondInnerDiv,
    165      outerRoot,
    166      innerRoot
    167    );
    168 
    169    // <div #host> (delegatesFocus = true)
    170    //   #shadowRoot
    171    //     <div #firstOuterDiv>
    172    //     <div #innertHost>
    173    //       #shadowRoot
    174    //         <div tabIndex=0 #firstInnerDiv>
    175    //         <div tabIndex=0 autofocus #secondInnerDiv>
    176    //     <div #secondOuterDiv>
    177    firstInnerDiv.tabIndex = 0;
    178    secondInnerDiv.tabIndex = 0;
    179    secondInnerDiv.setAttribute("autofocus", true);
    180 
    181    host.focus();
    182    assert_equals(document.activeElement, document.body);
    183    assert_equals(outerRoot.activeElement, null);
    184  }, "Focus should not be delegated to the autofocus element because the inner host doesn't have delegates focus");
    185 
    186  test(function() {
    187    const [
    188      host,
    189      outerRoot,
    190      firstOuterDiv,
    191      secondOuterDiv,
    192      innerHost,
    193      innerRoot,
    194      firstInnerDiv,
    195      secondInnerDiv
    196    ] = resetShadowDOMTree();
    197 
    198    resetTabIndexAndFocus(
    199      firstOuterDiv,
    200      secondOuterDiv,
    201      firstInnerDiv,
    202      secondInnerDiv,
    203      outerRoot,
    204      innerRoot
    205    );
    206 
    207    const newInnerHost = document.createElement("div");
    208    const newInnerRoot = newInnerHost.attachShadow({mode: "open", delegatesFocus: true});
    209    const newFirstInnerDiv = document.createElement("div");
    210    const newSecondInnerDiv = document.createElement("div");
    211    newFirstInnerDiv.setAttribute("tabIndex", 0);
    212    newSecondInnerDiv.setAttribute("tabIndex", 0);
    213 
    214    newSecondInnerDiv.setAttribute("autofocus", true);
    215    newInnerRoot.appendChild(newFirstInnerDiv);
    216    newInnerRoot.appendChild(newSecondInnerDiv);
    217 
    218    // <div #host> (delegatesFocus = true)
    219    //   #shadowRoot
    220    //     <div #firstOuterDiv>
    221    //     <div #innertHost> (delegatesFocus = true)
    222    //       #shadowRoot
    223    //         <div tabIndex=0 #newFirstInnerDiv>
    224    //         <div tabIndex=0 autofocus #newSecondInnerDiv>
    225    //     <div #secondOuterDiv>
    226    outerRoot.replaceChild(newInnerHost, innerHost);
    227 
    228    host.focus();
    229 
    230    assert_equals(document.activeElement, host);
    231    assert_equals(outerRoot.activeElement, newInnerHost);
    232    assert_equals(newInnerRoot.activeElement, newSecondInnerDiv);
    233  }, "Focus should be delegated to the autofocus element when the inner host has delegates focus");
    234 
    235  test(function() {
    236    const [
    237      host,
    238      outerRoot,
    239      firstOuterDiv,
    240      secondOuterDiv,
    241      innerHost,
    242      innerRoot,
    243      firstInnerDiv,
    244      secondInnerDiv
    245    ] = resetShadowDOMTree();
    246 
    247    resetTabIndexAndFocus(
    248      firstOuterDiv,
    249      secondOuterDiv,
    250      firstInnerDiv,
    251      secondInnerDiv,
    252      outerRoot,
    253      innerRoot
    254    );
    255 
    256    // <div #host> (delegatesFocus = true)
    257    //   #shadowRoot
    258    //     <slot>
    259    //       (slotted) <div autofocus tabIndex=0 #slottedAutofocus></div>
    260    //     <div tabIndex=0 #firstOuterDiv>
    261    //     <div #innertHost>
    262    //       #shadowRoot
    263    //         <div tabIndex=0 #firstInnerDiv>
    264    //         <div tabIndex=0 autofocus #secondInnerDiv>
    265    //     <div #secondOuterDiv>
    266 
    267    const slottedAutofocus = document.createElement("div");
    268    slottedAutofocus.tabIndex = 0;
    269    slottedAutofocus.setAttribute("autofocus", true);
    270    host.appendChild(slottedAutofocus);
    271 
    272    const slot = document.createElement("slot");
    273    outerRoot.insertBefore(slot, firstOuterDiv);
    274 
    275    firstOuterDiv.tabIndex = 0;
    276 
    277    host.focus();
    278    assert_equals(document.activeElement, host);
    279    assert_equals(outerRoot.activeElement, firstOuterDiv);
    280  }, "Focus should not be delegated to the slotted elements");
    281 
    282  test(function() {
    283    const [
    284      host,
    285      outerRoot,
    286      firstOuterDiv,
    287      secondOuterDiv,
    288      innerHost,
    289      innerRoot,
    290      firstInnerDiv,
    291      secondInnerDiv
    292    ] = resetShadowDOMTree();
    293 
    294    resetTabIndexAndFocus(
    295      firstOuterDiv,
    296      secondOuterDiv,
    297      firstInnerDiv,
    298      secondInnerDiv,
    299      outerRoot,
    300      innerRoot
    301    );
    302 
    303    // <div #host> (delegatesFocus = true)
    304    //   #shadowRoot
    305    //     <div #firstOuterDiv>
    306    //       <div tabIndex=0 #firstNestedDiv>
    307    //         <div tabIndex=0 #secondNestedDiv>
    308    //           <div tabIndex=0 autofocus #thirdNestedDiv>
    309    //     <div #innertHost>
    310    //       #shadowRoot
    311    //         <div #firstInnerDiv>
    312    //         <div #secondInnerDiv>
    313    //     <div autofocus tabIndex=0 #secondOuterDiv>
    314 
    315    secondInnerDiv.tabIndex = 0;
    316    secondInnerDiv.setAttribute("autofocus", true);
    317 
    318    const firstNestedDiv = document.createElement("div");
    319    const secondNestedDiv = document.createElement("div");
    320    const thirdNestedDiv = document.createElement("div");
    321 
    322    firstNestedDiv.tabIndex = 0;
    323    secondNestedDiv.tabIndex = 0;
    324    thirdNestedDiv.tabIndex = 0;
    325    thirdNestedDiv.setAttribute("autofocus", true);
    326 
    327    firstOuterDiv.appendChild(firstNestedDiv);
    328    firstNestedDiv.appendChild(secondNestedDiv);
    329    secondNestedDiv.appendChild(thirdNestedDiv);
    330 
    331    host.focus();
    332 
    333    assert_equals(document.activeElement, host);
    334    assert_equals(outerRoot.activeElement, thirdNestedDiv);
    335  }, "Focus should be delegated to the nested div which has autofocus based on the tree order");
    336  </script>
    337 </body>
    338 </html>