Upgrade to ExtJS 4.0.2 - Released 06/09/2011
[extjs.git] / src / tab / Bar.js
1 /*
2
3 This file is part of Ext JS 4
4
5 Copyright (c) 2011 Sencha Inc
6
7 Contact:  http://www.sencha.com/contact
8
9 GNU General Public License Usage
10 This file may be used under the terms of the GNU General Public License version 3.0 as published by the Free Software Foundation and appearing in the file LICENSE included in the packaging of this file.  Please review the following information to ensure the GNU General Public License version 3.0 requirements will be met: http://www.gnu.org/copyleft/gpl.html.
11
12 If you are unsure which license is appropriate for your use, please contact the sales department at http://www.sencha.com/contact.
13
14 */
15 /**
16  * @author Ed Spencer
17  * @class Ext.tab.Bar
18  * @extends Ext.panel.Header
19  * <p>TabBar is used internally by a {@link Ext.tab.Panel TabPanel} and wouldn't usually need to be created manually.</p>
20  */
21 Ext.define('Ext.tab.Bar', {
22     extend: 'Ext.panel.Header',
23     alias: 'widget.tabbar',
24     baseCls: Ext.baseCSSPrefix + 'tab-bar',
25
26     requires: [
27         'Ext.tab.Tab',
28         'Ext.FocusManager'
29     ],
30
31     // @private
32     defaultType: 'tab',
33
34     /**
35      * @cfg Boolean plain
36      * True to not show the full background on the tabbar
37      */
38     plain: false,
39
40     // @private
41     renderTpl: [
42         '<div class="{baseCls}-body<tpl if="ui"> {baseCls}-body-{ui}<tpl for="uiCls"> {parent.baseCls}-body-{parent.ui}-{.}</tpl></tpl>"<tpl if="bodyStyle"> style="{bodyStyle}"</tpl>></div>',
43         '<div class="{baseCls}-strip<tpl if="ui"> {baseCls}-strip-{ui}<tpl for="uiCls"> {parent.baseCls}-strip-{parent.ui}-{.}</tpl></tpl>"></div>'
44     ],
45
46     /**
47      * @cfg {Number} minTabWidth The minimum width for each tab. Defaults to <tt>30</tt>.
48      */
49     minTabWidth: 30,
50
51     /**
52      * @cfg {Number} maxTabWidth The maximum width for each tab. Defaults to <tt>undefined</tt>.
53      */
54     maxTabWidth: undefined,
55
56     // @private
57     initComponent: function() {
58         var me = this,
59             keys;
60
61         if (me.plain) {
62             me.setUI(me.ui + '-plain');
63         }
64         
65         me.addClsWithUI(me.dock);
66
67         me.addEvents(
68             /**
69              * @event change
70              * Fired when the currently-active tab has changed
71              * @param {Ext.tab.Bar} tabBar The TabBar
72              * @param {Ext.Tab} tab The new Tab
73              * @param {Ext.Component} card The card that was just shown in the TabPanel
74              */
75             'change'
76         );
77
78         Ext.applyIf(me.renderSelectors, {
79             body : '.' + me.baseCls + '-body',
80             strip: '.' + me.baseCls + '-strip'
81         });
82         me.callParent(arguments);
83
84         // TabBar must override the Header's align setting.
85         me.layout.align = (me.orientation == 'vertical') ? 'left' : 'top';
86         me.layout.overflowHandler = Ext.create('Ext.layout.container.boxOverflow.Scroller', me.layout);
87         me.items.removeAt(me.items.getCount() - 1);
88         me.items.removeAt(me.items.getCount() - 1);
89         
90         // Subscribe to Ext.FocusManager for key navigation
91         keys = me.orientation == 'vertical' ? ['up', 'down'] : ['left', 'right'];
92         Ext.FocusManager.subscribe(me, {
93             keys: keys
94         });
95     },
96
97     // @private
98     onAdd: function(tab) {
99         var me = this,
100             tabPanel = me.tabPanel,
101             hasOwner = !!tabPanel;
102
103         me.callParent(arguments);
104         tab.position = me.dock;
105         if (hasOwner) {
106             tab.minWidth = tabPanel.minTabWidth;
107         }
108         else {
109             tab.minWidth = me.minTabWidth + (tab.iconCls ? 25 : 0);
110         }
111         tab.maxWidth = me.maxTabWidth || (hasOwner ? tabPanel.maxTabWidth : undefined);
112     },
113
114     // @private
115     afterRender: function() {
116         var me = this;
117
118         me.mon(me.el, {
119             scope: me,
120             click: me.onClick,
121             delegate: '.' + Ext.baseCSSPrefix + 'tab'
122         });
123         me.callParent(arguments);
124         
125     },
126
127     afterComponentLayout : function() {
128         var me = this;
129         
130         me.callParent(arguments);
131         me.strip.setWidth(me.el.getWidth());
132     },
133
134     // @private
135     onClick: function(e, target) {
136         // The target might not be a valid tab el.
137         var tab = Ext.getCmp(target.id),
138             tabPanel = this.tabPanel,
139             allowActive = true;
140
141         target = e.getTarget();
142
143         if (tab && tab.isDisabled && !tab.isDisabled()) {
144             if (tab.closable && target === tab.closeEl.dom) {
145                 tab.onCloseClick();
146             } else {
147                 if (tabPanel) {
148                     // TabPanel will card setActiveTab of the TabBar
149                     tabPanel.setActiveTab(tab.card);
150                 } else {
151                     this.setActiveTab(tab);
152                 }
153                 tab.focus();
154             }
155         }
156     },
157
158     /**
159      * @private
160      * Closes the given tab by removing it from the TabBar and removing the corresponding card from the TabPanel
161      * @param {Ext.Tab} tab The tab to close
162      */
163     closeTab: function(tab) {
164         var me = this,
165             card = tab.card,
166             tabPanel = me.tabPanel,
167             nextTab;
168             
169         if (card && card.fireEvent('beforeclose', card) === false) {
170             return false;
171         }
172
173         if (tab.active && me.items.getCount() > 1) {
174             nextTab = tab.next('tab') || me.items.items[0];
175             me.setActiveTab(nextTab);
176             if (tabPanel) {
177                 tabPanel.setActiveTab(nextTab.card);
178             }
179         }
180         /*
181          * force the close event to fire. By the time this function returns,
182          * the tab is already destroyed and all listeners have been purged
183          * so the tab can't fire itself.
184          */
185         tab.fireClose();
186         me.remove(tab);
187
188         if (tabPanel && card) {
189             card.fireEvent('close', card);
190             tabPanel.remove(card);
191         }
192         
193         if (nextTab) {
194             nextTab.focus();
195         }
196     },
197
198     /**
199      * @private
200      * Marks the given tab as active
201      * @param {Ext.Tab} tab The tab to mark active
202      */
203     setActiveTab: function(tab) {
204         if (tab.disabled) {
205             return;
206         }
207         var me = this;
208         if (me.activeTab) {
209             me.activeTab.deactivate();
210         }
211         tab.activate();
212         
213         if (me.rendered) {
214             me.layout.layout();
215             tab.el.scrollIntoView(me.layout.getRenderTarget());
216         }
217         me.activeTab = tab;
218         me.fireEvent('change', me, tab, tab.card);
219     }
220 });