(function(clsPrefix) {
/**
* The Default Layout is the layout that all other layouts inherit from. The main capability it provides is docking,
* which means that every other layout can also provide docking support. It's unusual to use Default layout directly,
* instead it's much more common to use one of the sub classes:
*
* * {@link Ext.layout.HBox hbox layout}
* * {@link Ext.layout.VBox vbox layout}
* * {@link Ext.layout.Card card layout}
* * {@link Ext.layout.Fit fit layout}
*
* For a full overview of layouts check out the [Layout Guide](#!/guide/layouts).
*
* ## Docking
*
* Docking enables you to place additional Components at the top, right, bottom or left edges of the parent Container,
* resizing the other items as necessary. For example, let's say we're using an {@link Ext.layout.HBox hbox layout}
* with a couple of items and we want to add a banner to the top so that we end up with something like this:
*
* {@img ../guides/layouts/docktop.jpg}
*
* This is simple to achieve with the `docked: 'top'` configuration below. We can dock as many of the items as we like,
* to either the top, right, bottom or left edges of the Container:
*
* Ext.create('Ext.Container', {
* fullscreen: true,
* layout: 'hbox',
* items: [
* {
* docked: 'top',
* height: 20,
* html: 'This is docked to the top'
* },
* {
* html: 'message list',
* flex: 1
* },
* {
* html: 'message preview',
* flex: 2
* }
* ]
* });
*
* Similarly, to dock something to the left of a layout (a {@link Ext.layout.VBox vbox} in this case), such as the
* following:
*
* {@img ../guides/layouts/dockleft.jpg}
*
* We can simply dock to the left:
*
* Ext.create('Ext.Container', {
* fullscreen: true,
* layout: 'vbox',
* items: [
* {
* docked: 'left',
* width: 100,
* html: 'This is docked to the left'
* },
* {
* html: 'message list',
* flex: 1
* },
* {
* html: 'message preview',
* flex: 2
* }
* ]
* });
*
* We can also dock to the bottom and right and use other layouts than hbox and vbox ({@link Ext.layout.Card card} and
* {@link Ext.layout.Fit fit} layouts both accept docking too).
*/
Ext.define('Ext.layout.Default', {
extend: 'Ext.Evented',
alternateClassName: ['Ext.layout.AutoContainerLayout', 'Ext.layout.ContainerLayout'],
alias: ['layout.auto', 'layout.default'],
isLayout: true,
hasDockedItemsCls: clsPrefix + 'hasdocked',
centeredItemCls: clsPrefix + 'centered',
floatingItemCls: clsPrefix + 'floating',
dockingWrapperCls: clsPrefix + 'docking',
dockingInnerCls: clsPrefix + 'docking-inner',
maskCls: clsPrefix + 'mask',
positionMap: {
top: 'start',
left: 'start',
bottom: 'end',
right: 'end'
},
positionDirectionMap: {
top: 'vertical',
bottom: 'vertical',
left: 'horizontal',
right: 'horizontal'
},
DIRECTION_VERTICAL: 'vertical',
DIRECTION_HORIZONTAL: 'horizontal',
POSITION_START: 'start',
POSITION_END: 'end',
constructor: function(container, config) {
this.container = container;
this.innerItems = [];
this.centeringWrappers = {};
this.initConfig(config);
},
reapply: Ext.emptyFn,
unapply: Ext.emptyFn,
onItemAdd: function() {
this.doItemAdd.apply(this, arguments);
},
onItemRemove: function() {
this.doItemRemove.apply(this, arguments);
},
onItemMove: function() {
this.doItemMove.apply(this, arguments);
},
onItemCenteredChange: function() {
this.doItemCenteredChange.apply(this, arguments);
},
onItemFloatingChange: function() {
this.doItemFloatingChange.apply(this, arguments);
},
onItemDockedChange: function() {
this.doItemDockedChange.apply(this, arguments);
},
/**
* @private
*/
doItemAdd: function(item, index) {
var docked = item.getDocked();
if (docked !== null) {
this.dockItem(item, docked);
}
else if (item.isCentered()) {
this.centerItem(item, index);
}
else {
this.insertItem(item, index);
}
if (item.isFloating()) {
this.onItemFloatingChange(item, true);
}
},
/**
* @private
*/
doItemRemove: function(item) {
if (item.isDocked()) {
this.undockItem(item);
}
else if (item.isCentered()) {
this.uncenterItem(item);
}
Ext.Array.remove(this.innerItems, item);
this.container.innerElement.dom.removeChild(item.renderElement.dom);
},
/**
* @private
*/
doItemMove: function(item, toIndex, fromIndex) {
if (item.isCentered()) {
item.setZIndex((toIndex + 1) * 2);
}
else {
if (item.isFloating()) {
item.setZIndex((toIndex + 1) * 2);
}
this.insertItem(item, toIndex);
}
},
/**
* @private
*/
doItemCenteredChange: function(item, centered) {
if (centered) {
this.centerItem(item);
}
else {
this.uncenterItem(item);
}
},
/**
* @private
*/
doItemFloatingChange: function(item, floating) {
var element = item.element,
floatingItemCls = this.floatingItemCls;
if (floating) {
if (item.getZIndex() === null) {
item.setZIndex((this.container.indexOf(item) + 1) * 2);
}
element.addCls(floatingItemCls);
}
else {
item.setZIndex(null);
element.removeCls(floatingItemCls);
}
},
/**
* @private
*/
doItemDockedChange: function(item, docked, oldDocked) {
if (oldDocked) {
this.undockItem(item, oldDocked);
}
if (docked) {
this.dockItem(item, docked);
}
},
centerItem: function(item) {
this.insertItem(item, 0);
if (item.getZIndex() === null) {
item.setZIndex((this.container.indexOf(item) + 1) * 2);
}
this.createCenteringWrapper(item);
// Mainly for styling
item.element.addCls(this.floatingItemCls);
},
uncenterItem: function(item) {
this.destroyCenteringWrapper(item);
item.setZIndex(null);
this.insertItem(item, this.container.indexOf(item));
// Mainly for styling
item.element.removeCls(this.floatingItemCls);
},
dockItem: function(item, position) {
var container = this.container,
itemRenderElement = item.renderElement,
itemElement = item.element,
dockingInnerElement = this.dockingInnerElement;
if (!dockingInnerElement) {
container.setUseBodyElement(true);
this.dockingInnerElement = dockingInnerElement = container.bodyElement;
}
this.getDockingWrapper(position);
if (this.positionMap[position] === this.POSITION_START) {
itemRenderElement.insertBefore(dockingInnerElement);
}
else {
itemRenderElement.insertAfter(dockingInnerElement);
}
itemElement.addCls(clsPrefix + 'docked-' + position);
},
undockItem: function(item, docked) {
this.insertItem(item, this.container.indexOf(item));
item.element.removeCls(clsPrefix + 'docked-' + docked);
},
getDockingWrapper: function(position) {
var currentDockingDirection = this.currentDockingDirection,
direction = this.positionDirectionMap[position],
dockingWrapper = this.dockingWrapper;
if (currentDockingDirection !== direction) {
this.currentDockingDirection = direction;
this.dockingWrapper = dockingWrapper = this.createDockingWrapper(direction);
}
return dockingWrapper;
},
createDockingWrapper: function(direction) {
return this.dockingInnerElement.wrap({
classList: [this.dockingWrapperCls + '-' + direction]
}, true);
},
createCenteringWrapper: function(item) {
var id = item.getId(),
wrappers = this.centeringWrappers,
renderElement = item.renderElement,
wrapper;
wrappers[id] = wrapper = renderElement.wrap({
className: this.centeredItemCls
});
return wrapper;
},
destroyCenteringWrapper: function(item) {
var id = item.getId(),
wrappers = this.centeringWrappers,
renderElement = item.renderElement,
wrapper = wrappers[id];
renderElement.unwrap();
wrapper.destroy();
delete wrappers[id];
return this;
},
insertItem: function(item, index) {
var container = this.container,
items = container.getItems().items,
innerItems = this.innerItems,
containerDom = container.innerElement.dom,
itemDom = item.renderElement.dom,
relativeItem, relativeItemDom, domIndex;
if (container.has(item)) {
Ext.Array.remove(innerItems, item);
}
if (typeof index == 'number') {
// Retrieve the *logical* relativeItem reference to insertBefore
relativeItem = items[index];
// If it is the item itself, get the next sibling
if (relativeItem === item) {
relativeItem = items[++index];
}
// Continue finding the relativeItem that is neither currently centered nor docked
while (relativeItem && (relativeItem.isCentered() || relativeItem.isDocked())) {
relativeItem = items[++index];
}
if (relativeItem) {
// Retrieve the *physical* index of that relativeItem
domIndex = innerItems.indexOf(relativeItem);
if (domIndex !== -1) {
while (relativeItem && (relativeItem.isCentered() || relativeItem.isDocked())) {
relativeItem = innerItems[++domIndex];
}
if (relativeItem) {
innerItems.splice(domIndex, 0, item);
relativeItemDom = relativeItem.renderElement.dom;
containerDom.insertBefore(itemDom, relativeItemDom);
return this;
}
}
}
}
innerItems.push(item);
containerDom.appendChild(itemDom);
return this;
}
});
})(Ext.baseCSSPrefix);