X-Git-Url: http://git.ithinksw.org/extjs.git/blobdiff_plain/25ef3491bd9ae007ff1fc2b0d7943e6eaaccf775..10a866c12701c0a0afd0ac85dcdcf32a421514ac:/docs/source/Container.html?ds=sidebyside diff --git a/docs/source/Container.html b/docs/source/Container.html index c8c7f5d0..9495b6e6 100644 --- a/docs/source/Container.html +++ b/docs/source/Container.html @@ -1,963 +1,1012 @@ - -
-/*! - * Ext JS Library 3.0.3 - * Copyright(c) 2006-2009 Ext JS, LLC - * licensing@extjs.com - * http://www.extjs.com/license + + + ++ \ No newline at end of fileThe source code + + + + +/** + * @class Ext.Container + * @extends Ext.BoxComponent + *- +Ext.Container = Ext.extend(Ext.BoxComponent, { + /** + * @cfg {Boolean} monitorResize + * True to automatically monitor window resize events to handle anything that is sensitive to the current size + * of the viewport. This value is typically managed by the chosenBase class for any {@link Ext.BoxComponent} that may contain other Components. Containers handle the + * basic behavior of containing items, namely adding, inserting and removing items.
+ * + *The most commonly used Container classes are {@link Ext.Panel}, {@link Ext.Window} and {@link Ext.TabPanel}. + * If you do not need the capabilities offered by the aforementioned classes you can create a lightweight + * Container to be encapsulated by an HTML element to your specifications by using the + *
+ * + *{@link Ext.Component#autoEl autoEl}
config option. This is a useful technique when creating + * embedded {@link Ext.layout.ColumnLayout column} layouts inside {@link Ext.form.FormPanel FormPanels} + * for example.The code below illustrates both how to explicitly create a Container, and how to implicitly + * create one using the
'container'
xtype:+ * + *+// explicitly create a Container +var embeddedColumns = new Ext.Container({ + autoEl: 'div', // This is the default + layout: 'column', + defaults: { + // implicitly create Container by specifying xtype + xtype: 'container', + autoEl: 'div', // This is the default. + layout: 'form', + columnWidth: 0.5, + style: { + padding: '10px' + } + }, +// The two items below will be Ext.Containers, each encapsulated by a <DIV> element. + items: [{ + items: { + xtype: 'datefield', + name: 'startDate', + fieldLabel: 'Start date' + } + }, { + items: { + xtype: 'datefield', + name: 'endDate', + fieldLabel: 'End date' + } + }] +});
Layout
+ *Container classes delegate the rendering of child Components to a layout + * manager class which must be configured into the Container using the + *
+ *{@link #layout}
configuration property.When either specifying child
+ *{@link #items}
of a Container, + * or dynamically {@link #add adding} Components to a Container, remember to + * consider how you wish the Container to arrange those child elements, and + * whether those child elements need to be sized using one of Ext's built-in + *{@link #layout}
schemes. By default, Containers use the + * {@link Ext.layout.ContainerLayout ContainerLayout} scheme which only + * renders child components, appending them one after the other inside the + * Container, and does not apply any sizing at all.A common mistake is when a developer neglects to specify a + *
+ *{@link #layout}
(e.g. widgets like GridPanels or + * TreePanels are added to Containers for which no{@link #layout}
+ * has been specified). If a Container is left to use the default + * {@link Ext.layout.ContainerLayout ContainerLayout} scheme, none of its + * child components will be resized, or changed in any way when the Container + * is resized.Certain layout managers allow dynamic addition of child components. + * Those that do include {@link Ext.layout.CardLayout}, + * {@link Ext.layout.AnchorLayout}, {@link Ext.layout.FormLayout}, and + * {@link Ext.layout.TableLayout}. For example:
+ *+// Create the GridPanel. +var myNewGrid = new Ext.grid.GridPanel({ + store: myStore, + columns: myColumnModel, + title: 'Results', // the title becomes the title of the tab +}); + +myTabPanel.add(myNewGrid); // {@link Ext.TabPanel} implicitly uses {@link Ext.layout.CardLayout CardLayout} +myTabPanel.{@link Ext.TabPanel#setActiveTab setActiveTab}(myNewGrid); + *
The example above adds a newly created GridPanel to a TabPanel. Note that + * a TabPanel uses {@link Ext.layout.CardLayout} as its layout manager which + * means all its child items are sized to {@link Ext.layout.FitLayout fit} + * exactly into its client area. + *
Overnesting is a common problem. + * An example of overnesting occurs when a GridPanel is added to a TabPanel + * by wrapping the GridPanel inside a wrapping Panel (that has no + *
{@link #layout}
specified) and then add that wrapping Panel + * to the TabPanel. The point to realize is that a GridPanel is a + * Component which can be added directly to a Container. If the wrapping Panel + * has no{@link #layout}
configuration, then the overnested + * GridPanel will not be sized as expected.+ * + *
Adding via remote configuration
+ * + *A server side script can be used to add Components which are generated dynamically on the server. + * An example of adding a GridPanel to a TabPanel where the GridPanel is generated by the server + * based on certain parameters: + *
+ *+// execute an Ajax request to invoke server side script: +Ext.Ajax.request({ + url: 'gen-invoice-grid.php', + // send additional parameters to instruct server script + params: { + startDate: Ext.getCmp('start-date').getValue(), + endDate: Ext.getCmp('end-date').getValue() + }, + // process the response object to add it to the TabPanel: + success: function(xhr) { + var newComponent = eval(xhr.responseText); // see discussion below + myTabPanel.add(newComponent); // add the component to the TabPanel + myTabPanel.setActiveTab(newComponent); + }, + failure: function() { + Ext.Msg.alert("Grid create failed", "Server communication failure"); + } +}); +
The server script needs to return an executable Javascript statement which, when processed + * using
eval()
, will return either a config object with an {@link Ext.Component#xtype xtype}, + * or an instantiated Component. The server might return this for example:+ *+(function() { + function formatDate(value){ + return value ? value.dateFormat('M d, Y') : ''; + }; + + var store = new Ext.data.Store({ + url: 'get-invoice-data.php', + baseParams: { + startDate: '01/01/2008', + endDate: '01/31/2008' + }, + reader: new Ext.data.JsonReader({ + record: 'transaction', + idProperty: 'id', + totalRecords: 'total' + }, [ + 'customer', + 'invNo', + {name: 'date', type: 'date', dateFormat: 'm/d/Y'}, + {name: 'value', type: 'float'} + ]) + }); + + var grid = new Ext.grid.GridPanel({ + title: 'Invoice Report', + bbar: new Ext.PagingToolbar(store), + store: store, + columns: [ + {header: "Customer", width: 250, dataIndex: 'customer', sortable: true}, + {header: "Invoice Number", width: 120, dataIndex: 'invNo', sortable: true}, + {header: "Invoice Date", width: 100, dataIndex: 'date', renderer: formatDate, sortable: true}, + {header: "Value", width: 120, dataIndex: 'value', renderer: 'usMoney', sortable: true} + ], + }); + store.load(); + return grid; // return instantiated component +})(); +
When the above code fragment is passed through the
+ *eval
function in the success handler + * of the Ajax request, the code is executed by the Javascript processor, and the anonymous function + * runs, and returns the instantiated grid component.Note: since the code above is generated by a server script, the
+ * + * @xtype container */ -/** - * @class Ext.Container - * @extends Ext.BoxComponent - *baseParams
for + * the Store, the metadata to allow generation of the Record layout, and the ColumnModel + * can all be generated into the code since these are all known on the server.Base class for any {@link Ext.BoxComponent} that may contain other Components. Containers handle the - * basic behavior of containing items, namely adding, inserting and removing items.
- * - *The most commonly used Container classes are {@link Ext.Panel}, {@link Ext.Window} and {@link Ext.TabPanel}. - * If you do not need the capabilities offered by the aforementioned classes you can create a lightweight - * Container to be encapsulated by an HTML element to your specifications by using the - * {@link Ext.Component#autoEl autoEl} config option. This is a useful technique when creating - * embedded {@link Ext.layout.ColumnLayout column} layouts inside {@link Ext.form.FormPanel FormPanels} - * for example.
- * - *The code below illustrates both how to explicitly create a Container, and how to implicitly - * create one using the 'container' xtype:
- * - *-// explicitly create a Container -var embeddedColumns = new Ext.Container({ - autoEl: 'div', // This is the default - layout: 'column', - defaults: { - // implicitly create Container by specifying xtype - xtype: 'container', - autoEl: 'div', // This is the default. - layout: 'form', - columnWidth: 0.5, - style: { - padding: '10px' - } - }, -// The two items below will be Ext.Containers, each encapsulated by a <DIV> element. - items: [{ - items: { - xtype: 'datefield', - name: 'startDate', - fieldLabel: 'Start date' - } - }, { - items: { - xtype: 'datefield', - name: 'endDate', - fieldLabel: 'End date' - } - }] -});
Layout
- *Container classes delegate the rendering of child Components to a layout - * manager class which must be configured into the Container using the - *
- *{@link #layout}
configuration property.When either specifying child
- *{@link #items}
of a Container, - * or dynamically {@link #add adding} Components to a Container, remember to - * consider how you wish the Container to arrange those child elements, and - * whether those child elements need to be sized using one of Ext's built-in - *{@link #layout}
schemes. By default, Containers use the - * {@link Ext.layout.ContainerLayout ContainerLayout} scheme which only - * renders child components, appending them one after the other inside the - * Container, and does not apply any sizing at all.A common mistake is when a developer neglects to specify a - *
- *{@link #layout}
(e.g. widgets like GridPanels or - * TreePanels are added to Containers for which no {@link #layout} - * has been specified). If a Container is left to use the default - * {@link Ext.layout.ContainerLayout ContainerLayout} scheme, none of its - * child components will be resized, or changed in any way when the Container - * is resized.Certain layout managers allow dynamic addition of child components. - * Those that do include {@link Ext.layout.CardLayout}, - * {@link Ext.layout.AnchorLayout}, {@link Ext.layout.FormLayout}, and - * {@link Ext.layout.TableLayout}. For example:
- *-// Create the GridPanel. -var myNewGrid = new Ext.grid.GridPanel({ - store: myStore, - columns: myColumnModel, - title: 'Results', // the title becomes the title of the tab -}); - -myTabPanel.add(myNewGrid); // {@link Ext.TabPanel} implicitly uses {@link Ext.layout.CardLayout CardLayout} -myTabPanel.{@link Ext.TabPanel#setActiveTab setActiveTab}(myNewGrid); - *
The example above adds a newly created GridPanel to a TabPanel. Note that - * a TabPanel uses {@link Ext.layout.CardLayout} as its layout manager which - * means all its child items are sized to {@link Ext.layout.FitLayout fit} - * exactly into its client area. - *
Overnesting is a common problem. - * An example of overnesting occurs when a GridPanel is added to a TabPanel - * by wrapping the GridPanel inside a wrapping Panel (that has no - * {@link #layout} specified) and then add that wrapping Panel - * to the TabPanel. The point to realize is that a GridPanel is a - * Component which can be added directly to a Container. If the wrapping Panel - * has no {@link #layout} configuration, then the overnested - * GridPanel will not be sized as expected.
- * - *
Adding via remote configuration
- * - *A server side script can be used to add Components which are generated dynamically on the server. - * An example of adding a GridPanel to a TabPanel where the GridPanel is generated by the server - * based on certain parameters: - *
- *-// execute an Ajax request to invoke server side script: -Ext.Ajax.request({ - url: 'gen-invoice-grid.php', - // send additional parameters to instruct server script - params: { - startDate: Ext.getCmp('start-date').getValue(), - endDate: Ext.getCmp('end-date').getValue() - }, - // process the response object to add it to the TabPanel: - success: function(xhr) { - var newComponent = eval(xhr.responseText); // see discussion below - myTabPanel.add(newComponent); // add the component to the TabPanel - myTabPanel.setActiveTab(newComponent); - }, - failure: function() { - Ext.Msg.alert("Grid create failed", "Server communication failure"); - } -}); -
The server script needs to return an executable Javascript statement which, when processed - * using eval(), will return either a config object with an {@link Ext.Component#xtype xtype}, - * or an instantiated Component. The server might return this for example:
- *-(function() { - function formatDate(value){ - return value ? value.dateFormat('M d, Y') : ''; - }; - - var store = new Ext.data.Store({ - url: 'get-invoice-data.php', - baseParams: { - startDate: '01/01/2008', - endDate: '01/31/2008' - }, - reader: new Ext.data.JsonReader({ - record: 'transaction', - idProperty: 'id', - totalRecords: 'total' - }, [ - 'customer', - 'invNo', - {name: 'date', type: 'date', dateFormat: 'm/d/Y'}, - {name: 'value', type: 'float'} - ]) - }); - - var grid = new Ext.grid.GridPanel({ - title: 'Invoice Report', - bbar: new Ext.PagingToolbar(store), - store: store, - columns: [ - {header: "Customer", width: 250, dataIndex: 'customer', sortable: true}, - {header: "Invoice Number", width: 120, dataIndex: 'invNo', sortable: true}, - {header: "Invoice Date", width: 100, dataIndex: 'date', renderer: formatDate, sortable: true}, - {header: "Value", width: 120, dataIndex: 'value', renderer: 'usMoney', sortable: true} - ], - }); - store.load(); - return grid; // return instantiated component -})(); -
When the above code fragment is passed through the eval function in the success handler - * of the Ajax request, the code is executed by the Javascript processor, and the anonymous function - * runs, and returns the instantiated grid component.
- *Note: since the code above is generated by a server script, the baseParams for - * the Store, the metadata to allow generation of the Record layout, and the ColumnModel - * can all be generated into the code since these are all known on the server.
- * - * @xtype container - */ -Ext.Container = Ext.extend(Ext.BoxComponent, { - /** - * @cfg {Boolean} monitorResize - * True to automatically monitor window resize events to handle anything that is sensitive to the current size - * of the viewport. This value is typically managed by the chosen{@link #layout}
and should not need - * to be set manually. - */ - /** - * @cfg {String/Object} layout - **Important: In order for child items to be correctly sized and - * positioned, typically a layout manager must be specified through - * the
- *layout
configuration option.The sizing and positioning of child {@link items} is the responsibility of - * the Container's layout manager which creates and manages the type of layout - * you have in mind. For example:
- *-new Ext.Window({ - width:300, height: 300, - layout: 'fit', // explicitly set layout manager: override the default (layout:'auto') - items: [{ - title: 'Panel inside a Window' - }] -}).show(); - *
If the {@link #layout} configuration is not explicitly specified for - * a general purpose container (e.g. Container or Panel) the - * {@link Ext.layout.ContainerLayout default layout manager} will be used - * which does nothing but render child components sequentially into the - * Container (no sizing or positioning will be performed in this situation). - * Some container classes implicitly specify a default layout - * (e.g. FormPanel specifies
- *layout:'form'
). Other specific - * purpose classes internally specify/manage their internal layout (e.g. - * GridPanel, TabPanel, TreePanel, Toolbar, Menu, etc.).
layout
may be specified as either as an Object or - * as a String:- */ - /** - * @cfg {Object} layoutConfig - * This is a config object containing properties specific to the chosen - *- * - *
- Specify as an Object
- *- * - *- *
- Example usage:
-- * - *-layout: { - type: 'vbox', - padding: '5', - align: 'left' -} -
- type
- *The layout type to be used for this container. If not specified, - * a default {@link Ext.layout.ContainerLayout} will be created and used.
- *Valid layout type values are:
- *- * - *- *
- {@link Ext.layout.AbsoluteLayout absolute}
- *- {@link Ext.layout.AccordionLayout accordion}
- *- {@link Ext.layout.AnchorLayout anchor}
- *- {@link Ext.layout.ContainerLayout auto} Default
- *- {@link Ext.layout.BorderLayout border}
- *- {@link Ext.layout.CardLayout card}
- *- {@link Ext.layout.ColumnLayout column}
- *- {@link Ext.layout.FitLayout fit}
- *- {@link Ext.layout.FormLayout form}
- *- {@link Ext.layout.HBoxLayout hbox}
- *- {@link Ext.layout.MenuLayout menu}
- *- {@link Ext.layout.TableLayout table}
- *- {@link Ext.layout.ToolbarLayout toolbar}
- *- {@link Ext.layout.VBoxLayout vbox}
- *- Layout specific configuration properties
- *Additional layout specific configuration properties may also be - * specified. For complete details regarding the valid config options for - * each layout type, see the layout class corresponding to the type - * specified.
- * - *- Specify as a String
- *- *
- Example usage:
-- *-layout: 'vbox', -layoutConfig: { - padding: '5', - align: 'left' -} -
- layout
- *The layout type to be used for this container (see list - * of valid layout type values above).
- *- {@link #layoutConfig}
- *Additional layout specific configuration properties. For complete - * details regarding the valid config options for each layout type, see the - * layout class corresponding to the layout specified.
- *{@link #layout}
if{@link #layout}
- * has been specified as a string. - */ - /** - * @cfg {Boolean/Number} bufferResize - * When set to true (50 milliseconds) or a number of milliseconds, the layout assigned for this container will buffer - * the frequency it calculates and does a re-layout of components. This is useful for heavy containers or containers - * with a large quantity of sub-components for which frequent layout calls would be expensive. Defaults to 50. - */ - bufferResize: 50, - - /** - * @cfg {String/Number} activeItem - * A string component id or the numeric index of the component that should be initially activated within the - * container's layout on render. For example, activeItem: 'item-1' or activeItem: 0 (index 0 = the first - * item in the container's collection). activeItem only applies to layout styles that can display - * items one at a time (like {@link Ext.layout.AccordionLayout}, {@link Ext.layout.CardLayout} and - * {@link Ext.layout.FitLayout}). Related to {@link Ext.layout.ContainerLayout#activeItem}. - */ - /** - * @cfg {Object/Array} items - *** IMPORTANT: be sure to {@link #layout specify a- *layout
} if needed ! **A single item, or an array of child Components to be added to this container, - * for example:
- *- *-// specifying a single item -items: {...}, -layout: 'fit', // specify a layout! - -// specifying multiple items -items: [{...}, {...}], -layout: 'anchor', // specify a layout! - *
Each item may be:
- *- *- *
- any type of object based on {@link Ext.Component}
- *- a fully instanciated object or
- *- an object literal that:
- *- *
- has a specified
- *{@link Ext.Component#xtype xtype}
- the {@link Ext.Component#xtype} specified is associated with the Component - * desired and should be chosen from one of the available xtypes as listed - * in {@link Ext.Component}.
- *- If an
- *{@link Ext.Component#xtype xtype}
is not explicitly - * specified, the {@link #defaultType} for that Container is used.- will be "lazily instanciated", avoiding the overhead of constructing a fully - * instanciated Component object
- *Notes:
- *- */ - /** - * @cfg {Object} defaults - *- *
- Ext uses lazy rendering. Child Components will only be rendered - * should it become necessary. Items are automatically laid out when they are first - * shown (no sizing is done while hidden), or in response to a {@link #doLayout} call.
- *- Do not specify
- *{@link Ext.Panel#contentEl contentEl}
/ - *{@link Ext.Panel#html html}
withitems
.A config object that will be applied to all components added to this container either via the {@link #items} - * config or via the {@link #add} or {@link #insert} methods. The defaults config can contain any - * number of name/value property pairs to be added to each item, and should be valid for the types of items - * being added to the container. For example, to automatically apply padding to the body of each of a set of - * contained {@link Ext.Panel} items, you could pass: defaults: {bodyStyle:'padding:15px'}.
- *Note: defaults will not be applied to config objects if the option is already specified. - * For example:
- */ - - - /** @cfg {Boolean} autoDestroy - * If true the container will automatically destroy any contained component that is removed from it, else - * destruction must be handled manually (defaults to true). - */ - autoDestroy : true, - - /** @cfg {Boolean} forceLayout - * If true the container will force a layout initially even if hidden or collapsed. This option - * is useful for forcing forms to render in collapsed or hidden containers. (defaults to false). - */ - forceLayout: false, - - /** @cfg {Boolean} hideBorders - * True to hide the borders of each contained component, false to defer to the component's existing - * border settings (defaults to false). - */ - /** @cfg {String} defaultType - *-defaults: { // defaults are applied to items, not the container - autoScroll:true -}, -items: [ - { - xtype: 'panel', // defaults do not have precedence over - id: 'panel1', // options in config objects, so the defaults - autoScroll: false // will not be applied here, panel1 will be autoScroll:false - }, - new Ext.Panel({ // defaults do have precedence over options - id: 'panel2', // options in components, so the defaults - autoScroll: false // will be applied here, panel2 will be autoScroll:true. - }) -] - *
The default {@link Ext.Component xtype} of child Components to create in this Container when - * a child item is specified as a raw configuration object, rather than as an instantiated Component.
- *Defaults to 'panel', except {@link Ext.menu.Menu} which defaults to 'menuitem', - * and {@link Ext.Toolbar} and {@link Ext.ButtonGroup} which default to 'button'.
- */ - defaultType : 'panel', - - /** @cfg {String} resizeEvent - * The event to listen to for resizing in layouts. Defaults to 'resize'. - */ - resizeEvent: 'resize', - - /** - * @cfg {Array} bubbleEvents - *An array of events that, when fired, should be bubbled to any parent container. - * Defaults to ['add', 'remove']. - */ - bubbleEvents: ['add', 'remove'], - - // private - initComponent : function(){ - Ext.Container.superclass.initComponent.call(this); - - this.addEvents( -
/** - * @event afterlayout - * Fires when the components in this container are arranged by the associated layout manager. - * @param {Ext.Container} this - * @param {ContainerLayout} layout The ContainerLayout implementation for this container - */ - 'afterlayout', - /** - * @event beforeadd - * Fires before any {@link Ext.Component} is added or inserted into the container. - * A handler can return false to cancel the add. - * @param {Ext.Container} this - * @param {Ext.Component} component The component being added - * @param {Number} index The index at which the component will be added to the container's items collection - */ - 'beforeadd', - /** - * @event beforeremove - * Fires before any {@link Ext.Component} is removed from the container. A handler can return - * false to cancel the remove. - * @param {Ext.Container} this - * @param {Ext.Component} component The component being removed - */ - 'beforeremove', - /** - * @event add - * @bubbles - * Fires after any {@link Ext.Component} is added or inserted into the container. - * @param {Ext.Container} this - * @param {Ext.Component} component The component that was added - * @param {Number} index The index at which the component was added to the container's items collection - */ - 'add', - /** - * @event remove - * @bubbles - * Fires after any {@link Ext.Component} is removed from the container. - * @param {Ext.Container} this - * @param {Ext.Component} component The component that was removed - */ - 'remove' - ); - - this.enableBubble(this.bubbleEvents); - - /** - * The collection of components in this container as a {@link Ext.util.MixedCollection} - * @type MixedCollection - * @property items - */ - var items = this.items; - if(items){ - delete this.items; - this.add(items); - } - }, - - // private - initItems : function(){ - if(!this.items){ - this.items = new Ext.util.MixedCollection(false, this.getComponentId); - this.getLayout(); // initialize the layout - } - }, - - // private - setLayout : function(layout){ - if(this.layout && this.layout != layout){ - this.layout.setContainer(null); - } - this.initItems(); - this.layout = layout; - layout.setContainer(this); - }, - - afterRender: function(){ - Ext.Container.superclass.afterRender.call(this); - if(!this.layout){ - this.layout = 'auto'; - } - if(Ext.isObject(this.layout) && !this.layout.layout){ - this.layoutConfig = this.layout; - this.layout = this.layoutConfig.type; - } - if(Ext.isString(this.layout)){ - this.layout = new Ext.Container.LAYOUTS[this.layout.toLowerCase()](this.layoutConfig); - } - this.setLayout(this.layout); - - if(this.activeItem !== undefined){ - var item = this.activeItem; - delete this.activeItem; - this.layout.setActiveItem(item); - } - if(!this.ownerCt){ - // force a layout if no ownerCt is set - this.doLayout(false, true); - } - if(this.monitorResize === true){ - Ext.EventManager.onWindowResize(this.doLayout, this, [false]); - } - }, - - /** - *Returns the Element to be used to contain the child Components of this Container.
- *An implementation is provided which returns the Container's {@link #getEl Element}, but - * if there is a more complex structure to a Container, this may be overridden to return - * the element into which the {@link #layout layout} renders child Components.
- * @return {Ext.Element} The Element to render child Components into. - */ - getLayoutTarget : function(){ - return this.el; - }, - - // private - used as the key lookup function for the items collection - getComponentId : function(comp){ - return comp.getItemId(); - }, - - /** - *Adds {@link Ext.Component Component}(s) to this Container.
- *Description : - *
- *- *
- Fires the {@link #beforeadd} event before adding
- *- The Container's {@link #defaults default config values} will be applied - * accordingly (see
- *{@link #defaults}
for details).- Fires the {@link #add} event after the component has been added.
- *Notes : - *
- * @param {Object/Array} component - *- *
- If the Container is already rendered when add - * is called, you may need to call {@link #doLayout} to refresh the view which causes - * any unrendered child Components to be rendered. This is required so that you can - * add multiple child components if needed while only refreshing the layout - * once. For example:
- *-var tb = new {@link Ext.Toolbar}(); -tb.render(document.body); // toolbar is rendered -tb.add({text:'Button 1'}); // add multiple items ({@link #defaultType} for {@link Ext.Toolbar Toolbar} is 'button') -tb.add({text:'Button 2'}); -tb.{@link #doLayout}(); // refresh the layout - *
- Warning: Containers directly managed by the BorderLayout layout manager - * may not be removed or added. See the Notes for {@link Ext.layout.BorderLayout BorderLayout} - * for more details.
- *Either a single component or an Array of components to add. See - *
- * @param {Object} (Optional) component_2 - * @param {Object} (Optional) component_n - * @return {Ext.Component} component The Component (or config object) that was added. - */ - add : function(comp){ - this.initItems(); - var args = arguments.length > 1; - if(args || Ext.isArray(comp)){ - Ext.each(args ? arguments : comp, function(c){ - this.add(c); - }, this); - return; - } - var c = this.lookupComponent(this.applyDefaults(comp)); - var pos = this.items.length; - if(this.fireEvent('beforeadd', this, c, pos) !== false && this.onBeforeAdd(c) !== false){ - this.items.add(c); - c.ownerCt = this; - this.onAdd(c); - this.fireEvent('add', this, c, pos); - } - return c; - }, - - onAdd : function(c){ - // Empty template method - }, - - /** - * Inserts a Component into this Container at a specified index. Fires the - * {@link #beforeadd} event before inserting, then fires the {@link #add} event after the - * Component has been inserted. - * @param {Number} index The index at which the Component will be inserted - * into the Container's items collection - * @param {Ext.Component} component The child Component to insert.{@link #items}
for additional information.
- * Ext uses lazy rendering, and will only render the inserted Component should - * it become necessary.
- * A Component config object may be passed in order to avoid the overhead of - * constructing a real Component object if lazy rendering might mean that the - * inserted Component will not be rendered immediately. To take advantage of - * this 'lazy instantiation', set the {@link Ext.Component#xtype} config - * property to the registered type of the Component wanted.
- * For a list of all available xtypes, see {@link Ext.Component}. - * @return {Ext.Component} component The Component (or config object) that was - * inserted with the Container's default config values applied. - */ - insert : function(index, comp){ - this.initItems(); - var a = arguments, len = a.length; - if(len > 2){ - for(var i = len-1; i >= 1; --i) { - this.insert(index, a[i]); - } - return; - } - var c = this.lookupComponent(this.applyDefaults(comp)); - index = Math.min(index, this.items.length); - if(this.fireEvent('beforeadd', this, c, index) !== false && this.onBeforeAdd(c) !== false){ - if(c.ownerCt == this){ - this.items.remove(c); - } - this.items.insert(index, c); - c.ownerCt = this; - this.onAdd(c); - this.fireEvent('add', this, c, index); - } - return c; - }, - - // private - applyDefaults : function(c){ - if(this.defaults){ - if(Ext.isString(c)){ - c = Ext.ComponentMgr.get(c); - Ext.apply(c, this.defaults); - }else if(!c.events){ - Ext.applyIf(c, this.defaults); - }else{ - Ext.apply(c, this.defaults); - } - } - return c; - }, - - // private - onBeforeAdd : function(item){ - if(item.ownerCt){ - item.ownerCt.remove(item, false); - } - if(this.hideBorders === true){ - item.border = (item.border === true); - } - }, - - /** - * Removes a component from this container. Fires the {@link #beforeremove} event before removing, then fires - * the {@link #remove} event after the component has been removed. - * @param {Component/String} component The component reference or id to remove. - * @param {Boolean} autoDestroy (optional) True to automatically invoke the removed Component's {@link Ext.Component#destroy} function. - * Defaults to the value of this Container's {@link #autoDestroy} config. - * @return {Ext.Component} component The Component that was removed. - */ - remove : function(comp, autoDestroy){ - this.initItems(); - var c = this.getComponent(comp); - if(c && this.fireEvent('beforeremove', this, c) !== false){ - delete c.ownerCt; - if(this.layout && this.rendered){ - this.layout.onRemove(c); - } - this.onRemove(c); - this.items.remove(c); - if(autoDestroy === true || (autoDestroy !== false && this.autoDestroy)){ - c.destroy(); - } - this.fireEvent('remove', this, c); - } - return c; - }, - - onRemove: function(c){ - // Empty template method - }, - - /** - * Removes all components from this container. - * @param {Boolean} autoDestroy (optional) True to automatically invoke the removed Component's {@link Ext.Component#destroy} function. - * Defaults to the value of this Container's {@link #autoDestroy} config. - * @return {Array} Array of the destroyed components - */ - removeAll: function(autoDestroy){ - this.initItems(); - var item, rem = [], items = []; - this.items.each(function(i){ - rem.push(i); - }); - for (var i = 0, len = rem.length; i < len; ++i){ - item = rem[i]; - this.remove(item, autoDestroy); - if(item.ownerCt !== this){ - items.push(item); - } - } - return items; - }, - - /** - * Examines this container's{@link #items}
property - * and gets a direct child component of this container. - * @param {String/Number} comp This parameter may be any of the following: - *- *- *
- a String : representing the
- *{@link Ext.Component#itemId itemId}
- * or{@link Ext.Component#id id}
of the child component- a Number : representing the position of the child component - * within the
- *{@link #items}
propertyFor additional information see {@link Ext.util.MixedCollection#get}. - * @return Ext.Component The component (if found). - */ - getComponent : function(comp){ - if(Ext.isObject(comp)){ - comp = comp.getItemId(); - } - return this.items.get(comp); - }, - - // private - lookupComponent : function(comp){ - if(Ext.isString(comp)){ - return Ext.ComponentMgr.get(comp); - }else if(!comp.events){ - return this.createComponent(comp); - } - return comp; - }, - - // private - createComponent : function(config){ - return Ext.create(config, this.defaultType); - }, - - // private - canLayout: function() { - var el = this.getVisibilityEl(); - return el && !el.isStyle("display", "none"); - }, - - -
/** - * Force this container's layout to be recalculated. A call to this function is required after adding a new component - * to an already rendered container, or possibly after changing sizing/position properties of child components. - * @param {Boolean} shallow (optional) True to only calc the layout of this component, and let child components auto - * calc layouts as required (defaults to false, which calls doLayout recursively for each subcontainer) - * @param {Boolean} force (optional) True to force a layout to occur, even if the item is hidden. - * @return {Ext.Container} this - */ - doLayout: function(shallow, force){ - var rendered = this.rendered; - forceLayout = force || this.forceLayout; - - if(!this.canLayout() || this.collapsed){ - this.deferLayout = this.deferLayout || !shallow; - if(!forceLayout){ - return; - } - shallow = shallow && !this.deferLayout; - } else { - delete this.deferLayout; - } - if(rendered && this.layout){ - this.layout.layout(); - } - if(shallow !== true && this.items){ - var cs = this.items.items; - for(var i = 0, len = cs.length; i < len; i++){ - var c = cs[i]; - if(c.doLayout){ - c.doLayout(false, forceLayout); - } - } - } - if(rendered){ - this.onLayout(shallow, forceLayout); - } - // Initial layout completed - this.hasLayout = true; - delete this.forceLayout; - }, - - //private - onLayout : Ext.emptyFn, - - // private - shouldBufferLayout: function(){ - /* - * Returns true if the container should buffer a layout. - * This is true only if the container has previously been laid out - * and has a parent container that is pending a layout. - */ - var hl = this.hasLayout; - if(this.ownerCt){ - // Only ever buffer if we've laid out the first time and we have one pending. - return hl ? !this.hasLayoutPending() : false; - } - // Never buffer initial layout - return hl; - }, - - // private - hasLayoutPending: function(){ - // Traverse hierarchy to see if any parent container has a pending layout. - var pending = false; - this.ownerCt.bubble(function(c){ - if(c.layoutPending){ - pending = true; - return false; - } - }); - return pending; - }, - - onShow : function(){ - Ext.Container.superclass.onShow.call(this); - if(this.deferLayout !== undefined){ - this.doLayout(true); - } - }, - - /** - * Returns the layout currently in use by the container. If the container does not currently have a layout - * set, a default {@link Ext.layout.ContainerLayout} will be created and set as the container's layout. - * @return {ContainerLayout} layout The container's layout - */ - getLayout : function(){ - if(!this.layout){ - var layout = new Ext.layout.ContainerLayout(this.layoutConfig); - this.setLayout(layout); - } - return this.layout; - }, - - // private - beforeDestroy : function(){ - if(this.items){ - Ext.destroy.apply(Ext, this.items.items); - } - if(this.monitorResize){ - Ext.EventManager.removeResizeListener(this.doLayout, this); - } - Ext.destroy(this.layout); - Ext.Container.superclass.beforeDestroy.call(this); - }, - - /** - * Bubbles up the component/container heirarchy, calling the specified function with each component. The scope (this) of - * function call will be the scope provided or the current component. The arguments to the function - * will be the args provided or the current component. If the function returns false at any point, - * the bubble is stopped. - * @param {Function} fn The function to call - * @param {Object} scope (optional) The scope of the function (defaults to current node) - * @param {Array} args (optional) The args to call the function with (default to passing the current component) - * @return {Ext.Container} this - */ - bubble : function(fn, scope, args){ - var p = this; - while(p){ - if(fn.apply(scope || p, args || [p]) === false){ - break; - } - p = p.ownerCt; - } - return this; - }, - - /** - * Cascades down the component/container heirarchy from this component (called first), calling the specified function with - * each component. The scope (this) of - * function call will be the scope provided or the current component. The arguments to the function - * will be the args provided or the current component. If the function returns false at any point, - * the cascade is stopped on that branch. - * @param {Function} fn The function to call - * @param {Object} scope (optional) The scope of the function (defaults to current component) - * @param {Array} args (optional) The args to call the function with (defaults to passing the current component) - * @return {Ext.Container} this - */ - cascade : function(fn, scope, args){ - if(fn.apply(scope || this, args || [this]) !== false){ - if(this.items){ - var cs = this.items.items; - for(var i = 0, len = cs.length; i < len; i++){ - if(cs[i].cascade){ - cs[i].cascade(fn, scope, args); - }else{ - fn.apply(scope || cs[i], args || [cs[i]]); - } - } - } - } - return this; - }, - - /** - * Find a component under this container at any level by id - * @param {String} id - * @return Ext.Component - */ - findById : function(id){ - var m, ct = this; - this.cascade(function(c){ - if(ct != c && c.id === id){ - m = c; - return false; - } - }); - return m || null; - }, - - /** - * Find a component under this container at any level by xtype or class - * @param {String/Class} xtype The xtype string for a component, or the class of the component directly - * @param {Boolean} shallow (optional) False to check whether this Component is descended from the xtype (this is - * the default), or true to check whether this Component is directly of the specified xtype. - * @return {Array} Array of Ext.Components - */ - findByType : function(xtype, shallow){ - return this.findBy(function(c){ - return c.isXType(xtype, shallow); - }); - }, - - /** - * Find a component under this container at any level by property - * @param {String} prop - * @param {String} value - * @return {Array} Array of Ext.Components - */ - find : function(prop, value){ - return this.findBy(function(c){ - return c[prop] === value; - }); - }, - - /** - * Find a component under this container at any level by a custom function. If the passed function returns - * true, the component will be included in the results. The passed function is called with the arguments (component, this container). - * @param {Function} fn The function to call - * @param {Object} scope (optional) - * @return {Array} Array of Ext.Components - */ - findBy : function(fn, scope){ - var m = [], ct = this; - this.cascade(function(c){ - if(ct != c && fn.call(scope || c, c, ct) === true){ - m.push(c); - } - }); - return m; - }, - - /** - * Get a component contained by this container (alias for items.get(key)) - * @param {String/Number} key The index or id of the component - * @return {Ext.Component} Ext.Component - */ - get : function(key){ - return this.items.get(key); - } -}); - -Ext.Container.LAYOUTS = {}; -Ext.reg('container', Ext.Container); -{@link #layout}
and should not need + * to be set manually. + */ + /** + * @cfg {String/Object} layout + **Important: In order for child items to be correctly sized and + * positioned, typically a layout manager must be specified through + * the
+ *layout
configuration option.The sizing and positioning of child {@link items} is the responsibility of + * the Container's layout manager which creates and manages the type of layout + * you have in mind. For example:
+ *+new Ext.Window({ + width:300, height: 300, + layout: 'fit', // explicitly set layout manager: override the default (layout:'auto') + items: [{ + title: 'Panel inside a Window' + }] +}).show(); + *
If the {@link #layout} configuration is not explicitly specified for + * a general purpose container (e.g. Container or Panel) the + * {@link Ext.layout.ContainerLayout default layout manager} will be used + * which does nothing but render child components sequentially into the + * Container (no sizing or positioning will be performed in this situation). + * Some container classes implicitly specify a default layout + * (e.g. FormPanel specifies
+ *layout:'form'
). Other specific + * purpose classes internally specify/manage their internal layout (e.g. + * GridPanel, TabPanel, TreePanel, Toolbar, Menu, etc.).
layout
may be specified as either as an Object or + * as a String:+ */ + /** + * @cfg {Object} layoutConfig + * This is a config object containing properties specific to the chosen + *+ * + *
- Specify as an Object
+ *+ * + *+ *
- Example usage:
++ * + *+layout: { + type: 'vbox', + padding: '5', + align: 'left' +} +
- + *
type
The layout type to be used for this container. If not specified, + * a default {@link Ext.layout.ContainerLayout} will be created and used.
+ *Valid layout
+ *type
values are:+ * + *+ *
- + *
{@link Ext.layout.AbsoluteLayout absolute}
- + *
{@link Ext.layout.AccordionLayout accordion}
- + *
{@link Ext.layout.AnchorLayout anchor}
- + *
{@link Ext.layout.ContainerLayout auto}
Default- + *
{@link Ext.layout.BorderLayout border}
- + *
{@link Ext.layout.CardLayout card}
- + *
{@link Ext.layout.ColumnLayout column}
- + *
{@link Ext.layout.FitLayout fit}
- + *
{@link Ext.layout.FormLayout form}
- + *
{@link Ext.layout.HBoxLayout hbox}
- + *
{@link Ext.layout.MenuLayout menu}
- + *
{@link Ext.layout.TableLayout table}
- + *
{@link Ext.layout.ToolbarLayout toolbar}
- + *
{@link Ext.layout.VBoxLayout vbox}
- Layout specific configuration properties
+ *Additional layout specific configuration properties may also be + * specified. For complete details regarding the valid config options for + * each layout type, see the layout class corresponding to the
+ * + *type
+ * specified.- Specify as a String
+ *+ *
- Example usage:
++ *+layout: 'vbox', +layoutConfig: { + padding: '5', + align: 'left' +} +
- + *
layout
The layout
type
to be used for this container (see list + * of valid layout type values above).
+ *- + *
{@link #layoutConfig}
Additional layout specific configuration properties. For complete + * details regarding the valid config options for each layout type, see the + * layout class corresponding to the
+ *layout
specified.{@link #layout}
if{@link #layout}
+ * has been specified as a string. + */ + /** + * @cfg {Boolean/Number} bufferResize + * When set to true (50 milliseconds) or a number of milliseconds, the layout assigned for this container will buffer + * the frequency it calculates and does a re-layout of components. This is useful for heavy containers or containers + * with a large quantity of sub-components for which frequent layout calls would be expensive. Defaults to50
. + */ + bufferResize: 50, + + /** + * @cfg {String/Number} activeItem + * A string component id or the numeric index of the component that should be initially activated within the + * container's layout on render. For example, activeItem: 'item-1' or activeItem: 0 (index 0 = the first + * item in the container's collection). activeItem only applies to layout styles that can display + * items one at a time (like {@link Ext.layout.AccordionLayout}, {@link Ext.layout.CardLayout} and + * {@link Ext.layout.FitLayout}). Related to {@link Ext.layout.ContainerLayout#activeItem}. + */ + /** + * @cfg {Object/Array} items + *** IMPORTANT: be sure to {@link #layout specify a+ *layout
} if needed ! **A single item, or an array of child Components to be added to this container, + * for example:
+ *+ *+// specifying a single item +items: {...}, +layout: 'fit', // specify a layout! + +// specifying multiple items +items: [{...}, {...}], +layout: 'anchor', // specify a layout! + *
Each item may be:
+ *+ *+ *
- any type of object based on {@link Ext.Component}
+ *- a fully instanciated object or
+ *- an object literal that:
+ *+ *
- has a specified
+ *{@link Ext.Component#xtype xtype}
- the {@link Ext.Component#xtype} specified is associated with the Component + * desired and should be chosen from one of the available xtypes as listed + * in {@link Ext.Component}.
+ *- If an
+ *{@link Ext.Component#xtype xtype}
is not explicitly + * specified, the {@link #defaultType} for that Container is used.- will be "lazily instanciated", avoiding the overhead of constructing a fully + * instanciated Component object
+ *Notes:
+ *+ */ + /** + * @cfg {Object|Function} defaults + *+ *
- Ext uses lazy rendering. Child Components will only be rendered + * should it become necessary. Items are automatically laid out when they are first + * shown (no sizing is done while hidden), or in response to a {@link #doLayout} call.
+ *- Do not specify
+ *{@link Ext.Panel#contentEl contentEl}
/ + *{@link Ext.Panel#html html}
withitems
.This option is a means of applying default settings to all added items whether added through the {@link #items} + * config or via the {@link #add} or {@link #insert} methods.
+ *If an added item is a config object, and not an instantiated Component, then the default properties are + * unconditionally applied. If the added item is an instantiated Component, then the default properties are + * applied conditionally so as not to override existing properties in the item.
+ *If the defaults option is specified as a function, then the function will be called using this Container as the + * scope (
+ *this
reference) and passing the added item as the first parameter. Any resulting object + * from that call is then applied to the item as default properties.For example, to automatically apply padding to the body of each of a set of + * contained {@link Ext.Panel} items, you could pass:
+ *defaults: {bodyStyle:'padding:15px'}
.Usage:
+ */ + + + /** @cfg {Boolean} autoDestroy + * If true the container will automatically destroy any contained component that is removed from it, else + * destruction must be handled manually (defaults to true). + */ + autoDestroy : true, + + /** @cfg {Boolean} forceLayout + * If true the container will force a layout initially even if hidden or collapsed. This option + * is useful for forcing forms to render in collapsed or hidden containers. (defaults to false). + */ + forceLayout: false, + + /** @cfg {Boolean} hideBorders + * True to hide the borders of each contained component, false to defer to the component's existing + * border settings (defaults to false). + */ + /** @cfg {String} defaultType + *+defaults: { // defaults are applied to items, not the container + autoScroll:true +}, +items: [ + { + xtype: 'panel', // defaults do not have precedence over + id: 'panel1', // options in config objects, so the defaults + autoScroll: false // will not be applied here, panel1 will be autoScroll:false + }, + new Ext.Panel({ // defaults do have precedence over options + id: 'panel2', // options in components, so the defaults + autoScroll: false // will be applied here, panel2 will be autoScroll:true. + }) +] + *
The default {@link Ext.Component xtype} of child Components to create in this Container when + * a child item is specified as a raw configuration object, rather than as an instantiated Component.
+ *Defaults to
+ */ + defaultType : 'panel', + + /** @cfg {String} resizeEvent + * The event to listen to for resizing in layouts. Defaults to'panel'
, except {@link Ext.menu.Menu} which defaults to'menuitem'
, + * and {@link Ext.Toolbar} and {@link Ext.ButtonGroup} which default to'button'
.'resize'
. + */ + resizeEvent: 'resize', + + /** + * @cfg {Array} bubbleEvents + *An array of events that, when fired, should be bubbled to any parent container. + * See {@link Ext.util.Observable#enableBubble}. + * Defaults to
/** + * @event afterlayout + * Fires when the components in this container are arranged by the associated layout manager. + * @param {Ext.Container} this + * @param {ContainerLayout} layout The ContainerLayout implementation for this container + */ + 'afterlayout', + /** + * @event beforeadd + * Fires before any {@link Ext.Component} is added or inserted into the container. + * A handler can return false to cancel the add. + * @param {Ext.Container} this + * @param {Ext.Component} component The component being added + * @param {Number} index The index at which the component will be added to the container's items collection + */ + 'beforeadd', + /** + * @event beforeremove + * Fires before any {@link Ext.Component} is removed from the container. A handler can return + * false to cancel the remove. + * @param {Ext.Container} this + * @param {Ext.Component} component The component being removed + */ + 'beforeremove', + /** + * @event add + * @bubbles + * Fires after any {@link Ext.Component} is added or inserted into the container. + * @param {Ext.Container} this + * @param {Ext.Component} component The component that was added + * @param {Number} index The index at which the component was added to the container's items collection + */ + 'add', + /** + * @event remove + * @bubbles + * Fires after any {@link Ext.Component} is removed from the container. + * @param {Ext.Container} this + * @param {Ext.Component} component The component that was removed + */ + 'remove' + ); + + this.enableBubble(this.bubbleEvents); + + /** + * The collection of components in this container as a {@link Ext.util.MixedCollection} + * @type MixedCollection + * @property items + */ + var items = this.items; + if(items){ + delete this.items; + this.add(items); + } + }, + + // private + initItems : function(){ + if(!this.items){ + this.items = new Ext.util.MixedCollection(false, this.getComponentId); + this.getLayout(); // initialize the layout + } + }, + + // private + setLayout : function(layout){ + if(this.layout && this.layout != layout){ + this.layout.setContainer(null); + } + this.initItems(); + this.layout = layout; + layout.setContainer(this); + }, + + afterRender: function(){ + this.layoutDone = false; + if(!this.layout){ + this.layout = 'auto'; + } + if(Ext.isObject(this.layout) && !this.layout.layout){ + this.layoutConfig = this.layout; + this.layout = this.layoutConfig.type; + } + if(Ext.isString(this.layout)){ + this.layout = new Ext.Container.LAYOUTS[this.layout.toLowerCase()](this.layoutConfig); + } + this.setLayout(this.layout); + + // BoxComponent's afterRender will set the size. + // This will will trigger a layout if the layout is configured to monitor resize + Ext.Container.superclass.afterRender.call(this); + + if(Ext.isDefined(this.activeItem)){ + var item = this.activeItem; + delete this.activeItem; + this.layout.setActiveItem(item); + } + + // If we have no ownerCt and the BoxComponent's sizing did not trigger a layout, force a layout + if(!this.ownerCt && !this.layoutDone){ + this.doLayout(false, true); + } + + if(this.monitorResize === true){ + Ext.EventManager.onWindowResize(this.doLayout, this, [false]); + } + }, + + /** + *['add', 'remove']
. + */ + bubbleEvents: ['add', 'remove'], + + // private + initComponent : function(){ + Ext.Container.superclass.initComponent.call(this); + + this.addEvents( +Returns the Element to be used to contain the child Components of this Container.
+ *An implementation is provided which returns the Container's {@link #getEl Element}, but + * if there is a more complex structure to a Container, this may be overridden to return + * the element into which the {@link #layout layout} renders child Components.
+ * @return {Ext.Element} The Element to render child Components into. + */ + getLayoutTarget : function(){ + return this.el; + }, + + // private - used as the key lookup function for the items collection + getComponentId : function(comp){ + return comp.getItemId(); + }, + + /** + *Adds {@link Ext.Component Component}(s) to this Container.
+ *Description : + *
+ *+ *
- Fires the {@link #beforeadd} event before adding
+ *- The Container's {@link #defaults default config values} will be applied + * accordingly (see
+ *{@link #defaults}
for details).- Fires the {@link #add} event after the component has been added.
+ *Notes : + *
+ * @param {Object/Array} component + *+ *
- If the Container is already rendered when
+ *add
+ * is called, you may need to call {@link #doLayout} to refresh the view which causes + * any unrendered child Components to be rendered. This is required so that you can + *add
multiple child components if needed while only refreshing the layout + * once. For example:+var tb = new {@link Ext.Toolbar}(); +tb.render(document.body); // toolbar is rendered +tb.add({text:'Button 1'}); // add multiple items ({@link #defaultType} for {@link Ext.Toolbar Toolbar} is 'button') +tb.add({text:'Button 2'}); +tb.{@link #doLayout}(); // refresh the layout + *
- Warning: Containers directly managed by the BorderLayout layout manager + * may not be removed or added. See the Notes for {@link Ext.layout.BorderLayout BorderLayout} + * for more details.
+ *Either a single component or an Array of components to add. See + *
+ * @param {Object} (Optional) component_2 + * @param {Object} (Optional) component_n + * @return {Ext.Component} component The Component (or config object) that was added. + */ + add : function(comp){ + this.initItems(); + var args = arguments.length > 1; + if(args || Ext.isArray(comp)){ + var result = []; + Ext.each(args ? arguments : comp, function(c){ + result.push(this.add(c)); + }, this); + return result; + } + var c = this.lookupComponent(this.applyDefaults(comp)); + var index = this.items.length; + if(this.fireEvent('beforeadd', this, c, index) !== false && this.onBeforeAdd(c) !== false){ + this.items.add(c); + // *onAdded + c.onAdded(this, index); + this.onAdd(c); + this.fireEvent('add', this, c, index); + } + return c; + }, + + onAdd : function(c){ + // Empty template method + }, + + // private + onAdded : function(container, pos) { + //overridden here so we can cascade down, not worth creating a template method. + this.ownerCt = container; + this.initRef(); + //initialize references for child items + this.cascade(function(c){ + c.initRef(); + }); + this.fireEvent('added', this, container, pos); + }, + + /** + * Inserts a Component into this Container at a specified index. Fires the + * {@link #beforeadd} event before inserting, then fires the {@link #add} event after the + * Component has been inserted. + * @param {Number} index The index at which the Component will be inserted + * into the Container's items collection + * @param {Ext.Component} component The child Component to insert.{@link #items}
for additional information.
+ * Ext uses lazy rendering, and will only render the inserted Component should + * it become necessary.
+ * A Component config object may be passed in order to avoid the overhead of + * constructing a real Component object if lazy rendering might mean that the + * inserted Component will not be rendered immediately. To take advantage of + * this 'lazy instantiation', set the {@link Ext.Component#xtype} config + * property to the registered type of the Component wanted.
+ * For a list of all available xtypes, see {@link Ext.Component}. + * @return {Ext.Component} component The Component (or config object) that was + * inserted with the Container's default config values applied. + */ + insert : function(index, comp){ + this.initItems(); + var a = arguments, len = a.length; + if(len > 2){ + var result = []; + for(var i = len-1; i >= 1; --i) { + result.push(this.insert(index, a[i])); + } + return result; + } + var c = this.lookupComponent(this.applyDefaults(comp)); + index = Math.min(index, this.items.length); + if(this.fireEvent('beforeadd', this, c, index) !== false && this.onBeforeAdd(c) !== false){ + if(c.ownerCt == this){ + this.items.remove(c); + } + this.items.insert(index, c); + c.onAdded(this, index); + this.onAdd(c); + this.fireEvent('add', this, c, index); + } + return c; + }, + + // private + applyDefaults : function(c){ + var d = this.defaults; + if(d){ + if(Ext.isFunction(d)){ + d = d.call(this, c); + } + if(Ext.isString(c)){ + c = Ext.ComponentMgr.get(c); + Ext.apply(c, d); + }else if(!c.events){ + Ext.applyIf(c, d); + }else{ + Ext.apply(c, d); + } + } + return c; + }, + + // private + onBeforeAdd : function(item){ + if(item.ownerCt){ + item.ownerCt.remove(item, false); + } + if(this.hideBorders === true){ + item.border = (item.border === true); + } + }, + + /** + * Removes a component from this container. Fires the {@link #beforeremove} event before removing, then fires + * the {@link #remove} event after the component has been removed. + * @param {Component/String} component The component reference or id to remove. + * @param {Boolean} autoDestroy (optional) True to automatically invoke the removed Component's {@link Ext.Component#destroy} function. + * Defaults to the value of this Container's {@link #autoDestroy} config. + * @return {Ext.Component} component The Component that was removed. + */ + remove : function(comp, autoDestroy){ + this.initItems(); + var c = this.getComponent(comp); + if(c && this.fireEvent('beforeremove', this, c) !== false){ + this.doRemove(c, autoDestroy); + this.fireEvent('remove', this, c); + } + return c; + }, + + onRemove: function(c){ + // Empty template method + }, + + // private + doRemove: function(c, autoDestroy){ + if(this.layout && this.rendered){ + this.layout.onRemove(c); + } + this.items.remove(c); + c.onRemoved(); + this.onRemove(c); + if(autoDestroy === true || (autoDestroy !== false && this.autoDestroy)){ + c.destroy(); + } + }, + + /** + * Removes all components from this container. + * @param {Boolean} autoDestroy (optional) True to automatically invoke the removed Component's {@link Ext.Component#destroy} function. + * Defaults to the value of this Container's {@link #autoDestroy} config. + * @return {Array} Array of the destroyed components + */ + removeAll: function(autoDestroy){ + this.initItems(); + var item, rem = [], items = []; + this.items.each(function(i){ + rem.push(i); + }); + for (var i = 0, len = rem.length; i < len; ++i){ + item = rem[i]; + this.remove(item, autoDestroy); + if(item.ownerCt !== this){ + items.push(item); + } + } + return items; + }, + + /** + * Examines this container's{@link #items}
property + * and gets a direct child component of this container. + * @param {String/Number} comp This parameter may be any of the following: + *+ *+ *
- a
+ *String
: representing the{@link Ext.Component#itemId itemId}
+ * or{@link Ext.Component#id id}
of the child component- a
+ *Number
: representing the position of the child component + * within the{@link #items}
propertyFor additional information see {@link Ext.util.MixedCollection#get}. + * @return Ext.Component The component (if found). + */ + getComponent : function(comp){ + if(Ext.isObject(comp)){ + comp = comp.getItemId(); + } + return this.items.get(comp); + }, + + // private + lookupComponent : function(comp){ + if(Ext.isString(comp)){ + return Ext.ComponentMgr.get(comp); + }else if(!comp.events){ + return this.createComponent(comp); + } + return comp; + }, + + // private + createComponent : function(config, defaultType){ + // add in ownerCt at creation time but then immediately + // remove so that onBeforeAdd can handle it + var c = config.render ? config : Ext.create(Ext.apply({ + ownerCt: this + }, config), defaultType || this.defaultType); + delete c.ownerCt; + return c; + }, + +
/** + * We can only lay out if there is a view area in which to layout. + * display:none on the layout target, *or any of its parent elements* will mean it has no view area. + */ + canLayout: function() { + var el = this.getLayoutTarget(), vs; + return !!(el && (vs = el.dom.offsetWidth || el.dom.offsetHeight)); + }, + + /** + * Force this container's layout to be recalculated. A call to this function is required after adding a new component + * to an already rendered container, or possibly after changing sizing/position properties of child components. + * @param {Boolean} shallow (optional) True to only calc the layout of this component, and let child components auto + * calc layouts as required (defaults to false, which calls doLayout recursively for each subcontainer) + * @param {Boolean} force (optional) True to force a layout to occur, even if the item is hidden. + * @return {Ext.Container} this + */ + doLayout: function(shallow, force){ + var rendered = this.rendered, + forceLayout = force || this.forceLayout, + cs, i, len, c; + + this.layoutDone = true; + if(!this.canLayout() || this.collapsed){ + this.deferLayout = this.deferLayout || !shallow; + if(!forceLayout){ + return; + } + shallow = shallow && !this.deferLayout; + } else { + delete this.deferLayout; + } + + cs = (shallow !== true && this.items) ? this.items.items : []; + +// Inhibit child Containers from relaying on resize since we are about to to explicitly call doLayout on them all! + for(i = 0, len = cs.length; i < len; i++){ + if ((c = cs[i]).layout) { + c.suspendLayoutResize = true; + } + } + +// Tell the layout manager to ensure all child items are rendered, and sized according to their rules. +// Will not cause the child items to relayout. + if(rendered && this.layout){ + this.layout.layout(); + } + +// Explicitly lay out all child items + for(i = 0; i < len; i++){ + if((c = cs[i]).doLayout){ + c.doLayout(false, forceLayout); + } + } + if(rendered){ + this.onLayout(shallow, forceLayout); + } + // Initial layout completed + this.hasLayout = true; + delete this.forceLayout; + +// Re-enable child layouts relaying on resize. + for(i = 0; i < len; i++){ + if ((c = cs[i]).layout) { + delete c.suspendLayoutResize; + } + } + }, + + //private + onLayout : Ext.emptyFn, + + onResize: function(adjWidth, adjHeight, rawWidth, rawHeight){ + Ext.Container.superclass.onResize.apply(this, arguments); + if ((this.rendered && this.layout && this.layout.monitorResize) && !this.suspendLayoutResize) { + this.layout.onResize(); + } + }, + + // private + hasLayoutPending: function(){ + // Traverse hierarchy to see if any parent container has a pending layout. + var pending = this.layoutPending; + this.ownerCt.bubble(function(c){ + return !(pending = c.layoutPending); + }); + return pending; + + }, + + onShow : function(){ + Ext.Container.superclass.onShow.call(this); + if(Ext.isDefined(this.deferLayout)){ + this.doLayout(true); + } + }, + + /** + * Returns the layout currently in use by the container. If the container does not currently have a layout + * set, a default {@link Ext.layout.ContainerLayout} will be created and set as the container's layout. + * @return {ContainerLayout} layout The container's layout + */ + getLayout : function(){ + if(!this.layout){ + var layout = new Ext.layout.ContainerLayout(this.layoutConfig); + this.setLayout(layout); + } + return this.layout; + }, + + // private + beforeDestroy : function(){ + var c; + if(this.items){ + while(c = this.items.first()){ + this.doRemove(c, true); + } + } + if(this.monitorResize){ + Ext.EventManager.removeResizeListener(this.doLayout, this); + } + Ext.destroy(this.layout); + Ext.Container.superclass.beforeDestroy.call(this); + }, + + /** + * Bubbles up the component/container heirarchy, calling the specified function with each component. The scope (this) of + * function call will be the scope provided or the current component. The arguments to the function + * will be the args provided or the current component. If the function returns false at any point, + * the bubble is stopped. + * @param {Function} fn The function to call + * @param {Object} scope (optional) The scope of the function (defaults to current node) + * @param {Array} args (optional) The args to call the function with (default to passing the current component) + * @return {Ext.Container} this + */ + bubble : function(fn, scope, args){ + var p = this; + while(p){ + if(fn.apply(scope || p, args || [p]) === false){ + break; + } + p = p.ownerCt; + } + return this; + }, + + /** + * Cascades down the component/container heirarchy from this component (called first), calling the specified function with + * each component. The scope (this) of + * function call will be the scope provided or the current component. The arguments to the function + * will be the args provided or the current component. If the function returns false at any point, + * the cascade is stopped on that branch. + * @param {Function} fn The function to call + * @param {Object} scope (optional) The scope of the function (defaults to current component) + * @param {Array} args (optional) The args to call the function with (defaults to passing the current component) + * @return {Ext.Container} this + */ + cascade : function(fn, scope, args){ + if(fn.apply(scope || this, args || [this]) !== false){ + if(this.items){ + var cs = this.items.items; + for(var i = 0, len = cs.length; i < len; i++){ + if(cs[i].cascade){ + cs[i].cascade(fn, scope, args); + }else{ + fn.apply(scope || cs[i], args || [cs[i]]); + } + } + } + } + return this; + }, + + /** + * Find a component under this container at any level by id + * @param {String} id + * @return Ext.Component + */ + findById : function(id){ + var m, ct = this; + this.cascade(function(c){ + if(ct != c && c.id === id){ + m = c; + return false; + } + }); + return m || null; + }, + + /** + * Find a component under this container at any level by xtype or class + * @param {String/Class} xtype The xtype string for a component, or the class of the component directly + * @param {Boolean} shallow (optional) False to check whether this Component is descended from the xtype (this is + * the default), or true to check whether this Component is directly of the specified xtype. + * @return {Array} Array of Ext.Components + */ + findByType : function(xtype, shallow){ + return this.findBy(function(c){ + return c.isXType(xtype, shallow); + }); + }, + + /** + * Find a component under this container at any level by property + * @param {String} prop + * @param {String} value + * @return {Array} Array of Ext.Components + */ + find : function(prop, value){ + return this.findBy(function(c){ + return c[prop] === value; + }); + }, + + /** + * Find a component under this container at any level by a custom function. If the passed function returns + * true, the component will be included in the results. The passed function is called with the arguments (component, this container). + * @param {Function} fn The function to call + * @param {Object} scope (optional) + * @return {Array} Array of Ext.Components + */ + findBy : function(fn, scope){ + var m = [], ct = this; + this.cascade(function(c){ + if(ct != c && fn.call(scope || c, c, ct) === true){ + m.push(c); + } + }); + return m; + }, + + /** + * Get a component contained by this container (alias for items.get(key)) + * @param {String/Number} key The index or id of the component + * @return {Ext.Component} Ext.Component + */ + get : function(key){ + return this.items.get(key); + } +}); + +Ext.Container.LAYOUTS = {}; +Ext.reg('container', Ext.Container); +