Manager.js 5.9 KB

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