Manager.js 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. define("dojo/dnd/Manager", ["../main", "../Evented", "./common", "./autoscroll", "./Avatar"], function(dojo, Evented) {
  2. // module:
  3. // dojo/dnd/Manager
  4. // summary:
  5. // TODOC
  6. var Manager = dojo.declare("dojo.dnd.Manager", [Evented], {
  7. // summary:
  8. // the manager of DnD operations (usually a singleton)
  9. constructor: function(){
  10. this.avatar = null;
  11. this.source = null;
  12. this.nodes = [];
  13. this.copy = true;
  14. this.target = null;
  15. this.canDropFlag = false;
  16. this.events = [];
  17. },
  18. // avatar's offset from the mouse
  19. OFFSET_X: 16,
  20. OFFSET_Y: 16,
  21. // methods
  22. overSource: function(source){
  23. // summary:
  24. // called when a source detected a mouse-over condition
  25. // source: Object
  26. // the reporter
  27. if(this.avatar){
  28. this.target = (source && source.targetState != "Disabled") ? source : null;
  29. this.canDropFlag = Boolean(this.target);
  30. this.avatar.update();
  31. }
  32. dojo.publish("/dnd/source/over", [source]);
  33. },
  34. outSource: function(source){
  35. // summary:
  36. // called when a source detected a mouse-out condition
  37. // source: Object
  38. // the reporter
  39. if(this.avatar){
  40. if(this.target == source){
  41. this.target = null;
  42. this.canDropFlag = false;
  43. this.avatar.update();
  44. dojo.publish("/dnd/source/over", [null]);
  45. }
  46. }else{
  47. dojo.publish("/dnd/source/over", [null]);
  48. }
  49. },
  50. startDrag: function(source, nodes, copy){
  51. // summary:
  52. // called to initiate the DnD operation
  53. // source: Object
  54. // the source which provides items
  55. // nodes: Array
  56. // the list of transferred items
  57. // copy: Boolean
  58. // copy items, if true, move items otherwise
  59. this.source = source;
  60. this.nodes = nodes;
  61. this.copy = Boolean(copy); // normalizing to true boolean
  62. this.avatar = this.makeAvatar();
  63. dojo.body().appendChild(this.avatar.node);
  64. dojo.publish("/dnd/start", [source, nodes, this.copy]);
  65. this.events = [
  66. dojo.connect(dojo.doc, "onmousemove", this, "onMouseMove"),
  67. dojo.connect(dojo.doc, "onmouseup", this, "onMouseUp"),
  68. dojo.connect(dojo.doc, "onkeydown", this, "onKeyDown"),
  69. dojo.connect(dojo.doc, "onkeyup", this, "onKeyUp"),
  70. // cancel text selection and text dragging
  71. dojo.connect(dojo.doc, "ondragstart", dojo.stopEvent),
  72. dojo.connect(dojo.body(), "onselectstart", dojo.stopEvent)
  73. ];
  74. var c = "dojoDnd" + (copy ? "Copy" : "Move");
  75. dojo.addClass(dojo.body(), c);
  76. },
  77. canDrop: function(flag){
  78. // summary:
  79. // called to notify if the current target can accept items
  80. var canDropFlag = Boolean(this.target && flag);
  81. if(this.canDropFlag != canDropFlag){
  82. this.canDropFlag = canDropFlag;
  83. this.avatar.update();
  84. }
  85. },
  86. stopDrag: function(){
  87. // summary:
  88. // stop the DnD in progress
  89. dojo.removeClass(dojo.body(), ["dojoDndCopy", "dojoDndMove"]);
  90. dojo.forEach(this.events, dojo.disconnect);
  91. this.events = [];
  92. this.avatar.destroy();
  93. this.avatar = null;
  94. this.source = this.target = null;
  95. this.nodes = [];
  96. },
  97. makeAvatar: function(){
  98. // summary:
  99. // makes the avatar; it is separate to be overwritten dynamically, if needed
  100. return new dojo.dnd.Avatar(this);
  101. },
  102. updateAvatar: function(){
  103. // summary:
  104. // updates the avatar; it is separate to be overwritten dynamically, if needed
  105. this.avatar.update();
  106. },
  107. // mouse event processors
  108. onMouseMove: function(e){
  109. // summary:
  110. // event processor for onmousemove
  111. // e: Event
  112. // mouse event
  113. var a = this.avatar;
  114. if(a){
  115. dojo.dnd.autoScrollNodes(e);
  116. //dojo.dnd.autoScroll(e);
  117. var s = a.node.style;
  118. s.left = (e.pageX + this.OFFSET_X) + "px";
  119. s.top = (e.pageY + this.OFFSET_Y) + "px";
  120. var copy = Boolean(this.source.copyState(dojo.isCopyKey(e)));
  121. if(this.copy != copy){
  122. this._setCopyStatus(copy);
  123. }
  124. }
  125. },
  126. onMouseUp: function(e){
  127. // summary:
  128. // event processor for onmouseup
  129. // e: Event
  130. // mouse event
  131. if(this.avatar){
  132. if(this.target && this.canDropFlag){
  133. var copy = Boolean(this.source.copyState(dojo.isCopyKey(e))),
  134. params = [this.source, this.nodes, copy, this.target, e];
  135. dojo.publish("/dnd/drop/before", params);
  136. dojo.publish("/dnd/drop", params);
  137. }else{
  138. dojo.publish("/dnd/cancel");
  139. }
  140. this.stopDrag();
  141. }
  142. },
  143. // keyboard event processors
  144. onKeyDown: function(e){
  145. // summary:
  146. // event processor for onkeydown:
  147. // watching for CTRL for copy/move status, watching for ESCAPE to cancel the drag
  148. // e: Event
  149. // keyboard event
  150. if(this.avatar){
  151. switch(e.keyCode){
  152. case dojo.keys.CTRL:
  153. var copy = Boolean(this.source.copyState(true));
  154. if(this.copy != copy){
  155. this._setCopyStatus(copy);
  156. }
  157. break;
  158. case dojo.keys.ESCAPE:
  159. dojo.publish("/dnd/cancel");
  160. this.stopDrag();
  161. break;
  162. }
  163. }
  164. },
  165. onKeyUp: function(e){
  166. // summary:
  167. // event processor for onkeyup, watching for CTRL for copy/move status
  168. // e: Event
  169. // keyboard event
  170. if(this.avatar && e.keyCode == dojo.keys.CTRL){
  171. var copy = Boolean(this.source.copyState(false));
  172. if(this.copy != copy){
  173. this._setCopyStatus(copy);
  174. }
  175. }
  176. },
  177. // utilities
  178. _setCopyStatus: function(copy){
  179. // summary:
  180. // changes the copy status
  181. // copy: Boolean
  182. // the copy status
  183. this.copy = copy;
  184. this.source._markDndStatus(this.copy);
  185. this.updateAvatar();
  186. dojo.replaceClass(dojo.body(),
  187. "dojoDnd" + (this.copy ? "Copy" : "Move"),
  188. "dojoDnd" + (this.copy ? "Move" : "Copy"));
  189. }
  190. });
  191. // dojo.dnd._manager:
  192. // The manager singleton variable. Can be overwritten if needed.
  193. dojo.dnd._manager = null;
  194. Manager.manager = dojo.dnd.manager = function(){
  195. // summary:
  196. // Returns the current DnD manager. Creates one if it is not created yet.
  197. if(!dojo.dnd._manager){
  198. dojo.dnd._manager = new dojo.dnd.Manager();
  199. }
  200. return dojo.dnd._manager; // Object
  201. };
  202. return Manager;
  203. });