Skip to content

Commit

Permalink
Call capture event listeners in capturing phase at shadow hosts
Browse files Browse the repository at this point in the history
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
  • Loading branch information
hayatoito authored and Chrome-bot committed Sep 14, 2018
1 parent 8a062c1 commit 7920786
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 9 deletions.
30 changes: 30 additions & 0 deletions shadow-dom/event-dispatch-order.tentative.html
@@ -0,0 +1,30 @@
<!DOCTYPE html>
<title>Shadow DOM: event dispatch order for capture and non-capture listerns at a shadow host</title>
<meta name="author" title="Hayato Ito" href="mailto:hayato@google.com">
<link rel="help" href="https://github.com/whatwg/dom/issues/685">
<link rel="help" href="https://github.com/whatwg/dom/pull/686">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="resources/shadow-dom.js"></script>
<div id=host>
<template id=shadowroot data-mode=open>
<div id=target></div>
</template>
</div>
<script>
test(() => {
let nodes = createTestTree(host);
let log = dispatchEventWithLog(nodes, nodes.target,
new Event('my-event', { bubbles: true, composed: true }),
{ capture: true });
let path = ['target', 'shadowroot', 'host'];
assert_event_path_equals(log,
[['host', 'host', null, path, 'capture'],
['shadowroot', 'target', null, path, 'capture'],
['target', 'target', null, path, 'capture'],
['target', 'target', null, path, 'non-capture'],
['shadowroot', 'target', null, path, 'non-capture'],
['host', 'host', null, path, 'non-capture'],
]);
}, 'Event dispatch order: capture listerns should be called in capturing phase at a shadow host');
</script>
49 changes: 40 additions & 9 deletions shadow-dom/resources/shadow-dom.js
Expand Up @@ -53,7 +53,9 @@ function createTestTree(node) {
return ids;
}

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

function labelFor(e) {
return e.id || e.tagName;
Expand All @@ -70,15 +72,40 @@ function dispatchEventWithLog(nodes, target, event) {
if (!id)
continue;
attachedNodes.push(node);
node.addEventListener(event.type, (e) => {
if (options && options.capture) {
// Record [currentTarget, target, relatedTarget, composedPath(), 'capture' | 'non-capture']
// TODO(hayato): Support register listeners in different orders.
// e.g. Register non-capture listener at first, then register capture listener.
node.addEventListener(event.type, (e) => {
log.push([id,
labelFor(e.target),
e.relatedTarget ? labelFor(e.relatedTarget) : null,
e.composedPath().map((n) => {
return labelFor(n);
}),
'capture']);
}, true);
node.addEventListener(event.type, (e) => {
log.push([id,
labelFor(e.target),
e.relatedTarget ? labelFor(e.relatedTarget) : null,
e.composedPath().map((n) => {
return labelFor(n);
}),
'non-capture']);
});
} else {
// Record [currentTarget, target, relatedTarget, composedPath()]
log.push([id,
labelFor(e.target),
e.relatedTarget ? labelFor(e.relatedTarget) : null,
e.composedPath().map((n) => {
return labelFor(n);
})]);
});
node.addEventListener(event.type, (e) => {
log.push([id,
labelFor(e.target),
e.relatedTarget ? labelFor(e.relatedTarget) : null,
e.composedPath().map((n) => {
return labelFor(n);
})]
);
});
}
}
}
target.dispatchEvent(event);
Expand Down Expand Up @@ -122,9 +149,13 @@ function dispatchUAEventWithLog(nodes, target, eventType, callback) {
function assert_event_path_equals(actual, expected) {
assert_equals(actual.length, expected.length);
for (let i = 0; i < actual.length; ++i) {
assert_equals(actual[i].length, expected[i].length);
assert_equals(actual[i][0], expected[i][0], 'currentTarget at ' + i + ' should be same');
assert_equals(actual[i][1], expected[i][1], 'target at ' + i + ' should be same');
assert_equals(actual[i][2], expected[i][2], 'relatedTarget at ' + i + ' should be same');
assert_array_equals(actual[i][3], expected[i][3], 'composedPath at ' + i + ' should be same');
if (actual[i][4]) {
assert_equals(actual[i][4], expected[i][4], 'listener type should be same at ' + i);
}
}
}

0 comments on commit 7920786

Please sign in to comment.