Upgrade to ExtJS 4.0.1 - Released 05/18/2011
[extjs.git] / docs / source / ViewDropZone2.html
1 <!DOCTYPE html>
2 <html>
3 <head>
4   <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
5   <title>The source code</title>
6   <link href="../prettify/prettify.css" type="text/css" rel="stylesheet" />
7   <script type="text/javascript" src="../prettify/prettify.js"></script>
8   <style type="text/css">
9     .highlight { display: block; background-color: #ddd; }
10   </style>
11   <script type="text/javascript">
12     function highlight() {
13       document.getElementById(location.hash.replace(/#/, "")).className = "highlight";
14     }
15   </script>
16 </head>
17 <body onload="prettyPrint(); highlight();">
18   <pre class="prettyprint lang-js"><span id='Ext-tree-ViewDropZone'>/**
19 </span> * @class Ext.tree.ViewDropZone
20  * @extends Ext.view.DropZone
21  * @private
22  */
23 Ext.define('Ext.tree.ViewDropZone', {
24     extend: 'Ext.view.DropZone',
25
26 <span id='Ext-tree-ViewDropZone-cfg-allowParentInsert'>    /**
27 </span>     * @cfg {Boolean} allowParentInsert
28      * Allow inserting a dragged node between an expanded parent node and its first child that will become a
29      * sibling of the parent when dropped (defaults to false)
30      */
31     allowParentInserts: false,
32  
33 <span id='Ext-tree-ViewDropZone-cfg-allowContainerDrop'>    /**
34 </span>     * @cfg {String} allowContainerDrop
35      * True if drops on the tree container (outside of a specific tree node) are allowed (defaults to false)
36      */
37     allowContainerDrops: false,
38
39 <span id='Ext-tree-ViewDropZone-cfg-appendOnly'>    /**
40 </span>     * @cfg {String} appendOnly
41      * True if the tree should only allow append drops (use for trees which are sorted, defaults to false)
42      */
43     appendOnly: false,
44
45 <span id='Ext-tree-ViewDropZone-cfg-expandDelay'>    /**
46 </span>     * @cfg {String} expandDelay
47      * The delay in milliseconds to wait before expanding a target tree node while dragging a droppable node
48      * over the target (defaults to 500)
49      */
50     expandDelay : 500,
51
52     indicatorCls: 'x-tree-ddindicator',
53
54     // private
55     expandNode : function(node) {
56         var view = this.view;
57         if (!node.isLeaf() &amp;&amp; !node.isExpanded()) {
58             view.expand(node);
59             this.expandProcId = false;
60         }
61     },
62
63     // private
64     queueExpand : function(node) {
65         this.expandProcId = Ext.Function.defer(this.expandNode, this.expandDelay, this, [node]);
66     },
67
68     // private
69     cancelExpand : function() {
70         if (this.expandProcId) {
71             clearTimeout(this.expandProcId);
72             this.expandProcId = false;
73         }
74     },
75
76     getPosition: function(e, node) {
77         var view = this.view,
78             record = view.getRecord(node),
79             y = e.getPageY(),
80             noAppend = record.isLeaf(),
81             noBelow = false,
82             region = Ext.fly(node).getRegion(),
83             fragment;
84
85         // If we are dragging on top of the root node of the tree, we always want to append.
86         if (record.isRoot()) {
87             return 'append';
88         }
89
90         // Return 'append' if the node we are dragging on top of is not a leaf else return false.
91         if (this.appendOnly) {
92             return noAppend ? false : 'append';
93         }
94
95         if (!this.allowParentInsert) {
96             noBelow = record.hasChildNodes() &amp;&amp; record.isExpanded();
97         }
98
99         fragment = (region.bottom - region.top) / (noAppend ? 2 : 3);
100         if (y &gt;= region.top &amp;&amp; y &lt; (region.top + fragment)) {
101             return 'before';
102         }
103         else if (!noBelow &amp;&amp; (noAppend || (y &gt;= (region.bottom - fragment) &amp;&amp; y &lt;= region.bottom))) {
104             return 'after';
105         }
106         else {
107             return 'append';
108         }
109     },
110
111     isValidDropPoint : function(node, position, dragZone, e, data) {
112         if (!node || !data.item) {
113             return false;
114         }
115
116         var view = this.view,
117             targetNode = view.getRecord(node),
118             draggedRecords = data.records,
119             dataLength = draggedRecords.length,
120             ln = draggedRecords.length,
121             i, record;
122
123         // No drop position, or dragged records: invalid drop point
124         if (!(targetNode &amp;&amp; position &amp;&amp; dataLength)) {
125             return false;
126         }
127
128         // If the targetNode is within the folder we are dragging
129         for (i = 0; i &lt; ln; i++) {
130             record = draggedRecords[i];
131             if (record.isNode &amp;&amp; record.contains(targetNode)) {
132                 return false;
133             }
134         }
135         
136         // Respect the allowDrop field on Tree nodes
137         if (position === 'append' &amp;&amp; targetNode.get('allowDrop') == false) {
138             return false;
139         }
140         else if (position != 'append' &amp;&amp; targetNode.parentNode.get('allowDrop') == false) {
141             return false;
142         }
143
144         // If the target record is in the dragged dataset, then invalid drop
145         if (Ext.Array.contains(draggedRecords, targetNode)) {
146              return false;
147         }
148
149         // @TODO: fire some event to notify that there is a valid drop possible for the node you're dragging
150         // Yes: this.fireViewEvent(blah....) fires an event through the owning View.
151         return true;
152     },
153
154     onNodeOver : function(node, dragZone, e, data) {
155         var position = this.getPosition(e, node),
156             returnCls = this.dropNotAllowed,
157             view = this.view,
158             targetNode = view.getRecord(node),
159             indicator = this.getIndicator(),
160             indicatorX = 0,
161             indicatorY = 0;
162
163         // auto node expand check
164         this.cancelExpand();
165         if (position == 'append' &amp;&amp; !this.expandProcId &amp;&amp; !Ext.Array.contains(data.records, targetNode) &amp;&amp; !targetNode.isLeaf() &amp;&amp; !targetNode.isExpanded()) {
166             this.queueExpand(targetNode);
167         }
168             
169         if (this.isValidDropPoint(node, position, dragZone, e, data)) {
170             this.valid = true;
171             this.currentPosition = position;
172             this.overRecord = targetNode;
173
174             indicator.setWidth(Ext.fly(node).getWidth());
175             indicatorY = Ext.fly(node).getY() - Ext.fly(view.el).getY() - 1;
176
177             if (position == 'before') {
178                 returnCls = targetNode.isFirst() ? Ext.baseCSSPrefix + 'tree-drop-ok-above' : Ext.baseCSSPrefix + 'tree-drop-ok-between';
179                 indicator.showAt(0, indicatorY);
180                 indicator.toFront();
181             }
182             else if (position == 'after') {
183                 returnCls = targetNode.isLast() ? Ext.baseCSSPrefix + 'tree-drop-ok-below' : Ext.baseCSSPrefix + 'tree-drop-ok-between';
184                 indicatorY += Ext.fly(node).getHeight();
185                 indicator.showAt(0, indicatorY);
186                 indicator.toFront();
187             }
188             else {
189                 returnCls = Ext.baseCSSPrefix + 'tree-drop-ok-append';
190                 // @TODO: set a class on the parent folder node to be able to style it
191                 indicator.hide();
192             }
193         }
194         else {
195             this.valid = false;
196         }
197
198         this.currentCls = returnCls;
199         return returnCls;
200     },
201
202     onContainerOver : function(dd, e, data) {
203         return e.getTarget('.' + this.indicatorCls) ? this.currentCls : this.dropNotAllowed;
204     },
205     
206     notifyOut: function() {
207         this.callParent(arguments);
208         this.cancelExpand();
209     },
210
211     handleNodeDrop : function(data, targetNode, position) {
212         var me = this,
213             view = me.view,
214             parentNode = targetNode.parentNode,
215             store = view.getStore(),
216             recordDomNodes = [],
217             records, i, len,
218             insertionMethod, argList,
219             needTargetExpand,
220             transferData,
221             processDrop;
222
223         // If the copy flag is set, create a copy of the Models with the same IDs
224         if (data.copy) {
225             records = data.records;
226             data.records = [];
227             for (i = 0, len = records.length; i &lt; len; i++) {
228                 data.records.push(Ext.apply({}, records[i].data));
229             }
230         }
231
232         // Cancel any pending expand operation
233         me.cancelExpand();
234
235         // Grab a reference to the correct node insertion method.
236         // Create an arg list array intended for the apply method of the
237         // chosen node insertion method.
238         // Ensure the target object for the method is referenced by 'targetNode'
239         if (position == 'before') {
240             insertionMethod = parentNode.insertBefore;
241             argList = [null, targetNode];
242             targetNode = parentNode;
243         }
244         else if (position == 'after') {
245             if (targetNode.nextSibling) {
246                 insertionMethod = parentNode.insertBefore;
247                 argList = [null, targetNode.nextSibling];
248             }
249             else {
250                 insertionMethod = parentNode.appendChild;
251                 argList = [null];
252             }
253             targetNode = parentNode;
254         }
255         else {
256             if (!targetNode.isExpanded()) {
257                 needTargetExpand = true;
258             }
259             insertionMethod = targetNode.appendChild;
260             argList = [null];
261         }
262
263         // A function to transfer the data into the destination tree
264         transferData = function() {
265             var node;
266             for (i = 0, len = data.records.length; i &lt; len; i++) {
267                 argList[0] = data.records[i];
268                 node = insertionMethod.apply(targetNode, argList);
269                 
270                 if (Ext.enableFx &amp;&amp; me.dropHighlight) {
271                     recordDomNodes.push(view.getNode(node));
272                 }
273             }
274             
275             // Kick off highlights after everything's been inserted, so they are
276             // more in sync without insertion/render overhead.
277             if (Ext.enableFx &amp;&amp; me.dropHighlight) {
278                 //FIXME: the check for n.firstChild is not a great solution here. Ideally the line should simply read 
279                 //Ext.fly(n.firstChild) but this yields errors in IE6 and 7. See ticket EXTJSIV-1705 for more details
280                 Ext.Array.forEach(recordDomNodes, function(n) {
281                     Ext.fly(n.firstChild ? n.firstChild : n).highlight(me.dropHighlightColor);
282                 });
283             }
284         };
285
286         // If dropping right on an unexpanded node, transfer the data after it is expanded.
287         if (needTargetExpand) {
288             targetNode.expand(false, transferData);
289         }
290         // Otherwise, call the data transfer function immediately
291         else {
292             transferData();
293         }
294     }
295 });</pre>
296 </body>
297 </html>