<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()"> <P>Try dragging the red square onto the blue square.</p> <div id="div1"></div> <div id="divDropTarget"></div> </body> </html>
|