I'm trying to understand what events that originate in light DOM look like when received in shadow DOM via a <content>
element. I'm reading the Shadow DOM W3C Draft, and I don't entirely understand it but it sounds like events are to be "retargeted" from the point of view of the EventListener attachment.
In the cases where event path is across multiple node trees, the
event's information about the target of the event is adjusted in order
to maintain encapsulation. Event retargeting is a process of computing
relative targets for each ancestor of the node at which the event is
dispatched. A relative target is a node that most accurately
represents the target of a dispatched event at a given ancestor while
maintaining the encapsulation.
and
At the time of event dispatch:
- The Event target and currentTarget attributes must return the relative
target for the node on which event listeners are invoked
So here's a simple Polymer custom element that just puts its children into a container, and adds a click EventListener to the container (in the shadow DOM). In this case the child is a button.
<!DOCTYPE html>
<html>
<head>
<script src="bower_components/platform/platform.js"></script>
<link rel="import" href="bower_components/polymer/polymer.html">
</head>
<body unresolved>
<polymer-element name="foo-bar">
<template>
<div id="internal-container" style="background-color:red; width:100%;">
<content></content>
</div>
</template>
<script>
Polymer("foo-bar", {
clickHandler: function(event) {
console.log(event);
var element = event.target;
while (element) {
console.log(element.tagName, element.id);
element = element.parentElement;
}
},
ready: function() {
this.shadowRoot.querySelector('#internal-container').addEventListener('click', this.clickHandler);
}
});
</script>
</polymer-element>
<foo-bar id="custom-element">
<button>Click me</button>
</foo-bar>
</body>
</html>
When I run this on Chrome 38.0.2075.0 canary, when I click on the button I get:
MouseEvent {dataTransfer: null, toElement: button, fromElement: null, y: 19, x: 53…}altKey: falsebubbles: truebutton: 0cancelBubble: falsecancelable: truecharCode: 0clientX: 53clientY: 19clipboardData: undefinedctrlKey: falsecurrentTarget: nulldataTransfer: nulldefaultPrevented: falsedetail: 1eventPhase: 0fromElement: nullkeyCode: 0layerX: 53layerY: 19metaKey: falsemovementX: 0movementY: 0offsetX: 45offsetY: 10pageX: 53pageY: 19path: NodeList[0]relatedTarget: nullreturnValue: truescreenX: 472screenY: 113shiftKey: falsesrcElement: buttontarget: buttontimeStamp: 1404078533176toElement: buttontype: "click"view: WindowwebkitMovementX: 0webkitMovementY: 0which: 1x: 53y: 19__proto__: MouseEvent test.html:17
BUTTON test.html:20
FOO-BAR custom-element test.html:20
BODY test.html:20
HTML test.html:20
and when I click on the container I get:
MouseEvent {dataTransfer: null, toElement: div#internal-container, fromElement: null, y: 15, x: 82…} test.html:17
DIV internal-container test.html:20
So I get an event target in either the light or shadow DOM, depending on which DOM the source element was in. I was expecting to get a target from the shadow DOM in both cases because that's where the EventListener is attached. My questions are:
- Is this the way it is supposed to work, and
- If so, is there an alternative way to get events that bubble up from the light DOM retargeted to the shadow DOM?
In case someone wants to ask, "What are you trying to do?", I'm not trying to do anything specifically other than understand the behavior.
See Question&Answers more detail:
os