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