Skip to content
This repository was archived by the owner on Mar 19, 2021. It is now read-only.

Commit 9d63cfd

Browse files
hayatoitochromium-wpt-export-bot
authored andcommitted
Call capture event listeners in capturing phase at shadow hosts
Chromestatus entry is here: https://www.chromestatus.com/feature/5636327009681408 Per the discussion of whatwg/dom#685, Blink will try to align the event dispatch behavior with other browsers; Call capture event listeners in capturing phase at shadow hosts. So far, Blink and WebKit call capture event listeners in *bubbling* phase, instead of *capturing* phase, at shadow hosts. Other browsers: - Safari: Will try to change the behavior in the next Safari Technical Preview. - Firefox: Already implemented the new behavior - Edge: Strong public support for the new behavior. This change is guard by CallCaptureListenersAtCapturePhaseAtShadowHosts flag, which is disabled at this moment, to confirm that this CL doesn't cause any behavior change when the flag is disabled. This CL adds a wpt for new behavior, which is now marked as [Failure] in Blink. After this CL lands, I will flip the flag in a follow-up CL, with rebasing a very few existing tests. BUG=883650 Change-Id: I29938840aed4f3430d8b749cd4843176b8668b5d Reviewed-on: https://chromium-review.googlesource.com/1212255 Commit-Queue: Hayato Ito <[email protected]> Reviewed-by: Kent Tamura <[email protected]> Cr-Commit-Position: refs/heads/master@{#591939}
1 parent 8f8ff0e commit 9d63cfd

File tree

2 files changed

+70
-9
lines changed

2 files changed

+70
-9
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<!DOCTYPE html>
2+
<title>Shadow DOM: event dispatch order for capture and non-capture listerns at a shadow host</title>
3+
<meta name="author" title="Hayato Ito" href="mailto:[email protected]">
4+
<link rel="help" href="https://github.com/whatwg/dom/issues/685">
5+
<link rel="help" href="https://github.com/whatwg/dom/pull/686">
6+
<script src="/resources/testharness.js"></script>
7+
<script src="/resources/testharnessreport.js"></script>
8+
<script src="resources/shadow-dom.js"></script>
9+
<div id=host>
10+
<template id=shadowroot data-mode=open>
11+
<div id=target></div>
12+
</template>
13+
</div>
14+
<script>
15+
test(() => {
16+
let nodes = createTestTree(host);
17+
let log = dispatchEventWithLog(nodes, nodes.target,
18+
new Event('my-event', { bubbles: true, composed: true }),
19+
{ capture: true });
20+
let path = ['target', 'shadowroot', 'host'];
21+
assert_event_path_equals(log,
22+
[['host', 'host', null, path, 'capture'],
23+
['shadowroot', 'target', null, path, 'capture'],
24+
['target', 'target', null, path, 'capture'],
25+
['target', 'target', null, path, 'non-capture'],
26+
['shadowroot', 'target', null, path, 'non-capture'],
27+
['host', 'host', null, path, 'non-capture'],
28+
]);
29+
}, 'Event dispatch order: capture listerns should be called in capturing phase at a shadow host');
30+
</script>

shadow-dom/resources/shadow-dom.js

+40-9
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,9 @@ function createTestTree(node) {
5353
return ids;
5454
}
5555

56-
function dispatchEventWithLog(nodes, target, event) {
56+
// TODO: Refactor this so that only interested results are recorded.
57+
// Callers of this function would not be interested in every results.
58+
function dispatchEventWithLog(nodes, target, event, options) {
5759

5860
function labelFor(e) {
5961
return e.id || e.tagName;
@@ -70,15 +72,40 @@ function dispatchEventWithLog(nodes, target, event) {
7072
if (!id)
7173
continue;
7274
attachedNodes.push(node);
73-
node.addEventListener(event.type, (e) => {
75+
if (options && options.capture) {
76+
// Record [currentTarget, target, relatedTarget, composedPath(), 'capture' | 'non-capture']
77+
// TODO: Support registering listeners in different orders.
78+
// e.g. Register a non-capture listener at first, then register a capture listener.
79+
node.addEventListener(event.type, (e) => {
80+
log.push([id,
81+
labelFor(e.target),
82+
e.relatedTarget ? labelFor(e.relatedTarget) : null,
83+
e.composedPath().map((n) => {
84+
return labelFor(n);
85+
}),
86+
'capture']);
87+
}, true);
88+
node.addEventListener(event.type, (e) => {
89+
log.push([id,
90+
labelFor(e.target),
91+
e.relatedTarget ? labelFor(e.relatedTarget) : null,
92+
e.composedPath().map((n) => {
93+
return labelFor(n);
94+
}),
95+
'non-capture']);
96+
});
97+
} else {
7498
// Record [currentTarget, target, relatedTarget, composedPath()]
75-
log.push([id,
76-
labelFor(e.target),
77-
e.relatedTarget ? labelFor(e.relatedTarget) : null,
78-
e.composedPath().map((n) => {
79-
return labelFor(n);
80-
})]);
81-
});
99+
node.addEventListener(event.type, (e) => {
100+
log.push([id,
101+
labelFor(e.target),
102+
e.relatedTarget ? labelFor(e.relatedTarget) : null,
103+
e.composedPath().map((n) => {
104+
return labelFor(n);
105+
})]
106+
);
107+
});
108+
}
82109
}
83110
}
84111
target.dispatchEvent(event);
@@ -122,9 +149,13 @@ function dispatchUAEventWithLog(nodes, target, eventType, callback) {
122149
function assert_event_path_equals(actual, expected) {
123150
assert_equals(actual.length, expected.length);
124151
for (let i = 0; i < actual.length; ++i) {
152+
assert_equals(actual[i].length, expected[i].length);
125153
assert_equals(actual[i][0], expected[i][0], 'currentTarget at ' + i + ' should be same');
126154
assert_equals(actual[i][1], expected[i][1], 'target at ' + i + ' should be same');
127155
assert_equals(actual[i][2], expected[i][2], 'relatedTarget at ' + i + ' should be same');
128156
assert_array_equals(actual[i][3], expected[i][3], 'composedPath at ' + i + ' should be same');
157+
if (actual[i][4]) {
158+
assert_equals(actual[i][4], expected[i][4], 'listener type should be same at ' + i);
159+
}
129160
}
130161
}

0 commit comments

Comments
 (0)