X-Git-Url: http://git.ithinksw.org/extjs.git/blobdiff_plain/3789b528d8dd8aad4558e38e22d775bcab1cbd36..f562e4c6e5fac7bcb445985b99acbea4d706e6f0:/docs/source/Panel3.html?ds=sidebyside diff --git a/docs/source/Panel3.html b/docs/source/Panel3.html index 1797bc62..756d9522 100644 --- a/docs/source/Panel3.html +++ b/docs/source/Panel3.html @@ -3,8 +3,8 @@
/** - * @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'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's how to do it:<pre><code> -Ext.create('Ext.panel.Panel', { - title: 'Hello', - width: 200, - html: '<p>World!</p>', - 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'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'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) - }] -}); -</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'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', @@ -113,173 +129,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'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'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'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'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 {Mixed} 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} 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', @@ -296,90 +329,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); }, @@ -410,7 +504,7 @@ tools:[{ }, /** - * Set a title for the panel'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) { @@ -431,8 +525,9 @@ tools:[{ }, /** - * Set the iconCls for the panel'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, @@ -448,11 +543,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', @@ -466,89 +562,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 - - /** - * @cfg {Object/Array} tbar + // Short-hand toolbars (tbar, bbar and fbar plus new lbar and rbar): -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; @@ -556,33 +661,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 @@ -598,66 +701,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 + * @cfg {Object/Object[]} lbar + * Convenience config. Short for 'Left Bar' (left-docked, vertical toolbar). * - * Convenience method. 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 + * @cfg {Object/Object[]} rbar + * Convenience config. Short for 'Right Bar' (right-docked, vertical toolbar). * - * Convenience method. 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; + } }, /** @@ -668,7 +769,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. @@ -708,17 +809,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) { @@ -743,35 +845,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, @@ -833,13 +928,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) { @@ -857,15 +991,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 */ @@ -900,7 +1037,6 @@ each of the buttons in the fbar. reExpanderOrientation, reExpanderDock, getDimension, - setDimension, collapseDimension; if (!direction) { @@ -923,23 +1059,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; } } @@ -951,15 +1086,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()) { @@ -968,6 +1100,8 @@ each of the buttons in the fbar. } else { me.hiddenDocked.push(comp); } + } else if (comp === me.reExpander) { + reExpander = comp; } } @@ -981,12 +1115,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(); @@ -999,7 +1127,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); @@ -1008,13 +1137,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); } @@ -1073,21 +1202,26 @@ 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); } else { - // EXTJSIV-1937 (would like to use setCalculateSize) - // save width/height here, expand puts them back - me.uncollapsedSize = { width: me.width, height: me.height }; - me.setSize(anim.to.width, anim.to.height); if (Ext.isDefined(anim.to.left) || Ext.isDefined(anim.to.top)) { me.setPosition(anim.to.left, anim.to.top); @@ -1102,10 +1236,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(); } @@ -1114,9 +1262,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) { @@ -1138,36 +1295,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; } - // EXTJSIV-1937 (would like to use setCalculateSize) - if (this.uncollapsedSize) { - Ext.Object.each(this.uncollapsedSize, function (name, value) { - if (Ext.isDefined(value)) { - this[name] = value; - } else { - delete this[name]; - } - }, this); - delete this.uncollapsedSize; - } - - 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) { @@ -1198,12 +1343,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) { @@ -1225,8 +1371,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(); @@ -1242,7 +1392,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 @@ -1253,8 +1403,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(); @@ -1270,7 +1424,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 @@ -1284,7 +1438,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); } @@ -1299,7 +1453,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) { @@ -1309,10 +1462,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) { @@ -1351,12 +1509,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); }, @@ -1364,10 +1522,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 @@ -1376,8 +1534,7 @@ each of the buttons in the fbar. type: tool.type }); }); - } - else { + } else { tools = [{ type: 'placeholder' }]; @@ -1389,23 +1546,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; @@ -1416,6 +1569,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); @@ -1451,6 +1617,8 @@ each of the buttons in the fbar. } this.callParent([resizable]); } +}, function(){ + this.prototype.animCollapse = Ext.enableFx; });