PageRenderTime 62ms CodeModel.GetById 13ms app.highlight 26ms RepoModel.GetById 2ms app.codeStats 1ms

/ext-4.0.7/docs/source/Border.html

https://bitbucket.org/srogerf/javascript
HTML | 1130 lines | 1004 code | 126 blank | 0 comment | 0 complexity | 5d4366a9c99954a646446b4ac23f7480 MD5 | raw file
   1<!DOCTYPE html>
   2<html>
   3<head>
   4  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
   5  <title>The source code</title>
   6  <link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />
   7  <script type="text/javascript" src="../resources/prettify/prettify.js"></script>
   8  <style type="text/css">
   9    .highlight { display: block; background-color: #ddd; }
  10  </style>
  11  <script type="text/javascript">
  12    function highlight() {
  13      document.getElementById(location.hash.replace(/#/, "")).className = "highlight";
  14    }
  15  </script>
  16</head>
  17<body onload="prettyPrint(); highlight();">
  18  <pre class="prettyprint lang-js"><span id='Ext-layout-container-Border'>/**
  19</span> * This is a multi-pane, application-oriented UI layout style that supports multiple nested panels, automatic bars
  20 * between regions and built-in {@link Ext.panel.Panel#collapsible expanding and collapsing} of regions.
  21 *
  22 * This class is intended to be extended or created via the `layout:'border'` {@link Ext.container.Container#layout}
  23 * config, and should generally not need to be created directly via the new keyword.
  24 *
  25 *     @example
  26 *     Ext.create('Ext.panel.Panel', {
  27 *         width: 500,
  28 *         height: 400,
  29 *         title: 'Border Layout',
  30 *         layout: 'border',
  31 *         items: [{
  32 *             title: 'South Region is resizable',
  33 *             region: 'south',     // position for region
  34 *             xtype: 'panel',
  35 *             height: 100,
  36 *             split: true,         // enable resizing
  37 *             margins: '0 5 5 5'
  38 *         },{
  39 *             // xtype: 'panel' implied by default
  40 *             title: 'West Region is collapsible',
  41 *             region:'west',
  42 *             xtype: 'panel',
  43 *             margins: '5 0 0 5',
  44 *             width: 200,
  45 *             collapsible: true,   // make collapsible
  46 *             id: 'west-region-container',
  47 *             layout: 'fit'
  48 *         },{
  49 *             title: 'Center Region',
  50 *             region: 'center',     // center region is required, no width/height specified
  51 *             xtype: 'panel',
  52 *             layout: 'fit',
  53 *             margins: '5 5 0 0'
  54 *         }],
  55 *         renderTo: Ext.getBody()
  56 *     });
  57 *
  58 * # Notes
  59 *
  60 * - Any Container using the Border layout **must** have a child item with `region:'center'`.
  61 *   The child item in the center region will always be resized to fill the remaining space
  62 *   not used by the other regions in the layout.
  63 *
  64 * - Any child items with a region of `west` or `east` may be configured with either an initial
  65 *   `width`, or a {@link Ext.layout.container.Box#flex} value, or an initial percentage width
  66 *   **string** (Which is simply divided by 100 and used as a flex value).
  67 *   The 'center' region has a flex value of `1`.
  68 *
  69 * - Any child items with a region of `north` or `south` may be configured with either an initial
  70 *   `height`, or a {@link Ext.layout.container.Box#flex} value, or an initial percentage height
  71 *   **string** (Which is simply divided by 100 and used as a flex value).
  72 *   The 'center' region has a flex value of `1`.
  73 *
  74 * - The regions of a BorderLayout are **fixed at render time** and thereafter, its child
  75 *   Components may not be removed or added**. To add/remove Components within a BorderLayout,
  76 *   have them wrapped by an additional Container which is directly managed by the BorderLayout.
  77 *   If the region is to be collapsible, the Container used directly by the BorderLayout manager
  78 *   should be a Panel. In the following example a Container (an Ext.panel.Panel) is added to
  79 *   the west region:
  80 *
  81 *       wrc = {@link Ext#getCmp Ext.getCmp}('west-region-container');
  82 *       wrc.{@link Ext.container.Container#removeAll removeAll}();
  83 *       wrc.{@link Ext.container.Container#add add}({
  84 *           title: 'Added Panel',
  85 *           html: 'Some content'
  86 *       });
  87 *
  88 * - **There is no BorderLayout.Region class in ExtJS 4.0+**
  89 */
  90Ext.define('Ext.layout.container.Border', {
  91
  92    alias: ['layout.border'],
  93    extend: 'Ext.layout.container.Container',
  94    requires: ['Ext.resizer.Splitter', 'Ext.container.Container', 'Ext.fx.Anim'],
  95    alternateClassName: 'Ext.layout.BorderLayout',
  96
  97    targetCls: Ext.baseCSSPrefix + 'border-layout-ct',
  98
  99    itemCls: Ext.baseCSSPrefix + 'border-item',
 100
 101    bindToOwnerCtContainer: true,
 102
 103    percentageRe: /(\d+)%/,
 104
 105    slideDirection: {
 106        north: 't',
 107        south: 'b',
 108        west: 'l',
 109        east: 'r'
 110    },
 111
 112    constructor: function(config) {
 113        this.initialConfig = config;
 114        this.callParent(arguments);
 115    },
 116
 117    onLayout: function() {
 118        var me = this;
 119        if (!me.borderLayoutInitialized) {
 120            me.initializeBorderLayout();
 121        }
 122
 123        // Delegate this operation to the shadow &quot;V&quot; or &quot;H&quot; box layout, and then down to any embedded layout.
 124        me.fixHeightConstraints();
 125        me.shadowLayout.onLayout();
 126        if (me.embeddedContainer) {
 127            me.embeddedContainer.layout.onLayout();
 128        }
 129
 130        // If the panel was originally configured with collapsed: true, it will have
 131        // been initialized with a &quot;borderCollapse&quot; flag: Collapse it now before the first layout.
 132        if (!me.initialCollapsedComplete) {
 133            Ext.iterate(me.regions, function(name, region){
 134                if (region.borderCollapse) {
 135                    me.onBeforeRegionCollapse(region, region.collapseDirection, false, 0);
 136                }
 137            });
 138            me.initialCollapsedComplete = true;
 139        }
 140    },
 141
 142    isValidParent : function(item, target, position) {
 143        if (!this.borderLayoutInitialized) {
 144            this.initializeBorderLayout();
 145        }
 146
 147        // Delegate this operation to the shadow &quot;V&quot; or &quot;H&quot; box layout.
 148        return this.shadowLayout.isValidParent(item, target, position);
 149    },
 150
 151    beforeLayout: function() {
 152        if (!this.borderLayoutInitialized) {
 153            this.initializeBorderLayout();
 154        }
 155
 156        // Delegate this operation to the shadow &quot;V&quot; or &quot;H&quot; box layout.
 157        this.shadowLayout.beforeLayout();
 158
 159        // note: don't call base because that does a renderItems again
 160    },
 161
 162    renderItems: function(items, target) {
 163        //&lt;debug&gt;
 164        Ext.Error.raise('This should not be called');
 165        //&lt;/debug&gt;
 166    },
 167
 168    renderItem: function(item) {
 169        //&lt;debug&gt;
 170        Ext.Error.raise('This should not be called');
 171        //&lt;/debug&gt;
 172    },
 173
 174    renderChildren: function() {
 175        if (!this.borderLayoutInitialized) {
 176            this.initializeBorderLayout();
 177        }
 178
 179        this.shadowLayout.renderChildren();
 180    },
 181
 182    /*
 183     * Gathers items for a layout operation. Injected into child Box layouts through configuration.
 184     * We must not include child items which are floated over the layout (are primed with a slide out animation)
 185     */
 186    getVisibleItems: function() {
 187        return Ext.ComponentQuery.query(':not([slideOutAnim])', this.callParent(arguments));
 188    },
 189
 190    initializeBorderLayout: function() {
 191        var me = this,
 192            i = 0,
 193            items = me.getLayoutItems(),
 194            ln = items.length,
 195            regions = (me.regions = {}),
 196            vBoxItems = [],
 197            hBoxItems = [],
 198            horizontalFlex = 0,
 199            verticalFlex = 0,
 200            comp, percentage;
 201
 202        // Map of Splitters for each region
 203        me.splitters = {};
 204
 205        // Map of regions
 206        for (; i &lt; ln; i++) {
 207            comp = items[i];
 208            regions[comp.region] = comp;
 209
 210            // Intercept collapsing to implement showing an alternate Component as a collapsed placeholder
 211            if (comp.region != 'center' &amp;&amp; comp.collapsible &amp;&amp; comp.collapseMode != 'header') {
 212
 213                // This layout intercepts any initial collapsed state. Panel must not do this itself.
 214                comp.borderCollapse = comp.collapsed;
 215                comp.collapsed = false;
 216
 217                comp.on({
 218                    beforecollapse: me.onBeforeRegionCollapse,
 219                    beforeexpand: me.onBeforeRegionExpand,
 220                    destroy: me.onRegionDestroy,
 221                    scope: me
 222                });
 223                me.setupState(comp);
 224            }
 225        }
 226        //&lt;debug&gt;
 227        if (!regions.center) {
 228            Ext.Error.raise(&quot;You must specify a center region when defining a BorderLayout.&quot;);
 229        }
 230        //&lt;/debug&gt;
 231        comp = regions.center;
 232        if (!comp.flex) {
 233            comp.flex = 1;
 234        }
 235        delete comp.width;
 236        comp.maintainFlex = true;
 237
 238        // Begin the VBox and HBox item list.
 239        comp = regions.west;
 240        if (comp) {
 241            comp.collapseDirection = Ext.Component.DIRECTION_LEFT;
 242            hBoxItems.push(comp);
 243            if (comp.split) {
 244                hBoxItems.push(me.splitters.west = me.createSplitter(comp));
 245            }
 246            percentage = Ext.isString(comp.width) &amp;&amp; comp.width.match(me.percentageRe);
 247            if (percentage) {
 248                horizontalFlex += (comp.flex = parseInt(percentage[1], 10) / 100);
 249                delete comp.width;
 250            }
 251        }
 252        comp = regions.north;
 253        if (comp) {
 254            comp.collapseDirection = Ext.Component.DIRECTION_TOP;
 255            vBoxItems.push(comp);
 256            if (comp.split) {
 257                vBoxItems.push(me.splitters.north = me.createSplitter(comp));
 258            }
 259            percentage = Ext.isString(comp.height) &amp;&amp; comp.height.match(me.percentageRe);
 260            if (percentage) {
 261                verticalFlex += (comp.flex = parseInt(percentage[1], 10) / 100);
 262                delete comp.height;
 263            }
 264        }
 265
 266        // Decide into which Collection the center region goes.
 267        if (regions.north || regions.south) {
 268            if (regions.east || regions.west) {
 269
 270                // Create the embedded center. Mark it with the region: 'center' property so that it can be identified as the center.
 271                vBoxItems.push(me.embeddedContainer = Ext.create('Ext.container.Container', {
 272                    xtype: 'container',
 273                    region: 'center',
 274                    id: me.owner.id + '-embedded-center',
 275                    cls: Ext.baseCSSPrefix + 'border-item',
 276                    flex: regions.center.flex,
 277                    maintainFlex: true,
 278                    layout: {
 279                        type: 'hbox',
 280                        align: 'stretch',
 281                        getVisibleItems: me.getVisibleItems
 282                    }
 283                }));
 284                hBoxItems.push(regions.center);
 285            }
 286            // No east or west: the original center goes straight into the vbox
 287            else {
 288                vBoxItems.push(regions.center);
 289            }
 290        }
 291        // If we have no north or south, then the center is part of the HBox items
 292        else {
 293            hBoxItems.push(regions.center);
 294        }
 295
 296        // Finish off the VBox and HBox item list.
 297        comp = regions.south;
 298        if (comp) {
 299            comp.collapseDirection = Ext.Component.DIRECTION_BOTTOM;
 300            if (comp.split) {
 301                vBoxItems.push(me.splitters.south = me.createSplitter(comp));
 302            }
 303            percentage = Ext.isString(comp.height) &amp;&amp; comp.height.match(me.percentageRe);
 304            if (percentage) {
 305                verticalFlex += (comp.flex = parseInt(percentage[1], 10) / 100);
 306                delete comp.height;
 307            }
 308            vBoxItems.push(comp);
 309        }
 310        comp = regions.east;
 311        if (comp) {
 312            comp.collapseDirection = Ext.Component.DIRECTION_RIGHT;
 313            if (comp.split) {
 314                hBoxItems.push(me.splitters.east = me.createSplitter(comp));
 315            }
 316            percentage = Ext.isString(comp.width) &amp;&amp; comp.width.match(me.percentageRe);
 317            if (percentage) {
 318                horizontalFlex += (comp.flex = parseInt(percentage[1], 10) / 100);
 319                delete comp.width;
 320            }
 321            hBoxItems.push(comp);
 322        }
 323
 324        // Create the injected &quot;items&quot; collections for the Containers.
 325        // If we have north or south, then the shadow Container will be a VBox.
 326        // If there are also east or west regions, its center will be a shadow HBox.
 327        // If there are *only* east or west regions, then the shadow layout will be an HBox (or Fit).
 328        if (regions.north || regions.south) {
 329
 330            me.shadowContainer = Ext.create('Ext.container.Container', {
 331                ownerCt: me.owner,
 332                el: me.getTarget(),
 333                layout: Ext.applyIf({
 334                    type: 'vbox',
 335                    align: 'stretch',
 336                    getVisibleItems: me.getVisibleItems
 337                }, me.initialConfig)
 338            });
 339            me.createItems(me.shadowContainer, vBoxItems);
 340
 341            // Allow the Splitters to orientate themselves
 342            if (me.splitters.north) {
 343                me.splitters.north.ownerCt = me.shadowContainer;
 344            }
 345            if (me.splitters.south) {
 346                me.splitters.south.ownerCt = me.shadowContainer;
 347            }
 348
 349            // Inject items into the HBox Container if there is one - if there was an east or west.
 350            if (me.embeddedContainer) {
 351                me.embeddedContainer.ownerCt = me.shadowContainer;
 352                me.createItems(me.embeddedContainer, hBoxItems);
 353
 354                // Allow the Splitters to orientate themselves
 355                if (me.splitters.east) {
 356                    me.splitters.east.ownerCt = me.embeddedContainer;
 357                }
 358                if (me.splitters.west) {
 359                    me.splitters.west.ownerCt = me.embeddedContainer;
 360                }
 361
 362                // These spliiters need to be constrained by components one-level below
 363                // the component in their vobx. We update the min/maxHeight on the helper
 364                // (embeddedContainer) prior to starting the split/drag. This has to be
 365                // done on-the-fly to allow min/maxHeight of the E/C/W regions to be set
 366                // dynamically.
 367                Ext.each([me.splitters.north, me.splitters.south], function (splitter) {
 368                    if (splitter) {
 369                        splitter.on('beforedragstart', me.fixHeightConstraints, me);
 370                    }
 371                });
 372
 373                // The east or west region wanted a percentage
 374                if (horizontalFlex) {
 375                    regions.center.flex -= horizontalFlex;
 376                }
 377                // The north or south region wanted a percentage
 378                if (verticalFlex) {
 379                    me.embeddedContainer.flex -= verticalFlex;
 380                }
 381            } else {
 382                // The north or south region wanted a percentage
 383                if (verticalFlex) {
 384                    regions.center.flex -= verticalFlex;
 385                }
 386            }
 387        }
 388        // If we have no north or south, then there's only one Container, and it's
 389        // an HBox, or, if only a center region was specified, a Fit.
 390        else {
 391            me.shadowContainer = Ext.create('Ext.container.Container', {
 392                ownerCt: me.owner,
 393                el: me.getTarget(),
 394                layout: Ext.applyIf({
 395                    type: (hBoxItems.length == 1) ? 'fit' : 'hbox',
 396                    align: 'stretch'
 397                }, me.initialConfig)
 398            });
 399            me.createItems(me.shadowContainer, hBoxItems);
 400
 401            // Allow the Splitters to orientate themselves
 402            if (me.splitters.east) {
 403                me.splitters.east.ownerCt = me.shadowContainer;
 404            }
 405            if (me.splitters.west) {
 406                me.splitters.west.ownerCt = me.shadowContainer;
 407            }
 408
 409            // The east or west region wanted a percentage
 410            if (horizontalFlex) {
 411                regions.center.flex -= verticalFlex;
 412            }
 413        }
 414
 415        // Create upward links from the region Components to their shadow ownerCts
 416        for (i = 0, items = me.shadowContainer.items.items, ln = items.length; i &lt; ln; i++) {
 417            items[i].shadowOwnerCt = me.shadowContainer;
 418        }
 419        if (me.embeddedContainer) {
 420            for (i = 0, items = me.embeddedContainer.items.items, ln = items.length; i &lt; ln; i++) {
 421                items[i].shadowOwnerCt = me.embeddedContainer;
 422            }
 423        }
 424
 425        // This is the layout that we delegate all operations to
 426        me.shadowLayout = me.shadowContainer.getLayout();
 427
 428        me.borderLayoutInitialized = true;
 429    },
 430
 431    setupState: function(comp){
 432        var getState = comp.getState;
 433        comp.getState = function(){
 434            // call the original getState
 435            var state = getState.call(comp) || {},
 436                region = comp.region;
 437
 438            state.collapsed = !!comp.collapsed;
 439            if (region == 'west' || region == 'east') {
 440                state.width = comp.getWidth();
 441            } else {
 442                state.height = comp.getHeight();
 443            }
 444            return state;
 445        };
 446        comp.addStateEvents(['collapse', 'expand', 'resize']);
 447    },
 448
 449<span id='Ext-layout-container-Border-method-createItems'>    /**
 450</span>     * Create the items collection for our shadow/embedded containers
 451     * @private
 452     */
 453    createItems: function(container, items){
 454        // Have to inject an items Collection *after* construction.
 455        // The child items of the shadow layout must retain their original, user-defined ownerCt
 456        delete container.items;
 457        container.initItems();
 458        container.items.addAll(items);
 459    },
 460
 461    // Private
 462    // Create a splitter for a child of the layout.
 463    createSplitter: function(comp) {
 464        var me = this,
 465            interceptCollapse = (comp.collapseMode != 'header'),
 466            resizer;
 467
 468        resizer = Ext.create('Ext.resizer.Splitter', {
 469            hidden: !!comp.hidden,
 470            collapseTarget: comp,
 471            performCollapse: !interceptCollapse,
 472            listeners: interceptCollapse ? {
 473                click: {
 474                    fn: Ext.Function.bind(me.onSplitterCollapseClick, me, [comp]),
 475                    element: 'collapseEl'
 476                }
 477            } : null
 478        });
 479
 480        // Mini collapse means that the splitter is the placeholder Component
 481        if (comp.collapseMode == 'mini') {
 482            comp.placeholder = resizer;
 483            resizer.collapsedCls = comp.collapsedCls;
 484        }
 485
 486        // Arrange to hide/show a region's associated splitter when the region is hidden/shown
 487        comp.on({
 488            hide: me.onRegionVisibilityChange,
 489            show: me.onRegionVisibilityChange,
 490            scope: me
 491        });
 492        return resizer;
 493    },
 494
 495    // Private
 496    // Propagates the min/maxHeight values from the inner hbox items to its container.
 497    fixHeightConstraints: function () {
 498        var me = this,
 499            ct = me.embeddedContainer,
 500            maxHeight = 1e99, minHeight = -1;
 501
 502        if (!ct) {
 503            return;
 504        }
 505
 506        ct.items.each(function (item) {
 507            if (Ext.isNumber(item.maxHeight)) {
 508                maxHeight = Math.max(maxHeight, item.maxHeight);
 509            }
 510            if (Ext.isNumber(item.minHeight)) {
 511                minHeight = Math.max(minHeight, item.minHeight);
 512            }
 513        });
 514
 515        ct.maxHeight = maxHeight;
 516        ct.minHeight = minHeight;
 517    },
 518
 519    // Hide/show a region's associated splitter when the region is hidden/shown
 520    onRegionVisibilityChange: function(comp){
 521        this.splitters[comp.region][comp.hidden ? 'hide' : 'show']();
 522        this.layout();
 523    },
 524
 525    // Called when a splitter mini-collapse tool is clicked on.
 526    // The listener is only added if this layout is controlling collapsing,
 527    // not if the component's collapseMode is 'mini' or 'header'.
 528    onSplitterCollapseClick: function(comp) {
 529        if (comp.collapsed) {
 530            this.onPlaceHolderToolClick(null, null, null, {client: comp});
 531        } else {
 532            comp.collapse();
 533        }
 534    },
 535
 536<span id='Ext-layout-container-Border-method-getPlaceholder'>    /**
 537</span>     * Return the {@link Ext.panel.Panel#placeholder placeholder} Component to which the passed child Panel of the
 538     * layout will collapse. By default, this will be a {@link Ext.panel.Header Header} component (Docked to the
 539     * appropriate border). See {@link Ext.panel.Panel#placeholder placeholder}. config to customize this.
 540     *
 541     * **Note that this will be a fully instantiated Component, but will only be _rendered_ when the Panel is first
 542     * collapsed.**
 543     * @param {Ext.panel.Panel} panel The child Panel of the layout for which to return the {@link
 544     * Ext.panel.Panel#placeholder placeholder}.
 545     * @return {Ext.Component} The Panel's {@link Ext.panel.Panel#placeholder placeholder} unless the {@link
 546     * Ext.panel.Panel#collapseMode collapseMode} is `'header'`, in which case _undefined_ is returned.
 547     */
 548    getPlaceholder: function(comp) {
 549        var me = this,
 550            placeholder = comp.placeholder,
 551            shadowContainer = comp.shadowOwnerCt,
 552            shadowLayout = shadowContainer.layout,
 553            oppositeDirection = Ext.panel.Panel.prototype.getOppositeDirection(comp.collapseDirection),
 554            horiz = (comp.region == 'north' || comp.region == 'south');
 555
 556        // No placeholder if the collapse mode is not the Border layout default
 557        if (comp.collapseMode == 'header') {
 558            return;
 559        }
 560
 561        // Provide a replacement Container with an expand tool
 562        if (!placeholder) {
 563            if (comp.collapseMode == 'mini') {
 564                placeholder = Ext.create('Ext.resizer.Splitter', {
 565                    id: 'collapse-placeholder-' + comp.id,
 566                    collapseTarget: comp,
 567                    performCollapse: false,
 568                    listeners: {
 569                        click: {
 570                            fn: Ext.Function.bind(me.onSplitterCollapseClick, me, [comp]),
 571                            element: 'collapseEl'
 572                        }
 573                    }
 574                });
 575                placeholder.addCls(placeholder.collapsedCls);
 576            } else {
 577                placeholder = {
 578                    id: 'collapse-placeholder-' + comp.id,
 579                    margins: comp.initialConfig.margins || Ext.getClass(comp).prototype.margins,
 580                    xtype: 'header',
 581                    orientation: horiz ? 'horizontal' : 'vertical',
 582                    title: comp.title,
 583                    textCls: comp.headerTextCls,
 584                    iconCls: comp.iconCls,
 585                    baseCls: comp.baseCls + '-header',
 586                    ui: comp.ui,
 587                    indicateDrag: comp.draggable,
 588                    cls: Ext.baseCSSPrefix + 'region-collapsed-placeholder ' + Ext.baseCSSPrefix + 'region-collapsed-' + comp.collapseDirection + '-placeholder ' + comp.collapsedCls,
 589                    listeners: comp.floatable ? {
 590                        click: {
 591                            fn: function(e) {
 592                                me.floatCollapsedPanel(e, comp);
 593                            },
 594                            element: 'el'
 595                        }
 596                    } : null
 597                };
 598                // Hack for IE6/7/IEQuirks's inability to display an inline-block
 599                if ((Ext.isIE6 || Ext.isIE7 || (Ext.isIEQuirks)) &amp;&amp; !horiz) {
 600                    placeholder.width = 25;
 601                }
 602                if (!comp.hideCollapseTool) {
 603                    placeholder[horiz ? 'tools' : 'items'] = [{
 604                        xtype: 'tool',
 605                        client: comp,
 606                        type: 'expand-' + oppositeDirection,
 607                        handler: me.onPlaceHolderToolClick,
 608                        scope: me
 609                    }];
 610                }
 611            }
 612            placeholder = me.owner.createComponent(placeholder);
 613            if (comp.isXType('panel')) {
 614                comp.on({
 615                    titlechange: me.onRegionTitleChange,
 616                    iconchange: me.onRegionIconChange,
 617                    scope: me
 618                });
 619            }
 620        }
 621
 622        // The collapsed Component holds a reference to its placeholder and vice versa
 623        comp.placeholder = placeholder;
 624        placeholder.comp = comp;
 625
 626        return placeholder;
 627    },
 628
 629<span id='Ext-layout-container-Border-method-onRegionTitleChange'>    /**
 630</span>     * @private
 631     * Update the placeholder title when panel title has been set or changed.
 632     */
 633    onRegionTitleChange: function(comp, newTitle) {
 634        comp.placeholder.setTitle(newTitle);
 635    },
 636
 637<span id='Ext-layout-container-Border-method-onRegionIconChange'>    /**
 638</span>     * @private
 639     * Update the placeholder iconCls when panel iconCls has been set or changed.
 640     */
 641    onRegionIconChange: function(comp, newIconCls) {
 642        comp.placeholder.setIconCls(newIconCls);
 643    },
 644
 645<span id='Ext-layout-container-Border-method-calculateChildBox'>    /**
 646</span>     * @private
 647     * Calculates the size and positioning of the passed child item. Must be present because Panel's expand,
 648     * when configured with a flex, calls this method on its ownerCt's layout.
 649     * @param {Ext.Component} child The child Component to calculate the box for
 650     * @return {Object} Object containing box measurements for the child. Properties are left,top,width,height.
 651     */
 652    calculateChildBox: function(comp) {
 653        var me = this;
 654        if (me.shadowContainer.items.contains(comp)) {
 655            return me.shadowContainer.layout.calculateChildBox(comp);
 656        }
 657        else if (me.embeddedContainer &amp;&amp; me.embeddedContainer.items.contains(comp)) {
 658            return me.embeddedContainer.layout.calculateChildBox(comp);
 659        }
 660    },
 661
 662<span id='Ext-layout-container-Border-method-onBeforeRegionCollapse'>    /**
 663</span>     * @private
 664     * Intercepts the Panel's own collapse event and perform's substitution of the Panel
 665     * with a placeholder Header orientated in the appropriate dimension.
 666     * @param comp The Panel being collapsed.
 667     * @param direction
 668     * @param animate
 669     * @returns {Boolean} false to inhibit the Panel from performing its own collapse.
 670     */
 671    onBeforeRegionCollapse: function(comp, direction, animate) {
 672        if (comp.collapsedChangingLayout) {
 673            //&lt;debug warn&gt;
 674            if (Ext.global.console &amp;&amp; Ext.global.console.warn) {
 675                Ext.global.console.warn(Ext.getDisplayName(arguments.callee), 'aborted because the collapsed state is in the middle of changing');
 676            }
 677            //&lt;/debug&gt;
 678            return false;
 679        }
 680        comp.collapsedChangingLayout = true;
 681        var me = this,
 682            compEl = comp.el,
 683            width,
 684            miniCollapse = comp.collapseMode == 'mini',
 685            shadowContainer = comp.shadowOwnerCt,
 686            shadowLayout = shadowContainer.layout,
 687            placeholder = comp.placeholder,
 688            sl = me.owner.suspendLayout,
 689            scsl = shadowContainer.suspendLayout,
 690            isNorthOrWest = (comp.region == 'north' || comp.region == 'west'); // Flag to keep the placeholder non-adjacent to any Splitter
 691
 692        // Do not trigger a layout during transition to collapsed Component
 693        me.owner.suspendLayout = true;
 694        shadowContainer.suspendLayout = true;
 695
 696        // Prevent upward notifications from downstream layouts
 697        shadowLayout.layoutBusy = true;
 698        if (shadowContainer.componentLayout) {
 699            shadowContainer.componentLayout.layoutBusy = true;
 700        }
 701        me.shadowContainer.layout.layoutBusy = true;
 702        me.layoutBusy = true;
 703        me.owner.componentLayout.layoutBusy = true;
 704
 705        // Provide a replacement Container with an expand tool
 706        if (!placeholder) {
 707            placeholder = me.getPlaceholder(comp);
 708        }
 709
 710        // placeholder already in place; show it.
 711        if (placeholder.shadowOwnerCt === shadowContainer) {
 712            placeholder.show();
 713        }
 714        // Insert the collapsed placeholder Component into the appropriate Box layout shadow Container
 715        // It must go next to its client Component, but non-adjacent to the splitter so splitter can find its collapse client.
 716        // Inject an ownerCt value pointing to the owner, border layout Container as the user will expect.
 717        else {
 718            shadowContainer.insert(shadowContainer.items.indexOf(comp) + (isNorthOrWest ? 0 : 1), placeholder);
 719            placeholder.shadowOwnerCt = shadowContainer;
 720            placeholder.ownerCt = me.owner;
 721        }
 722
 723        // Flag the collapsing Component as hidden and show the placeholder.
 724        // This causes the shadow Box layout's calculateChildBoxes to calculate the correct new arrangement.
 725        // We hide or slideOut the Component's element
 726        comp.hidden = true;
 727
 728        if (!placeholder.rendered) {
 729            shadowLayout.renderItem(placeholder, shadowLayout.innerCt);
 730
 731            // The inserted placeholder does not have the proper size, so copy the width
 732            // for N/S or the height for E/W from the component. This fixes EXTJSIV-1562
 733            // without recursive layouts. This is only an issue initially. After this time,
 734            // placeholder will have the correct width/height set by the layout (which has
 735            // already happened when we get here initially).
 736            if (comp.region == 'north' || comp.region == 'south') {
 737                placeholder.setCalculatedSize(comp.getWidth());
 738            } else {
 739                placeholder.setCalculatedSize(undefined, comp.getHeight());
 740            }
 741        }
 742
 743        // Jobs to be done after the collapse has been done
 744        function afterCollapse() {
 745            // Reinstate automatic laying out.
 746            me.owner.suspendLayout = sl;
 747            shadowContainer.suspendLayout = scsl;
 748            delete shadowLayout.layoutBusy;
 749            if (shadowContainer.componentLayout) {
 750                delete shadowContainer.componentLayout.layoutBusy;
 751            }
 752            delete me.shadowContainer.layout.layoutBusy;
 753            delete me.layoutBusy;
 754            delete me.owner.componentLayout.layoutBusy;
 755            delete comp.collapsedChangingLayout;
 756
 757            // Fire the collapse event: The Panel has in fact been collapsed, but by substitution of an alternative Component
 758            comp.collapsed = true;
 759            comp.fireEvent('collapse', comp);
 760        }
 761
 762        /*
 763         * Set everything to the new positions. Note that we
 764         * only want to animate the collapse if it wasn't configured
 765         * initially with collapsed: true
 766         */
 767        if (comp.animCollapse &amp;&amp; me.initialCollapsedComplete) {
 768            shadowLayout.layout();
 769            compEl.dom.style.zIndex = 100;
 770
 771            // If we're mini-collapsing, the placholder is a Splitter. We don't want it to &quot;bounce in&quot;
 772            if (!miniCollapse) {
 773                placeholder.el.hide();
 774            }
 775            compEl.slideOut(me.slideDirection[comp.region], {
 776                duration: Ext.Number.from(comp.animCollapse, Ext.fx.Anim.prototype.duration),
 777                listeners: {
 778                    afteranimate: function() {
 779                        compEl.show().setLeftTop(-10000, -10000);
 780                        compEl.dom.style.zIndex = '';
 781
 782                        // If we're mini-collapsing, the placholder is a Splitter. We don't want it to &quot;bounce in&quot;
 783                       if (!miniCollapse) {
 784                            placeholder.el.slideIn(me.slideDirection[comp.region], {
 785                                easing: 'linear',
 786                                duration: 100
 787                            });
 788                        }
 789                        afterCollapse();
 790                    }
 791                }
 792            });
 793        } else {
 794            compEl.setLeftTop(-10000, -10000);
 795            shadowLayout.layout();
 796            afterCollapse();
 797        }
 798
 799        return false;
 800    },
 801
 802    // Hijack the expand operation to remove the placeholder and slide the region back in.
 803    onBeforeRegionExpand: function(comp, animate) {
 804        // We don't check for comp.collapsedChangingLayout here because onPlaceHolderToolClick does it
 805        this.onPlaceHolderToolClick(null, null, null, {client: comp, shouldFireBeforeexpand: false});
 806        return false;
 807    },
 808
 809    // Called when the collapsed placeholder is clicked to reinstate a &quot;collapsed&quot; (in reality hidden) Panel.
 810    onPlaceHolderToolClick: function(e, target, owner, tool) {
 811        var me = this,
 812            comp = tool.client,
 813
 814            // Hide the placeholder unless it was the Component's preexisting splitter
 815            hidePlaceholder = (comp.collapseMode != 'mini') || !comp.split,
 816            compEl = comp.el,
 817            toCompBox,
 818            placeholder = comp.placeholder,
 819            placeholderEl = placeholder.el,
 820            shadowContainer = comp.shadowOwnerCt,
 821            shadowLayout = shadowContainer.layout,
 822            curSize,
 823            sl = me.owner.suspendLayout,
 824            scsl = shadowContainer.suspendLayout,
 825            isFloating;
 826
 827        if (comp.collapsedChangingLayout) {
 828            //&lt;debug warn&gt;
 829            if (Ext.global.console &amp;&amp; Ext.global.console.warn) {
 830                Ext.global.console.warn(Ext.getDisplayName(arguments.callee), 'aborted because the collapsed state is in the middle of changing');
 831            }
 832            //&lt;/debug&gt;
 833            return false;
 834        }
 835        if (tool.shouldFireBeforeexpand !== false &amp;&amp; comp.fireEvent('beforeexpand', comp, true) === false) {
 836            return false;
 837        }
 838        comp.collapsedChangingLayout = true;
 839        // If the slide in is still going, stop it.
 840        // This will either leave the Component in its fully floated state (which is processed below)
 841        // or in its collapsed state. Either way, we expand it..
 842        if (comp.getActiveAnimation()) {
 843            comp.stopAnimation();
 844        }
 845
 846        // If the Component is fully floated when they click the placeholder Tool,
 847        // it will be primed with a slide out animation object... so delete that
 848        // and remove the mouseout listeners
 849        if (comp.slideOutAnim) {
 850            // Remove mouse leave monitors
 851            compEl.un(comp.panelMouseMon);
 852            placeholderEl.un(comp.placeholderMouseMon);
 853
 854            delete comp.slideOutAnim;
 855            delete comp.panelMouseMon;
 856            delete comp.placeholderMouseMon;
 857
 858            // If the Panel was floated and primed with a slideOut animation, we don't want to animate its layout operation.
 859            isFloating = true;
 860        }
 861
 862        // Do not trigger a layout during transition to expanded Component
 863        me.owner.suspendLayout = true;
 864        shadowContainer.suspendLayout = true;
 865
 866        // Prevent upward notifications from downstream layouts
 867        shadowLayout.layoutBusy = true;
 868        if (shadowContainer.componentLayout) {
 869            shadowContainer.componentLayout.layoutBusy = true;
 870        }
 871        me.shadowContainer.layout.layoutBusy = true;
 872        me.layoutBusy = true;
 873        me.owner.componentLayout.layoutBusy = true;
 874
 875        // Unset the hidden and collapsed flags set in onBeforeRegionCollapse. The shadowLayout will now take it into account
 876        // Find where the shadow Box layout plans to put the expanding Component.
 877        comp.hidden = false;
 878        comp.collapsed = false;
 879        if (hidePlaceholder) {
 880            placeholder.hidden = true;
 881        }
 882        toCompBox = shadowLayout.calculateChildBox(comp);
 883
 884        // Show the collapse tool in case it was hidden by the slide-in
 885        if (comp.collapseTool) {
 886            comp.collapseTool.show();
 887        }
 888
 889        // If we're going to animate, we need to hide the component before moving it back into position
 890        if (comp.animCollapse &amp;&amp; !isFloating) {
 891            compEl.setStyle('visibility', 'hidden');
 892        }
 893        compEl.setLeftTop(toCompBox.left, toCompBox.top);
 894
 895        // Equalize the size of the expanding Component prior to animation
 896        // in case the layout area has changed size during the time it was collapsed.
 897        curSize = comp.getSize();
 898        if (curSize.height != toCompBox.height || curSize.width != toCompBox.width) {
 899            me.setItemSize(comp, toCompBox.width, toCompBox.height);
 900        }
 901
 902        // Jobs to be done after the expand has been done
 903        function afterExpand() {
 904            // Reinstate automatic laying out.
 905            me.owner.suspendLayout = sl;
 906            shadowContainer.suspendLayout = scsl;
 907            delete shadowLayout.layoutBusy;
 908            if (shadowContainer.componentLayout) {
 909                delete shadowContainer.componentLayout.layoutBusy;
 910            }
 911            delete me.shadowContainer.layout.layoutBusy;
 912            delete me.layoutBusy;
 913            delete me.owner.componentLayout.layoutBusy;
 914            delete comp.collapsedChangingLayout;
 915
 916            // In case it was floated out and they clicked the re-expand tool
 917            comp.removeCls(Ext.baseCSSPrefix + 'border-region-slide-in');
 918
 919            // Fire the expand event: The Panel has in fact been expanded, but by removal of an alternative Component
 920            comp.fireEvent('expand', comp);
 921        }
 922
 923        // Hide the placeholder
 924        if (hidePlaceholder) {
 925            placeholder.el.hide();
 926        }
 927
 928        // Slide the expanding Component to its new position.
 929        // When that is done, layout the layout.
 930        if (comp.animCollapse &amp;&amp; !isFloating) {
 931            compEl.dom.style.zIndex = 100;
 932            compEl.slideIn(me.slideDirection[comp.region], {
 933                duration: Ext.Number.from(comp.animCollapse, Ext.fx.Anim.prototype.duration),
 934                listeners: {
 935                    afteranimate: function() {
 936                        compEl.dom.style.zIndex = '';
 937                        comp.hidden = false;
 938                        shadowLayout.onLayout();
 939                        afterExpand();
 940                    }
 941                }
 942            });
 943        } else {
 944            shadowLayout.onLayout();
 945            afterExpand();
 946        }
 947    },
 948
 949    floatCollapsedPanel: function(e, comp) {
 950
 951        if (comp.floatable === false) {
 952            return;
 953        }
 954
 955        var me = this,
 956            compEl = comp.el,
 957            placeholder = comp.placeholder,
 958            placeholderEl = placeholder.el,
 959            shadowContainer = comp.shadowOwnerCt,
 960            shadowLayout = shadowContainer.layout,
 961            placeholderBox = shadowLayout.getChildBox(placeholder),
 962            scsl = shadowContainer.suspendLayout,
 963            curSize, toCompBox, compAnim;
 964
 965        // Ignore clicks on tools.
 966        if (e.getTarget('.' + Ext.baseCSSPrefix + 'tool')) {
 967            return;
 968        }
 969
 970        // It's *being* animated, ignore the click.
 971        // Possible future enhancement: Stop and *reverse* the current active Fx.
 972        if (compEl.getActiveAnimation()) {
 973            return;
 974        }
 975
 976        // If the Component is already fully floated when they click the placeholder,
 977        // it will be primed with a slide out animation object... so slide it out.
 978        if (comp.slideOutAnim) {
 979            me.slideOutFloatedComponent(comp);
 980            return;
 981        }
 982
 983        // Function to be called when the mouse leaves the floated Panel
 984        // Slide out when the mouse leaves the region bounded by the slid Component and its placeholder.
 985        function onMouseLeaveFloated(e) {
 986            var slideRegion = compEl.getRegion().union(placeholderEl.getRegion()).adjust(1, -1, -1, 1);
 987
 988            // If mouse is not within slide Region, slide it out
 989            if (!slideRegion.contains(e.getPoint())) {
 990                me.slideOutFloatedComponent(comp);
 991            }
 992        }
 993
 994        // Monitor for mouseouting of the placeholder. Hide it if they exit for half a second or more
 995        comp.placeholderMouseMon = placeholderEl.monitorMouseLeave(500, onMouseLeaveFloated);
 996
 997        // Do not trigger a layout during slide out of the Component
 998        shadowContainer.suspendLayout = true;
 999
1000        // Prevent upward notifications from downstream layouts
1001        me.layoutBusy = true;
1002        me.owner.componentLayout.layoutBusy = true;
1003
1004        // The collapse tool is hidden while slid.
1005        // It is re-shown on expand.
1006        if (comp.collapseTool) {
1007            comp.collapseTool.hide();
1008        }
1009
1010        // Set flags so that the layout will calculate the boxes for what we want
1011        comp.hidden = false;
1012        comp.collapsed = false;
1013        placeholder.hidden = true;
1014
1015        // Recalculate new arrangement of the Component being floated.
1016        toCompBox = shadowLayout.calculateChildBox(comp);
1017        placeholder.hidden = false;
1018
1019        // Component to appear just after the placeholder, whatever &quot;after&quot; means in the context of the shadow Box layout.
1020        if (comp.region == 'north' || comp.region == 'west') {
1021            toCompBox[shadowLayout.parallelBefore] += placeholderBox[shadowLayout.parallelPrefix] - 1;
1022        } else {
1023            toCompBox[shadowLayout.parallelBefore] -= (placeholderBox[shadowLayout.parallelPrefix] - 1);
1024        }
1025        compEl.setStyle('visibility', 'hidden');
1026        compEl.setLeftTop(toCompBox.left, toCompBox.top);
1027
1028        // Equalize the size of the expanding Component prior to animation
1029        // in case the layout area has changed size during the time it was collapsed.
1030        curSize = comp.getSize();
1031        if (curSize.height != toCompBox.height || curSize.width != toCompBox.width) {
1032            me.setItemSize(comp, toCompBox.width, toCompBox.height);
1033        }
1034
1035        // This animation slides the collapsed Component's el out to just beyond its placeholder
1036        compAnim = {
1037            listeners: {
1038                afteranimate: function() {
1039                    shadowContainer.suspendLayout = scsl;
1040                    delete me.layoutBusy;
1041                    delete me.owner.componentLayout.layoutBusy;
1042
1043                    // Prime the Component with an Anim config object to slide it back out
1044                    compAnim.listeners = {
1045                        afterAnimate: function() {
1046                            compEl.show().removeCls(Ext.baseCSSPrefix + 'border-region-slide-in').setLeftTop(-10000, -10000);
1047
1048                            // Reinstate the correct, current state after slide out animation finishes
1049                            comp.hidden = true;
1050                            comp.collapsed = true;
1051                            delete comp.slideOutAnim;
1052                            delete comp.panelMouseMon;
1053                            delete comp.placeholderMouseMon;
1054                        }
1055                    };
1056                    comp.slideOutAnim = compAnim;
1057                }
1058            },
1059            duration: 500
1060        };
1061
1062        // Give the element the correct class which places it at a high z-index
1063        compEl.addCls(Ext.baseCSSPrefix + 'border-region-slide-in');
1064
1065        // Begin the slide in
1066        compEl.slideIn(me.slideDirection[comp.region], compAnim);
1067
1068        // Monitor for mouseouting of the slid area. Hide it if they exit for half a second or more
1069        comp.panelMouseMon = compEl.monitorMouseLeave(500, onMouseLeaveFloated);
1070
1071    },
1072
1073    slideOutFloatedComponent: function(comp) {
1074        var compEl = comp.el,
1075            slideOutAnim;
1076
1077        // Remove mouse leave monitors
1078        compEl.un(comp.panelMouseMon);
1079        comp.placeholder.el.un(comp.placeholderMouseMon);
1080
1081        // Slide the Component out
1082        compEl.slideOut(this.slideDirection[comp.region], comp.slideOutAnim);
1083
1084        delete comp.slideOutAnim;
1085        delete comp.panelMouseMon;
1086        delete comp.placeholderMouseMon;
1087    },
1088
1089    /*
1090     * @private
1091     * Ensure any collapsed placeholder Component is destroyed along with its region.
1092     * Can't do this in onDestroy because they may remove a Component and use it elsewhere.
1093     */
1094    onRegionDestroy: function(comp) {
1095        var placeholder = comp.placeholder;
1096        if (placeholder) {
1097            delete placeholder.ownerCt;
1098            placeholder.destroy();
1099        }
1100    },
1101
1102    /*
1103     * @private
1104     * Ensure any shadow Containers are destroyed.
1105     * Ensure we don't keep references to Components.
1106     */
1107    onDestroy: function() {
1108        var me = this,
1109            shadowContainer = me.shadowContainer,
1110            embeddedContainer = me.embeddedContainer;
1111
1112        if (shadowContainer) {
1113            delete shadowContainer.ownerCt;
1114            Ext.destroy(shadowContainer);
1115        }
1116
1117        if (embeddedContainer) {
1118            delete embeddedContainer.ownerCt;
1119            Ext.destroy(embeddedContainer);
1120        }
1121        delete me.regions;
1122        delete me.splitters;
1123        delete me.shadowContainer;
1124        delete me.embeddedContainer;
1125        me.callParent(arguments);
1126    }
1127});
1128</pre>
1129</body>
1130</html>