Upgrade to ExtJS 4.0.7 - Released 10/19/2011
[extjs.git] / docs / source / DropZone3.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="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />
7   <script type="text/javascript" src="../resources/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-view-DropZone'>/**
19 </span> * @class Ext.view.DropZone
20  * @extends Ext.dd.DropZone
21  * @private
22  */
23 Ext.define('Ext.view.DropZone', {
24     extend: 'Ext.dd.DropZone',
25
26     indicatorHtml: '&lt;div class=&quot;x-grid-drop-indicator-left&quot;&gt;&lt;/div&gt;&lt;div class=&quot;x-grid-drop-indicator-right&quot;&gt;&lt;/div&gt;',
27     indicatorCls: 'x-grid-drop-indicator',
28
29     constructor: function(config) {
30         var me = this;
31         Ext.apply(me, config);
32
33         // Create a ddGroup unless one has been configured.
34         // User configuration of ddGroups allows users to specify which
35         // DD instances can interact with each other. Using one
36         // based on the id of the View would isolate it and mean it can only
37         // interact with a DragZone on the same View also using a generated ID.
38         if (!me.ddGroup) {
39             me.ddGroup = 'view-dd-zone-' + me.view.id;
40         }
41
42         // The DropZone's encapsulating element is the View's main element. It must be this because drop gestures
43         // may require scrolling on hover near a scrolling boundary. In Ext 4.x two DD instances may not use the
44         // same element, so a DragZone on this same View must use the View's parent element as its element.
45         me.callParent([me.view.el]);
46     },
47
48 //  Fire an event through the client DataView. Lock this DropZone during the event processing so that
49 //  its data does not become corrupted by processing mouse events.
50     fireViewEvent: function() {
51         var me = this,
52             result;
53
54         me.lock();
55         result = me.view.fireEvent.apply(me.view, arguments);
56         me.unlock();
57         return result;
58     },
59
60     getTargetFromEvent : function(e) {
61         var node = e.getTarget(this.view.getItemSelector()),
62             mouseY, nodeList, testNode, i, len, box;
63
64 //      Not over a row node: The content may be narrower than the View's encapsulating element, so return the closest.
65 //      If we fall through because the mouse is below the nodes (or there are no nodes), we'll get an onContainerOver call.
66         if (!node) {
67             mouseY = e.getPageY();
68             for (i = 0, nodeList = this.view.getNodes(), len = nodeList.length; i &lt; len; i++) {
69                 testNode = nodeList[i];
70                 box = Ext.fly(testNode).getBox();
71                 if (mouseY &lt;= box.bottom) {
72                     return testNode;
73                 }
74             }
75         }
76         return node;
77     },
78
79     getIndicator: function() {
80         var me = this;
81
82         if (!me.indicator) {
83             me.indicator = Ext.createWidget('component', {
84                 html: me.indicatorHtml,
85                 cls: me.indicatorCls,
86                 ownerCt: me.view,
87                 floating: true,
88                 shadow: false
89             });
90         }
91         return me.indicator;
92     },
93
94     getPosition: function(e, node) {
95         var y      = e.getXY()[1],
96             region = Ext.fly(node).getRegion(),
97             pos;
98
99         if ((region.bottom - y) &gt;= (region.bottom - region.top) / 2) {
100             pos = &quot;before&quot;;
101         } else {
102             pos = &quot;after&quot;;
103         }
104         return pos;
105     },
106
107 <span id='Ext-view-DropZone-method-containsRecordAtOffset'>    /**
108 </span>     * @private Determines whether the record at the specified offset from the passed record
109      * is in the drag payload.
110      * @param records
111      * @param record
112      * @param offset
113      * @returns {Boolean} True if the targeted record is in the drag payload
114      */
115     containsRecordAtOffset: function(records, record, offset) {
116         if (!record) {
117             return false;
118         }
119         var view = this.view,
120             recordIndex = view.indexOf(record),
121             nodeBefore = view.getNode(recordIndex + offset),
122             recordBefore = nodeBefore ? view.getRecord(nodeBefore) : null;
123
124         return recordBefore &amp;&amp; Ext.Array.contains(records, recordBefore);
125     },
126
127     positionIndicator: function(node, data, e) {
128         var me = this,
129             view = me.view,
130             pos = me.getPosition(e, node),
131             overRecord = view.getRecord(node),
132             draggingRecords = data.records,
133             indicator, indicatorY;
134
135         if (!Ext.Array.contains(draggingRecords, overRecord) &amp;&amp; (
136             pos == 'before' &amp;&amp; !me.containsRecordAtOffset(draggingRecords, overRecord, -1) ||
137             pos == 'after' &amp;&amp; !me.containsRecordAtOffset(draggingRecords, overRecord, 1)
138         )) {
139             me.valid = true;
140
141             if (me.overRecord != overRecord || me.currentPosition != pos) {
142
143                 indicatorY = Ext.fly(node).getY() - view.el.getY() - 1;
144                 if (pos == 'after') {
145                     indicatorY += Ext.fly(node).getHeight();
146                 }
147                 me.getIndicator().setWidth(Ext.fly(view.el).getWidth()).showAt(0, indicatorY);
148
149                 // Cache the overRecord and the 'before' or 'after' indicator.
150                 me.overRecord = overRecord;
151                 me.currentPosition = pos;
152             }
153         } else {
154             me.invalidateDrop();
155         }
156     },
157
158     invalidateDrop: function() {
159         if (this.valid) {
160             this.valid = false;
161             this.getIndicator().hide();
162         }
163     },
164
165     // The mouse is over a View node
166     onNodeOver: function(node, dragZone, e, data) {
167         var me = this;
168
169         if (!Ext.Array.contains(data.records, me.view.getRecord(node))) {
170             me.positionIndicator(node, data, e);
171         }
172         return me.valid ? me.dropAllowed : me.dropNotAllowed;
173     },
174
175     // Moved out of the DropZone without dropping.
176     // Remove drop position indicator
177     notifyOut: function(node, dragZone, e, data) {
178         var me = this;
179
180         me.callParent(arguments);
181         delete me.overRecord;
182         delete me.currentPosition;
183         if (me.indicator) {
184             me.indicator.hide();
185         }
186     },
187
188     // The mouse is past the end of all nodes (or there are no nodes)
189     onContainerOver : function(dd, e, data) {
190         var me = this,
191             view = me.view,
192             count = view.store.getCount();
193
194         // There are records, so position after the last one
195         if (count) {
196             me.positionIndicator(view.getNode(count - 1), data, e);
197         }
198
199         // No records, position the indicator at the top
200         else {
201             delete me.overRecord;
202             delete me.currentPosition;
203             me.getIndicator().setWidth(Ext.fly(view.el).getWidth()).showAt(0, 0);
204             me.valid = true;
205         }
206         return me.dropAllowed;
207     },
208
209     onContainerDrop : function(dd, e, data) {
210         return this.onNodeDrop(dd, null, e, data);
211     },
212
213     onNodeDrop: function(node, dragZone, e, data) {
214         var me = this,
215             dropped = false,
216
217             // Create a closure to perform the operation which the event handler may use.
218             // Users may now return &lt;code&gt;false&lt;/code&gt; from the beforedrop handler, and perform any kind
219             // of asynchronous processing such as an Ext.Msg.confirm, or an Ajax request,
220             // and complete the drop gesture at some point in the future by calling this function.
221             processDrop = function () {
222                 me.invalidateDrop();
223                 me.handleNodeDrop(data, me.overRecord, me.currentPosition);
224                 dropped = true;
225                 me.fireViewEvent('drop', node, data, me.overRecord, me.currentPosition);
226             },
227             performOperation = false;
228
229         if (me.valid) {
230             performOperation = me.fireViewEvent('beforedrop', node, data, me.overRecord, me.currentPosition, processDrop);
231             if (performOperation !== false) {
232                 // If the processDrop function was called in the event handler, do not do it again.
233                 if (!dropped) {
234                     processDrop();
235                 }
236             }
237         }
238         return performOperation;
239     },
240     
241     destroy: function(){
242         Ext.destroy(this.indicator);
243         delete this.indicator;
244         this.callParent();
245     }
246 });
247 </pre>
248 </body>
249 </html>