touch.js 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. define("dojo/touch", ["./_base/kernel", "./aspect", "./dom", "./on", "./has", "./mouse", "./domReady", "./_base/window"],
  2. function(dojo, aspect, dom, on, has, mouse, domReady, win){
  3. // module:
  4. // dojo/touch
  5. var hasTouch = has("touch");
  6. // TODO: get iOS version from dojo/sniff after #15827 is fixed
  7. var ios4 = false;
  8. if(has("ios")){
  9. var ua = navigator.userAgent;
  10. var v = ua.match(/OS ([\d_]+)/) ? RegExp.$1 : "1";
  11. var os = parseFloat(v.replace(/_/, '.').replace(/_/g, ''));
  12. ios4 = os < 5;
  13. }
  14. // Time of most recent touchstart or touchmove event
  15. var lastTouch;
  16. function dualEvent(mouseType, touchType){
  17. // Returns synthetic event that listens for both the specified mouse event and specified touch event.
  18. // But ignore fake mouse events that were generated due to the user touching the screen.
  19. if(hasTouch){
  20. return function(node, listener){
  21. var handle1 = on(node, touchType, listener),
  22. handle2 = on(node, mouseType, function(evt){
  23. if(!lastTouch || (new Date()).getTime() > lastTouch + 1000){
  24. listener.call(this, evt);
  25. }
  26. });
  27. return {
  28. remove: function(){
  29. handle1.remove();
  30. handle2.remove();
  31. }
  32. };
  33. };
  34. }else{
  35. // Avoid creating listeners for touch events on performance sensitive older browsers like IE6
  36. return function(node, listener){
  37. return on(node, mouseType, listener);
  38. }
  39. }
  40. }
  41. var touchmove, hoveredNode;
  42. if(hasTouch){
  43. domReady(function(){
  44. // Keep track of currently hovered node
  45. hoveredNode = win.body(); // currently hovered node
  46. win.doc.addEventListener("touchstart", function(evt){
  47. lastTouch = (new Date()).getTime();
  48. // Precede touchstart event with touch.over event. DnD depends on this.
  49. // Use addEventListener(cb, true) to run cb before any touchstart handlers on node run,
  50. // and to ensure this code runs even if the listener on the node does event.stop().
  51. var oldNode = hoveredNode;
  52. hoveredNode = evt.target;
  53. on.emit(oldNode, "dojotouchout", {
  54. target: oldNode,
  55. relatedTarget: hoveredNode,
  56. bubbles: true
  57. });
  58. on.emit(hoveredNode, "dojotouchover", {
  59. target: hoveredNode,
  60. relatedTarget: oldNode,
  61. bubbles: true
  62. });
  63. }, true);
  64. // Fire synthetic touchover and touchout events on nodes since the browser won't do it natively.
  65. on(win.doc, "touchmove", function(evt){
  66. lastTouch = (new Date()).getTime();
  67. var newNode = win.doc.elementFromPoint(
  68. evt.pageX - (ios4 ? 0 : win.global.pageXOffset), // iOS 4 expects page coords
  69. evt.pageY - (ios4 ? 0 : win.global.pageYOffset)
  70. );
  71. if(newNode && hoveredNode !== newNode){
  72. // touch out on the old node
  73. on.emit(hoveredNode, "dojotouchout", {
  74. target: hoveredNode,
  75. relatedTarget: newNode,
  76. bubbles: true
  77. });
  78. // touchover on the new node
  79. on.emit(newNode, "dojotouchover", {
  80. target: newNode,
  81. relatedTarget: hoveredNode,
  82. bubbles: true
  83. });
  84. hoveredNode = newNode;
  85. }
  86. });
  87. });
  88. // Define synthetic touch.move event that unlike the native touchmove, fires for the node the finger is
  89. // currently dragging over rather than the node where the touch started.
  90. touchmove = function(node, listener){
  91. return on(win.doc, "touchmove", function(evt){
  92. if(node === win.doc || dom.isDescendant(hoveredNode, node)){
  93. evt.target = hoveredNode;
  94. listener.call(this, evt);
  95. }
  96. });
  97. };
  98. }
  99. //device neutral events - touch.press|move|release|cancel/over/out
  100. var touch = {
  101. press: dualEvent("mousedown", "touchstart"),
  102. move: dualEvent("mousemove", touchmove),
  103. release: dualEvent("mouseup", "touchend"),
  104. cancel: dualEvent(mouse.leave, "touchcancel"),
  105. over: dualEvent("mouseover", "dojotouchover"),
  106. out: dualEvent("mouseout", "dojotouchout"),
  107. enter: mouse._eventHandler(dualEvent("mouseover","dojotouchover")),
  108. leave: mouse._eventHandler(dualEvent("mouseout", "dojotouchout"))
  109. };
  110. /*=====
  111. touch = {
  112. // summary:
  113. // This module provides unified touch event handlers by exporting
  114. // press, move, release and cancel which can also run well on desktop.
  115. // Based on http://dvcs.w3.org/hg/webevents/raw-file/tip/touchevents.html
  116. //
  117. // example:
  118. // Used with dojo.on
  119. // | define(["dojo/on", "dojo/touch"], function(on, touch){
  120. // | on(node, touch.press, function(e){});
  121. // | on(node, touch.move, function(e){});
  122. // | on(node, touch.release, function(e){});
  123. // | on(node, touch.cancel, function(e){});
  124. // example:
  125. // Used with touch.* directly
  126. // | touch.press(node, function(e){});
  127. // | touch.move(node, function(e){});
  128. // | touch.release(node, function(e){});
  129. // | touch.cancel(node, function(e){});
  130. press: function(node, listener){
  131. // summary:
  132. // Register a listener to 'touchstart'|'mousedown' for the given node
  133. // node: Dom
  134. // Target node to listen to
  135. // listener: Function
  136. // Callback function
  137. // returns:
  138. // A handle which will be used to remove the listener by handle.remove()
  139. },
  140. move: function(node, listener){
  141. // summary:
  142. // Register a listener to 'touchmove'|'mousemove' for the given node
  143. // node: Dom
  144. // Target node to listen to
  145. // listener: Function
  146. // Callback function
  147. // returns:
  148. // A handle which will be used to remove the listener by handle.remove()
  149. },
  150. release: function(node, listener){
  151. // summary:
  152. // Register a listener to 'touchend'|'mouseup' for the given node
  153. // node: Dom
  154. // Target node to listen to
  155. // listener: Function
  156. // Callback function
  157. // returns:
  158. // A handle which will be used to remove the listener by handle.remove()
  159. },
  160. cancel: function(node, listener){
  161. // summary:
  162. // Register a listener to 'touchcancel'|'mouseleave' for the given node
  163. // node: Dom
  164. // Target node to listen to
  165. // listener: Function
  166. // Callback function
  167. // returns:
  168. // A handle which will be used to remove the listener by handle.remove()
  169. },
  170. over: function(node, listener){
  171. // summary:
  172. // Register a listener to 'mouseover' or touch equivalent for the given node
  173. // node: Dom
  174. // Target node to listen to
  175. // listener: Function
  176. // Callback function
  177. // returns:
  178. // A handle which will be used to remove the listener by handle.remove()
  179. },
  180. out: function(node, listener){
  181. // summary:
  182. // Register a listener to 'mouseout' or touch equivalent for the given node
  183. // node: Dom
  184. // Target node to listen to
  185. // listener: Function
  186. // Callback function
  187. // returns:
  188. // A handle which will be used to remove the listener by handle.remove()
  189. },
  190. enter: function(node, listener){
  191. // summary:
  192. // Register a listener to mouse.enter or touch equivalent for the given node
  193. // node: Dom
  194. // Target node to listen to
  195. // listener: Function
  196. // Callback function
  197. // returns:
  198. // A handle which will be used to remove the listener by handle.remove()
  199. },
  200. leave: function(node, listener){
  201. // summary:
  202. // Register a listener to mouse.leave or touch equivalent for the given node
  203. // node: Dom
  204. // Target node to listen to
  205. // listener: Function
  206. // Callback function
  207. // returns:
  208. // A handle which will be used to remove the listener by handle.remove()
  209. }
  210. };
  211. =====*/
  212. 1 && (dojo.touch = touch);
  213. return touch;
  214. });