/** * jQuery.UI.iPad plugin * Copyright (c) 2010 Stephen von Takach * licensed under MIT. * Date: 27/8/2010 * * Project Home: * http://code.google.com/p/jquery-ui-for-ipad-and-iphone/ * * Modified: 19/01/2012 * Organized as a proper plugin and added addTouch() */ (function ($) { var lastTap = null, // Holds last tapped element (so we can compare for double tap) tapValid = false, // Are we still in the .6 second window where a double tap can occur tapTimeout = null, // The timeout reference rightClickPending = false, // Is a right click still feasible rightClickEvent = null, // the original event holdTimeout = null, // timeout reference cancelMouseUp = false, // prevents a click from occurring as we want the context menu currentDOMElement = null; // the last DOM element that was seen during a drag. function cancelTap() { tapValid = false; } function cancelHold() { if (rightClickPending) { window.clearTimeout(holdTimeout); rightClickPending = false; rightClickEvent = null; } } function startHold(event) { if (rightClickPending) { return; } rightClickPending = true; // We could be performing a right click rightClickEvent = (event.changedTouches)[0]; holdTimeout = window.setTimeout(doRightClick, 800); } function doRightClick() { rightClickPending = false; // We need to mouse up (as we were down) var first = rightClickEvent, simulatedEvent = document.createEvent("MouseEvent"); simulatedEvent.initMouseEvent("mouseup", true, true, window, 1, first.screenX, first.screenY, first.clientX, first.clientY, false, false, false, false, 0, null); first.target.dispatchEvent(simulatedEvent); // Emulate a right click simulatedEvent = document.createEvent("MouseEvent"); simulatedEvent.initMouseEvent("mousedown", true, true, window, 1, first.screenX, first.screenY, first.clientX, first.clientY, false, false, false, false, 2, null); first.target.dispatchEvent(simulatedEvent); // Show a context menu simulatedEvent = document.createEvent("MouseEvent"); simulatedEvent.initMouseEvent("contextmenu", true, true, window, 1, first.screenX + 50, first.screenY + 5, first.clientX + 50, first.clientY + 5, false, false, false, false, 2, null); first.target.dispatchEvent(simulatedEvent); simulatedEvent = document.createEvent("MouseEvent"); simulatedEvent.initMouseEvent("mouseup", true, true, window, 1, first.screenX + 50, first.screenY + 5, first.clientX + 50, first.clientY + 5, false, false, false, false, 2, null); first.target.dispatchEvent(simulatedEvent); cancelMouseUp = true; rightClickEvent = null; // Release memory } // mouse over event then mouse down function iPadTouchStart(event) { var touches = event.changedTouches, first = touches[0], type = "mouseover", simulatedEvent = document.createEvent("MouseEvent"); // Mouse over first - I have live events attached on mouse over simulatedEvent.initMouseEvent(type, true, true, window, 1, first.screenX, first.screenY, first.clientX, first.clientY, false, false, false, false, 0, null); first.target.dispatchEvent(simulatedEvent); type = "mousedown"; simulatedEvent = document.createEvent("MouseEvent"); simulatedEvent.initMouseEvent(type, true, true, window, 1, first.screenX, first.screenY, first.clientX, first.clientY, false, false, false, false, 0, null); first.target.dispatchEvent(simulatedEvent); if (!tapValid) { lastTap = first.target; tapValid = true; tapTimeout = window.setTimeout(cancelTap, 600); startHold(event); } else { window.clearTimeout(tapTimeout); // If a double tap is still a possibility and the elements are the same then perform a double click if (first.target == lastTap) { lastTap = null; tapValid = false; type = "click"; simulatedEvent = document.createEvent("MouseEvent"); simulatedEvent.initMouseEvent(type, true, true, window, 1, first.screenX, first.screenY, first.clientX, first.clientY, false, false, false, false, 0, null); first.target.dispatchEvent(simulatedEvent); type = "dblclick"; simulatedEvent = document.createEvent("MouseEvent"); simulatedEvent.initMouseEvent(type, true, true, window, 1, first.screenX, first.screenY, first.clientX, first.clientY, false, false, false, false, 0, null); first.target.dispatchEvent(simulatedEvent); } else { lastTap = first.target; tapValid = true; tapTimeout = window.setTimeout(cancelTap, 600); startHold(event); } } } function getDOMElementFromEvent(event) { if (event.targetTouches && event.targetTouches[0]) { return document.elementFromPoint(event.targetTouches[0].pageX - window.pageXOffset, event.targetTouches[0].pageY - window.pageYOffset); } return null; } function iPadTouchHandler(event) { var type = "", button = 0; /*left*/ if (event.touches.length > 1) { return; } switch (event.type) { case "touchstart": if ($(event.changedTouches[0].target).is("select")) { return; } iPadTouchStart(event); /*We need to trigger two events here to support one touch drag and drop*/ event.preventDefault(); currentDOMElement = getDOMElementFromEvent(event); return false; case "touchmove": cancelHold(); type = "mousemove"; event.preventDefault(); currentDOMElement = getDOMElementFromEvent(event); break; case "touchend": if (cancelMouseUp) { cancelMouseUp = false; event.preventDefault(); return false; } cancelHold(); type = "mouseup"; break; default: return; } var touches = event.changedTouches, first = touches[0], simulatedEvent = document.createEvent("MouseEvent"); simulatedEvent.initMouseEvent(type, true, true, window, 1, first.screenX, first.screenY, first.clientX, first.clientY,false, false, false, false, button, null); currentDOMElement.dispatchEvent(simulatedEvent); if (type == "mouseup" && tapValid && first.target == lastTap) { // This actually emulates the ipad's default behavior (which we prevented) simulatedEvent = document.createEvent("MouseEvent"); // This check avoids click being emulated on a double tap simulatedEvent.initMouseEvent("click", true, true, window, 1, first.screenX, first.screenY, first.clientX, first.clientY,false, false, false, false, button, null); currentDOMElement.dispatchEvent(simulatedEvent); } } $.extend($.support, { touch: "ontouchend" in document }); $.fn.addTouch = function () { if ($.support.touch) { this.each(function (i, el) { el.addEventListener("touchstart", iPadTouchHandler, false); el.addEventListener("touchmove", iPadTouchHandler, false); el.addEventListener("touchend", iPadTouchHandler, false); el.addEventListener("touchcancel", iPadTouchHandler, false); }); } return this; }; })(jQuery);