Upgrade to ExtJS 3.1.1 - Released 02/08/2010
[extjs.git] / examples / ux / Portal.js
1 /*!
2  * Ext JS Library 3.1.1
3  * Copyright(c) 2006-2010 Ext JS, LLC
4  * licensing@extjs.com
5  * http://www.extjs.com/license
6  */
7 Ext.ux.Portal = Ext.extend(Ext.Panel, {\r
8     layout : 'column',\r
9     autoScroll : true,\r
10     cls : 'x-portal',\r
11     defaultType : 'portalcolumn',\r
12     \r
13     initComponent : function(){\r
14         Ext.ux.Portal.superclass.initComponent.call(this);\r
15         this.addEvents({\r
16             validatedrop:true,\r
17             beforedragover:true,\r
18             dragover:true,\r
19             beforedrop:true,\r
20             drop:true\r
21         });\r
22     },\r
23 \r
24     initEvents : function(){\r
25         Ext.ux.Portal.superclass.initEvents.call(this);\r
26         this.dd = new Ext.ux.Portal.DropZone(this, this.dropConfig);\r
27     },\r
28     \r
29     beforeDestroy : function() {\r
30         if(this.dd){\r
31             this.dd.unreg();\r
32         }\r
33         Ext.ux.Portal.superclass.beforeDestroy.call(this);\r
34     }\r
35 });\r
36 \r
37 Ext.reg('portal', Ext.ux.Portal);\r
38 \r
39 \r
40 Ext.ux.Portal.DropZone = function(portal, cfg){\r
41     this.portal = portal;\r
42     Ext.dd.ScrollManager.register(portal.body);\r
43     Ext.ux.Portal.DropZone.superclass.constructor.call(this, portal.bwrap.dom, cfg);\r
44     portal.body.ddScrollConfig = this.ddScrollConfig;\r
45 };\r
46 \r
47 Ext.extend(Ext.ux.Portal.DropZone, Ext.dd.DropTarget, {\r
48     ddScrollConfig : {\r
49         vthresh: 50,\r
50         hthresh: -1,\r
51         animate: true,\r
52         increment: 200\r
53     },\r
54 \r
55     createEvent : function(dd, e, data, col, c, pos){\r
56         return {\r
57             portal: this.portal,\r
58             panel: data.panel,\r
59             columnIndex: col,\r
60             column: c,\r
61             position: pos,\r
62             data: data,\r
63             source: dd,\r
64             rawEvent: e,\r
65             status: this.dropAllowed\r
66         };\r
67     },\r
68 \r
69     notifyOver : function(dd, e, data){\r
70         var xy = e.getXY(), portal = this.portal, px = dd.proxy;\r
71 \r
72         // case column widths\r
73         if(!this.grid){\r
74             this.grid = this.getGrid();\r
75         }\r
76 \r
77         // handle case scroll where scrollbars appear during drag\r
78         var cw = portal.body.dom.clientWidth;\r
79         if(!this.lastCW){\r
80             this.lastCW = cw;\r
81         }else if(this.lastCW != cw){\r
82             this.lastCW = cw;\r
83             portal.doLayout();\r
84             this.grid = this.getGrid();\r
85         }\r
86 \r
87         // determine column\r
88         var col = 0, xs = this.grid.columnX, cmatch = false;\r
89         for(var len = xs.length; col < len; col++){\r
90             if(xy[0] < (xs[col].x + xs[col].w)){\r
91                 cmatch = true;\r
92                 break;\r
93             }\r
94         }\r
95         // no match, fix last index\r
96         if(!cmatch){\r
97             col--;\r
98         }\r
99 \r
100         // find insert position\r
101         var p, match = false, pos = 0,\r
102             c = portal.items.itemAt(col),\r
103             items = c.items.items, overSelf = false;\r
104 \r
105         for(var len = items.length; pos < len; pos++){\r
106             p = items[pos];\r
107             var h = p.el.getHeight();\r
108             if(h === 0){\r
109                 overSelf = true;\r
110             }\r
111             else if((p.el.getY()+(h/2)) > xy[1]){\r
112                 match = true;\r
113                 break;\r
114             }\r
115         }\r
116 \r
117         pos = (match && p ? pos : c.items.getCount()) + (overSelf ? -1 : 0);\r
118         var overEvent = this.createEvent(dd, e, data, col, c, pos);\r
119 \r
120         if(portal.fireEvent('validatedrop', overEvent) !== false &&\r
121            portal.fireEvent('beforedragover', overEvent) !== false){\r
122 \r
123             // make sure proxy width is fluid\r
124             px.getProxy().setWidth('auto');\r
125 \r
126             if(p){\r
127                 px.moveProxy(p.el.dom.parentNode, match ? p.el.dom : null);\r
128             }else{\r
129                 px.moveProxy(c.el.dom, null);\r
130             }\r
131 \r
132             this.lastPos = {c: c, col: col, p: overSelf || (match && p) ? pos : false};\r
133             this.scrollPos = portal.body.getScroll();\r
134 \r
135             portal.fireEvent('dragover', overEvent);\r
136 \r
137             return overEvent.status;\r
138         }else{\r
139             return overEvent.status;\r
140         }\r
141 \r
142     },\r
143 \r
144     notifyOut : function(){\r
145         delete this.grid;\r
146     },\r
147 \r
148     notifyDrop : function(dd, e, data){\r
149         delete this.grid;\r
150         if(!this.lastPos){\r
151             return;\r
152         }\r
153         var c = this.lastPos.c, col = this.lastPos.col, pos = this.lastPos.p;\r
154 \r
155         var dropEvent = this.createEvent(dd, e, data, col, c,\r
156             pos !== false ? pos : c.items.getCount());\r
157 \r
158         if(this.portal.fireEvent('validatedrop', dropEvent) !== false &&\r
159            this.portal.fireEvent('beforedrop', dropEvent) !== false){\r
160 \r
161             dd.proxy.getProxy().remove();\r
162             dd.panel.el.dom.parentNode.removeChild(dd.panel.el.dom);\r
163             \r
164             if(pos !== false){\r
165                 if(c == dd.panel.ownerCt && (c.items.items.indexOf(dd.panel) <= pos)){\r
166                     pos++;\r
167                 }\r
168                 c.insert(pos, dd.panel);\r
169             }else{\r
170                 c.add(dd.panel);\r
171             }\r
172             \r
173             c.doLayout();\r
174 \r
175             this.portal.fireEvent('drop', dropEvent);\r
176 \r
177             // scroll position is lost on drop, fix it\r
178             var st = this.scrollPos.top;\r
179             if(st){\r
180                 var d = this.portal.body.dom;\r
181                 setTimeout(function(){\r
182                     d.scrollTop = st;\r
183                 }, 10);\r
184             }\r
185 \r
186         }\r
187         delete this.lastPos;\r
188     },\r
189 \r
190     // internal cache of body and column coords\r
191     getGrid : function(){\r
192         var box = this.portal.bwrap.getBox();\r
193         box.columnX = [];\r
194         this.portal.items.each(function(c){\r
195              box.columnX.push({x: c.el.getX(), w: c.el.getWidth()});\r
196         });\r
197         return box;\r
198     },\r
199 \r
200     // unregister the dropzone from ScrollManager\r
201     unreg: function() {\r
202         //Ext.dd.ScrollManager.unregister(this.portal.body);\r
203         Ext.ux.Portal.DropZone.superclass.unreg.call(this);\r
204     }\r
205 });\r