From 6f2c1fc7950d72ccb512d44514b22f8edce1bdda Mon Sep 17 00:00:00 2001 From: Daniel Freedman Date: Wed, 10 Feb 2016 15:24:44 -0800 Subject: [PATCH] Disable tap gesture when track gesture is firing for ancestor node Move tap disable into track start Fixes #3405 --- src/standard/gestures.html | 20 ++++--- test/unit/gestures-elements.html | 91 +++++++++++++++++++++++--------- test/unit/gestures.html | 62 +++++++++++++++++++--- 3 files changed, 132 insertions(+), 41 deletions(-) diff --git a/src/standard/gestures.html b/src/standard/gestures.html index 093fc8d9d0..45250924a0 100644 --- a/src/standard/gestures.html +++ b/src/standard/gestures.html @@ -230,7 +230,8 @@ Gestures.handleTouchAction(ev); } } - if (type === 'touchend') { + // disable synth mouse events, unless this event is itself simulated + if (type === 'touchend' && !ev.__polymerSimulatedTouch) { POINTERSTATE.mouse.target = Polymer.dom(ev).rootTarget; // ignore syntethic mouse events after a touch ignoreMouse(true); @@ -247,10 +248,8 @@ for (var i = 0, r; i < recognizers.length; i++) { r = recognizers[i]; if (gs[r.name] && !handled[r.name]) { - if (r.flow && r.flow.start.indexOf(ev.type) > -1) { - if (r.reset) { - r.reset(); - } + if (r.flow && r.flow.start.indexOf(ev.type) > -1 && r.reset) { + r.reset(); } } } @@ -525,6 +524,10 @@ if (self.hasMovedEnough(x, y)) { // first move is 'start', subsequent moves are 'move', mouseup is 'end' self.info.state = self.info.started ? (e.type === 'mouseup' ? 'end' : 'track') : 'start'; + if (self.info.state === 'start') { + // iff tracking, always prevent tap + Gestures.prevent('tap'); + } self.info.addMove({x: x, y: y}); if (!hasLeftMouseButton(e)) { // always fire "end" @@ -537,7 +540,6 @@ }; var upfn = function upfn(e) { if (self.info.started) { - Gestures.prevent('tap'); movefn(e); } @@ -561,6 +563,10 @@ var ct = e.changedTouches[0]; var x = ct.clientX, y = ct.clientY; if (this.hasMovedEnough(x, y)) { + if (this.info.state === 'start') { + // iff tracking, always prevent tap + Gestures.prevent('tap'); + } this.info.addMove({x: x, y: y}); this.fire(t, ct); this.info.state = 'track'; @@ -573,8 +579,6 @@ var ct = e.changedTouches[0]; // only trackend if track was started and not aborted if (this.info.started) { - // iff tracking, always prevent tap - Gestures.prevent('tap'); // reset started state on up this.info.state = 'end'; this.info.addMove({x: ct.clientX, y: ct.clientY}); diff --git a/test/unit/gestures-elements.html b/test/unit/gestures-elements.html index ee9a3c13d0..ede8f81c50 100644 --- a/test/unit/gestures-elements.html +++ b/test/unit/gestures-elements.html @@ -94,6 +94,22 @@ + + @@ -144,23 +150,58 @@ + + + + + + + + + diff --git a/test/unit/gestures.html b/test/unit/gestures.html index 24efc9e15f..8b94a21c9d 100644 --- a/test/unit/gestures.html +++ b/test/unit/gestures.html @@ -81,11 +81,11 @@ assert.equal(obj.mousedown.downup, 2, 'mousedown downup'); assert.equal(obj.mousedown.track, 1, 'mousedown track'); assert.equal(obj.mousedown.tap, 1, 'mousedown tap'); - assert.equal(obj.mousedown._count, 4, 'total mousedown') + assert.equal(obj.mousedown._count, 4, 'total mousedown'); assert.equal(obj.touchstart.downup, 2, 'touchstart downup'); assert.equal(obj.touchstart.tap, 1, 'touchstart tap'); assert.equal(obj.touchstart.track, 1, 'touchstart track'); - assert.equal(obj.touchstart._count, 4, 'total touchstart') + assert.equal(obj.touchstart._count, 4, 'total touchstart'); assert.equal(obj.touchmove.track, 1, 'touchmove track'); assert.equal(obj.touchmove._count, 1, 'total touchmove'); assert.equal(obj.touchend.downup, 2, 'touchend downup'); @@ -100,17 +100,17 @@ assert.equal(obj.mousedown.downup, 2, 'mousedown downup'); assert.equal(obj.mousedown.track, 1, 'mousedown track'); assert.equal(obj.mousedown.tap, 1, 'mousedown tap'); - assert.equal(obj.mousedown._count, 4, 'total mousedown') + assert.equal(obj.mousedown._count, 4, 'total mousedown'); assert.equal(obj.touchstart.downup, 2, 'touchstart downup'); assert.equal(obj.touchstart.tap, 1, 'touchstart tap'); assert.equal(obj.touchstart.track, 1, 'touchstart track'); - assert.equal(obj.touchstart._count, 4, 'total touchstart') + assert.equal(obj.touchstart._count, 4, 'total touchstart'); assert.equal(obj.touchmove.track, 1, 'touchmove track'); assert.equal(obj.touchmove._count, 1, 'total touchmove'); assert.equal(obj.touchend.downup, 2, 'touchend downup'); assert.equal(obj.touchend.track, 1, 'touchend track'); assert.equal(obj.touchend.tap, 1, 'touchend tap'); - assert.equal(obj.touchend._count, 4, 'total touchend');; + assert.equal(obj.touchend._count, 4, 'total touchend'); }); test('dynamic', function() { @@ -142,7 +142,7 @@ assert.equal(obj.touchstart.downup, 0, 'touchstart downup'); assert.equal(obj.touchstart._count, 0, 'total touchstart'); assert.equal(obj.touchmove.track, 0, 'touchmove track'); - assert.equal(obj.touchmove._count, 0, 'total touchmove') + assert.equal(obj.touchmove._count, 0, 'total touchmove'); assert.equal(obj.touchstart.tap, 0, 'touchstart tap'); assert.equal(obj.touchend.downup, 0, 'touchend downup'); assert.equal(obj.touchend.track, 0, 'touchend track'); @@ -164,7 +164,7 @@ assert.equal(obj.touchstart.downup, 0, 'touchstart downup'); assert.equal(obj.touchstart._count, 0, 'total touchstart'); assert.equal(obj.touchmove.track, 0, 'touchmove track'); - assert.equal(obj.touchmove._count, 0, 'total touchmove') + assert.equal(obj.touchmove._count, 0, 'total touchmove'); assert.equal(obj.touchstart.tap, 0, 'touchstart tap'); assert.equal(obj.touchend.downup, 0, 'touchend downup'); assert.equal(obj.touchend.track, 0, 'touchend track'); @@ -202,7 +202,7 @@ test('target finding returns null outside the window', function() { var actual = Polymer.Gestures.deepTargetFind(-1, -1); assert.equal(actual, null); - }) + }); test('find the div in document', function() { var x = divLocation.left, y = divLocation.top; @@ -291,6 +291,52 @@ assert.equal(el.stream[0].defaultPrevented, true, 'down was prevented'); assert.equal(el.stream[1].type, 'up', 'up was found'); }); + + test('nested track and tap with touch', function() { + el.parentNode.removeChild(el); + el = document.createElement('x-nested-prevent'); + var child = el.$.child; + document.body.appendChild(el); + var options = {bubbles: true, cancelable: true}; + + var bgr = el.getBoundingClientRect(); + var clientX = bgr.left + (bgr.width / 2); + var clientY = bgr.top + (bgr.bottom / 2); + var ev = new CustomEvent('touchstart', options); + ev.touches = ev.changedTouches = [ + { + clientX: clientX, + clientY: clientY, + identifier: 1, + target: child + } + ]; + ev.clientX = clientX; + ev.clientY = clientY; + ev.__polymerSimulatedTouch = true; + child.dispatchEvent(ev); + + for (var i = 0; i < 10; i++) { + clientX += 1; + ev = new CustomEvent(i === 9 ? 'touchend' : 'touchmove', options); + ev.touches = ev.changedTouches = [ + { + clientX: clientX, + clientY: clientY, + identifier: 1, + target: child + } + ]; + ev.clientX = clientX; + ev.clientY = clientY; + // tell gestures to not turn off mouse events + ev.__polymerSimulatedTouch = true; + child.dispatchEvent(ev); + } + + assert.equal(child.stream.length, 0, 'expected no taps on the child'); + assert.notEqual(el.stream.length, 0, 'expected some tracks on the parent'); + }); }); suite('Buttons', function() {