X-Git-Url: http://git.ithinksw.org/extjs.git/blobdiff_plain/6746dc89c47ed01b165cc1152533605f97eb8e8d..HEAD:/src/panel/Panel.js diff --git a/src/panel/Panel.js b/src/panel/Panel.js index b314f306..af479cbf 100644 --- a/src/panel/Panel.js +++ b/src/panel/Panel.js @@ -13,91 +13,110 @@ If you are unsure which license is appropriate for your use, please contact the */ /** - * @class Ext.panel.Panel - * @extends Ext.panel.AbstractPanel - *

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 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 {@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.

+ * 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} - *

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).

- *

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:


-Ext.create('Ext.panel.Panel', {
-    title: 'Hello',
-    width: 200,
-    html: '<p>World!</p>',
-    renderTo: document.body
-});
-

- *

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:


-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'
-    }]
-});
-

- *

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:


-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)
-    }]
-});
-
- * 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.

+ * + * 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: '

World!

', + * 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', @@ -115,166 +134,182 @@ Ext.define('Ext.panel.Panel', { /** * @cfg {String} collapsedCls - * A CSS class to add to the panel's element after it has been collapsed (defaults to - * 'collapsed'). + * A CSS class to add to the panel's element after it has been collapsed. */ collapsedCls: 'collapsed', /** * @cfg {Boolean} animCollapse - * 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. + * `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 75). 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#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 - * true to render the panel collapsed, false to render it expanded (defaults to - * false). + * `true` to render the panel collapsed, `false` to render it expanded. */ collapsed: false, /** * @cfg {Boolean} collapseFirst - * 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 (defaults to true). + * `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 - * true to hide the expand/collapse toggle button when {@link #collapsible} == true, - * false to display it (defaults to false). + * `true` to hide the expand/collapse toggle button when `{@link #collapsible} == true`, `false` to display it. */ hideCollapseTool: false, /** * @cfg {Boolean} titleCollapse - * 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 button - * (defaults to false)). + * `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 - *

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: - *

+ * **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 - *

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 {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 - *

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 (defaults to true). + * **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 - *

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).

+ * 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 - *

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'.

+ * 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 - *

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 false).

- *

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'.

+ * 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 - *

The action to take when the close header tool is clicked: - *

- *

Note: 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: - *


-var panel = new Ext.panel.Panel({
-    dockedItems: [{
-        xtype: 'toolbar',
-        dock: 'top',
-        items: [{
-            text: 'Docked to the top'
-        }]
-    }]
-});
+ * @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 'top', 'bottom', 'left' or 'right'. Defaults to 'top'. + * @cfg {String} headerPosition + * Specify as `'top'`, `'bottom'`, `'left'` or `'right'`. */ headerPosition: 'top', @@ -291,45 +326,60 @@ 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. - *

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',
-    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
-    }
-}]
-
+ * @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} (defaults to ''). - * When a `title` is specified the {@link Ext.panel.Header} will automatically be created and displayed unless + * @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 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. @@ -342,11 +392,13 @@ tools:[{ * @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 + * @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", @@ -395,12 +447,11 @@ tools:[{ 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) { @@ -450,7 +501,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) { @@ -471,8 +522,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, @@ -488,6 +540,7 @@ tools:[{ bridgeToolbars: function() { var me = this, + docked = [], fbar, fbarDefaults, minButtonWidth = me.minButtonWidth; @@ -519,94 +572,85 @@ tools:[{ // Short-hand toolbars (tbar, bbar and fbar plus new lbar and rbar): - /** - * @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 newer way to specify toolbars is to use the dockedItems config, and - * instead of buttonAlign you would add the layout: { pack: 'start' | 'center' | 'end' } - * option to the dockedItem config.

- */ - /** - * @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 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. - - * @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; @@ -614,31 +658,28 @@ each of the buttons in the buttons toolbar. } /** - * @cfg {Object/Array} fbar - -Convenience method 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. - - * @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', true); // only we useButtonAlign @@ -657,14 +698,13 @@ each of the buttons in the fbar. }; } - me.addDocked(fbar); + 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' } @@ -679,18 +719,15 @@ each of the buttons in the fbar. * { xtype: 'button', text: 'Button 1' } * ] * }] - * - * @markdown */ 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' } @@ -705,13 +742,20 @@ each of the buttons in the fbar. * { xtype: 'button', text: 'Button 1' } * ] * }] - * - * @markdown */ 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; + } }, /** @@ -722,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. @@ -762,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, /** - *

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 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}.

+ * 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) { @@ -803,7 +848,12 @@ each of the buttons in the fbar. 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; me.collapse(null, false, true); @@ -875,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) { @@ -899,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 {String} direction. The direction to collapse towards. Must be one of - * @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 */ @@ -942,7 +1034,6 @@ each of the buttons in the fbar. reExpanderOrientation, reExpanderDock, getDimension, - setDimension, collapseDimension; if (!direction) { @@ -965,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; } } @@ -993,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()) { @@ -1010,6 +1097,8 @@ each of the buttons in the fbar. } else { me.hiddenDocked.push(comp); } + } else if (comp === me.reExpander) { + reExpander = comp; } } @@ -1023,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(); @@ -1041,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); @@ -1123,13 +1207,14 @@ each of the buttons in the fbar. if (!me.collapseMemento) { me.collapseMemento = new Ext.util.Memento(me); } - me.collapseMemento.capture(['width', 'height', 'minWidth', 'minHeight']); + me.collapseMemento.capture(['width', 'height', 'minWidth', 'minHeight', 'layoutManagedHeight', 'layoutManagedWidth']); // Remove any flex config before we attempt to collapse. me.savedFlex = me.flex; me.minWidth = 0; me.minHeight = 0; delete me.flex; + me.suspendLayout = true; if (animate) { me.animate(anim); @@ -1150,7 +1235,22 @@ each of the buttons in the fbar. me.collapseMemento.restore(['minWidth', 'minHeight']); - me.body.hide(); + // 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'); + for (; i < l; i++) { me.hiddenDocked[i].hide(); } @@ -1159,22 +1259,24 @@ 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) { me.resizer.disable(); } - // Now we can restore the dimension we don't control to its original state - if (Ext.Component.VERTICAL_DIRECTION.test(me.expandDirection)) { - me.collapseMemento.restore('width'); - } else { - me.collapseMemento.restore('height'); - } - // If me Panel was configured with a collapse tool in its header, flip it's type if (me.collapseTool) { me.collapseTool.setType('expand-' + me.expandDirection); @@ -1190,9 +1292,9 @@ 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 */ @@ -1238,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) { @@ -1265,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(); @@ -1282,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 @@ -1293,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(); @@ -1310,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 @@ -1340,15 +1451,6 @@ each of the buttons in the fbar. afterExpand: function(animated) { var me = this; - if (me.collapseMemento) { - // collapse has to use setSize (since it takes control of the component's size in - // collapsed mode) and so we restore the original size now that the component has - // been expanded. - me.collapseMemento.restoreAll(); - } - - 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) { me.flex = me.savedFlex; @@ -1357,8 +1459,11 @@ 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) { // IE 6 has an intermittent repaint issue in this case so give // it a little extra time to catch up before laying out. @@ -1401,12 +1506,12 @@ each of the buttons in the fbar. // private initDraggable : function(){ /** - *

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}. - * @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); }, @@ -1414,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 @@ -1426,8 +1531,7 @@ each of the buttons in the fbar. type: tool.type }); }); - } - else { + } else { tools = [{ type: 'placeholder' }]; @@ -1439,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; @@ -1466,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); @@ -1501,5 +1614,7 @@ each of the buttons in the fbar. } this.callParent([resizable]); } +}, function(){ + this.prototype.animCollapse = Ext.enableFx; });