// ========================================================================== // Project: SproutCore
- JavaScript Application Framework // Copyright: ©2006-2014 Strobe Inc. and contributors. // portions copyright @2011 Apple Inc. // License: Licensed under MIT license (see license.js) // ========================================================================== /*global module, test, ok, equals */
var pane,
// TODO: This custom event counting could/should be replaced with CoreTest.stub. outerCapture = 0, outerStart = 0, outerDragged = 0, outerCancel = 0, outerEnd = 0, innerStart = 0, innerDragged = 0, innerCancel = 0, innerEnd = 0;
module(“SC.View#captureTouch”, {
setup: function() { SC.run(function() { pane = SC.Pane.create({ layout: { width: 200, height: 200, left: 0, top: 0 }, childViews: ['outerView'], outerView: SC.View.extend({ captureTouch: function() { outerCapture++; return YES; }, touchStart: function() { outerStart++; return YES; }, // When touch is dragged, this passes control of the touch to the inner view. touchesDragged: function(evt, viewTouches) { outerDragged++; viewTouches.forEach(function(touch) { touch.stackNextTouchResponder(this.innerView); }, this); }, touchCancelled: function() { outerCancel++; }, touchEnd: function() { outerEnd++; }, childViews: ['innerView'], innerView: SC.View.extend({ layout: { width: 50, height: 50, left: 100, top: 100 }, touchStart: function() { innerStart++; }, // When touch is dragged, this passes control of the touch BACK to the outer view. touchesDragged: function(evt, viewTouches) { innerDragged++; viewTouches.invoke('restoreLastTouchResponder'); }, touchCancelled: function() { innerCancel++; }, touchEnd: function() { innerEnd++; } }) }) }).append(); }); }, teardown: function() { pane.remove(); pane = null; }
});
test(“Touch event handling and juggling.”, function() {
var outer = pane.outerView, inner = outer.innerView, layer = inner.get('layer'), event = SC.Event.simulateEvent(layer, 'touchstart'), touch; event.touches = []; event.identifier = 4; event.changedTouches = [event]; // Trigger touchstart: outerView.captureTouch > outerView.touchStart SC.Event.trigger(layer, 'touchstart', [event]); equals(outerCapture, 1, "To capture the initial touch, outerView.captureTouch should have run:"); equals(outerStart, 1, "Having captured the initial touch, outerView.touchStart should have run:"); if (innerStart) ok(false, "outerView.innerStart should not have been called yet!"); if (outerDragged) ok(false, "outerView.touchesDragged should not have been called yet!"); if (innerDragged) ok(false, "innerView.touchesDragged should not have been called yet!"); if (outerCancel) ok(false, "outerView.touchCancelled should not have been called yet!"); if (innerCancel) ok(false, "innerView.touchCancelled should not have been called yet!"); if (innerEnd) ok(false, "innerView.touchEnd should not have been called yet!"); if (outerEnd) ok(false, "outerView.touchEnd should not have been called yet!"); // Trigger touchmoved: outerView.touchesDragged > [passes touch to innerView] > innerView.touchStart // Copy the last DOM touch as the basis of an updated DOM touch. touch = SC.RootResponder.responder._touches[event.identifier]; touch = SC.copy(touch); event = SC.Event.simulateEvent(layer, 'touchmove', { touches: [touch], identifier: 4, changedTouches: [touch] }); SC.Event.trigger(layer, 'touchmove', [event]); if (outerCapture !== 1) ok(false, "outerView.captureTouch should only have been called once!"); if (outerStart !== 1) ok(false, "outerView.touchStart should only have been called once!"); equals(outerDragged, 1, "Having captured the initial touch, outerView.touchesDragged should have been called:"); equals(outerCancel, 0, "Having given up ownership but not removed itself from the stack, outerView.touchCancelled should not have been called:"); equals(innerStart, 1, "Having been passed touch ownership by outerView, innerView.touchesStart should have been called:"); if (innerDragged) ok(false, "innerView.touchesDragged should not have been called yet!"); if (innerCancel) ok(false, "innerView.touchCancelled should not have been called yet!"); if (innerEnd) ok(false, "innerView.touchEnd should not have been called yet!"); if (outerEnd) ok(false, "outerView.touchEnd should not have been called yet!"); // Trigger touchmoved x2: innerView.touchesDragged > [passes touch back to outerView] > outerView.touchStart > innerView.touchCancelled // Copy the last DOM touch as the basis of an updated DOM touch. touch = SC.RootResponder.responder._touches[event.identifier]; touch = SC.copy(touch); event = SC.Event.simulateEvent(layer, 'touchmove', { touches: [touch], identifier: 4, changedTouches: [touch] }); SC.Event.trigger(layer, 'touchmove', [event]); if (outerCapture !== 1) ok(false, "outerView.captureTouch should only have been called once!"); equals(outerDragged, 1, "Having passed ownership to innerView, outerView.touchesDragged should not have been called again:"); if (outerStart !== 1) ok(false, "Even having retaken ownership of the touch, outerView.touchStart should only have been called once!"); if (innerStart !== 1) ok(false, "innerView.touchStart should only have been called once!"); equals(innerDragged, 1, "Now having ownership of the touch, innerView.touchesDragged should have been called:"); if (outerCancel) ok(false, "Having never been removed from the touch responder stack, outerView.touchCancelled should not have been called!"); equals(innerCancel, 1, "Having passed ownership permanently back to outerView, innerView.touchCancelled should have been called:"); if (innerEnd) ok(false, "innerView.touchEnd should not have been called yet!"); if (outerEnd) ok(false, "outerView.touchEnd should not have been called yet!"); // Trigger touchend: outerView.touchEnd // Copy the last DOM touch as the basis of an updated DOM touch. touch = SC.RootResponder.responder._touches[event.identifier]; touch = SC.copy(touch); event = SC.Event.simulateEvent(layer, 'touchend', { touches: [touch], identifier: 4, changedTouches: [touch] }); SC.Event.trigger(layer, 'touchend', [event]); if (outerCapture !== 1) ok(false, "outerView.captureTouch should only have been called once!"); if (outerStart !== 1) ok(false, "outerView.touchStart should only have been called once!"); if (innerStart !== 1) ok(false, "innerView.touchStart should only have been called once!"); if (outerDragged !== 1) ok(false, "outerView.touchesDragged should only have been called once!"); if (innerDragged !== 1) ok(false, "innerView.touchesDragged should only have been called once!"); if (innerCancel !== 1) ok(false, "innerView.touchCancelled should only have been called once!"); equals(outerCancel, 0, "Having never been removed from the touch's responder stack, outerView.touchCancelled should never have been called."); equals(innerEnd, 0, "Having previously given up control of the touch, innerView.touchEnd should never have been called:"); equals(outerEnd, 1, "outerView.touchEnd should have been called:");
});
module(“SC.Touch”, { });
/* Class Methods */
// This method creates a new SC
.Touch. test(“Class Method: create”, function () {
equals(SC.Touch.create({ identifier: 'test-touch' }).constructor, SC.Touch.prototype.constructor, "The method returns instance of type");
});
// This method returns the average of all the given touches. test(“Class Method: averagedTouch”, function () {
var touch1 = SC.Touch.create({ identifier: 'touch-1', pageX: 0, pageY: 0, velocityX: 0, velocityY: 0 }), touch2 = SC.Touch.create({ identifier: 'touch-2', pageX: 100, pageY: 100, velocityX: 0, velocityY: 0 }), touch3 = SC.Touch.create({ identifier: 'touch-3', pageX: 200, pageY: 200, velocityX: 0, velocityY: 0 }), avgTouch; // Test two touches. avgTouch = SC.Touch.averagedTouch([touch1, touch2]); equals(avgTouch.x.toFixed(1), '50.0', "The value of x is"); equals(avgTouch.y.toFixed(1), '50.0', "The value of y is"); equals(avgTouch.velocityX.toFixed(1), '0.0', "The value of velocityX is"); equals(avgTouch.velocityY.toFixed(1), '0.0', "The value of velocityY is"); equals(avgTouch.d.toFixed(1), '70.7', "The value of d is"); // Test two touches in reverse. avgTouch = SC.Touch.averagedTouch([touch2, touch1]); equals(avgTouch.x.toFixed(1), '50.0', "The value of x is"); equals(avgTouch.y.toFixed(1), '50.0', "The value of y is"); equals(avgTouch.velocityX.toFixed(1), '0.0', "The value of velocityX is"); equals(avgTouch.velocityY.toFixed(1), '0.0', "The value of velocityY is"); equals(avgTouch.d.toFixed(1), '70.7', "The value of d is"); // Test three touches. avgTouch = SC.Touch.averagedTouch([touch1, touch2, touch3]); equals(avgTouch.x.toFixed(1), '100.0', "The value of x is"); equals(avgTouch.y.toFixed(1), '100.0', "The value of y is"); equals(avgTouch.velocityX.toFixed(1), '0.0', "The value of velocityX is"); equals(avgTouch.velocityY.toFixed(1), '0.0', "The value of velocityY is"); equals(avgTouch.d.toFixed(1), '94.3', "The value of d is"); // Test three touches in different order. avgTouch = SC.Touch.averagedTouch([touch2, touch3, touch1]); equals(avgTouch.x.toFixed(1), '100.0', "The value of x is"); equals(avgTouch.y.toFixed(1), '100.0', "The value of y is"); equals(avgTouch.velocityX.toFixed(1), '0.0', "The value of velocityX is"); equals(avgTouch.velocityY.toFixed(1), '0.0', "The value of velocityY is"); equals(avgTouch.d.toFixed(1), '94.3', "The value of d is");
});
/* Properties */
test(“Default Properties:”, function () {
var touch = SC.Touch.create({ identifier: 'test-touch' }); equals(touch.identifier, 'test-touch', "The default value of identifier is");
});
/* Methods */
// This method registers _sc_pinchAnchorScale to the value of the view's scale. test(“Method: touchSessionStarted”, function () { });