Форк Rambox
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.
 
 
 

1598 lines
62 KiB

/**
* This ComponentLayout handles docking for Panels. It takes care of panels that are
* part of a ContainerLayout that sets this Panel's size and Panels that are part of
* an AutoContainerLayout in which this panel get his height based of the CSS or
* its content.
* @private
*/
Ext.define('Ext.layout.component.Dock', {
/* Begin Definitions */
extend: 'Ext.layout.component.Component',
alias: 'layout.dock',
alternateClassName: 'Ext.layout.component.AbstractDock',
/* End Definitions */
type: 'dock',
horzAxisProps: {
name: 'horz',
oppositeName: 'vert',
dockBegin: 'left',
dockEnd: 'right',
horizontal: true,
marginBegin: 'margin-left',
maxSize: 'maxWidth',
minSize: 'minWidth',
pos: 'x',
setSize: 'setWidth',
shrinkWrapDock: 'shrinkWrapDockWidth',
size: 'width',
sizeModel: 'widthModel'
},
vertAxisProps: {
name: 'vert',
oppositeName: 'horz',
dockBegin: 'top',
dockEnd: 'bottom',
horizontal: false,
marginBegin: 'margin-top',
maxSize: 'maxHeight',
minSize: 'minHeight',
pos: 'y',
setSize: 'setHeight',
shrinkWrapDock: 'shrinkWrapDockHeight',
size: 'height',
sizeModel: 'heightModel'
},
initializedBorders: -1,
horizontalCollapsePolicy: { width: true, x: true },
verticalCollapsePolicy: { height: true, y: true },
finishRender: function () {
var me = this,
target, items;
me.callParent();
target = me.getRenderTarget();
items = me.getDockedItems();
me.finishRenderItems(target, items);
},
isItemBoxParent: function (itemContext) {
return true;
},
isItemShrinkWrap: function (item) {
return true;
},
noBorderClasses: [
Ext.baseCSSPrefix + 'docked-noborder-top',
Ext.baseCSSPrefix + 'docked-noborder-right',
Ext.baseCSSPrefix + 'docked-noborder-bottom',
Ext.baseCSSPrefix + 'docked-noborder-left'
],
noBorderClassesSides: {
top: Ext.baseCSSPrefix + 'docked-noborder-top',
right: Ext.baseCSSPrefix + 'docked-noborder-right',
bottom: Ext.baseCSSPrefix + 'docked-noborder-bottom',
left: Ext.baseCSSPrefix + 'docked-noborder-left'
},
borderWidthProps: {
top: 'border-top-width',
right: 'border-right-width',
bottom: 'border-bottom-width',
left: 'border-left-width'
},
_itemCls: Ext.baseCSSPrefix + 'docked',
handleItemBorders: function() {
var me = this,
owner = me.owner,
borders, docked,
lastItems = me.lastDockedItems,
oldBorders = me.borders,
currentGeneration = owner.dockedItems.generation,
noBorderClassesSides = me.noBorderClassesSides,
borderWidthProps = me.borderWidthProps,
i, ln, item, dock, side,
collapsed = me.collapsed;
// If we're collapsed with mini, it means we're in a border layout so we'll
// be visibility: hidden
if (me.initializedBorders === currentGeneration || (owner.border && !owner.manageBodyBorders) || (owner.collapsed && owner.collapseMode === 'mini')) {
return;
}
me.initializedBorders = currentGeneration;
// Borders have to be calculated using expanded docked item collection.
me.collapsed = false;
me.lastDockedItems = docked = me.getLayoutItems();
me.collapsed = collapsed;
borders = { top: [], right: [], bottom: [], left: [] };
for (i = 0, ln = docked.length; i < ln; i++) {
item = docked[i];
dock = item.dock;
if (item.ignoreBorderManagement) {
continue;
}
if (!borders[dock].satisfied) {
borders[dock].push(item);
borders[dock].satisfied = true;
}
if (!borders.top.satisfied && dock !== 'bottom') {
borders.top.push(item);
}
if (!borders.right.satisfied && dock !== 'left') {
borders.right.push(item);
}
if (!borders.bottom.satisfied && dock !== 'top') {
borders.bottom.push(item);
}
if (!borders.left.satisfied && dock !== 'right') {
borders.left.push(item);
}
}
if (lastItems) {
for (i = 0, ln = lastItems.length; i < ln; i++) {
item = lastItems[i];
if (!item.isDestroyed && !item.ignoreBorderManagement && !owner.manageBodyBorders) {
item.removeCls(me.noBorderClasses);
}
}
}
if (oldBorders) {
for (side in oldBorders) {
if (owner.manageBodyBorders && oldBorders[side].satisfied) {
owner.setBodyStyle(borderWidthProps[side], '');
}
}
}
for (side in borders) {
ln = borders[side].length;
if (!owner.manageBodyBorders) {
for (i = 0; i < ln; i++) {
borders[side][i].addCls(noBorderClassesSides[side]);
}
if ((!borders[side].satisfied && !owner.bodyBorder) || owner.bodyBorder === false) {
owner.addBodyCls(noBorderClassesSides[side]);
} else {
owner.removeBodyCls(noBorderClassesSides[side]);
}
}
else if (borders[side].satisfied) {
owner.setBodyStyle(borderWidthProps[side], '1px');
}
}
me.borders = borders;
},
beforeLayoutCycle: function (ownerContext) {
var me = this,
owner = me.owner,
shrinkWrap = me.sizeModels.shrinkWrap,
shrinkWrapDock = owner.shrinkWrapDock,
collapsedHorz, collapsedVert;
if (owner.collapsed) {
if (owner.collapsedVertical()) {
collapsedVert = true;
ownerContext.measureDimensions = 1;
} else {
collapsedHorz = true;
ownerContext.measureDimensions = 2;
}
}
ownerContext.collapsedVert = collapsedVert;
ownerContext.collapsedHorz = collapsedHorz;
// If we are collapsed, we want to auto-layout using the placeholder/expander
// instead of the normal items/dockedItems. This must be done here since we could
// be in a box layout w/stretchmax which sets the width/heightModel to allow it to
// control the size.
if (collapsedVert) {
ownerContext.heightModel = shrinkWrap;
} else if (collapsedHorz) {
ownerContext.widthModel = shrinkWrap;
}
shrinkWrapDock = shrinkWrapDock === true ? 3 : (shrinkWrapDock || 0);
ownerContext.shrinkWrapDockHeight = (shrinkWrapDock & 1) && // jshint ignore:line
ownerContext.heightModel.shrinkWrap;
ownerContext.shrinkWrapDockWidth = (shrinkWrapDock & 2) && // jshint ignore:line
ownerContext.widthModel.shrinkWrap;
},
beginLayout: function(ownerContext) {
var me = this,
owner = me.owner,
docked = me.getLayoutItems(),
layoutContext = ownerContext.context,
dockedItemCount = docked.length,
lastCollapsedState = me.lastCollapsedState,
dockedItems, i, item, itemContext, offsets,
collapsed, dock;
me.callParent(arguments);
// Cache the children as ContextItems (like a Container). Also setup to handle
// collapsed state:
collapsed = owner.getCollapsed();
if (collapsed !== lastCollapsedState && lastCollapsedState !== undefined) {
// If we are collapsing...
if (me.owner.collapsed) {
ownerContext.isCollapsingOrExpanding = 1;
// Add the collapsed class now, so that collapsed CSS rules are applied before measurements are taken by the layout.
owner.addClsWithUI(owner.collapsedCls);
} else {
ownerContext.isCollapsingOrExpanding = 2;
// Remove the collapsed class now, before layout calculations are done.
owner.removeClsWithUI(owner.collapsedCls);
ownerContext.lastCollapsedState = me.lastCollapsedState;
}
}
me.lastCollapsedState = collapsed;
ownerContext.dockedItems = dockedItems = [];
for (i = 0; i < dockedItemCount; i++) {
item = docked[i];
if (item.rendered) {
dock = item.dock;
itemContext = layoutContext.getCmp(item);
itemContext.dockedAt = { x: 0, y: 0 };
itemContext.offsets = offsets = Ext.Element.parseBox(item.offsets || 0);
itemContext.horizontal = dock === 'top' || dock === 'bottom';
offsets.width = offsets.left + offsets.right;
offsets.height = offsets.top + offsets.bottom;
dockedItems.push(itemContext);
}
}
ownerContext.bodyContext = ownerContext.getEl('body');
},
beginLayoutCycle: function(ownerContext) {
var me = this,
docked = ownerContext.dockedItems,
len = docked.length,
owner = me.owner,
frameBody = owner.frameBody,
lastHeightModel = me.lastHeightModel,
i, item, dock;
me.callParent(arguments);
if (me.owner.manageHeight) {
// Reset in case manageHeight gets turned on during lifecycle.
// See below for why display could be set to non-default value.
if (me.lastBodyDisplay) {
owner.body.dom.style.display = me.lastBodyDisplay = '';
}
} else {
// When manageHeight is false, the body stretches the outer el by using wide margins to force it to
// accommodate the docked items. When overflow is visible (when panel is resizable and has embedded handles),
// the body must be inline-block so as not to collapse its margins
if (me.lastBodyDisplay !== 'inline-block') {
owner.body.dom.style.display = me.lastBodyDisplay = 'inline-block';
}
if (lastHeightModel && lastHeightModel.shrinkWrap &&
!ownerContext.heightModel.shrinkWrap) {
owner.body.dom.style.marginBottom = '';
}
}
if (ownerContext.widthModel.auto) {
if (ownerContext.widthModel.shrinkWrap) {
owner.el.setWidth(null);
}
owner.body.setWidth(null);
if (frameBody) {
frameBody.setWidth(null);
}
}
if (ownerContext.heightModel.auto) {
owner.body.setHeight(null);
//owner.el.setHeight(null); Disable this for now
if (frameBody) {
frameBody.setHeight(null);
}
}
// Each time we begin (2nd+ would be due to invalidate) we need to publish the
// known contentWidth/Height if we are collapsed:
if (ownerContext.collapsedVert) {
ownerContext.setContentHeight(0);
} else if (ownerContext.collapsedHorz) {
ownerContext.setContentWidth(0);
}
// dock: 'right' items, when a panel gets narrower get "squished". Moving them to
// left:0px avoids this!
for (i = 0; i < len; i++) {
item = docked[i].target;
dock = item.dock;
if (dock === 'right') {
item.setLocalX(0);
} else if (dock !== 'left') {
continue;
}
// TODO - clear width/height?
}
},
calculate: function (ownerContext) {
var me = this,
measure = me.measureAutoDimensions(ownerContext, ownerContext.measureDimensions),
state = ownerContext.state,
horzDone = state.horzDone,
vertDone = state.vertDone,
bodyContext = ownerContext.bodyContext,
framing, horz, vert, forward, backward;
// make sure we can use these value w/o calling methods to get them
ownerContext.borderInfo || ownerContext.getBorderInfo(); // jshint ignore:line
ownerContext.paddingInfo || ownerContext.getPaddingInfo(); // jshint ignore:line
ownerContext.frameInfo || ownerContext.getFrameInfo(); // jshint ignore:line
bodyContext.borderInfo || bodyContext.getBorderInfo(); // jshint ignore:line
bodyContext.paddingInfo || bodyContext.getPaddingInfo(); // jshint ignore:line
// On CSS3 browsers, the border and padding frame the outer el. On non-CSS3
// browsers, the outer el has no border or padding - all that appears on the
// framing elements as padding and height. In CSS3, the border size effects the
// origin of the dockedItems but the padding does not (so that must be added in
// most of the time). In non-CSS3 mode, the dockedItems are outside the framing:
//
// ... top / left dockedItems ...
// <div id="...-ml" style="padding-left: border-radius-left;">
// <div id="...-mr" style="padding-right: border-radius-right;">
// <div id="...-mc" style="padding: extra;">
// ... body ...
// </div>
// </div>
// </div>
// ... bottom / right dockedItems ...
//
// For the sake of sanity, we perform all the calculations in CSS3 mode. We test
// for the presence of non-CSS3 framing only when necessary.
//
if (!ownerContext.frameBorder) {
if (!(framing = ownerContext.framing)) {
ownerContext.frameBorder = ownerContext.borderInfo;
ownerContext.framePadding = ownerContext.paddingInfo;
} else {
// These values match what they would have been in CSS3.
ownerContext.frameBorder = framing.border;
ownerContext.framePadding = framing.padding;
}
}
// Start the axes so they are ready to proceed inwards (fixed-size) or outwards
// (shrinkWrap) and stash key property names as well:
horz = !horzDone &&
me.createAxis(ownerContext, measure.contentWidth, ownerContext.widthModel,
me.horzAxisProps, ownerContext.collapsedHorz);
vert = !vertDone &&
me.createAxis(ownerContext, measure.contentHeight, ownerContext.heightModel,
me.vertAxisProps, ownerContext.collapsedVert);
// We iterate forward and backward over the dockedItems at the same time based on
// whether an axis is shrinkWrap or fixed-size. For a fixed-size axis, the outer box
// axis is allocated to docked items in forward order and is reduced accordingly.
// To handle a shrinkWrap axis, the box starts at the inner (body) size and is used to
// size docked items in backwards order. This is because the last docked item shares
// an edge with the body. The item size is used to adjust the shrinkWrap axis outwards
// until the first docked item (at the outermost edge) is processed. This backwards
// order ensures that docked items never get an incorrect size for any dimension.
for (forward = 0, backward = ownerContext.dockedItems.length; backward--; ++forward) {
if (horz) {
me.dockChild(ownerContext, horz, backward, forward);
}
if (vert) {
me.dockChild(ownerContext, vert, backward, forward);
}
}
if (horz && me.finishAxis(ownerContext, horz)) {
state.horzDone = horzDone = horz;
}
if (vert && me.finishAxis(ownerContext, vert)) {
state.vertDone = vertDone = vert;
}
// Once all items are docked, the final size of the outer panel or inner body can
// be determined. If we can determine both width and height, we are done.
if (horzDone && vertDone && me.finishConstraints(ownerContext, horzDone, vertDone)) {
// Size information is published as we dock items but position is hard to do
// that way (while avoiding published multiple times) so we publish all the
// positions at the end.
me.finishPositions(ownerContext, horzDone, vertDone);
} else {
me.done = false;
}
},
/**
* Creates an axis object given the particulars. The process starts by placing the
* dockedItems in an idealized box where this method is called once for each side.
* The ideal box is defined by the CSS3 border and padding values (which account for
* the influence of border-radius). The origin (the (0,0) point) of the ideal box is
* the top-left edge of the border or the border-box. Normal dockedItems are placed
* inside this box at an offset to clear the border and padding and sit properly in
* the panel next to the body.
*
* The origin has to be started differently if the axis is in shrinkWrap mode. When
* shrink-wrapping an axis, the axis starts at the edge of the body and expands
* outwards as items are docked. This means the ideal (0,0) for shrinkWrap is on the
* top-left corner of the body.
*
* The following diagram illustrates this using the vertical axis.
*
* +---------------------------+ 10px (border)
* | |
* | xxxxxxxxxxxxxxxxxxxxxxx | 5px (padding) shrinkWrap other
* | +=====================+ | -50 15
* | | Header | | 30px
* | | | |
* | +=====================+ |
* | +---------------------+ | -20 45
* | | tbar | | 20 px
* | +---------------------+ |
* | +---------------------+ | 0 65
* | | Body | | 100px
* | | | |
* | | | |
* | +---------------------+ |
* | +---------------------+ | 100 165
* | | bbar | | 15px
* | +---------------------+ |
* | xxxxxxxxxxxxxxxxxxxxxxx | 5px
* | |
* +---------------------------+ 10px
*
* These are sufficient to determine sizes of things, but to finalize this process
* and assign proper positions, the tentative coordinates have to be adjusted by an
* amount appropriate for the item. Because dockedItems are position:absolute, they
* sit inside the border and so must be adjusted for padding. The body is different
* because it is position:relative and so it naturally sits inside the padding and
* the padding must not be included in its position.
*
* Headers and footers that use `ignoreParentFrame` interact with this process by
* moving themselves outside the border and padding. So in the above diagram, the
* Header would move up by 15px and *everything else* would move up by 10px. When
* shrinkWrap is taking place, the 10px of border on the top is removed from the
* height as well.
*
* The bbar behaves slightly different when it is `ignoreParentFrame`. In shrinkWrap
* mode, it alone would move down by the padding and the bottom border would not be
* included in the height. Otherwise, the bbar would be moved down 15px (since the
* edge is fixed) and the next dockedItem would be placed at, or the body would be
* stretched down to, 5px (padding) pixels above the bbar.
*
* @private
*/
createAxis: function (ownerContext, contentSize, sizeModel, axisProps, collapsedAxis) {
var me = this,
begin = 0,
owner = me.owner,
maxSize = owner[axisProps.maxSize],
minSize = owner[axisProps.minSize] || 0,
dockBegin = axisProps.dockBegin,
dockEnd = axisProps.dockEnd,
posProp = axisProps.pos,
sizeProp = axisProps.size,
hasMaxSize = maxSize != null, // exactly the same as "maxSize !== null && maxSize !== undefined"
shrinkWrap = sizeModel.shrinkWrap,
bodyContext, framing, padding, end;
if (shrinkWrap) {
// End position before adding docks around the content is content size plus the body borders in this axis.
// If collapsed in this axis, the body borders will not be shown.
if (collapsedAxis) {
end = 0;
} else {
bodyContext = ownerContext.bodyContext;
end = contentSize + bodyContext.borderInfo[sizeProp];
}
} else {
framing = ownerContext.frameBorder;
padding = ownerContext.framePadding;
begin = framing[dockBegin] + padding[dockBegin];
end = ownerContext.getProp(sizeProp) - (framing[dockEnd] + padding[dockEnd]);
}
return {
shrinkWrap: sizeModel.shrinkWrap,
sizeModel: sizeModel,
// An axis tracks start and end+1 px positions. eg 0 to 10 for 10px high
initialBegin: begin,
begin: begin,
end: end,
collapsed: collapsedAxis,
horizontal: axisProps.horizontal,
ignoreFrameBegin: null,
ignoreFrameEnd: null,
initialSize: end - begin,
maxChildSize: 0,
hasMinMaxConstraints: (minSize || hasMaxSize) && sizeModel.shrinkWrap,
minSize: minSize,
maxSize: hasMaxSize ? maxSize : 1e9,
bodyPosProp: me.owner.manageHeight ? posProp : axisProps.marginBegin,
dockBegin: dockBegin, // 'left' or 'top'
dockEnd: dockEnd, // 'right' or 'end'
posProp: posProp, // 'x' or 'y'
sizeProp: sizeProp, // 'width' or 'height'
setSize: axisProps.setSize,
shrinkWrapDock: ownerContext[axisProps.shrinkWrapDock],
sizeModelName: axisProps.sizeModel,
dockedPixelsEnd: 0
};
},
/**
* Docks a child item on the specified axis. This boils down to determining if the item
* is docked at the "beginning" of the axis ("left" if horizontal, "top" if vertical),
* the "end" of the axis ("right" if horizontal, "bottom" if vertical) or stretches
* along the axis ("top" or "bottom" if horizontal, "left" or "right" if vertical). It
* also has to differentiate between fixed and shrinkWrap sized dimensions.
* @private
*/
dockChild: function (ownerContext, axis, backward, forward) {
var me = this,
itemContext = ownerContext.dockedItems[axis.shrinkWrap ? backward : forward],
item = itemContext.target,
dock = item.dock, // left/top/right/bottom
sizeProp = axis.sizeProp,
pos, size;
if (item.ignoreParentFrame && ownerContext.isCollapsingOrExpanding) {
// collapsed window header margins may differ from expanded window header margins
// so we need to make sure the old cached values are not used in axis calculations
itemContext.clearMarginCache();
}
if (!itemContext.marginInfo) {
itemContext.getMarginInfo(); // get marginInfo ready
}
if (dock === axis.dockBegin) {
if (axis.shrinkWrap) {
pos = me.dockOutwardBegin(ownerContext, itemContext, item, axis);
} else {
pos = me.dockInwardBegin(ownerContext, itemContext, item, axis);
}
} else if (dock === axis.dockEnd) {
if (axis.shrinkWrap) {
pos = me.dockOutwardEnd(ownerContext, itemContext, item, axis);
} else {
pos = me.dockInwardEnd(ownerContext, itemContext, item, axis);
}
} else {
if (axis.shrinkWrapDock) {
// we are still shrinkwrapping transversely... so we need to include the
// size of this item in the max calculation
size = itemContext.getProp(sizeProp) + itemContext.marginInfo[sizeProp];
axis.maxChildSize = Math.max(axis.maxChildSize, size);
pos = 0;
} else {
pos = me.dockStretch(ownerContext, itemContext, item, axis);
}
}
itemContext.dockedAt[axis.posProp] = pos;
},
/**
* Docks an item on a fixed-size axis at the "beginning". The "beginning" of the horizontal
* axis is "left" and the vertical is "top". For a fixed-size axis, the size works from
* the outer element (the panel) towards the body.
* @private
*/
dockInwardBegin: function (ownerContext, itemContext, item, axis) {
var pos = axis.begin,
sizeProp = axis.sizeProp,
ignoreParentFrame = item.ignoreParentFrame,
delta,
size,
dock;
if (ignoreParentFrame) {
axis.ignoreFrameBegin = itemContext;
dock = item.dock;
// We need to move everything up by the border-width.
delta = ownerContext.frameBorder[dock];
// We need to move the header "up" by the padding as well.
pos -= delta + ownerContext.framePadding[dock];
}
if (!item.overlay) {
size = itemContext.getProp(sizeProp) + itemContext.marginInfo[sizeProp];
axis.begin += size;
if (ignoreParentFrame) {
axis.begin -= delta;
}
}
return pos;
},
/**
* Docks an item on a fixed-size axis at the "end". The "end" of the horizontal axis is
* "right" and the vertical is "bottom".
* @private
*/
dockInwardEnd: function (ownerContext, itemContext, item, axis) {
var sizeProp = axis.sizeProp,
size = itemContext.getProp(sizeProp) + itemContext.marginInfo[sizeProp],
pos = axis.end - size,
frameEnd;
if (!item.overlay) {
axis.end = pos;
}
if (item.ignoreParentFrame) {
axis.ignoreFrameEnd = itemContext;
frameEnd = ownerContext.frameBorder[item.dock];
pos += frameEnd + ownerContext.framePadding[item.dock];
axis.end += frameEnd;
}
return pos;
},
/**
* Docks an item on a shrinkWrap axis at the "beginning". The "beginning" of the horizontal
* axis is "left" and the vertical is "top". For a shrinkWrap axis, the size works from
* the body outward to the outermost element (the panel).
*
* During the docking process, coordinates are allowed to be negative. We start with the
* body at (0,0) so items docked "top" or "left" will simply be assigned negative x/y. In
* the {@link #finishPositions} method these are corrected and framing is added. This way
* the correction is applied as a simple translation of delta x/y on all coordinates to
* bring the origin back to (0,0).
* @private
*/
dockOutwardBegin: function (ownerContext, itemContext, item, axis) {
var pos = axis.begin,
sizeProp = axis.sizeProp,
size;
if (axis.collapsed) {
axis.ignoreFrameBegin = axis.ignoreFrameEnd = itemContext;
} else if (item.ignoreParentFrame) {
axis.ignoreFrameBegin = itemContext;
}
// NOTE - When shrinkWrapping an ignoreParentFrame, this must be the last item
// on the axis. Since that is so, we let finishAxis take this in to account.
if (!item.overlay) {
size = itemContext.getProp(sizeProp) + itemContext.marginInfo[sizeProp];
pos -= size;
axis.begin = pos;
}
return pos;
},
/**
* Docks an item on a shrinkWrap axis at the "end". The "end" of the horizontal axis is
* "right" and the vertical is "bottom".
* @private
*/
dockOutwardEnd: function (ownerContext, itemContext, item, axis) {
var pos = axis.end,
sizeProp = axis.sizeProp,
size;
size = itemContext.getProp(sizeProp) + itemContext.marginInfo[sizeProp];
if (axis.collapsed) {
axis.ignoreFrameBegin = axis.ignoreFrameEnd = itemContext;
} else if (item.ignoreParentFrame) {
axis.ignoreFrameEnd = itemContext;
}
// NOTE - When shrinkWrapping an ignoreParentFrame, this must be the last item
// on the axis. Since that is so, we let finishAxis take this in to account.
if (!item.overlay) {
axis.end = pos + size;
axis.dockedPixelsEnd += size;
}
return pos;
},
/**
* Docks an item that might stretch across an axis. This is done for dock "top" and
* "bottom" items on the horizontal axis and dock "left" and "right" on the vertical.
* @private
*/
dockStretch: function (ownerContext, itemContext, item, axis) {
var dock = item.dock, // left/top/right/bottom (also used to index padding/border)
sizeProp = axis.sizeProp, // 'width' or 'height'
horizontal = dock === 'top' || dock === 'bottom',
border = ownerContext.frameBorder,
offsets = itemContext.offsets,
padding = ownerContext.framePadding,
endProp = horizontal ? 'right' : 'bottom',
startProp = horizontal ? 'left' : 'top',
pos = axis.begin + offsets[startProp],
margin, size;
if (item.stretch !== false) {
size = axis.end - pos - offsets[endProp];
if (item.ignoreParentFrame) {
// In CSS3, the border and padding need to be ignored specifically. In
// non-CSS3 / framing mode, the border and padding will be 0 **but** the
// header is not rendered inside the framing elements and so we do not
// want to do anything anyway!
pos -= padding[startProp] + border[startProp];
size += padding[sizeProp] + border[sizeProp];
}
margin = itemContext.marginInfo;
size -= margin[sizeProp];
itemContext[axis.setSize](size);
}
return pos;
},
/**
* Finishes the calculation of an axis by determining its size. In non-shrink-wrap
* cases, this is also where we set the body size.
* @private
*/
finishAxis: function (ownerContext, axis) {
// If the maxChildSize is NaN it means at some point we tried to determine
// The size of a docked item but we couldn't, so just jump out straight
// away before doing any other processing
if (isNaN(axis.maxChildSize)) {
return false;
}
var axisBegin = axis.begin,
size = axis.end - axisBegin,
collapsed = axis.collapsed,
setSizeMethod = axis.setSize,
beginName = axis.dockBegin, // left or top
endName = axis.dockEnd, // right or bottom
padding = ownerContext.framePadding,
border = ownerContext.frameBorder,
borderBegin = border[beginName],
framing = ownerContext.framing,
framingBegin = framing && framing[beginName],
// The padding is in play unless the axis is collapsed.
paddingBegin = collapsed ? 0 : padding[beginName],
sizeProp = axis.sizeProp,
ignoreFrameBegin = axis.ignoreFrameBegin,
ignoreFrameEnd = axis.ignoreFrameEnd,
bodyContext = ownerContext.bodyContext,
extraPaddingBegin = Math.max(borderBegin + paddingBegin - framingBegin, 0),
bodyPos, bodySize, delta, dirty;
if (axis.shrinkWrap) {
// Since items docked left/top on a shrinkWrap axis go into negative coordinates,
// we apply a delta to all coordinates to adjust their relative origin back to
// a (0,0) inside the border.
bodySize = axis.initialSize;
if (framing) {
// In CSS3 mode, things are compartively simple because "framing" is just
// borders and padding. In non-CSS3 mode, however, the framing elements
// are given a size equal to the max of the border-width and border-radius
// and this pushes the body down accordingly. Further, the dockedItems are
// all rendered outside the framing elements, so their origin equals the
// ideal box origin. To translate this to match CSS3, we have to add on
// the border-top.
delta = -axisBegin + borderBegin + paddingBegin;
bodyPos = delta - framingBegin - extraPaddingBegin;
} else {
bodyPos = -axisBegin;
delta = bodyPos + paddingBegin;
}
if (!collapsed) {
size += padding[sizeProp];
}
if (ignoreFrameBegin) {
// When some component ignores the begin framing, we move everything "up"
// by that amount of framing. We also do not include that amount of the
// framing in the shrinkWrap size.
delta -= borderBegin;
bodyPos -= borderBegin;
// The item ignoring the framing must also escape the padding. Since the
// axis.delta includes the padding and we want to apply this to only the
// one item, we just poke its dockedAt.x/y property so that when we add
// axis.begin the padding will cancel out. (Note: when we are collapsed
// paddingBegin will be 0).
ignoreFrameBegin.dockedAt[axis.posProp] -= paddingBegin;
} else {
size += borderBegin;
}
if (collapsed) {
// in this case "ignoreFrameBegin === ignoreFrameEnd" so we can take the
// special cases out of the mix here...
} // jshint ignore:line
else if (ignoreFrameEnd) {
// When a component ignores the end framing, we simply move it further
// "down" by the end padding and we do not add the end framing to the
// shrinkWrap size.
ignoreFrameEnd.dockedAt[axis.posProp] += padding[endName];
} else {
size += border[endName];
}
axis.size = size; // we have to wait for min/maxWidth/Height processing
if (!axis.horizontal && !this.owner.manageHeight) {
// the height of the bodyEl will give the proper height to the outerEl so
// we don't need to set heights in the DOM
dirty = false;
}
} else {
// For a fixed-size axis, we started at the outer box and already have the
// proper origin... almost... except for the owner's border.
if (framing) {
// since dockedItems are rendered outside the framing, they have the
// proper origin already:
delta = 0;
bodyPos = axisBegin - framingBegin - extraPaddingBegin;
} else {
delta = -borderBegin;
bodyPos = axisBegin - paddingBegin - borderBegin;
}
// Body size is remaining space between ends of Axis.
bodySize = size;
}
axis.delta = delta;
bodyContext[setSizeMethod](bodySize, dirty);
bodyContext.setProp(axis.bodyPosProp, bodyPos);
return !isNaN(size);
},
beforeInvalidateShrinkWrapDock: function(itemContext, options){
var sizeModelName = options.axis.sizeModelName;
if (!itemContext[sizeModelName].constrainedMin) {
// if the child hit a min constraint, it needs to be at its configured size, so
// we leave the sizeModel alone
itemContext[sizeModelName] = Ext.layout.SizeModel.calculated;
}
},
afterInvalidateShrinkWrapDock: function(itemContext, options){
var axis = options.axis,
me = options.layout,
pos;
if (itemContext[axis.sizeModelName].calculated) {
pos = me.dockStretch(options.ownerContext, itemContext, itemContext.target, axis);
itemContext.setProp(axis.posProp, axis.delta + pos);
}
},
/**
* Finishes processing of each axis by applying the min/max size constraints.
* @private
*/
finishConstraints: function (ownerContext, horz, vert) {
var me = this,
sizeModels = me.sizeModels,
publishWidth = horz.shrinkWrap,
publishHeight = vert.shrinkWrap,
owner = me.owner,
dirty, height, width, heightModel, widthModel, size,
minSize, maxSize, maxChildSize, desiredSize;
// In these calculations, maxChildSize will only be > 0 in the scenario where
// we are dock shrink wrapping in that direction, otherwise it is not measured.
// As such, the additions are done to simplify the logic, even though in most
// cases, it will have no impact on the overall result.
if (publishWidth) {
size = horz.size;
minSize = horz.collapsed ? 0 : horz.minSize;
maxSize = horz.maxSize;
maxChildSize = horz.maxChildSize;
desiredSize = Math.max(size, maxChildSize);
if (desiredSize > maxSize) {
widthModel = sizeModels.constrainedMax;
width = maxSize;
} else if (desiredSize < minSize) {
widthModel = sizeModels.constrainedMin;
width = minSize;
} else if (size < maxChildSize) {
widthModel = sizeModels.constrainedDock;
owner.dockConstrainedWidth = width = maxChildSize;
} else {
width = size;
}
}
if (publishHeight) {
size = vert.size;
minSize = vert.collapsed ? 0 : vert.minSize;
maxSize = vert.maxSize;
maxChildSize = vert.maxChildSize;
// For vertical docks, their weighting means the height is affected by top/bottom
// docked items, so we need to subtract them here
desiredSize = Math.max(size, maxChildSize + size - vert.initialSize);
if (desiredSize > maxSize) {
heightModel = sizeModels.constrainedMax;
height = maxSize;
} else if (desiredSize < minSize) {
heightModel = sizeModels.constrainedMin;
height = minSize;
} else if (size < maxChildSize) {
heightModel = sizeModels.constrainedDock;
owner.dockConstrainedHeight = height = maxChildSize;
} else {
if (!ownerContext.collapsedVert && !owner.manageHeight) {
// height of the outerEl is provided by the height (including margins)
// of the bodyEl, so this value does not need to be written to the DOM
dirty = false;
// so long as we set top and bottom margins on the bodyEl!
ownerContext.bodyContext.setProp('margin-bottom', vert.dockedPixelsEnd);
}
height = size;
}
}
// Handle the constraints...
if (widthModel || heightModel) {
// See ContextItem#init for an analysis of why this case is special. Basically,
// in this case, we only know the width and the height could be anything.
if (widthModel && heightModel &&
widthModel.constrainedMax && heightModel.constrainedByMin) {
ownerContext.invalidate({ widthModel: widthModel });
return false;
}
// To process a width or height other than that to which we have shrinkWrapped,
// we need to invalidate our component and carry forward w/these constrains...
// unless the ownerLayout wants these results and will invalidate us anyway.
if (!ownerContext.widthModel.calculatedFromShrinkWrap &&
!ownerContext.heightModel.calculatedFromShrinkWrap) {
// nope, just us to handle the constraint...
ownerContext.invalidate({ widthModel: widthModel, heightModel: heightModel });
return false;
}
// We have a constraint to deal with, so we just adjust the size models and
// allow the ownerLayout to invalidate us with its contribution to our final
// size...
} else {
// We're not invalidating, the ownerContext, so if we're shrink wrapping we'll need to
// tell any docked items to invalidate themselves if necessary.'
me.invalidateAxes(ownerContext, horz, vert);
}
// we only publish the sizes if we are not invalidating the result...
if (publishWidth) {
ownerContext.setWidth(width);
if (widthModel) {
ownerContext.widthModel = widthModel; // important to the ownerLayout
}
}
if (publishHeight) {
ownerContext.setHeight(height, dirty);
if (heightModel) {
ownerContext.heightModel = heightModel; // important to the ownerLayout
}
}
return true;
},
/**
*
* The default weighting of docked items produces this arrangement:
*
* +--------------------------------------------+
* | Top 1 |
* +--------------------------------------------+
* | Top 2 |
* +-----+-----+--------------------+-----+-----+
* | | | | | |
* | | | | | |
* | | | | R | R |
* | L | L | | I | I |
* | E | E | | G | G |
* | F | F | | H | H |
* | T | T | | T | T |
* | | | | | |
* | 2 | 1 | | 1 | 2 |
* | | | | | |
* | | | | | |
* +-----+-----+--------------------+-----+-----+
* | Bottom 1 |
* +--------------------------------------------+
* | Bottom 2 |
* +--------------------------------------------+
*
* So when we are shrinkWrapDock on the horizontal, the stretch size for top/bottom
* docked items is the final axis size. For the vertical axis, however, the stretch
*
*/
invalidateAxes: function(ownerContext, horz, vert){
var before = this.beforeInvalidateShrinkWrapDock,
after = this.afterInvalidateShrinkWrapDock,
horzSize = horz.end - horz.begin,
vertSize = vert.initialSize,
invalidateHorz = horz.shrinkWrapDock && horz.maxChildSize <= horzSize,
invalidateVert = vert.shrinkWrapDock && vert.maxChildSize <= vertSize,
dockedItems, len, i, itemContext, itemSize, isHorz, axis, sizeProp;
if (invalidateHorz || invalidateVert) {
if (invalidateVert) {
// For vertical, we need to reset the initial position because they are affected
// by the horizontally docked items
vert.begin = vert.initialBegin;
vert.end = vert.begin + vert.initialSize;
}
dockedItems = ownerContext.dockedItems;
for (i = 0, len = dockedItems.length; i < len; ++i) {
itemContext = dockedItems[i];
isHorz = itemContext.horizontal;
axis = null;
if (invalidateHorz && isHorz) {
sizeProp = horz.sizeProp;
itemSize = horzSize;
axis = horz;
} else if (invalidateVert && !isHorz) {
sizeProp = vert.sizeProp;
itemSize = vertSize;
axis = vert;
}
if (axis) {
// subtract any margins
itemSize -= itemContext.getMarginInfo()[sizeProp];
if (itemSize !== itemContext.props[sizeProp]) {
itemContext.invalidate({
before: before,
after: after,
axis: axis,
ownerContext: ownerContext,
layout: this
});
}
}
}
}
},
/**
* Finishes the calculation by setting positions on the body and all of the items.
* @private
*/
finishPositions: function (ownerContext, horz, vert) {
var dockedItems = ownerContext.dockedItems,
length = dockedItems.length,
deltaX = horz.delta,
deltaY = vert.delta,
index, itemContext;
for (index = 0; index < length; ++index) {
itemContext = dockedItems[index];
itemContext.setProp('x', deltaX + itemContext.dockedAt.x);
itemContext.setProp('y', deltaY + itemContext.dockedAt.y);
}
},
finishedLayout: function(ownerContext) {
var me = this,
target = ownerContext.target;
me.callParent(arguments);
if (!ownerContext.animatePolicy) {
if (ownerContext.isCollapsingOrExpanding === 1) {
target.afterCollapse(false);
} else if (ownerContext.isCollapsingOrExpanding === 2) {
target.afterExpand(false);
}
}
},
getAnimatePolicy: function(ownerContext) {
var me = this,
lastCollapsedState, policy;
if (ownerContext.isCollapsingOrExpanding === 1) {
lastCollapsedState = me.lastCollapsedState;
} else if (ownerContext.isCollapsingOrExpanding === 2) {
lastCollapsedState = ownerContext.lastCollapsedState;
}
if (lastCollapsedState === 'left' || lastCollapsedState === 'right') {
policy = me.horizontalCollapsePolicy;
} else if (lastCollapsedState === 'top' || lastCollapsedState === 'bottom') {
policy = me.verticalCollapsePolicy;
}
return policy;
},
/**
* Retrieve an ordered and/or filtered array of all docked Components.
* @param {String} [order='render'] The desired ordering of the items ('render' or 'visual').
* @param {Boolean} [beforeBody] An optional flag to limit the set of items to only those
* before the body (true) or after the body (false). All components are returned by
* default.
* @return {Ext.Component[]} An array of components.
* @protected
*/
getDockedItems: function(order, beforeBody) {
var me = this,
renderedOnly = (order === 'visual'),
all = renderedOnly ? Ext.ComponentQuery.query('[rendered]', me.owner.dockedItems.items) : me.owner.dockedItems.items,
sort = all && all.length && order !== false,
renderOrder,
dock, dockedItems, i, isBefore, length;
if (beforeBody == null) {
dockedItems = sort && !renderedOnly ? all.slice() : all;
} else {
dockedItems = [];
for (i = 0, length = all.length; i < length; ++i) {
dock = all[i].dock;
isBefore = (dock === 'top' || dock === 'left');
if (beforeBody ? isBefore : !isBefore) {
dockedItems.push(all[i]);
}
}
sort = sort && dockedItems.length;
}
if (sort) {
renderOrder = (order = order || 'render') === 'render';
Ext.Array.sort(dockedItems, function(a, b) {
var aw,
bw;
// If the two items are on opposite sides of the body, they must not be sorted by any weight value:
// For rendering purposes, left/top *always* sorts before right/bottom
if (renderOrder && ((aw = me.owner.dockOrder[a.dock]) !== (bw = me.owner.dockOrder[b.dock]))) {
// The two dockOrder values cancel out when two items are on opposite sides.
if (!(aw + bw)) { // jshint ignore:line
return aw - bw;
}
}
aw = me.getItemWeight(a, order);
bw = me.getItemWeight(b, order);
if ((aw !== undefined) && (bw !== undefined)) {
return aw - bw;
}
return 0;
});
}
return dockedItems || [];
},
getItemWeight: function (item, order) {
var weight = item.weight || this.owner.defaultDockWeights[item.dock];
return weight[order] || weight;
},
/**
* @protected
* Returns an array containing all the **visible** docked items inside this layout's owner Panel
* @return {Array} An array containing all the **visible** docked items of the Panel
*/
getLayoutItems : function() {
var me = this,
items,
itemCount,
item,
i,
result;
if (me.owner.collapsed) {
result = me.owner.getCollapsedDockedItems();
} else {
items = me.getDockedItems('visual');
itemCount = items.length;
result = [];
for (i = 0; i < itemCount; i++) {
item = items[i];
if (!item.hidden) {
result.push(item);
}
}
}
return result;
},
// Content size includes padding but not borders, so subtract them off
measureContentWidth: function (ownerContext) {
var bodyContext = ownerContext.bodyContext;
return bodyContext.el.getWidth() - bodyContext.getBorderInfo().width;
},
measureContentHeight: function (ownerContext) {
var bodyContext = ownerContext.bodyContext;
return bodyContext.el.getHeight() - bodyContext.getBorderInfo().height;
},
redoLayout: function(ownerContext) {
var me = this,
owner = me.owner;
// If we are collapsing...
if (ownerContext.isCollapsingOrExpanding === 1) {
if (owner.reExpander) {
owner.reExpander.el.show();
}
// Add the collapsed class now, so that collapsed CSS rules are applied before measurements are taken by the layout.
owner.addClsWithUI(owner.collapsedCls);
ownerContext.redo(true);
} else if (ownerContext.isCollapsingOrExpanding === 2) {
// Remove the collapsed class now, before layout calculations are done.
owner.removeClsWithUI(owner.collapsedCls);
ownerContext.bodyContext.redo();
}
},
// @private override inherited.
// We need to render in the correct order, top/left before bottom/right
renderChildren: function() {
var me = this,
items = me.getDockedItems(),
target = me.getRenderTarget();
me.handleItemBorders();
me.renderItems(items, target);
},
/**
* @protected
* Render the top and left docked items before any existing DOM nodes in our render target,
* and then render the right and bottom docked items after. This is important, for such things
* as tab stops and ARIA readers, that the DOM nodes are in a meaningful order.
* Our collection of docked items will already be ordered via Panel.getDockedItems().
*/
renderItems: function(items, target) {
var me = this,
dockedItemCount = items.length,
itemIndex = 0,
correctPosition = 0,
staticNodeCount = 0,
targetNodes = me.getRenderTarget().dom.childNodes,
targetChildCount = targetNodes.length,
i, j, targetChildNode, item;
// Calculate the number of DOM nodes in our target that are not our docked items
for (i = 0, j = 0; i < targetChildCount; i++) {
targetChildNode = targetNodes[i];
if (targetChildNode.nodeType === 1 && Ext.fly(targetChildNode).hasCls(Ext.baseCSSPrefix + 'resizable-handle')) {
break;
}
for (j = 0; j < dockedItemCount; j++) {
item = items[j];
if (item.rendered && item.el.dom === targetChildNode) {
break;
}
}
// Walked off the end of the docked items without matching the found child node;
// Then it's a static node.
if (j === dockedItemCount) {
staticNodeCount++;
}
}
// Now we go through our docked items and render/move them
for (; itemIndex < dockedItemCount; itemIndex++, correctPosition++) {
item = items[itemIndex];
// If we're now at the first right/bottom docked item, we jump over the body element.
//
// TODO: This is affected if users provide custom weight values to their
// docked items, which puts it out of (t,l,r,b) order. Avoiding a second
// sort operation here, for now, in the name of performance. getDockedItems()
// needs the sort operation not just for this layout-time rendering, but
// also for getRefItems() to return a logical ordering (FocusManager, CQ, et al).
if (itemIndex === correctPosition && (item.dock === 'right' || item.dock === 'bottom')) {
correctPosition += staticNodeCount;
}
// Same logic as Layout.renderItems()
if (item && !item.rendered) {
me.renderItem(item, target, correctPosition);
}
else if (!me.isValidParent(item, target, correctPosition)) {
me.moveItem(item, target, correctPosition);
}
}
},
undoLayout: function(ownerContext) {
var me = this,
owner = me.owner;
// If we are collapsing...
if (ownerContext.isCollapsingOrExpanding === 1) {
// We do not want to see the re-expander header until the final collapse is complete
if (owner.reExpander) {
owner.reExpander.el.hide();
}
// Add the collapsed class now, so that collapsed CSS rules are applied before measurements are taken by the layout.
owner.removeClsWithUI(owner.collapsedCls);
ownerContext.undo(true);
} else if (ownerContext.isCollapsingOrExpanding === 2) {
// Remove the collapsed class now, before layout calculations are done.
owner.addClsWithUI(owner.collapsedCls);
ownerContext.bodyContext.undo();
}
},
sizePolicy: {
nostretch: {
setsWidth: 0,
setsHeight: 0
},
horz: { // item goes horizontally (top or bottom docked)
shrinkWrap: {
// This is how we manage the width of a top/bottom docked item when its
// shrinkWrapWidth and ours need to be maxed (calculatedFromShrinkWrap)
setsWidth: 1,
setsHeight: 0,
readsWidth: 1
},
stretch: {
setsWidth: 1,
setsHeight: 0
}
},
vert: { // item goes vertically (left or right docked)
shrinkWrap: {
setsWidth: 0,
setsHeight: 1,
readsHeight: 1
},
stretch: {
setsWidth: 0,
setsHeight: 1
}
},
stretchV: {
setsWidth: 0,
setsHeight: 1
},
// Circular dependency with partial auto-sized panels:
//
// If we have an autoHeight docked item being stretched horizontally (top/bottom),
// that stretching will determine its width and its width must be set before its
// autoHeight can be determined. If that item is docked in an autoWidth panel, the
// body will need its height set before it can determine its width, but the height
// of the docked item is needed to subtract from the panel height in order to set
// the body height.
//
// This same pattern occurs with autoHeight panels with autoWidth docked items on
// left or right. If the panel is fully auto or fully fixed, these problems don't
// come up because there is no dependency between the dimensions.
//
// Cutting the Gordian Knot: In these cases, we have to allow something to measure
// itself without full context. This is OK as long as the managed dimension doesn't
// effect the auto-dimension, which is often the case for things like toolbars. The
// managed dimension only effects overflow handlers and such and does not change the
// auto-dimension. To encourage the item to measure itself without waiting for the
// managed dimension, we have to tell it that the layout will also be reading that
// dimension. This is similar to how stretchmax works.
autoStretchH: {
readsWidth: 1,
setsWidth: 1,
setsHeight: 0
},
autoStretchV: {
readsHeight: 1,
setsWidth: 0,
setsHeight: 1
}
},
getItemSizePolicy: function (item, ownerSizeModel) {
var me = this,
policy = me.sizePolicy,
shrinkWrapDock = me.owner.shrinkWrapDock,
dock, vertical;
if (item.stretch === false) {
return policy.nostretch;
}
dock = item.dock;
vertical = (dock === 'left' || dock === 'right');
shrinkWrapDock = shrinkWrapDock === true ? 3 : (shrinkWrapDock || 0);
if (vertical) {
policy = policy.vert;
shrinkWrapDock = shrinkWrapDock & 1; // jshint ignore:line
} else {
policy = policy.horz;
shrinkWrapDock = shrinkWrapDock & 2; // jshint ignore:line
}
if (shrinkWrapDock) {
// Getting the size model is expensive, so only do so if we really need it
if (!ownerSizeModel) {
ownerSizeModel = me.owner.getSizeModel();
}
if (ownerSizeModel[vertical ? 'height' : 'width'].shrinkWrap) {
return policy.shrinkWrap;
}
}
return policy.stretch;
},
/**
* @protected
* We are overriding the Ext.layout.Layout configureItem method to also add a class that
* indicates the position of the docked item. We use the itemCls (x-docked) as a prefix.
* An example of a class added to a dock: right item is x-docked-right
* @param {Ext.Component} item The item we are configuring
*/
configureItem : function(item, pos) {
this.callParent(arguments);
item.addCls(this._itemCls);
if (!item.ignoreBorderManagement) {
item.addClsWithUI(this.getDockCls(item.dock));
}
},
/**
* Get's the css class name for a given dock position.
* @param {String} dock `top`, `right`, `bottom`, or `left`
* @return {String}
* @private
*/
getDockCls: function(dock) {
return 'docked-' + dock;
},
afterRemove: function(item) {
var dom;
this.callParent(arguments);
item.removeCls(this._itemCls);
if (!item.ignoreBorderManagement) {
item.removeClsWithUI(this.getDockCls(item.dock));
}
dom = item.el.dom;
if (!item.destroying && dom) {
dom.parentNode.removeChild(dom);
}
this.childrenChanged = true;
},
/**
* This object is indexed by a component's `baseCls` to yield another object which
* is then indexed by the component's `ui` to produce an array of CSS class names.
* This array is indexed in the same manner as the `noBorderClassTable` and indicates
* the a particular edge of a docked item or the body element is actually "collapsed"
* with the component's outer border.
* @private
*/
borderCollapseMap: {
/*
'x-panel': {
'default': []
}
*/
},
/**
* Returns the array of class names to add to a docked item or body element when for
* the edges that should collapse with the outer component border. Basically, the
* panel's outer border must look visually like a contiguous border but may need to
* be realized by using the border of docked items and/or the body. This class name
* allows the border color and width to be controlled accordingly and distinctly from
* the border of the docked item or body element when it is not having its border
* collapsed.
* @private
*/
getBorderCollapseTable: function () {
var me = this,
map = me.borderCollapseMap,
owner = me.owner,
baseCls = owner.baseCls,
ui = owner.ui,
table;
map = map[baseCls] || (map[baseCls] = {});
table = map[ui];
if (!table) {
baseCls += '-' + ui + '-outer-border-';
map[ui] = table = [
0, // TRBL
baseCls + 'l', // 0001 = 1
baseCls + 'b', // 0010 = 2
baseCls + 'bl', // 0011 = 3
baseCls + 'r', // 0100 = 4
baseCls + 'rl', // 0101 = 5
baseCls + 'rb', // 0110 = 6
baseCls + 'rbl', // 0111 = 7
baseCls + 't', // 1000 = 8
baseCls + 'tl', // 1001 = 9
baseCls + 'tb', // 1010 = 10
baseCls + 'tbl', // 1011 = 11
baseCls + 'tr', // 1100 = 12
baseCls + 'trl', // 1101 = 13
baseCls + 'trb', // 1110 = 14
baseCls + 'trbl' // 1111 = 15
];
}
return table;
}
});