/**
* Internal class that manages drag/drop for the `Dashboard`.
* @private
*/
Ext.define('Ext.dashboard.DropZone', {
extend: 'Ext.dd.DropTarget',
ddScrollConfig: {
vthresh: 75,
hthresh: -1,
animate: true,
increment: 200
},
containerScroll: true,
// This causes overflow to go hidden during the drag so that we don't cause panels to
// wrap by triggering overflow.
overClass: Ext.baseCSSPrefix + 'dashboard-dd-over',
constructor: function(dashboard, cfg) {
this.dashboard = dashboard;
dashboard.body.ddScrollConfig = this.ddScrollConfig;
this.callParent([dashboard.body, cfg]);
},
getOverEvent: function(dd, e, data) {
var dashboard = this.dashboard,
dbody = dashboard.body,
items = dashboard.items.items,
bodyBox = dbody.getBox(),
count = items.length,
xy = e.getXY(),
orginalX = xy[0] - bodyBox.x + dbody.getScrollLeft(),
orginalY = xy[1] - bodyBox.y + dbody.getScrollTop(),
x = orginalX,
y = orginalY,
yOffset = 0,
rowIterationIndex = 0,
over = {
columnIndex: 0,
column: null,
dashboard: dashboard,
above: null,
extensible: false,
beforeAfter: 0,
data: data,
panel: data.panel,
rawEvent: e,
source: dd,
status: this.dropAllowed
},
t, ht, i, k, item, w, h, childCount, childItems, childItem;
for (i = 0; i < count; i += 2) {
item = items[i];
if (rowIterationIndex !== item.rowIndex) {
rowIterationIndex = item.rowIndex;
x = orginalX;
if (rowIterationIndex > 0) {
y -= yOffset;
yOffset = 0;
}
}
w = item.lastBox.width;
h = item.lastBox.height;
if (yOffset <= h) {
yOffset = h;
}
if (items[i + 1]) {
// This is for splitter
w += items[i + 1].lastBox.width;
}
if (e.within(item.el)) {
over.columnIndex = i;
over.column = item;
over.extensible = this.isRowExtensible(item.rowIndex);
t = Math.min(80, w * 0.2);
over.beforeAfter = t = (over.extensible && ((x < t) ? -1 : ((x > w - t) ? 1 : 0)));
if (!t || !over.extensible) {
childItems = item.items.items;
// if we are not on an edge OR reached maxColumns
// (which means "insert the panel in between the columns"),
// we need to dig one more level down
for (k = 0, childCount = childItems.length; k < childCount; ++k) {
childItem = childItems[k];
ht = childItem.el.getHeight();
if (y < ht / 2) {
// if mouse is above the current child's top, Y coord, it
// is considered as "above" the previous child
over.above = childItem;
break;
}
y -= ht;
}
}
break;
}
x -= w;
}
return over;
},
notifyOver: function(dd, e, data) {
var me = this,
dashboard = me.dashboard,
hasListeners = dashboard.hasListeners,
over = me.getOverEvent(dd, e, data),
colEl = over.column && over.column.el,
proxy = dd.proxy,
aboveItem = over.above,
width = 0,
proxyProxy, colWidth, padding;
data.lastOver = over;
if ((!hasListeners.validatedrop || dashboard.fireEvent('validatedrop', over) !== false) &&
(!hasListeners.beforedragover || dashboard.fireEvent('beforedragover', over) !== false)) { // eslint-disable-line max-len
proxyProxy = dd.panelProxy.getProxy();
// make sure proxy width is fluid in different width columns
proxy.getProxy().setWidth('auto');
if (colEl) {
width = colWidth = colEl.getWidth();
// A floating column was targeted
if (over.beforeAfter) {
dd.panelProxy.moveProxy(colEl.dom, colEl.dom.firstChild);
width = colWidth / 2;
proxyProxy.setWidth(width);
}
else {
if (aboveItem) {
dd.panelProxy.moveProxy(aboveItem.el.dom.parentNode, aboveItem.el.dom);
}
else {
dd.panelProxy.moveProxy(colEl.dom, null);
}
proxyProxy.setWidth('auto');
}
proxyProxy.setStyle({
'float': 'none',
'clear': 'none',
'margin-left': (over.beforeAfter > 0)
? (colWidth - width - colEl.getPadding('lr')) + 'px'
: '',
'margin-top': '7px'
});
}
else {
padding = dashboard.body.getPadding('lr');
proxyProxy.setStyle({
'float': 'left',
'clear': 'left',
'margin': '0 7px 0 7px'
});
proxyProxy.setWidth(dashboard.body.getWidth() - padding);
// Target the innerCt for the move
dd.panelProxy.moveProxy(dashboard.body.dom.firstChild.firstChild, null);
}
this.scrollPos = dashboard.body.getScroll();
if (hasListeners.dragover) {
dashboard.fireEvent('dragover', over);
}
}
return over.status;
},
isRowExtensible: function(rowIndex) {
var me = this,
dashboard = me.dashboard,
maxColumns = dashboard.getMaxColumns() || 1,
items;
items = dashboard.query('>dashboard-column[rowIndex=' + rowIndex + ']');
return Ext.Array.from(items).length < maxColumns;
},
notifyDrop: function(dd, e, data) {
this.callParent(arguments);
// eslint-disable-next-line vars-on-top
var dashboard = this.dashboard,
over = data.lastOver,
panel = over.panel,
fromCt = panel.ownerCt,
toCt = over.column,
side = toCt ? over.beforeAfter : 1,
currentIndex = fromCt.items.indexOf(panel),
newIndex = toCt
? (over.above ? toCt.items.indexOf(over.above) : toCt.items.getCount())
: 0,
colIndex, newCol,
hasListeners = dashboard.hasListeners;
// Same column tests
if (fromCt === toCt) {
if (fromCt.items.getCount() === 1) {
return;
}
if (!side) {
if (currentIndex < newIndex) {
--newIndex;
}
if (currentIndex === newIndex) {
return;
}
}
}
if ((hasListeners.validatedrop && dashboard.fireEvent('validatedrop', over) === false) ||
(hasListeners.beforedrop && dashboard.fireEvent('beforedrop', over) === false)) {
return;
}
Ext.suspendLayouts();
panel.isMoving = true;
if (side) {
colIndex = dashboard.items.indexOf(toCt);
// inserting into new Row ?
if (colIndex < 0) {
colIndex = dashboard.items.getCount();
}
else if (side > 0) {
++colIndex;
}
newCol = dashboard.createColumn();
if (toCt) {
newCol.columnWidth = toCt.columnWidth = toCt.columnWidth / 2;
delete toCt.width;
}
else {
newCol.columnWidth = 1; // full row
}
toCt = dashboard.insert(colIndex, newCol);
newIndex = 0;
}
// make sure panel is visible prior to inserting so the layout doesn't ignore it
panel.el.dom.style.display = '';
toCt.insert(newIndex, panel);
panel.isMoving = false;
toCt.updateLayout();
Ext.resumeLayouts(true);
if (hasListeners.drop) {
dashboard.fireEvent('drop', over);
}
}
});