3
* Copyright(c) 2006-2008, Ext JS, LLC.
6
* http://extjs.com/license
10
* @class Ext.Container
11
* @extends Ext.BoxComponent
12
* <p>Base class for any {@link Ext.BoxComponent} that can contain other components. This class is intended
13
* to be extended and should generally not need to be created directly via the new keyword. {@link Ext.Panel},
14
* {@link Ext.Window} and {@link Ext.TabPanel} are the most commonly used Container classes.</p>
15
* Containers handle the basic behavior of containing items, namely adding, inserting and removing them.
16
* The specific layout logic required to visually render contained items is delegated to any one of the different
17
* {@link #layout} classes available.</p>
18
* <p>When either specifying child {@link #items} of a Container, or dynamically adding components to a Container,
19
* remember to consider how you wish the Container to arrange those child elements, and whether those child elements
20
* need to be sized using one of Ext's built-in layout schemes.</p>
21
* <p>By default, Containers use the {@link Ext.layout.ContainerLayout ContainerLayout} scheme. This simply renders
22
* child components, appending them one after the other inside the Container, and does not apply any sizing at all.
23
* This is a common source of confusion when widgets like GridPanels or TreePanels are added to Containers for
24
* which no layout has been specified. If a Container is left to use the ContainerLayout scheme, none of its child
25
* components will be resized, or changed in any way when the Container is resized.</p>
26
* <p>A very common example of this is where a developer will attempt to add a GridPanel to a TabPanel by wrapping
27
* the GridPanel <i>inside</i> a wrapping Panel and add that wrapping Panel to the TabPanel. This misses the point that
28
* Ext's inheritance means that a GridPanel <b>is</b> a Component which can be added unadorned into a Container. If
29
* that wrapping Panel has no layout configuration, then the GridPanel will not be sized as expected.<p>
30
* <p>Below is an example of adding a newly created GridPanel to a TabPanel. A TabPanel uses {@link Ext.layout.CardLayout}
31
* as its layout manager which means all its child items are sized to fit exactly into its client area. The following
32
* code requires prior knowledge of how to create GridPanels. See {@link Ext.grid.GridPanel}, {@link Ext.data.Store}
33
* and {@link Ext.data.JsonReader} as well as the grid examples in the Ext installation's <tt>examples/grid</tt>
34
* directory.</p><pre><code>
35
// Create the GridPanel.
36
myGrid = new Ext.grid.GridPanel({
38
columns: myColumnModel,
42
myTabPanel.add(myGrid);
43
myTabPanel.setActiveItem(myGrid);
46
Ext.Container = Ext.extend(Ext.BoxComponent, {
47
/** @cfg {Boolean} monitorResize
48
* True to automatically monitor window resize events to handle anything that is sensitive to the current size
49
* of the viewport. This value is typically managed by the chosen {@link #layout} and should not need to be set manually.
52
* @cfg {String} layout
53
* The layout type to be used in this container. If not specified, a default {@link Ext.layout.ContainerLayout}
54
* will be created and used. Valid values are: absolute, accordion, anchor, border, card, column, fit, form and table.
55
* Specific config values for the chosen layout type can be specified using {@link #layoutConfig}.
58
* @cfg {Object} layoutConfig
59
* This is a config object containing properties specific to the chosen layout (to be used in conjunction with
60
* the {@link #layout} config value). For complete details regarding the valid config options for each layout
61
* type, see the layout class corresponding to the type specified:<ul class="mdetail-params">
62
* <li>{@link Ext.layout.Absolute}</li>
63
* <li>{@link Ext.layout.Accordion}</li>
64
* <li>{@link Ext.layout.AnchorLayout}</li>
65
* <li>{@link Ext.layout.BorderLayout}</li>
66
* <li>{@link Ext.layout.CardLayout}</li>
67
* <li>{@link Ext.layout.ColumnLayout}</li>
68
* <li>{@link Ext.layout.FitLayout}</li>
69
* <li>{@link Ext.layout.FormLayout}</li>
70
* <li>{@link Ext.layout.TableLayout}</li></ul>
73
* @cfg {Boolean/Number} bufferResize
74
* When set to true (100 milliseconds) or a number of milliseconds, the layout assigned for this container will buffer
75
* the frequency it calculates and does a re-layout of components. This is useful for heavy containers or containers
76
* with a large quantity of sub-components for which frequent layout calls would be expensive.
79
* @cfg {String/Number} activeItem
80
* A string component id or the numeric index of the component that should be initially activated within the
81
* container's layout on render. For example, activeItem: 'item-1' or activeItem: 0 (index 0 = the first
82
* item in the container's collection). activeItem only applies to layout styles that can display
83
* items one at a time (like {@link Ext.layout.Accordion}, {@link Ext.layout.CardLayout} and
84
* {@link Ext.layout.FitLayout}). Related to {@link Ext.layout.ContainerLayout#activeItem}.
88
* A single item, or an array of child Components to be added to this container.
89
* Each item can be any type of object based on {@link Ext.Component}.<br><br>
90
* Component config objects may also be specified in order to avoid the overhead
91
* of constructing a real Component object if lazy rendering might mean that the
92
* added Component will not be rendered immediately. To take advantage of this
93
* "lazy instantiation", set the {@link Ext.Component#xtype} config property to
94
* the registered type of the Component wanted.<br><br>
95
* For a list of all available xtypes, see {@link Ext.Component}.
96
* If a single item is being passed, it should be passed directly as an object
97
* reference (e.g., items: {...}). Multiple items should be passed as an array
98
* of objects (e.g., items: [{...}, {...}]).
101
* @cfg {Object} defaults
102
* A config object that will be applied to all components added to this container either via the {@link #items}
103
* config or via the {@link #add} or {@link #insert} methods. The defaults config can contain any number of
104
* name/value property pairs to be added to each item, and should be valid for the types of items
105
* being added to the container. For example, to automatically apply padding to the body of each of a set of
106
* contained {@link Ext.Panel} items, you could pass: defaults: {bodyStyle:'padding:15px'}.
109
/** @cfg {Boolean} autoDestroy
110
* If true the container will automatically destroy any contained component that is removed from it, else
111
* destruction must be handled manually (defaults to true).
114
/** @cfg {Boolean} hideBorders
115
* True to hide the borders of each contained component, false to defer to the component's existing
116
* border settings (defaults to false).
118
/** @cfg {String} defaultType
119
* <p>The default {@link Ext.Component xtype} of child Components to create in this Container when
120
* a child item is specified as a raw configuration object, rather than as an instantiated Component.</p>
121
* <p>This usually defaults to 'panel', but for {@link Ext.form.FormPanel} and {@link Ext.form.FieldSet},
122
* the defaultType is 'textfield'.</p>
124
defaultType: 'panel',
127
initComponent : function(){
128
Ext.Container.superclass.initComponent.call(this);
133
* Fires when the components in this container are arranged by the associated layout manager.
134
* @param {Ext.Container} this
135
* @param {ContainerLayout} layout The ContainerLayout implementation for this container
140
* Fires before any {@link Ext.Component} is added or inserted into the container.
141
* A handler can return false to cancel the add.
142
* @param {Ext.Container} this
143
* @param {Ext.Component} component The component being added
144
* @param {Number} index The index at which the component will be added to the container's items collection
148
* @event beforeremove
149
* Fires before any {@link Ext.Component} is removed from the container. A handler can return
150
* false to cancel the remove.
151
* @param {Ext.Container} this
152
* @param {Ext.Component} component The component being removed
157
* Fires after any {@link Ext.Component} is added or inserted into the container.
158
* @param {Ext.Container} this
159
* @param {Ext.Component} component The component that was added
160
* @param {Number} index The index at which the component was added to the container's items collection
165
* Fires after any {@link Ext.Component} is removed from the container.
166
* @param {Ext.Container} this
167
* @param {Ext.Component} component The component that was removed
173
* The collection of components in this container as a {@link Ext.util.MixedCollection}
174
* @type MixedCollection
177
var items = this.items;
180
if(Ext.isArray(items)){
181
this.add.apply(this, items);
189
initItems : function(){
191
this.items = new Ext.util.MixedCollection(false, this.getComponentId);
192
this.getLayout(); // initialize the layout
197
setLayout : function(layout){
198
if(this.layout && this.layout != layout){
199
this.layout.setContainer(null);
202
this.layout = layout;
203
layout.setContainer(this);
208
Ext.Container.superclass.render.apply(this, arguments);
210
if(typeof this.layout == 'string'){
211
this.layout = new Ext.Container.LAYOUTS[this.layout.toLowerCase()](this.layoutConfig);
213
this.setLayout(this.layout);
215
if(this.activeItem !== undefined){
216
var item = this.activeItem;
217
delete this.activeItem;
218
this.layout.setActiveItem(item);
225
if(this.monitorResize === true){
226
Ext.EventManager.onWindowResize(this.doLayout, this, [false]);
230
// protected - should only be called by layouts
231
getLayoutTarget : function(){
235
// private - used as the key lookup function for the items collection
236
getComponentId : function(comp){
237
return comp.itemId || comp.id;
241
* <p>Adds a {@link Ext.Component Component} to this Container. Fires the {@link #beforeadd} event before
242
* adding, then fires the {@link #add} event after the component has been added.</p>
243
* <p>You will never call the render method of a child Component when using a Container.
244
* Child Components are rendered by this Container's {@link #layout} manager when
245
* this Container is first rendered.</p>
246
* <p>Certain layout managers allow dynamic addition of child components. Those that do
247
* include {@link Ext.layout.CardLayout}, {@link Ext.layout.AnchorLayout},
248
* {@link Ext.layout.FormLayout}, {@link Ext.layout.TableLayout}.</p>
249
* <p>If the Container is already rendered when add is called, you may need to call
250
* {@link #doLayout} to refresh the view which causes any unrendered child Components
251
* to be rendered. This is required so that you can add multiple child components if needed
252
* while only refreshing the layout once.</p>
253
* <p>When creating complex UIs, it is important to remember that sizing and positioning
254
* of child items is the responsibility of the Container's {@link #layout} manager. If
255
* you expect child items to be sized in response to user interactions, you must
256
* specify a layout manager which creates and manages the type of layout you have in mind.</p>
257
* <p><b>Omitting the {@link #layout} config means that a basic layout manager is
258
* used which does nothnig but render child components sequentially into the Container.
259
* No sizing or positioning will be performed in this situation.</b></p>
260
* @param {Ext.Component/Object} component The Component to add.<br><br>
261
* Ext uses lazy rendering, and will only render the added Component should
262
* it become necessary, that is: when the Container is layed out either on first render
263
* or in response to a {@link #doLayout} call.<br><br>
264
* A Component config object may be passed instead of an instantiated Component object.
265
* The type of Component created from a config object is determined by the {@link Ext.Component#xtype xtype}
266
* config property. If no xtype is configured, the Container's {@link #defaultType}
268
* For a list of all available xtypes, see {@link Ext.Component}.
269
* @return {Ext.Component} component The Component (or config object) that was
270
* added with the Container's default config values applied.
271
* <p>example:</p><pre><code>
272
var myNewGrid = new Ext.grid.GridPanel({
276
myTabPanel.add(myNewGrid);
277
myTabPanel.setActiveTab(myNewGrid);
280
add : function(comp){
284
var a = arguments, len = a.length;
286
for(var i = 0; i < len; i++) {
291
var c = this.lookupComponent(this.applyDefaults(comp));
292
var pos = this.items.length;
293
if(this.fireEvent('beforeadd', this, c, pos) !== false && this.onBeforeAdd(c) !== false){
296
this.fireEvent('add', this, c, pos);
302
* Inserts a Component into this Container at a specified index. Fires the
303
* {@link #beforeadd} event before inserting, then fires the {@link #add} event after the
304
* Component has been inserted.
305
* @param {Number} index The index at which the Component will be inserted
306
* into the Container's items collection
307
* @param {Ext.Component} component The child Component to insert.<br><br>
308
* Ext uses lazy rendering, and will only render the inserted Component should
309
* it become necessary.<br><br>
310
* A Component config object may be passed in order to avoid the overhead of
311
* constructing a real Component object if lazy rendering might mean that the
312
* inserted Component will not be rendered immediately. To take advantage of
313
* this "lazy instantiation", set the {@link Ext.Component#xtype} config
314
* property to the registered type of the Component wanted.<br><br>
315
* For a list of all available xtypes, see {@link Ext.Component}.
316
* @return {Ext.Component} component The Component (or config object) that was
317
* inserted with the Container's default config values applied.
319
insert : function(index, comp){
323
var a = arguments, len = a.length;
325
for(var i = len-1; i >= 1; --i) {
326
this.insert(index, a[i]);
330
var c = this.lookupComponent(this.applyDefaults(comp));
332
if(c.ownerCt == this && this.items.indexOf(c) < index){
336
if(this.fireEvent('beforeadd', this, c, index) !== false && this.onBeforeAdd(c) !== false){
337
this.items.insert(index, c);
339
this.fireEvent('add', this, c, index);
345
applyDefaults : function(c){
347
if(typeof c == 'string'){
348
c = Ext.ComponentMgr.get(c);
349
Ext.apply(c, this.defaults);
351
Ext.applyIf(c, this.defaults);
353
Ext.apply(c, this.defaults);
360
onBeforeAdd : function(item){
362
item.ownerCt.remove(item, false);
364
if(this.hideBorders === true){
365
item.border = (item.border === true);
370
* Removes a component from this container. Fires the {@link #beforeremove} event before removing, then fires
371
* the {@link #remove} event after the component has been removed.
372
* @param {Component/String} component The component reference or id to remove.
373
* @param {Boolean} autoDestroy (optional) True to automatically invoke the removed Component's {@link Ext.Component#destroy} function.
374
* Defaults to the value of this Container's {@link #autoDestroy} config.
376
remove : function(comp, autoDestroy){
377
var c = this.getComponent(comp);
378
if(c && this.fireEvent('beforeremove', this, c) !== false){
379
this.items.remove(c);
381
if(autoDestroy === true || (autoDestroy !== false && this.autoDestroy)){
384
if(this.layout && this.layout.activeItem == c){
385
delete this.layout.activeItem;
387
this.fireEvent('remove', this, c);
393
* Gets a direct child Component by id, or by index.
394
* @param {String/Number} id or index of child Component to return.
395
* @return Ext.Component
397
getComponent : function(comp){
398
if(typeof comp == 'object'){
401
return this.items.get(comp);
405
lookupComponent : function(comp){
406
if(typeof comp == 'string'){
407
return Ext.ComponentMgr.get(comp);
408
}else if(!comp.events){
409
return this.createComponent(comp);
415
createComponent : function(config){
416
return Ext.ComponentMgr.create(config, this.defaultType);
420
* Force this container's layout to be recalculated. A call to this function is required after adding a new component
421
* to an already rendered container, or possibly after changing sizing/position properties of child components.
422
* @param {Boolean} shallow (optional) True to only calc the layout of this component, and let child components auto
423
* calc layouts as required (defaults to false, which calls doLayout recursively for each subcontainer)
425
doLayout : function(shallow){
426
if(this.rendered && this.layout){
427
this.layout.layout();
429
if(shallow !== false && this.items){
430
var cs = this.items.items;
431
for(var i = 0, len = cs.length; i < len; i++) {
441
* Returns the layout currently in use by the container. If the container does not currently have a layout
442
* set, a default {@link Ext.layout.ContainerLayout} will be created and set as the container's layout.
443
* @return {ContainerLayout} layout The container's layout
445
getLayout : function(){
447
var layout = new Ext.layout.ContainerLayout(this.layoutConfig);
448
this.setLayout(layout);
454
beforeDestroy : function(){
456
Ext.destroy.apply(Ext, this.items.items);
458
if(this.monitorResize){
459
Ext.EventManager.removeResizeListener(this.doLayout, this);
461
if (this.layout && this.layout.destroy) {
462
this.layout.destroy();
464
Ext.Container.superclass.beforeDestroy.call(this);
468
* Bubbles up the component/container heirarchy, calling the specified function with each component. The scope (<i>this</i>) of
469
* function call will be the scope provided or the current component. The arguments to the function
470
* will be the args provided or the current component. If the function returns false at any point,
471
* the bubble is stopped.
472
* @param {Function} fn The function to call
473
* @param {Object} scope (optional) The scope of the function (defaults to current node)
474
* @param {Array} args (optional) The args to call the function with (default to passing the current component)
476
bubble : function(fn, scope, args){
479
if(fn.apply(scope || p, args || [p]) === false){
487
* Cascades down the component/container heirarchy from this component (called first), calling the specified function with
488
* each component. The scope (<i>this</i>) of
489
* function call will be the scope provided or the current component. The arguments to the function
490
* will be the args provided or the current component. If the function returns false at any point,
491
* the cascade is stopped on that branch.
492
* @param {Function} fn The function to call
493
* @param {Object} scope (optional) The scope of the function (defaults to current component)
494
* @param {Array} args (optional) The args to call the function with (defaults to passing the current component)
496
cascade : function(fn, scope, args){
497
if(fn.apply(scope || this, args || [this]) !== false){
499
var cs = this.items.items;
500
for(var i = 0, len = cs.length; i < len; i++){
502
cs[i].cascade(fn, scope, args);
504
fn.apply(scope || cs[i], args || [cs[i]]);
512
* Find a component under this container at any level by id
514
* @return Ext.Component
516
findById : function(id){
518
this.cascade(function(c){
519
if(ct != c && c.id === id){
528
* Find a component under this container at any level by xtype or class
529
* @param {String/Class} xtype The xtype string for a component, or the class of the component directly
530
* @return {Array} Array of Ext.Components
532
findByType : function(xtype){
533
return typeof xtype == 'function' ?
534
this.findBy(function(c){
535
return c.constructor === xtype;
537
this.findBy(function(c){
538
return c.constructor.xtype === xtype;
543
* Find a component under this container at any level by property
544
* @param {String} prop
545
* @param {String} value
546
* @return {Array} Array of Ext.Components
548
find : function(prop, value){
549
return this.findBy(function(c){
550
return c[prop] === value;
555
* Find a component under this container at any level by a custom function. If the passed function returns
556
* true, the component will be included in the results. The passed function is called with the arguments (component, this container).
557
* @param {Function} fcn
558
* @param {Object} scope (optional)
559
* @return {Array} Array of Ext.Components
561
findBy : function(fn, scope){
562
var m = [], ct = this;
563
this.cascade(function(c){
564
if(ct != c && fn.call(scope || c, c, ct) === true){
572
Ext.Container.LAYOUTS = {};
573
Ext.reg('container', Ext.Container);
b'\\ No newline at end of file'