From e33ee0463de1ccdebbe393caa08b3173f9adaf2d Mon Sep 17 00:00:00 2001 From: Maira Bello Date: Wed, 9 Jul 2014 11:38:17 -0300 Subject: [PATCH] Fix #1901: stopPropagation doesn't work for gesturemovestart when minTime or minDistance is set When using minTime or minDistance, stopPropagation calls don't work anymore for the gesturemovestart event. That's because these are triggered asynchronously, so stopPropagation ends up being called after the original events already propagated. This is explained in more detail in issue #1901. This is fixing the problem by adding a flag to the original event indicating it has been stopped, and then preventing any gesturemovestart events tied events with that flag from firing. --- src/event-gestures/HISTORY.md | 2 +- src/event-gestures/js/Move.js | 36 ++++++++ .../tests/unit/assets/gesture-tests.js | 86 ++++++++++++++++++- 3 files changed, 120 insertions(+), 4 deletions(-) diff --git a/src/event-gestures/HISTORY.md b/src/event-gestures/HISTORY.md index c6736ea960c..8e2323b5a45 100644 --- a/src/event-gestures/HISTORY.md +++ b/src/event-gestures/HISTORY.md @@ -4,7 +4,7 @@ Gestures Change History @VERSION@ ------ -* No changes. +* [#1901][]: stopPropagation doesn't work for gesturemovestart when minTime or minDistance is set (@mairatma) 3.17.2 ------ diff --git a/src/event-gestures/js/Move.js b/src/event-gestures/js/Move.js index 1feed003d47..f521d623eff 100644 --- a/src/event-gestures/js/Move.js +++ b/src/event-gestures/js/Move.js @@ -328,18 +328,54 @@ define(GESTURE_MOVE_START, { } }, + /** + * Checks if the given event should be fired or not. + * + * @method _shouldFireEvent + * @param {EventFacade} + * @protected + */ + _shouldFireEvent: function(e) { + if (e._event.stopped === 2) { + // Don't fire the event if it has been completely stopped. + return false; + } + + if (e._event.stopped === 1 && + !e.currentTarget.compareTo(e._event.stoppedTarget)) { + + // Don't fire the event if it has been propagated when propagation + // should have been stopped. + return false; + } + + return true; + }, + _start : function(e, node, ce, params) { if (params) { this._cancel(params); } + if (!this._shouldFireEvent(e)) { + return; + } + e.type = GESTURE_MOVE_START; Y.log("gesturemovestart: Firing start: " + new Date().getTime(), "event-gestures"); node.setData(_MOVE_START, e); ce.fire(e); + + if (e.stopped) { + // If the event was stopped, add a flag to the event that triggered it, + // so we can prevent any subsequent events related to it from firing + // as well. + e._event.stopped = e.stopped; + e._event.stoppedTarget = e.currentTarget; + } }, MIN_TIME : 0, diff --git a/src/event-gestures/tests/unit/assets/gesture-tests.js b/src/event-gestures/tests/unit/assets/gesture-tests.js index f817dd1443d..df9bd18371d 100644 --- a/src/event-gestures/tests/unit/assets/gesture-tests.js +++ b/src/event-gestures/tests/unit/assets/gesture-tests.js @@ -24,12 +24,14 @@ YUI.add('gesture-tests', function(Y) { screenX: 100, screenY: 100 } - ] + ], + _event: {} }, eventNoTouch = { target: node, - currentTarget: node + currentTarget: node, + _event: {} }, suite = new Y.Test.Suite('Gesture Event Suite'); @@ -87,6 +89,84 @@ YUI.add('gesture-tests', function(Y) { Assert.areEqual(1, e.button, 'e.button is not set'); } }); + }, + + 'test: stopPropagation should work as expected': function() { + var currentEvent, + mock = new Y.Mock(), + node1 = Y.Node.create('
'), + node2 = Y.Node.create('
'); + + node2.append(node1); + currentEvent = { + currentTarget: node1, + touches: event.touches, + target: node1, + _event: {} + }; + + eventData.start._start(currentEvent, node1, { + fire: function(e) { + Assert.areSame('gesturemovestart', e.type, 'Event type not correct'); + e.stopped = 1; + } + }); + + Y.Mock.expect(mock, { + callCount: 1, + method: 'fire1', + args: [Y.Mock.Value.Object] + }); + eventData.start._start(currentEvent, node1, {fire: Y.bind(mock.fire1, mock)}); + Y.Mock.verify(mock); + + Y.Mock.expect(mock, { + callCount: 0, + method: 'fire2', + args: [Y.Mock.Value.Object] + }); + currentEvent.currentTarget = node2; + eventData.start._start(currentEvent, node2, {fire: Y.bind(mock.fire2, mock)}); + Y.Mock.verify(mock); + }, + + 'test: stopImmediatePropagation should work as expected': function() { + var currentEvent, + mock = new Y.Mock(), + node1 = Y.Node.create('
'), + node2 = Y.Node.create('
'); + + node2.append(node1); + currentEvent = { + currentTarget: node1, + touches: event.touches, + target: node1, + _event: {} + }; + + eventData.start._start(currentEvent, node1, { + fire: function(e) { + Assert.areSame('gesturemovestart', e.type, 'Event type not correct'); + e.stopped = 2; + } + }); + + Y.Mock.expect(mock, { + callCount: 0, + method: 'fire1', + args: [Y.Mock.Value.Object] + }); + eventData.start._start(currentEvent, node1, {fire: Y.bind(mock.fire1, mock)}); + Y.Mock.verify(mock); + + Y.Mock.expect(mock, { + callCount: 0, + method: 'fire2', + args: [Y.Mock.Value.Object] + }); + currentEvent.currentTarget = node2; + eventData.start._start(currentEvent, node2, {fire: Y.bind(mock.fire2, mock)}); + Y.Mock.verify(mock); } })); @@ -392,4 +472,4 @@ YUI.add('gesture-tests', function(Y) { Y.Test.Runner.add(suite); -}); +}, '', {requires:['test', 'node']});