/* Copyright (c) 2004-2010, The Dojo Foundation All Rights Reserved. Available via Academic Free License >= 2.1 OR the modified BSD license. see: http://dojotoolkit.org/license for details */ if(!dojo._hasResource["dojo.dnd.Manager"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code. dojo._hasResource["dojo.dnd.Manager"] = true; dojo.provide("dojo.dnd.Manager"); dojo.require("dojo.dnd.common"); dojo.require("dojo.dnd.autoscroll"); dojo.require("dojo.dnd.Avatar"); dojo.declare("dojo.dnd.Manager", null, { // summary: // the manager of DnD operations (usually a singleton) constructor: function(){ this.avatar = null; this.source = null; this.nodes = []; this.copy = true; this.target = null; this.canDropFlag = false; this.events = []; }, // avatar's offset from the mouse OFFSET_X: 16, OFFSET_Y: 16, // methods overSource: function(source){ // summary: // called when a source detected a mouse-over condition // source: Object // the reporter if(this.avatar){ this.target = (source && source.targetState != "Disabled") ? source : null; this.canDropFlag = Boolean(this.target); this.avatar.update(); } dojo.publish("/dnd/source/over", [source]); }, outSource: function(source){ // summary: // called when a source detected a mouse-out condition // source: Object // the reporter if(this.avatar){ if(this.target == source){ this.target = null; this.canDropFlag = false; this.avatar.update(); dojo.publish("/dnd/source/over", [null]); } }else{ dojo.publish("/dnd/source/over", [null]); } }, startDrag: function(source, nodes, copy){ // summary: // called to initiate the DnD operation // source: Object // the source which provides items // nodes: Array // the list of transferred items // copy: Boolean // copy items, if true, move items otherwise this.source = source; this.nodes = nodes; this.copy = Boolean(copy); // normalizing to true boolean this.avatar = this.makeAvatar(); dojo.body().appendChild(this.avatar.node); dojo.publish("/dnd/start", [source, nodes, this.copy]); this.events = [ dojo.connect(dojo.doc, "onmousemove", this, "onMouseMove"), dojo.connect(dojo.doc, "onmouseup", this, "onMouseUp"), dojo.connect(dojo.doc, "onkeydown", this, "onKeyDown"), dojo.connect(dojo.doc, "onkeyup", this, "onKeyUp"), // cancel text selection and text dragging dojo.connect(dojo.doc, "ondragstart", dojo.stopEvent), dojo.connect(dojo.body(), "onselectstart", dojo.stopEvent) ]; var c = "dojoDnd" + (copy ? "Copy" : "Move"); dojo.addClass(dojo.body(), c); }, canDrop: function(flag){ // summary: // called to notify if the current target can accept items var canDropFlag = Boolean(this.target && flag); if(this.canDropFlag != canDropFlag){ this.canDropFlag = canDropFlag; this.avatar.update(); } }, stopDrag: function(){ // summary: // stop the DnD in progress dojo.removeClass(dojo.body(), "dojoDndCopy"); dojo.removeClass(dojo.body(), "dojoDndMove"); dojo.forEach(this.events, dojo.disconnect); this.events = []; this.avatar.destroy(); this.avatar = null; this.source = this.target = null; this.nodes = []; }, makeAvatar: function(){ // summary: // makes the avatar; it is separate to be overwritten dynamically, if needed return new dojo.dnd.Avatar(this); }, updateAvatar: function(){ // summary: // updates the avatar; it is separate to be overwritten dynamically, if needed this.avatar.update(); }, // mouse event processors onMouseMove: function(e){ // summary: // event processor for onmousemove // e: Event // mouse event var a = this.avatar; if(a){ dojo.dnd.autoScrollNodes(e); //dojo.dnd.autoScroll(e); var s = a.node.style; s.left = (e.pageX + this.OFFSET_X) + "px"; s.top = (e.pageY + this.OFFSET_Y) + "px"; var copy = Boolean(this.source.copyState(dojo.isCopyKey(e))); if(this.copy != copy){ this._setCopyStatus(copy); } } }, onMouseUp: function(e){ // summary: // event processor for onmouseup // e: Event // mouse event if(this.avatar){ if(this.target && this.canDropFlag){ var copy = Boolean(this.source.copyState(dojo.isCopyKey(e))), params = [this.source, this.nodes, copy, this.target, e]; dojo.publish("/dnd/drop/before", params); dojo.publish("/dnd/drop", params); }else{ dojo.publish("/dnd/cancel"); } this.stopDrag(); } }, // keyboard event processors onKeyDown: function(e){ // summary: // event processor for onkeydown: // watching for CTRL for copy/move status, watching for ESCAPE to cancel the drag // e: Event // keyboard event if(this.avatar){ switch(e.keyCode){ case dojo.keys.CTRL: var copy = Boolean(this.source.copyState(true)); if(this.copy != copy){ this._setCopyStatus(copy); } break; case dojo.keys.ESCAPE: dojo.publish("/dnd/cancel"); this.stopDrag(); break; } } }, onKeyUp: function(e){ // summary: // event processor for onkeyup, watching for CTRL for copy/move status // e: Event // keyboard event if(this.avatar && e.keyCode == dojo.keys.CTRL){ var copy = Boolean(this.source.copyState(false)); if(this.copy != copy){ this._setCopyStatus(copy); } } }, // utilities _setCopyStatus: function(copy){ // summary: // changes the copy status // copy: Boolean // the copy status this.copy = copy; this.source._markDndStatus(this.copy); this.updateAvatar(); dojo.removeClass(dojo.body(), "dojoDnd" + (this.copy ? "Move" : "Copy")); dojo.addClass(dojo.body(), "dojoDnd" + (this.copy ? "Copy" : "Move")); } }); // dojo.dnd._manager: // The manager singleton variable. Can be overwritten if needed. dojo.dnd._manager = null; dojo.dnd.manager = function(){ // summary: // Returns the current DnD manager. Creates one if it is not created yet. if(!dojo.dnd._manager){ dojo.dnd._manager = new dojo.dnd.Manager(); } return dojo.dnd._manager; // Object }; }