3 This file is part of Ext JS 4
5 Copyright (c) 2011 Sencha Inc
7 Contact: http://www.sencha.com/contact
9 GNU General Public License Usage
10 This file may be used under the terms of the GNU General Public License version 3.0 as published by the Free Software Foundation and appearing in the file LICENSE included in the packaging of this file. Please review the following information to ensure the GNU General Public License version 3.0 requirements will be met: http://www.gnu.org/copyleft/gpl.html.
12 If you are unsure which license is appropriate for your use, please contact the sales department at http://www.sencha.com/contact.
16 * @class Ext.view.DropZone
17 * @extends Ext.dd.DropZone
20 Ext.define('Ext.view.DropZone', {
21 extend: 'Ext.dd.DropZone',
23 indicatorHtml: '<div class="x-grid-drop-indicator-left"></div><div class="x-grid-drop-indicator-right"></div>',
24 indicatorCls: 'x-grid-drop-indicator',
26 constructor: function(config) {
28 Ext.apply(me, config);
30 // Create a ddGroup unless one has been configured.
31 // User configuration of ddGroups allows users to specify which
32 // DD instances can interact with each other. Using one
33 // based on the id of the View would isolate it and mean it can only
34 // interact with a DragZone on the same View also using a generated ID.
36 me.ddGroup = 'view-dd-zone-' + me.view.id;
39 // The DropZone's encapsulating element is the View's main element. It must be this because drop gestures
40 // may require scrolling on hover near a scrolling boundary. In Ext 4.x two DD instances may not use the
41 // same element, so a DragZone on this same View must use the View's parent element as its element.
42 me.callParent([me.view.el]);
45 // Fire an event through the client DataView. Lock this DropZone during the event processing so that
46 // its data does not become corrupted by processing mouse events.
47 fireViewEvent: function() {
52 result = me.view.fireEvent.apply(me.view, arguments);
57 getTargetFromEvent : function(e) {
58 var node = e.getTarget(this.view.getItemSelector()),
59 mouseY, nodeList, testNode, i, len, box;
61 // Not over a row node: The content may be narrower than the View's encapsulating element, so return the closest.
62 // If we fall through because the mouse is below the nodes (or there are no nodes), we'll get an onContainerOver call.
64 mouseY = e.getPageY();
65 for (i = 0, nodeList = this.view.getNodes(), len = nodeList.length; i < len; i++) {
66 testNode = nodeList[i];
67 box = Ext.fly(testNode).getBox();
68 if (mouseY <= box.bottom) {
76 getIndicator: function() {
80 me.indicator = Ext.createWidget('component', {
81 html: me.indicatorHtml,
91 getPosition: function(e, node) {
93 region = Ext.fly(node).getRegion(),
96 if ((region.bottom - y) >= (region.bottom - region.top) / 2) {
105 * @private Determines whether the record at the specified offset from the passed record
106 * is in the drag payload.
110 * @returns {Boolean} True if the targeted record is in the drag payload
112 containsRecordAtOffset: function(records, record, offset) {
116 var view = this.view,
117 recordIndex = view.indexOf(record),
118 nodeBefore = view.getNode(recordIndex + offset),
119 recordBefore = nodeBefore ? view.getRecord(nodeBefore) : null;
121 return recordBefore && Ext.Array.contains(records, recordBefore);
124 positionIndicator: function(node, data, e) {
127 pos = me.getPosition(e, node),
128 overRecord = view.getRecord(node),
129 draggingRecords = data.records,
130 indicator, indicatorY;
132 if (!Ext.Array.contains(draggingRecords, overRecord) && (
133 pos == 'before' && !me.containsRecordAtOffset(draggingRecords, overRecord, -1) ||
134 pos == 'after' && !me.containsRecordAtOffset(draggingRecords, overRecord, 1)
138 if (me.overRecord != overRecord || me.currentPosition != pos) {
140 indicatorY = Ext.fly(node).getY() - view.el.getY() - 1;
141 if (pos == 'after') {
142 indicatorY += Ext.fly(node).getHeight();
144 me.getIndicator().setWidth(Ext.fly(view.el).getWidth()).showAt(0, indicatorY);
146 // Cache the overRecord and the 'before' or 'after' indicator.
147 me.overRecord = overRecord;
148 me.currentPosition = pos;
155 invalidateDrop: function() {
158 this.getIndicator().hide();
162 // The mouse is over a View node
163 onNodeOver: function(node, dragZone, e, data) {
166 if (!Ext.Array.contains(data.records, me.view.getRecord(node))) {
167 me.positionIndicator(node, data, e);
169 return me.valid ? me.dropAllowed : me.dropNotAllowed;
172 // Moved out of the DropZone without dropping.
173 // Remove drop position indicator
174 notifyOut: function(node, dragZone, e, data) {
177 me.callParent(arguments);
178 delete me.overRecord;
179 delete me.currentPosition;
185 // The mouse is past the end of all nodes (or there are no nodes)
186 onContainerOver : function(dd, e, data) {
189 count = view.store.getCount();
191 // There are records, so position after the last one
193 me.positionIndicator(view.getNode(count - 1), data, e);
196 // No records, position the indicator at the top
198 delete me.overRecord;
199 delete me.currentPosition;
200 me.getIndicator().setWidth(Ext.fly(view.el).getWidth()).showAt(0, 0);
203 return me.dropAllowed;
206 onContainerDrop : function(dd, e, data) {
207 return this.onNodeDrop(dd, null, e, data);
210 onNodeDrop: function(node, dragZone, e, data) {
214 // Create a closure to perform the operation which the event handler may use.
215 // Users may now return <code>false</code> from the beforedrop handler, and perform any kind
216 // of asynchronous processing such as an Ext.Msg.confirm, or an Ajax request,
217 // and complete the drop gesture at some point in the future by calling this function.
218 processDrop = function () {
220 me.handleNodeDrop(data, me.overRecord, me.currentPosition);
222 me.fireViewEvent('drop', node, data, me.overRecord, me.currentPosition);
224 performOperation = false;
227 performOperation = me.fireViewEvent('beforedrop', node, data, me.overRecord, me.currentPosition, processDrop);
228 if (performOperation !== false) {
229 // If the processDrop function was called in the event handler, do not do it again.
235 return performOperation;
239 Ext.destroy(this.indicator);
240 delete this.indicator;