dojo.require("dojo.lang.common");
dojo.require("dojo.lang.func");
dojo.require("dojo.lang.declare");
dojo.provide("dojo.dnd.DragAndDrop");
// summary:
// Core "interfaces" for the participants in all DnD operations.
// Subclasses implement all of the actions outlined by these APIs, with
// most of the ones you probably care about being defined in
// HtmlDragAndDrop.js, which will be automatically included should you
// dojo.require("dojo.dnd.*");.
//
// In addition to the various actor classes, a global manager will be
// created/installed at dojo.dnd.dragManager. This manager object is of
// type dojo.dnd.DragManager and will be replaced by environment-specific
// managers.
//
// The 3 object types involved in any Drag and Drop operation are:
// * DragSource
// This is the item that can be selected for dragging. Drag
// sources can have "types" to help mediate whether or not various
// DropTargets will accept (or reject them). Most dragging actions
// are handled by the DragObject which the DragSource generates
// from its onDragStart method.
// * DragObject
// This, along with the manger, does most of the hard work of DnD.
// Implementations may rely on DragObject instances to implement
// "shadowing", "movement", or other kinds of DnD variations that
// affect the visual representation of the drag operation.
// * DropTarget
// Represents some section of the screen that can accept drag
// and drop events. DropTargets keep a list of accepted types
// which is checked agains the types of the respective DragSource
// objects that pass over it. DropTargets may implement behaviors
// that respond to drop events to take application-level actions.
dojo.declare("dojo.dnd.DragSource", null, {
// String:
// what kind of drag source are we? Used to determine if we can be
// dropped on a given DropTarget
type: "",
onDragEnd: function(/*dojo.dnd.DragEvent*/evt){
// summary:
// stub handler that is called when dragging finishes.
},
onDragStart: function(/*dojo.dnd.DragEvent*/evt){ // dojo.dnd.DragObject
// summary:
// stub handler that is called when dragging starts. Subclasses
// should ensure that onDragStart *always* returns a
// dojo.dnd.DragObject instance.
},
onSelected: function(/*dojo.dnd.DragEvent*/evt){
// summary:
// This function gets called when the DOM element was selected for
// dragging by the HtmlDragAndDropManager.
},
unregister: function(){
// summary: remove this drag source from the manager
dojo.dnd.dragManager.unregisterDragSource(this);
},
reregister: function(){
// summary: add this drag source to the manager
dojo.dnd.dragManager.registerDragSource(this);
}
});
dojo.declare("dojo.dnd.DragObject", null, {
// String:
// what kind of drag object are we? Used to determine if we can be
// dropped on a given DropTarget
type: "",
register: function(){
// summary: register this DragObject with the manager
var dm = dojo.dnd.dragManager;
if(dm["registerDragObject"]){ // side-effect prevention
dm.registerDragObject(this);
}
},
onDragStart: function(/*dojo.dnd.DragEvent*/evt){
// summary:
// over-ridden by subclasses. Gets called directly after being
// created by the DragSource default action is to clone self as
// icon
},
onDragMove: function(/*dojo.dnd.DragEvent*/evt){
// summary:
// Implemented by subclasses. Should change the UI for the drag
// icon i.e., "it moves itself"
},
onDragOver: function(/*dojo.dnd.DragEvent*/evt){
// summary:
// stub handler that is called when the DragObject instance is
// "over" a DropTarget.
},
onDragOut: function(/*dojo.dnd.DragEvent*/evt){
// summary:
// stub handler that is called when the DragObject instance leaves
// a DropTarget.
},
onDragEnd: function(/*dojo.dnd.DragEvent*/evt){
// summary:
// stub handler that is called when dragging ends, either through
// dropping or cancelation.
},
// normal aliases
onDragLeave: dojo.lang.forward("onDragOut"),
onDragEnter: dojo.lang.forward("onDragOver"),
// non-camel aliases
ondragout: dojo.lang.forward("onDragOut"),
ondragover: dojo.lang.forward("onDragOver")
});
dojo.declare("dojo.dnd.DropTarget", null, {
acceptsType: function(/*String*/type){
// summary:
// determines whether or not this DropTarget will accept the given
// type. The default behavior is to consult this.acceptedTypes and
// if "*" is a member, to always accept the type.
if(!dojo.lang.inArray(this.acceptedTypes, "*")){ // wildcard
if(!dojo.lang.inArray(this.acceptedTypes, type)) { return false; } // Boolean
}
return true; // Boolean
},
accepts: function(/*Array*/dragObjects){
// summary:
// determines if we'll accept all members of the passed array of
// dojo.dnd.DragObject instances
if(!dojo.lang.inArray(this.acceptedTypes, "*")){ // wildcard
for (var i = 0; i < dragObjects.length; i++) {
if (!dojo.lang.inArray(this.acceptedTypes,
dragObjects[i].type)) { return false; } // Boolean
}
}
return true; // Boolean
},
unregister: function(){
// summary: remove from the drag manager
dojo.dnd.dragManager.unregisterDropTarget(this);
},
onDragOver: function(/*dojo.dnd.DragEvent*/evt){
// summary:
// stub handler that is called when DragObject instances are
// "over" this DropTarget.
},
onDragOut: function(/*dojo.dnd.DragEvent*/evt){
// summary:
// stub handler that is called when DragObject instances are
// "leave" this DropTarget.
},
onDragMove: function(/*dojo.dnd.DragEvent*/evt){
// summary:
// stub handler that is called when DragObject instances are
// moved across this DropTarget. May fire many times in the course
// of the drag operation but will end after onDragOut
},
onDropStart: function(/*dojo.dnd.DragEvent*/evt){ // Boolean
// summary:
// stub handler that is called when DragObject instances are
// dropped on this target. If true is returned from onDropStart,
// dropping proceeds, otherwise it's cancled.
},
onDrop: function(/*dojo.dnd.DragEvent*/evt){
// summary: we're getting dropped on!
},
onDropEnd: function(){
// summary: dropping is over
}
}, function(){
this.acceptedTypes = [];
});
// NOTE: this interface is defined here for the convenience of the DragManager
// implementor. It is expected that in most cases it will be satisfied by
// extending a native event (DOM event in HTML and SVG).
dojo.dnd.DragEvent = function(){
this.dragSource = null;
this.dragObject = null;
this.target = null;
this.eventStatus = "success";
//
// can be one of:
// [ "dropSuccess", "dropFailure", "dragMove",
// "dragStart", "dragEnter", "dragLeave"]
//
}
/*
* The DragManager handles listening for low-level events and dispatching
* them to higher-level primitives like drag sources and drop targets. In
* order to do this, it must keep a list of the items.
*/
dojo.declare("dojo.dnd.DragManager", null, {
// Array: an array of currently selected DragSource objects
selectedSources: [],
// Array: all DragObjects we know about
dragObjects: [],
// Array: all DragSources we know about
dragSources: [],
registerDragSource: function(/*dojo.dnd.DragSource*/ source){
// summary: called by DragSource class constructor
},
// Array: all DropTargets we know about
dropTargets: [],
registerDropTarget: function(/*dojo.dnd.DropTarget*/ target){
// summary: called by DropTarget class constructor
},
// dojo.dnd.DropTarget:
// what was the last DropTarget instance we left in the drag phase?
lastDragTarget: null,
// dojo.dnd.DropTarget:
// the DropTarget the mouse is currently over
currentDragTarget: null,
onKeyDown: function(){
// summary: generic handler called by low-level events
},
onMouseOut: function(){
// summary: generic handler called by low-level events
},
onMouseMove: function(){
// summary: generic handler called by low-level events
},
onMouseUp: function(){
// summary: generic handler called by low-level events
}
});
// NOTE: despite the existance of the DragManager class, there will be a
// singleton drag manager provided by the renderer-specific D&D support code.
// It is therefore sane for us to assign instance variables to the DragManager
// prototype
// The renderer-specific file will define the following object:
// dojo.dnd.dragManager = null;