Upgrade to ExtJS 4.0.7 - Released 10/19/2011
[extjs.git] / src / panel / Panel.js
index 845680b..af479cb 100644 (file)
+/*
+
+This file is part of Ext JS 4
+
+Copyright (c) 2011 Sencha Inc
+
+Contact:  http://www.sencha.com/contact
+
+GNU General Public License Usage
+This file may be used under the terms of the GNU General Public License version 3.0 as published by the Free Software Foundation and appearing in the file LICENSE included in the packaging of this file.  Please review the following information to ensure the GNU General Public License version 3.0 requirements will be met: http://www.gnu.org/copyleft/gpl.html.
+
+If you are unsure which license is appropriate for your use, please contact the sales department at http://www.sencha.com/contact.
+
+*/
 /**
- * @class Ext.panel.Panel
- * @extends Ext.panel.AbstractPanel
- * <p>Panel is a container that has specific functionality and structural components that make
- * it the perfect building block for application-oriented user interfaces.</p>
- * <p>Panels are, by virtue of their inheritance from {@link Ext.container.Container}, capable
- * of being configured with a {@link Ext.container.Container#layout layout}, and containing child Components.</p>
- * <p>When either specifying child {@link Ext.Component#items items} of a Panel, or dynamically {@link Ext.container.Container#add adding} Components
- * to a Panel, remember to consider how you wish the Panel to arrange those child elements, and whether
- * those child elements need to be sized using one of Ext&#39;s built-in <code><b>{@link Ext.container.Container#layout layout}</b></code> schemes. By
- * default, Panels use the {@link Ext.layout.container.Auto Auto} scheme. This simply renders
- * child components, appending them one after the other inside the Container, and <b>does not apply any sizing</b>
- * at all.</p>
+ * Panel is a container that has specific functionality and structural components that make it the perfect building
+ * block for application-oriented user interfaces.
+ *
+ * Panels are, by virtue of their inheritance from {@link Ext.container.Container}, capable of being configured with a
+ * {@link Ext.container.Container#layout layout}, and containing child Components.
+ *
+ * When either specifying child {@link #items} of a Panel, or dynamically {@link Ext.container.Container#add adding}
+ * Components to a Panel, remember to consider how you wish the Panel to arrange those child elements, and whether those
+ * child elements need to be sized using one of Ext's built-in `{@link Ext.container.Container#layout layout}`
+ * schemes. By default, Panels use the {@link Ext.layout.container.Auto Auto} scheme. This simply renders child
+ * components, appending them one after the other inside the Container, and **does not apply any sizing** at all.
+ *
  * {@img Ext.panel.Panel/panel.png Panel components}
- * <p>A Panel may also contain {@link #bbar bottom} and {@link #tbar top} toolbars, along with separate
- * {@link #header}, {@link #footer} and {@link #body} sections (see {@link #frame} for additional
- * information).</p>
- * <p>Panel also provides built-in {@link #collapsible collapsible, expandable} and {@link #closable} behavior.
- * Panels can be easily dropped into any {@link Ext.container.Container Container} or layout, and the
- * layout and rendering pipeline is {@link Ext.container.Container#add completely managed by the framework}.</p>
- * <p><b>Note:</b> By default, the <code>{@link #closable close}</code> header tool <i>destroys</i> the Panel resulting in removal of the Panel
- * and the destruction of any descendant Components. This makes the Panel object, and all its descendants <b>unusable</b>. To enable the close
- * tool to simply <i>hide</i> a Panel for later re-use, configure the Panel with <b><code>{@link #closeAction closeAction: 'hide'}</code></b>.</p>
- * <p>Usually, Panels are used as constituents within an application, in which case, they would be used as child items of Containers,
- * and would themselves use Ext.Components as child {@link #items}. However to illustrate simply rendering a Panel into the document,
- * here&#39;s how to do it:<pre><code>
-Ext.create('Ext.panel.Panel', {
-    title: 'Hello',
-    width: 200,
-    html: '&lt;p&gt;World!&lt;/p&gt;',
-    renderTo: document.body
-});
-</code></pre></p>
- * <p>A more realistic scenario is a Panel created to house input fields which will not be rendered, but used as a constituent part of a Container:<pre><code>
-var filterPanel = Ext.create('Ext.panel.Panel', {
-    bodyPadding: 5,  // Don&#39;t want content to crunch against the borders
-    title: 'Filters',
-    items: [{
-        xtype: 'datefield',
-        fieldLabel: 'Start date'
-    }, {
-        xtype: 'datefield',
-        fieldLabel: 'End date'
-    }]
-});
-</code></pre></p>
- * <p>Note that the Panel above is not configured to render into the document, nor is it configured with a size or position. In a real world scenario,
- * the Container into which the Panel is added will use a {@link #layout} to render, size and position its child Components.</p>
- * <p>Panels will often use specific {@link #layout}s to provide an application with shape and structure by containing and arranging child
- * Components: <pre><code>
-var resultsPanel = Ext.create('Ext.panel.Panel', {
-    title: 'Results',
-    width: 600,
-    height: 400,
-    renderTo: document.body,
-    layout: {
-        type: 'vbox',       // Arrange child items vertically
-        align: 'stretch',    // Each takes up full width
-        padding: 5
-    },
-    items: [{               // Results grid specified as a config object with an xtype of 'grid'
-        xtype: 'grid',
-        columns: [{header: 'Column One'}],            // One header just for show. There&#39;s no data,
-        store: Ext.create('Ext.data.ArrayStore', {}), // A dummy empty data store
-        flex: 1                                       // Use 1/3 of Container&#39;s height (hint to Box layout)
-    }, {
-        xtype: 'splitter'   // A splitter between the two child items
-    }, {                    // Details Panel specified as a config object (no xtype defaults to 'panel').
-        title: 'Details',
-        bodyPadding: 5,
-        items: [{
-            fieldLabel: 'Data item',
-            xtype: 'textfield'
-        }], // An array of form fields
-        flex: 2             // Use 2/3 of Container&#39;s height (hint to Box layout)
-    }]
-});
-</code></pre>
- * The example illustrates one possible method of displaying search results. The Panel contains a grid with the resulting data arranged
- * in rows. Each selected row may be displayed in detail in the Panel below. The {@link Ext.layout.container.VBox vbox} layout is used
- * to arrange the two vertically. It is configured to stretch child items horizontally to full width. Child items may either be configured
- * with a numeric height, or with a <code>flex</code> value to distribute available space proportionately.</p>
- * <p>This Panel itself may be a child item of, for exaple, a {@link Ext.tab.Panel} which will size its child items to fit within its
- * content area.</p>
- * <p>Using these techniques, as long as the <b>layout</b> is chosen and configured correctly, an application may have any level of
- * nested containment, all dynamically sized according to configuration, the user&#39;s preference and available browser size.</p>
- * @constructor
- * @param {Object} config The config object
- * @xtype panel
+ *
+ * A Panel may also contain {@link #bbar bottom} and {@link #tbar top} toolbars, along with separate {@link
+ * Ext.panel.Header header}, {@link #fbar footer} and body sections.
+ *
+ * Panel also provides built-in {@link #collapsible collapsible, expandable} and {@link #closable} behavior. Panels can
+ * be easily dropped into any {@link Ext.container.Container Container} or layout, and the layout and rendering pipeline
+ * is {@link Ext.container.Container#add completely managed by the framework}.
+ *
+ * **Note:** By default, the `{@link #closable close}` header tool _destroys_ the Panel resulting in removal of the
+ * Panel and the destruction of any descendant Components. This makes the Panel object, and all its descendants
+ * **unusable**. To enable the close tool to simply _hide_ a Panel for later re-use, configure the Panel with
+ * `{@link #closeAction closeAction}: 'hide'`.
+ *
+ * Usually, Panels are used as constituents within an application, in which case, they would be used as child items of
+ * Containers, and would themselves use Ext.Components as child {@link #items}. However to illustrate simply rendering a
+ * Panel into the document, here's how to do it:
+ *
+ *     @example
+ *     Ext.create('Ext.panel.Panel', {
+ *         title: 'Hello',
+ *         width: 200,
+ *         html: '<p>World!</p>',
+ *         renderTo: Ext.getBody()
+ *     });
+ *
+ * A more realistic scenario is a Panel created to house input fields which will not be rendered, but used as a
+ * constituent part of a Container:
+ *
+ *     @example
+ *     var filterPanel = Ext.create('Ext.panel.Panel', {
+ *         bodyPadding: 5,  // Don't want content to crunch against the borders
+ *         width: 300,
+ *         title: 'Filters',
+ *         items: [{
+ *             xtype: 'datefield',
+ *             fieldLabel: 'Start date'
+ *         }, {
+ *             xtype: 'datefield',
+ *             fieldLabel: 'End date'
+ *         }],
+ *         renderTo: Ext.getBody()
+ *     });
+ *
+ * Note that the Panel above is not configured to render into the document, nor is it configured with a size or
+ * position. In a real world scenario, the Container into which the Panel is added will use a {@link #layout} to render,
+ * size and position its child Components.
+ *
+ * Panels will often use specific {@link #layout}s to provide an application with shape and structure by containing and
+ * arranging child Components:
+ *
+ *     @example
+ *     var resultsPanel = Ext.create('Ext.panel.Panel', {
+ *         title: 'Results',
+ *         width: 600,
+ *         height: 400,
+ *         renderTo: Ext.getBody(),
+ *         layout: {
+ *             type: 'vbox',       // Arrange child items vertically
+ *             align: 'stretch',    // Each takes up full width
+ *             padding: 5
+ *         },
+ *         items: [{               // Results grid specified as a config object with an xtype of 'grid'
+ *             xtype: 'grid',
+ *             columns: [{header: 'Column One'}],            // One header just for show. There's no data,
+ *             store: Ext.create('Ext.data.ArrayStore', {}), // A dummy empty data store
+ *             flex: 1                                       // Use 1/3 of Container's height (hint to Box layout)
+ *         }, {
+ *             xtype: 'splitter'   // A splitter between the two child items
+ *         }, {                    // Details Panel specified as a config object (no xtype defaults to 'panel').
+ *             title: 'Details',
+ *             bodyPadding: 5,
+ *             items: [{
+ *                 fieldLabel: 'Data item',
+ *                 xtype: 'textfield'
+ *             }], // An array of form fields
+ *             flex: 2             // Use 2/3 of Container's height (hint to Box layout)
+ *         }]
+ *     });
+ *
+ * The example illustrates one possible method of displaying search results. The Panel contains a grid with the
+ * resulting data arranged in rows. Each selected row may be displayed in detail in the Panel below. The {@link
+ * Ext.layout.container.VBox vbox} layout is used to arrange the two vertically. It is configured to stretch child items
+ * horizontally to full width. Child items may either be configured with a numeric height, or with a `flex` value to
+ * distribute available space proportionately.
+ *
+ * This Panel itself may be a child item of, for exaple, a {@link Ext.tab.Panel} which will size its child items to fit
+ * within its content area.
+ *
+ * Using these techniques, as long as the **layout** is chosen and configured correctly, an application may have any
+ * level of nested containment, all dynamically sized according to configuration, the user's preference and available
+ * browser size.
  */
 Ext.define('Ext.panel.Panel', {
     extend: 'Ext.panel.AbstractPanel',
@@ -96,167 +126,190 @@ Ext.define('Ext.panel.Panel', {
         'Ext.util.KeyMap',
         'Ext.panel.DD',
         'Ext.XTemplate',
-        'Ext.layout.component.Dock'
+        'Ext.layout.component.Dock',
+        'Ext.util.Memento'
     ],
     alias: 'widget.panel',
     alternateClassName: 'Ext.Panel',
 
     /**
      * @cfg {String} collapsedCls
-     * A CSS class to add to the panel&#39;s element after it has been collapsed (defaults to
-     * <code>'collapsed'</code>).
+     * A CSS class to add to the panel's element after it has been collapsed.
      */
     collapsedCls: 'collapsed',
 
     /**
      * @cfg {Boolean} animCollapse
-     * <code>true</code> to animate the transition when the panel is collapsed, <code>false</code> to skip the
-     * animation (defaults to <code>true</code> if the {@link Ext.fx.Anim} class is available, otherwise <code>false</code>).
-     * May also be specified as the animation duration in milliseconds.
+     * `true` to animate the transition when the panel is collapsed, `false` to skip the animation (defaults to `true`
+     * if the {@link Ext.fx.Anim} class is available, otherwise `false`). May also be specified as the animation
+     * duration in milliseconds.
      */
     animCollapse: Ext.enableFx,
 
     /**
      * @cfg {Number} minButtonWidth
-     * Minimum width of all footer toolbar buttons in pixels (defaults to <tt>75</tt>). If set, this will
-     * be used as the default value for the <tt>{@link Ext.button.Button#minWidth}</tt> config of
-     * each Button added to the <b>footer toolbar</b> via the {@link #fbar} or {@link #buttons} configurations.
-     * It will be ignored for buttons that have a minWidth configured some other way, e.g. in their own config
-     * object or via the {@link Ext.container.Container#config-defaults defaults} of their parent container.
+     * Minimum width of all footer toolbar buttons in pixels. If set, this will be used as the default
+     * value for the {@link Ext.button.Button#minWidth} config of each Button added to the **footer toolbar** via the
+     * {@link #fbar} or {@link #buttons} configurations. It will be ignored for buttons that have a minWidth configured
+     * some other way, e.g. in their own config object or via the {@link Ext.container.Container#defaults defaults} of
+     * their parent container.
      */
     minButtonWidth: 75,
 
     /**
      * @cfg {Boolean} collapsed
-     * <code>true</code> to render the panel collapsed, <code>false</code> to render it expanded (defaults to
-     * <code>false</code>).
+     * `true` to render the panel collapsed, `false` to render it expanded.
      */
     collapsed: false,
 
     /**
      * @cfg {Boolean} collapseFirst
-     * <code>true</code> to make sure the collapse/expand toggle button always renders first (to the left of)
-     * any other tools in the panel&#39;s title bar, <code>false</code> to render it last (defaults to <code>true</code>).
+     * `true` to make sure the collapse/expand toggle button always renders first (to the left of) any other tools in
+     * the panel's title bar, `false` to render it last.
      */
     collapseFirst: true,
 
     /**
      * @cfg {Boolean} hideCollapseTool
-     * <code>true</code> to hide the expand/collapse toggle button when <code>{@link #collapsible} == true</code>,
-     * <code>false</code> to display it (defaults to <code>false</code>).
+     * `true` to hide the expand/collapse toggle button when `{@link #collapsible} == true`, `false` to display it.
      */
     hideCollapseTool: false,
 
     /**
      * @cfg {Boolean} titleCollapse
-     * <code>true</code> to allow expanding and collapsing the panel (when <code>{@link #collapsible} = true</code>)
-     * by clicking anywhere in the header bar, <code>false</code>) to allow it only by clicking to tool button
-     * (defaults to <code>false</code>)).
+     * `true` to allow expanding and collapsing the panel (when `{@link #collapsible} = true`) by clicking anywhere in
+     * the header bar, `false`) to allow it only by clicking to tool butto).
      */
     titleCollapse: false,
 
     /**
      * @cfg {String} collapseMode
-     * <p><b>Important: this config is only effective for {@link #collapsible} Panels which are direct child items of a {@link Ext.layout.container.Border border layout}.</b></p>
-     * <p>When <i>not</i> a direct child item of a {@link Ext.layout.container.Border border layout}, then the Panel&#39;s header remains visible, and the body is collapsed to zero dimensions.
-     * If the Panel has no header, then a new header (orientated correctly depending on the {@link #collapseDirection}) will be inserted to show a the title and a re-expand tool.</p>
-     * <p>When a child item of a {@link Ext.layout.container.Border border layout}, this config has two options:
-     * <div class="mdetail-params"><ul>
-     * <li><b><code>undefined/omitted</code></b><div class="sub-desc">When collapsed, a placeholder {@link Ext.panel.Header Header} is injected into the layout to represent the Panel
-     * and to provide a UI with a Tool to allow the user to re-expand the Panel.</div></li>
-     * <li><b><code>header</code></b> : <div class="sub-desc">The Panel collapses to leave its header visible as when not inside a {@link Ext.layout.container.Border border layout}.</div></li>
-     * </ul></div></p>
+     * **Important: this config is only effective for {@link #collapsible} Panels which are direct child items of a
+     * {@link Ext.layout.container.Border border layout}.**
+     *
+     * When _not_ a direct child item of a {@link Ext.layout.container.Border border layout}, then the Panel's header
+     * remains visible, and the body is collapsed to zero dimensions. If the Panel has no header, then a new header
+     * (orientated correctly depending on the {@link #collapseDirection}) will be inserted to show a the title and a re-
+     * expand tool.
+     *
+     * When a child item of a {@link Ext.layout.container.Border border layout}, this config has two options:
+     *
+     * - **`undefined/omitted`**
+     *
+     *   When collapsed, a placeholder {@link Ext.panel.Header Header} is injected into the layout to represent the Panel
+     *   and to provide a UI with a Tool to allow the user to re-expand the Panel.
+     *
+     * - **`header`** :
+     *
+     *   The Panel collapses to leave its header visible as when not inside a {@link Ext.layout.container.Border border
+     *   layout}.
      */
 
     /**
-     * @cfg {Mixed} placeholder
-     * <p><b>Important: This config is only effective for {@link #collapsible} Panels which are direct child items of a {@link Ext.layout.container.Border border layout}
-     * when not using the <code>'header'</code> {@link #collapseMode}.</b></p>
-     * <p><b>Optional.</b> A Component (or config object for a Component) to show in place of this Panel when this Panel is collapsed by a
-     * {@link Ext.layout.container.Border border layout}. Defaults to a generated {@link Ext.panel.Header Header}
-     * containing a {@link Ext.panel.Tool Tool} to re-expand the Panel.</p>
+     * @cfg {Ext.Component/Object} placeholder
+     * **Important: This config is only effective for {@link #collapsible} Panels which are direct child items of a
+     * {@link Ext.layout.container.Border border layout} when not using the `'header'` {@link #collapseMode}.**
+     *
+     * **Optional.** A Component (or config object for a Component) to show in place of this Panel when this Panel is
+     * collapsed by a {@link Ext.layout.container.Border border layout}. Defaults to a generated {@link Ext.panel.Header
+     * Header} containing a {@link Ext.panel.Tool Tool} to re-expand the Panel.
      */
 
     /**
      * @cfg {Boolean} floatable
-     * <p><b>Important: This config is only effective for {@link #collapsible} Panels which are direct child items of a {@link Ext.layout.container.Border border layout}.</b></p>
-     * <tt>true</tt> to allow clicking a collapsed Panel&#39;s {@link #placeholder} to display the Panel floated
-     * above the layout, <tt>false</tt> to force the user to fully expand a collapsed region by
-     * clicking the expand button to see it again (defaults to <tt>true</tt>).
+     * **Important: This config is only effective for {@link #collapsible} Panels which are direct child items of a
+     * {@link Ext.layout.container.Border border layout}.**
+     *
+     * true to allow clicking a collapsed Panel's {@link #placeholder} to display the Panel floated above the layout,
+     * false to force the user to fully expand a collapsed region by clicking the expand button to see it again.
      */
     floatable: true,
 
+    /**
+     * @cfg {Boolean} overlapHeader
+     * True to overlap the header in a panel over the framing of the panel itself. This is needed when frame:true (and
+     * is done automatically for you). Otherwise it is undefined. If you manually add rounded corners to a panel header
+     * which does not have frame:true, this will need to be set to true.
+     */
+
     /**
      * @cfg {Boolean} collapsible
-     * <p>True to make the panel collapsible and have an expand/collapse toggle Tool added into
-     * the header tool button area. False to keep the panel sized either statically, or by an owning layout manager, with no toggle Tool (defaults to false).</p>
+     * True to make the panel collapsible and have an expand/collapse toggle Tool added into the header tool button
+     * area. False to keep the panel sized either statically, or by an owning layout manager, with no toggle Tool.
+     *
      * See {@link #collapseMode} and {@link #collapseDirection}
      */
     collapsible: false,
 
     /**
      * @cfg {Boolean} collapseDirection
-     * <p>The direction to collapse the Panel when the toggle button is clicked.</p>
-     * <p>Defaults to the {@link #headerPosition}</p>
-     * <p><b>Important: This config is <u>ignored</u> for {@link #collapsible} Panels which are direct child items of a {@link Ext.layout.container.Border border layout}.</b></p>
-     * <p>Specify as <code>'top'</code>, <code>'bottom'</code>, <code>'left'</code> or <code>'right'</code>.</p>
+     * The direction to collapse the Panel when the toggle button is clicked.
+     *
+     * Defaults to the {@link #headerPosition}
+     *
+     * **Important: This config is _ignored_ for {@link #collapsible} Panels which are direct child items of a {@link
+     * Ext.layout.container.Border border layout}.**
+     *
+     * Specify as `'top'`, `'bottom'`, `'left'` or `'right'`.
      */
 
     /**
      * @cfg {Boolean} closable
-     * <p>True to display the 'close' tool button and allow the user to close the window, false to
-     * hide the button and disallow closing the window (defaults to <code>false</code>).</p>
-     * <p>By default, when close is requested by clicking the close button in the header, the {@link #close}
-     * method will be called. This will <i>{@link Ext.Component#destroy destroy}</i> the Panel and its content
-     * meaning that it may not be reused.</p>
-     * <p>To make closing a Panel <i>hide</i> the Panel so that it may be reused, set
-     * {@link #closeAction} to 'hide'.</p>
+     * True to display the 'close' tool button and allow the user to close the window, false to hide the button and
+     * disallow closing the window.
+     *
+     * By default, when close is requested by clicking the close button in the header, the {@link #close} method will be
+     * called. This will _{@link Ext.Component#destroy destroy}_ the Panel and its content meaning that it may not be
+     * reused.
+     *
+     * To make closing a Panel _hide_ the Panel so that it may be reused, set {@link #closeAction} to 'hide'.
      */
     closable: false,
 
     /**
      * @cfg {String} closeAction
-     * <p>The action to take when the close header tool is clicked:
-     * <div class="mdetail-params"><ul>
-     * <li><b><code>'{@link #destroy}'</code></b> : <b>Default</b><div class="sub-desc">
-     * {@link #destroy remove} the window from the DOM and {@link Ext.Component#destroy destroy}
-     * it and all descendant Components. The window will <b>not</b> be available to be
-     * redisplayed via the {@link #show} method.
-     * </div></li>
-     * <li><b><code>'{@link #hide}'</code></b> : <div class="sub-desc">
-     * {@link #hide} the window by setting visibility to hidden and applying negative offsets.
-     * The window will be available to be redisplayed via the {@link #show} method.
-     * </div></li>
-     * </ul></div>
-     * <p><b>Note:</b> This behavior has changed! setting *does* affect the {@link #close} method
-     * which will invoke the approriate closeAction.
+     * The action to take when the close header tool is clicked:
+     *
+     * - **`'{@link #destroy}'`** :
+     *
+     *   {@link #destroy remove} the window from the DOM and {@link Ext.Component#destroy destroy} it and all descendant
+     *   Components. The window will **not** be available to be redisplayed via the {@link #show} method.
+     *
+     * - **`'{@link #hide}'`** :
+     *
+     *   {@link #hide} the window by setting visibility to hidden and applying negative offsets. The window will be
+     *   available to be redisplayed via the {@link #show} method.
+     *
+     * **Note:** This behavior has changed! setting *does* affect the {@link #close} method which will invoke the
+     * approriate closeAction.
      */
     closeAction: 'destroy',
 
     /**
-     * @cfg {Object/Array} dockedItems
-     * A component or series of components to be added as docked items to this panel.
-     * The docked items can be docked to either the top, right, left or bottom of a panel.
-     * This is typically used for things like toolbars or tab bars:
-     * <pre><code>
-var panel = new Ext.panel.Panel({
-    dockedItems: [{
-        xtype: 'toolbar',
-        dock: 'top',
-        items: [{
-            text: 'Docked to the top'
-        }]
-    }]
-});</pre></code>
+     * @cfg {Object/Object[]} dockedItems
+     * A component or series of components to be added as docked items to this panel. The docked items can be docked to
+     * either the top, right, left or bottom of a panel. This is typically used for things like toolbars or tab bars:
+     *
+     *     var panel = new Ext.panel.Panel({
+     *         dockedItems: [{
+     *             xtype: 'toolbar',
+     *             dock: 'top',
+     *             items: [{
+     *                 text: 'Docked to the top'
+     *             }]
+     *         }]
+     *     });
      */
 
     /**
-      * @cfg {Boolean} preventHeader Prevent a Header from being created and shown. Defaults to false.
+      * @cfg {Boolean} preventHeader
+      * Prevent a Header from being created and shown.
       */
     preventHeader: false,
 
      /**
-      * @cfg {String} headerPosition Specify as <code>'top'</code>, <code>'bottom'</code>, <code>'left'</code> or <code>'right'</code>. Defaults to <code>'top'</code>.
+      * @cfg {String} headerPosition
+      * Specify as `'top'`, `'bottom'`, `'left'` or `'right'`.
       */
     headerPosition: 'top',
 
@@ -273,90 +326,151 @@ var panel = new Ext.panel.Panel({
     frameHeader: true,
 
     /**
-     * @cfg {Array} tools
-     * An array of {@link Ext.panel.Tool} configs/instances to be added to the header tool area. The tools are stored as child
-     * components of the header container. They can be accessed using {@link #down} and {#query}, as well as the other
-     * component methods. The toggle tool is automatically created if {@link #collapsible} is set to true.
-     * <p>Note that, apart from the toggle tool which is provided when a panel is collapsible, these
-     * tools only provide the visual button. Any required functionality must be provided by adding
-     * handlers that implement the necessary behavior.</p>
-     * <p>Example usage:</p>
-     * <pre><code>
-tools:[{
-    type:'refresh',
-    qtip: 'Refresh form Data',
-    // hidden:true,
-    handler: function(event, toolEl, panel){
-        // refresh logic
-    }
-},
-{
-    type:'help',
-    qtip: 'Get Help',
-    handler: function(event, toolEl, panel){
-        // show help here
-    }
-}]
-</code></pre>
+     * @cfg {Object[]/Ext.panel.Tool[]} tools
+     * An array of {@link Ext.panel.Tool} configs/instances to be added to the header tool area. The tools are stored as
+     * child components of the header container. They can be accessed using {@link #down} and {#query}, as well as the
+     * other component methods. The toggle tool is automatically created if {@link #collapsible} is set to true.
+     *
+     * Note that, apart from the toggle tool which is provided when a panel is collapsible, these tools only provide the
+     * visual button. Any required functionality must be provided by adding handlers that implement the necessary
+     * behavior.
+     *
+     * Example usage:
+     *
+     *     tools:[{
+     *         type:'refresh',
+     *         tooltip: 'Refresh form Data',
+     *         // hidden:true,
+     *         handler: function(event, toolEl, panel){
+     *             // refresh logic
+     *         }
+     *     },
+     *     {
+     *         type:'help',
+     *         tooltip: 'Get Help',
+     *         handler: function(event, toolEl, panel){
+     *             // show help here
+     *         }
+     *     }]
      */
 
+    /**
+     * @cfg {String} [title='']
+     * The title text to be used to display in the {@link Ext.panel.Header panel header}. When a
+     * `title` is specified the {@link Ext.panel.Header} will automatically be created and displayed unless
+     * {@link #preventHeader} is set to `true`.
+     */
+
+    /**
+     * @cfg {String} iconCls
+     * CSS class for icon in header. Used for displaying an icon to the left of a title.
+     */
 
     initComponent: function() {
         var me = this,
             cls;
 
         me.addEvents(
-        /**
-         * @event titlechange
-         * Fires after the Panel title has been set or changed.
-         * @param {Ext.panel.Panel} p the Panel which has been resized.
-         * @param {String} newTitle The new title.
-         * @param {String} oldTitle The previous panel title.
-         */
+
+            /**
+             * @event beforeclose
+             * Fires before the user closes the panel. Return false from any listener to stop the close event being
+             * fired
+             * @param {Ext.panel.Panel} panel The Panel object
+             */
+            'beforeclose',
+
+            /**
+             * @event beforeexpand
+             * Fires before this panel is expanded. Return false to prevent the expand.
+             * @param {Ext.panel.Panel} p The Panel being expanded.
+             * @param {Boolean} animate True if the expand is animated, else false.
+             */
+            "beforeexpand",
+
+            /**
+             * @event beforecollapse
+             * Fires before this panel is collapsed. Return false to prevent the collapse.
+             * @param {Ext.panel.Panel} p The Panel being collapsed.
+             * @param {String} direction . The direction of the collapse. One of
+             *
+             *   - Ext.Component.DIRECTION_TOP
+             *   - Ext.Component.DIRECTION_RIGHT
+             *   - Ext.Component.DIRECTION_BOTTOM
+             *   - Ext.Component.DIRECTION_LEFT
+             *
+             * @param {Boolean} animate True if the collapse is animated, else false.
+             */
+            "beforecollapse",
+
+            /**
+             * @event expand
+             * Fires after this Panel has expanded.
+             * @param {Ext.panel.Panel} p The Panel that has been expanded.
+             */
+            "expand",
+
+            /**
+             * @event collapse
+             * Fires after this Panel hass collapsed.
+             * @param {Ext.panel.Panel} p The Panel that has been collapsed.
+             */
+            "collapse",
+
+            /**
+             * @event titlechange
+             * Fires after the Panel title has been set or changed.
+             * @param {Ext.panel.Panel} p the Panel which has been resized.
+             * @param {String} newTitle The new title.
+             * @param {String} oldTitle The previous panel title.
+             */
             'titlechange',
-        /**
-         * @event iconchange
-         * Fires after the Panel iconCls has been set or changed.
-         * @param {Ext.panel.Panel} p the Panel which has been resized.
-         * @param {String} newIconCls The new iconCls.
-         * @param {String} oldIconCls The previous panel iconCls.
-         */
+
+            /**
+             * @event iconchange
+             * Fires after the Panel iconCls has been set or changed.
+             * @param {Ext.panel.Panel} p the Panel which has been resized.
+             * @param {String} newIconCls The new iconCls.
+             * @param {String} oldIconCls The previous panel iconCls.
+             */
             'iconchange'
         );
 
+        // Save state on these two events.
+        this.addStateEvents('expand', 'collapse');
+
         if (me.unstyled) {
             me.setUI('plain');
         }
 
         if (me.frame) {
-            me.setUI('default-framed');
+            me.setUI(me.ui + '-framed');
         }
 
-        me.callParent();
-
-        me.collapseDirection = me.collapseDirection || me.headerPosition || Ext.Component.DIRECTION_TOP;
-
         // Backwards compatibility
         me.bridgeToolbars();
+
+        me.callParent();
+        me.collapseDirection = me.collapseDirection || me.headerPosition || Ext.Component.DIRECTION_TOP;
     },
 
     setBorder: function(border) {
         // var me     = this,
         //     method = (border === false || border === 0) ? 'addClsWithUI' : 'removeClsWithUI';
-        // 
+        //
         // me.callParent(arguments);
-        // 
+        //
         // if (me.collapsed) {
         //     me[method](me.collapsedCls + '-noborder');
         // }
-        // 
+        //
         // if (me.header) {
         //     me.header.setBorder(border);
         //     if (me.collapsed) {
         //         me.header[method](me.collapsedCls + '-noborder');
         //     }
         // }
-        
+
         this.callParent(arguments);
     },
 
@@ -387,7 +501,7 @@ tools:[{
     },
 
     /**
-     * Set a title for the panel&#39;s header. See {@link Ext.panel.Header#title}.
+     * Set a title for the panel's header. See {@link Ext.panel.Header#title}.
      * @param {String} newTitle
      */
     setTitle: function(newTitle) {
@@ -408,8 +522,9 @@ tools:[{
     },
 
     /**
-     * Set the iconCls for the panel&#39;s header. See {@link Ext.panel.Header#iconCls}.
-     * @param {String} newIconCls
+     * Set the iconCls for the panel's header. See {@link Ext.panel.Header#iconCls}. It will fire the
+     * {@link #iconchange} event after completion.
+     * @param {String} newIconCls The new CSS class name
      */
     setIconCls: function(newIconCls) {
         var me = this,
@@ -425,11 +540,12 @@ tools:[{
 
     bridgeToolbars: function() {
         var me = this,
+            docked = [],
             fbar,
             fbarDefaults,
             minButtonWidth = me.minButtonWidth;
 
-        function initToolbar (toolbar, pos) {
+        function initToolbar (toolbar, pos, useButtonAlign) {
             if (Ext.isArray(toolbar)) {
                 toolbar = {
                     xtype: 'toolbar',
@@ -443,89 +559,98 @@ tools:[{
             if (pos == 'left' || pos == 'right') {
                 toolbar.vertical = true;
             }
+
+            // Legacy support for buttonAlign (only used by buttons/fbar)
+            if (useButtonAlign) {
+                toolbar.layout = Ext.applyIf(toolbar.layout || {}, {
+                    // default to 'end' (right-aligned) if me.buttonAlign is undefined or invalid
+                    pack: { left:'start', center:'center' }[me.buttonAlign] || 'end'
+                });
+            }
             return toolbar;
         }
 
-        // Backwards compatibility
+        // Short-hand toolbars (tbar, bbar and fbar plus new lbar and rbar):
 
         /**
-         * @cfg {Object/Array} tbar
-
-Convenience method. Short for 'Top Bar'.
-
-    tbar: [
-      { xtype: 'button', text: 'Button 1' }
-    ]
-
-is equivalent to
-
-    dockedItems: [{
-        xtype: 'toolbar',
-        dock: 'top',
-        items: [
-            { xtype: 'button', text: 'Button 1' }
-        ]
-    }]
+         * @cfg {String} buttonAlign
+         * The alignment of any buttons added to this panel. Valid values are 'right', 'left' and 'center' (defaults to
+         * 'right' for buttons/fbar, 'left' for other toolbar types).
+         *
+         * **NOTE:** The prefered way to specify toolbars is to use the dockedItems config. Instead of buttonAlign you
+         * would add the layout: { pack: 'start' | 'center' | 'end' } option to the dockedItem config.
+         */
 
-         * @markdown
+        /**
+         * @cfg {Object/Object[]} tbar
+         * Convenience config. Short for 'Top Bar'.
+         *
+         *     tbar: [
+         *       { xtype: 'button', text: 'Button 1' }
+         *     ]
+         *
+         * is equivalent to
+         *
+         *     dockedItems: [{
+         *         xtype: 'toolbar',
+         *         dock: 'top',
+         *         items: [
+         *             { xtype: 'button', text: 'Button 1' }
+         *         ]
+         *     }]
          */
         if (me.tbar) {
-            me.addDocked(initToolbar(me.tbar, 'top'));
+            docked.push(initToolbar(me.tbar, 'top'));
             me.tbar = null;
         }
 
         /**
-         * @cfg {Object/Array} bbar
-
-Convenience method. Short for 'Bottom Bar'.
-
-    bbar: [
-      { xtype: 'button', text: 'Button 1' }
-    ]
-
-is equivalent to
-
-    dockedItems: [{
-        xtype: 'toolbar',
-        dock: 'bottom',
-        items: [
-            { xtype: 'button', text: 'Button 1' }
-        ]
-    }]
-
-         * @markdown
+         * @cfg {Object/Object[]} bbar
+         * Convenience config. Short for 'Bottom Bar'.
+         *
+         *     bbar: [
+         *       { xtype: 'button', text: 'Button 1' }
+         *     ]
+         *
+         * is equivalent to
+         *
+         *     dockedItems: [{
+         *         xtype: 'toolbar',
+         *         dock: 'bottom',
+         *         items: [
+         *             { xtype: 'button', text: 'Button 1' }
+         *         ]
+         *     }]
          */
         if (me.bbar) {
-            me.addDocked(initToolbar(me.bbar, 'bottom'));
+            docked.push(initToolbar(me.bbar, 'bottom'));
             me.bbar = null;
         }
 
         /**
-         * @cfg {Object/Array} buttons
-
-Convenience method used for adding buttons docked to the bottom right of the panel. This is a
-synonym for the {@link #fbar} config.
-
-    buttons: [
-      { text: 'Button 1' }
-    ]
-
-is equivalent to
-
-    dockedItems: [{
-        xtype: 'toolbar',
-        dock: 'bottom',
-        defaults: {minWidth: {@link #minButtonWidth}},
-        items: [
-            { xtype: 'component', flex: 1 },
-            { xtype: 'button', text: 'Button 1' }
-        ]
-    }]
-
-The {@link #minButtonWidth} is used as the default {@link Ext.button.Button#minWidth minWidth} for
-each of the buttons in the buttons toolbar.
-
-         * @markdown
+         * @cfg {Object/Object[]} buttons
+         * Convenience config used for adding buttons docked to the bottom of the panel. This is a
+         * synonym for the {@link #fbar} config.
+         *
+         *     buttons: [
+         *       { text: 'Button 1' }
+         *     ]
+         *
+         * is equivalent to
+         *
+         *     dockedItems: [{
+         *         xtype: 'toolbar',
+         *         dock: 'bottom',
+         *         ui: 'footer',
+         *         defaults: {minWidth: {@link #minButtonWidth}},
+         *         items: [
+         *             { xtype: 'component', flex: 1 },
+         *             { xtype: 'button', text: 'Button 1' }
+         *         ]
+         *     }]
+         *
+         * The {@link #minButtonWidth} is used as the default {@link Ext.button.Button#minWidth minWidth} for
+         * each of the buttons in the buttons toolbar.
          */
         if (me.buttons) {
             me.fbar = me.buttons;
@@ -533,33 +658,31 @@ each of the buttons in the buttons toolbar.
         }
 
         /**
-         * @cfg {Object/Array} fbar
-
-Convenience method used for adding items to the bottom right of the panel. Short for Footer Bar.
-
-    fbar: [
-      { type: 'button', text: 'Button 1' }
-    ]
-
-is equivalent to
-
-    dockedItems: [{
-        xtype: 'toolbar',
-        dock: 'bottom',
-        defaults: {minWidth: {@link #minButtonWidth}},
-        items: [
-            { xtype: 'component', flex: 1 },
-            { xtype: 'button', text: 'Button 1' }
-        ]
-    }]
-
-The {@link #minButtonWidth} is used as the default {@link Ext.button.Button#minWidth minWidth} for
-each of the buttons in the fbar.
-
-         * @markdown
+         * @cfg {Object/Object[]} fbar
+         * Convenience config used for adding items to the bottom of the panel. Short for Footer Bar.
+         *
+         *     fbar: [
+         *       { type: 'button', text: 'Button 1' }
+         *     ]
+         *
+         * is equivalent to
+         *
+         *     dockedItems: [{
+         *         xtype: 'toolbar',
+         *         dock: 'bottom',
+         *         ui: 'footer',
+         *         defaults: {minWidth: {@link #minButtonWidth}},
+         *         items: [
+         *             { xtype: 'component', flex: 1 },
+         *             { xtype: 'button', text: 'Button 1' }
+         *         ]
+         *     }]
+         *
+         * The {@link #minButtonWidth} is used as the default {@link Ext.button.Button#minWidth minWidth} for
+         * each of the buttons in the fbar.
          */
         if (me.fbar) {
-            fbar = initToolbar(me.fbar, 'bottom');
+            fbar = initToolbar(me.fbar, 'bottom', true); // only we useButtonAlign
             fbar.ui = 'footer';
 
             // Apply the minButtonWidth config to buttons in the toolbar
@@ -575,66 +698,64 @@ each of the buttons in the fbar.
                 };
             }
 
-            fbar = me.addDocked(fbar)[0];
-            fbar.insert(0, {
-                flex: 1,
-                xtype: 'component',
-                focusable: false
-            });
+            docked.push(fbar);
             me.fbar = null;
         }
 
         /**
-         * @cfg {Object/Array} lbar
-         *
-         * Convenience method. Short for 'Left Bar' (left-docked, vertical toolbar).
+         * @cfg {Object/Object[]} lbar
+         * Convenience config. Short for 'Left Bar' (left-docked, vertical toolbar).
          *
-         *    lbar: [
-         *      { xtype: 'button', text: 'Button 1' }
-         *    ]
+         *     lbar: [
+         *       { xtype: 'button', text: 'Button 1' }
+         *     ]
          *
          * is equivalent to
          *
-         *    dockedItems: [{
-         *        xtype: 'toolbar',
-         *        dock: 'left',
-         *        items: [
-         *            { xtype: 'button', text: 'Button 1' }
-         *        ]
-         *    }]
-         *
-         * @markdown
+         *     dockedItems: [{
+         *         xtype: 'toolbar',
+         *         dock: 'left',
+         *         items: [
+         *             { xtype: 'button', text: 'Button 1' }
+         *         ]
+         *     }]
          */
         if (me.lbar) {
-            me.addDocked(initToolbar(me.lbar, 'left'));
+            docked.push(initToolbar(me.lbar, 'left'));
             me.lbar = null;
         }
 
         /**
-         * @cfg {Object/Array} rbar
-         *
-         * Convenience method. Short for 'Right Bar' (right-docked, vertical toolbar).
+         * @cfg {Object/Object[]} rbar
+         * Convenience config. Short for 'Right Bar' (right-docked, vertical toolbar).
          *
-         *    rbar: [
-         *      { xtype: 'button', text: 'Button 1' }
-         *    ]
+         *     rbar: [
+         *       { xtype: 'button', text: 'Button 1' }
+         *     ]
          *
          * is equivalent to
          *
-         *    dockedItems: [{
-         *        xtype: 'toolbar',
-         *        dock: 'right',
-         *        items: [
-         *            { xtype: 'button', text: 'Button 1' }
-         *        ]
-         *    }]
-         *
-         * @markdown
+         *     dockedItems: [{
+         *         xtype: 'toolbar',
+         *         dock: 'right',
+         *         items: [
+         *             { xtype: 'button', text: 'Button 1' }
+         *         ]
+         *     }]
          */
         if (me.rbar) {
-            me.addDocked(initToolbar(me.rbar, 'right'));
+            docked.push(initToolbar(me.rbar, 'right'));
             me.rbar = null;
         }
+
+        if (me.dockedItems) {
+            if (!Ext.isArray(me.dockedItems)) {
+                me.dockedItems = [me.dockedItems];
+            }
+            me.dockedItems = me.dockedItems.concat(docked);
+        } else {
+            me.dockedItems = docked;
+        }
     },
 
     /**
@@ -645,7 +766,7 @@ each of the buttons in the fbar.
     initTools: function() {
         var me = this;
 
-        me.tools = me.tools || [];
+        me.tools = me.tools ? Ext.Array.clone(me.tools) : [];
 
         // Add a collapse tool unless configured to not show a collapse tool
         // or to not even show a header.
@@ -685,17 +806,18 @@ each of the buttons in the fbar.
 
     /**
      * @private
+     * @template
      * Template method to be implemented in subclasses to add their tools after the collapsible tool.
      */
     addTools: Ext.emptyFn,
 
     /**
-     * <p>Closes the Panel. By default, this method, removes it from the DOM, {@link Ext.Component#destroy destroy}s
-     * the Panel object and all its descendant Components. The {@link #beforeclose beforeclose}
-     * event is fired before the close happens and will cancel the close action if it returns false.<p>
-     * <p><b>Note:</b> This method is not affected by the {@link #closeAction} setting which
-     * only affects the action triggered when clicking the {@link #closable 'close' tool in the header}.
-     * To hide the Panel without destroying it, call {@link #hide}.</p>
+     * Closes the Panel. By default, this method, removes it from the DOM, {@link Ext.Component#destroy destroy}s the
+     * Panel object and all its descendant Components. The {@link #beforeclose beforeclose} event is fired before the
+     * close happens and will cancel the close action if it returns false.
+     *
+     * **Note:** This method is also affected by the {@link #closeAction} setting. For more explicit control use
+     * {@link #destroy} and {@link #hide} methods.
      */
     close: function() {
         if (this.fireEvent('beforeclose', this) !== false) {
@@ -720,35 +842,28 @@ each of the buttons in the fbar.
         // Dock the header/title
         me.updateHeader();
 
-        // If initially collapsed, collapsed flag must indicate true current state at this point.
-        // Do collapse after the first time the Panel's structure has been laid out.
+        // Call to super after adding the header, to prevent an unnecessary re-layout
+        me.callParent(arguments);
+    },
+
+    afterRender: function() {
+        var me = this;
+
+        me.callParent(arguments);
+
+        // Instate the collapsed state after render. We need to wait for
+        // this moment so that we have established at least some of our size (from our
+        // configured dimensions or from content via the component layout)
         if (me.collapsed) {
             me.collapsed = false;
-            topContainer = me.findLayoutController();
-            if (!me.hidden && topContainer) {
-                topContainer.on({
-                    afterlayout: function() {
-                        me.collapse(null, false, true);
-                    },
-                    single: true
-                });
-            } else {
-                me.afterComponentLayout = function() {
-                    delete me.afterComponentLayout;
-                    Ext.getClass(me).prototype.afterComponentLayout.apply(me, arguments);
-                    me.collapse(null, false, true);
-                };
-            }
+            me.collapse(null, false, true);
         }
-
-        // Call to super after adding the header, to prevent an unnecessary re-layout
-        me.callParent(arguments);
     },
 
     /**
      * Create, hide, or show the header component as appropriate based on the current config.
      * @private
-     * @param {Boolean} force True to force the the header to be created
+     * @param {Boolean} force True to force the header to be created
      */
     updateHeader: function(force) {
         var me = this,
@@ -810,13 +925,52 @@ each of the buttons in the fbar.
         return this.body || this.frameBody || this.el;
     },
 
+    // the overrides below allow for collapsed regions inside the border layout to be hidden
+
+    // inherit docs
+    isVisible: function(deep){
+        var me = this;
+        if (me.collapsed && me.placeholder) {
+            return me.placeholder.isVisible(deep);
+        }
+        return me.callParent(arguments);
+    },
+
+    // inherit docs
+    onHide: function(){
+        var me = this;
+        if (me.collapsed && me.placeholder) {
+            me.placeholder.hide();
+        } else {
+            me.callParent(arguments);
+        }
+    },
+
+    // inherit docs
+    onShow: function(){
+        var me = this;
+        if (me.collapsed && me.placeholder) {
+            // force hidden back to true, since this gets set by the layout
+            me.hidden = true;
+            me.placeholder.show();
+        } else {
+            me.callParent(arguments);
+        }
+    },
+
     addTool: function(tool) {
-        this.tools.push(tool);
-        var header = this.header;
+        var me = this,
+            header = me.header;
+
+        if (Ext.isArray(tool)) {
+            Ext.each(tool, me.addTool, me);
+            return;
+        }
+        me.tools.push(tool);
         if (header) {
             header.addTool(tool);
         }
-        this.updateHeader();
+        me.updateHeader();
     },
 
     getOppositeDirection: function(d) {
@@ -834,15 +988,18 @@ each of the buttons in the fbar.
     },
 
     /**
-     * Collapses the panel body so that the body becomes hidden. Docked Components parallel to the
-     * border towards which the collapse takes place will remain visible.  Fires the {@link #beforecollapse} event which will
-     * cancel the collapse action if it returns false.
-     * @param {Number} direction. The direction to collapse towards. Must be one of<ul>
-     * <li>Ext.Component.DIRECTION_TOP</li>
-     * <li>Ext.Component.DIRECTION_RIGHT</li>
-     * <li>Ext.Component.DIRECTION_BOTTOM</li>
-     * <li>Ext.Component.DIRECTION_LEFT</li></ul>
-     * @param {Boolean} animate True to animate the transition, else false (defaults to the value of the
+     * Collapses the panel body so that the body becomes hidden. Docked Components parallel to the border towards which
+     * the collapse takes place will remain visible. Fires the {@link #beforecollapse} event which will cancel the
+     * collapse action if it returns false.
+     *
+     * @param {String} direction . The direction to collapse towards. Must be one of
+     *
+     *   - Ext.Component.DIRECTION_TOP
+     *   - Ext.Component.DIRECTION_RIGHT
+     *   - Ext.Component.DIRECTION_BOTTOM
+     *   - Ext.Component.DIRECTION_LEFT
+     *
+     * @param {Boolean} [animate] True to animate the transition, else false (defaults to the value of the
      * {@link #animCollapse} panel config)
      * @return {Ext.panel.Panel} this
      */
@@ -877,7 +1034,6 @@ each of the buttons in the fbar.
             reExpanderOrientation,
             reExpanderDock,
             getDimension,
-            setDimension,
             collapseDimension;
 
         if (!direction) {
@@ -900,23 +1056,22 @@ each of the buttons in the fbar.
         switch (direction) {
             case c.DIRECTION_TOP:
             case c.DIRECTION_BOTTOM:
-                me.expandedSize = me.getHeight();
                 reExpanderOrientation = 'horizontal';
                 collapseDimension = 'height';
                 getDimension = 'getHeight';
-                setDimension = 'setHeight';
 
-                // Collect the height of the visible header.
-                // Hide all docked items except the header.
-                // Hide *ALL* docked items if we're going to end up hiding the whole Panel anyway
+                // Attempt to find a reExpander Component (docked in a horizontal orientation)
+                // Also, collect all other docked items which we must hide after collapse.
                 for (; i < dockedItemCount; i++) {
                     comp = dockedItems[i];
                     if (comp.isVisible()) {
-                        if (comp.isHeader && (!comp.dock || comp.dock == 'top' || comp.dock == 'bottom')) {
+                        if (comp.isXType('header', true) && (!comp.dock || comp.dock == 'top' || comp.dock == 'bottom')) {
                             reExpander = comp;
                         } else {
                             me.hiddenDocked.push(comp);
                         }
+                    } else if (comp === me.reExpander) {
+                        reExpander = comp;
                     }
                 }
 
@@ -928,15 +1083,12 @@ each of the buttons in the fbar.
 
             case c.DIRECTION_LEFT:
             case c.DIRECTION_RIGHT:
-                me.expandedSize = me.getWidth();
                 reExpanderOrientation = 'vertical';
                 collapseDimension = 'width';
                 getDimension = 'getWidth';
-                setDimension = 'setWidth';
 
-                // Collect the height of the visible header.
-                // Hide all docked items except the header.
-                // Hide *ALL* docked items if we're going to end up hiding the whole Panel anyway
+                // Attempt to find a reExpander Component (docked in a vecrtical orientation)
+                // Also, collect all other docked items which we must hide after collapse.
                 for (; i < dockedItemCount; i++) {
                     comp = dockedItems[i];
                     if (comp.isVisible()) {
@@ -945,6 +1097,8 @@ each of the buttons in the fbar.
                         } else {
                             me.hiddenDocked.push(comp);
                         }
+                    } else if (comp === me.reExpander) {
+                        reExpander = comp;
                     }
                 }
 
@@ -958,12 +1112,6 @@ each of the buttons in the fbar.
                 throw('Panel collapse must be passed a valid Component collapse direction');
         }
 
-        // No scrollbars when we shrink this Panel
-        // And no laying out of any children... we're effectively *hiding* the body
-        me.setAutoScroll(false);
-        me.suspendLayout = true;
-        me.body.setVisibilityMode(Ext.core.Element.DISPLAY);
-
         // Disable toggle tool during animated collapse
         if (animate && me.collapseTool) {
             me.collapseTool.disable();
@@ -976,7 +1124,8 @@ each of the buttons in the fbar.
         // }
 
         // We found a header: Measure it to find the collapse-to size.
-        if (reExpander) {
+        if (reExpander && reExpander.rendered) {
+
             //we must add the collapsed cls to the header and then remove to get the proper height
             reExpander.addClsWithUI(me.collapsedCls);
             reExpander.addClsWithUI(me.collapsedCls + '-' + reExpander.dock);
@@ -985,13 +1134,13 @@ each of the buttons in the fbar.
             }
 
             frameInfo = reExpander.getFrameInfo();
-                        
+
             //get the size
             newSize = reExpander[getDimension]() + (frameInfo ? frameInfo[direction] : 0);
 
             //and remove
             reExpander.removeClsWithUI(me.collapsedCls);
-            reExpander.removeClsWithUI(me.collapsedCls + '-' + reExpander.dock);              
+            reExpander.removeClsWithUI(me.collapsedCls + '-' + reExpander.dock);
             if (me.border && (!me.frame || (me.frame && Ext.supports.CSS3BorderRadius))) {
                 reExpander.removeClsWithUI(me.collapsedCls + '-border-' + reExpander.dock);
             }
@@ -1014,12 +1163,14 @@ each of the buttons in the fbar.
                 cls: me.baseCls + '-collapsed-placeholder ' + ' ' + Ext.baseCSSPrefix + 'docked ' + me.baseCls + '-' + me.ui + '-collapsed',
                 renderTo: me.el
             };
-            reExpander[(reExpander.orientation == 'horizontal') ? 'tools' : 'items'] = [{
-                xtype: 'tool',
-                type: 'expand-' + me.expandDirection,
-                handler: me.toggleCollapse,
-                scope: me
-            }];
+            if (!me.hideCollapseTool) {
+                reExpander[(reExpander.orientation == 'horizontal') ? 'tools' : 'items'] = [{
+                    xtype: 'tool',
+                    type: 'expand-' + me.expandDirection,
+                    handler: me.toggleCollapse,
+                    scope: me
+                }];
+            }
 
             // Capture the size of the re-expander.
             // For vertical headers in IE6 and IE7, this will be sized by a CSS rule in _panel.scss
@@ -1048,13 +1199,22 @@ each of the buttons in the fbar.
         // Animate to the new size
         anim.to[collapseDimension] = newSize;
 
+        // When we collapse a panel, the panel is in control of one dimension (depending on
+        // collapse direction) and sets that on the component. We must restore the user's
+        // original value (including non-existance) when we expand. Using this technique, we
+        // mimic setCalculatedSize for the dimension we do not control and setSize for the
+        // one we do (only while collapsed).
+        if (!me.collapseMemento) {
+            me.collapseMemento = new Ext.util.Memento(me);
+        }
+        me.collapseMemento.capture(['width', 'height', 'minWidth', 'minHeight', 'layoutManagedHeight', 'layoutManagedWidth']);
+
         // Remove any flex config before we attempt to collapse.
         me.savedFlex = me.flex;
-        me.savedMinWidth = me.minWidth;
-        me.savedMinHeight = me.minHeight;
         me.minWidth = 0;
         me.minHeight = 0;
         delete me.flex;
+        me.suspendLayout = true;
 
         if (animate) {
             me.animate(anim);
@@ -1073,10 +1233,24 @@ each of the buttons in the fbar.
             i = 0,
             l = me.hiddenDocked.length;
 
-        me.minWidth = me.savedMinWidth;
-        me.minHeight = me.savedMinHeight;
+        me.collapseMemento.restore(['minWidth', 'minHeight']);
+
+        // Now we can restore the dimension we don't control to its original state
+        // Leave the value in the memento so that it can be correctly restored
+        // if it is set by animation.
+        if (Ext.Component.VERTICAL_DIRECTION_Re.test(me.expandDirection)) {
+            me.layoutManagedHeight = 2;
+            me.collapseMemento.restore('width', false);
+        } else {
+            me.layoutManagedWidth = 2;
+            me.collapseMemento.restore('height', false);
+        }
+
+        // We must hide the body, otherwise it overlays docked items which come before
+        // it in the DOM order. Collapsing its dimension won't work - padding and borders keep a size.
+        me.saveScrollTop = me.body.dom.scrollTop;
+        me.body.setStyle('display', 'none');
 
-        me.body.hide();
         for (; i < l; i++) {
             me.hiddenDocked[i].hide();
         }
@@ -1085,9 +1259,18 @@ each of the buttons in the fbar.
             me.reExpander.show();
         }
         me.collapsed = true;
+        me.suspendLayout = false;
 
         if (!internal) {
-            me.doComponentLayout();
+            if (me.ownerCt) {
+                // Because Component layouts only inform upstream containers if they have changed size,
+                // explicitly lay out the container now, because the lastComponentsize will have been set by the non-animated setCalculatedSize.
+                if (animated) {
+                    me.ownerCt.layout.layout();
+                }
+            } else if (me.reExpander.temporary) {
+                me.doComponentLayout();
+            }
         }
 
         if (me.resizer) {
@@ -1109,23 +1292,24 @@ each of the buttons in the fbar.
     },
 
     /**
-     * Expands the panel body so that it becomes visible.  Fires the {@link #beforeexpand} event which will
-     * cancel the expand action if it returns false.
-     * @param {Boolean} animate True to animate the transition, else false (defaults to the value of the
+     * Expands the panel body so that it becomes visible. Fires the {@link #beforeexpand} event which will cancel the
+     * expand action if it returns false.
+     * @param {Boolean} [animate] True to animate the transition, else false (defaults to the value of the
      * {@link #animCollapse} panel config)
      * @return {Ext.panel.Panel} this
      */
     expand: function(animate) {
-        if (!this.collapsed || this.fireEvent('beforeexpand', this, animate) === false) {
+        var me = this;
+        if (!me.collapsed || me.fireEvent('beforeexpand', me, animate) === false) {
             return false;
         }
-        var me = this,
-            i = 0,
+
+        var i = 0,
             l = me.hiddenDocked.length,
             direction = me.expandDirection,
             height = me.getHeight(),
             width = me.getWidth(),
-            pos, anim, satisfyJSLint;
+            pos, anim;
 
         // Disable toggle tool during animated expand
         if (animate && me.collapseTool) {
@@ -1156,12 +1340,13 @@ each of the buttons in the fbar.
             me.collapseTool.setType('collapse-' + me.collapseDirection);
         }
 
+        // Restore body display and scroll position
+        me.body.setStyle('display', '');
+        me.body.dom.scrollTop = me.saveScrollTop;
+
         // Unset the flag before the potential call to calculateChildBox to calculate our newly flexed size
         me.collapsed = false;
 
-        // Collapsed means body element was hidden
-        me.body.show();
-
         // Remove any collapsed styling before any animation begins
         me.removeClsWithUI(me.collapsedCls);
         // if (me.border === false) {
@@ -1183,8 +1368,12 @@ each of the buttons in the fbar.
 
         if ((direction == Ext.Component.DIRECTION_TOP) || (direction == Ext.Component.DIRECTION_BOTTOM)) {
 
+            // Restore the collapsed dimension.
+            // Leave it in the memento, so that the final restoreAll can overwrite anything that animation does.
+            me.collapseMemento.restore('height', false);
+
             // If autoHeight, measure the height now we have shown the body element.
-            if (me.autoHeight) {
+            if (me.height === undefined) {
                 me.setCalculatedSize(me.width, null);
                 anim.to.height = me.getHeight();
 
@@ -1200,7 +1389,7 @@ each of the buttons in the fbar.
             }
             // Else, restore to saved height
             else {
-                anim.to.height = me.expandedSize;
+                anim.to.height = me.height;
             }
 
             // top needs animating upwards
@@ -1211,8 +1400,12 @@ each of the buttons in the fbar.
             }
         } else if ((direction == Ext.Component.DIRECTION_LEFT) || (direction == Ext.Component.DIRECTION_RIGHT)) {
 
+            // Restore the collapsed dimension.
+            // Leave it in the memento, so that the final restoreAll can overwrite anything that animation does.
+            me.collapseMemento.restore('width', false);
+
             // If autoWidth, measure the width now we have shown the body element.
-            if (me.autoWidth) {
+            if (me.width === undefined) {
                 me.setCalculatedSize(null, me.height);
                 anim.to.width = me.getWidth();
 
@@ -1228,7 +1421,7 @@ each of the buttons in the fbar.
             }
             // Else, restore to saved width
             else {
-                anim.to.width = me.expandedSize;
+                anim.to.width = me.width;
             }
 
             // left needs animating leftwards
@@ -1242,7 +1435,7 @@ each of the buttons in the fbar.
         if (animate) {
             me.animate(anim);
         } else {
-            me.setSize(anim.to.width, anim.to.height);
+            me.setCalculatedSize(anim.to.width, anim.to.height);
             if (anim.to.x) {
                 me.setLeft(anim.to.x);
             }
@@ -1257,7 +1450,6 @@ each of the buttons in the fbar.
 
     afterExpand: function(animated) {
         var me = this;
-        me.setAutoScroll(me.initialConfig.autoScroll);
 
         // Restored to a calculated flex. Delete the set width and height properties so that flex works from now on.
         if (me.savedFlex) {
@@ -1267,10 +1459,15 @@ each of the buttons in the fbar.
             delete me.height;
         }
 
-        // Reinstate layout out after Panel has re-expanded
-        delete me.suspendLayout;
+        // Restore width/height and dimension management flags to original values
+        if (me.collapseMemento) {
+            me.collapseMemento.restoreAll();
+        }
+
         if (animated && me.ownerCt) {
-            me.ownerCt.doLayout();
+            // IE 6 has an intermittent repaint issue in this case so give
+            // it a little extra time to catch up before laying out.
+            Ext.defer(me.ownerCt.doLayout, Ext.isIE6 ? 1 : 0, me);
         }
 
         if (me.resizer) {
@@ -1309,12 +1506,12 @@ each of the buttons in the fbar.
     // private
     initDraggable : function(){
         /**
-         * <p>If this Panel is configured {@link #draggable}, this property will contain
-         * an instance of {@link Ext.dd.DragSource} which handles dragging the Panel.</p>
-         * The developer must provide implementations of the abstract methods of {@link Ext.dd.DragSource}
-         * in order to supply behaviour for each stage of the drag/drop process. See {@link #draggable}.
-         * @type Ext.dd.DragSource.
-         * @property dd
+         * @property {Ext.dd.DragSource} dd
+         * If this Panel is configured {@link #draggable}, this property will contain an instance of {@link
+         * Ext.dd.DragSource} which handles dragging the Panel.
+         *
+         * The developer must provide implementations of the abstract methods of {@link Ext.dd.DragSource} in order to
+         * supply behaviour for each stage of the drag/drop process. See {@link #draggable}.
          */
         this.dd = Ext.create('Ext.panel.DD', this, Ext.isBoolean(this.draggable) ? null : this.draggable);
     },
@@ -1322,10 +1519,10 @@ each of the buttons in the fbar.
     // private - helper function for ghost
     ghostTools : function() {
         var tools = [],
-            origTools = this.initialConfig.tools;
+            headerTools = this.header.query('tool[hidden=false]');
 
-        if (origTools) {
-            Ext.each(origTools, function(tool) {
+        if (headerTools.length) {
+            Ext.each(headerTools, function(tool) {
                 // Some tools can be full components, and copying them into the ghost
                 // actually removes them from the owning panel. You could also potentially
                 // end up with duplicate DOM ids as well. To avoid any issues we just make
@@ -1334,8 +1531,7 @@ each of the buttons in the fbar.
                     type: tool.type
                 });
             });
-        }
-        else {
+        } else {
             tools = [{
                 type: 'placeholder'
             }];
@@ -1347,23 +1543,19 @@ each of the buttons in the fbar.
     ghost: function(cls) {
         var me = this,
             ghostPanel = me.ghostPanel,
-            box = me.getBox();
+            box = me.getBox(),
+            header;
 
         if (!ghostPanel) {
             ghostPanel = Ext.create('Ext.panel.Panel', {
-                renderTo: document.body,
+                renderTo: me.floating ? me.el.dom.parentNode : document.body,
                 floating: {
                     shadow: false
                 },
                 frame: Ext.supports.CSS3BorderRadius ? me.frame : false,
-                title: me.title,
                 overlapHeader: me.overlapHeader,
                 headerPosition: me.headerPosition,
-                width: me.getWidth(),
-                height: me.getHeight(),
-                iconCls: me.iconCls,
                 baseCls: me.baseCls,
-                tools: me.ghostTools(),
                 cls: me.baseCls + '-ghost ' + (cls ||'')
             });
             me.ghostPanel = ghostPanel;
@@ -1374,6 +1566,19 @@ each of the buttons in the fbar.
         } else {
             ghostPanel.toFront();
         }
+        header = ghostPanel.header;
+        // restore options
+        if (header) {
+            header.suspendLayout = true;
+            Ext.Array.forEach(header.query('tool'), function(tool){
+                header.remove(tool);
+            });
+            header.suspendLayout = false;
+        }
+        ghostPanel.addTool(me.ghostTools());
+        ghostPanel.setTitle(me.title);
+        ghostPanel.setIconCls(me.iconCls);
+
         ghostPanel.el.show();
         ghostPanel.setPosition(box.x, box.y);
         ghostPanel.setSize(box.width, box.height);
@@ -1409,4 +1614,7 @@ each of the buttons in the fbar.
         }
         this.callParent([resizable]);
     }
+}, function(){
+    this.prototype.animCollapse = Ext.enableFx;
 });
+