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