-
Notifications
You must be signed in to change notification settings - Fork 318
Description
We have a bug report saying that WebKit fires event listeners with capture flag set to true during bubbling phase.
Consider the following DOM:
const hostParent = document.createElement('section');
hostParent.id = 'hostParent';
hostParent.innerHTML = '<div id="host"></div>';
const host = hostParent.firstChild;
const shadowRoot = host.attachShadow({mode: 'closed'});
shadowRoot.innerHTML = '<p id="parent"><span id="target"></span></p>';
...
target.dispatchEvent(new CustomEvent('test', {detail: {}, bubbles: true, composed: true}));Then the event listeners on target, parent, host, and hostParent are invoked in the following order on WebKit & Chrome:
- hostParent, capturing, eventPhase: CAPTURING_PHASE
- parent, capturing, eventPhase: CAPTURING_PHASE
- target, capturing, eventPhase: AT_TARGET
- target, non-capturing, eventPhase: AT_TARGET
- parent, non-capturing, eventPhase: BUBBLING_PHASE
- host, capturing, eventPhase: AT_TARGET
- host, non-capturing, eventPhase: AT_TARGET
- hostParent, non-capturing, eventPhase: BUBBLING_PHASE
As far as I can tell, the current behavior of WebKit & Chrome is in accordance with the latest DOM specification. What happens is that step 5 (event path construction) in dispatching an event ends up appending an tuple/struct (we should probably stick with either term, btw) with target set to null. In step 14, we only invoke event listeners with capture flag set if target is null, meaning that shadow hosts' event listeners with capture flag set would NOT be called. Then in step 15, we set eventPhase to AT_TARGET and invoke event listeners. Because the concept to inner invoke an event listener doesn't skip event listeners with capture flag set to true when the event phase is AT_TARGET, we end up firing capturing event listeners during bubbling.