First, I want to say I am not a JavaScript expert. The last time I used JavaScript was 7 years ago. Recently I started working on a web site which needs to allow user drag and drop items from a list. I did a lot of research and found some very useful articles. They helped me to implement this feature on my site.
These articles are
http://aspalliance.com/1300_Custom_Client_Side_Drag_and_Drop_Behavior_in_ASPNET_AJAX
http://www.codeproject.com/KB/ajax/JigsawPuzzleGame.aspx
http://msdn.microsoft.com/en-us/magazine/cc135985.aspx
Although they are very helpful, my scenario is not exactly the same. I want to be able to drag an item, drop to an area and then drag/drop it again later. I tried to mimic the Jigsaw Puzzle sample. However, since my item is not an image, only a string, I got lost during the re-writing. Finally I figured out my own solution.
Below is the screen shot of my sample. You can download the sample code from here.
User can drag/drop an item from the list on top to the “Drop it here” area. User can also move the items between grids. Finally, user can remove an item by drag/drop it to the Garbage Can area.
Let’s see how we implement this by using ASP.NET AJAX and Javascript:
Before you start, you will need to download the ASP.NET 3.5 Extension Preview:
and ASP.NET Future
http://www.asp.net/downloads/futures/default.aspx?wwwaspnetrdirset=1
-
Add reference to “Microsoft.Web.Preview for .NET 3.5” in your project.
-
Add ScriptManager to the page since we are using AJAX
-
Add ScriptReference
<asp:ScriptManager runat="server" ID="ScriptManager1">
<Scripts>
<asp:ScriptReference Name="PreviewScript.js" Assembly="Microsoft.Web.Preview" />
<asp:ScriptReference Name="PreviewDragDrop.js" Assembly="Microsoft.Web.Preview" />
</Scripts>
</asp:ScriptManager>
- Create a page with the following html elements
<div id="dragItem1">Item 1</div><br />
<div id="dragItem2">Item 2</div><br />
<div id="dragItem3">Item 3</div><br />
<div id="dragItem4">Item 4</div><br />
<div>
<table border="1" id="dragDropZone">
<tr>
<td width="100" height="100" id="target1">Drop it here</td>
<td width="100" height="100" id="target2">Drop it here</td>
<td width="100" height="100" id="target3">Drop it here</td>
<td width="100" height="100" id="target4">Drop it here</td>
</tr>
<tr><td colspan="4" height="100" id="garbageCan">Garbage Can</td></tr>
</table>
</div>
- Create DragDrop.js. I posted the whole file here. Please see comments for explaination.
Type.registerNamespace('DotNetIdeas.Ajax.UI');
//ItemDragSourceBehavior
DotNetIdeas.Ajax.UI.ItemDragSourceBehavior = function(element, item, parent, target)
{
DotNetIdeas.Ajax.UI.ItemDragSourceBehavior.initializeBase(this, [element]);
this._mouseDownHandler = Function.createDelegate(this,
this.mouseDownHandler);
this._item = item;
this._visual = null;
this._parent = parent; // Parent control which hold the drag items and drop targes
this._target = target; // current target the drag item is on
}
DotNetIdeas.Ajax.UI.ItemDragSourceBehavior.prototype =
{
// IDragSource methods
get_dragDataType: function() {
return 'DragDropItem';
},
getDragData: function(context) {
return this._item;
},
get_dragMode: function() {
return Sys.Preview.UI.DragMode.Move;
},
//The following two functions are for FireFox, so it won't select the text when drag starts
returnFalse: function() { return false; },
returnTrue: function() { return true; },
onDragStart: function() {
document.onmousedown = this.returnFalse;
// Set the leaving target, so we can remove this item from it later
if (this._parent) this._parent.setLeavingTarget(this._target);
},
onDrag: function() { },
onDragEnd: function(canceled) {
// If drag from the outside of the dragdrop control, then there will be a shadow when moving the item,
// so we need to remove it when drag is end
if (this._visual && this.get_element().parentNode)
this.get_element().parentNode.removeChild(this._visual);
document.onmousedown = this.returnTrue;
},
// Other methods
initialize: function() {
DotNetIdeas.Ajax.UI.ItemDragSourceBehavior.callBaseMethod(this,
'initialize');
$addHandler(this.get_element(), 'mousedown',
this._mouseDownHandler)
},
mouseDownHandler: function(ev) {
window._event = ev; // Needed internally by _DragDropManager
this._visual = this.get_element().cloneNode(true);
this._visual.style.opacity = '0.4';
this._visual.style.filter =
'progid:DXImageTransform.Microsoft.BasicImage(opacity=0.4)';
this._visual.style.zIndex = 99999;
this.get_element().parentNode.appendChild(this._visual);
var location =
Sys.UI.DomElement.getLocation(this.get_element());
Sys.UI.DomElement.setLocation(this._visual, location.x,
location.y);
Sys.Preview.UI.DragDropManager.startDragDrop(this,
this._visual, null);
},
dispose: function() {
if (this._mouseDownHandler)
$removeHandler(this.get_element(), 'mousedown',
this._mouseDownHandler);
this._mouseDownHandler = null;
DotNetIdeas.Ajax.UI.ItemDragSourceBehavior.callBaseMethod(this,
'dispose');
}
}
DotNetIdeas.Ajax.UI.ItemDragSourceBehavior.registerClass
('DotNetIdeas.Ajax.UI.ItemDragSourceBehavior', Sys.UI.Behavior,
Sys.Preview.UI.IDragSource);
//ItemDropTargetBehavior
DotNetIdeas.Ajax.UI.ItemDropTargetBehavior = function(element, parent)
{
DotNetIdeas.Ajax.UI.ItemDropTargetBehavior.initializeBase(this, [element]);
this._items = new Array();
this._parent = parent;
this.targetType = "Target";
}
DotNetIdeas.Ajax.UI.ItemDropTargetBehavior.prototype =
{
// IDropTarget methods
get_dropTargetElement: function()
{
return this.get_element();
},
canDrop: function(dragMode, dataType, data)
{
return (dataType == 'DragDropItem' && data);
},
drop: function(dragMode, dataType, data)
{
if (dataType == 'DragDropItem' && data)
{
if (this.targetType != 'GarbageCan')
{
// If the item already exists in this target area, do not add it again.
for(var id in this._items)
{
if (this._items[id] == data) return;
}
// Add new item to item list in this target area
var newId = this._items.length;
this._items[newId] = data;
var itemBuilder = new Sys.StringBuilder();
var targetId = this.get_element().id.toString();
// Re-generate the HTML string for the items
for (var id in this._items) {
itemBuilder.append("<div id='droppedItem_" + targetId + "_" + id.toString() + "'>" );
itemBuilder.append(this._items[id]);
itemBuilder.append("</div>");
}
this.get_element().innerHTML = itemBuilder.toString();
// Create the draggable items
for (var id in this._items) {
var itemId = "droppedItem" + "_" + targetId + "_" + id.toString();
var droppedItem = new DotNetIdeas.Ajax.UI.ItemDragSourceBehavior($get(itemId), $get(itemId).innerHTML, this._parent, this);
droppedItem.initialize();
}
}
// Remove this item from its previous target
var leavingTarget = this._parent.getLeavingTarget();
if (leavingTarget)
{
leavingTarget.removeItem(data);
}
this._parent.setLeavingTarget(null);
}
},
onDragEnterTarget: function(dragMode, dataType, data)
{
// Highlight the drop zone by changing its background
// color to light gray
if (dataType == 'DragDropItem' && data)
{
this._color = this.get_element().style.backgroundColor;
this.get_element().style.backgroundColor = '#E0E0E0';
}
},
onDragLeaveTarget: function(dragMode, dataType, data)
{
// Unhighlight the drop zone by restoring its original
// background color
if (dataType == 'DragDropItem' && data)
{
this.get_element().style.backgroundColor = "White";
}
},
onDragInTarget: function(dragMode, dataType, data) {},
// Other methods
initialize: function()
{
DotNetIdeas.Ajax.UI.ItemDropTargetBehavior.callBaseMethod(this,
'initialize');
Sys.Preview.UI.DragDropManager.registerDropTarget(this);
},
dispose: function()
{
Sys.Preview.UI.DragDropManager.unregisterDropTarget(this);
DotNetIdeas.Ajax.UI.ItemDropTargetBehavior.callBaseMethod(this,
'dispose');
},
// Remove items from target area
removeItem : function(data)
{
// Remove item from the item list
var j = 0;
while (j < this._items.length) {
if (this._items[j] == data) {
this._items.splice(j, 1);
}
else {
j++;
}
}
// Re-generate HTML for the items
var itemBuilder = new Sys.StringBuilder();
var targetId = this.get_element().id.toString();
for (var id in this._items) {
itemBuilder.append("<div id='droppedItem_" + targetId + "_" + id.toString() + "'>" );
itemBuilder.append(this._items[id]);
itemBuilder.append("</div>");
}
this.get_element().innerHTML = itemBuilder.toString();
// Re-create the draggable items
for (var id in this._items) {
var itemId = "droppedItem" + "_" + targetId + "_" + id.toString();
var droppedItem = new DotNetIdeas.Ajax.UI.ItemDragSourceBehavior($get(itemId), $get(itemId).innerHTML);
droppedItem.initialize();
}
}
}
DotNetIdeas.Ajax.UI.ItemDropTargetBehavior.registerClass
('DotNetIdeas.Ajax.UI.ItemDropTargetBehavior', Sys.UI.Behavior,
Sys.Preview.UI.IDropTarget);
//DragDrop Zone. It is used as an container of the drop target areas. It is the parent of all the targets.
//When one item is moved from one target to another. It will call setLeavingTarget() to store the previous target,
//so when the item is drop, it knows to remove it from the previous target.
DotNetIdeas.Ajax.UI.DragDropZone = function(element)
{
DotNetIdeas.Ajax.UI.DragDropZone.initializeBase(this, [element]);
this._leavingTarget = null;
}
DotNetIdeas.Ajax.UI.DragDropZone.prototype =
{
initialize : function()
{
DotNetIdeas.Ajax.UI.DragDropZone.callBaseMethod(this, "initialize");
this._renderControl();
},
dispose : function()
{
DotNetIdeas.Ajax.UI.DragDropZone.callBaseMethod(this, "dispose");
},
_renderControl : function()
{
// Create drag/drop targets
var target1 = new DotNetIdeas.Ajax.UI.ItemDropTargetBehavior($get('target1'), this);
var target2 = new DotNetIdeas.Ajax.UI.ItemDropTargetBehavior($get('target2'), this);
var target3 = new DotNetIdeas.Ajax.UI.ItemDropTargetBehavior($get('target3'), this);
var target4 = new DotNetIdeas.Ajax.UI.ItemDropTargetBehavior($get('target4'), this);
var garbageCan = new DotNetIdeas.Ajax.UI.ItemDropTargetBehavior($get('garbageCan'), this);
target1.initialize();
target2.initialize();
target3.initialize();
target4.initialize();
garbageCan.initialize();
garbageCan.targetType = "GarbageCan";
},
setLeavingTarget : function(leavingTarget)
{
this._leavingTarget = leavingTarget;
},
getLeavingTarget : function()
{
return this._leavingTarget;
}
};
DotNetIdeas.Ajax.UI.DragDropZone.registerClass("DotNetIdeas.Ajax.UI.DragDropZone", Sys.UI.Control);
///////////////////////////////////////////////////////////////////////
// Script registration
Sys.Application.notifyScriptLoaded();
Add ScriptReference for DragDrop.js
<asp:ScriptReference Path="~/DragDrop.js" />
- Add following code to header section
<script type="text/javascript">
function pageLoad() {
var source1 = new DotNetIdeas.Ajax.UI.ItemDragSourceBehavior($get('dragItem1'), $get('dragItem1').innerHTML);
var source2 = new DotNetIdeas.Ajax.UI.ItemDragSourceBehavior($get('dragItem2'), $get('dragItem2').innerHTML);
var source3 = new DotNetIdeas.Ajax.UI.ItemDragSourceBehavior($get('dragItem3'), $get('dragItem3').innerHTML);
var source4 = new DotNetIdeas.Ajax.UI.ItemDragSourceBehavior($get('dragItem4'), $get('dragItem4').innerHTML);
source1.initialize();
source2.initialize();
source3.initialize();
source4.initialize();
var dragDropZone = new DotNetIdeas.Ajax.UI.DragDropZone($get('dragDropZone'));
dragDropZone.initialize();
}
</script>
No comments:
Post a Comment