tor-browser

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

source-attribute-retargeting.html (4794B)


      1 <!DOCTYPE html>
      2 <link rel=author href="mailto:jarhar@chromium.org">
      3 <script src="/resources/testharness.js"></script>
      4 <script src="/resources/testharnessreport.js"></script>
      5 
      6 <div id=popover popover=auto>popover</div>
      7 <div id=host>
      8  <template shadowrootmode=open>
      9    <button id=shadow-button command=show-popover>button in shadowroot</button>
     10  </template>
     11 </div>
     12 
     13 <script>
     14 promise_test(async () => {
     15  const popover = document.getElementById('popover');
     16  const host = document.getElementById('host');
     17  const shadowButton = host.shadowRoot.getElementById('shadow-button');
     18  shadowButton.commandForElement = popover;
     19 
     20  const eventNames = ['beforetoggle', 'toggle', 'command'];
     21  const eventNameToEvent = {};
     22  const eventNameToCaptureSource = {};
     23  const eventNameToBubbleSource = {};
     24 
     25  for (const eventName of eventNames) {
     26    popover.addEventListener(eventName, event => {
     27      eventNameToEvent[eventName] = event;
     28      eventNameToBubbleSource[eventName] = event.source;
     29    });
     30    popover.addEventListener(eventName, event => {
     31      eventNameToCaptureSource[eventName] = event.source;
     32    }, {capture: true});
     33  }
     34 
     35  shadowButton.click();
     36  await new Promise(requestAnimationFrame);
     37  await new Promise(requestAnimationFrame);
     38 
     39  for (const eventName of eventNames) {
     40    const event = eventNameToEvent[eventName];
     41    assert_true(!!event, `A ${eventName} event should have been fired.`);
     42    assert_equals(eventNameToCaptureSource[eventName], host,
     43      `${eventName}.source during capture.`);
     44    assert_equals(eventNameToBubbleSource[eventName], host,
     45      `${eventName}.source during bubble.`);
     46    assert_not_equals(event.source, shadowButton,
     47      `${eventName}.source shouldn't leak the shadow button.`);
     48    assert_equals(event.source, host,
     49      `${eventName}.source after dispatch.`);
     50  }
     51 }, 'CommandEvent.source and ToggleEvent.source should be retargeted during and after event dispatch.');
     52 </script>
     53 
     54 <div id=host2>
     55  <template shadowrootmode=open>
     56    <div id=source>source</div>
     57    <div id=innerhost>
     58      <template shadowrootmode=open>
     59        <div id=target>target</div>
     60      </template>
     61    </div>
     62  </template>
     63 </div>
     64 
     65 <script>
     66 // This does not test ToggleEvent because ToggleEventInit does not have a source attribute.
     67 promise_test(async () => {
     68  const host2 = document.getElementById('host2');
     69  const source = host2.shadowRoot.getElementById('source');
     70  const innerhost = host2.shadowRoot.getElementById('innerhost');
     71  const target = innerhost.shadowRoot.getElementById('target');
     72 
     73  const targets = [host2, innerhost, target];
     74  const targetToEvent = new Map();
     75  const targetToCaptureSource = new Map();
     76  const targetToBubbleSource = new Map();
     77 
     78  for (const target of targets) {
     79    target.addEventListener('command', event => {
     80      targetToEvent.set(target, event);
     81      targetToBubbleSource.set(target, event.source);
     82    });
     83    target.addEventListener('command', event => {
     84      targetToCaptureSource.set(target, event.source);
     85    }, {capture: true});
     86  }
     87 
     88  const commandEvent = new CommandEvent('command', {composed: true, source});
     89  target.dispatchEvent(commandEvent);
     90 
     91  for (const target of targets) {
     92    const expectedSource = target == host2 ? host2 : source;
     93    assert_true(targetToEvent.has(target),
     94      `${target.id}: event should have fired.`);
     95    assert_equals(targetToCaptureSource.get(target), expectedSource,
     96      `${target.id}: event.source at capture.`);
     97    assert_equals(targetToBubbleSource.get(target), expectedSource,
     98      `${target.id}: event.source at bubble.`);
     99    assert_equals(targetToEvent.get(target).source, host2,
    100      `${target.id}: event.source after dispatch.`);
    101  }
    102 }, 'CommandEvent.source should be retargeted when manually dispatched with composed set to true.');
    103 </script>
    104 
    105 <div id=popover3 popover=auto>popover 3</div>
    106 <button id=button3 commandfor=popover3 command=show-popover>show popover 3</button>
    107 
    108 <script>
    109 promise_test(async () => {
    110  const button = document.getElementById('button3');
    111  const popover = document.getElementById('popover3');
    112 
    113  const eventNames = ['beforetoggle', 'toggle', 'command'];
    114  const eventNameToEvent = {};
    115  for (const eventName of eventNames) {
    116    popover.addEventListener(eventName, event => {
    117      eventNameToEvent[eventName] = event;
    118    });
    119  }
    120 
    121  button.click();
    122  await new Promise(requestAnimationFrame);
    123  await new Promise(requestAnimationFrame);
    124 
    125  for (const eventName of eventNames) {
    126    const event = eventNameToEvent[eventName];
    127    assert_true(!!event, `${eventName} should have been fired.`);
    128    assert_equals(event.source, button,
    129      `${eventName}.source should be the invoker button after dispatch.`);
    130  }
    131 }, 'CommandEvent.source and ToggleEvent.source should not be set to null after dispatch without ShadowDOM.');
    132 </script>