Upgrade to ExtJS 4.0.2 - Released 06/09/2011
[extjs.git] / examples / portal / classes / PortalDropZone.js
1 /*
2
3 This file is part of Ext JS 4
4
5 Copyright (c) 2011 Sencha Inc
6
7 Contact:  http://www.sencha.com/contact
8
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.
11
12 If you are unsure which license is appropriate for your use, please contact the sales department at http://www.sencha.com/contact.
13
14 */
15 /**
16  * @class Ext.app.PortalDropZone
17  * @extends Ext.dd.DropTarget
18  * Internal class that manages drag/drop for {@link Ext.app.PortalPanel}.
19  */
20 Ext.define('Ext.app.PortalDropZone', {
21     extend: 'Ext.dd.DropTarget',
22
23     constructor: function(portal, cfg) {
24         this.portal = portal;
25         Ext.dd.ScrollManager.register(portal.body);
26         Ext.app.PortalDropZone.superclass.constructor.call(this, portal.body, cfg);
27         portal.body.ddScrollConfig = this.ddScrollConfig;
28     },
29
30     ddScrollConfig: {
31         vthresh: 50,
32         hthresh: -1,
33         animate: true,
34         increment: 200
35     },
36
37     createEvent: function(dd, e, data, col, c, pos) {
38         return {
39             portal: this.portal,
40             panel: data.panel,
41             columnIndex: col,
42             column: c,
43             position: pos,
44             data: data,
45             source: dd,
46             rawEvent: e,
47             status: this.dropAllowed
48         };
49     },
50
51     notifyOver: function(dd, e, data) {
52         var xy = e.getXY(),
53             portal = this.portal,
54             proxy = dd.proxy;
55
56         // case column widths
57         if (!this.grid) {
58             this.grid = this.getGrid();
59         }
60
61         // handle case scroll where scrollbars appear during drag
62         var cw = portal.body.dom.clientWidth;
63         if (!this.lastCW) {
64             // set initial client width
65             this.lastCW = cw;
66         } else if (this.lastCW != cw) {
67             // client width has changed, so refresh layout & grid calcs
68             this.lastCW = cw;
69             //portal.doLayout();
70             this.grid = this.getGrid();
71         }
72
73         // determine column
74         var colIndex = 0,
75             colRight = 0,
76             cols = this.grid.columnX,
77             len = cols.length,
78             cmatch = false;
79
80         for (len; colIndex < len; colIndex++) {
81             colRight = cols[colIndex].x + cols[colIndex].w;
82             if (xy[0] < colRight) {
83                 cmatch = true;
84                 break;
85             }
86         }
87         // no match, fix last index
88         if (!cmatch) {
89             colIndex--;
90         }
91
92         // find insert position
93         var overPortlet, pos = 0,
94             h = 0,
95             match = false,
96             overColumn = portal.items.getAt(colIndex),
97             portlets = overColumn.items.items,
98             overSelf = false;
99
100         len = portlets.length;
101
102         for (len; pos < len; pos++) {
103             overPortlet = portlets[pos];
104             h = overPortlet.el.getHeight();
105             if (h === 0) {
106                 overSelf = true;
107             } else if ((overPortlet.el.getY() + (h / 2)) > xy[1]) {
108                 match = true;
109                 break;
110             }
111         }
112
113         pos = (match && overPortlet ? pos : overColumn.items.getCount()) + (overSelf ? -1 : 0);
114         var overEvent = this.createEvent(dd, e, data, colIndex, overColumn, pos);
115
116         if (portal.fireEvent('validatedrop', overEvent) !== false && portal.fireEvent('beforedragover', overEvent) !== false) {
117
118             // make sure proxy width is fluid in different width columns
119             proxy.getProxy().setWidth('auto');
120
121             if (overPortlet) {
122                 proxy.moveProxy(overPortlet.el.dom.parentNode, match ? overPortlet.el.dom : null);
123             } else {
124                 proxy.moveProxy(overColumn.el.dom, null);
125             }
126
127             this.lastPos = {
128                 c: overColumn,
129                 col: colIndex,
130                 p: overSelf || (match && overPortlet) ? pos : false
131             };
132             this.scrollPos = portal.body.getScroll();
133
134             portal.fireEvent('dragover', overEvent);
135             return overEvent.status;
136         } else {
137             return overEvent.status;
138         }
139
140     },
141
142     notifyOut: function() {
143         delete this.grid;
144     },
145
146     notifyDrop: function(dd, e, data) {
147         delete this.grid;
148         if (!this.lastPos) {
149             return;
150         }
151         var c = this.lastPos.c,
152             col = this.lastPos.col,
153             pos = this.lastPos.p,
154             panel = dd.panel,
155             dropEvent = this.createEvent(dd, e, data, col, c, pos !== false ? pos : c.items.getCount());
156
157         if (this.portal.fireEvent('validatedrop', dropEvent) !== false && this.portal.fireEvent('beforedrop', dropEvent) !== false) {
158
159             // make sure panel is visible prior to inserting so that the layout doesn't ignore it
160             panel.el.dom.style.display = '';
161
162             if (pos !== false) {
163                 c.insert(pos, panel);
164             } else {
165                 c.add(panel);
166             }
167
168             dd.proxy.hide();
169             this.portal.fireEvent('drop', dropEvent);
170
171             // scroll position is lost on drop, fix it
172             var st = this.scrollPos.top;
173             if (st) {
174                 var d = this.portal.body.dom;
175                 setTimeout(function() {
176                     d.scrollTop = st;
177                 },
178                 10);
179             }
180
181         }
182         delete this.lastPos;
183         return true;
184     },
185
186     // internal cache of body and column coords
187     getGrid: function() {
188         var box = this.portal.body.getBox();
189         box.columnX = [];
190         this.portal.items.each(function(c) {
191             box.columnX.push({
192                 x: c.el.getX(),
193                 w: c.el.getWidth()
194             });
195         });
196         return box;
197     },
198
199     // unregister the dropzone from ScrollManager
200     unreg: function() {
201         Ext.dd.ScrollManager.unregister(this.portal.body);
202         Ext.app.PortalDropZone.superclass.unreg.call(this);
203     }
204 });
205