Skip to content

Instantly share code, notes, and snippets.

@jeffreytgilbert
Created October 17, 2013 16:29
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jeffreytgilbert/7027985 to your computer and use it in GitHub Desktop.
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 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