// @author Rich Adams // Implements a tap and hold functionality. If you click/tap and release, it will trigger a normal // click event. But if you click/tap and hold for 1s (default), it will trigger a taphold event instead. ;(function($) { // Default options var defaults = { duration: 1000, // ms clickHandler: null }; // When start of a taphold event is triggered. function startHandler(event) { var $elem = jQuery(this); // Merge the defaults and any user defined settings. settings = jQuery.extend({}, defaults, event.data); // If object also has click handler, store it and unbind. Taphold will trigger the // click itself, rather than normal propagation. if (typeof $elem.data("events") != "undefined" && typeof $elem.data("events").click != "undefined") { // Find the one without a namespace defined. for (var c in $elem.data("events").click) { if ($elem.data("events").click[c].namespace == "") { var handler = $elem.data("events").click[c].handler; $elem.data("taphold_click_handler", handler); $elem.unbind("click", handler); break; } } } // Otherwise, if a custom click handler was explicitly defined, then store it instead. else if (typeof settings.clickHandler == "function") { $elem.data("taphold_click_handler", settings.clickHandler); } // Reset the flags $elem.data("taphold_triggered", false); // If a hold was triggered $elem.data("taphold_clicked", false); // If a click was triggered $elem.data("taphold_cancelled", false); // If event has been cancelled. // Set the timer for the hold event. $elem.data("taphold_timer", setTimeout(function() { // If event hasn't been cancelled/clicked already, then go ahead and trigger the hold. if (!$elem.data("taphold_cancelled") && !$elem.data("taphold_clicked")) { // Trigger the hold event, and set the flag to say it's been triggered. $elem.trigger(jQuery.extend(event, jQuery.Event("taphold"))); $elem.data("taphold_triggered", true); } }, settings.duration)); } // When user ends a tap or click, decide what we should do. function stopHandler(event) { var $elem = jQuery(this); // If taphold has been cancelled, then we're done. if ($elem.data("taphold_cancelled")) { return; } // Clear the hold timer. If it hasn't already triggered, then it's too late anyway. clearTimeout($elem.data("taphold_timer")); // If hold wasn't triggered and not already clicked, then was a click event. if (!$elem.data("taphold_triggered") && !$elem.data("taphold_clicked")) { // If click handler, trigger it. if (typeof $elem.data("taphold_click_handler") == "function") { $elem.data("taphold_click_handler")(jQuery.extend(event, jQuery.Event("click"))); } // Set flag to say we've triggered the click event. $elem.data("taphold_clicked", true); } } // If a user prematurely leaves the boundary of the object we're working on. function leaveHandler(event) { // Cancel the event. $(this).data("taphold_cancelled", true); } // Determine if touch events are supported. var touchSupported = ("ontouchstart" in window) // Most browsers || ("onmsgesturechange" in window); // Microsoft var taphold = $.event.special.taphold = { setup: function(data) { $(this).bind((touchSupported ? "touchstart" : "mousedown"), data, startHandler) .bind((touchSupported ? "touchend" : "mouseup"), stopHandler) .bind((touchSupported ? "touchmove touchcancel" : "mouseleave"), leaveHandler); }, teardown: function(namespaces) { $(this).unbind((touchSupported ? "touchstart" : "mousedown"), startHandler) .unbind((touchSupported ? "touchend" : "mouseup"), stopHandler) .unbind((touchSupported ? "touchmove touchcancel" : "mouseleave"), leaveHandler); } }; })(jQuery);