| Summary: Advanced Custom Drag & Drop Basics Part 1 |
| Author: Jozef Sakalos |
| Published: September 16, 2007 |
| Ext Version: 1.1+ / 2.0+ |
Languages: English
|
Contents |
This tutorial will guide you through basics of advanced custom drag & drop. You can use this approach when you have a container with many items to be dragged. Items can be dynamically created and they don't require any special setup as long as they are children of the container.
The tutorial is really advanced what means that you have to be familiar with principles described in the following tutorials:
We will extend Ext.dd.DragZone in this part. This class creates its own drag proxy (Ext.dd.StatusProxy) which will do for now. The most important method we will override is getDragData which is called on mousedown event and it is responsible for finding out which item was clicked and for preparing drag data object that is returned from this function. Returned object has to have ddel property containing an HTML element. This element is appended to drag proxy.
It contains two containers (DragZones) each containing three items to be dragged. For the simplicity of the tutorial it also contains embedded style sheets.
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <link rel="stylesheet" type="text/css" href="../extjs/resources/css/ext-all.css"> <script type="text/javascript" src="../extjs/adapter/ext/ext-base.js"></script> <script type="text/javascript" src="../extjs/ext-all-debug.js"></script> <script type="text/javascript" src="dd.js"></script> <!-- A Localization Script File comes here --> <script type="text/javascript">Ext.onReady(Tutorial.dd.init, Tutorial.dd);</script> <title>Advanced Custom Drag & Drop Tutorial</title> <style type="text/css"> body { font-size: 11px; font-family: arial; } .dd-ct { position:absolute; border: 1px solid silver; width: 180px; height: 180px; top: 32px; background-color: #ffffc0; } #dd1-ct { left: 64px; } #dd2-ct { left: 256px; } .dd-item { height: 14px; border: 1px solid #a0a0a0; background-color: #c4d0ff; vertical-align: middle; cursor: move; padding: 2px; z-index: 1000; margin: 2px; } .dd-ct .dd-item { margin: 2px; } .dd-proxy { opacity: 0.4; -moz-opacity: 0.4; filter: alpha(opacity=40); } .dd-over { background-color: #ffff60; } </style> </head> <body> <div class="dd-ct" id="dd1-ct"> <div class="dd-item" id="dd1-item1">Item 1.1</div> <div class="dd-item" id="dd1-item2">Item 1.2</div> <div class="dd-item" id="dd1-item3">Item 1.3</div> </div> <div class="dd-ct" id="dd2-ct"> <div class="dd-item" id="dd2-item1">Item 2.1</div> <div class="dd-item" id="dd2-item2">Item 2.2</div> <div class="dd-item" id="dd2-item3">Item 2.3</div> </div> </body> </html>
This is file we are going to work with. It contains javascript code of both the extension class and the application. Let's start with this content:
/** * Advanced_Custom Drag & Drop Tutorial * by Jozef Sakalos, aka Saki * http://extjs.com/learn/Tutorial:Advanced_Custom_Drag_and_Drop_Part_1 */ // reference local blank image Ext.BLANK_IMAGE_URL = '../extjs/resources/images/default/s.gif'; Ext.namespace('Tutorial', 'Tutorial.dd'); // create application Tutorial.dd = function() { // do NOT access DOM from here; elements don't exist yet // private variables var dragZone1, dragZone2; // private functions // public space return { // public properties, e.g. strings to translate // public methods init: function() { dragZone1 = new Tutorial.dd.MyDragZone('dd1-ct', { ddGroup: 'group', scroll: false }); dragZone2 = new Tutorial.dd.MyDragZone('dd2-ct', { ddGroup: 'group', scroll: false }); } }; }(); // end of app Tutorial.dd.MyDragZone = function(el, config) { config = config || {}; Ext.apply(config, { ddel: document.createElement('div') }); Tutorial.dd.MyDragZone.superclass.constructor.call(this, el, config); }; Ext.extend(Tutorial.dd.MyDragZone, Ext.dd.DragZone, { getDragData: function(e) { var target = Ext.get(e.getTarget()); if(target.hasClass('dd-ct')) { return false; } return {ddel:this.ddel, item:target}; } }); // end of file
In the constructor of our extended class (MyDragZone) we create ddel and call the parent constructor.
In getDragData we filter out container as we don't want to drag it and then we return drag data object. The item decision logic would need to be much more clever in real life; here we only have simple divs with text to be dragged. Returned drag data object contains mandatory ddel and property item which is element being dragged. Again, in real life, you might need more data to return.
Navigate to dd.html and try to drag an item. Well, we got some result but we're dragging an empty div. Let's improve it.
Add the following method to our extension class:
onInitDrag: function(e) { this.ddel.innerHTML = this.dragData.item.dom.innerHTML; this.ddel.className = this.dragData.item.dom.className; this.ddel.style.width = this.dragData.item.getWidth() + "px"; this.proxy.update(this.ddel); }
What it does: It copies dragged item content (this.dragData.item) to the drag proxy and adjusts its appearance (className and width).
Test it now! Nice, yeah. The only problem is that when we drop the item it doesn't look nice. It just somehow disappears at the drop position. Let's improve it a bit.
All we need to do is to add the following method to our extension class:
getRepairXY: function(e, data) { data.item.highlight('#e8edff'); return data.item.getXY(); }
What it does? It highlights the original element using specified highlight color and then returns position of the original element.
Test it now! That is what we wanted to have.
So far, so good. Continue to Part 2 to see how to process drops.