Ext.ux.Portal = Ext.extend(Ext.Panel, {
layout : 'column',
autoScroll : true,
cls : 'x-portal',
defaultType : 'portalcolumn',
initComponent : function(){
Ext.ux.Portal.superclass.initComponent.call(this);
this.addEvents({
validatedrop:true,
beforedragover:true,
dragover:true,
beforedrop:true,
drop:true
});
},
initEvents : function(){
Ext.ux.Portal.superclass.initEvents.call(this);
this.dd = new Ext.ux.Portal.DropZone(this, this.dropConfig);
},
beforeDestroy : function() {
if(this.dd){
this.dd.unreg();
}
Ext.ux.Portal.superclass.beforeDestroy.call(this);
}
});
Ext.reg('portal', Ext.ux.Portal);
Ext.ux.Portal.DropZone = function(portal, cfg){
this.portal = portal;
Ext.dd.ScrollManager.register(portal.body);
Ext.ux.Portal.DropZone.superclass.constructor.call(this, portal.bwrap.dom, cfg);
portal.body.ddScrollConfig = this.ddScrollConfig;
};
Ext.extend(Ext.ux.Portal.DropZone, Ext.dd.DropTarget, {
ddScrollConfig : {
vthresh: 50,
hthresh: -1,
animate: true,
increment: 200
},
createEvent : function(dd, e, data, col, c, pos){
return {
portal: this.portal,
panel: data.panel,
columnIndex: col,
column: c,
position: pos,
data: data,
source: dd,
rawEvent: e,
status: this.dropAllowed
};
},
notifyOver : function(dd, e, data){
var xy = e.getXY(), portal = this.portal, px = dd.proxy;
// case column widths
if(!this.grid){
this.grid = this.getGrid();
}
// handle case scroll where scrollbars appear during drag
var cw = portal.body.dom.clientWidth;
if(!this.lastCW){
this.lastCW = cw;
}else if(this.lastCW != cw){
this.lastCW = cw;
portal.doLayout();
this.grid = this.getGrid();
}
// determine column
var col = 0, xs = this.grid.columnX, cmatch = false;
for(var len = xs.length; col < len; col++){
if(xy[0] < (xs[col].x + xs[col].w)){
cmatch = true;
break;
}
}
// no match, fix last index
if(!cmatch){
col--;
}
// find insert position
var p, match = false, pos = 0,
c = portal.items.itemAt(col),
items = c.items.items, overSelf = false;
for(var len = items.length; pos < len; pos++){
p = items[pos];
var h = p.el.getHeight();
if(h === 0){
overSelf = true;
}
else if((p.el.getY()+(h/2)) > xy[1]){
match = true;
break;
}
}
pos = (match && p ? pos : c.items.getCount()) + (overSelf ? -1 : 0);
var overEvent = this.createEvent(dd, e, data, col, c, pos);
if(portal.fireEvent('validatedrop', overEvent) !== false &&
portal.fireEvent('beforedragover', overEvent) !== false){
// make sure proxy width is fluid
px.getProxy().setWidth('auto');
if(p){
px.moveProxy(p.el.dom.parentNode, match ? p.el.dom : null);
}else{
px.moveProxy(c.el.dom, null);
}
this.lastPos = {c: c, col: col, p: overSelf || (match && p) ? pos : false};
this.scrollPos = portal.body.getScroll();
portal.fireEvent('dragover', overEvent);
return overEvent.status;
}else{
return overEvent.status;
}
},
notifyOut : function(){
delete this.grid;
},
notifyDrop : function(dd, e, data){
delete this.grid;
if(!this.lastPos){
return;
}
var c = this.lastPos.c, col = this.lastPos.col, pos = this.lastPos.p;
var dropEvent = this.createEvent(dd, e, data, col, c,
pos !== false ? pos : c.items.getCount());
if(this.portal.fireEvent('validatedrop', dropEvent) !== false &&
this.portal.fireEvent('beforedrop', dropEvent) !== false){
dd.proxy.getProxy().remove();
dd.panel.el.dom.parentNode.removeChild(dd.panel.el.dom);
if(pos !== false){
if(c == dd.panel.ownerCt && (c.items.items.indexOf(dd.panel) <= pos)){
pos++;
}
c.insert(pos, dd.panel);
}else{
c.add(dd.panel);
}
c.doLayout();
this.portal.fireEvent('drop', dropEvent);
// scroll position is lost on drop, fix it
var st = this.scrollPos.top;
if(st){
var d = this.portal.body.dom;
setTimeout(function(){
d.scrollTop = st;
}, 10);
}
}
delete this.lastPos;
},
// internal cache of body and column coords
getGrid : function(){
var box = this.portal.bwrap.getBox();
box.columnX = [];
this.portal.items.each(function(c){
box.columnX.push({x: c.el.getX(), w: c.el.getWidth()});
});
return box;
},
// unregister the dropzone from ScrollManager
unreg: function() {
//Ext.dd.ScrollManager.unregister(this.portal.body);
Ext.ux.Portal.DropZone.superclass.unreg.call(this);
}
});