4 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
5 <title>The source code</title>
6 <link href="../prettify/prettify.css" type="text/css" rel="stylesheet" />
7 <script type="text/javascript" src="../prettify/prettify.js"></script>
8 <style type="text/css">
9 .highlight { display: block; background-color: #ddd; }
11 <script type="text/javascript">
12 function highlight() {
13 document.getElementById(location.hash.replace(/#/, "")).className = "highlight";
17 <body onload="prettyPrint(); highlight();">
18 <pre class="prettyprint lang-js"><span id='Ext-layout-container-Border'>/**
19 </span> * @class Ext.layout.container.Border
20 * @extends Ext.layout.container.Container
21 * <p>This is a multi-pane, application-oriented UI layout style that supports multiple
22 * nested panels, automatic bars between regions and built-in
23 * {@link Ext.panel.Panel#collapsible expanding and collapsing} of regions.</p>
24 * <p>This class is intended to be extended or created via the <code>layout:'border'</code>
25 * {@link Ext.container.Container#layout} config, and should generally not need to be created directly
26 * via the new keyword.</p>
27 * {@img Ext.layout.container.Border/Ext.layout.container.Border.png Ext.layout.container.Border container layout}
28 * <p>Example usage:</p>
29 * <pre><code>
30 Ext.create('Ext.panel.Panel', {
33 title: 'Border Layout',
36 title: 'South Region is resizable',
37 region: 'south', // position for region
40 split: true, // enable resizing
43 // xtype: 'panel' implied by default
44 title: 'West Region is collapsible',
49 collapsible: true, // make collapsible
50 id: 'west-region-container',
53 title: 'Center Region',
54 region: 'center', // center region is required, no width/height specified
59 renderTo: Ext.getBody()
61 </code></pre>
62 * <p><b><u>Notes</u></b>:</p><div class="mdetail-params"><ul>
63 * <li>Any Container using the Border layout <b>must</b> have a child item with <code>region:'center'</code>.
64 * The child item in the center region will always be resized to fill the remaining space not used by
65 * the other regions in the layout.</li>
66 * <li>Any child items with a region of <code>west</code> or <code>east</code> may be configured with either
67 * 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>
68 * <li>Any child items with a region of <code>north</code> or <code>south</code> may be configured with either
69 * 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>
70 * <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
71 * Components within a BorderLayout, have them wrapped by an additional Container which is directly
72 * managed by the BorderLayout. If the region is to be collapsible, the Container used directly
73 * by the BorderLayout manager should be a Panel. In the following example a Container (an Ext.panel.Panel)
74 * is added to the west region:<pre><code>
75 wrc = {@link Ext#getCmp Ext.getCmp}('west-region-container');
76 wrc.{@link Ext.container.Container#removeAll removeAll}();
77 wrc.{@link Ext.container.Container#add add}({
81 * </code></pre>
83 * <li><b>There is no BorderLayout.Region class in ExtJS 4.0+</b></li>
84 * </ul></div>
86 Ext.define('Ext.layout.container.Border', {
88 alias: ['layout.border'],
89 extend: 'Ext.layout.container.Container',
90 requires: ['Ext.resizer.Splitter', 'Ext.container.Container', 'Ext.fx.Anim'],
91 alternateClassName: 'Ext.layout.BorderLayout',
93 targetCls: Ext.baseCSSPrefix + 'border-layout-ct',
95 itemCls: Ext.baseCSSPrefix + 'border-item',
97 bindToOwnerCtContainer: true,
101 percentageRe: /(\d+)%/,
110 constructor: function(config) {
111 this.initialConfig = config;
112 this.callParent(arguments);
115 onLayout: function() {
117 if (!me.borderLayoutInitialized) {
118 me.initializeBorderLayout();
121 // Delegate this operation to the shadow "V" or "H" box layout, and then down to any embedded layout.
122 me.fixHeightConstraints();
123 me.shadowLayout.onLayout();
124 if (me.embeddedContainer) {
125 me.embeddedContainer.layout.onLayout();
128 // If the panel was originally configured with collapsed: true, it will have
129 // been initialized with a "borderCollapse" flag: Collapse it now before the first layout.
130 if (!me.initialCollapsedComplete) {
131 Ext.iterate(me.regions, function(name, region){
132 if (region.borderCollapse) {
133 me.onBeforeRegionCollapse(region, region.collapseDirection, false, 0);
136 me.initialCollapsedComplete = true;
140 isValidParent : function(item, target, position) {
141 if (!this.borderLayoutInitialized) {
142 this.initializeBorderLayout();
145 // Delegate this operation to the shadow "V" or "H" box layout.
146 return this.shadowLayout.isValidParent(item, target, position);
149 beforeLayout: function() {
150 if (!this.borderLayoutInitialized) {
151 this.initializeBorderLayout();
154 // Delegate this operation to the shadow "V" or "H" box layout.
155 this.shadowLayout.beforeLayout();
158 renderItems: function(items, target) {
160 Ext.Error.raise('This should not be called');
164 renderItem: function(item) {
166 Ext.Error.raise('This should not be called');
170 initializeBorderLayout: function() {
173 items = me.getLayoutItems(),
175 regions = (me.regions = {}),
182 // Map of Splitters for each region
186 for (; i < ln; i++) {
188 regions[comp.region] = comp;
190 // Intercept collapsing to implement showing an alternate Component as a collapsed placeholder
191 if (comp.region != 'center' && comp.collapsible && comp.collapseMode != 'header') {
193 // This layout intercepts any initial collapsed state. Panel must not do this itself.
194 comp.borderCollapse = comp.collapsed;
195 delete comp.collapsed;
198 beforecollapse: me.onBeforeRegionCollapse,
199 beforeexpand: me.onBeforeRegionExpand,
200 destroy: me.onRegionDestroy,
207 if (!regions.center) {
208 Ext.Error.raise("You must specify a center region when defining a BorderLayout.");
211 comp = regions.center;
216 comp.maintainFlex = true;
218 // Begin the VBox and HBox item list.
221 comp.collapseDirection = Ext.Component.DIRECTION_LEFT;
222 hBoxItems.push(comp);
224 hBoxItems.push(me.splitters.west = me.createSplitter(comp));
226 percentage = Ext.isString(comp.width) && comp.width.match(me.percentageRe);
228 horizontalFlex += (comp.flex = parseInt(percentage[1], 10) / 100);
232 comp = regions.north;
234 comp.collapseDirection = Ext.Component.DIRECTION_TOP;
235 vBoxItems.push(comp);
237 vBoxItems.push(me.splitters.north = me.createSplitter(comp));
239 percentage = Ext.isString(comp.height) && comp.height.match(me.percentageRe);
241 verticalFlex += (comp.flex = parseInt(percentage[1], 10) / 100);
246 // Decide into which Collection the center region goes.
247 if (regions.north || regions.south) {
248 if (regions.east || regions.west) {
250 // Create the embedded center. Mark it with the region: 'center' property so that it can be identified as the center.
251 vBoxItems.push(me.embeddedContainer = Ext.create('Ext.container.Container', {
254 id: me.owner.id + '-embedded-center',
255 cls: Ext.baseCSSPrefix + 'border-item',
256 flex: regions.center.flex,
263 hBoxItems.push(regions.center);
265 // No east or west: the original center goes straight into the vbox
267 vBoxItems.push(regions.center);
270 // If we have no north or south, then the center is part of the HBox items
272 hBoxItems.push(regions.center);
275 // Finish off the VBox and HBox item list.
276 comp = regions.south;
278 comp.collapseDirection = Ext.Component.DIRECTION_BOTTOM;
280 vBoxItems.push(me.splitters.south = me.createSplitter(comp));
282 percentage = Ext.isString(comp.height) && comp.height.match(me.percentageRe);
284 verticalFlex += (comp.flex = parseInt(percentage[1], 10) / 100);
287 vBoxItems.push(comp);
291 comp.collapseDirection = Ext.Component.DIRECTION_RIGHT;
293 hBoxItems.push(me.splitters.east = me.createSplitter(comp));
295 percentage = Ext.isString(comp.width) && comp.width.match(me.percentageRe);
297 horizontalFlex += (comp.flex = parseInt(percentage[1], 10) / 100);
300 hBoxItems.push(comp);
303 // Create the injected "items" collections for the Containers.
304 // If we have north or south, then the shadow Container will be a VBox.
305 // If there are also east or west regions, its center will be a shadow HBox.
306 // If there are *only* east or west regions, then the shadow layout will be an HBox (or Fit).
307 if (regions.north || regions.south) {
309 me.shadowContainer = Ext.create('Ext.container.Container', {
312 layout: Ext.applyIf({
317 me.createItems(me.shadowContainer, vBoxItems);
319 // Allow the Splitters to orientate themselves
320 if (me.splitters.north) {
321 me.splitters.north.ownerCt = me.shadowContainer;
323 if (me.splitters.south) {
324 me.splitters.south.ownerCt = me.shadowContainer;
327 // Inject items into the HBox Container if there is one - if there was an east or west.
328 if (me.embeddedContainer) {
329 me.embeddedContainer.ownerCt = me.shadowContainer;
330 me.createItems(me.embeddedContainer, hBoxItems);
332 // Allow the Splitters to orientate themselves
333 if (me.splitters.east) {
334 me.splitters.east.ownerCt = me.embeddedContainer;
336 if (me.splitters.west) {
337 me.splitters.west.ownerCt = me.embeddedContainer;
340 // These spliiters need to be constrained by components one-level below
341 // the component in their vobx. We update the min/maxHeight on the helper
342 // (embeddedContainer) prior to starting the split/drag. This has to be
343 // done on-the-fly to allow min/maxHeight of the E/C/W regions to be set
345 Ext.each([me.splitters.north, me.splitters.south], function (splitter) {
347 splitter.on('beforedragstart', me.fixHeightConstraints, me);
351 // The east or west region wanted a percentage
352 if (horizontalFlex) {
353 regions.center.flex -= horizontalFlex;
355 // The north or south region wanted a percentage
357 me.embeddedContainer.flex -= verticalFlex;
360 // The north or south region wanted a percentage
362 regions.center.flex -= verticalFlex;
366 // If we have no north or south, then there's only one Container, and it's
367 // an HBox, or, if only a center region was specified, a Fit.
369 me.shadowContainer = Ext.create('Ext.container.Container', {
372 layout: Ext.applyIf({
373 type: (hBoxItems.length == 1) ? 'fit' : 'hbox',
377 me.createItems(me.shadowContainer, hBoxItems);
379 // Allow the Splitters to orientate themselves
380 if (me.splitters.east) {
381 me.splitters.east.ownerCt = me.shadowContainer;
383 if (me.splitters.west) {
384 me.splitters.west.ownerCt = me.shadowContainer;
387 // The east or west region wanted a percentage
388 if (horizontalFlex) {
389 regions.center.flex -= verticalFlex;
393 // Create upward links from the region Components to their shadow ownerCts
394 for (i = 0, items = me.shadowContainer.items.items, ln = items.length; i < ln; i++) {
395 items[i].shadowOwnerCt = me.shadowContainer;
397 if (me.embeddedContainer) {
398 for (i = 0, items = me.embeddedContainer.items.items, ln = items.length; i < ln; i++) {
399 items[i].shadowOwnerCt = me.embeddedContainer;
403 // This is the layout that we delegate all operations to
404 me.shadowLayout = me.shadowContainer.getLayout();
406 me.borderLayoutInitialized = true;
409 setupState: function(comp){
410 var getState = comp.getState;
411 comp.getState = function(){
412 // call the original getState
413 var state = getState.call(comp) || {},
414 region = comp.region;
416 state.collapsed = !!comp.collapsed;
417 if (region == 'west' || region == 'east') {
418 state.width = comp.getWidth();
420 state.height = comp.getHeight();
424 comp.addStateEvents(['collapse', 'expand', 'resize']);
427 <span id='Ext-layout-container-Border-method-createItems'> /**
428 </span> * Create the items collection for our shadow/embedded containers
431 createItems: function(container, items){
432 // Have to inject an items Collection *after* construction.
433 // The child items of the shadow layout must retain their original, user-defined ownerCt
434 delete container.items;
435 container.initItems();
436 container.items.addAll(items);
440 // Create a splitter for a child of the layout.
441 createSplitter: function(comp) {
443 interceptCollapse = (comp.collapseMode != 'header'),
446 resizer = Ext.create('Ext.resizer.Splitter', {
447 hidden: !!comp.hidden,
448 collapseTarget: comp,
449 performCollapse: !interceptCollapse,
450 listeners: interceptCollapse ? {
452 fn: Ext.Function.bind(me.onSplitterCollapseClick, me, [comp]),
453 element: 'collapseEl'
458 // Mini collapse means that the splitter is the placeholder Component
459 if (comp.collapseMode == 'mini') {
460 comp.placeholder = resizer;
461 resizer.collapsedCls = comp.collapsedCls;
464 // Arrange to hide/show a region's associated splitter when the region is hidden/shown
466 hide: me.onRegionVisibilityChange,
467 show: me.onRegionVisibilityChange,
474 // Propogates the min/maxHeight values from the inner hbox items to its container.
475 fixHeightConstraints: function () {
477 ct = me.embeddedContainer,
478 maxHeight = 1e99, minHeight = -1;
484 ct.items.each(function (item) {
485 if (Ext.isNumber(item.maxHeight)) {
486 maxHeight = Math.max(maxHeight, item.maxHeight);
488 if (Ext.isNumber(item.minHeight)) {
489 minHeight = Math.max(minHeight, item.minHeight);
493 ct.maxHeight = maxHeight;
494 ct.minHeight = minHeight;
497 // Hide/show a region's associated splitter when the region is hidden/shown
498 onRegionVisibilityChange: function(comp){
499 this.splitters[comp.region][comp.hidden ? 'hide' : 'show']();
503 // Called when a splitter mini-collapse tool is clicked on.
504 // The listener is only added if this layout is controlling collapsing,
505 // not if the component's collapseMode is 'mini' or 'header'.
506 onSplitterCollapseClick: function(comp) {
507 if (comp.collapsed) {
508 this.onPlaceHolderToolClick(null, null, null, {client: comp});
514 <span id='Ext-layout-container-Border-method-getPlaceholder'> /**
515 </span> * <p>Return the {@link Ext.panel.Panel#placeholder placeholder} Component to which the passed child Panel of the layout will collapse.
516 * By default, this will be a {@link Ext.panel.Header Header} component (Docked to the appropriate border). See {@link Ext.panel.Panel#placeholder placeholder}.
517 * config to customize this.</p>
518 * <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>
519 * @param {Panel} panel The child Panel of the layout for which to return the {@link Ext.panel.Panel#placeholder placeholder}.
520 * @returns {Component} The Panel's {@link Ext.panel.Panel#placeholder placeholder} unless the {@link Ext.panel.Panel#collapseMode collapseMode} is
521 * <code>'header'</code>, in which case <i>undefined</i> is returned.
523 getPlaceholder: function(comp) {
525 placeholder = comp.placeholder,
526 shadowContainer = comp.shadowOwnerCt,
527 shadowLayout = shadowContainer.layout,
528 oppositeDirection = Ext.panel.Panel.prototype.getOppositeDirection(comp.collapseDirection),
529 horiz = (comp.region == 'north' || comp.region == 'south');
531 // No placeholder if the collapse mode is not the Border layout default
532 if (comp.collapseMode == 'header') {
536 // Provide a replacement Container with an expand tool
538 if (comp.collapseMode == 'mini') {
539 placeholder = Ext.create('Ext.resizer.Splitter', {
540 id: 'collapse-placeholder-' + comp.id,
541 collapseTarget: comp,
542 performCollapse: false,
545 fn: Ext.Function.bind(me.onSplitterCollapseClick, me, [comp]),
546 element: 'collapseEl'
550 placeholder.addCls(placeholder.collapsedCls);
553 id: 'collapse-placeholder-' + comp.id,
554 margins: comp.initialConfig.margins || Ext.getClass(comp).prototype.margins,
556 orientation: horiz ? 'horizontal' : 'vertical',
558 textCls: comp.headerTextCls,
559 iconCls: comp.iconCls,
560 baseCls: comp.baseCls + '-header',
562 indicateDrag: comp.draggable,
563 cls: Ext.baseCSSPrefix + 'region-collapsed-placeholder ' + Ext.baseCSSPrefix + 'region-collapsed-' + comp.collapseDirection + '-placeholder ' + comp.collapsedCls,
564 listeners: comp.floatable ? {
567 me.floatCollapsedPanel(e, comp);
573 // Hack for IE6/7/IEQuirks's inability to display an inline-block
574 if ((Ext.isIE6 || Ext.isIE7 || (Ext.isIEQuirks)) && !horiz) {
575 placeholder.width = 25;
577 if (!comp.hideCollapseTool) {
578 placeholder[horiz ? 'tools' : 'items'] = [{
581 type: 'expand-' + oppositeDirection,
582 handler: me.onPlaceHolderToolClick,
587 placeholder = me.owner.createComponent(placeholder);
588 if (comp.isXType('panel')) {
590 titlechange: me.onRegionTitleChange,
591 iconchange: me.onRegionIconChange,
597 // The collapsed Component holds a reference to its placeholder and vice versa
598 comp.placeholder = placeholder;
599 placeholder.comp = comp;
604 <span id='Ext-layout-container-Border-method-onRegionTitleChange'> /**
606 * Update the placeholder title when panel title has been set or changed.
608 onRegionTitleChange: function(comp, newTitle) {
609 comp.placeholder.setTitle(newTitle);
612 <span id='Ext-layout-container-Border-method-onRegionIconChange'> /**
614 * Update the placeholder iconCls when panel iconCls has been set or changed.
616 onRegionIconChange: function(comp, newIconCls) {
617 comp.placeholder.setIconCls(newIconCls);
620 <span id='Ext-layout-container-Border-method-calculateChildBox'> /**
622 * Calculates the size and positioning of the passed child item. Must be present because Panel's expand,
623 * when configured with a flex, calls this method on its ownerCt's layout.
624 * @param {Component} child The child Component to calculate the box for
625 * @return {Object} Object containing box measurements for the child. Properties are left,top,width,height.
627 calculateChildBox: function(comp) {
629 if (me.shadowContainer.items.contains(comp)) {
630 return me.shadowContainer.layout.calculateChildBox(comp);
632 else if (me.embeddedContainer && me.embeddedContainer.items.contains(comp)) {
633 return me.embeddedContainer.layout.calculateChildBox(comp);
637 <span id='Ext-layout-container-Border-method-onBeforeRegionCollapse'> /**
639 * Intercepts the Panel's own collapse event and perform's substitution of the Panel
640 * with a placeholder Header orientated in the appropriate dimension.
641 * @param comp The Panel being collapsed.
644 * @returns {Boolean} false to inhibit the Panel from performing its own collapse.
646 onBeforeRegionCollapse: function(comp, direction, animate) {
650 miniCollapse = comp.collapseMode == 'mini',
651 shadowContainer = comp.shadowOwnerCt,
652 shadowLayout = shadowContainer.layout,
653 placeholder = comp.placeholder,
654 sl = me.owner.suspendLayout,
655 scsl = shadowContainer.suspendLayout,
656 isNorthOrWest = (comp.region == 'north' || comp.region == 'west'); // Flag to keep the placeholder non-adjacent to any Splitter
658 // Do not trigger a layout during transition to collapsed Component
659 me.owner.suspendLayout = true;
660 shadowContainer.suspendLayout = true;
662 // Prevent upward notifications from downstream layouts
663 shadowLayout.layoutBusy = true;
664 if (shadowContainer.componentLayout) {
665 shadowContainer.componentLayout.layoutBusy = true;
667 me.shadowContainer.layout.layoutBusy = true;
668 me.layoutBusy = true;
669 me.owner.componentLayout.layoutBusy = true;
671 // Provide a replacement Container with an expand tool
673 placeholder = me.getPlaceholder(comp);
676 // placeholder already in place; show it.
677 if (placeholder.shadowOwnerCt === shadowContainer) {
680 // Insert the collapsed placeholder Component into the appropriate Box layout shadow Container
681 // It must go next to its client Component, but non-adjacent to the splitter so splitter can find its collapse client.
682 // Inject an ownerCt value pointing to the owner, border layout Container as the user will expect.
684 shadowContainer.insert(shadowContainer.items.indexOf(comp) + (isNorthOrWest ? 0 : 1), placeholder);
685 placeholder.shadowOwnerCt = shadowContainer;
686 placeholder.ownerCt = me.owner;
689 // Flag the collapsing Component as hidden and show the placeholder.
690 // This causes the shadow Box layout's calculateChildBoxes to calculate the correct new arrangement.
691 // We hide or slideOut the Component's element
694 if (!placeholder.rendered) {
695 shadowLayout.renderItem(placeholder, shadowLayout.innerCt);
697 // The inserted placeholder does not have the proper size, so copy the width
698 // for N/S or the height for E/W from the component. This fixes EXTJSIV-1562
699 // without recursive layouts. This is only an issue initially. After this time,
700 // placeholder will have the correct width/height set by the layout (which has
701 // already happened when we get here initially).
702 if (comp.region == 'north' || comp.region == 'south') {
703 placeholder.setCalculatedSize(comp.getWidth());
705 placeholder.setCalculatedSize(undefined, comp.getHeight());
709 // Jobs to be done after the collapse has been done
710 function afterCollapse() {
711 // Reinstate automatic laying out.
712 me.owner.suspendLayout = sl;
713 shadowContainer.suspendLayout = scsl;
714 delete shadowLayout.layoutBusy;
715 if (shadowContainer.componentLayout) {
716 delete shadowContainer.componentLayout.layoutBusy;
718 delete me.shadowContainer.layout.layoutBusy;
719 delete me.layoutBusy;
720 delete me.owner.componentLayout.layoutBusy;
722 // Fire the collapse event: The Panel has in fact been collapsed, but by substitution of an alternative Component
723 comp.collapsed = true;
724 comp.fireEvent('collapse', comp);
728 * Set everything to the new positions. Note that we
729 * only want to animate the collapse if it wasn't configured
730 * initially with collapsed: true
732 if (comp.animCollapse && me.initialCollapsedComplete) {
733 shadowLayout.layout();
734 compEl.dom.style.zIndex = 100;
736 // If we're mini-collapsing, the placholder is a Splitter. We don't want it to "bounce in"
738 placeholder.el.hide();
740 compEl.slideOut(me.slideDirection[comp.region], {
741 duration: Ext.Number.from(comp.animCollapse, Ext.fx.Anim.prototype.duration),
743 afteranimate: function() {
744 compEl.show().setLeftTop(-10000, -10000);
745 compEl.dom.style.zIndex = '';
747 // If we're mini-collapsing, the placholder is a Splitter. We don't want it to "bounce in"
749 placeholder.el.slideIn(me.slideDirection[comp.region], {
759 compEl.setLeftTop(-10000, -10000);
760 shadowLayout.layout();
767 // Hijack the expand operation to remove the placeholder and slide the region back in.
768 onBeforeRegionExpand: function(comp, animate) {
769 this.onPlaceHolderToolClick(null, null, null, {client: comp});
773 // Called when the collapsed placeholder is clicked to reinstate a "collapsed" (in reality hidden) Panel.
774 onPlaceHolderToolClick: function(e, target, owner, tool) {
778 // Hide the placeholder unless it was the Component's preexisting splitter
779 hidePlaceholder = (comp.collapseMode != 'mini') || !comp.split,
782 placeholder = comp.placeholder,
783 placeholderEl = placeholder.el,
784 shadowContainer = comp.shadowOwnerCt,
785 shadowLayout = shadowContainer.layout,
787 sl = me.owner.suspendLayout,
788 scsl = shadowContainer.suspendLayout,
791 // If the slide in is still going, stop it.
792 // This will either leave the Component in its fully floated state (which is processed below)
793 // or in its collapsed state. Either way, we expand it..
794 if (comp.getActiveAnimation()) {
795 comp.stopAnimation();
798 // If the Component is fully floated when they click the placeholder Tool,
799 // it will be primed with a slide out animation object... so delete that
800 // and remove the mouseout listeners
801 if (comp.slideOutAnim) {
802 // Remove mouse leave monitors
803 compEl.un(comp.panelMouseMon);
804 placeholderEl.un(comp.placeholderMouseMon);
806 delete comp.slideOutAnim;
807 delete comp.panelMouseMon;
808 delete comp.placeholderMouseMon;
810 // If the Panel was floated and primed with a slideOut animation, we don't want to animate its layout operation.
814 // Do not trigger a layout during transition to expanded Component
815 me.owner.suspendLayout = true;
816 shadowContainer.suspendLayout = true;
818 // Prevent upward notifications from downstream layouts
819 shadowLayout.layoutBusy = true;
820 if (shadowContainer.componentLayout) {
821 shadowContainer.componentLayout.layoutBusy = true;
823 me.shadowContainer.layout.layoutBusy = true;
824 me.layoutBusy = true;
825 me.owner.componentLayout.layoutBusy = true;
827 // Unset the hidden and collapsed flags set in onBeforeRegionCollapse. The shadowLayout will now take it into account
828 // Find where the shadow Box layout plans to put the expanding Component.
830 comp.collapsed = false;
831 if (hidePlaceholder) {
832 placeholder.hidden = true;
834 toCompBox = shadowLayout.calculateChildBox(comp);
836 // Show the collapse tool in case it was hidden by the slide-in
837 if (comp.collapseTool) {
838 comp.collapseTool.show();
841 // If we're going to animate, we need to hide the component before moving it back into position
842 if (comp.animCollapse && !isFloating) {
843 compEl.setStyle('visibility', 'hidden');
845 compEl.setLeftTop(toCompBox.left, toCompBox.top);
847 // Equalize the size of the expanding Component prior to animation
848 // in case the layout area has changed size during the time it was collapsed.
849 curSize = comp.getSize();
850 if (curSize.height != toCompBox.height || curSize.width != toCompBox.width) {
851 me.setItemSize(comp, toCompBox.width, toCompBox.height);
854 // Jobs to be done after the expand has been done
855 function afterExpand() {
856 // Reinstate automatic laying out.
857 me.owner.suspendLayout = sl;
858 shadowContainer.suspendLayout = scsl;
859 delete shadowLayout.layoutBusy;
860 if (shadowContainer.componentLayout) {
861 delete shadowContainer.componentLayout.layoutBusy;
863 delete me.shadowContainer.layout.layoutBusy;
864 delete me.layoutBusy;
865 delete me.owner.componentLayout.layoutBusy;
867 // In case it was floated out and they clicked the re-expand tool
868 comp.removeCls(Ext.baseCSSPrefix + 'border-region-slide-in');
870 // Fire the expand event: The Panel has in fact been expanded, but by removal of an alternative Component
871 comp.fireEvent('expand', comp);
874 // Hide the placeholder
875 if (hidePlaceholder) {
876 placeholder.el.hide();
879 // Slide the expanding Component to its new position.
880 // When that is done, layout the layout.
881 if (comp.animCollapse && !isFloating) {
882 compEl.dom.style.zIndex = 100;
883 compEl.slideIn(me.slideDirection[comp.region], {
884 duration: Ext.Number.from(comp.animCollapse, Ext.fx.Anim.prototype.duration),
886 afteranimate: function() {
887 compEl.dom.style.zIndex = '';
889 shadowLayout.onLayout();
895 shadowLayout.onLayout();
900 floatCollapsedPanel: function(e, comp) {
902 if (comp.floatable === false) {
908 placeholder = comp.placeholder,
909 placeholderEl = placeholder.el,
910 shadowContainer = comp.shadowOwnerCt,
911 shadowLayout = shadowContainer.layout,
912 placeholderBox = shadowLayout.getChildBox(placeholder),
913 scsl = shadowContainer.suspendLayout,
914 curSize, toCompBox, compAnim;
916 // Ignore clicks on tools.
917 if (e.getTarget('.' + Ext.baseCSSPrefix + 'tool')) {
921 // It's *being* animated, ignore the click.
922 // Possible future enhancement: Stop and *reverse* the current active Fx.
923 if (compEl.getActiveAnimation()) {
927 // If the Component is already fully floated when they click the placeholder,
928 // it will be primed with a slide out animation object... so slide it out.
929 if (comp.slideOutAnim) {
930 me.slideOutFloatedComponent(comp);
934 // Function to be called when the mouse leaves the floated Panel
935 // Slide out when the mouse leaves the region bounded by the slid Component and its placeholder.
936 function onMouseLeaveFloated(e) {
937 var slideRegion = compEl.getRegion().union(placeholderEl.getRegion()).adjust(1, -1, -1, 1);
939 // If mouse is not within slide Region, slide it out
940 if (!slideRegion.contains(e.getPoint())) {
941 me.slideOutFloatedComponent(comp);
945 // Monitor for mouseouting of the placeholder. Hide it if they exit for half a second or more
946 comp.placeholderMouseMon = placeholderEl.monitorMouseLeave(500, onMouseLeaveFloated);
948 // Do not trigger a layout during slide out of the Component
949 shadowContainer.suspendLayout = true;
951 // Prevent upward notifications from downstream layouts
952 me.layoutBusy = true;
953 me.owner.componentLayout.layoutBusy = true;
955 // The collapse tool is hidden while slid.
956 // It is re-shown on expand.
957 if (comp.collapseTool) {
958 comp.collapseTool.hide();
961 // Set flags so that the layout will calculate the boxes for what we want
963 comp.collapsed = false;
964 placeholder.hidden = true;
966 // Recalculate new arrangement of the Component being floated.
967 toCompBox = shadowLayout.calculateChildBox(comp);
968 placeholder.hidden = false;
970 // Component to appear just after the placeholder, whatever "after" means in the context of the shadow Box layout.
971 if (comp.region == 'north' || comp.region == 'west') {
972 toCompBox[shadowLayout.parallelBefore] += placeholderBox[shadowLayout.parallelPrefix] - 1;
974 toCompBox[shadowLayout.parallelBefore] -= (placeholderBox[shadowLayout.parallelPrefix] - 1);
976 compEl.setStyle('visibility', 'hidden');
977 compEl.setLeftTop(toCompBox.left, toCompBox.top);
979 // Equalize the size of the expanding Component prior to animation
980 // in case the layout area has changed size during the time it was collapsed.
981 curSize = comp.getSize();
982 if (curSize.height != toCompBox.height || curSize.width != toCompBox.width) {
983 me.setItemSize(comp, toCompBox.width, toCompBox.height);
986 // This animation slides the collapsed Component's el out to just beyond its placeholder
989 afteranimate: function() {
990 shadowContainer.suspendLayout = scsl;
991 delete me.layoutBusy;
992 delete me.owner.componentLayout.layoutBusy;
994 // Prime the Component with an Anim config object to slide it back out
995 compAnim.listeners = {
996 afterAnimate: function() {
997 compEl.show().removeCls(Ext.baseCSSPrefix + 'border-region-slide-in').setLeftTop(-10000, -10000);
999 // Reinstate the correct, current state after slide out animation finishes
1001 comp.collapsed = true;
1002 delete comp.slideOutAnim;
1003 delete comp.panelMouseMon;
1004 delete comp.placeholderMouseMon;
1007 comp.slideOutAnim = compAnim;
1013 // Give the element the correct class which places it at a high z-index
1014 compEl.addCls(Ext.baseCSSPrefix + 'border-region-slide-in');
1016 // Begin the slide in
1017 compEl.slideIn(me.slideDirection[comp.region], compAnim);
1019 // Monitor for mouseouting of the slid area. Hide it if they exit for half a second or more
1020 comp.panelMouseMon = compEl.monitorMouseLeave(500, onMouseLeaveFloated);
1024 slideOutFloatedComponent: function(comp) {
1025 var compEl = comp.el,
1028 // Remove mouse leave monitors
1029 compEl.un(comp.panelMouseMon);
1030 comp.placeholder.el.un(comp.placeholderMouseMon);
1032 // Slide the Component out
1033 compEl.slideOut(this.slideDirection[comp.region], comp.slideOutAnim);
1035 delete comp.slideOutAnim;
1036 delete comp.panelMouseMon;
1037 delete comp.placeholderMouseMon;
1042 * Ensure any collapsed placeholder Component is destroyed along with its region.
1043 * Can't do this in onDestroy because they may remove a Component and use it elsewhere.
1045 onRegionDestroy: function(comp) {
1046 var placeholder = comp.placeholder;
1048 delete placeholder.ownerCt;
1049 placeholder.destroy();
1055 * Ensure any shadow Containers are destroyed.
1056 * Ensure we don't keep references to Components.
1058 onDestroy: function() {
1060 shadowContainer = me.shadowContainer,
1061 embeddedContainer = me.embeddedContainer;
1063 if (shadowContainer) {
1064 delete shadowContainer.ownerCt;
1065 Ext.destroy(shadowContainer);
1068 if (embeddedContainer) {
1069 delete embeddedContainer.ownerCt;
1070 Ext.destroy(embeddedContainer);
1073 delete me.splitters;
1074 delete me.shadowContainer;
1075 delete me.embeddedContainer;
1076 me.callParent(arguments);