diff --git a/frameworks/foundation/mixins/gesturable.js b/frameworks/foundation/mixins/gesturable.js index 0662d4588c..bb957450a2 100644 --- a/frameworks/foundation/mixins/gesturable.js +++ b/frameworks/foundation/mixins/gesturable.js @@ -143,7 +143,6 @@ SC.Gesturable = { @param {Boolean} wasCancelled Whether the touch was cancelled or not (i.e. ended normally). */ _sc_gestureTouchFinish: function (touch, wasCancelled) { - // console.log("%@ - _sc_gestureTouchFinish".fmt(this)); var touchesInSession = this._sc_touchesInSession, touchIndexInSession = touchesInSession.indexOf(touch); @@ -323,23 +322,22 @@ SC.Gesturable = { }, /** - Tells the gesture recognizing system about a new touch. + Tells the gesture recognizing system about a new touch. This notifies all gestures of a new + touch session starting (if there were no previous touches) or notifies all interested gestures + that a touch has been added. - This informs all gestures that a new touch, "unassigned" to any gesture, - has been located. Later, each gesture has an opportunity to claim the touch. - - Once they have claimed the touch, further events will go _directly_ to them— - this view will cease receiving the touchesDragged and will not receive a touchEnd. + As touches are added beyond the first touch, gestures may "lose interest" in the touch session. + For example, a gesture may explicitly want only a single touch and if a second touch appears, + the gesture may not want any further updates on this touch session (even if the second touch + ends again). @param {SC.Touch} touch The touch that started. @returns {Boolean} Whether any gesture is interested in the touch or not. */ gestureTouchStart: function (touch) { - // touch.isInteresting = 0; - var interestedGestures = this._sc_interestedGestures, touchesInSession = this._sc_touchesInSession, - addedTouchToSession = false, + claimedTouch = false, idx; // Instantiate once. @@ -360,6 +358,9 @@ SC.Gesturable = { interestedGestures.push(gesture); } + // Keep this touch. + claimedTouch = true; + // Only check gestures that are interested. } else { // Loop through the gestures in reverse, as the list may be mutated. @@ -370,7 +371,10 @@ SC.Gesturable = { // Keep only the gestures still interested in the touch. isInterested = interestedGesture.touchAddedToSession(touch, touchesInSession); - if (!isInterested) { + if (isInterested) { + // Keep this touch. + claimedTouch = true; + } else { // Tell the gesture that the touch session has ended for it. interestedGesture.touchSessionCancelled(); @@ -379,22 +383,20 @@ SC.Gesturable = { } } - // If any gesture is interested or still interested, increment our list of interesting touches - // that are being acted upon in this session. - if (interestedGestures.length > 0) { + // If any gesture is interested in the new touch. Add it to the list of touches in the session. + if (claimedTouch) { touchesInSession.push(touch); - - addedTouchToSession = true; } - return addedTouchToSession; + return claimedTouch; }, /** - Tells the gesture recognition system that some unassigned touches have moved. + Tells the gesture recognition system that touches have moved. - This informs all interested gestures that these touches have changed. All such touches - will be "unassigned" because all "assigned" touches already get sent directly to the gesture. + @param {SC.Event} evt The touch event. + @param {Array} touches The touches previously claimed by this view. + @returns {void} */ gestureTouchesDragged: function (evt, touches) { var gestures = this._sc_interestedGestures, @@ -411,6 +413,8 @@ SC.Gesturable = { gesture.touchSessionCancelled(); gestures.replace(i, 1); + + // TODO: When there are no more interested gestures? Do what with the touches? Anything? } } }, diff --git a/frameworks/foundation/tests/mixins/gesturable_test.js b/frameworks/foundation/tests/mixins/gesturable_test.js index 12cc38a934..62754d0569 100644 --- a/frameworks/foundation/tests/mixins/gesturable_test.js +++ b/frameworks/foundation/tests/mixins/gesturable_test.js @@ -73,9 +73,9 @@ test("Method: touchStart", function () { gestureTouchStart: CoreTest.stub('gestureTouchStart', SC.Gesturable.gestureTouchStart) }); - var touch = SC.Touch.create({ identifier: 'test-touch' }, this); + var testTouch = SC.Touch.create({ identifier: 'test-touch' }, this); - view.touchStart(touch); + view.touchStart(testTouch); view.gestureTouchStart.expect(1); }); @@ -90,9 +90,10 @@ test("Method: touchesDragged", function () { gestureTouchesDragged: CoreTest.stub('gestureTouchesDragged', SC.Gesturable.gestureTouchesDragged) }); - var touch = SC.Touch.create({ identifier: 'test-touch' }, this); + var testTouch = SC.Touch.create({ identifier: 'test-touch' }, this); - view.touchesDragged({}, [touch]); + view.touchStart(testTouch); + view.touchesDragged({}, [testTouch]); view.gestureTouchesDragged.expect(1); }); @@ -107,47 +108,53 @@ test("Method: touchEnd", function () { gestureTouchEnd: CoreTest.stub('gestureTouchEnd', SC.Gesturable.gestureTouchEnd) }); - var touch = SC.Touch.create({ identifier: 'test-touch' }, this); + var testTouch = SC.Touch.create({ identifier: 'test-touch' }, this); - view.touchEnd(touch); + view.touchStart(testTouch); + view.touchEnd(testTouch); view.gestureTouchEnd.expect(1); }); -// This method initializes the isInteresting property of the touch and calls unassignedTouchDidStart +// This method initializes the _sc_interestedGestures & _sc_touchesInSession properties and calls touchSessionStarted // on each gesture. test("Method: gestureTouchStart", function () { var testTouch = SC.Touch.create({ identifier: 'test-touch' }, this); + testTouch._isSeen = 0; + view = view.create({ gestures: [ SC.Gesture.extend({ name: 'a', - unassignedTouchDidStart: function (aTouch) { + touchSessionStarted: function (aTouch) { equals(aTouch, testTouch, "The touch is passed to the gesture. The touch param is"); - equals(aTouch.isInteresting, 0, "The value of isInteresting is set on the touch to"); + equals(aTouch._isSeen, 0, "The value of _isSeen is set on the touch to"); - // Bump up isInteresting to assert the order of the gestures is correct. - aTouch.isInteresting = 1; + // Bump up _isSeen to assert the order of the gestures is correct. + aTouch._isSeen = 1; } }), SC.Gesture.extend({ name: 'b', - unassignedTouchDidStart: function (aTouch) { + touchSessionStarted: function (aTouch) { equals(aTouch, testTouch, "The touch is passed to the gesture. The touch param is"); - equals(aTouch.isInteresting, 1, "The value of isInteresting is set on the touch to"); + equals(aTouch._isSeen, 1, "The value of _isSeen is set on the touch to"); } })] }); - view.gestureTouchStart(testTouch); + equals(view.gestureTouchStart(testTouch), true, "The method returns"); + + same(view._sc_interestedGestures, view.gestures, "The value of view._sc_interestedGestures is"); + same(view._sc_touchesInSession, [testTouch], "The value of view._sc_touchesInSession is"); - // Ensure 4 tests run. - expect(4); + // Ensure 7 tests run. + expect(7); }); -// This method calls unassignedTouchesDidChange on each gesture. +// This method calls touchesMovedInSession on each gesture. test("Method: gestureTouchesDragged", function () { var testTouch = SC.Touch.create({ identifier: 'test-touch' }, this); @@ -156,27 +163,28 @@ test("Method: gestureTouchesDragged", function () { SC.Gesture.extend({ name: 'a', - unassignedTouchesDidChange: function (evt, touches) { + touchesMovedInSession: function (touches) { same(touches, [testTouch], "The touches are passed to the gesture. The touches param is"); } }), SC.Gesture.extend({ name: 'b', - unassignedTouchesDidChange: function (evt, touches) { + touchesMovedInSession: function (touches) { same(touches, [testTouch], "The touches are passed to the gesture. The touches param is"); } })] }); - view.gestureTouchesDragged({}, [testTouch]); + view.gestureTouchStart(testTouch); + equals(view.gestureTouchesDragged({}, [testTouch]), undefined, "The method returns"); - // Ensure 2 tests run. - expect(2); + // Ensure 3 tests run. + expect(3); }); -// This method calls unassignedTouchDidEnd on each gesture. +// This method calls touchEndedInSession on each gesture. test("Method: gestureTouchEnd", function () { var testTouch = SC.Touch.create({ identifier: 'test-touch' }, this); @@ -185,22 +193,23 @@ test("Method: gestureTouchEnd", function () { SC.Gesture.extend({ name: 'a', - unassignedTouchDidEnd: function (touch) { + touchEndedInSession: function (touch) { equals(touch, testTouch, "The touch is passed to the gesture. The touch param is"); } }), SC.Gesture.extend({ name: 'b', - unassignedTouchDidEnd: function (touch) { + touchEndedInSession: function (touch) { equals(touch, testTouch, "The touch is passed to the gesture. The touch param is"); console.log(touch); } })] }); - view.gestureTouchEnd(testTouch); + view.gestureTouchStart(testTouch); + equals(view.gestureTouchEnd(testTouch), undefined, "The method returns"); - // Ensure 2 tests run. - expect(2); + // Ensure 3 tests run. + expect(3); });