jquery.ui.touch.js 6.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. /**
  2. * jQuery.UI.iPad plugin
  3. * Copyright (c) 2010 Stephen von Takach
  4. * licensed under MIT.
  5. * Date: 27/8/2010
  6. *
  7. * Project Home:
  8. * http://code.google.com/p/jquery-ui-for-ipad-and-iphone/
  9. *
  10. * Modified: 19/01/2012
  11. * Organized as a proper plugin and added addTouch()
  12. */
  13. (function ($) {
  14. var lastTap = null, // Holds last tapped element (so we can compare for double tap)
  15. tapValid = false, // Are we still in the .6 second window where a double tap can occur
  16. tapTimeout = null, // The timeout reference
  17. rightClickPending = false, // Is a right click still feasible
  18. rightClickEvent = null, // the original event
  19. holdTimeout = null, // timeout reference
  20. cancelMouseUp = false, // prevents a click from occurring as we want the context menu
  21. currentDOMElement = null; // the last DOM element that was seen during a drag.
  22. function cancelTap() {
  23. tapValid = false;
  24. }
  25. function cancelHold() {
  26. if (rightClickPending) {
  27. window.clearTimeout(holdTimeout);
  28. rightClickPending = false;
  29. rightClickEvent = null;
  30. }
  31. }
  32. function startHold(event) {
  33. if (rightClickPending) {
  34. return;
  35. }
  36. rightClickPending = true; // We could be performing a right click
  37. rightClickEvent = (event.changedTouches)[0];
  38. holdTimeout = window.setTimeout(doRightClick, 800);
  39. }
  40. function doRightClick() {
  41. rightClickPending = false;
  42. // We need to mouse up (as we were down)
  43. var first = rightClickEvent,
  44. simulatedEvent = document.createEvent("MouseEvent");
  45. simulatedEvent.initMouseEvent("mouseup", true, true, window, 1, first.screenX, first.screenY, first.clientX, first.clientY, false, false, false, false, 0, null);
  46. first.target.dispatchEvent(simulatedEvent);
  47. // Emulate a right click
  48. simulatedEvent = document.createEvent("MouseEvent");
  49. simulatedEvent.initMouseEvent("mousedown", true, true, window, 1, first.screenX, first.screenY, first.clientX, first.clientY, false, false, false, false, 2, null);
  50. first.target.dispatchEvent(simulatedEvent);
  51. // Show a context menu
  52. simulatedEvent = document.createEvent("MouseEvent");
  53. 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);
  54. first.target.dispatchEvent(simulatedEvent);
  55. simulatedEvent = document.createEvent("MouseEvent");
  56. 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);
  57. first.target.dispatchEvent(simulatedEvent);
  58. cancelMouseUp = true;
  59. rightClickEvent = null; // Release memory
  60. }
  61. // mouse over event then mouse down
  62. function iPadTouchStart(event) {
  63. var touches = event.changedTouches,
  64. first = touches[0],
  65. type = "mouseover",
  66. simulatedEvent = document.createEvent("MouseEvent");
  67. // Mouse over first - I have live events attached on mouse over
  68. simulatedEvent.initMouseEvent(type, true, true, window, 1, first.screenX, first.screenY, first.clientX, first.clientY, false, false, false, false, 0, null);
  69. first.target.dispatchEvent(simulatedEvent);
  70. type = "mousedown";
  71. simulatedEvent = document.createEvent("MouseEvent");
  72. simulatedEvent.initMouseEvent(type, true, true, window, 1, first.screenX, first.screenY, first.clientX, first.clientY, false, false, false, false, 0, null);
  73. first.target.dispatchEvent(simulatedEvent);
  74. if (!tapValid) {
  75. lastTap = first.target;
  76. tapValid = true;
  77. tapTimeout = window.setTimeout(cancelTap, 600);
  78. startHold(event);
  79. } else {
  80. window.clearTimeout(tapTimeout);
  81. // If a double tap is still a possibility and the elements are the same then perform a double click
  82. if (first.target == lastTap) {
  83. lastTap = null;
  84. tapValid = false;
  85. type = "click";
  86. simulatedEvent = document.createEvent("MouseEvent");
  87. simulatedEvent.initMouseEvent(type, true, true, window, 1, first.screenX, first.screenY, first.clientX, first.clientY, false, false, false, false, 0, null);
  88. first.target.dispatchEvent(simulatedEvent);
  89. type = "dblclick";
  90. simulatedEvent = document.createEvent("MouseEvent");
  91. simulatedEvent.initMouseEvent(type, true, true, window, 1, first.screenX, first.screenY, first.clientX, first.clientY, false, false, false, false, 0, null);
  92. first.target.dispatchEvent(simulatedEvent);
  93. } else {
  94. lastTap = first.target;
  95. tapValid = true;
  96. tapTimeout = window.setTimeout(cancelTap, 600);
  97. startHold(event);
  98. }
  99. }
  100. }
  101. function getDOMElementFromEvent(event) {
  102. if (event.targetTouches && event.targetTouches[0]) {
  103. return document.elementFromPoint(event.targetTouches[0].pageX - window.pageXOffset, event.targetTouches[0].pageY - window.pageYOffset);
  104. }
  105. return null;
  106. }
  107. function iPadTouchHandler(event) {
  108. var type = "",
  109. button = 0; /*left*/
  110. if (event.touches.length > 1) {
  111. return;
  112. }
  113. switch (event.type) {
  114. case "touchstart":
  115. if ($(event.changedTouches[0].target).is("select")) {
  116. return;
  117. }
  118. iPadTouchStart(event); /*We need to trigger two events here to support one touch drag and drop*/
  119. event.preventDefault();
  120. currentDOMElement = getDOMElementFromEvent(event);
  121. return false;
  122. case "touchmove":
  123. cancelHold();
  124. type = "mousemove";
  125. event.preventDefault();
  126. currentDOMElement = getDOMElementFromEvent(event);
  127. break;
  128. case "touchend":
  129. if (cancelMouseUp) {
  130. cancelMouseUp = false;
  131. event.preventDefault();
  132. return false;
  133. }
  134. cancelHold();
  135. type = "mouseup";
  136. break;
  137. default:
  138. return;
  139. }
  140. var touches = event.changedTouches,
  141. first = touches[0],
  142. simulatedEvent = document.createEvent("MouseEvent");
  143. simulatedEvent.initMouseEvent(type, true, true, window, 1, first.screenX, first.screenY, first.clientX, first.clientY,false, false, false, false, button, null);
  144. currentDOMElement.dispatchEvent(simulatedEvent);
  145. if (type == "mouseup" && tapValid && first.target == lastTap) { // This actually emulates the ipad's default behavior (which we prevented)
  146. simulatedEvent = document.createEvent("MouseEvent"); // This check avoids click being emulated on a double tap
  147. simulatedEvent.initMouseEvent("click", true, true, window, 1, first.screenX, first.screenY, first.clientX, first.clientY,false, false, false, false, button, null);
  148. currentDOMElement.dispatchEvent(simulatedEvent);
  149. }
  150. }
  151. $.extend($.support, {
  152. touch: "ontouchend" in document
  153. });
  154. $.fn.addTouch = function () {
  155. if ($.support.touch) {
  156. this.each(function (i, el) {
  157. el.addEventListener("touchstart", iPadTouchHandler, false);
  158. el.addEventListener("touchmove", iPadTouchHandler, false);
  159. el.addEventListener("touchend", iPadTouchHandler, false);
  160. el.addEventListener("touchcancel", iPadTouchHandler, false);
  161. });
  162. }
  163. return this;
  164. };
  165. })(jQuery);