Address PR feedback

Fix typos
Refactor event retargeting algorithm to be used with relatedTarget
Differentiate `stopPropagation()` and `stopImmediatePropagation()`
This commit is contained in:
Daniel Freedman
2016-08-17 14:52:21 -07:00
parent ec2b452863
commit fb652012be
2 changed files with 62 additions and 62 deletions

View File

@@ -1,4 +1,4 @@
<!--
<!--
@license
Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
@@ -796,15 +796,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
var current = startNode;
while (current) {
composedPath.push(current);
// BREAKME(sorvell): remove v0 support
var contents = current.getDestinationInsertionPoints &&
current.getDestinationInsertionPoints();
if (contents && contents.length) {
for (var i = 0; i < contents.length - 1; i++) {
composedPath.push(contents[i]);
}
current = contents[contents.length - 1];
} else if (current.assignedSlot) {
if (current.assignedSlot) {
current = current.assignedSlot;
} else if (current.host && composed) {
current = current.host;
@@ -819,6 +811,21 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
return composedPath;
}
function retarget(refNode, path) {
// If ANCESTOR's root is not a shadow root or ANCESTOR's root is BASE's
// shadow-including inclusive ancestor, return ANCESTOR.
var base = refNode;
var baseRoot = base && ShadyDom.ownerRootForNode(base);
var p$ = path;
for (var i=0, ancestor, root; i < p$.length; i++) {
ancestor = p$[i];
root = ShadyDom.ownerRootForNode(ancestor);
if (!ShadyDom.isShadyRoot(root) || root === baseRoot) {
return ancestor;
}
}
}
var EventMixin = {
__patched: 'Event',
@@ -838,19 +845,10 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
},
get target() {
// If ANCESTOR's root is not a shadow root or ANCESTOR's root is BASE's
// shadow-including inclusive ancestor, return ANCESTOR.
var base = this.currentTarget;
var baseRoot = base && ShadyDom.ownerRootForNode(base);
var p$ = this.composedPath();
for (var i=0, ancestor, root; i < p$.length; i++) {
ancestor = p$[i];
root = ShadyDom.ownerRootForNode(ancestor);
if (!ShadyDom.isShadyRoot(root) || root === baseRoot) {
return ancestor;
}
}
return retarget(this.currentTarget, this.composedPath());
},
// http://w3c.github.io/webcomponents/spec/shadow/#event-relatedtarget-retargeting
get relatedTarget() {
if (!this.__relatedTarget) {
return null;
@@ -858,24 +856,8 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
if (!this.__relatedTargetComposedPath) {
this.__relatedTargetComposedPath = pathComposer(this.__relatedTarget, true);
}
var path = this.__relatedTargetComposedPath;
var currentRoot = this.target.getRootNode();
var rt = null;
var idx = path.indexOf(currentRoot);
if (idx === -1) {
var targetPath = this.composedPath();
var tidx = targetPath.indexOf(currentRoot) + 1;
while(idx === -1 && tidx < (targetPath.length - 1)) {
idx = path.indexOf(targetPath[++tidx]);
}
} else {
idx--;
}
rt = path[idx];
while(idx >= 0 && rt && !rt.shadowRoot) {
rt = path[--idx];
}
return rt;
// find the deepest node in relatedTarget composed path that is in the same root with the currentTarget
return retarget(this.currentTarget, this.__relatedTargetComposedPath);
},
stopPropagation() {
Event.prototype.stopPropagation.call(this);
@@ -883,6 +865,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
},
stopImmediatePropagation() {
Event.prototype.stopImmediatePropagation.call(this);
this.__immediatePropagationStopped = true;
this.__propagationStopped = true;
}
@@ -892,11 +875,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
var klazz = class extends Base {
constructor(type, options) {
super(type, options);
if (options && options.composed) {
this.__composed = true;
} else {
this.__composed = false;
}
this.__composed = options && Boolean(options.composed);
}
}
return klazz;
@@ -904,7 +883,6 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
ShadyDom.origEvent = Event;
ShadyDom.PatchedEvent = mixinComposedFlag(Event);
ShadyDom.PatchedCustomEvent = mixinComposedFlag(CustomEvent);
var nonBubblingEventsToRetarget = {
@@ -913,19 +891,28 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
};
function retargetNonBubblingEvent(e) {
// override `currentTarget` to let patched `target` calculate correctly
var ct = null;
Object.defineProperty(e, 'currentTarget', {
get: function() {
return ct;
},
configurable: true
});
var path = e.composedPath();
for (var i = 0, n; i < path.length; i++) {
n = path[i];
var hs = n.__handlers && n.__handlers[e.type];
for (var i = 0; i < path.length; i++) {
ct = path[i];
var hs = ct.__handlers && ct.__handlers[e.type];
if (hs) {
for (var j = 0, fn; (fn = hs[j]); j++) {
// override `currentTarget` to let patched `target` calculate correctly
Object.defineProperty(e, 'currentTarget', {value: n, configurable: true});
fn.call(n, e);
if (e.__propagationStopped) {
fn.call(ct, e);
if (e.__immediatePropagationStopped) {
break;
}
}
if (e.__propagationStopped) {
break;
}
}
}
}
@@ -934,6 +921,8 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
if (!fn) {
return;
}
// TODO: investigate if this is worth tracking, as it is only used for
// deciding if the `slotchanged` event should be fired
if (!this.__eventListenerCount) {
this.__eventListenerCount = 0;
}
@@ -947,7 +936,10 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
e.__proto__ = proto;
}
}
if (e.composedPath().indexOf(this) > -1 && e.target !== e.relatedTarget) {
// There are two critera that should stop events from firing on nodes
// 1. after retargeting, relatedTarget and target point to the same node
// 2. the event is not composed and the current node is not in the same root as the target
if (e.target !== e.relatedTarget && (e.composed || e.composedPath().indexOf(this) > -1)) {
return fn(e);
} else {
e.stopImmediatePropagation();
@@ -984,22 +976,22 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
}
};
document.addEventListener('focus', function(e){
document.addEventListener('focus', function(e) {
var proto = ShadyDom.patchImpl.prototypeForObject(e);
if (!e.__target) {
e.__target = e.target;
e.__relatedTarget = e.__relatedTarget;
e.__relatedTarget = e.relatedTarget;
e.__proto__ = proto;
retargetNonBubblingEvent(e);
e.stopImmediatePropagation();
}
}, true);
document.addEventListener('blur', function(e){
document.addEventListener('blur', function(e) {
var proto = ShadyDom.patchImpl.prototypeForObject(e);
if (!e.__target) {
e.__target = e.target;
e.__relatedTarget = e.__relatedTarget;
e.__relatedTarget = e.relatedTarget;
e.__proto__ = proto;
retargetNonBubblingEvent(e);
e.stopImmediatePropagation();

View File

@@ -112,7 +112,8 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
<dom-module id="x-a">
<template>
<div id="child"></div>
<div id="child" on-foo="childFooHandler"></div>
<div id="child2"></div>
</template>
<script>
HTMLImports.whenReady(function() {
@@ -123,6 +124,9 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
},
fooHandler: function(e) {
this.event = {target: e.target, relatedTarget: e.relatedTarget};
},
childFooHandler: function(e) {
this.childEvent = {target: e.target, relatedTarget: e.relatedTarget};
}
})
});
@@ -181,7 +185,7 @@ suite('ShadyDOM event patching', function() {
assert.deepEqual([el, el.parentNode, document.body, document.documentElement, document, window], path);
});
test('events handle the `composed` flag correctly', function() {
test('`composed` flag controls event propagation through roots', function() {
var el = fixture('scoped');
el.fireScoped();
el.fireComposed();
@@ -220,6 +224,8 @@ suite('ShadyDOM event patching', function() {
var ev = new MouseEvent('foo', {bubbles: true, composed: true, relatedTarget: b.$.child});
ev.__composed = true;
a.$.child.dispatchEvent(ev);
assert.property(a, 'childEvent');
assert.deepEqual(a.childEvent, {target: a.$.child, relatedTarget: b});
assert.property(a, 'event');
assert.deepEqual(a.event, {target: a, relatedTarget: b});
});
@@ -227,9 +233,11 @@ suite('ShadyDOM event patching', function() {
test('events do not fire if relatedtarget and target are the same node after retargeting', function() {
var els = fixture('relatedtarget');
var a = els[0];
var ev = new MouseEvent('foo', {bubbles: true, composed: true, relatedTarget: a.$.child});
var ev = new MouseEvent('foo', {bubbles: true, composed: true, relatedTarget: a.$.child2});
ev.__composed = true;
a.dispatchEvent(ev);
a.$.child.dispatchEvent(ev);
assert.property(a, 'childEvent');
assert.deepEqual(a.childEvent, {target: a.$.child, relatedTarget: a.$.child2});
assert.notProperty(a, 'event');
});
});