/* Copyright (c) 2004-2006, The Dojo Foundation All Rights Reserved. Licensed under the Academic Free License version 2.1 or above OR the modified BSD license. For more information on Dojo licensing, see: http://dojotoolkit.org/community/licensing.shtml */ 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;