tor-browser

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

interestfor-pseudo-classes.tentative.html (7572B)


      1 <!DOCTYPE html>
      2 <meta charset="utf-8" />
      3 <meta name="timeout" content="long">
      4 <link rel="author" href="mailto:masonf@chromium.org">
      5 <link rel="help" href="https://open-ui.org/components/interest-invokers.explainer">
      6 <script src="/resources/testharness.js"></script>
      7 <script src="/resources/testharnessreport.js"></script>
      8 <script src="/resources/testdriver.js"></script>
      9 <script src="/resources/testdriver-actions.js"></script>
     10 <script src="/resources/testdriver-vendor.js"></script>
     11 <script src="resources/invoker-utils.js"></script>
     12 <script src="/html/semantics/popovers/resources/popover-utils.js"></script>
     13 
     14 <div id=unrelated tabindex=0>Unrelated</div>
     15 <button id=invoker interestfor=target>Invoker</button>
     16 <div id=target popover>Target popover with all kinds of focusable things
     17  <button id=target_button>contained button</button>
     18  <button id=target_button_2>contained button 2</button>
     19  <a href=foo>Link</a>
     20  <dialog open>Dialog</dialog>
     21  <textarea></textarea>
     22  <input type=text>
     23  <input type=checkbox>
     24  <input type=radio>
     25  <input type=button>
     26  <input type=range>
     27  <map name="mymap">
     28    <area shape="circle" coords="75,75,75" href=foo>
     29  </map>
     30  <img usemap="#mymap" src="../../embedded-content/the-img-element/resources/green.png">
     31  <div tabindex=0>tabindex=0</div>
     32 </div>
     33 <button id=after>Button after</button>
     34 <style>
     35  button {
     36    interest-delay: 0s;
     37  }
     38 </style>
     39 <script>
     40 function checkPseudos(invoker,target,expectHasInterest,expectTargetHasInterest,msg) {
     41  msg = msg ?? 'Error';
     42  assert_equals(invoker.matches(':interest-source'),expectHasInterest,`${msg}: :interest-source mismatch`);
     43  assert_equals(target.matches(':interest-target'),expectTargetHasInterest,`${msg}: :interest-target mismatch`);
     44  assert_false(invoker.matches(':interest-target'),'invoker should never match :interest-target');
     45  assert_false(target.matches(':interest-source'),'target should never match :interest-source');
     46  assert_equals(target.matches(':popover-open'),expectTargetHasInterest,'Popover should be open if target has interest');
     47 }
     48 // Note that add_cleanup does not wait for async functions.
     49 async function do_cleanup(t) {
     50  invoker.removeAttribute('style');
     51  await focusOn(unrelated);
     52  await hoverOver(unrelated);
     53  await sendLoseInterestHotkey();
     54  target.hidePopover();
     55  await waitForRender();
     56 }
     57 
     58 promise_test(async (t) => {
     59  let hasInterest = false;
     60  target.addEventListener('interest',() => (hasInterest=true));
     61  target.addEventListener('loseinterest',() => (hasInterest=false));
     62  checkPseudos(invoker,target,false,false,'initial');
     63  assert_false(hasInterest);
     64  await hoverOver(invoker);
     65  checkPseudos(invoker,target,true,true,'hovering invoker shows full interest');
     66  assert_true(hasInterest,'event was fired');
     67  await hoverOver(target);
     68  checkPseudos(invoker,target,true,true,'hovering the target maintains interest');
     69  assert_true(hasInterest,'loseinterest event was not yet fired');
     70  await hoverOver(unrelated);
     71  checkPseudos(invoker,target,false,false,'hovering unrelated loses interest');
     72  assert_false(hasInterest,'loseinterest event was fired');
     73  await do_cleanup();
     74 },'Basic pseudo class function, with mouse hover triggering');
     75 
     76 promise_test(async (t) => {
     77  let hasInterest = false;
     78  target.addEventListener('interest',() => (hasInterest=true));
     79  target.addEventListener('loseinterest',() => (hasInterest=false));
     80  checkPseudos(invoker,target,false,false,'initial');
     81  assert_false(hasInterest);
     82  await focusOn(invoker);
     83  checkPseudos(invoker,target,true,true,'focusing invoker shows interest');
     84  assert_true(hasInterest,'event was fired');
     85  await focusOn(invoker);
     86  checkPseudos(invoker,target,true,true,'focusing back on invoker keeps full interest');
     87  assert_true(hasInterest,'loseinterest event was not yet fired');
     88  await focusOn(unrelated);
     89  checkPseudos(invoker,target,false,false,'focusing unrelated loses interest');
     90  assert_false(hasInterest,'loseinterest event was fired');
     91  await do_cleanup();
     92 },'Basic pseudo class function, with keyboard focus triggering');
     93 
     94 promise_test(async (t) => {
     95  checkPseudos(invoker,target,false,false,'initial');
     96  await focusOn(invoker);
     97  checkPseudos(invoker,target,true,true,'invoker now has full interest');
     98  await sendTab();
     99  assert_equals(document.activeElement,target_button,'focus should now be able to move within the target');
    100  await sendTab();
    101  assert_equals(document.activeElement,target_button_2,'focus should be able to move within the target');
    102  await sendShiftTab();
    103  await sendShiftTab();
    104  assert_equals(document.activeElement,invoker,'focus should go back to invoker');
    105  checkPseudos(invoker,target,true,true,'focusing back on invoker keeps full interest');
    106  await focusOn(unrelated);
    107  checkPseudos(invoker,target,false,false,'focusing unrelated loses interest');
    108  await do_cleanup();
    109 },'Contents of target popover are keyboard focusable');
    110 
    111 promise_test(async (t) => {
    112  checkPseudos(invoker,target,false,false,'initial');
    113  await focusOn(invoker);
    114  checkPseudos(invoker,target,true,true,'focusing invoker shows interest');
    115  invoker.setAttribute('style',`interest-delay: 10000s`);
    116  await sendLoseInterestHotkey();
    117  checkPseudos(invoker,target,false,false,'Hot key loses interest immediately (no delays)');
    118  await do_cleanup();
    119 },`Lose interest hotkey works`);
    120 
    121 promise_test(async (t) => {
    122  checkPseudos(invoker,target,false,false,'initial');
    123  await focusOn(invoker);
    124  checkPseudos(invoker,target,true,true,'focusing invoker shows interest');
    125  invoker.setAttribute('style',`interest-delay: 10000s`);
    126  target.hidePopover();
    127  checkPseudos(invoker,target,false,false,'closing the popover loses interest');
    128  assert_equals(document.activeElement,invoker,'focus does not move');
    129  await do_cleanup();
    130 },'Closing the target popover loses interest, without any delays (keyboard activation)');
    131 
    132 promise_test(async (t) => {
    133  checkPseudos(invoker,target,false,false,'initial');
    134  await hoverOver(invoker);
    135  checkPseudos(invoker,target,true,true,'hovering invoker shows full interest');
    136  invoker.setAttribute('style',`interest-delay: 10000s`);
    137  target.hidePopover();
    138  checkPseudos(invoker,target,false,false,'closing the popover loses interest');
    139  await do_cleanup();
    140 },'Closing the target popover loses interest, without any delays (mouse activation)');
    141 
    142 const invokerDelayMs = 100; // The CSS delay setting.
    143 const hoverWaitTime = 200; // How long to wait to cover the delay for sure.
    144 promise_test(async (t) => {
    145  invoker.setAttribute('style',`interest-delay: ${invokerDelayMs}ms`);
    146  checkPseudos(invoker,target,false,false,'initial');
    147  const token1 = await mouseOverAndRecord(t,invoker);
    148  const immediate_result = invoker.matches(':interest-source') ||
    149      target.matches(':interest-target');
    150  if (msSinceMouseOver(token1) < invokerDelayMs) {
    151    assert_false(immediate_result,'No pseudos should match before the show delay elapses');
    152  }
    153  await waitForHoverTime(hoverWaitTime);
    154  checkPseudos(invoker,target,true,true,'pseudos should match after hover delay');
    155  const token2 = await mouseOverAndRecord(t,unrelated);
    156  const immediate_result2 =  invoker.matches(':interest-source') &&
    157      target.matches(':interest-target');
    158  if (msSinceMouseOver(token2) < invokerDelayMs) {
    159    assert_true(immediate_result2,'all pseudos should still match before the hide delay elapses');
    160  }
    161  await waitForHoverTime(hoverWaitTime);
    162  checkPseudos(invoker,target,false,false,'no pseudos should match after de-hover delay');
    163  await do_cleanup();
    164 },'The pseudo classes only match after delays, once interest is shown');
    165 </script>