diff --git a/src/ngScenario/browserTrigger.js b/src/ngScenario/browserTrigger.js index 35aa54aad93e..bcbdb27acc29 100644 --- a/src/ngScenario/browserTrigger.js +++ b/src/ngScenario/browserTrigger.js @@ -77,6 +77,8 @@ evnt.initAnimationEvent(eventType, null, null, null, eventData.elapsedTime || 0); } } + } else if (/touch/.test(eventType) && supportsTouchEvents()) { + evnt = createTouchEvent(element, eventType, x, y); } else { evnt = document.createEvent('MouseEvents'); x = x || 0; @@ -112,4 +114,37 @@ return finalProcessDefault; }; + + function supportsTouchEvents() { + if ('_cached' in supportsTouchEvents) { + return supportsTouchEvents._cached; + } + if (!document.createTouch || !document.createTouchList) { + supportsTouchEvents._cached = false; + return false; + } + try { + document.createEvent('TouchEvent'); + } catch (e) { + supportsTouchEvents._cached = false; + return false; + } + supportsTouchEvents._cached = true; + return true; + } + + function createTouchEvent(element, eventType, x, y) { + var evnt = document.createEvent('TouchEvent'); + x = x || 0; + y = y || 0; + + var touch = document.createTouch(window, element, Date.now(), x, y, x, y); + var touches = document.createTouchList(touch); + var targetTouches = document.createTouchList(touch); + var changedTouches = document.createTouchList(touch); + + evnt.initTouchEvent(eventType, true, true, window, null, 0, 0, 0, 0, false, false, false, false, + touches, targetTouches, changedTouches, 1, 0); + return evnt; + } }()); diff --git a/src/ngTouch/directive/ngClick.js b/src/ngTouch/directive/ngClick.js index 90274aba7322..4d48f8e86a28 100644 --- a/src/ngTouch/directive/ngClick.js +++ b/src/ngTouch/directive/ngClick.js @@ -221,8 +221,10 @@ ngTouch.directive('ngClick', ['$parse', '$timeout', '$rootElement', startTime = Date.now(); - var touches = event.touches && event.touches.length ? event.touches : [event]; - var e = touches[0].originalEvent || touches[0]; + // Use jQuery originalEvent + var originalEvent = event.originalEvent || event; + var touches = originalEvent.touches && originalEvent.touches.length ? originalEvent.touches : [originalEvent]; + var e = touches[0]; touchStartX = e.clientX; touchStartY = e.clientY; }); @@ -238,9 +240,12 @@ ngTouch.directive('ngClick', ['$parse', '$timeout', '$rootElement', element.on('touchend', function(event) { var diff = Date.now() - startTime; - var touches = (event.changedTouches && event.changedTouches.length) ? event.changedTouches : - ((event.touches && event.touches.length) ? event.touches : [event]); - var e = touches[0].originalEvent || touches[0]; + // Use jQuery originalEvent + var originalEvent = event.originalEvent || event; + var touches = (originalEvent.changedTouches && originalEvent.changedTouches.length) ? + originalEvent.changedTouches : + ((originalEvent.touches && originalEvent.touches.length) ? originalEvent.touches : [originalEvent]); + var e = touches[0]; var x = e.clientX; var y = e.clientY; var dist = Math.sqrt(Math.pow(x - touchStartX, 2) + Math.pow(y - touchStartY, 2)); diff --git a/src/ngTouch/swipe.js b/src/ngTouch/swipe.js index 884e0800d83c..ff5416b2d51b 100644 --- a/src/ngTouch/swipe.js +++ b/src/ngTouch/swipe.js @@ -40,11 +40,9 @@ ngTouch.factory('$swipe', [function() { }; function getCoordinates(event) { - var touches = event.touches && event.touches.length ? event.touches : [event]; - var e = (event.changedTouches && event.changedTouches[0]) || - (event.originalEvent && event.originalEvent.changedTouches && - event.originalEvent.changedTouches[0]) || - touches[0].originalEvent || touches[0]; + var originalEvent = event.originalEvent || event; + var touches = originalEvent.touches && originalEvent.touches.length ? originalEvent.touches : [originalEvent]; + var e = (originalEvent.changedTouches && originalEvent.changedTouches[0]) || touches[0]; return { x: e.clientX, diff --git a/test/ngTouch/directive/ngClickSpec.js b/test/ngTouch/directive/ngClickSpec.js index 921c64578b2b..53b34db37dea 100644 --- a/test/ngTouch/directive/ngClickSpec.js +++ b/test/ngTouch/directive/ngClickSpec.js @@ -5,8 +5,8 @@ describe('ngClick (touch)', function() { // TODO(braden): Once we have other touch-friendly browsers on CI, allow them here. // Currently Firefox and IE refuse to fire touch events. - var chrome = /chrome/.test(navigator.userAgent.toLowerCase()); - if (!chrome) { + // Enable iPhone for manual testing. + if (!/chrome|iphone/i.test(navigator.userAgent)) { return; } @@ -48,6 +48,34 @@ describe('ngClick (touch)', function() { expect($rootScope.event).toBeDefined(); })); + if (window.jQuery) { + it('should not unwrap a jQuery-wrapped event object on click', inject(function($rootScope, $compile) { + element = $compile('
')($rootScope); + $rootScope.$digest(); + + browserTrigger(element, 'click', { + keys: [], + x: 10, + y: 10 + }); + expect($rootScope.event.originalEvent).toBeDefined(); + expect($rootScope.event.originalEvent.clientX).toBe(10); + expect($rootScope.event.originalEvent.clientY).toBe(10); + })); + + it('should not unwrap a jQuery-wrapped event object on touchstart/touchend', + inject(function($rootScope, $compile, $rootElement) { + element = $compile('
')($rootScope); + $rootElement.append(element); + $rootScope.$digest(); + + browserTrigger(element, 'touchstart'); + browserTrigger(element, 'touchend'); + + expect($rootScope.event.originalEvent).toBeDefined(); + })); + } + it('should not click if the touch is held too long', inject(function($rootScope, $compile, $rootElement) { element = $compile('
')($rootScope); @@ -463,6 +491,17 @@ describe('ngClick (touch)', function() { expect($rootScope.selection).toBe('initial'); }); + + + it('should blur the other element on click', function() { + var blurSpy = spyOn(otherElement, 'blur'); + touch(otherElement, 10, 10); + + time = 500; + click(label, 10, 10); + + expect(blurSpy).toHaveBeenCalled(); + }); }); }); diff --git a/test/ngTouch/swipeSpec.js b/test/ngTouch/swipeSpec.js index 416d9f5d632d..1135ba3c19d8 100644 --- a/test/ngTouch/swipeSpec.js +++ b/test/ngTouch/swipeSpec.js @@ -67,8 +67,8 @@ describe('$swipe', function() { if (restrictBrowsers) { // TODO(braden): Once we have other touch-friendly browsers on CI, allow them here. // Currently Firefox and IE refuse to fire touch events. - var chrome = /chrome/.test(navigator.userAgent.toLowerCase()); - if (!chrome) { + // Enable iPhone for manual testing. + if (!/chrome|iphone/i.test(navigator.userAgent)) { return; } }