Upgrade to ExtJS 3.2.0 - Released 03/30/2010
[extjs.git] / src / dd / DropZone.js
1 /*!
2  * Ext JS Library 3.2.0
3  * Copyright(c) 2006-2010 Ext JS, Inc.
4  * licensing@extjs.com
5  * http://www.extjs.com/license
6  */
7 /**
8  * @class Ext.dd.DropZone
9  * @extends Ext.dd.DropTarget
10  * <p>This class provides a container DD instance that allows dropping on multiple child target nodes.</p>
11  * <p>By default, this class requires that child nodes accepting drop are registered with {@link Ext.dd.Registry}.
12  * However a simpler way to allow a DropZone to manage any number of target elements is to configure the
13  * DropZone with an implementation of {@link #getTargetFromEvent} which interrogates the passed
14  * mouse event to see if it has taken place within an element, or class of elements. This is easily done
15  * by using the event's {@link Ext.EventObject#getTarget getTarget} method to identify a node based on a
16  * {@link Ext.DomQuery} selector.</p>
17  * <p>Once the DropZone has detected through calling getTargetFromEvent, that the mouse is over
18  * a drop target, that target is passed as the first parameter to {@link #onNodeEnter}, {@link #onNodeOver},
19  * {@link #onNodeOut}, {@link #onNodeDrop}. You may configure the instance of DropZone with implementations
20  * of these methods to provide application-specific behaviour for these events to update both
21  * application state, and UI state.</p>
22  * <p>For example to make a GridPanel a cooperating target with the example illustrated in
23  * {@link Ext.dd.DragZone DragZone}, the following technique might be used:</p><pre><code>
24 myGridPanel.on('render', function() {
25     myGridPanel.dropZone = new Ext.dd.DropZone(myGridPanel.getView().scroller, {
26
27 //      If the mouse is over a grid row, return that node. This is
28 //      provided as the "target" parameter in all "onNodeXXXX" node event handling functions
29         getTargetFromEvent: function(e) {
30             return e.getTarget(myGridPanel.getView().rowSelector);
31         },
32
33 //      On entry into a target node, highlight that node.
34         onNodeEnter : function(target, dd, e, data){ 
35             Ext.fly(target).addClass('my-row-highlight-class');
36         },
37
38 //      On exit from a target node, unhighlight that node.
39         onNodeOut : function(target, dd, e, data){ 
40             Ext.fly(target).removeClass('my-row-highlight-class');
41         },
42
43 //      While over a target node, return the default drop allowed class which
44 //      places a "tick" icon into the drag proxy.
45         onNodeOver : function(target, dd, e, data){ 
46             return Ext.dd.DropZone.prototype.dropAllowed;
47         },
48
49 //      On node drop we can interrogate the target to find the underlying
50 //      application object that is the real target of the dragged data.
51 //      In this case, it is a Record in the GridPanel's Store.
52 //      We can use the data set up by the DragZone's getDragData method to read
53 //      any data we decided to attach in the DragZone's getDragData method.
54         onNodeDrop : function(target, dd, e, data){
55             var rowIndex = myGridPanel.getView().findRowIndex(target);
56             var r = myGridPanel.getStore().getAt(rowIndex);
57             Ext.Msg.alert('Drop gesture', 'Dropped Record id ' + data.draggedRecord.id +
58                 ' on Record id ' + r.id);
59             return true;
60         }
61     });
62 }
63 </code></pre>
64  * See the {@link Ext.dd.DragZone DragZone} documentation for details about building a DragZone which
65  * cooperates with this DropZone.
66  * @constructor
67  * @param {Mixed} el The container element
68  * @param {Object} config
69  */
70 Ext.dd.DropZone = function(el, config){
71     Ext.dd.DropZone.superclass.constructor.call(this, el, config);
72 };
73
74 Ext.extend(Ext.dd.DropZone, Ext.dd.DropTarget, {
75     /**
76      * Returns a custom data object associated with the DOM node that is the target of the event.  By default
77      * this looks up the event target in the {@link Ext.dd.Registry}, although you can override this method to
78      * provide your own custom lookup.
79      * @param {Event} e The event
80      * @return {Object} data The custom data
81      */
82     getTargetFromEvent : function(e){
83         return Ext.dd.Registry.getTargetFromEvent(e);
84     },
85
86     /**
87      * Called when the DropZone determines that a {@link Ext.dd.DragSource} has entered a drop node
88      * that has either been registered or detected by a configured implementation of {@link #getTargetFromEvent}.
89      * This method has no default implementation and should be overridden to provide
90      * node-specific processing if necessary.
91      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from 
92      * {@link #getTargetFromEvent} for this node)
93      * @param {Ext.dd.DragSource} source The drag source that was dragged over this drop zone
94      * @param {Event} e The event
95      * @param {Object} data An object containing arbitrary data supplied by the drag source
96      */
97     onNodeEnter : function(n, dd, e, data){
98         
99     },
100
101     /**
102      * Called while the DropZone determines that a {@link Ext.dd.DragSource} is over a drop node
103      * that has either been registered or detected by a configured implementation of {@link #getTargetFromEvent}.
104      * The default implementation returns this.dropNotAllowed, so it should be
105      * overridden to provide the proper feedback.
106      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
107      * {@link #getTargetFromEvent} for this node)
108      * @param {Ext.dd.DragSource} source The drag source that was dragged over this drop zone
109      * @param {Event} e The event
110      * @param {Object} data An object containing arbitrary data supplied by the drag source
111      * @return {String} status The CSS class that communicates the drop status back to the source so that the
112      * underlying {@link Ext.dd.StatusProxy} can be updated
113      */
114     onNodeOver : function(n, dd, e, data){
115         return this.dropAllowed;
116     },
117
118     /**
119      * Called when the DropZone determines that a {@link Ext.dd.DragSource} has been dragged out of
120      * the drop node without dropping.  This method has no default implementation and should be overridden to provide
121      * node-specific processing if necessary.
122      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
123      * {@link #getTargetFromEvent} for this node)
124      * @param {Ext.dd.DragSource} source The drag source that was dragged over this drop zone
125      * @param {Event} e The event
126      * @param {Object} data An object containing arbitrary data supplied by the drag source
127      */
128     onNodeOut : function(n, dd, e, data){
129         
130     },
131
132     /**
133      * Called when the DropZone determines that a {@link Ext.dd.DragSource} has been dropped onto
134      * the drop node.  The default implementation returns false, so it should be overridden to provide the
135      * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
136      * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
137      * {@link #getTargetFromEvent} for this node)
138      * @param {Ext.dd.DragSource} source The drag source that was dragged over this drop zone
139      * @param {Event} e The event
140      * @param {Object} data An object containing arbitrary data supplied by the drag source
141      * @return {Boolean} True if the drop was valid, else false
142      */
143     onNodeDrop : function(n, dd, e, data){
144         return false;
145     },
146
147     /**
148      * Called while the DropZone determines that a {@link Ext.dd.DragSource} is being dragged over it,
149      * but not over any of its registered drop nodes.  The default implementation returns this.dropNotAllowed, so
150      * it should be overridden to provide the proper feedback if necessary.
151      * @param {Ext.dd.DragSource} source The drag source that was dragged over this drop zone
152      * @param {Event} e The event
153      * @param {Object} data An object containing arbitrary data supplied by the drag source
154      * @return {String} status The CSS class that communicates the drop status back to the source so that the
155      * underlying {@link Ext.dd.StatusProxy} can be updated
156      */
157     onContainerOver : function(dd, e, data){
158         return this.dropNotAllowed;
159     },
160
161     /**
162      * Called when the DropZone determines that a {@link Ext.dd.DragSource} has been dropped on it,
163      * but not on any of its registered drop nodes.  The default implementation returns false, so it should be
164      * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
165      * be able to accept drops.  It should return true when valid so that the drag source's repair action does not run.
166      * @param {Ext.dd.DragSource} source The drag source that was dragged over this drop zone
167      * @param {Event} e The event
168      * @param {Object} data An object containing arbitrary data supplied by the drag source
169      * @return {Boolean} True if the drop was valid, else false
170      */
171     onContainerDrop : function(dd, e, data){
172         return false;
173     },
174
175     /**
176      * The function a {@link Ext.dd.DragSource} calls once to notify this drop zone that the source is now over
177      * the zone.  The default implementation returns this.dropNotAllowed and expects that only registered drop
178      * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
179      * you should override this method and provide a custom implementation.
180      * @param {Ext.dd.DragSource} source The drag source that was dragged over this drop zone
181      * @param {Event} e The event
182      * @param {Object} data An object containing arbitrary data supplied by the drag source
183      * @return {String} status The CSS class that communicates the drop status back to the source so that the
184      * underlying {@link Ext.dd.StatusProxy} can be updated
185      */
186     notifyEnter : function(dd, e, data){
187         return this.dropNotAllowed;
188     },
189
190     /**
191      * The function a {@link Ext.dd.DragSource} calls continuously while it is being dragged over the drop zone.
192      * This method will be called on every mouse movement while the drag source is over the drop zone.
193      * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
194      * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
195      * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
196      * registered node, it will call {@link #onContainerOver}.
197      * @param {Ext.dd.DragSource} source The drag source that was dragged over this drop zone
198      * @param {Event} e The event
199      * @param {Object} data An object containing arbitrary data supplied by the drag source
200      * @return {String} status The CSS class that communicates the drop status back to the source so that the
201      * underlying {@link Ext.dd.StatusProxy} can be updated
202      */
203     notifyOver : function(dd, e, data){
204         var n = this.getTargetFromEvent(e);
205         if(!n){ // not over valid drop target
206             if(this.lastOverNode){
207                 this.onNodeOut(this.lastOverNode, dd, e, data);
208                 this.lastOverNode = null;
209             }
210             return this.onContainerOver(dd, e, data);
211         }
212         if(this.lastOverNode != n){
213             if(this.lastOverNode){
214                 this.onNodeOut(this.lastOverNode, dd, e, data);
215             }
216             this.onNodeEnter(n, dd, e, data);
217             this.lastOverNode = n;
218         }
219         return this.onNodeOver(n, dd, e, data);
220     },
221
222     /**
223      * The function a {@link Ext.dd.DragSource} calls once to notify this drop zone that the source has been dragged
224      * out of the zone without dropping.  If the drag source is currently over a registered node, the notification
225      * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
226      * @param {Ext.dd.DragSource} source The drag source that was dragged over this drop target
227      * @param {Event} e The event
228      * @param {Object} data An object containing arbitrary data supplied by the drag zone
229      */
230     notifyOut : function(dd, e, data){
231         if(this.lastOverNode){
232             this.onNodeOut(this.lastOverNode, dd, e, data);
233             this.lastOverNode = null;
234         }
235     },
236
237     /**
238      * The function a {@link Ext.dd.DragSource} calls once to notify this drop zone that the dragged item has
239      * been dropped on it.  The drag zone will look up the target node based on the event passed in, and if there
240      * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
241      * otherwise it will call {@link #onContainerDrop}.
242      * @param {Ext.dd.DragSource} source The drag source that was dragged over this drop zone
243      * @param {Event} e The event
244      * @param {Object} data An object containing arbitrary data supplied by the drag source
245      * @return {Boolean} True if the drop was valid, else false
246      */
247     notifyDrop : function(dd, e, data){
248         if(this.lastOverNode){
249             this.onNodeOut(this.lastOverNode, dd, e, data);
250             this.lastOverNode = null;
251         }
252         var n = this.getTargetFromEvent(e);
253         return n ?
254             this.onNodeDrop(n, dd, e, data) :
255             this.onContainerDrop(dd, e, data);
256     },
257
258     // private
259     triggerCacheRefresh : function(){
260         Ext.dd.DDM.refreshCache(this.groups);
261     }  
262 });