Mover.js 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. /*
  2. Copyright (c) 2004-2012, The Dojo Foundation All Rights Reserved.
  3. Available via Academic Free License >= 2.1 OR the modified BSD license.
  4. see: http://dojotoolkit.org/license for details
  5. */
  6. if(!dojo._hasResource["dojo.dnd.Mover"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  7. dojo._hasResource["dojo.dnd.Mover"] = true;
  8. dojo.provide("dojo.dnd.Mover");
  9. dojo.require("dojo.dnd.common");
  10. dojo.require("dojo.dnd.autoscroll");
  11. dojo.declare("dojo.dnd.Mover", null, {
  12. constructor: function(node, e, host){
  13. // summary:
  14. // an object which makes a node follow the mouse, or touch-drag on touch devices.
  15. // Used as a default mover, and as a base class for custom movers.
  16. // node: Node
  17. // a node (or node's id) to be moved
  18. // e: Event
  19. // a mouse event, which started the move;
  20. // only pageX and pageY properties are used
  21. // host: Object?
  22. // object which implements the functionality of the move,
  23. // and defines proper events (onMoveStart and onMoveStop)
  24. this.node = dojo.byId(node);
  25. var pos = e.touches ? e.touches[0] : e;
  26. this.marginBox = {l: pos.pageX, t: pos.pageY};
  27. this.mouseButton = e.button;
  28. var h = (this.host = host), d = node.ownerDocument;
  29. this.events = [
  30. // At the start of a drag, onFirstMove is called, and then the following two
  31. // connects are disconnected
  32. dojo.connect(d, "onmousemove", this, "onFirstMove"),
  33. dojo.connect(d, "ontouchmove", this, "onFirstMove"),
  34. // These are called continually during the drag
  35. dojo.connect(d, "onmousemove", this, "onMouseMove"),
  36. dojo.connect(d, "ontouchmove", this, "onMouseMove"),
  37. // And these are called at the end of the drag
  38. dojo.connect(d, "onmouseup", this, "onMouseUp"),
  39. dojo.connect(d, "ontouchend", this, "onMouseUp"),
  40. // cancel text selection and text dragging
  41. dojo.connect(d, "ondragstart", dojo.stopEvent),
  42. dojo.connect(d.body, "onselectstart", dojo.stopEvent)
  43. ];
  44. // notify that the move has started
  45. if(h && h.onMoveStart){
  46. h.onMoveStart(this);
  47. }
  48. },
  49. // mouse event processors
  50. onMouseMove: function(e){
  51. // summary:
  52. // event processor for onmousemove/ontouchmove
  53. // e: Event
  54. // mouse/touch event
  55. dojo.dnd.autoScroll(e);
  56. var m = this.marginBox,
  57. pos = e.touches ? e.touches[0] : e;
  58. this.host.onMove(this, {l: m.l + pos.pageX, t: m.t + pos.pageY}, e);
  59. dojo.stopEvent(e);
  60. },
  61. onMouseUp: function(e){
  62. if(dojo.isWebKit && dojo.isMac && this.mouseButton == 2 ?
  63. e.button == 0 : this.mouseButton == e.button){ // TODO Should condition be met for touch devices, too?
  64. this.destroy();
  65. }
  66. dojo.stopEvent(e);
  67. },
  68. // utilities
  69. onFirstMove: function(e){
  70. // summary:
  71. // makes the node absolute; it is meant to be called only once.
  72. // relative and absolutely positioned nodes are assumed to use pixel units
  73. var s = this.node.style, l, t, h = this.host;
  74. switch(s.position){
  75. case "relative":
  76. case "absolute":
  77. // assume that left and top values are in pixels already
  78. l = Math.round(parseFloat(s.left)) || 0;
  79. t = Math.round(parseFloat(s.top)) || 0;
  80. break;
  81. default:
  82. s.position = "absolute"; // enforcing the absolute mode
  83. var m = dojo.marginBox(this.node);
  84. // event.pageX/pageY (which we used to generate the initial
  85. // margin box) includes padding and margin set on the body.
  86. // However, setting the node's position to absolute and then
  87. // doing dojo.marginBox on it *doesn't* take that additional
  88. // space into account - so we need to subtract the combined
  89. // padding and margin. We use getComputedStyle and
  90. // _getMarginBox/_getContentBox to avoid the extra lookup of
  91. // the computed style.
  92. var b = dojo.doc.body;
  93. var bs = dojo.getComputedStyle(b);
  94. var bm = dojo._getMarginBox(b, bs);
  95. var bc = dojo._getContentBox(b, bs);
  96. l = m.l - (bc.l - bm.l);
  97. t = m.t - (bc.t - bm.t);
  98. break;
  99. }
  100. this.marginBox.l = l - this.marginBox.l;
  101. this.marginBox.t = t - this.marginBox.t;
  102. if(h && h.onFirstMove){
  103. h.onFirstMove(this, e);
  104. }
  105. // Disconnect onmousemove and ontouchmove events that call this function
  106. dojo.disconnect(this.events.shift());
  107. dojo.disconnect(this.events.shift());
  108. },
  109. destroy: function(){
  110. // summary:
  111. // stops the move, deletes all references, so the object can be garbage-collected
  112. dojo.forEach(this.events, dojo.disconnect);
  113. // undo global settings
  114. var h = this.host;
  115. if(h && h.onMoveStop){
  116. h.onMoveStop(this);
  117. }
  118. // destroy objects
  119. this.events = this.node = this.host = null;
  120. }
  121. });
  122. }