From 98e7e1aa87ef6fddc01443faa447a7f72f56994d Mon Sep 17 00:00:00 2001 From: Adam Bradley Date: Tue, 11 Mar 2014 16:20:15 -0500 Subject: [PATCH] fix(tap): Do not trigger a click if the element was scrolled after touchstart/mousedown --- js/ext/angular/test/list.html | 17 ++++++++++-- js/utils/poly.js | 51 ++++++++++++++++++++++++++++------- 2 files changed, 57 insertions(+), 11 deletions(-) diff --git a/js/ext/angular/test/list.html b/js/ext/angular/test/list.html index a60a05e8773..a0a44f0eef5 100644 --- a/js/ext/angular/test/list.html +++ b/js/ext/angular/test/list.html @@ -67,11 +67,20 @@ .my-repeat-animation > .ng-move.ng-move-active { opacity:1; } + #click-notify { + position: absolute; + z-index: 9999; + background: red; + min-width: 50px; + left: 48%; + top: 150px; + display: none; + } - +
CLICK!
@@ -211,7 +220,11 @@

YELLOW {{slideBox.slideIndex}}

$scope.itemClick = function() { - console.debug('itemClick'); + console.info('itemClick'); + document.getElementById('click-notify').style.display = 'block'; + setTimeout(function(){ + document.getElementById('click-notify').style.display = 'none'; + }, 500); }; // Item Methods/Properties diff --git a/js/utils/poly.js b/js/utils/poly.js index aa9f1744785..83f5e46f795 100644 --- a/js/utils/poly.js +++ b/js/utils/poly.js @@ -148,16 +148,30 @@ } function preventGhostClick(e) { - if(e.target.control) { - // this is a label that has an associated input - // the native layer will send the actual event, so stop this one - console.debug('preventGhostClick', 'label'); - return stopEvent(e); - } - if( isRecentTap(e) ) { - // a tap has already happened at these coordinates recently, ignore this event - console.debug('preventGhostClick', 'isRecentTap', e.target.tagName); + console.debug((function(){ + // Great for debugging, and thankfully this gets removed from the build, OMG it's ugly + + if(e.target.control) { + // this is a label that has an associated input + // the native layer will send the actual event, so stop this one + console.debug('preventGhostClick', 'label'); + + } else if(isRecentTap(e)) { + // a tap has already happened at these coordinates recently, ignore this event + console.debug('preventGhostClick', 'isRecentTap', e.target.tagName); + + } else if(isScrolledSinceStart(e)) { + // this click's coordinates are different than its touchstart/mousedown, must have been scrolling + console.debug('preventGhostClick', 'isScrolledSinceStart, startCoordinates, x:' + startCoordinates.x + ' y:' + startCoordinates.y); + } + + var c = getCoordinates(e); + return 'click at x:' + c.x + ', y:' + c.y; + })()); + + + if(e.target.control || isRecentTap(e) || isScrolledSinceStart(e)) { return stopEvent(e); } @@ -184,6 +198,16 @@ } } + function isScrolledSinceStart(event) { + // check if this click's coordinates are different than its touchstart/mousedown + var c = getCoordinates(event); + + return (c.x > startCoordinates.x + HIT_RADIUS || + c.x < startCoordinates.x - HIT_RADIUS || + c.y > startCoordinates.y + HIT_RADIUS || + c.y < startCoordinates.y - HIT_RADIUS); + } + function recordCoordinates(event) { var c = getCoordinates(event); if(c.x && c.y) { @@ -242,7 +266,12 @@ } } + function recordStartCoordinates(e) { + startCoordinates = getCoordinates(e); + } + var tapCoordinates = {}; // used to remember coordinates to ignore if they happen again quickly + var startCoordinates = {}; // used to remember where the coordinates of the start of the tap var CLICK_PREVENT_DURATION = 1500; // max milliseconds ghostclicks in the same area should be prevented var REMOVE_PREVENT_DELAY = 375; // delay after a touchend/mouseup before removing the ghostclick prevent var HIT_RADIUS = 15; @@ -257,4 +286,8 @@ document.addEventListener('touchend', removeClickPrevent, false); document.addEventListener('mouseup', removeClickPrevent, false); + // in the case the user touched the screen, then scrolled, it shouldn't fire the click + document.addEventListener('touchstart', recordStartCoordinates, false); + document.addEventListener('mousedown', recordStartCoordinates, false); + })(this, document, ionic);