facebook-workplaceoutlookemailmicrosoft-teamsdiscordmessengercustom-servicesmacoslinuxwindowsinboxwhatsappicloudtweetdeckhipchattelegramhangoutsslackgmailskype
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
293 lines
10 KiB
293 lines
10 KiB
/** |
|
* Private utility class for Ext.Splitter. |
|
* @private |
|
*/ |
|
Ext.define('Ext.resizer.SplitterTracker', { |
|
extend: 'Ext.dd.DragTracker', |
|
requires: ['Ext.util.Region'], |
|
enabled: true, |
|
|
|
overlayCls: Ext.baseCSSPrefix + 'resizable-overlay', |
|
|
|
createDragOverlay: function () { |
|
var overlay, |
|
El = Ext.dom.Element; |
|
|
|
overlay = this.overlay = Ext.getBody().createChild({ |
|
role: 'presentation', |
|
cls: this.overlayCls, |
|
html: ' ' |
|
}); |
|
|
|
overlay.unselectable(); |
|
overlay.setSize(El.getDocumentWidth(), El.getDocumentHeight()); |
|
overlay.show(); |
|
}, |
|
|
|
getPrevCmp: function() { |
|
var splitter = this.getSplitter(); |
|
return splitter.previousSibling(':not([hidden])'); |
|
}, |
|
|
|
getNextCmp: function() { |
|
var splitter = this.getSplitter(); |
|
return splitter.nextSibling(':not([hidden])'); |
|
}, |
|
|
|
// ensure the tracker is enabled, store boxes of previous and next |
|
// components and calculate the constrain region |
|
onBeforeStart: function(e) { |
|
var me = this, |
|
prevCmp = me.getPrevCmp(), |
|
nextCmp = me.getNextCmp(), |
|
collapseEl = me.getSplitter().collapseEl, |
|
target = e.getTarget(), |
|
box; |
|
|
|
if (!prevCmp || !nextCmp) { |
|
return false; |
|
} |
|
|
|
if (collapseEl && target === collapseEl.dom) { |
|
return false; |
|
} |
|
|
|
// SplitterTracker is disabled if any of its adjacents are collapsed. |
|
if (nextCmp.collapsed || prevCmp.collapsed) { |
|
return false; |
|
} |
|
|
|
// store boxes of previous and next |
|
me.prevBox = prevCmp.getEl().getBox(); |
|
me.nextBox = nextCmp.getEl().getBox(); |
|
me.constrainTo = box = me.calculateConstrainRegion(); |
|
|
|
if (!box) { |
|
return false; |
|
} |
|
|
|
return box; |
|
}, |
|
|
|
// We move the splitter el. Add the proxy class. |
|
onStart: function(e) { |
|
var splitter = this.getSplitter(); |
|
this.createDragOverlay(); |
|
splitter.addCls(splitter.baseCls + '-active'); |
|
}, |
|
|
|
onResizeKeyDown: function(e) { |
|
var me = this, |
|
splitter = me.getSplitter(), |
|
key = e.getKey(), |
|
incrIdx = splitter.orientation === 'vertical' ? 0 : 1, |
|
incr = key === e.UP || key === e.LEFT ? -1 : 1, |
|
easing; |
|
|
|
if (!me.active && me.onBeforeStart(e)) { |
|
Ext.fly(e.target).on('keyup', me.onResizeKeyUp, me); |
|
me.triggerStart(e); |
|
me.onMouseDown(e); |
|
me.startXY = splitter.getXY(); |
|
me.lastKeyDownXY = Ext.Array.slice(me.startXY); |
|
|
|
// Movement increment eases to 4 over two seconds. |
|
easing = me.easing = new Ext.fx.easing.Linear(); |
|
easing.setStartTime(Ext.Date.now()); |
|
easing.setStartValue(1); |
|
easing.setEndValue(4); |
|
easing.setDuration(2000); |
|
} |
|
if (me.active) { |
|
me.lastKeyDownXY[incrIdx] = Math.round(me.lastKeyDownXY[incrIdx] + (incr * me.easing.getValue())); |
|
me.lastXY = me.lastKeyDownXY; |
|
splitter.setXY(me.getXY('dragTarget')); |
|
} |
|
}, |
|
|
|
onResizeKeyUp: function(e) { |
|
this.onMouseUp(e); |
|
}, |
|
|
|
// calculate the constrain Region in which the splitter el may be moved. |
|
calculateConstrainRegion: function() { |
|
var me = this, |
|
splitter = me.getSplitter(), |
|
splitWidth = splitter.getWidth(), |
|
defaultMin = splitter.defaultSplitMin, |
|
orient = splitter.orientation, |
|
prevBox = me.prevBox, |
|
prevCmp = me.getPrevCmp(), |
|
nextBox = me.nextBox, |
|
nextCmp = me.getNextCmp(), |
|
// prev and nextConstrainRegions are the maximumBoxes minus the |
|
// minimumBoxes. The result is always the intersection |
|
// of these two boxes. |
|
prevConstrainRegion, nextConstrainRegion, constrainOptions; |
|
|
|
// vertical splitters, so resizing left to right |
|
if (orient === 'vertical') { |
|
constrainOptions = { |
|
prevCmp: prevCmp, |
|
nextCmp: nextCmp, |
|
prevBox: prevBox, |
|
nextBox: nextBox, |
|
defaultMin: defaultMin, |
|
splitWidth: splitWidth |
|
}; |
|
// Region constructor accepts (top, right, bottom, left) |
|
// anchored/calculated from the left |
|
prevConstrainRegion = new Ext.util.Region( |
|
prevBox.y, |
|
me.getVertPrevConstrainRight(constrainOptions), |
|
prevBox.bottom, |
|
me.getVertPrevConstrainLeft(constrainOptions) |
|
); |
|
// anchored/calculated from the right |
|
nextConstrainRegion = new Ext.util.Region( |
|
nextBox.y, |
|
me.getVertNextConstrainRight(constrainOptions), |
|
nextBox.bottom, |
|
me.getVertNextConstrainLeft(constrainOptions) |
|
); |
|
} else { |
|
// anchored/calculated from the top |
|
prevConstrainRegion = new Ext.util.Region( |
|
prevBox.y + (prevCmp.minHeight || defaultMin), |
|
prevBox.right, |
|
// Bottom boundary is y + maxHeight if there IS a maxHeight. |
|
// Otherwise it is calculated based upon the minWidth of the next Component |
|
(prevCmp.maxHeight ? prevBox.y + prevCmp.maxHeight : nextBox.bottom - (nextCmp.minHeight || defaultMin)) + splitWidth, |
|
prevBox.x |
|
); |
|
// anchored/calculated from the bottom |
|
nextConstrainRegion = new Ext.util.Region( |
|
// Top boundary is bottom - maxHeight if there IS a maxHeight. |
|
// Otherwise it is calculated based upon the minHeight of the previous Component |
|
(nextCmp.maxHeight ? nextBox.bottom - nextCmp.maxHeight : prevBox.y + (prevCmp.minHeight || defaultMin)) - splitWidth, |
|
nextBox.right, |
|
nextBox.bottom - (nextCmp.minHeight || defaultMin), |
|
nextBox.x |
|
); |
|
} |
|
|
|
// intersection of the two regions to provide region draggable |
|
return prevConstrainRegion.intersect(nextConstrainRegion); |
|
}, |
|
|
|
// Performs the actual resizing of the previous and next components |
|
performResize: function(e, offset) { |
|
var me = this, |
|
splitter = me.getSplitter(), |
|
orient = splitter.orientation, |
|
prevCmp = me.getPrevCmp(), |
|
nextCmp = me.getNextCmp(), |
|
owner = splitter.ownerCt, |
|
flexedSiblings = owner.query('>[flex]'), |
|
len = flexedSiblings.length, |
|
vertical = orient === 'vertical', |
|
i = 0, |
|
dimension = vertical ? 'width' : 'height', |
|
totalFlex = 0, |
|
item, size; |
|
|
|
// Convert flexes to pixel values proportional to the total pixel width of all flexes. |
|
for (; i < len; i++) { |
|
item = flexedSiblings[i]; |
|
size = vertical ? item.getWidth() : item.getHeight(); |
|
totalFlex += size; |
|
item.flex = size; |
|
} |
|
|
|
offset = vertical ? offset[0] : offset[1]; |
|
|
|
if (prevCmp) { |
|
size = me.prevBox[dimension] + offset; |
|
if (prevCmp.flex) { |
|
prevCmp.flex = size; |
|
} else { |
|
prevCmp[dimension] = size; |
|
} |
|
} |
|
if (nextCmp) { |
|
size = me.nextBox[dimension] - offset; |
|
if (nextCmp.flex) { |
|
nextCmp.flex = size; |
|
} else { |
|
nextCmp[dimension] = size; |
|
} |
|
} |
|
|
|
owner.updateLayout(); |
|
}, |
|
|
|
// Cleans up the overlay (if we have one) and calls the base. This cannot be done in |
|
// onEnd, because onEnd is only called if a drag is detected but the overlay is created |
|
// regardless (by onBeforeStart). |
|
endDrag: function () { |
|
var me = this; |
|
|
|
if (me.overlay) { |
|
me.overlay.destroy(); |
|
delete me.overlay; |
|
} |
|
|
|
me.callParent(arguments); // this calls onEnd |
|
}, |
|
|
|
// perform the resize and remove the proxy class from the splitter el |
|
onEnd: function(e) { |
|
var me = this, |
|
splitter = me.getSplitter(); |
|
|
|
splitter.removeCls(splitter.baseCls + '-active'); |
|
me.performResize(e, me.getResizeOffset()); |
|
}, |
|
|
|
// Track the proxy and set the proper XY coordinates |
|
// while constraining the drag |
|
onDrag: function(e) { |
|
var me = this, |
|
offset = me.getOffset('dragTarget'), |
|
splitter = me.getSplitter(), |
|
splitEl = splitter.getEl(), |
|
orient = splitter.orientation; |
|
|
|
if (orient === "vertical") { |
|
splitEl.setX(me.startRegion.left + offset[0]); |
|
} else { |
|
splitEl.setY(me.startRegion.top + offset[1]); |
|
} |
|
}, |
|
|
|
getSplitter: function() { |
|
return this.splitter; |
|
}, |
|
|
|
getVertPrevConstrainRight: function(o) { |
|
// Right boundary is x + maxWidth if there IS a maxWidth. |
|
// Otherwise it is calculated based upon the minWidth of the next Component |
|
return (o.prevCmp.maxWidth ? o.prevBox.x + o.prevCmp.maxWidth : |
|
o.nextBox.right - (o.nextCmp.minWidth || o.defaultMin)) + o.splitWidth; |
|
}, |
|
|
|
getVertPrevConstrainLeft: function(o) { |
|
return o.prevBox.x + (o.prevCmp.minWidth || o.defaultMin); |
|
}, |
|
|
|
|
|
getVertNextConstrainRight: function(o) { |
|
return o.nextBox.right - (o.nextCmp.minWidth || o.defaultMin); |
|
}, |
|
|
|
getVertNextConstrainLeft: function(o) { |
|
// Left boundary is right - maxWidth if there IS a maxWidth. |
|
// Otherwise it is calculated based upon the minWidth of the previous Component |
|
return (o.nextCmp.maxWidth ? o.nextBox.right - o.nextCmp.maxWidth : |
|
o.prevBox.x + (o.prevBox.minWidth || o.defaultMin)) - o.splitWidth; |
|
}, |
|
|
|
getResizeOffset: function() { |
|
return this.getOffset('dragTarget'); |
|
} |
|
}); |