/**
* This is a multi-pane, application-oriented UI layout style that supports multiple nested panels,
* automatic bars between regions and built-in
* {@link Ext.panel.Panel#collapsible expanding and collapsing} of regions.
*
* This class is intended to be extended or created via the `layout: 'border'`
* {@link Ext.container.Container#layout} config, and should generally not need to be created
* directly via the new keyword.
*
* @example
* Ext.create('Ext.panel.Panel', {
* width: 500,
* height: 300,
* title: 'Border Layout',
* layout: 'border',
* items: [{
* title: 'South Region is resizable',
* region: 'south', // position for region
* xtype: 'panel',
* height: 100,
* split: true, // enable resizing
* margin: '0 5 5 5'
* },{
* // xtype: 'panel' implied by default
* title: 'West Region is collapsible',
* region:'west',
* xtype: 'panel',
* margin: '5 0 0 5',
* width: 200,
* collapsible: true, // make collapsible
* id: 'west-region-container',
* layout: 'fit'
* },{
* title: 'Center Region',
* region: 'center', // center region is required, no width/height specified
* xtype: 'panel',
* layout: 'fit',
* margin: '5 5 0 0'
* }],
* renderTo: Ext.getBody()
* });
*
* # Notes
*
* - When using the split option, the layout will automatically insert a
* {@link Ext.resizer.Splitter} into the appropriate place. This will modify the underlying
* {@link Ext.container.Container#property-items items} collection in the container.
*
* - Any Container using the Border layout **must** have a child item with `region:'center'`.
* The child item in the center region will always be resized to fill the remaining space
* not used by the other regions in the layout.
*
* - Any child items with a region of `west` or `east` may be configured with either an initial
* `width`, or a {@link Ext.layout.container.Box#flex} value, or an initial percentage width
* **string** (Which is simply divided by 100 and used as a flex value).
* The 'center' region has a flex value of `1`.
*
* - Any child items with a region of `north` or `south` may be configured with either an initial
* `height`, or a {@link Ext.layout.container.Box#flex} value, or an initial percentage height
* **string** (Which is simply divided by 100 and used as a flex value).
* The 'center' region has a flex value of `1`.
*
* - **There is no BorderLayout.Region class in ExtJS 4.0+**
*/
Ext.define('Ext.layout.container.Border', {
extend: 'Ext.layout.container.Container',
alias: 'layout.border',
alternateClassName: 'Ext.layout.BorderLayout',
requires: [
'Ext.resizer.BorderSplitter',
'Ext.fx.Anim',
// Overrides for Panel that provide border layout features
'Ext.layout.container.border.Region'
],
targetCls: Ext.baseCSSPrefix + 'border-layout-ct',
itemCls: [Ext.baseCSSPrefix + 'border-item', Ext.baseCSSPrefix + 'box-item'],
type: 'border',
isBorderLayout: true,
/**
* @cfg {Boolean/Ext.resizer.BorderSplitter} split
* This configuration option is to be applied to the **child `items`** managed by this layout.
* Each region with `split:true` will get a {@link Ext.resizer.BorderSplitter Splitter} that
* allows for manual resizing of the container. Except for the `center` region.
*
* This option can also accept an object of configurations from the
* {@link Ext.resizer.BorderSplitter}. An example of this would be:
*
* {
* title: 'North',
* region: 'north',
* height: 100,
* collapsible: true,
* split: {
* size: 20
* }
* }
*/
/**
* @cfg {Boolean} [splitterResize=true]
* This configuration option is to be applied to the **child `items`** managed by this layout
* and is used in conjunction with {@link #split}. By default, when specifying {@link #split},
* the region can be dragged to be resized. Set this option to false to show the split bar
* but prevent resizing.
*/
/**
* @cfg {Number/String/Object} padding
* Sets the padding to be applied to all child items managed by this layout.
*
* This property can be specified as a string containing space-separated, numeric
* padding values. The order of the sides associated with each value matches the way
* CSS processes padding values:
*
* - If there is only one value, it applies to all sides.
* - If there are two values, the top and bottom borders are set to the first value
* and the right and left are set to the second.
* - If there are three values, the top is set to the first value, the left and right
* are set to the second, and the bottom is set to the third.
* - If there are four values, they apply to the top, right, bottom, and left,
* respectively.
*
*/
padding: undefined,
percentageRe: /(\d+)%/,
horzPositionProp: 'left',
padOnContainerProp: 'left',
padNotOnContainerProp: 'right',
/**
* Reused meta-data objects that describe axis properties.
* @private
*/
axisProps: {
horz: {
borderBegin: 'west',
borderEnd: 'east',
horizontal: true,
posProp: 'x',
sizeProp: 'width',
sizePropCap: 'Width'
},
vert: {
borderBegin: 'north',
borderEnd: 'south',
horizontal: false,
posProp: 'y',
sizeProp: 'height',
sizePropCap: 'Height'
}
},
/**
* @private
*/
centerRegion: null,
manageMargins: true,
panelCollapseAnimate: true,
panelCollapseMode: 'placeholder',
/**
* @cfg {Object} regionWeights
* The default weights to assign to regions in the border layout. These values are
* used when a region does not contain a `weight` property. This object must have
* properties for all regions ("north", "south", "east" and "west").
*
* **IMPORTANT:** Since this is an object, changing its properties will impact ALL
* instances of Border layout. If this is not desired, provide a replacement object as
* a config option instead:
*
* layout: {
* type: 'border',
* regionWeights: {
* west: 20,
* north: 10,
* south: -10,
* east: -20
* }
* }
*
* The region with the highest weight is assigned space from the border before other
* regions. Regions of equal weight are assigned space based on their position in the
* owner's items list (first come, first served).
*/
regionWeights: {
north: 20,
south: 10,
center: 0,
west: -10,
east: -20
},
//----------------------------------
// Layout processing
/**
* Creates the axis objects for the layout. These are only missing size information
* which is added during {@link #calculate}.
* @private
*/
beginAxis: function(ownerContext, regions, name) {
var me = this,
props = me.axisProps[name],
isVert = !props.horizontal,
sizeProp = props.sizeProp,
totalFlex = 0,
childItems = ownerContext.childItems,
length = childItems.length,
center, i, childContext, centerFlex, comp, region, match, size, type, target,
placeholder;
for (i = 0; i < length; ++i) {
childContext = childItems[i];
comp = childContext.target;
childContext.layoutPos = {};
if (comp.region) {
childContext.region = region = comp.region;
childContext.isCenter = comp.isCenter;
childContext.isHorz = comp.isHorz;
childContext.isVert = comp.isVert;
childContext.weight = comp.weight || me.regionWeights[region] || 0;
comp.weight = childContext.weight;
regions[comp.id] = childContext;
if (comp.isCenter) {
center = childContext;
centerFlex = comp.flex;
ownerContext.centerRegion = center;
continue;
}
if (isVert !== childContext.isVert) {
continue;
}
// process regions "isVert ? north||south : east||center||west"
childContext.reverseWeighting = (region === props.borderEnd);
size = comp[sizeProp];
type = typeof size;
if (!comp.collapsed) {
if (type === 'string' && (match = me.percentageRe.exec(size))) {
childContext.percentage = parseInt(match[1], 10);
}
else if (comp.flex) {
totalFlex += childContext.flex = comp.flex;
}
}
}
}
// Special cases for a collapsed center region
if (center) {
target = center.target;
if ((placeholder = target.placeholderFor)) {
if (!centerFlex && isVert === placeholder.collapsedVertical()) {
// The center region is a placeholder, collapsed in this axis
centerFlex = 0;
center.collapseAxis = name;
}
}
else if (target.collapsed && (isVert === target.collapsedVertical())) {
// The center region is a collapsed header, collapsed in this axis
centerFlex = 0;
center.collapseAxis = name;
}
}
if (centerFlex == null) {
// If we still don't have a center flex, default to 1
centerFlex = 1;
}
totalFlex += centerFlex;
return Ext.apply({
before: isVert ? 'top' : 'left',
totalFlex: totalFlex
}, props);
},
beginLayout: function(ownerContext) {
var me = this,
items = me.getLayoutItems(),
pad = me.padding,
type = typeof pad,
padOnContainer = false,
childContext, item, length, i, regions, collapseTarget,
doShow, hidden, region;
//<debug>
// TODO: EXTJSIV-13015
if (ownerContext.heightModel.shrinkWrap) {
Ext.raise("Border layout does not currently support shrinkWrap height. " +
"Please specify a height on component: " + me.owner.id +
", or use a container layout that sets the component's height.");
}
if (ownerContext.widthModel.shrinkWrap) {
Ext.raise("Border layout does not currently support shrinkWrap width. " +
"Please specify a width on component: " + me.owner.id +
", or use a container layout that sets the component's width.");
}
//</debug>
// We sync the visibility state of splitters with their region:
if (pad) {
if (type === 'string' || type === 'number') {
pad = Ext.util.Format.parseBox(pad);
}
}
else {
pad = ownerContext.getEl('getTargetEl').getPaddingInfo();
padOnContainer = true;
}
ownerContext.outerPad = pad;
ownerContext.padOnContainer = padOnContainer;
for (i = 0, length = items.length; i < length; ++i) {
item = items[i];
collapseTarget = me.getSplitterTarget(item);
if (collapseTarget) { // if (splitter)
doShow = undefined;
hidden = !!item.hidden;
if (!collapseTarget.split) {
if (collapseTarget.isCollapsingOrExpanding) {
doShow = !!collapseTarget.collapsed;
}
}
else if (hidden !== collapseTarget.hidden) {
doShow = !collapseTarget.hidden;
}
if (doShow) {
item.show();
}
else if (doShow === false) {
item.hide();
}
}
}
// The above synchronized visibility of splitters with their regions, so we need
// to make this call after that so that childItems and visibleItems are correct:
//
me.callParent(arguments);
items = ownerContext.childItems;
length = items.length;
regions = {};
ownerContext.borderAxisHorz = me.beginAxis(ownerContext, regions, 'horz');
ownerContext.borderAxisVert = me.beginAxis(ownerContext, regions, 'vert');
// Now that weights are assigned to the region's contextItems, we assign those
// same weights to the contextItem for the splitters. We also cross link the
// contextItems for the collapseTarget and its splitter.
for (i = 0; i < length; ++i) {
childContext = items[i];
collapseTarget = me.getSplitterTarget(childContext.target);
if (collapseTarget) { // if (splitter)
region = regions[collapseTarget.id];
if (!region) {
// if the region was hidden it will not be part of childItems, and
// so beginAxis() won't add it to the regions object, so we have
// to create the context item here.
region = ownerContext.getEl(collapseTarget.el, me);
region.region = collapseTarget.region;
}
childContext.collapseTarget = collapseTarget = region;
childContext.weight = collapseTarget.weight;
childContext.reverseWeighting = collapseTarget.reverseWeighting;
collapseTarget.splitter = childContext;
childContext.isHorz = collapseTarget.isHorz;
childContext.isVert = collapseTarget.isVert;
}
}
// Now we want to sort the childItems by their weight.
me.sortWeightedItems(items, 'reverseWeighting');
me.setupSplitterNeighbors(items);
},
calculate: function(ownerContext) {
var me = this,
containerSize = me.getContainerSize(ownerContext),
childItems = ownerContext.childItems,
length = childItems.length,
horz = ownerContext.borderAxisHorz,
vert = ownerContext.borderAxisVert,
pad = ownerContext.outerPad,
padOnContainer = ownerContext.padOnContainer,
i, childContext, childMargins, size, horzPercentTotal, vertPercentTotal;
horz.begin = pad[me.padOnContainerProp];
vert.begin = pad.top;
// If the padding is already on the container we need to add it to the space
// If not on the container, it's "virtual" padding.
horzPercentTotal = horz.end = horz.flexSpace =
containerSize.width +
(padOnContainer ? pad[me.padOnContainerProp] : -pad[me.padNotOnContainerProp]);
vertPercentTotal = vert.end = vert.flexSpace =
containerSize.height + (padOnContainer ? pad.top : -pad.bottom);
// Reduce flexSpace on each axis by the fixed/auto sized dimensions of items that
// aren't flexed along that axis.
for (i = 0; i < length; ++i) {
childContext = childItems[i];
childMargins = childContext.getMarginInfo();
// Margins are always fixed size and must be removed from the space
// used for percentages and flexes
if (childContext.isHorz || childContext.isCenter) {
horz.addUnflexed(childMargins.width);
horzPercentTotal -= childMargins.width;
}
if (childContext.isVert || childContext.isCenter) {
vert.addUnflexed(childMargins.height);
vertPercentTotal -= childMargins.height;
}
// Fixed size components must have their sizes removed from the space used for flex
if (!childContext.flex && !childContext.percentage) {
if (childContext.isHorz ||
(childContext.isCenter && childContext.collapseAxis === 'horz')) {
size = childContext.getProp('width');
horz.addUnflexed(size);
// splitters should not count towards percentages
if (childContext.collapseTarget) {
horzPercentTotal -= size;
}
}
else if (childContext.isVert ||
(childContext.isCenter && childContext.collapseAxis === 'vert')) {
size = childContext.getProp('height');
vert.addUnflexed(size);
// splitters should not count towards percentages
if (childContext.collapseTarget) {
vertPercentTotal -= size;
}
}
// else ignore center since it is fully flexed
}
}
for (i = 0; i < length; ++i) {
childContext = childItems[i];
childMargins = childContext.getMarginInfo();
// Calculate the percentage sizes. After this calculation percentages
// are very similar to fixed sizes
if (childContext.percentage) {
if (childContext.isHorz) {
size = Math.ceil(horzPercentTotal * childContext.percentage / 100);
size = childContext.setWidth(size);
horz.addUnflexed(size);
}
else if (childContext.isVert) {
size = Math.ceil(vertPercentTotal * childContext.percentage / 100);
size = childContext.setHeight(size);
vert.addUnflexed(size);
}
// center shouldn't have a percentage but if it does it should be ignored
}
}
// If we haven't gotten sizes for all unflexed dimensions on an axis, the flexSpace
// will be NaN so we won't be calculating flexed dimensions until that is resolved.
for (i = 0; i < length; ++i) {
childContext = childItems[i];
if (!childContext.isCenter) {
me.calculateChildAxis(childContext, horz);
me.calculateChildAxis(childContext, vert);
}
}
// Once all items are placed, the final size of the center can be determined. If we
// can determine both width and height, we are done. We use '+' instead of '&&' to
// avoid short-circuiting (we want to call both):
if (me.finishAxis(ownerContext, vert) + me.finishAxis(ownerContext, horz) < 2) {
me.done = false;
}
else {
// Size information is published as we place regions but position is hard to do
// that way (while avoiding published multiple times) so we publish all the
// positions at the end.
me.finishPositions(childItems);
}
},
/**
* Performs the calculations for a region on a specified axis.
* @private
*/
calculateChildAxis: function(childContext, axis) {
var collapseTarget = childContext.collapseTarget,
setSizeMethod = 'set' + axis.sizePropCap,
sizeProp = axis.sizeProp,
childMarginSize = childContext.getMarginInfo()[sizeProp],
region, isBegin, flex, pos, size;
if (collapseTarget) { // if (splitter)
region = collapseTarget.region;
}
else {
region = childContext.region;
flex = childContext.flex;
}
isBegin = region === axis.borderBegin;
if (!isBegin && region !== axis.borderEnd) {
// a north/south region on the horizontal axis or an east/west region on the
// vertical axis: stretch to fill remaining space:
childContext[setSizeMethod](axis.end - axis.begin - childMarginSize);
pos = axis.begin;
}
else {
if (flex) {
size = Math.ceil(axis.flexSpace * (flex / axis.totalFlex));
size = childContext[setSizeMethod](size);
}
else if (childContext.percentage) {
// Like getProp but without registering a dependency - we calculated the size,
// we don't depend on it
size = childContext.peek(sizeProp);
}
else {
size = childContext.getProp(sizeProp);
}
size += childMarginSize;
if (isBegin) {
pos = axis.begin;
axis.begin += size;
}
else {
axis.end = pos = axis.end - size;
}
}
childContext.layoutPos[axis.posProp] = pos;
},
eachItem: function(region, fn, scope) {
var me = this,
items = me.getLayoutItems(),
i = 0,
item;
if (Ext.isFunction(region)) {
fn = region;
scope = fn;
}
for (i; i < items.length; i++) {
item = items[i];
if (!region || item.region === region) {
if (fn.call(scope, item) === false) {
break;
}
}
}
},
/**
* Finishes the calculations on an axis. This basically just assigns the remaining
* space to the center region.
* @private
*/
finishAxis: function(ownerContext, axis) {
var size = axis.end - axis.begin,
center = ownerContext.centerRegion;
if (center) {
center['set' + axis.sizePropCap](size - center.getMarginInfo()[axis.sizeProp]);
center.layoutPos[axis.posProp] = axis.begin;
}
return Ext.isNumber(size) ? 1 : 0;
},
/**
* Finishes by setting the positions on the child items.
* @private
*/
finishPositions: function(childItems) {
var length = childItems.length,
index, childContext,
marginProp = this.horzPositionProp;
for (index = 0; index < length; ++index) {
childContext = childItems[index];
childContext.setProp(
'x', childContext.layoutPos.x + childContext.marginInfo[marginProp]
);
childContext.setProp(
'y', childContext.layoutPos.y + childContext.marginInfo.top
);
}
},
getLayoutItems: function() {
var owner = this.owner,
ownerItems = (owner && owner.items && owner.items.items) || [],
length = ownerItems.length,
items = [],
i = 0,
ownerItem, placeholderFor;
for (; i < length; i++) {
ownerItem = ownerItems[i];
placeholderFor = ownerItem.placeholderFor;
// There are a couple of scenarios where we do NOT want an item to
// be included in the layout items:
//
// 1. If the item is floated. This can happen when a region's header
// is clicked to "float" the item, then another region's header or
// is clicked quickly before the first floated region has had a
// chance to slide out. When this happens, the second click triggers
// a layout, the purpose of which is to determine what the size of the
// second region will be after it is floated, so it can be animated
// to that size. In this case the existing floated item should not be
// included in the layout items because it will not be visible once
// it's slideout animation has completed.
//
// 2. If the item is a placeholder for a panel that is currently
// being expanded. Similar to scenario 1, a second layout can be
// triggered by another panel being expanded/collapsed/floated before
// the first panel has finished it's expand animation. If this is the
// case we do not want the placeholder to be included in the layout
// items because it will not be once the panel has finished expanding.
//
// If the component is hidden, we need none of these shenanigans
if (ownerItem.hidden ||
((!ownerItem.floated || ownerItem.isCollapsingOrExpanding === 2) &&
!(placeholderFor && placeholderFor.isCollapsingOrExpanding === 2))) {
items.push(ownerItem);
}
}
return items;
},
getPlaceholder: function(comp) {
return comp.getPlaceholder && comp.getPlaceholder();
},
getMaxWeight: function(region) {
return this.getMinMaxWeight(region);
},
getMinWeight: function(region) {
return this.getMinMaxWeight(region, true);
},
getMinMaxWeight: function(region, min) {
var me = this,
weight = null;
me.eachItem(region, function(item) {
if (item.hasOwnProperty('weight')) {
if (weight === null) {
weight = item.weight;
return;
}
if ((min && item.weight < weight) || item.weight > weight) {
weight = item.weight;
}
}
}, this);
return weight;
},
getSplitterTarget: function(splitter) {
var collapseTarget = splitter.collapseTarget;
if (collapseTarget && collapseTarget.collapsed) {
return collapseTarget.placeholder || collapseTarget;
}
return collapseTarget;
},
isItemBoxParent: function(itemContext) {
return true;
},
isItemShrinkWrap: function(item) {
return true;
},
//----------------------------------
// Event handlers
/**
* Inserts the splitter for a given region. A reference to the splitter is also stored
* on the component as "splitter".
* @private
*/
insertSplitter: function(item, index, hidden, splitterCfg) {
var region = item.region,
splitter = Ext.apply({
xtype: 'bordersplitter',
collapseTarget: item,
id: item.id + '-splitter',
hidden: hidden,
canResize: item.splitterResize !== false,
splitterFor: item,
synthetic: true // not user-defined
}, splitterCfg),
at = index + ((region === 'south' || region === 'east') ? 0 : 1);
if (item.collapseMode === 'mini') {
splitter.collapsedCls = item.collapsedCls;
}
item.splitter = this.owner.add(at, splitter);
},
getMoveAfterIndex: function(after) {
var index = this.callParent(arguments);
if (after.splitter) {
index++;
}
return index;
},
moveItemBefore: function(item, before) {
var beforeRegion;
if (before && before.splitter) {
beforeRegion = before.region;
if (beforeRegion === 'south' || beforeRegion === 'east') {
before = before.splitter;
}
}
return this.callParent([item, before]);
},
/**
* Called when a region (actually when any component) is added to the container. The
* region is decorated with some helpful properties (isCenter, isHorz, isVert) and its
* splitter is added if its "split" property is true.
* @private
*/
onAdd: function(item, index) {
var me = this,
placeholderFor = item.placeholderFor,
region = item.region,
isCenter,
split,
hidden,
cfg;
me.callParent(arguments);
if (region) {
Ext.apply(item, me.regionFlags[region]);
if (me.owner.isViewport) {
item.isViewportBorderChild = true;
}
if (item.initBorderRegion) {
// This method should always be present but perhaps the override is being
// excluded.
item.initBorderRegion();
}
isCenter = region === 'center';
if (isCenter) {
//<debug>
if (me.centerRegion) {
Ext.raise("Cannot have multiple center regions in a BorderLayout.");
}
//</debug>
me.centerRegion = item;
}
else {
split = item.split;
hidden = !!item.hidden;
if (typeof split === 'object') {
cfg = split;
split = true;
}
if ((item.isHorz || item.isVert) && (split || item.collapseMode === 'mini')) {
if (item.collapseMode === 'mini' && item.collapsed) {
hidden = false;
}
else if (!split) {
hidden = true;
}
me.insertSplitter(item, index, hidden, cfg);
}
}
if (!isCenter && !item.hasOwnProperty('collapseMode')) {
item.collapseMode = me.panelCollapseMode;
}
if (!item.hasOwnProperty('animCollapse')) {
if (item.collapseMode !== 'placeholder') {
// other collapse modes do not animate nicely in a border layout, so
// default them to off:
item.animCollapse = false;
}
else {
item.animCollapse = me.panelCollapseAnimate;
}
}
// Item can be collapsed when added
if (hidden && item.placeholder && item.placeholder.isVisible()) {
me.owner.insert(index, item.placeholder);
}
}
else if (placeholderFor) {
Ext.apply(item, me.regionFlags[placeholderFor.region]);
item.region = placeholderFor.region;
item.weight = placeholderFor.weight;
}
},
onDestroy: function() {
this.centerRegion = null;
this.callParent();
},
onRemove: function(comp, isDestroying) {
var me = this,
region = comp.region,
splitter = comp.splitter,
owner = me.owner,
destroying = owner.destroying,
el;
if (region) {
if (comp.isCenter) {
me.centerRegion = null;
}
delete comp.isCenter;
delete comp.isHorz;
delete comp.isVert;
// If the owner is destroying, the splitter will be cleared anyway
if (splitter && !owner.destroying) {
owner.doRemove(splitter, true); // avoid another layout
}
delete comp.splitter;
}
me.callParent(arguments);
if (!destroying && !isDestroying && comp.rendered) {
// Clear top/left styles
el = comp.getEl();
if (el) {
el.setStyle('top', '');
el.setStyle(me.horzPositionProp, '');
}
}
},
//----------------------------------
// Misc
regionMeta: {
center: { splitterDelta: 0 },
north: { splitterDelta: 1 },
south: { splitterDelta: -1 },
west: { splitterDelta: 1 },
east: { splitterDelta: -1 }
},
/**
* Flags and configs that get set of regions based on their `region` property.
* @private
*/
regionFlags: {
center: {
isCenter: true, isHorz: false, isVert: false
},
north: {
isCenter: false, isHorz: false, isVert: true, collapseDirection: 'top'
},
south: {
isCenter: false, isHorz: false, isVert: true, collapseDirection: 'bottom'
},
west: {
isCenter: false, isHorz: true, isVert: false, collapseDirection: 'left'
},
east: {
isCenter: false, isHorz: true, isVert: false, collapseDirection: 'right'
}
},
setupSplitterNeighbors: function(items) {
var edgeRegions = {
// north: null,
// south: null,
// east: null,
// west: null
},
length = items.length,
touchedRegions = this.touchedRegions,
i, j, center, count, edge, comp, region, splitter, touched;
for (i = 0; i < length; ++i) {
comp = items[i].target;
region = comp.region;
if (comp.isCenter) {
center = comp;
}
else if (region) {
touched = touchedRegions[region];
for (j = 0, count = touched.length; j < count; ++j) {
edge = edgeRegions[touched[j]];
if (edge) {
edge.neighbors.push(comp);
}
}
if (comp.placeholderFor) {
// placeholder, so grab the splitter for the actual panel
splitter = comp.placeholderFor.splitter;
}
else {
splitter = comp.splitter;
}
if (splitter) {
splitter.neighbors = [];
}
edgeRegions[region] = splitter;
}
}
if (center) {
touched = touchedRegions.center;
for (j = 0, count = touched.length; j < count; ++j) {
edge = edgeRegions[touched[j]];
if (edge) {
edge.neighbors.push(center);
}
}
}
},
/**
* Lists the regions that would consider an interior region a neighbor. For example,
* a north region would consider an east or west region its neighbords (as well as
* an inner north region).
* @private
*/
touchedRegions: {
center: [ 'north', 'south', 'east', 'west' ],
north: [ 'north', 'east', 'west' ],
south: [ 'south', 'east', 'west' ],
east: [ 'east', 'north', 'south' ],
west: [ 'west', 'north', 'south' ]
},
sizePolicies: {
vert: {
readsWidth: 0,
readsHeight: 1,
setsWidth: 1,
setsHeight: 0
},
horz: {
readsWidth: 1,
readsHeight: 0,
setsWidth: 0,
setsHeight: 1
},
flexAll: {
readsWidth: 0,
readsHeight: 0,
setsWidth: 1,
setsHeight: 1
}
},
getItemSizePolicy: function(item) {
var me = this,
policies = this.sizePolicies,
collapseTarget, size, policy, placeholderFor;
if (item.isCenter) {
placeholderFor = item.placeholderFor;
if (placeholderFor) {
if (placeholderFor.collapsedVertical()) {
return policies.vert;
}
return policies.horz;
}
if (item.collapsed) {
if (item.collapsedVertical()) {
return policies.vert;
}
return policies.horz;
}
return policies.flexAll;
}
collapseTarget = item.collapseTarget;
if (collapseTarget) {
return collapseTarget.isVert ? policies.vert : policies.horz;
}
if (item.region) {
if (item.isVert) {
size = item.height;
policy = policies.vert;
}
else {
size = item.width;
policy = policies.horz;
}
if (item.flex || (typeof size === 'string' && me.percentageRe.test(size))) {
return policies.flexAll;
}
return policy;
}
return me.autoSizePolicy;
}
}, function() {
var methods = {
addUnflexed: function(px) {
this.flexSpace = Math.max(this.flexSpace - px, 0);
}
},
props = this.prototype.axisProps;
Ext.apply(props.horz, methods);
Ext.apply(props.vert, methods);
});