tor-browser

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

interestfor-invoker-descendants.tentative.html (9845B)


      1 <!DOCTYPE html>
      2 <meta charset="utf-8" />
      3 <link rel="author" href="mailto:masonf@chromium.org">
      4 <link rel="help" href="https://open-ui.org/components/interest-invokers.explainer/" />
      5 <script src="/resources/testharness.js"></script>
      6 <script src="/resources/testharnessreport.js"></script>
      7 <script src="/resources/testdriver.js"></script>
      8 <script src="/resources/testdriver-actions.js"></script>
      9 <script src="/resources/testdriver-vendor.js"></script>
     10 <script src="resources/invoker-utils.js"></script>
     11 
     12 <button id=invoker interestfor=target>
     13  Button content
     14  <span id=inner-span tabindex=0>Inner content</span>
     15 </button>
     16 <div id=target>Target</div>
     17 <button id=otherbutton>Other button</button>
     18 <style>
     19  [interestfor] { interest-delay: 0s; }
     20  :interest-source { background-color: lightgreen;}
     21  :interest-target { background-color: lightblue;}
     22 </style>
     23 
     24 <script>
     25 const invoker = document.getElementById('invoker');
     26 const innerSpan = document.getElementById('inner-span');
     27 const target = document.getElementById('target');
     28 const otherbutton = document.getElementById('otherbutton');
     29 
     30 async function showInterest(el, method) {
     31  if (method === 'focus') {
     32    await focusOn(el);
     33  } else {
     34    assert_equals(method,'hover');
     35    await hoverOver(el);
     36  }
     37 }
     38 
     39 ['focus','hover'].forEach(method => {
     40  promise_test(async function (t) {
     41    t.add_cleanup(() => showInterest(otherbutton, method));
     42    const signal = t.get_signal();
     43    let interestCount = 0;
     44    let loseInterestCount = 0;
     45    target.addEventListener('interest',() => (++interestCount),{signal});
     46    target.addEventListener('loseinterest',() => (++loseInterestCount),{signal});
     47    await showInterest(invoker, method);
     48    assert_true(invoker.matches(':interest-source'),'focusing invoker should show interest');
     49    assert_equals(interestCount,1,'One interest event');
     50    interestCount = 0;
     51    assert_equals(loseInterestCount,0,'No loseinterest events');
     52    await showInterest(innerSpan, method);
     53    assert_true(invoker.matches(':interest-source'),'focusing inner span should keep interest');
     54    assert_equals(interestCount,0,'No extra interest events');
     55    assert_equals(loseInterestCount,0,'No loseinterest events');
     56    await showInterest(invoker, method);
     57    assert_true(invoker.matches(':interest-source'),'focusing back to outer button should keep interest');
     58    assert_equals(interestCount,0,'No extra interest events');
     59    assert_equals(loseInterestCount,0,'No loseinterest events');
     60    await showInterest(otherbutton, method);
     61    assert_false(invoker.matches(':interest-source'),'focusing outside should lose interest');
     62    assert_equals(interestCount,0,'No extra interest events');
     63    assert_equals(loseInterestCount,1,'Finally got loseinterest event');
     64  },`Moving focus within invoker, ${method}`);
     65 });
     66 </script>
     67 
     68 <a id=outer href="#" interestfor="middle">Outer</a>
     69 <div id="middle" popover>
     70  <a id="middle-link" href="#" interestfor="inner">Middle</a>
     71 </div>
     72 <div id="inner" popover>Inner <button id="inner-button">btn</button></div>
     73 
     74 <script>
     75 const outer = document.getElementById('outer');
     76 const middle = document.getElementById('middle');
     77 const middleLink = document.getElementById('middle-link');
     78 const inner = document.getElementById('inner');
     79 const innerButton = document.getElementById('inner-button');
     80 
     81 ['focus','hover'].forEach(method => {
     82  promise_test(async function (t) {
     83    t.add_cleanup(() => showInterest(otherbutton, method));
     84    assert_false(middle.matches(':popover-open'),'middle starts closed');
     85    await showInterest(outer, method);
     86    assert_true(outer.matches(':interest-source'),'focusing outer should show interest');
     87    assert_true(middle.matches(':popover-open'),'outer popover open');
     88 
     89    await showInterest(middleLink, method);
     90    assert_true(middleLink.matches(':interest-source'),'focusing middle should show interest');
     91    assert_true(outer.matches(':interest-source'),'outer keeps interest');
     92    assert_true(middle.matches(':popover-open'),'middle popover stays open');
     93    assert_true(inner.matches(':popover-open'),'inner popover opens');
     94 
     95    await showInterest(innerButton, method);
     96    assert_true(outer.matches(':interest-source'),'outer keeps interest');
     97    assert_true(middleLink.matches(':interest-source'),'middle keeps interest');
     98    assert_true(middle.matches(':popover-open'),'middle popover stays open');
     99    assert_true(inner.matches(':popover-open'),'inner popover stays open');
    100  },`Nested invokers, ${method}`);
    101 });
    102 </script>
    103 
    104 <a id=outer2-first href="#" interestfor="middle2-inner">Outer first</a>
    105 <a id=outer2-second href="#" interestfor="middle2-outer">Outer second</a>
    106 <div id="middle2-outer">Middle outer
    107  <div id="middle2-inner">Middle inner
    108    <a id="middle2-link" href="#" interestfor="inner2">Middle</a>
    109  </div>
    110 </div>
    111 <div id="inner2">Inner <button id="inner2-button">btn</button></div>
    112 
    113 <script>
    114 const outer2First = document.getElementById('outer2-first');
    115 const outer2Second = document.getElementById('outer2-second');
    116 const middle2Outer = document.getElementById('middle2-outer');
    117 const middle2Inner = document.getElementById('middle2-inner');
    118 const middle2Link = document.getElementById('middle2-link');
    119 const inner2 = document.getElementById('inner2');
    120 const inner2Button = document.getElementById('inner2-button');
    121 
    122 ['focus','hover'].forEach(method => {
    123  promise_test(async function (t) {
    124    t.add_cleanup(() => showInterest(otherbutton, method));
    125    const hideDelayMs = 500; // Long enough to focus a few things without elapsing
    126    outer2First.style.interestDelayEnd = `${hideDelayMs}ms`;
    127 
    128    const hoverStart = performance.now();
    129    await showInterest(outer2First, method);
    130    assert_true(outer2First.matches(':interest-source'),'should show interest');
    131    assert_false(outer2Second.matches(':interest-source'),'no interest yet in second target');
    132    await showInterest(outer2Second, method);
    133    assert_true(outer2Second.matches(':interest-source'),'outer2Second should now have interest');
    134    await showInterest(middle2Link, method);
    135    let firstHasInterest = outer2First.matches(':interest-source');
    136    if (performance.now() - hoverStart >= hideDelayMs) {
    137      return; // Test is running too slowly
    138    }
    139    assert_true(firstHasInterest,'outer2First should still have interest (delay)');
    140    assert_true(inner2.matches(':interest-target'),'inner2 should be an interest target');
    141    assert_true(middle2Outer.matches(':interest-target'),'middle2Outer should still be an interest target');
    142    assert_true(outer2Second.matches(':interest-source'),'outer2Second should still have interest');
    143 
    144    // Focusing the inner target should keep both outer invokers alive.
    145    await showInterest(inner2Button, method);
    146    assert_true(middle2Outer.matches(':interest-target'),'middle2Outer should still be an interest target (after moving to inner button)');
    147    assert_true(outer2Second.matches(':interest-source'),'outer2Second should still have interest (after moving to inner button)');
    148    assert_true(outer2First.matches(':interest-source'),'outer2First should still have interest');
    149 
    150    // Now let the time elapse and make sure things are still good.
    151    const elapsedMs = performance.now() - hoverStart;
    152    await new Promise(resolve => step_timeout(resolve,hideDelayMs - elapsedMs + 10));
    153    assert_true(inner2.matches(':interest-target'),'inner2 should still be an interest target');
    154    assert_true(middle2Outer.matches(':interest-target'),'middle2Outer should still be an interest target');
    155    assert_true(outer2Second.matches(':interest-source'),'outer2Second should still have interest');
    156    assert_true(outer2First.matches(':interest-source'),'outer2First should still have interest');
    157    assert_true(middle2Inner.matches(':interest-target'),'middle2Inner should still be an interest target');
    158  },`Nested invokers with intermediate interest target, ${method}`);
    159 });
    160 </script>
    161 
    162 
    163 <a id=outer3 href="#" interestfor="middle3-inner">Outer</a>
    164 <div id="middle3-outer">Middle <button id=middle3-button>outer</button>
    165  <div id="middle3-inner">Middle inner
    166    <a id="middle3-link" href="#" interestfor="middle3-outer">Middle</a>
    167  </div>
    168 </div>
    169 
    170 <script>
    171 const outer3 = document.getElementById('outer3');
    172 const middle3Outer = document.getElementById('middle3-outer');
    173 const middle3Inner = document.getElementById('middle3-inner');
    174 const middle3Link = document.getElementById('middle3-link');
    175 const middle3Button = document.getElementById('middle3-button');
    176 
    177 ['focus','hover'].forEach(method => {
    178  promise_test(async function (t) {
    179    t.add_cleanup(() => showInterest(otherbutton, method));
    180    await showInterest(outer3, method);
    181    assert_true(outer3.matches(':interest-source'),'should show interest');
    182    assert_true(middle3Inner.matches(':interest-target'),'middle3Inner should now be an interest target');
    183    await showInterest(middle3Link, method);
    184    assert_true(middle3Link.matches(':interest-source'),'middle3Link should now have interest');
    185    assert_true(middle3Outer.matches(':interest-target'),'middle3Outer should now be an interest target');
    186    assert_true(outer3.matches(':interest-source'),'outer3 should still have interest');
    187    assert_true(middle3Inner.matches(':interest-target'),'middle3Inner should still be an interest target');
    188    await showInterest(middle3Button, method);
    189    assert_true(middle3Link.matches(':interest-source'),'middle3Link should now have interest (on outer button)');
    190    assert_true(middle3Outer.matches(':interest-target'),'middle3Outer should now be an interest target (on outer button)');
    191    assert_true(outer3.matches(':interest-source'),'outer3 no longer has interest (on outer button)');
    192    assert_true(middle3Inner.matches(':interest-target'),'middle3Inner is no longer an interest target (on outer button)');
    193  },`Nested invokers with circular dependencies, ${method}`);
    194 });
    195 </script>