Upgrade to ExtJS 3.0.3 - Released 10/11/2009
[extjs.git] / src / dd / DragSource.js
1 /*!
2  * Ext JS Library 3.0.3
3  * Copyright(c) 2006-2009 Ext JS, LLC
4  * licensing@extjs.com
5  * http://www.extjs.com/license
6  */
7 /**\r
8  * @class Ext.dd.DragSource\r
9  * @extends Ext.dd.DDProxy\r
10  * A simple class that provides the basic implementation needed to make any element draggable.\r
11  * @constructor\r
12  * @param {Mixed} el The container element\r
13  * @param {Object} config\r
14  */\r
15 Ext.dd.DragSource = function(el, config){\r
16     this.el = Ext.get(el);\r
17     if(!this.dragData){\r
18         this.dragData = {};\r
19     }\r
20     \r
21     Ext.apply(this, config);\r
22     \r
23     if(!this.proxy){\r
24         this.proxy = new Ext.dd.StatusProxy();\r
25     }\r
26     Ext.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group, \r
27           {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});\r
28     \r
29     this.dragging = false;\r
30 };\r
31 \r
32 Ext.extend(Ext.dd.DragSource, Ext.dd.DDProxy, {\r
33     /**\r
34      * @cfg {String} ddGroup\r
35      * A named drag drop group to which this object belongs.  If a group is specified, then this object will only\r
36      * interact with other drag drop objects in the same group (defaults to undefined).\r
37      */\r
38     /**\r
39      * @cfg {String} dropAllowed\r
40      * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").\r
41      */\r
42     dropAllowed : "x-dd-drop-ok",\r
43     /**\r
44      * @cfg {String} dropNotAllowed\r
45      * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").\r
46      */\r
47     dropNotAllowed : "x-dd-drop-nodrop",\r
48 \r
49     /**\r
50      * Returns the data object associated with this drag source\r
51      * @return {Object} data An object containing arbitrary data\r
52      */\r
53     getDragData : function(e){\r
54         return this.dragData;\r
55     },\r
56 \r
57     // private\r
58     onDragEnter : function(e, id){\r
59         var target = Ext.dd.DragDropMgr.getDDById(id);\r
60         this.cachedTarget = target;\r
61         if(this.beforeDragEnter(target, e, id) !== false){\r
62             if(target.isNotifyTarget){\r
63                 var status = target.notifyEnter(this, e, this.dragData);\r
64                 this.proxy.setStatus(status);\r
65             }else{\r
66                 this.proxy.setStatus(this.dropAllowed);\r
67             }\r
68             \r
69             if(this.afterDragEnter){\r
70                 /**\r
71                  * An empty function by default, but provided so that you can perform a custom action\r
72                  * when the dragged item enters the drop target by providing an implementation.\r
73                  * @param {Ext.dd.DragDrop} target The drop target\r
74                  * @param {Event} e The event object\r
75                  * @param {String} id The id of the dragged element\r
76                  * @method afterDragEnter\r
77                  */\r
78                 this.afterDragEnter(target, e, id);\r
79             }\r
80         }\r
81     },\r
82 \r
83     /**\r
84      * An empty function by default, but provided so that you can perform a custom action\r
85      * before the dragged item enters the drop target and optionally cancel the onDragEnter.\r
86      * @param {Ext.dd.DragDrop} target The drop target\r
87      * @param {Event} e The event object\r
88      * @param {String} id The id of the dragged element\r
89      * @return {Boolean} isValid True if the drag event is valid, else false to cancel\r
90      */\r
91     beforeDragEnter : function(target, e, id){\r
92         return true;\r
93     },\r
94 \r
95     // private\r
96     alignElWithMouse: function() {\r
97         Ext.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);\r
98         this.proxy.sync();\r
99     },\r
100 \r
101     // private\r
102     onDragOver : function(e, id){\r
103         var target = this.cachedTarget || Ext.dd.DragDropMgr.getDDById(id);\r
104         if(this.beforeDragOver(target, e, id) !== false){\r
105             if(target.isNotifyTarget){\r
106                 var status = target.notifyOver(this, e, this.dragData);\r
107                 this.proxy.setStatus(status);\r
108             }\r
109 \r
110             if(this.afterDragOver){\r
111                 /**\r
112                  * An empty function by default, but provided so that you can perform a custom action\r
113                  * while the dragged item is over the drop target by providing an implementation.\r
114                  * @param {Ext.dd.DragDrop} target The drop target\r
115                  * @param {Event} e The event object\r
116                  * @param {String} id The id of the dragged element\r
117                  * @method afterDragOver\r
118                  */\r
119                 this.afterDragOver(target, e, id);\r
120             }\r
121         }\r
122     },\r
123 \r
124     /**\r
125      * An empty function by default, but provided so that you can perform a custom action\r
126      * while the dragged item is over the drop target and optionally cancel the onDragOver.\r
127      * @param {Ext.dd.DragDrop} target The drop target\r
128      * @param {Event} e The event object\r
129      * @param {String} id The id of the dragged element\r
130      * @return {Boolean} isValid True if the drag event is valid, else false to cancel\r
131      */\r
132     beforeDragOver : function(target, e, id){\r
133         return true;\r
134     },\r
135 \r
136     // private\r
137     onDragOut : function(e, id){\r
138         var target = this.cachedTarget || Ext.dd.DragDropMgr.getDDById(id);\r
139         if(this.beforeDragOut(target, e, id) !== false){\r
140             if(target.isNotifyTarget){\r
141                 target.notifyOut(this, e, this.dragData);\r
142             }\r
143             this.proxy.reset();\r
144             if(this.afterDragOut){\r
145                 /**\r
146                  * An empty function by default, but provided so that you can perform a custom action\r
147                  * after the dragged item is dragged out of the target without dropping.\r
148                  * @param {Ext.dd.DragDrop} target The drop target\r
149                  * @param {Event} e The event object\r
150                  * @param {String} id The id of the dragged element\r
151                  * @method afterDragOut\r
152                  */\r
153                 this.afterDragOut(target, e, id);\r
154             }\r
155         }\r
156         this.cachedTarget = null;\r
157     },\r
158 \r
159     /**\r
160      * An empty function by default, but provided so that you can perform a custom action before the dragged\r
161      * item is dragged out of the target without dropping, and optionally cancel the onDragOut.\r
162      * @param {Ext.dd.DragDrop} target The drop target\r
163      * @param {Event} e The event object\r
164      * @param {String} id The id of the dragged element\r
165      * @return {Boolean} isValid True if the drag event is valid, else false to cancel\r
166      */\r
167     beforeDragOut : function(target, e, id){\r
168         return true;\r
169     },\r
170     \r
171     // private\r
172     onDragDrop : function(e, id){\r
173         var target = this.cachedTarget || Ext.dd.DragDropMgr.getDDById(id);\r
174         if(this.beforeDragDrop(target, e, id) !== false){\r
175             if(target.isNotifyTarget){\r
176                 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?\r
177                     this.onValidDrop(target, e, id);\r
178                 }else{\r
179                     this.onInvalidDrop(target, e, id);\r
180                 }\r
181             }else{\r
182                 this.onValidDrop(target, e, id);\r
183             }\r
184             \r
185             if(this.afterDragDrop){\r
186                 /**\r
187                  * An empty function by default, but provided so that you can perform a custom action\r
188                  * after a valid drag drop has occurred by providing an implementation.\r
189                  * @param {Ext.dd.DragDrop} target The drop target\r
190                  * @param {Event} e The event object\r
191                  * @param {String} id The id of the dropped element\r
192                  * @method afterDragDrop\r
193                  */\r
194                 this.afterDragDrop(target, e, id);\r
195             }\r
196         }\r
197         delete this.cachedTarget;\r
198     },\r
199 \r
200     /**\r
201      * An empty function by default, but provided so that you can perform a custom action before the dragged\r
202      * item is dropped onto the target and optionally cancel the onDragDrop.\r
203      * @param {Ext.dd.DragDrop} target The drop target\r
204      * @param {Event} e The event object\r
205      * @param {String} id The id of the dragged element\r
206      * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel\r
207      */\r
208     beforeDragDrop : function(target, e, id){\r
209         return true;\r
210     },\r
211 \r
212     // private\r
213     onValidDrop : function(target, e, id){\r
214         this.hideProxy();\r
215         if(this.afterValidDrop){\r
216             /**\r
217              * An empty function by default, but provided so that you can perform a custom action\r
218              * after a valid drop has occurred by providing an implementation.\r
219              * @param {Object} target The target DD \r
220              * @param {Event} e The event object\r
221              * @param {String} id The id of the dropped element\r
222              * @method afterInvalidDrop\r
223              */\r
224             this.afterValidDrop(target, e, id);\r
225         }\r
226     },\r
227 \r
228     // private\r
229     getRepairXY : function(e, data){\r
230         return this.el.getXY();  \r
231     },\r
232 \r
233     // private\r
234     onInvalidDrop : function(target, e, id){\r
235         this.beforeInvalidDrop(target, e, id);\r
236         if(this.cachedTarget){\r
237             if(this.cachedTarget.isNotifyTarget){\r
238                 this.cachedTarget.notifyOut(this, e, this.dragData);\r
239             }\r
240             this.cacheTarget = null;\r
241         }\r
242         this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);\r
243 \r
244         if(this.afterInvalidDrop){\r
245             /**\r
246              * An empty function by default, but provided so that you can perform a custom action\r
247              * after an invalid drop has occurred by providing an implementation.\r
248              * @param {Event} e The event object\r
249              * @param {String} id The id of the dropped element\r
250              * @method afterInvalidDrop\r
251              */\r
252             this.afterInvalidDrop(e, id);\r
253         }\r
254     },\r
255 \r
256     // private\r
257     afterRepair : function(){\r
258         if(Ext.enableFx){\r
259             this.el.highlight(this.hlColor || "c3daf9");\r
260         }\r
261         this.dragging = false;\r
262     },\r
263 \r
264     /**\r
265      * An empty function by default, but provided so that you can perform a custom action after an invalid\r
266      * drop has occurred.\r
267      * @param {Ext.dd.DragDrop} target The drop target\r
268      * @param {Event} e The event object\r
269      * @param {String} id The id of the dragged element\r
270      * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel\r
271      */\r
272     beforeInvalidDrop : function(target, e, id){\r
273         return true;\r
274     },\r
275 \r
276     // private\r
277     handleMouseDown : function(e){\r
278         if(this.dragging) {\r
279             return;\r
280         }\r
281         var data = this.getDragData(e);\r
282         if(data && this.onBeforeDrag(data, e) !== false){\r
283             this.dragData = data;\r
284             this.proxy.stop();\r
285             Ext.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);\r
286         } \r
287     },\r
288 \r
289     /**\r
290      * An empty function by default, but provided so that you can perform a custom action before the initial\r
291      * drag event begins and optionally cancel it.\r
292      * @param {Object} data An object containing arbitrary data to be shared with drop targets\r
293      * @param {Event} e The event object\r
294      * @return {Boolean} isValid True if the drag event is valid, else false to cancel\r
295      */\r
296     onBeforeDrag : function(data, e){\r
297         return true;\r
298     },\r
299 \r
300     /**\r
301      * An empty function by default, but provided so that you can perform a custom action once the initial\r
302      * drag event has begun.  The drag cannot be canceled from this function.\r
303      * @param {Number} x The x position of the click on the dragged object\r
304      * @param {Number} y The y position of the click on the dragged object\r
305      */\r
306     onStartDrag : Ext.emptyFn,\r
307 \r
308     // private override\r
309     startDrag : function(x, y){\r
310         this.proxy.reset();\r
311         this.dragging = true;\r
312         this.proxy.update("");\r
313         this.onInitDrag(x, y);\r
314         this.proxy.show();\r
315     },\r
316 \r
317     // private\r
318     onInitDrag : function(x, y){\r
319         var clone = this.el.dom.cloneNode(true);\r
320         clone.id = Ext.id(); // prevent duplicate ids\r
321         this.proxy.update(clone);\r
322         this.onStartDrag(x, y);\r
323         return true;\r
324     },\r
325 \r
326     /**\r
327      * Returns the drag source's underlying {@link Ext.dd.StatusProxy}\r
328      * @return {Ext.dd.StatusProxy} proxy The StatusProxy\r
329      */\r
330     getProxy : function(){\r
331         return this.proxy;  \r
332     },\r
333 \r
334     /**\r
335      * Hides the drag source's {@link Ext.dd.StatusProxy}\r
336      */\r
337     hideProxy : function(){\r
338         this.proxy.hide();  \r
339         this.proxy.reset(true);\r
340         this.dragging = false;\r
341     },\r
342 \r
343     // private\r
344     triggerCacheRefresh : function(){\r
345         Ext.dd.DDM.refreshCache(this.groups);\r
346     },\r
347 \r
348     // private - override to prevent hiding\r
349     b4EndDrag: function(e) {\r
350     },\r
351 \r
352     // private - override to prevent moving\r
353     endDrag : function(e){\r
354         this.onEndDrag(this.dragData, e);\r
355     },\r
356 \r
357     // private\r
358     onEndDrag : function(data, e){\r
359     },\r
360     \r
361     // private - pin to cursor\r
362     autoOffset : function(x, y) {\r
363         this.setDelta(-12, -20);\r
364     }    \r
365 });