Upgrade to ExtJS 4.0.7 - Released 10/19/2011
[extjs.git] / docs / source / Panel4.html
1 <!DOCTYPE html>
2 <html>
3 <head>
4   <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
5   <title>The source code</title>
6   <link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />
7   <script type="text/javascript" src="../resources/prettify/prettify.js"></script>
8   <style type="text/css">
9     .highlight { display: block; background-color: #ddd; }
10   </style>
11   <script type="text/javascript">
12     function highlight() {
13       document.getElementById(location.hash.replace(/#/, "")).className = "highlight";
14     }
15   </script>
16 </head>
17 <body onload="prettyPrint(); highlight();">
18   <pre class="prettyprint lang-js"><span id='Ext-tab-Panel'>/**
19 </span> * @author Ed Spencer, Tommy Maintz, Brian Moeskau
20  *
21  * A basic tab container. TabPanels can be used exactly like a standard {@link Ext.panel.Panel} for
22  * layout purposes, but also have special support for containing child Components
23  * (`{@link Ext.container.Container#items items}`) that are managed using a
24  * {@link Ext.layout.container.Card CardLayout layout manager}, and displayed as separate tabs.
25  *
26  * **Note:** By default, a tab's close tool _destroys_ the child tab Component and all its descendants.
27  * This makes the child tab Component, and all its descendants **unusable**.  To enable re-use of a tab,
28  * configure the TabPanel with `{@link #autoDestroy autoDestroy: false}`.
29  *
30  * ## TabPanel's layout
31  *
32  * TabPanels use a Dock layout to position the {@link Ext.tab.Bar TabBar} at the top of the widget.
33  * Panels added to the TabPanel will have their header hidden by default because the Tab will
34  * automatically take the Panel's configured title and icon.
35  *
36  * TabPanels use their {@link Ext.panel.Header header} or {@link Ext.panel.Panel#fbar footer}
37  * element (depending on the {@link #tabPosition} configuration) to accommodate the tab selector buttons.
38  * This means that a TabPanel will not display any configured title, and will not display any configured
39  * header {@link Ext.panel.Panel#tools tools}.
40  *
41  * To display a header, embed the TabPanel in a {@link Ext.panel.Panel Panel} which uses
42  * `{@link Ext.container.Container#layout layout: 'fit'}`.
43  *
44  * ## Controlling tabs
45  *
46  * Configuration options for the {@link Ext.tab.Tab} that represents the component can be passed in
47  * by specifying the tabConfig option:
48  *
49  *     @example
50  *     Ext.create('Ext.tab.Panel', {
51  *         width: 400,
52  *         height: 400,
53  *         renderTo: document.body,
54  *         items: [{
55  *             title: 'Foo'
56  *         }, {
57  *             title: 'Bar',
58  *             tabConfig: {
59  *                 title: 'Custom Title',
60  *                 tooltip: 'A button tooltip'
61  *             }
62  *         }]
63  *     });
64  *
65  * # Examples
66  *
67  * Here is a basic TabPanel rendered to the body. This also shows the useful configuration {@link #activeTab},
68  * which allows you to set the active tab on render. If you do not set an {@link #activeTab}, no tabs will be
69  * active by default.
70  *
71  *     @example
72  *     Ext.create('Ext.tab.Panel', {
73  *         width: 300,
74  *         height: 200,
75  *         activeTab: 0,
76  *         items: [
77  *             {
78  *                 title: 'Tab 1',
79  *                 bodyPadding: 10,
80  *                 html : 'A simple tab'
81  *             },
82  *             {
83  *                 title: 'Tab 2',
84  *                 html : 'Another one'
85  *             }
86  *         ],
87  *         renderTo : Ext.getBody()
88  *     });
89  *
90  * It is easy to control the visibility of items in the tab bar. Specify hidden: true to have the
91  * tab button hidden initially. Items can be subsequently hidden and show by accessing the
92  * tab property on the child item.
93  *
94  *     @example
95  *     var tabs = Ext.create('Ext.tab.Panel', {
96  *         width: 400,
97  *         height: 400,
98  *         renderTo: document.body,
99  *         items: [{
100  *             title: 'Home',
101  *             html: 'Home',
102  *             itemId: 'home'
103  *         }, {
104  *             title: 'Users',
105  *             html: 'Users',
106  *             itemId: 'users',
107  *             hidden: true
108  *         }, {
109  *             title: 'Tickets',
110  *             html: 'Tickets',
111  *             itemId: 'tickets'
112  *         }]
113  *     });
114  *
115  *     setTimeout(function(){
116  *         tabs.child('#home').tab.hide();
117  *         var users = tabs.child('#users');
118  *         users.tab.show();
119  *         tabs.setActiveTab(users);
120  *     }, 1000);
121  *
122  * You can remove the background of the TabBar by setting the {@link #plain} property to `true`.
123  *
124  *     @example
125  *     Ext.create('Ext.tab.Panel', {
126  *         width: 300,
127  *         height: 200,
128  *         activeTab: 0,
129  *         plain: true,
130  *         items: [
131  *             {
132  *                 title: 'Tab 1',
133  *                 bodyPadding: 10,
134  *                 html : 'A simple tab'
135  *             },
136  *             {
137  *                 title: 'Tab 2',
138  *                 html : 'Another one'
139  *             }
140  *         ],
141  *         renderTo : Ext.getBody()
142  *     });
143  *
144  * Another useful configuration of TabPanel is {@link #tabPosition}. This allows you to change the
145  * position where the tabs are displayed. The available options for this are `'top'` (default) and
146  * `'bottom'`.
147  *
148  *     @example
149  *     Ext.create('Ext.tab.Panel', {
150  *         width: 300,
151  *         height: 200,
152  *         activeTab: 0,
153  *         bodyPadding: 10,
154  *         tabPosition: 'bottom',
155  *         items: [
156  *             {
157  *                 title: 'Tab 1',
158  *                 html : 'A simple tab'
159  *             },
160  *             {
161  *                 title: 'Tab 2',
162  *                 html : 'Another one'
163  *             }
164  *         ],
165  *         renderTo : Ext.getBody()
166  *     });
167  *
168  * The {@link #setActiveTab} is a very useful method in TabPanel which will allow you to change the
169  * current active tab. You can either give it an index or an instance of a tab. For example:
170  *
171  *     @example
172  *     var tabs = Ext.create('Ext.tab.Panel', {
173  *         items: [
174  *             {
175  *                 id   : 'my-tab',
176  *                 title: 'Tab 1',
177  *                 html : 'A simple tab'
178  *             },
179  *             {
180  *                 title: 'Tab 2',
181  *                 html : 'Another one'
182  *             }
183  *         ],
184  *         renderTo : Ext.getBody()
185  *     });
186  *
187  *     var tab = Ext.getCmp('my-tab');
188  *
189  *     Ext.create('Ext.button.Button', {
190  *         renderTo: Ext.getBody(),
191  *         text    : 'Select the first tab',
192  *         scope   : this,
193  *         handler : function() {
194  *             tabs.setActiveTab(tab);
195  *         }
196  *     });
197  *
198  *     Ext.create('Ext.button.Button', {
199  *         text    : 'Select the second tab',
200  *         scope   : this,
201  *         handler : function() {
202  *             tabs.setActiveTab(1);
203  *         },
204  *         renderTo : Ext.getBody()
205  *     });
206  *
207  * The {@link #getActiveTab} is a another useful method in TabPanel which will return the current active tab.
208  *
209  *     @example
210  *     var tabs = Ext.create('Ext.tab.Panel', {
211  *         items: [
212  *             {
213  *                 title: 'Tab 1',
214  *                 html : 'A simple tab'
215  *             },
216  *             {
217  *                 title: 'Tab 2',
218  *                 html : 'Another one'
219  *             }
220  *         ],
221  *         renderTo : Ext.getBody()
222  *     });
223  *
224  *     Ext.create('Ext.button.Button', {
225  *         text    : 'Get active tab',
226  *         scope   : this,
227  *         handler : function() {
228  *             var tab = tabs.getActiveTab();
229  *             alert('Current tab: ' + tab.title);
230  *         },
231  *         renderTo : Ext.getBody()
232  *     });
233  *
234  * Adding a new tab is very simple with a TabPanel. You simple call the {@link #add} method with an config
235  * object for a panel.
236  *
237  *     @example
238  *     var tabs = Ext.create('Ext.tab.Panel', {
239  *         items: [
240  *             {
241  *                 title: 'Tab 1',
242  *                 html : 'A simple tab'
243  *             },
244  *             {
245  *                 title: 'Tab 2',
246  *                 html : 'Another one'
247  *             }
248  *         ],
249  *         renderTo : Ext.getBody()
250  *     });
251  *
252  *     Ext.create('Ext.button.Button', {
253  *         text    : 'New tab',
254  *         scope   : this,
255  *         handler : function() {
256  *             var tab = tabs.add({
257  *                 // we use the tabs.items property to get the length of current items/tabs
258  *                 title: 'Tab ' + (tabs.items.length + 1),
259  *                 html : 'Another one'
260  *             });
261  *
262  *             tabs.setActiveTab(tab);
263  *         },
264  *         renderTo : Ext.getBody()
265  *     });
266  *
267  * Additionally, removing a tab is very also simple with a TabPanel. You simple call the {@link #remove} method
268  * with an config object for a panel.
269  *
270  *     @example
271  *     var tabs = Ext.create('Ext.tab.Panel', {
272  *         items: [
273  *             {
274  *                 title: 'Tab 1',
275  *                 html : 'A simple tab'
276  *             },
277  *             {
278  *                 id   : 'remove-this-tab',
279  *                 title: 'Tab 2',
280  *                 html : 'Another one'
281  *             }
282  *         ],
283  *         renderTo : Ext.getBody()
284  *     });
285  *
286  *     Ext.create('Ext.button.Button', {
287  *         text    : 'Remove tab',
288  *         scope   : this,
289  *         handler : function() {
290  *             var tab = Ext.getCmp('remove-this-tab');
291  *             tabs.remove(tab);
292  *         },
293  *         renderTo : Ext.getBody()
294  *     });
295  */
296 Ext.define('Ext.tab.Panel', {
297     extend: 'Ext.panel.Panel',
298     alias: 'widget.tabpanel',
299     alternateClassName: ['Ext.TabPanel'],
300
301     requires: ['Ext.layout.container.Card', 'Ext.tab.Bar'],
302
303 <span id='Ext-tab-Panel-cfg-tabPosition'>    /**
304 </span>     * @cfg {String} tabPosition
305      * The position where the tab strip should be rendered. Can be `top` or `bottom`.
306      */
307     tabPosition : 'top',
308
309 <span id='Ext-tab-Panel-cfg-activeItem'>    /**
310 </span>     * @cfg {String/Number} activeItem
311      * Doesn't apply for {@link Ext.tab.Panel TabPanel}, use {@link #activeTab} instead.
312      */
313
314 <span id='Ext-tab-Panel-cfg-activeTab'>    /**
315 </span>     * @cfg {String/Number/Ext.Component} activeTab
316      * The tab to activate initially. Either an ID, index or the tab component itself.
317      */
318
319 <span id='Ext-tab-Panel-cfg-tabBar'>    /**
320 </span>     * @cfg {Object} tabBar
321      * Optional configuration object for the internal {@link Ext.tab.Bar}.
322      * If present, this is passed straight through to the TabBar's constructor
323      */
324
325 <span id='Ext-tab-Panel-cfg-layout'>    /**
326 </span>     * @cfg {Object} layout
327      * Optional configuration object for the internal {@link Ext.layout.container.Card card layout}.
328      * If present, this is passed straight through to the layout's constructor
329      */
330
331 <span id='Ext-tab-Panel-cfg-removePanelHeader'>    /**
332 </span>     * @cfg {Boolean} removePanelHeader
333      * True to instruct each Panel added to the TabContainer to not render its header element.
334      * This is to ensure that the title of the panel does not appear twice.
335      */
336     removePanelHeader: true,
337
338 <span id='Ext-tab-Panel-cfg-plain'>    /**
339 </span>     * @cfg {Boolean} plain
340      * True to not show the full background on the TabBar.
341      */
342     plain: false,
343
344 <span id='Ext-tab-Panel-cfg-itemCls'>    /**
345 </span>     * @cfg {String} itemCls
346      * The class added to each child item of this TabPanel.
347      */
348     itemCls: 'x-tabpanel-child',
349
350 <span id='Ext-tab-Panel-cfg-minTabWidth'>    /**
351 </span>     * @cfg {Number} minTabWidth
352      * The minimum width for a tab in the {@link #tabBar}.
353      */
354     minTabWidth: undefined,
355
356 <span id='Ext-tab-Panel-cfg-maxTabWidth'>    /**
357 </span>     * @cfg {Number} maxTabWidth The maximum width for each tab.
358      */
359     maxTabWidth: undefined,
360
361 <span id='Ext-tab-Panel-cfg-deferredRender'>    /**
362 </span>     * @cfg {Boolean} deferredRender
363      *
364      * True by default to defer the rendering of child {@link Ext.container.Container#items items} to the browsers DOM
365      * until a tab is activated. False will render all contained {@link Ext.container.Container#items items} as soon as
366      * the {@link Ext.layout.container.Card layout} is rendered. If there is a significant amount of content or a lot of
367      * heavy controls being rendered into panels that are not displayed by default, setting this to true might improve
368      * performance.
369      *
370      * The deferredRender property is internally passed to the layout manager for TabPanels ({@link
371      * Ext.layout.container.Card}) as its {@link Ext.layout.container.Card#deferredRender} configuration value.
372      *
373      * **Note**: leaving deferredRender as true means that the content within an unactivated tab will not be available
374      */
375     deferredRender : true,
376
377     //inherit docs
378     initComponent: function() {
379         var me = this,
380             dockedItems = me.dockedItems || [],
381             activeTab = me.activeTab || 0;
382
383         me.layout = Ext.create('Ext.layout.container.Card', Ext.apply({
384             owner: me,
385             deferredRender: me.deferredRender,
386             itemCls: me.itemCls
387         }, me.layout));
388
389 <span id='Ext-tab-Panel-property-tabBar'>        /**
390 </span>         * @property {Ext.tab.Bar} tabBar Internal reference to the docked TabBar
391          */
392         me.tabBar = Ext.create('Ext.tab.Bar', Ext.apply({}, me.tabBar, {
393             dock: me.tabPosition,
394             plain: me.plain,
395             border: me.border,
396             cardLayout: me.layout,
397             tabPanel: me
398         }));
399
400         if (dockedItems &amp;&amp; !Ext.isArray(dockedItems)) {
401             dockedItems = [dockedItems];
402         }
403
404         dockedItems.push(me.tabBar);
405         me.dockedItems = dockedItems;
406
407         me.addEvents(
408 <span id='Ext-tab-Panel-event-beforetabchange'>            /**
409 </span>             * @event
410              * Fires before a tab change (activated by {@link #setActiveTab}). Return false in any listener to cancel
411              * the tabchange
412              * @param {Ext.tab.Panel} tabPanel The TabPanel
413              * @param {Ext.Component} newCard The card that is about to be activated
414              * @param {Ext.Component} oldCard The card that is currently active
415              */
416             'beforetabchange',
417
418 <span id='Ext-tab-Panel-event-tabchange'>            /**
419 </span>             * @event
420              * Fires when a new tab has been activated (activated by {@link #setActiveTab}).
421              * @param {Ext.tab.Panel} tabPanel The TabPanel
422              * @param {Ext.Component} newCard The newly activated item
423              * @param {Ext.Component} oldCard The previously active item
424              */
425             'tabchange'
426         );
427         me.callParent(arguments);
428
429         //set the active tab
430         me.setActiveTab(activeTab);
431         //set the active tab after initial layout
432         me.on('afterlayout', me.afterInitialLayout, me, {single: true});
433     },
434
435 <span id='Ext-tab-Panel-method-afterInitialLayout'>    /**
436 </span>     * @private
437      * We have to wait until after the initial layout to visually activate the activeTab (if set).
438      * The active tab has different margins than normal tabs, so if the initial layout happens with
439      * a tab active, its layout will be offset improperly due to the active margin style. Waiting
440      * until after the initial layout avoids this issue.
441      */
442     afterInitialLayout: function() {
443         var me = this,
444             card = me.getComponent(me.activeTab);
445
446         if (card) {
447             me.layout.setActiveItem(card);
448         }
449     },
450
451 <span id='Ext-tab-Panel-method-setActiveTab'>    /**
452 </span>     * Makes the given card active. Makes it the visible card in the TabPanel's CardLayout and highlights the Tab.
453      * @param {String/Number/Ext.Component} card The card to make active. Either an ID, index or the component itself.
454      */
455     setActiveTab: function(card) {
456         var me = this,
457             previous;
458
459         card = me.getComponent(card);
460         if (card) {
461             previous = me.getActiveTab();
462
463             if (previous &amp;&amp; previous !== card &amp;&amp; me.fireEvent('beforetabchange', me, card, previous) === false) {
464                 return false;
465             }
466
467             me.tabBar.setActiveTab(card.tab);
468             me.activeTab = card;
469             if (me.rendered) {
470                 me.layout.setActiveItem(card);
471             }
472
473             if (previous &amp;&amp; previous !== card) {
474                 me.fireEvent('tabchange', me, card, previous);
475             }
476         }
477     },
478
479 <span id='Ext-tab-Panel-method-getActiveTab'>    /**
480 </span>     * Returns the item that is currently active inside this TabPanel. Note that before the TabPanel first activates a
481      * child component this will return whatever was configured in the {@link #activeTab} config option
482      * @return {String/Number/Ext.Component} The currently active item
483      */
484     getActiveTab: function() {
485         return this.activeTab;
486     },
487
488 <span id='Ext-tab-Panel-method-getTabBar'>    /**
489 </span>     * Returns the {@link Ext.tab.Bar} currently used in this TabPanel
490      * @return {Ext.tab.Bar} The TabBar
491      */
492     getTabBar: function() {
493         return this.tabBar;
494     },
495
496 <span id='Ext-tab-Panel-method-onAdd'>    /**
497 </span>     * @ignore
498      * Makes sure we have a Tab for each item added to the TabPanel
499      */
500     onAdd: function(item, index) {
501         var me = this,
502             cfg = item.tabConfig || {},
503             defaultConfig = {
504                 xtype: 'tab',
505                 card: item,
506                 disabled: item.disabled,
507                 closable: item.closable,
508                 hidden: item.hidden,
509                 tabBar: me.tabBar
510             };
511
512         if (item.closeText) {
513             defaultConfig.closeText = item.closeText;
514         }
515         cfg = Ext.applyIf(cfg, defaultConfig);
516         item.tab = me.tabBar.insert(index, cfg);
517
518         item.on({
519             scope : me,
520             enable: me.onItemEnable,
521             disable: me.onItemDisable,
522             beforeshow: me.onItemBeforeShow,
523             iconchange: me.onItemIconChange,
524             titlechange: me.onItemTitleChange
525         });
526
527         if (item.isPanel) {
528             if (me.removePanelHeader) {
529                 item.preventHeader = true;
530                 if (item.rendered) {
531                     item.updateHeader();
532                 }
533             }
534             if (item.isPanel &amp;&amp; me.border) {
535                 item.setBorder(false);
536             }
537         }
538
539         // ensure that there is at least one active tab
540         if (this.rendered &amp;&amp; me.items.getCount() === 1) {
541             me.setActiveTab(0);
542         }
543     },
544
545 <span id='Ext-tab-Panel-method-onItemEnable'>    /**
546 </span>     * @private
547      * Enable corresponding tab when item is enabled.
548      */
549     onItemEnable: function(item){
550         item.tab.enable();
551     },
552
553 <span id='Ext-tab-Panel-method-onItemDisable'>    /**
554 </span>     * @private
555      * Disable corresponding tab when item is enabled.
556      */
557     onItemDisable: function(item){
558         item.tab.disable();
559     },
560
561 <span id='Ext-tab-Panel-method-onItemBeforeShow'>    /**
562 </span>     * @private
563      * Sets activeTab before item is shown.
564      */
565     onItemBeforeShow: function(item) {
566         if (item !== this.activeTab) {
567             this.setActiveTab(item);
568             return false;
569         }
570     },
571
572 <span id='Ext-tab-Panel-method-onItemIconChange'>    /**
573 </span>     * @private
574      * Update the tab iconCls when panel iconCls has been set or changed.
575      */
576     onItemIconChange: function(item, newIconCls) {
577         item.tab.setIconCls(newIconCls);
578         this.getTabBar().doLayout();
579     },
580
581 <span id='Ext-tab-Panel-method-onItemTitleChange'>    /**
582 </span>     * @private
583      * Update the tab title when panel title has been set or changed.
584      */
585     onItemTitleChange: function(item, newTitle) {
586         item.tab.setText(newTitle);
587         this.getTabBar().doLayout();
588     },
589
590
591 <span id='Ext-tab-Panel-method-doRemove'>    /**
592 </span>     * @ignore
593      * If we're removing the currently active tab, activate the nearest one. The item is removed when we call super,
594      * so we can do preprocessing before then to find the card's index
595      */
596     doRemove: function(item, autoDestroy) {
597         var me = this,
598             items = me.items,
599             // At this point the item hasn't been removed from the items collection.
600             // As such, if we want to check if there are no more tabs left, we have to
601             // check for one, as opposed to 0.
602             hasItemsLeft = items.getCount() &gt; 1;
603
604         if (me.destroying || !hasItemsLeft) {
605             me.activeTab = null;
606         } else if (item === me.activeTab) {
607              me.setActiveTab(item.next() || items.getAt(0));
608         }
609         me.callParent(arguments);
610
611         // Remove the two references
612         delete item.tab.card;
613         delete item.tab;
614     },
615
616 <span id='Ext-tab-Panel-method-onRemove'>    /**
617 </span>     * @ignore
618      * Makes sure we remove the corresponding Tab when an item is removed
619      */
620     onRemove: function(item, autoDestroy) {
621         var me = this;
622
623         item.un({
624             scope : me,
625             enable: me.onItemEnable,
626             disable: me.onItemDisable,
627             beforeshow: me.onItemBeforeShow
628         });
629         if (!me.destroying &amp;&amp; item.tab.ownerCt == me.tabBar) {
630             me.tabBar.remove(item.tab);
631         }
632     }
633 });
634 </pre>
635 </body>
636 </html>