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