Upgrade to ExtJS 4.0.7 - Released 10/19/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  * TabBar is used internally by a {@link Ext.tab.Panel TabPanel} and typically should not need to be created manually.
18  * The tab bar automatically removes the default title provided by {@link Ext.panel.Header}
19  */
20 Ext.define('Ext.tab.Bar', {
21     extend: 'Ext.panel.Header',
22     alias: 'widget.tabbar',
23     baseCls: Ext.baseCSSPrefix + 'tab-bar',
24
25     requires: [
26         'Ext.tab.Tab',
27         'Ext.FocusManager'
28     ],
29
30     isTabBar: true,
31     
32     /**
33      * @cfg {String} title @hide
34      */
35     
36     /**
37      * @cfg {String} iconCls @hide
38      */
39
40     // @private
41     defaultType: 'tab',
42
43     /**
44      * @cfg {Boolean} plain
45      * True to not show the full background on the tabbar
46      */
47     plain: false,
48
49     // @private
50     renderTpl: [
51         '<div id="{id}-body" class="{baseCls}-body <tpl if="bodyCls"> {bodyCls}</tpl> <tpl if="ui"> {baseCls}-body-{ui}<tpl for="uiCls"> {parent.baseCls}-body-{parent.ui}-{.}</tpl></tpl>"<tpl if="bodyStyle"> style="{bodyStyle}"</tpl>></div>',
52         '<div id="{id}-strip" class="{baseCls}-strip<tpl if="ui"> {baseCls}-strip-{ui}<tpl for="uiCls"> {parent.baseCls}-strip-{parent.ui}-{.}</tpl></tpl>"></div>'
53     ],
54
55     /**
56      * @cfg {Number} minTabWidth
57      * The minimum width for a tab in this tab Bar. Defaults to the tab Panel's {@link Ext.tab.Panel#minTabWidth minTabWidth} value.
58      * @deprecated This config is deprecated. It is much easier to use the {@link Ext.tab.Panel#minTabWidth minTabWidth} config on the TabPanel.
59      */
60
61     /**
62      * @cfg {Number} maxTabWidth
63      * The maximum width for a tab in this tab Bar. Defaults to the tab Panel's {@link Ext.tab.Panel#maxTabWidth maxTabWidth} value.
64      * @deprecated This config is deprecated. It is much easier to use the {@link Ext.tab.Panel#maxTabWidth maxTabWidth} config on the TabPanel.
65      */
66
67     // @private
68     initComponent: function() {
69         var me = this,
70             keys;
71
72         if (me.plain) {
73             me.setUI(me.ui + '-plain');
74         }
75
76         me.addClsWithUI(me.dock);
77
78         me.addEvents(
79             /**
80              * @event change
81              * Fired when the currently-active tab has changed
82              * @param {Ext.tab.Bar} tabBar The TabBar
83              * @param {Ext.tab.Tab} tab The new Tab
84              * @param {Ext.Component} card The card that was just shown in the TabPanel
85              */
86             'change'
87         );
88
89         me.addChildEls('body', 'strip');
90         me.callParent(arguments);
91
92         // TabBar must override the Header's align setting.
93         me.layout.align = (me.orientation == 'vertical') ? 'left' : 'top';
94         me.layout.overflowHandler = Ext.create('Ext.layout.container.boxOverflow.Scroller', me.layout);
95
96         me.remove(me.titleCmp);
97         delete me.titleCmp;
98
99         // Subscribe to Ext.FocusManager for key navigation
100         keys = me.orientation == 'vertical' ? ['up', 'down'] : ['left', 'right'];
101         Ext.FocusManager.subscribe(me, {
102             keys: keys
103         });
104
105         Ext.apply(me.renderData, {
106             bodyCls: me.bodyCls
107         });
108     },
109
110     // @private
111     onAdd: function(tab) {
112         tab.position = this.dock;
113         this.callParent(arguments);
114     },
115     
116     onRemove: function(tab) {
117         var me = this;
118         
119         if (tab === me.previousTab) {
120             me.previousTab = null;
121         }
122         if (me.items.getCount() === 0) {
123             me.activeTab = null;
124         }
125         me.callParent(arguments);    
126     },
127
128     // @private
129     afterRender: function() {
130         var me = this;
131
132         me.mon(me.el, {
133             scope: me,
134             click: me.onClick,
135             delegate: '.' + Ext.baseCSSPrefix + 'tab'
136         });
137         me.callParent(arguments);
138
139     },
140
141     afterComponentLayout : function() {
142         var me = this;
143
144         me.callParent(arguments);
145         me.strip.setWidth(me.el.getWidth());
146     },
147
148     // @private
149     onClick: function(e, target) {
150         // The target might not be a valid tab el.
151         var tab = Ext.getCmp(target.id),
152             tabPanel = this.tabPanel;
153
154         target = e.getTarget();
155
156         if (tab && tab.isDisabled && !tab.isDisabled()) {
157             if (tab.closable && target === tab.closeEl.dom) {
158                 tab.onCloseClick();
159             } else {
160                 if (tabPanel) {
161                     // TabPanel will card setActiveTab of the TabBar
162                     tabPanel.setActiveTab(tab.card);
163                 } else {
164                     this.setActiveTab(tab);
165                 }
166                 tab.focus();
167             }
168         }
169     },
170
171     /**
172      * @private
173      * Closes the given tab by removing it from the TabBar and removing the corresponding card from the TabPanel
174      * @param {Ext.tab.Tab} tab The tab to close
175      */
176     closeTab: function(tab) {
177         var me = this,
178             card = tab.card,
179             tabPanel = me.tabPanel,
180             nextTab;
181
182         if (card && card.fireEvent('beforeclose', card) === false) {
183             return false;
184         }
185
186         if (tab.active && me.items.getCount() > 1) {
187             nextTab = me.previousTab || tab.next('tab') || me.items.first();
188             me.setActiveTab(nextTab);
189             if (tabPanel) {
190                 tabPanel.setActiveTab(nextTab.card);
191             }
192         }
193         /*
194          * force the close event to fire. By the time this function returns,
195          * the tab is already destroyed and all listeners have been purged
196          * so the tab can't fire itself.
197          */
198         tab.fireClose();
199         me.remove(tab);
200
201         if (tabPanel && card) {
202             card.fireEvent('close', card);
203             tabPanel.remove(card);
204         }
205
206         if (nextTab) {
207             nextTab.focus();
208         }
209     },
210
211     /**
212      * @private
213      * Marks the given tab as active
214      * @param {Ext.tab.Tab} tab The tab to mark active
215      */
216     setActiveTab: function(tab) {
217         if (tab.disabled) {
218             return;
219         }
220         var me = this;
221         if (me.activeTab) {
222             me.previousTab = me.activeTab;
223             me.activeTab.deactivate();
224         }
225         tab.activate();
226
227         if (me.rendered) {
228             me.layout.layout();
229             tab.el && tab.el.scrollIntoView(me.layout.getRenderTarget());
230         }
231         me.activeTab = tab;
232         me.fireEvent('change', me, tab, tab.card);
233     }
234 });
235