-<!DOCTYPE html><html><head><title>Sencha Documentation Project</title><link rel="stylesheet" href="../reset.css" type="text/css"><link rel="stylesheet" href="../prettify.css" type="text/css"><link rel="stylesheet" href="../prettify_sa.css" type="text/css"><script type="text/javascript" src="../prettify.js"></script></head><body onload="prettyPrint()"><pre class="prettyprint"><pre><span id='Ext-layout.container.Border'>/**
-</span> * @class Ext.layout.container.Border
- * @extends Ext.layout.container.Container
- * <p>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.</p>
- * <p>This class is intended to be extended or created via the <code>layout:'border'</code>
- * {@link Ext.container.Container#layout} config, and should generally not need to be created directly
- * via the new keyword.</p>
- * {@img Ext.layout.container.Border/Ext.layout.container.Border.png Ext.layout.container.Border container layout}
- * <p>Example usage:</p>
- * <pre><code>
- Ext.create('Ext.panel.Panel', {
- width: 500,
- height: 400,
- title: 'Border Layout',
- layout: 'border',
- items: [{
- title: 'South Region is resizable',
- region: 'south', // position for region
- xtype: 'panel',
- height: 100,
- split: true, // enable resizing
- margins: '0 5 5 5'
- },{
- // xtype: 'panel' implied by default
- title: 'West Region is collapsible',
- region:'west',
- xtype: 'panel',
- margins: '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',
- margins: '5 5 0 0'
- }],
- renderTo: Ext.getBody()
- });
-</code></pre>
- * <p><b><u>Notes</u></b>:</p><div class="mdetail-params"><ul>
- * <li>Any Container using the Border layout <b>must</b> have a child item with <code>region:'center'</code>.
- * 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.</li>
- * <li>Any child items with a region of <code>west</code> or <code>east</code> may be configured with either
- * an initial <code>width</code>, or a {@link Ext.layout.container.Box#flex} value, or an initial percentage width <b>string</b> (Which is simply divided by 100 and used as a flex value). The 'center' region has a flex value of <code>1</code>.</li>
- * <li>Any child items with a region of <code>north</code> or <code>south</code> may be configured with either
- * an initial <code>height</code>, or a {@link Ext.layout.container.Box#flex} value, or an initial percentage height <b>string</b> (Which is simply divided by 100 and used as a flex value). The 'center' region has a flex value of <code>1</code>.</li>
- * <li>The regions of a BorderLayout are <b>fixed at render time</b> and thereafter, its child Components may not be removed or added</b>.To add/remove
- * Components within a BorderLayout, have them wrapped by an additional Container which is directly
- * managed by the BorderLayout. If the region is to be collapsible, the Container used directly
- * by the BorderLayout manager should be a Panel. In the following example a Container (an Ext.panel.Panel)
- * is added to the west region:<pre><code>
-wrc = {@link Ext#getCmp Ext.getCmp}('west-region-container');
-wrc.{@link Ext.container.Container#removeAll removeAll}();
-wrc.{@link Ext.container.Container#add add}({
- title: 'Added Panel',
- html: 'Some content'
-});
- * </code></pre>
- * </li>
- * <li><b>There is no BorderLayout.Region class in ExtJS 4.0+</b></li>
- * </ul></div>
+<!DOCTYPE html>
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+ <title>The source code</title>
+ <link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />
+ <script type="text/javascript" src="../resources/prettify/prettify.js"></script>
+ <style type="text/css">
+ .highlight { display: block; background-color: #ddd; }
+ </style>
+ <script type="text/javascript">
+ function highlight() {
+ document.getElementById(location.hash.replace(/#/, "")).className = "highlight";
+ }
+ </script>
+</head>
+<body onload="prettyPrint(); highlight();">
+ <pre class="prettyprint lang-js"><span id='Ext-layout-container-Border'>/**
+</span> * 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: 400,
+ * title: 'Border Layout',
+ * layout: 'border',
+ * items: [{
+ * title: 'South Region is resizable',
+ * region: 'south', // position for region
+ * xtype: 'panel',
+ * height: 100,
+ * split: true, // enable resizing
+ * margins: '0 5 5 5'
+ * },{
+ * // xtype: 'panel' implied by default
+ * title: 'West Region is collapsible',
+ * region:'west',
+ * xtype: 'panel',
+ * margins: '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',
+ * margins: '5 5 0 0'
+ * }],
+ * renderTo: Ext.getBody()
+ * });
+ *
+ * # Notes
+ *
+ * - 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`.
+ *
+ * - The regions of a BorderLayout are **fixed at render time** and thereafter, its child
+ * Components may not be removed or added**. To add/remove Components within a BorderLayout,
+ * have them wrapped by an additional Container which is directly managed by the BorderLayout.
+ * If the region is to be collapsible, the Container used directly by the BorderLayout manager
+ * should be a Panel. In the following example a Container (an Ext.panel.Panel) is added to
+ * the west region:
+ *
+ * wrc = {@link Ext#getCmp Ext.getCmp}('west-region-container');
+ * wrc.{@link Ext.container.Container#removeAll removeAll}();
+ * wrc.{@link Ext.container.Container#add add}({
+ * title: 'Added Panel',
+ * html: 'Some content'
+ * });
+ *
+ * - **There is no BorderLayout.Region class in ExtJS 4.0+**
*/
Ext.define('Ext.layout.container.Border', {
bindToOwnerCtContainer: true,
- fixedLayout: false,
-
percentageRe: /(\d+)%/,
slideDirection: {
}
// Delegate this operation to the shadow "V" or "H" box layout, and then down to any embedded layout.
+ me.fixHeightConstraints();
me.shadowLayout.onLayout();
if (me.embeddedContainer) {
me.embeddedContainer.layout.onLayout();
// Delegate this operation to the shadow "V" or "H" box layout.
this.shadowLayout.beforeLayout();
+
+ // note: don't call base because that does a renderItems again
},
renderItems: function(items, target) {
//</debug>
},
+ renderChildren: function() {
+ if (!this.borderLayoutInitialized) {
+ this.initializeBorderLayout();
+ }
+
+ this.shadowLayout.renderChildren();
+ },
+
+ /*
+ * Gathers items for a layout operation. Injected into child Box layouts through configuration.
+ * We must not include child items which are floated over the layout (are primed with a slide out animation)
+ */
+ getVisibleItems: function() {
+ return Ext.ComponentQuery.query(':not([slideOutAnim])', this.callParent(arguments));
+ },
+
initializeBorderLayout: function() {
var me = this,
i = 0,
// This layout intercepts any initial collapsed state. Panel must not do this itself.
comp.borderCollapse = comp.collapsed;
- delete comp.collapsed;
+ comp.collapsed = false;
comp.on({
beforecollapse: me.onBeforeRegionCollapse,
maintainFlex: true,
layout: {
type: 'hbox',
- align: 'stretch'
+ align: 'stretch',
+ getVisibleItems: me.getVisibleItems
}
}));
hBoxItems.push(regions.center);
el: me.getTarget(),
layout: Ext.applyIf({
type: 'vbox',
- align: 'stretch'
+ align: 'stretch',
+ getVisibleItems: me.getVisibleItems
}, me.initialConfig)
});
me.createItems(me.shadowContainer, vBoxItems);
me.splitters.west.ownerCt = me.embeddedContainer;
}
+ // These spliiters need to be constrained by components one-level below
+ // the component in their vobx. We update the min/maxHeight on the helper
+ // (embeddedContainer) prior to starting the split/drag. This has to be
+ // done on-the-fly to allow min/maxHeight of the E/C/W regions to be set
+ // dynamically.
+ Ext.each([me.splitters.north, me.splitters.south], function (splitter) {
+ if (splitter) {
+ splitter.on('beforedragstart', me.fixHeightConstraints, me);
+ }
+ });
+
// The east or west region wanted a percentage
if (horizontalFlex) {
regions.center.flex -= horizontalFlex;
me.borderLayoutInitialized = true;
},
-
setupState: function(comp){
var getState = comp.getState;
comp.getState = function(){
comp.addStateEvents(['collapse', 'expand', 'resize']);
},
-<span id='Ext-layout.container.Border-method-createItems'> /**
+<span id='Ext-layout-container-Border-method-createItems'> /**
</span> * Create the items collection for our shadow/embedded containers
* @private
*/
// Mini collapse means that the splitter is the placeholder Component
if (comp.collapseMode == 'mini') {
comp.placeholder = resizer;
+ resizer.collapsedCls = comp.collapsedCls;
}
// Arrange to hide/show a region's associated splitter when the region is hidden/shown
return resizer;
},
+ // Private
+ // Propagates the min/maxHeight values from the inner hbox items to its container.
+ fixHeightConstraints: function () {
+ var me = this,
+ ct = me.embeddedContainer,
+ maxHeight = 1e99, minHeight = -1;
+
+ if (!ct) {
+ return;
+ }
+
+ ct.items.each(function (item) {
+ if (Ext.isNumber(item.maxHeight)) {
+ maxHeight = Math.max(maxHeight, item.maxHeight);
+ }
+ if (Ext.isNumber(item.minHeight)) {
+ minHeight = Math.max(minHeight, item.minHeight);
+ }
+ });
+
+ ct.maxHeight = maxHeight;
+ ct.minHeight = minHeight;
+ },
+
// Hide/show a region's associated splitter when the region is hidden/shown
onRegionVisibilityChange: function(comp){
this.splitters[comp.region][comp.hidden ? 'hide' : 'show']();
}
},
-<span id='Ext-layout.container.Border-method-getPlaceholder'> /**
-</span> * <p>Return the {@link Ext.panel.Panel#placeholder placeholder} Component to which the passed child Panel of the layout will collapse.
- * By default, this will be a {@link Ext.panel.Header Header} component (Docked to the appropriate border). See {@link Ext.panel.Panel#placeholder placeholder}.
- * config to customize this.</p>
- * <p><b>Note that this will be a fully instantiated Component, but will only be <i>rendered</i> when the Panel is first collapsed.</b></p>
- * @param {Panel} panel The child Panel of the layout for which to return the {@link Ext.panel.Panel#placeholder placeholder}.
- * @returns {Component} The Panel's {@link Ext.panel.Panel#placeholder placeholder} unless the {@link Ext.panel.Panel#collapseMode collapseMode} is
- * <code>'header'</code>, in which case <i>undefined</i> is returned.
+<span id='Ext-layout-container-Border-method-getPlaceholder'> /**
+</span> * Return the {@link Ext.panel.Panel#placeholder placeholder} Component to which the passed child Panel of the
+ * layout will collapse. By default, this will be a {@link Ext.panel.Header Header} component (Docked to the
+ * appropriate border). See {@link Ext.panel.Panel#placeholder placeholder}. config to customize this.
+ *
+ * **Note that this will be a fully instantiated Component, but will only be _rendered_ when the Panel is first
+ * collapsed.**
+ * @param {Ext.panel.Panel} panel The child Panel of the layout for which to return the {@link
+ * Ext.panel.Panel#placeholder placeholder}.
+ * @return {Ext.Component} The Panel's {@link Ext.panel.Panel#placeholder placeholder} unless the {@link
+ * Ext.panel.Panel#collapseMode collapseMode} is `'header'`, in which case _undefined_ is returned.
*/
getPlaceholder: function(comp) {
var me = this,
baseCls: comp.baseCls + '-header',
ui: comp.ui,
indicateDrag: comp.draggable,
- cls: Ext.baseCSSPrefix + 'region-collapsed-placeholder ' + Ext.baseCSSPrefix + 'region-collapsed-' + comp.collapseDirection + '-placeholder',
+ cls: Ext.baseCSSPrefix + 'region-collapsed-placeholder ' + Ext.baseCSSPrefix + 'region-collapsed-' + comp.collapseDirection + '-placeholder ' + comp.collapsedCls,
listeners: comp.floatable ? {
click: {
fn: function(e) {
if ((Ext.isIE6 || Ext.isIE7 || (Ext.isIEQuirks)) && !horiz) {
placeholder.width = 25;
}
- placeholder[horiz ? 'tools' : 'items'] = [{
- xtype: 'tool',
- client: comp,
- type: 'expand-' + oppositeDirection,
- handler: me.onPlaceHolderToolClick,
- scope: me
- }];
+ if (!comp.hideCollapseTool) {
+ placeholder[horiz ? 'tools' : 'items'] = [{
+ xtype: 'tool',
+ client: comp,
+ type: 'expand-' + oppositeDirection,
+ handler: me.onPlaceHolderToolClick,
+ scope: me
+ }];
+ }
}
placeholder = me.owner.createComponent(placeholder);
if (comp.isXType('panel')) {
return placeholder;
},
-<span id='Ext-layout.container.Border-method-onRegionTitleChange'> /**
+<span id='Ext-layout-container-Border-method-onRegionTitleChange'> /**
</span> * @private
* Update the placeholder title when panel title has been set or changed.
*/
comp.placeholder.setTitle(newTitle);
},
-<span id='Ext-layout.container.Border-method-onRegionIconChange'> /**
+<span id='Ext-layout-container-Border-method-onRegionIconChange'> /**
</span> * @private
* Update the placeholder iconCls when panel iconCls has been set or changed.
*/
comp.placeholder.setIconCls(newIconCls);
},
-<span id='Ext-layout.container.Border-method-calculateChildBox'> /**
+<span id='Ext-layout-container-Border-method-calculateChildBox'> /**
</span> * @private
* Calculates the size and positioning of the passed child item. Must be present because Panel's expand,
* when configured with a flex, calls this method on its ownerCt's layout.
- * @param {Component} child The child Component to calculate the box for
+ * @param {Ext.Component} child The child Component to calculate the box for
* @return {Object} Object containing box measurements for the child. Properties are left,top,width,height.
*/
calculateChildBox: function(comp) {
}
},
-<span id='Ext-layout.container.Border-method-onBeforeRegionCollapse'> /**
+<span id='Ext-layout-container-Border-method-onBeforeRegionCollapse'> /**
</span> * @private
* Intercepts the Panel's own collapse event and perform's substitution of the Panel
* with a placeholder Header orientated in the appropriate dimension.
* @returns {Boolean} false to inhibit the Panel from performing its own collapse.
*/
onBeforeRegionCollapse: function(comp, direction, animate) {
+ if (comp.collapsedChangingLayout) {
+ //<debug warn>
+ if (Ext.global.console && Ext.global.console.warn) {
+ Ext.global.console.warn(Ext.getDisplayName(arguments.callee), 'aborted because the collapsed state is in the middle of changing');
+ }
+ //</debug>
+ return false;
+ }
+ comp.collapsedChangingLayout = true;
var me = this,
compEl = comp.el,
+ width,
miniCollapse = comp.collapseMode == 'mini',
shadowContainer = comp.shadowOwnerCt,
shadowLayout = shadowContainer.layout,
placeholder = comp.placeholder,
- placeholderBox,
- targetSize = shadowLayout.getLayoutTargetSize(),
sl = me.owner.suspendLayout,
scsl = shadowContainer.suspendLayout,
isNorthOrWest = (comp.region == 'north' || comp.region == 'west'); // Flag to keep the placeholder non-adjacent to any Splitter
if (!placeholder.rendered) {
shadowLayout.renderItem(placeholder, shadowLayout.innerCt);
+
+ // The inserted placeholder does not have the proper size, so copy the width
+ // for N/S or the height for E/W from the component. This fixes EXTJSIV-1562
+ // without recursive layouts. This is only an issue initially. After this time,
+ // placeholder will have the correct width/height set by the layout (which has
+ // already happened when we get here initially).
+ if (comp.region == 'north' || comp.region == 'south') {
+ placeholder.setCalculatedSize(comp.getWidth());
+ } else {
+ placeholder.setCalculatedSize(undefined, comp.getHeight());
+ }
}
// Jobs to be done after the collapse has been done
function afterCollapse() {
-
// Reinstate automatic laying out.
me.owner.suspendLayout = sl;
shadowContainer.suspendLayout = scsl;
delete me.shadowContainer.layout.layoutBusy;
delete me.layoutBusy;
delete me.owner.componentLayout.layoutBusy;
+ delete comp.collapsedChangingLayout;
// Fire the collapse event: The Panel has in fact been collapsed, but by substitution of an alternative Component
comp.collapsed = true;
compEl.setLeftTop(-10000, -10000);
shadowLayout.layout();
afterCollapse();
-
- // Horrible workaround for https://sencha.jira.com/browse/EXTJSIV-1562
- if (Ext.isIE) {
- placeholder.setCalculatedSize(placeholder.el.getWidth());
- }
}
return false;
// Hijack the expand operation to remove the placeholder and slide the region back in.
onBeforeRegionExpand: function(comp, animate) {
- this.onPlaceHolderToolClick(null, null, null, {client: comp});
+ // We don't check for comp.collapsedChangingLayout here because onPlaceHolderToolClick does it
+ this.onPlaceHolderToolClick(null, null, null, {client: comp, shouldFireBeforeexpand: false});
return false;
},
scsl = shadowContainer.suspendLayout,
isFloating;
+ if (comp.collapsedChangingLayout) {
+ //<debug warn>
+ if (Ext.global.console && Ext.global.console.warn) {
+ Ext.global.console.warn(Ext.getDisplayName(arguments.callee), 'aborted because the collapsed state is in the middle of changing');
+ }
+ //</debug>
+ return false;
+ }
+ if (tool.shouldFireBeforeexpand !== false && comp.fireEvent('beforeexpand', comp, true) === false) {
+ return false;
+ }
+ comp.collapsedChangingLayout = true;
// If the slide in is still going, stop it.
// This will either leave the Component in its fully floated state (which is processed below)
// or in its collapsed state. Either way, we expand it..
delete me.shadowContainer.layout.layoutBusy;
delete me.layoutBusy;
delete me.owner.componentLayout.layoutBusy;
+ delete comp.collapsedChangingLayout;
// In case it was floated out and they clicked the re-expand tool
comp.removeCls(Ext.baseCSSPrefix + 'border-region-slide-in');
me.callParent(arguments);
}
});
-</pre></pre></body></html>
\ No newline at end of file
+</pre>
+</body>
+</html>