Skip to content

Commit fdd4941

Browse files
committed
Merge pull request #3407 from Polymer/fix-nested-track-tap
Disable tap gesture when track gesture is firing for ancestor node
2 parents 9b34171 + 6f2c1fc commit fdd4941

File tree

3 files changed

+124
-33
lines changed

3 files changed

+124
-33
lines changed

src/standard/gestures.html

+12-8
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,8 @@
230230
Gestures.handleTouchAction(ev);
231231
}
232232
}
233-
if (type === 'touchend') {
233+
// disable synth mouse events, unless this event is itself simulated
234+
if (type === 'touchend' && !ev.__polymerSimulatedTouch) {
234235
POINTERSTATE.mouse.target = Polymer.dom(ev).rootTarget;
235236
// ignore syntethic mouse events after a touch
236237
ignoreMouse(true);
@@ -247,10 +248,8 @@
247248
for (var i = 0, r; i < recognizers.length; i++) {
248249
r = recognizers[i];
249250
if (gs[r.name] && !handled[r.name]) {
250-
if (r.flow && r.flow.start.indexOf(ev.type) > -1) {
251-
if (r.reset) {
252-
r.reset();
253-
}
251+
if (r.flow && r.flow.start.indexOf(ev.type) > -1 && r.reset) {
252+
r.reset();
254253
}
255254
}
256255
}
@@ -525,6 +524,10 @@
525524
if (self.hasMovedEnough(x, y)) {
526525
// first move is 'start', subsequent moves are 'move', mouseup is 'end'
527526
self.info.state = self.info.started ? (e.type === 'mouseup' ? 'end' : 'track') : 'start';
527+
if (self.info.state === 'start') {
528+
// iff tracking, always prevent tap
529+
Gestures.prevent('tap');
530+
}
528531
self.info.addMove({x: x, y: y});
529532
if (!hasLeftMouseButton(e)) {
530533
// always fire "end"
@@ -537,7 +540,6 @@
537540
};
538541
var upfn = function upfn(e) {
539542
if (self.info.started) {
540-
Gestures.prevent('tap');
541543
movefn(e);
542544
}
543545

@@ -561,6 +563,10 @@
561563
var ct = e.changedTouches[0];
562564
var x = ct.clientX, y = ct.clientY;
563565
if (this.hasMovedEnough(x, y)) {
566+
if (this.info.state === 'start') {
567+
// iff tracking, always prevent tap
568+
Gestures.prevent('tap');
569+
}
564570
this.info.addMove({x: x, y: y});
565571
this.fire(t, ct);
566572
this.info.state = 'track';
@@ -573,8 +579,6 @@
573579
var ct = e.changedTouches[0];
574580
// only trackend if track was started and not aborted
575581
if (this.info.started) {
576-
// iff tracking, always prevent tap
577-
Gestures.prevent('tap');
578582
// reset started state on up
579583
this.info.state = 'end';
580584
this.info.addMove({x: ct.clientX, y: ct.clientY});

test/unit/gestures-elements.html

+66-25
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,22 @@
9494
</script>
9595
</dom-module>
9696

97+
<script>
98+
var EventCaptureBehavior = {
99+
properties: {
100+
stream: {
101+
type: Array,
102+
value: function() {
103+
return [];
104+
}
105+
}
106+
},
107+
handle: function(e) {
108+
this.stream.push(e);
109+
}
110+
};
111+
</script>
112+
97113
<dom-module id="x-prevent">
98114
<script>
99115
Polymer({
@@ -103,13 +119,8 @@
103119
'tap': 'handle',
104120
'track': 'handle'
105121
},
122+
behaviors: [EventCaptureBehavior],
106123
is: 'x-prevent',
107-
created: function() {
108-
this.stream = [];
109-
},
110-
handle: function(e) {
111-
this.stream.push(e);
112-
},
113124
prevent: function(e, detail) {
114125
detail.prevent('tap');
115126
detail.prevent('track');
@@ -130,12 +141,7 @@
130141
'tap': 'handle',
131142
'track': 'handle'
132143
},
133-
created: function() {
134-
this.stream = [];
135-
},
136-
handle: function(e) {
137-
this.stream.push(e);
138-
}
144+
behaviors: [EventCaptureBehavior]
139145
});
140146
</script>
141147
</dom-module>
@@ -144,23 +150,58 @@
144150
<script>
145151
Polymer({
146152
is: 'x-document-listener',
147-
properties: {
148-
stream: {
149-
type: Array,
150-
value: function() {
151-
return [];
152-
}
153-
}
154-
},
155153
setup: function() {
156-
this.listen(document, 'down', 'handler');
154+
this.listen(document, 'down', 'handle');
157155
},
158156
teardown: function() {
159-
this.unlisten(document, 'down', 'handler');
157+
this.unlisten(document, 'down', 'handle');
160158
},
161-
handler: function(e) {
162-
this.stream.push(e);
163-
}
159+
behaviors: [EventCaptureBehavior]
164160
});
165161
</script>
166162
</dom-module>
163+
164+
<dom-module id="x-nested-child-prevent">
165+
<script>
166+
Polymer({
167+
is: 'x-nested-child-prevent',
168+
listeners: {
169+
tap: 'handle'
170+
},
171+
behaviors: [EventCaptureBehavior]
172+
});
173+
</script>
174+
</dom-module>
175+
176+
<dom-module id="x-nested-prevent">
177+
<template>
178+
<style>
179+
:host {
180+
position: absolute;
181+
display: block;
182+
background: orange;
183+
height: 100px;
184+
width: 100px;
185+
}
186+
#child {
187+
position: relative;
188+
display: block;
189+
background: blue;
190+
height: 50px;
191+
width: 50px;
192+
margin-top: 25px;
193+
margin-left: 25px;
194+
}
195+
</style>
196+
<x-nested-child-prevent id="child"></x-nested-child-prevent>
197+
</template>
198+
<script>
199+
Polymer({
200+
is: 'x-nested-prevent',
201+
listeners: {
202+
track: 'handle'
203+
},
204+
behaviors: [EventCaptureBehavior]
205+
});
206+
</script>
207+
</dom-module>

test/unit/gestures.html

+46
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,52 @@
291291
assert.equal(el.stream[0].defaultPrevented, true, 'down was prevented');
292292
assert.equal(el.stream[1].type, 'up', 'up was found');
293293
});
294+
295+
test('nested track and tap with touch', function() {
296+
el.parentNode.removeChild(el);
297+
el = document.createElement('x-nested-prevent');
298+
var child = el.$.child;
299+
document.body.appendChild(el);
300+
var options = {bubbles: true, cancelable: true};
301+
302+
var bgr = el.getBoundingClientRect();
303+
var clientX = bgr.left + (bgr.width / 2);
304+
var clientY = bgr.top + (bgr.bottom / 2);
305+
var ev = new CustomEvent('touchstart', options);
306+
ev.touches = ev.changedTouches = [
307+
{
308+
clientX: clientX,
309+
clientY: clientY,
310+
identifier: 1,
311+
target: child
312+
}
313+
];
314+
ev.clientX = clientX;
315+
ev.clientY = clientY;
316+
ev.__polymerSimulatedTouch = true;
317+
child.dispatchEvent(ev);
318+
319+
for (var i = 0; i < 10; i++) {
320+
clientX += 1;
321+
ev = new CustomEvent(i === 9 ? 'touchend' : 'touchmove', options);
322+
ev.touches = ev.changedTouches = [
323+
{
324+
clientX: clientX,
325+
clientY: clientY,
326+
identifier: 1,
327+
target: child
328+
}
329+
];
330+
ev.clientX = clientX;
331+
ev.clientY = clientY;
332+
// tell gestures to not turn off mouse events
333+
ev.__polymerSimulatedTouch = true;
334+
child.dispatchEvent(ev);
335+
}
336+
337+
assert.equal(child.stream.length, 0, 'expected no taps on the child');
338+
assert.notEqual(el.stream.length, 0, 'expected some tracks on the parent');
339+
});
294340
});
295341

296342
suite('Buttons', function() {

0 commit comments

Comments
 (0)