* @private
*/
Ext.define('Ext.grid.header.DropZone', {
extend: 'Ext.dd.DropZone',
this.headerCt = headerCt;
this.ddGroup = this.getDDGroup();
this.callParent([headerCt.el]);
},
return 'header-dd-zone-' + this.headerCt.up('[scrollerOwner]').id;
},
return e.getTarget('.' + this.colHeaderCls);
},
if (!this.topIndicator) {
this.self.prototype.topIndicator = Ext.DomHelper.append(Ext.getBody(), {
cls: "col-move-top",
html: " "
}, true);
this.self.prototype.indicatorXOffset = Math.floor((this.topIndicator.dom.offsetWidth + 1) / 2);
}
return this.topIndicator;
},
if (!this.bottomIndicator) {
this.self.prototype.bottomIndicator = Ext.DomHelper.append(Ext.getBody(), {
cls: "col-move-bottom",
html: " "
}, true);
}
return this.bottomIndicator;
},
var x = e.getXY()[0],
region = Ext.fly(t).getRegion(),
pos;
if ((region.right - x) <= (region.right - region.left) / 2) {
pos = "after";
} else {
pos = "before";
}
return {
pos: pos,
header: Ext.getCmp(t.id),
node: t
};
},
var me = this,
dragHeader = data.header,
dropLocation = me.getLocation(e, node),
targetHeader = dropLocation.header,
pos = dropLocation.pos,
nextHd,
prevHd,
topIndicator, bottomIndicator, topAnchor, bottomAnchor,
topXY, bottomXY, headerCtEl, minX, maxX,
allDropZones, ln, i, dropZone;
// Avoid expensive CQ lookups and DOM calculations if dropPosition has not changed
if (targetHeader === me.lastTargetHeader && pos === me.lastDropPos) {
return;
}
nextHd = dragHeader.nextSibling('gridcolumn:not([hidden])');
prevHd = dragHeader.previousSibling('gridcolumn:not([hidden])');
me.lastTargetHeader = targetHeader;
me.lastDropPos = pos;
// Cannot drag to before non-draggable start column
if (!targetHeader.draggable && pos === 'before' && targetHeader.getIndex() === 0) {
return false;
}
data.dropLocation = dropLocation;
if ((dragHeader !== targetHeader) &&
((pos === "before" && nextHd !== targetHeader) ||
(pos === "after" && prevHd !== targetHeader)) &&
!targetHeader.isDescendantOf(dragHeader)) {
// As we move in between different DropZones that are in the same
// group (such as the case when in a locked grid), invalidateDrop
// on the other dropZones.
allDropZones = Ext.dd.DragDropManager.getRelated(me);
ln = allDropZones.length;
i = 0;
for (; i < ln; i++) {
dropZone = allDropZones[i];
if (dropZone !== me && dropZone.invalidateDrop) {
dropZone.invalidateDrop();
}
}
me.valid = true;
topIndicator = me.getTopIndicator();
bottomIndicator = me.getBottomIndicator();
if (pos === 'before') {
topAnchor = 'bc-tl';
bottomAnchor = 'tc-bl';
} else {
topAnchor = 'bc-tr';
bottomAnchor = 'tc-br';
}
// Calculate arrow positions. Offset them to align exactly with column border line
topXY = topIndicator.getAlignToXY(targetHeader.el, topAnchor);
bottomXY = bottomIndicator.getAlignToXY(targetHeader.el, bottomAnchor);
// constrain the indicators to the viewable section
headerCtEl = me.headerCt.el;
minX = headerCtEl.getX() - me.indicatorXOffset;
maxX = headerCtEl.getX() + headerCtEl.getWidth();
topXY[0] = Ext.Number.constrain(topXY[0], minX, maxX);
bottomXY[0] = Ext.Number.constrain(bottomXY[0], minX, maxX);
// position and show indicators
topIndicator.setXY(topXY);
bottomIndicator.setXY(bottomXY);
topIndicator.show();
bottomIndicator.show();
// invalidate drop operation and hide indicators
} else {
me.invalidateDrop();
}
},
this.valid = false;
this.hideIndicators();
},
var me = this,
from = data.header,
doPosition,
to,
fromPanel,
toPanel;
if (data.header.el.dom === node) {
doPosition = false;
} else {
data.isLock = data.isUnlock = false;
to = me.getLocation(e, node).header;
// Dragging within the same container - always valid
doPosition = (from.ownerCt === to.ownerCt);
// If from different containers, and they are not sealed, then continue checking
if (!doPosition && (!from.ownerCt.sealed && !to.ownerCt.sealed)) {
doPosition = true;
fromPanel = from.up('tablepanel');
toPanel = to.up('tablepanel');
// If it's a lock operation, check that it's allowable.
data.isLock = toPanel.isLocked && !fromPanel.isLocked;
data.isUnlock = !toPanel.isLocked && fromPanel.isLocked;
if ((data.isUnlock && from.lockable === false) || (data.isLock && !from.isLockable())) {
doPosition = false;
}
}
}
if (doPosition) {
me.positionIndicator(data, node, e);
} else {
me.valid = false;
}
return me.valid ? me.dropAllowed : me.dropNotAllowed;
},
var me = this;
me.getTopIndicator().hide();
me.getBottomIndicator().hide();
me.lastTargetHeader = me.lastDropPos = null;
},
this.hideIndicators();
},
if (this.valid) {
var dragHeader = data.header,
dropLocation = data.dropLocation,
targetHeader = dropLocation.header,
fromCt = dragHeader.ownerCt,
localFromIdx = fromCt.items.indexOf(dragHeader), // Container.items is a MixedCollection
toCt = targetHeader.ownerCt,
localToIdx = toCt.items.indexOf(targetHeader),
headerCt = this.headerCt,
columnManager= headerCt.columnManager,
fromIdx = columnManager.getHeaderIndex(dragHeader),
toIdx = columnManager.getHeaderIndex(targetHeader),
colsToMove = dragHeader.isGroupHeader ? dragHeader.query(':not([isGroupHeader])').length : 1,
sameCt = fromCt === toCt,
scrollerOwner, savedWidth;
// Drop position is to the right of the targetHeader, increment the toIdx correctly
if (dropLocation.pos === 'after') {
localToIdx++;
toIdx += targetHeader.isGroupHeader ? targetHeader.query(':not([isGroupHeader])').length : 1;
}
// If we are dragging in between two HeaderContainers that have had the lockable
// mixin injected we will lock/unlock headers in between sections, and then continue
// with another execution of onNodeDrop to ensure the header is dropped into the correct group
if (data.isLock) {
scrollerOwner = fromCt.up('[scrollerOwner]');
scrollerOwner.lock(dragHeader, localToIdx);
data.isLock = false;
// Now that the header has been transferred into the correct HeaderContainer, recurse, and continue the drop operation with the same dragData
this.onNodeDrop(node, dragZone, e, data);
} else if (data.isUnlock) {
scrollerOwner = fromCt.up('[scrollerOwner]');
scrollerOwner.unlock(dragHeader, localToIdx);
data.isUnlock = false;
// Now that the header has been transferred into the correct HeaderContainer, recurse, and continue the drop operation with the same dragData
this.onNodeDrop(node, dragZone, e, data);
}
// This is a drop within the same HeaderContainer.
else {
this.invalidateDrop();
// Cache the width here, we need to get it before we removed it from the DOM
savedWidth = dragHeader.getWidth();
// Dragging within the same container.
if (sameCt) {
// A no-op. This can happen when cross lockable drag operations recurse (see above).
// If a drop was a lock/unlock, and the lock/unlock call placed the column in the
// desired position (lock places at end, unlock places at beginning) then we're done.
if (localToIdx === localFromIdx) {
// We still need to inform the rest of the components so that events can be fired.
headerCt.onHeaderMoved(dragHeader, colsToMove, fromIdx, toIdx);
return;
}
// If dragging rightwards, then after removal, the insertion index will be less.
if (localToIdx > localFromIdx) {
localToIdx -= 1;
}
}
// Suspend layouts while we sort all this out.
Ext.suspendLayouts();
if (sameCt) {
toCt.move(localFromIdx, localToIdx);
} else {
fromCt.remove(dragHeader, false);
toCt.insert(localToIdx, dragHeader);
}
// Group headers acquire the aggregate width of their child headers
// Therefore a child header may not flex; it must contribute a fixed width.
// But we restore the flex value when moving back into the main header container
if (toCt.isGroupHeader) {
// Adjust the width of the "to" group header only if we dragged in from somewhere else.
if (!sameCt) {
dragHeader.savedFlex = dragHeader.flex;
delete dragHeader.flex;
dragHeader.width = savedWidth;
}
} else {
if (dragHeader.savedFlex) {
dragHeader.flex = dragHeader.savedFlex;
delete dragHeader.width;
}
}
// Refresh columns cache in case we remove an emptied group column
headerCt.purgeCache();
Ext.resumeLayouts(true);
headerCt.onHeaderMoved(dragHeader, colsToMove, fromIdx, toIdx);
// Ext.grid.header.Container will handle the removal of empty groups, don't handle it here
}
}
}
});