File: source-attribute-retargeting.html

package info (click to toggle)
firefox 144.0-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 4,637,504 kB
  • sloc: cpp: 7,576,692; javascript: 6,430,831; ansic: 3,748,119; python: 1,398,978; xml: 628,810; asm: 438,679; java: 186,194; sh: 63,212; makefile: 19,159; objc: 13,086; perl: 12,986; yacc: 4,583; cs: 3,846; pascal: 3,448; lex: 1,720; ruby: 1,003; exp: 762; php: 436; lisp: 258; awk: 247; sql: 66; sed: 53; csh: 10
file content (132 lines) | stat: -rw-r--r-- 4,794 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
<!DOCTYPE html>
<link rel=author href="mailto:jarhar@chromium.org">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>

<div id=popover popover=auto>popover</div>
<div id=host>
  <template shadowrootmode=open>
    <button id=shadow-button command=show-popover>button in shadowroot</button>
  </template>
</div>

<script>
promise_test(async () => {
  const popover = document.getElementById('popover');
  const host = document.getElementById('host');
  const shadowButton = host.shadowRoot.getElementById('shadow-button');
  shadowButton.commandForElement = popover;

  const eventNames = ['beforetoggle', 'toggle', 'command'];
  const eventNameToEvent = {};
  const eventNameToCaptureSource = {};
  const eventNameToBubbleSource = {};

  for (const eventName of eventNames) {
    popover.addEventListener(eventName, event => {
      eventNameToEvent[eventName] = event;
      eventNameToBubbleSource[eventName] = event.source;
    });
    popover.addEventListener(eventName, event => {
      eventNameToCaptureSource[eventName] = event.source;
    }, {capture: true});
  }

  shadowButton.click();
  await new Promise(requestAnimationFrame);
  await new Promise(requestAnimationFrame);

  for (const eventName of eventNames) {
    const event = eventNameToEvent[eventName];
    assert_true(!!event, `A ${eventName} event should have been fired.`);
    assert_equals(eventNameToCaptureSource[eventName], host,
      `${eventName}.source during capture.`);
    assert_equals(eventNameToBubbleSource[eventName], host,
      `${eventName}.source during bubble.`);
    assert_not_equals(event.source, shadowButton,
      `${eventName}.source shouldn't leak the shadow button.`);
    assert_equals(event.source, host,
      `${eventName}.source after dispatch.`);
  }
}, 'CommandEvent.source and ToggleEvent.source should be retargeted during and after event dispatch.');
</script>

<div id=host2>
  <template shadowrootmode=open>
    <div id=source>source</div>
    <div id=innerhost>
      <template shadowrootmode=open>
        <div id=target>target</div>
      </template>
    </div>
  </template>
</div>

<script>
// This does not test ToggleEvent because ToggleEventInit does not have a source attribute.
promise_test(async () => {
  const host2 = document.getElementById('host2');
  const source = host2.shadowRoot.getElementById('source');
  const innerhost = host2.shadowRoot.getElementById('innerhost');
  const target = innerhost.shadowRoot.getElementById('target');

  const targets = [host2, innerhost, target];
  const targetToEvent = new Map();
  const targetToCaptureSource = new Map();
  const targetToBubbleSource = new Map();

  for (const target of targets) {
    target.addEventListener('command', event => {
      targetToEvent.set(target, event);
      targetToBubbleSource.set(target, event.source);
    });
    target.addEventListener('command', event => {
      targetToCaptureSource.set(target, event.source);
    }, {capture: true});
  }

  const commandEvent = new CommandEvent('command', {composed: true, source});
  target.dispatchEvent(commandEvent);

  for (const target of targets) {
    const expectedSource = target == host2 ? host2 : source;
    assert_true(targetToEvent.has(target),
      `${target.id}: event should have fired.`);
    assert_equals(targetToCaptureSource.get(target), expectedSource,
      `${target.id}: event.source at capture.`);
    assert_equals(targetToBubbleSource.get(target), expectedSource,
      `${target.id}: event.source at bubble.`);
    assert_equals(targetToEvent.get(target).source, host2,
      `${target.id}: event.source after dispatch.`);
  }
}, 'CommandEvent.source should be retargeted when manually dispatched with composed set to true.');
</script>

<div id=popover3 popover=auto>popover 3</div>
<button id=button3 commandfor=popover3 command=show-popover>show popover 3</button>

<script>
promise_test(async () => {
  const button = document.getElementById('button3');
  const popover = document.getElementById('popover3');

  const eventNames = ['beforetoggle', 'toggle', 'command'];
  const eventNameToEvent = {};
  for (const eventName of eventNames) {
    popover.addEventListener(eventName, event => {
      eventNameToEvent[eventName] = event;
    });
  }

  button.click();
  await new Promise(requestAnimationFrame);
  await new Promise(requestAnimationFrame);

  for (const eventName of eventNames) {
    const event = eventNameToEvent[eventName];
    assert_true(!!event, `${eventName} should have been fired.`);
    assert_equals(event.source, button,
      `${eventName}.source should be the invoker button after dispatch.`);
  }
}, 'CommandEvent.source and ToggleEvent.source should not be set to null after dispatch without ShadowDOM.');
</script>