JavaScript Tutorial/Drag Drop/Drag Drop
Simulated Drag And Drop with zEvents Library and zDragDrop Library
<source lang="javascript">
<html>
<head> <title>Simulated Drag And Drop Example</title> <script type="text/javascript">
/*------------------------------------------------------------------------------
* JavaScript zEvents Library * Version 1.1 * by Nicholas C. Zakas, http://www.nczonline.net/ * Copyright (c) 2004-2005 Nicholas C. Zakas. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *------------------------------------------------------------------------------ */
/**
* Encapsulates information about an event. * @scope public * @class */
function zEvent() {
/** * The type of event. * @scope public */ this.type /*: String */ = null; /** * The object that caused the event. * @scope public */ this.target /*: zEventTarget */ = null; /** * A secondary object related to the event. * @scope public */ this.relatedTarget /*: zEventTarget */ = null; /** * Indicates whether or not the event can be canceled. * @scope public */ this.cancelable /*: boolean */ = false; /** * The time that the event occurred. * @scope public */ this.timeStamp /*: long */ = null; /* * Set to false to cancel event. * @scope public */ this.returnValue /*: boolean */ = true;
} /**
* Initializes the event object with information for the event. * @scope public * @param sType The type of event encapsulated by the object. * @param bCancelable True if the event can be cancelled. */
zEvent.prototype.initEvent = function (sType /*: String */,
bCancelable /*: boolean */) { this.type = sType; this.cancelable = bCancelable; this.timeStamp = (new Date()).getTime();
}; /**
* Prevents the default behavior for an event. * @scope public */
zEvent.prototype.preventDefault = function () {
if (this.cancelable) { this.returnValue = false; }
}; /**
* Any class that wants to support events should inherit from this. * @class * @scope public */
function zEventTarget() {
/** * Array of event handlers. * @scope private */ this.eventhandlers /*: Object */ = new Object();
} /**
* Adds an event listener function to handle the type of event. * @scope public * @param sType The type of event to handle (i.e., "mousemove", not "onmousemove"). * @param fnListener The listener function for the event. */
zEventTarget.prototype.addEventListener = function (sType /*: String */,
fnListener /*: Function */) { if (typeof this.eventhandlers[sType] == "undefined") { this.eventhandlers[sType] = new Array; } this.eventhandlers[sType][this.eventhandlers[sType].length] = fnListener;
}; /**
* Causes an event to fire. * @scope public * @param oEvent The event object containing information about the event to fire. * @return True if the event should continue, false if not. */
zEventTarget.prototype.dispatchEvent = function (oEvent /*: zEvent */) /*: boolean */ {
/* * Set the target of the event. */ oEvent.target = this; /* * Call each event handler and pass in the event object. */ if (typeof this.eventhandlers[oEvent.type] != "undefined") { for (var i=0; i < this.eventhandlers[oEvent.type].length; i++) { this.eventhandlers[oEvent.type][i](oEvent); } } /* * Return the value of returnValue, which is changed to false * when preventDefault() is called. */ return oEvent.returnValue;
}; /**
* Removes an event listener function from handling the type of event. * @scope public * @param sType The type of event to remove from (i.e., "mousemove", not "onmousemove"). * @param fnListener The listener function to remove. */
zEventTarget.prototype.removeEventListener = function (sType /*: String */,
fnListener /*: Function */) { if (typeof this.eventhandlers[sType] != "undefined") { var arrTemp = new Array; for (var i=0; i < this.eventhandlers[sType].length; i++) { if (this.eventhandlers[sType][i] != fnListener) { arrTemp[arrTemp.length] = this.eventhandlers[sType][i]; } } this.eventhandlers[sType] = arrTemp; }
};
</script> <script type="text/javascript">
/*------------------------------------------------------------------------------
* JavaScript zDragDrop Library * Version 1.1 * by Nicholas C. Zakas, http://www.nczonline.net/ * Copyright (c) 2004-2005 Nicholas C. Zakas. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *------------------------------------------------------------------------------ */
/*
* This library requires the free zEvents library available from * http://www.nczonline.net/. */
/**
* Contains global settings and methods for drag and drop functionality. * @scope public */
function zDrag() {} /**
* The item currently being dragged. * @scope private */
zDrag.current /*: zDraggable */ = null; /**
* Indicates whether or not an item is being dragged. * @scope private */
zDrag.dragging /*: boolean */ = false; /**
* Returns true if an item is being dragged. * @scope public * @return True if an item is being dragged, false if not. * @type boolean */
zDrag.isDragging = function () /*: boolean */ {
return this.dragging;
}; /**
* Sets the item being dragged. * @scope protected * @param {zDraggable} oDraggable The draggable item. * @type void */
zDrag.setCurrent = function (oDraggable /*: zDraggable */) {
this.current = oDraggable; this.dragging = true;
}; /**
* Returns the currently dragged item. * @scope public * @return The currently dragged item. * @type zDraggable */
zDrag.getCurrent = function () /*: zDraggable */ {
return this.current;
}; /**
* Clears the currently dragged item from memory and sets the dragging * flag to false. * @scope protected * @type void */
zDrag.clearCurrent = function () {
this.current = null; this.dragging = false;
}; /**
* Encapsulates the functionality for a draggable element. * @scope public * @extends zEventTarget * @class */
function zDraggable(oElement, iConstraints) {
/* * Inherit properties from zEventTarget. */ zEventTarget.call(this); /* * Call constructor. */ this.construct(oElement, iConstraints); /** * The difference between the x cursor position and left edge of the element. * @scope private * @type int */ this.diffX /*: int */ = 0; /** * The difference between the y cursor position and top edge of the element. * @scope private * @type int */ this.diffY /*: int */ = 0; /** * Collection of drop targets for this item. * @scope private * @type Array */ this.targets /*: Array */ = [];
} /*
* Inherit methods from zEventTarget. */
zDraggable.prototype = new zEventTarget; /**
* Indicates the dragged item can be dragged along the X axis. * @scope public * @type int * @final */
zDraggable.DRAG_X /*: int */ = 1; /**
* Indicates the dragged item can be dragged along the Y axis. * @scope public * @type int * @final */
zDraggable.DRAG_Y /*: int */ = 2; /**
* Adds a new drop target to the draggable item. * @scope public * @param {zDropTarget} oDropTarget The drop target to register for this item. * @type void */
zDraggable.prototype.addDropTarget = function (oDropTarget /*: zDropTarget */) {
this.targets.push(oDropTarget);
}; /**
* Creates a new instance based on the given element and the constraints. * @scope private * @constructor * @param {HTMLElement} oElement The DOM element to make draggable. * @param {int} iConstraints The rules for dragging. */
zDraggable.prototype.construct = function (oElement /*: HTMLElement */,
iConstraints /*: int */) { /** * The element to make draggable. * @scope private * @type HTMLElement */ this.element /*: HTMLElement */ = oElement; /** * The constraints indicating the rules for dragging. * @scope private * @type int */ this.constraints /*: int */ = iConstraints; /* * Create a pointer to this object. */ var oThis = this; /* * Create a temporary function named fnTemp. */ var fnTemp = function () { /* * Create a dragstart event and fire it. */ var oDragStartEvent = new zDragDropEvent(); oDragStartEvent.initDragDropEvent("dragstart", true); /* * If the event isn"t cancelled, proceed. */ if (oThis.dispatchEvent(oDragStartEvent)) { /* * Get the event objects, which is either the first * argument (for DOM-compliant browsers and Netscape 4.x) * or window.event (for IE). */ var oEvent = arguments[0] || window.event; /* * Get the difference between the clientX and clientY * and the position of the element. */ oThis.diffX = oEvent.clientX - oThis.element.offsetLeft; oThis.diffY = oEvent.clientY - oThis.element.offsetTop; /* * Add all DOM event handlers */ oThis.attachEventHandlers(); /* * Set the currently dragged item. */ zDrag.setCurrent(oThis); } }; /* * Determine which method to use to add the event handler. */ if (this.element.addEventListener) { this.element.addEventListener("mousedown", fnTemp, false); } else if (this.element.attachEvent) { this.element.attachEvent("onmousedown", fnTemp); } else { throw new Error("zDrag not supported in this browser."); }
}; /**
* Attaches event handlers for the mousemove and mouseup events. * @scope private * @private * @type void */
zDraggable.prototype.attachEventHandlers = function () {
/* * Create a pointer to this object. */ var oThis = this; /* * Create a temporary function named tempMouseMove. */ this.tempMouseMove = function () { /* * Get the event objects, which is either the first * argument (for DOM-compliant browsers and Netscape 4.x) * or window.event (for IE). */ var oEvent = arguments[0] || window.event; /* * Get the new x and y coordinates for the dragged element by * subtracting the difference in the x and y direction from * the mouse position on the screen (clientX and clientY). */ var iNewX = oEvent.clientX - oThis.diffX; var iNewY = oEvent.clientY - oThis.diffY; /* * Move the x coordinate if zDraggable.DRAG_X is an option. */ if (oThis.constraints & zDraggable.DRAG_X) { oThis.element.style.left = iNewX + "px"; } /* * Move the y coordinate if zDraggable.DRAG_Y is an option. */ if (oThis.constraints & zDraggable.DRAG_Y) { oThis.element.style.top = iNewY + "px"; } /* * Create and fire a drag event. */ var oDragEvent = new zDragDropEvent(); oDragEvent.initDragDropEvent("drag", false); oThis.dispatchEvent(oDragEvent); }; /* * Create a temporary function for the mouseup event. */ oThis.tempMouseUp = function () { /* * Get the event object. */ var oEvent = arguments[0] || window.event; /* * Determine if the mouse is over a drop target. */ var oDropTarget = oThis.getDropTarget(oEvent.clientX, oEvent.clientY); if (oDropTarget != null) { /* * Fire the drop event. */ var oDropEvent = new zDragDropEvent(); oDropEvent.initDragDropEvent("drop", false, oThis); oDropTarget.dispatchEvent(oDropEvent); } /* * Create and fire a dragend event. */ var oDragEndEvent = new zDragDropEvent(); oDragEndEvent.initDragDropEvent("dragend", false); oThis.dispatchEvent(oDragEndEvent); /* * Clear the currently dragged item. */ zDrag.clearCurrent(); /* * Detach all of the event handlers. */ oThis.detachEventHandlers(); }; /* * Determine which method to use to add the event handlers for * the mousemove and mouseup events. */ if (document.addEventListener) { document.addEventListener("mousemove", this.tempMouseMove, false); document.addEventListener("mouseup", this.tempMouseUp, false); } else if (document.body.attachEvent) { document.body.attachEvent("onmousemove", this.tempMouseMove); document.body.attachEvent("onmouseup", this.tempMouseUp); } else { throw new Error("zDrag doesn"t support this browser."); }
}; /**
* Detaches event handlers for the mousemove and mouseup events. * @scope private */
zDraggable.prototype.detachEventHandlers = function () {
/* * Determine the method for removing the event handlers for the * mousemove and mouseup events. */ if (document.removeEventListener) { document.removeEventListener("mousemove", this.tempMouseMove, false); document.removeEventListener("mouseup", this.tempMouseUp, false); } else if (document.body.detachEvent) { document.body.detachEvent("onmousemove", this.tempMouseMove); document.body.detachEvent("onmouseup", this.tempMouseUp); } else { throw new Error("zDrag doesn"t support this browser."); }
}; /**
* Determines the drop target that the mouse is over. * @scope private * @param iX The x-coordinate of the mouse. * @param iY The y-coordinate of the mouse. * @return The drop target if the mouse is over one, null otherwise. */
zDraggable.prototype.getDropTarget = function (iX /*: int */,
iY /*: int */) /*: zDropTarget */ { for (var i=0; i < this.targets.length; i++) { if (this.targets[i].isOver(iX, iY)) { return this.targets[i]; } } return null;
}; /**
* Moves the draggable element to a given position. * @scope public * @param iX The x-coordinate to move to. * @param iY The y-coordinate to move to. */
zDraggable.prototype.moveTo = function (iX /*: int */, iY /*: int */) {
this.element.style.left = iX + "px"; this.element.style.top = iY + "px";
}; /**
* Returns the left coordinate of the element. * @scope public * @return The left coordinate of the element. */
zDraggable.prototype.getLeft = function () /*: int */ {
return this.element.offsetLeft;
}; /**
* Returns the top coordinate of the element. * @scope public * @return The top coordinate of the element. */
zDraggable.prototype.getTop = function () /*: int */ {
return this.element.offsetTop;
}; /**
* Encapsulates information about a drag drop event. * @class * @scope public * @extends zEvent */
function zDragDropEvent() {
/* * Inherit properties from zEvent. */ zEvent.call(this);
} /*
* Inherit methods from zEvent. */
zDragDropEvent.prototype = new zEvent(); /**
* Initializes the event object with information for the event. * @scope public * @param sType The type of event encapsulated by the object. * @param bCancelable True if the event can be cancelled. * @param oRelatedTarget The alternate target related to the event. */
zDragDropEvent.prototype.initDragDropEvent = function(sType /*: String */,
bCancelable /*: boolean */, oRelatedTarget /*: zEventTarget */) { /* * Call inherited method initEvent(). */ this.initEvent(sType, bCancelable); /* * Assign related target (may be null). */ this.relatedTarget = oRelatedTarget;
} /**
* A target for a zDraggable to be dropped. * @scope public * @class * @extends zEventTarget */
function zDropTarget(oElement) {
/* * Inherit properties from zEventTarget. */ zEventTarget.call(this); /* * Call constructor. */ this.construct(oElement);
} /*
* Inherit methods from zEventTarget. */
zDropTarget.prototype = new zEventTarget; /**
* Creates a new instance based on the given DOM element. * @constructor * @scope public * @param oElement The DOM element to make into a drop target. */
zDropTarget.prototype.construct = function (oElement /*: HTMLElement */) {
/** * The DOM element to use as a drop target. * @scope private */ this.element = oElement;
}; /**
* Determines if a given set of coordinates is over the element. * @scope protected * @param iX The x-coordinate to check. * @param iY The y-coordinate to check. * @return True if the coordinates are over the element, false if not. */
zDropTarget.prototype.isOver = function (iX /*: int */, iY /*: int */) /*: boolean */ {
var iX1 = this.element.offsetLeft; var iX2 = iX1 + this.element.offsetWidth; var iY1 = this.element.offsetTop; var iY2 = iY1 + this.element.offsetHeight; return (iX >= iX1 && iX <= iX2 && iY >= iY1 && iY <= iY2);
}; /**
* Returns the left coordinate of the drop target. * @scope public * @return The left coordinate of the drop target. */
zDropTarget.prototype.getLeft = function () /*: int */ {
return this.element.offsetLeft;
}; /**
* Returns the top coordinate of the drop target. * @scope public * @return The top coordinate of the drop target. */
zDropTarget.prototype.getTop = function () /*: int */{
return this.element.offsetTop;
}; /**
* Returns the height of the drop target. * @scope public * @return The height of the drop target. */
zDropTarget.prototype.getHeight = function () /*: int */{
return this.element.offsetHeight;
}; /**
* Returns the width of the drop target. * @scope public * @return The width of the drop target. */
zDropTarget.prototype.getWidth = function () /*: int */{
return this.element.offsetWidth;
};
</script> <script type="text/javascript"> function doLoad() { var oDraggable = new zDraggable(document.getElementById("div1"), zDraggable.DRAG_X | zDraggable.DRAG_Y); var oDropTarget = new zDropTarget(document.getElementById("divDropTarget")); oDraggable.addDropTarget(oDropTarget); oDropTarget.addEventListener("drop", function (oEvent) { oEvent.relatedTarget.moveTo(oDropTarget.getLeft(), oDropTarget.getTop()); }); } </script> <style type="text/css"> #div1 { background-color: red; height: 100px; width: 100px; position: absolute; z-index: 10; } #divDropTarget { background-color: blue; height: 200px; width: 200px; position: absolute; left: 300px; } </style> </head> <body onload="doLoad()">
Try dragging the red square onto the blue square.
</body>
</html></source>
System Drag And Drop between two text boxes
<source lang="javascript">
<html>
<head> <title>System Drag And Drop between two text boxes</title> <script type="text/javascript"> function handleDragDropEvent(oEvent) { var oTextbox = document.getElementById("txt1"); oTextbox.value += oEvent.type + "\n"; } </script> </head> <body>
Try dragging the text from the left textbox to the right one.
<input type="text" value="drag this text" ondragstart="handleDragDropEvent(event)" ondrag="handleDragDropEvent(event)" ondragend="handleDragDropEvent(event)" /> <input type="text" ondragenter="handleDragDropEvent(event)" ondragover="handleDragDropEvent(event)" ondragleave="handleDragDropEvent(event)" ondrop="handleDragDropEvent(event)" />
<textarea rows="10" cols="25" readonly="readonly" id="txt1"></textarea>
</body>
</html></source>