Upgrade to ExtJS 3.0.0 - Released 07/06/2009
[extjs.git] / docs / source / TreeDropZone.html
1 <html>\r
2 <head>\r
3   <title>The source code</title>\r
4     <link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />\r
5     <script type="text/javascript" src="../resources/prettify/prettify.js"></script>\r
6 </head>\r
7 <body  onload="prettyPrint();">\r
8     <pre class="prettyprint lang-js"><div id="cls-Ext.tree.TreeDropZone"></div>/**\r
9  * @class Ext.tree.TreeDropZone\r
10  * @extends Ext.dd.DropZone\r
11  * @constructor\r
12  * @param {String/HTMLElement/Element} tree The {@link Ext.tree.TreePanel} for which to enable dropping\r
13  * @param {Object} config\r
14  */\r
15 if(Ext.dd.DropZone){\r
16     \r
17 Ext.tree.TreeDropZone = function(tree, config){\r
18     <div id="cfg-Ext.tree.TreeDropZone-allowParentInsert"></div>/**\r
19      * @cfg {Boolean} allowParentInsert\r
20      * Allow inserting a dragged node between an expanded parent node and its first child that will become a\r
21      * sibling of the parent when dropped (defaults to false)\r
22      */\r
23     this.allowParentInsert = config.allowParentInsert || false;\r
24     <div id="cfg-Ext.tree.TreeDropZone-allowContainerDrop"></div>/**\r
25      * @cfg {String} allowContainerDrop\r
26      * True if drops on the tree container (outside of a specific tree node) are allowed (defaults to false)\r
27      */\r
28     this.allowContainerDrop = config.allowContainerDrop || false;\r
29     <div id="cfg-Ext.tree.TreeDropZone-appendOnly"></div>/**\r
30      * @cfg {String} appendOnly\r
31      * True if the tree should only allow append drops (use for trees which are sorted, defaults to false)\r
32      */\r
33     this.appendOnly = config.appendOnly || false;\r
34 \r
35     Ext.tree.TreeDropZone.superclass.constructor.call(this, tree.getTreeEl(), config);\r
36     <div id="prop-Ext.tree.TreeDropZone-tree"></div>/**\r
37     * The TreePanel for this drop zone\r
38     * @type Ext.tree.TreePanel\r
39     * @property\r
40     */\r
41     this.tree = tree;\r
42     <div id="prop-Ext.tree.TreeDropZone-dragOverData"></div>/**\r
43     * Arbitrary data that can be associated with this tree and will be included in the event object that gets\r
44     * passed to any nodedragover event handler (defaults to {})\r
45     * @type Ext.tree.TreePanel\r
46     * @property\r
47     */\r
48     this.dragOverData = {};\r
49     // private\r
50     this.lastInsertClass = "x-tree-no-status";\r
51 };\r
52 \r
53 Ext.extend(Ext.tree.TreeDropZone, Ext.dd.DropZone, {\r
54     <div id="cfg-Ext.tree.TreeDropZone-ddGroup"></div>/**\r
55      * @cfg {String} ddGroup\r
56      * A named drag drop group to which this object belongs.  If a group is specified, then this object will only\r
57      * interact with other drag drop objects in the same group (defaults to 'TreeDD').\r
58      */\r
59     ddGroup : "TreeDD",\r
60 \r
61     <div id="cfg-Ext.tree.TreeDropZone-expandDelay"></div>/**\r
62      * @cfg {String} expandDelay\r
63      * The delay in milliseconds to wait before expanding a target tree node while dragging a droppable node\r
64      * over the target (defaults to 1000)\r
65      */\r
66     expandDelay : 1000,\r
67 \r
68     // private\r
69     expandNode : function(node){\r
70         if(node.hasChildNodes() && !node.isExpanded()){\r
71             node.expand(false, null, this.triggerCacheRefresh.createDelegate(this));\r
72         }\r
73     },\r
74 \r
75     // private\r
76     queueExpand : function(node){\r
77         this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]);\r
78     },\r
79 \r
80     // private\r
81     cancelExpand : function(){\r
82         if(this.expandProcId){\r
83             clearTimeout(this.expandProcId);\r
84             this.expandProcId = false;\r
85         }\r
86     },\r
87 \r
88     // private\r
89     isValidDropPoint : function(n, pt, dd, e, data){\r
90         if(!n || !data){ return false; }\r
91         var targetNode = n.node;\r
92         var dropNode = data.node;\r
93         // default drop rules\r
94         if(!(targetNode && targetNode.isTarget && pt)){\r
95             return false;\r
96         }\r
97         if(pt == "append" && targetNode.allowChildren === false){\r
98             return false;\r
99         }\r
100         if((pt == "above" || pt == "below") && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){\r
101             return false;\r
102         }\r
103         if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){\r
104             return false;\r
105         }\r
106         // reuse the object\r
107         var overEvent = this.dragOverData;\r
108         overEvent.tree = this.tree;\r
109         overEvent.target = targetNode;\r
110         overEvent.data = data;\r
111         overEvent.point = pt;\r
112         overEvent.source = dd;\r
113         overEvent.rawEvent = e;\r
114         overEvent.dropNode = dropNode;\r
115         overEvent.cancel = false;  \r
116         var result = this.tree.fireEvent("nodedragover", overEvent);\r
117         return overEvent.cancel === false && result !== false;\r
118     },\r
119 \r
120     // private\r
121     getDropPoint : function(e, n, dd){\r
122         var tn = n.node;\r
123         if(tn.isRoot){\r
124             return tn.allowChildren !== false ? "append" : false; // always append for root\r
125         }\r
126         var dragEl = n.ddel;\r
127         var t = Ext.lib.Dom.getY(dragEl), b = t + dragEl.offsetHeight;\r
128         var y = Ext.lib.Event.getPageY(e);\r
129         var noAppend = tn.allowChildren === false || tn.isLeaf();\r
130         if(this.appendOnly || tn.parentNode.allowChildren === false){\r
131             return noAppend ? false : "append";\r
132         }\r
133         var noBelow = false;\r
134         if(!this.allowParentInsert){\r
135             noBelow = tn.hasChildNodes() && tn.isExpanded();\r
136         }\r
137         var q = (b - t) / (noAppend ? 2 : 3);\r
138         if(y >= t && y < (t + q)){\r
139             return "above";\r
140         }else if(!noBelow && (noAppend || y >= b-q && y <= b)){\r
141             return "below";\r
142         }else{\r
143             return "append";\r
144         }\r
145     },\r
146 \r
147     // private\r
148     onNodeEnter : function(n, dd, e, data){\r
149         this.cancelExpand();\r
150     },\r
151     \r
152     onContainerOver : function(dd, e, data) {\r
153         if (this.allowContainerDrop && this.isValidDropPoint({ ddel: this.tree.getRootNode().ui.elNode, node: this.tree.getRootNode() }, "append", dd, e, data)) {\r
154             return this.dropAllowed;\r
155         }\r
156         return this.dropNotAllowed;\r
157     },\r
158 \r
159     // private\r
160     onNodeOver : function(n, dd, e, data){\r
161         var pt = this.getDropPoint(e, n, dd);\r
162         var node = n.node;\r
163         \r
164         // auto node expand check\r
165         if(!this.expandProcId && pt == "append" && node.hasChildNodes() && !n.node.isExpanded()){\r
166             this.queueExpand(node);\r
167         }else if(pt != "append"){\r
168             this.cancelExpand();\r
169         }\r
170         \r
171         // set the insert point style on the target node\r
172         var returnCls = this.dropNotAllowed;\r
173         if(this.isValidDropPoint(n, pt, dd, e, data)){\r
174            if(pt){\r
175                var el = n.ddel;\r
176                var cls;\r
177                if(pt == "above"){\r
178                    returnCls = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between";\r
179                    cls = "x-tree-drag-insert-above";\r
180                }else if(pt == "below"){\r
181                    returnCls = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between";\r
182                    cls = "x-tree-drag-insert-below";\r
183                }else{\r
184                    returnCls = "x-tree-drop-ok-append";\r
185                    cls = "x-tree-drag-append";\r
186                }\r
187                if(this.lastInsertClass != cls){\r
188                    Ext.fly(el).replaceClass(this.lastInsertClass, cls);\r
189                    this.lastInsertClass = cls;\r
190                }\r
191            }\r
192        }\r
193        return returnCls;\r
194     },\r
195 \r
196     // private\r
197     onNodeOut : function(n, dd, e, data){\r
198         this.cancelExpand();\r
199         this.removeDropIndicators(n);\r
200     },\r
201 \r
202     // private\r
203     onNodeDrop : function(n, dd, e, data){\r
204         var point = this.getDropPoint(e, n, dd);\r
205         var targetNode = n.node;\r
206         targetNode.ui.startDrop();\r
207         if(!this.isValidDropPoint(n, point, dd, e, data)){\r
208             targetNode.ui.endDrop();\r
209             return false;\r
210         }\r
211         // first try to find the drop node\r
212         var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null);\r
213         return this.processDrop(targetNode, data, point, dd, e, dropNode);\r
214     },\r
215     \r
216     onContainerDrop : function(dd, e, data){\r
217         if (this.allowContainerDrop && this.isValidDropPoint({ ddel: this.tree.getRootNode().ui.elNode, node: this.tree.getRootNode() }, "append", dd, e, data)) {\r
218             var targetNode = this.tree.getRootNode();       \r
219             targetNode.ui.startDrop();\r
220             var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, 'append', e) : null);\r
221             return this.processDrop(targetNode, data, 'append', dd, e, dropNode);\r
222         }\r
223         return false;\r
224     },\r
225     \r
226     // private\r
227     processDrop: function(target, data, point, dd, e, dropNode){\r
228         var dropEvent = {\r
229             tree : this.tree,\r
230             target: target,\r
231             data: data,\r
232             point: point,\r
233             source: dd,\r
234             rawEvent: e,\r
235             dropNode: dropNode,\r
236             cancel: !dropNode,\r
237             dropStatus: false\r
238         };\r
239         var retval = this.tree.fireEvent("beforenodedrop", dropEvent);\r
240         if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){\r
241             target.ui.endDrop();\r
242             return dropEvent.dropStatus;\r
243         }\r
244     \r
245         target = dropEvent.target;\r
246         if(point == 'append' && !target.isExpanded()){\r
247             target.expand(false, null, function(){\r
248                 this.completeDrop(dropEvent);\r
249             }.createDelegate(this));\r
250         }else{\r
251             this.completeDrop(dropEvent);\r
252         }\r
253         return true;\r
254     },\r
255 \r
256     // private\r
257     completeDrop : function(de){\r
258         var ns = de.dropNode, p = de.point, t = de.target;\r
259         if(!Ext.isArray(ns)){\r
260             ns = [ns];\r
261         }\r
262         var n;\r
263         for(var i = 0, len = ns.length; i < len; i++){\r
264             n = ns[i];\r
265             if(p == "above"){\r
266                 t.parentNode.insertBefore(n, t);\r
267             }else if(p == "below"){\r
268                 t.parentNode.insertBefore(n, t.nextSibling);\r
269             }else{\r
270                 t.appendChild(n);\r
271             }\r
272         }\r
273         n.ui.focus();\r
274         if(Ext.enableFx && this.tree.hlDrop){\r
275             n.ui.highlight();\r
276         }\r
277         t.ui.endDrop();\r
278         this.tree.fireEvent("nodedrop", de);\r
279     },\r
280 \r
281     // private\r
282     afterNodeMoved : function(dd, data, e, targetNode, dropNode){\r
283         if(Ext.enableFx && this.tree.hlDrop){\r
284             dropNode.ui.focus();\r
285             dropNode.ui.highlight();\r
286         }\r
287         this.tree.fireEvent("nodedrop", this.tree, targetNode, data, dd, e);\r
288     },\r
289 \r
290     // private\r
291     getTree : function(){\r
292         return this.tree;\r
293     },\r
294 \r
295     // private\r
296     removeDropIndicators : function(n){\r
297         if(n && n.ddel){\r
298             var el = n.ddel;\r
299             Ext.fly(el).removeClass([\r
300                     "x-tree-drag-insert-above",\r
301                     "x-tree-drag-insert-below",\r
302                     "x-tree-drag-append"]);\r
303             this.lastInsertClass = "_noclass";\r
304         }\r
305     },\r
306 \r
307     // private\r
308     beforeDragDrop : function(target, e, id){\r
309         this.cancelExpand();\r
310         return true;\r
311     },\r
312 \r
313     // private\r
314     afterRepair : function(data){\r
315         if(data && Ext.enableFx){\r
316             data.node.ui.highlight();\r
317         }\r
318         this.hideProxy();\r
319     }    \r
320 });\r
321 \r
322 }</pre>    \r
323 </body>\r
324 </html>