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