Container_wev8.js
36.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
/*!
* Ext JS Library 3.0.0
* Copyright(c) 2006-2009 Ext JS, LLC
* licensing@extjs.com
* http://www.extjs.com/license
*/
/**
* @class Ext.Container
* @extends Ext.BoxComponent
* <p>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.</p>
*
* <p>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
* <tt><b>{@link Ext.Component#autoEl autoEl}</b></tt> config option. This is a useful technique when creating
* embedded {@link Ext.layout.ColumnLayout column} layouts inside {@link Ext.form.FormPanel FormPanels}
* for example.</p>
*
* <p>The code below illustrates both how to explicitly create a Container, and how to implicitly
* create one using the <b><tt>'container'</tt></b> xtype:<pre><code>
// 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'
}
}]
});</code></pre></p>
*
* <p><u><b>Layout</b></u></p>
* <p>Container classes delegate the rendering of child Components to a layout
* manager class which must be configured into the Container using the
* <code><b>{@link #layout}</b></code> configuration property.</p>
* <p>When either specifying child <code>{@link #items}</code> 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
* <b><code>{@link #layout}</code></b> 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 <b>does not apply any sizing</b> at all.</p>
* <p>A common mistake is when a developer neglects to specify a
* <b><code>{@link #layout}</code></b> (e.g. widgets like GridPanels or
* TreePanels are added to Containers for which no <tt><b>{@link #layout}</b></tt>
* 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.</p>
* <p>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:<pre><code>
// 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);
* </code></pre></p>
* <p>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.
* <p><b><u>Overnesting is a common problem</u></b>.
* An example of overnesting occurs when a GridPanel is added to a TabPanel
* by wrapping the GridPanel <i>inside</i> a wrapping Panel (that has no
* <tt><b>{@link #layout}</b></tt> specified) and then add that wrapping Panel
* to the TabPanel. The point to realize is that a GridPanel <b>is</b> a
* Component which can be added directly to a Container. If the wrapping Panel
* has no <tt><b>{@link #layout}</b></tt> configuration, then the overnested
* GridPanel will not be sized as expected.<p>
</code></pre>
*
* <p><u><b>Adding via remote configuration</b></u></p>
*
* <p>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:
* </p><pre><code>
// 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");
}
});
</code></pre>
* <p>The server script needs to return an executable Javascript statement which, when processed
* using <tt>eval()</tt>, will return either a config object with an {@link Ext.Component#xtype xtype},
* or an instantiated Component. The server might return this for example:</p><pre><code>
(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
})();
</code></pre>
* <p>When the above code fragment is passed through the <tt>eval</tt> 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.</p>
* <p>Note: since the code above is <i>generated</i> by a server script, the <tt>baseParams</tt> 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.</p>
*
* @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 <code>{@link #layout}</code> and should not need
* to be set manually.
*/
/**
* @cfg {String/Object} layout
* When creating complex UIs, it is important to remember that sizing and
* positioning of child items is the responsibility of the Container's
* layout manager. If you expect child items to be sized in response to
* user interactions, <b>you must specify a layout manager</b> which
* creates and manages the type of layout you have in mind. For example:<pre><code>
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();
* </code></pre>
* <p>Omitting the {@link #layout} config means that 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).</p>
* <p>The layout manager class for this container may be specified as either as an
* Object or as a String:</p>
* <div><ul class="mdetail-params">
*
* <li><u>Specify as an Object</u></li>
* <div><ul class="mdetail-params">
* <li>Example usage:</li>
<pre><code>
layout: {
type: 'vbox',
padding: '5',
align: 'left'
}
</code></pre>
*
* <li><tt><b>type</b></tt></li>
* <br/><p>The layout type to be used for this container. If not specified,
* a default {@link Ext.layout.ContainerLayout} will be created and used.</p>
* <br/><p>Valid layout <tt>type</tt> values are:</p>
* <div class="sub-desc"><ul class="mdetail-params">
* <li><tt><b>{@link Ext.layout.AbsoluteLayout absolute}</b></tt></li>
* <li><tt><b>{@link Ext.layout.AccordionLayout accordion}</b></tt></li>
* <li><tt><b>{@link Ext.layout.AnchorLayout anchor}</b></tt></li>
* <li><tt><b>{@link Ext.layout.ContainerLayout auto}</b></tt> <b>Default</b></li>
* <li><tt><b>{@link Ext.layout.BorderLayout border}</b></tt></li>
* <li><tt><b>{@link Ext.layout.CardLayout card}</b></tt></li>
* <li><tt><b>{@link Ext.layout.ColumnLayout column}</b></tt></li>
* <li><tt><b>{@link Ext.layout.FitLayout fit}</b></tt></li>
* <li><tt><b>{@link Ext.layout.FormLayout form}</b></tt></li>
* <li><tt><b>{@link Ext.layout.HBoxLayout hbox}</b></tt></li>
* <li><tt><b>{@link Ext.layout.MenuLayout menu}</b></tt></li>
* <li><tt><b>{@link Ext.layout.TableLayout table}</b></tt></li>
* <li><tt><b>{@link Ext.layout.ToolbarLayout toolbar}</b></tt></li>
* <li><tt><b>{@link Ext.layout.VBoxLayout vbox}</b></tt></li>
* </ul></div>
*
* <li>Layout specific configuration properties</li>
* <br/><p>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 <tt>type</tt>
* specified.</p>
*
* </ul></div>
*
* <li><u>Specify as a String</u></li>
* <div><ul class="mdetail-params">
* <li>Example usage:</li>
<pre><code>
layout: 'vbox',
layoutConfig: {
padding: '5',
align: 'left'
}
</code></pre>
* <li><tt><b>layout</b></tt></li>
* <br/><p>The layout <tt>type</tt> to be used for this container (see list
* of valid layout type values above).</p><br/>
* <li><tt><b>{@link #layoutConfig}</b></tt></li>
* <br/><p>Additional layout specific configuration properties. For complete
* details regarding the valid config options for each layout type, see the
* layout class corresponding to the <tt>layout</tt> specified.</p>
* </ul></div></ul></div>
*/
/**
* @cfg {Object} layoutConfig
* This is a config object containing properties specific to the chosen
* <b><code>{@link #layout}</code></b> if <b><code>{@link #layout}</code></b>
* has been specified as a <i>string</i>.</p>
*/
/**
* @cfg {Boolean/Number} bufferResize
* When set to true (100 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.
*/
bufferResize: 100,
/**
* @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
* <pre><b>** IMPORTANT</b>: be sure to specify a <b><code>{@link #layout}</code> ! **</b></pre>
* <p>A single item, or an array of child Components to be added to this container,
* for example:</p>
* <pre><code>
// specifying a single item
items: {...},
layout: 'fit', // specify a layout!
// specifying multiple items
items: [{...}, {...}],
layout: 'anchor', // specify a layout!
* </code></pre>
* <p>Each item may be:</p>
* <div><ul class="mdetail-params">
* <li>any type of object based on {@link Ext.Component}</li>
* <li>a fully instanciated object or</li>
* <li>an object literal that:</li>
* <div><ul class="mdetail-params">
* <li>has a specified <code>{@link Ext.Component#xtype xtype}</code></li>
* <li>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}.</li>
* <li>If an <code>{@link Ext.Component#xtype xtype}</code> is not explicitly
* specified, the {@link #defaultType} for that Container is used.</li>
* <li>will be "lazily instanciated", avoiding the overhead of constructing a fully
* instanciated Component object</li>
* </ul></div></ul></div>
* <p><b>Notes</b>:</p>
* <div><ul class="mdetail-params">
* <li>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.</li>
* <li>Do not specify <code>{@link Ext.Panel#contentEl contentEl}</code>/
* <code>{@link Ext.Panel#html html}</code> with <code>items</code>.</li>
* </ul></div>
*/
/**
* @cfg {Object} defaults
* <p>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 <tt>defaults</tt> 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: <tt>defaults: {bodyStyle:'padding:15px'}</tt>.</p><br/>
* <p><b>Note</b>: <tt>defaults</tt> will not be applied to config objects if the option is already specified.
* For example:</p><pre><code>
defaults: { // defaults are applied to items, not the container
autoScroll:true
},
items: [
{
xtype: 'panel', // defaults <b>do not</b> 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 <b>do</b> have precedence over options
id: 'panel2', // options in components, so the defaults
autoScroll: false // will be applied here, panel2 will be autoScroll:true.
})
]
* </code></pre>
*/
/** @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
* <p>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.</p>
* <p>Defaults to <tt>'panel'</tt>, except {@link Ext.menu.Menu} which defaults to <tt>'menuitem'</tt>,
* and {@link Ext.Toolbar} and {@link Ext.ButtonGroup} which default to <tt>'button'</tt>.</p>
*/
defaultType : 'panel',
// 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('add', 'remove');
/**
* 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;
if(Ext.isArray(items) && items.length > 0){
this.add.apply(this, items);
}else{
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);
},
// private
render : function(){
Ext.Container.superclass.render.apply(this, arguments);
if(this.layout){
if(Ext.isObject(this.layout) && !this.layout.layout){
this.layoutConfig = this.layout;
this.layout = this.layoutConfig.type;
}
if(typeof this.layout == 'string'){
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]);
}
},
/**
* <p>Returns the Element to be used to contain the child Components of this Container.</p>
* <p>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.</p>
* @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();
},
/**
* <p>Adds {@link Ext.Component Component}(s) to this Container.</p>
* <br><p><b>Description</b></u> :
* <div><ul class="mdetail-params">
* <li>Fires the {@link #beforeadd} event before adding</li>
* <li>The Container's {@link #defaults default config values} will be applied
* accordingly (see <code>{@link #defaults}</code> for details).</li>
* <li>Fires the {@link #add} event after the component has been added.</li>
* </ul></div>
* <br><p><b>Notes</b></u> :
* <div><ul class="mdetail-params">
* <li>If the Container is <i>already rendered</i> when <tt>add</tt>
* 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
* <tt>add</tt> multiple child components if needed while only refreshing the layout
* once. For example:<pre><code>
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
* </code></pre></li>
* <li><i>Warning:</i> 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.</li>
* </ul></div>
* @param {Object/Array} component
* <p>Either a single component or an Array of components to add. See
* <code>{@link #items}</code> for additional information.</p>
* @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.fireEvent('add', this, c, pos);
}
return c;
},
/**
* 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.<br><br>
* Ext uses lazy rendering, and will only render the inserted Component should
* it become necessary.<br><br>
* 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.<br><br>
* 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));
if(c.ownerCt == this && this.items.indexOf(c) < index){
--index;
}
if(this.fireEvent('beforeadd', this, c, index) !== false && this.onBeforeAdd(c) !== false){
this.items.insert(index, c);
c.ownerCt = this;
this.fireEvent('add', this, c, index);
}
return c;
},
// private
applyDefaults : function(c){
if(this.defaults){
if(typeof c == 'string'){
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){
this.items.remove(c);
delete c.ownerCt;
if(autoDestroy === true || (autoDestroy !== false && this.autoDestroy)){
c.destroy();
}
if(this.layout && this.layout.activeItem == c){
delete this.layout.activeItem;
}
this.fireEvent('remove', this, c);
}
return c;
},
/**
* 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 <code>{@link #items}</code> <b>property</b>
* and gets a direct child component of this container.
* @param {String/Number} comp This parameter may be any of the following:
* <div><ul class="mdetail-params">
* <li>a <b><tt>String</tt></b> : representing the <code>{@link Ext.Component#itemId itemId}</code>
* or <code>{@link Ext.Component#id id}</code> of the child component </li>
* <li>a <b><tt>Number</tt></b> : representing the position of the child component
* within the <code>{@link #items}</code> <b>property</b></li>
* </ul></div>
* <p>For additional information see {@link Ext.util.MixedCollection#get}.
* @return Ext.Component The component (if found).
*/
getComponent : function(comp){
if(Ext.isObject(comp)){
return comp;
}
return this.items.get(comp);
},
// private
lookupComponent : function(comp){
if(typeof comp == 'string'){
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);
},
/**
* 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 = this.forceLayout;
if(!this.isVisible() || this.collapsed){
this.deferLayout = this.deferLayout || !shallow;
if(!(force || 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.forceLayout = forceLayout;
c.doLayout();
}
}
}
if(rendered){
this.onLayout(shallow, force);
}
delete this.forceLayout;
},
//private
onLayout : Ext.emptyFn,
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 (<i>this</i>) 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 (<i>this</i>) 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);