Created
October 17, 2013 16:29
-
-
Save jeffreytgilbert/7027985 to your computer and use it in GitHub Desktop.
Mobile click detection without that pesky 300ms delay. Makes double clicking also work fine.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* This code was written by the FED team to handle fast taps between products on the browse results page. This was necessary because | |
* there is no native tap event, and jquery was doing some form of magic to handle taps with a timeout. Also, native click/mousedown handlers | |
* do not work because there is a 300ms delay in the mobile browser in order for them to detect if it is a click or double click or gesture | |
* but since we have doubleclick and singleclick code here and want a fast response, we use the touchstart and touchend events to detect if an item was clicked. | |
* We also measure the distance from the start of the tap to the end of the tap along with if the item was tapped on at any point to be able to see | |
* if this is a swipe gesture or a tap gesture so scrolling and swiping are unimpeded. There is a 10px tolerance added for movement of the finger during taps. | |
*/ | |
var SearchResultController = { | |
attachClickHandlers: function(){ | |
$('#results-list .result-item').each(function(index, element){ | |
var $element = $(element); | |
// on the touch start, mark the element tap start | |
element.addEventListener('touchstart',function(event){ | |
$element.data('touch-info',{ | |
touched:true, | |
origin:{ | |
x:event.pageX, | |
y:event.pageY | |
}, | |
destination:{ | |
x:event.pageX, | |
y:event.pageY | |
} | |
}); | |
}); | |
element.addEventListener('touchmove',function(event){ | |
var o = $element.data('touch-info'); | |
$element.data('touch-info',{ | |
touched:o.touched, | |
origin:o.origin, | |
destination:{ | |
x:event.pageX, | |
y:event.pageY | |
} | |
}); | |
}); | |
// on the touch end, check to see if the start happened here, and after the event is handled, set the touched data to false to restart the process | |
element.addEventListener('touchend',function(event){ | |
var o = $element.data('touch-info'), | |
a = 10, | |
lastClick = $element.data('last-click') || null; // allowed movement from origin in pixels | |
if(lastClick && new Date().getTime() - lastClick.getTime() < 800){ // 1000 miliseconds = 1 second tolerance for double tap | |
return SearchResultController.handleDoubleTap($element); | |
} | |
if(o.touched | |
&& (o.destination.x <= o.origin.x + a && o.destination.x >= o.origin.x - a) | |
&& (o.destination.y <= o.origin.y + a && o.destination.y >= o.origin.y - a) | |
){ | |
SearchResultController.handleTap($element); | |
} | |
$element.data('touched',{touched:false}); | |
$element.data('last-click',new Date()); | |
// reset other items click times so as soon as you click on another item, the click timer is reset for the other items | |
$('#results-list .result-item').not($element).data('last-click',null); | |
}); | |
// Register the click event so that other events broadcast. Without the click event, events are ignored | |
element.addEventListener('click',function(event){ | |
// however, this does need to have a failover option for desktop browsers. So if this is a desktop browser, behave the same as with the touchstart/touchend solution | |
if(!window.orientation){ | |
var lastClick = $element.data('last-click') || null; // allowed movement from origin in pixels | |
if(lastClick && new Date().getTime() - lastClick.getTime() < 800){ // 1000 miliseconds = 1 second tolerance for double tap | |
return SearchResultController.handleDoubleTap($element); | |
} | |
SearchResultController.handleTap($element); | |
$element.data('last-click',new Date()); | |
// reset other items click times so as soon as you click on another item, the click timer is reset for the other items | |
$('#results-list .result-item').not($element).data('last-click',null); | |
} | |
}); | |
}); | |
}, | |
handleTap: function($element){ | |
// handle single tap action | |
if($element.hasClass("selected")) { | |
$element.removeClass("selected"); | |
} else { | |
$element.addClass("selected"); | |
} | |
}, | |
removeClickHandlers: function(event){ | |
$('#results-list .result-item').each(function(index, element){ | |
element.removeEventListener('touchstart'); | |
element.removeEventListener('touchmove'); | |
element.removeEventListener('touchend'); | |
element.removeEventListener('click'); | |
}); | |
}, | |
handleDoubleTap: function($element){ | |
// do double tap action | |
} | |
}; | |
SearchResultController.attachClickHandlers(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment