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