/** * @author Ed Spencer * TabBar is used internally by a {@link Ext.tab.Panel TabPanel} and typically should not need to be created manually. * The tab bar automatically removes the default title provided by {@link Ext.panel.Header} */ Ext.define('Ext.tab.Bar', { extend: 'Ext.panel.Header', alias: 'widget.tabbar', baseCls: Ext.baseCSSPrefix + 'tab-bar', requires: ['Ext.tab.Tab'], /** * @property {Boolean} isTabBar * `true` in this class to identify an objact as an instantiated Tab Bar, or subclass thereof. */ isTabBar: true, /** * @cfg {String} title @hide */ /** * @cfg {String} iconCls @hide */ // @private defaultType: 'tab', /** * @cfg {Boolean} plain * True to not show the full background on the tabbar */ plain: false, childEls: [ 'body', 'strip' ], // @private renderTpl: [ '
{baseCls}-body-{ui} {parent.baseCls}-body-{parent.ui}-{.}" style="{bodyStyle}">', '{%this.renderContainer(out,values)%}', '
', '
{baseCls}-strip-{ui} {parent.baseCls}-strip-{parent.ui}-{.}">
' ], /** * @cfg {Number} minTabWidth * The minimum width for a tab in this tab Bar. Defaults to the tab Panel's {@link Ext.tab.Panel#minTabWidth minTabWidth} value. * @deprecated This config is deprecated. It is much easier to use the {@link Ext.tab.Panel#minTabWidth minTabWidth} config on the TabPanel. */ /** * @cfg {Number} maxTabWidth * The maximum width for a tab in this tab Bar. Defaults to the tab Panel's {@link Ext.tab.Panel#maxTabWidth maxTabWidth} value. * @deprecated This config is deprecated. It is much easier to use the {@link Ext.tab.Panel#maxTabWidth maxTabWidth} config on the TabPanel. */ // @private initComponent: function() { var me = this; if (me.plain) { me.setUI(me.ui + '-plain'); } me.addClsWithUI(me.dock); me.addEvents( /** * @event change * Fired when the currently-active tab has changed * @param {Ext.tab.Bar} tabBar The TabBar * @param {Ext.tab.Tab} tab The new Tab * @param {Ext.Component} card The card that was just shown in the TabPanel */ 'change' ); // Element onClick listener added by Header base class me.callParent(arguments); // TabBar must override the Header's align setting. me.layout.align = (me.orientation == 'vertical') ? 'left' : 'top'; me.layout.overflowHandler = new Ext.layout.container.boxOverflow.Scroller(me.layout); me.remove(me.titleCmp); delete me.titleCmp; Ext.apply(me.renderData, { bodyCls: me.bodyCls }); }, getLayout: function() { var me = this; me.layout.type = (me.dock === 'top' || me.dock === 'bottom') ? 'hbox' : 'vbox'; return me.callParent(arguments); }, // @private onAdd: function(tab) { tab.position = this.dock; this.callParent(arguments); }, onRemove: function(tab) { var me = this; if (tab === me.previousTab) { me.previousTab = null; } me.callParent(arguments); }, afterComponentLayout : function(width) { this.callParent(arguments); this.strip.setWidth(width); }, // @private onClick: function(e, target) { // The target might not be a valid tab el. var me = this, tabEl = e.getTarget('.' + Ext.tab.Tab.prototype.baseCls), tab = tabEl && Ext.getCmp(tabEl.id), tabPanel = me.tabPanel, isCloseClick = tab && tab.closeEl && (target === tab.closeEl.dom); if (isCloseClick) { e.preventDefault(); } if (tab && tab.isDisabled && !tab.isDisabled()) { if (tab.closable && isCloseClick) { tab.onCloseClick(); } else { if (tabPanel) { // TabPanel will card setActiveTab of the TabBar tabPanel.setActiveTab(tab.card); } else { me.setActiveTab(tab); } tab.focus(); } } }, /** * @private * Closes the given tab by removing it from the TabBar and removing the corresponding card from the TabPanel * @param {Ext.tab.Tab} toClose The tab to close */ closeTab: function(toClose) { var me = this, card = toClose.card, tabPanel = me.tabPanel, toActivate; if (card && card.fireEvent('beforeclose', card) === false) { return false; } // If we are closing the active tab, revert to the previously active tab (or the previous or next enabled sibling if // there *is* no previously active tab, or the previously active tab is the one that's being closed or the previously // active tab has since been disabled) toActivate = me.findNextActivatable(toClose); // We are going to remove the associated card, and then, if that was sucessful, remove the Tab, // And then potentially activate another Tab. We should not layout for each of these operations. Ext.suspendLayouts(); if (tabPanel && card) { // Remove the ownerCt so the tab doesn't get destroyed if the remove is successful // We need this so we can have the tab fire it's own close event. delete toClose.ownerCt; // we must fire 'close' before removing the card from panel, otherwise // the event will no loger have any listener card.fireEvent('close', card); tabPanel.remove(card); // Remove succeeded if (!tabPanel.getComponent(card)) { /* * Force the close event to fire. By the time this function returns, * the tab is already destroyed and all listeners have been purged * so the tab can't fire itself. */ toClose.fireClose(); me.remove(toClose); } else { // Restore the ownerCt from above toClose.ownerCt = me; Ext.resumeLayouts(true); return false; } } // If we are closing the active tab, revert to the previously active tab (or the previous sibling or the nnext sibling) if (toActivate) { // Our owning TabPanel calls our setActiveTab method, so only call that if this Bar is being used // in some other context (unlikely) if (tabPanel) { tabPanel.setActiveTab(toActivate.card); } else { me.setActiveTab(toActivate); } toActivate.focus(); } Ext.resumeLayouts(true); }, // private - used by TabPanel too. // Works out the next tab to activate when one tab is closed. findNextActivatable: function(toClose) { var me = this; if (toClose.active && me.items.getCount() > 1) { return (me.previousTab && me.previousTab !== toClose && !me.previousTab.disabled) ? me.previousTab : (toClose.next('tab[disabled=false]') || toClose.prev('tab[disabled=false]')); } }, /** * @private * Marks the given tab as active * @param {Ext.tab.Tab} tab The tab to mark active */ setActiveTab: function(tab) { var me = this; if (!tab.disabled && tab !== me.activeTab) { if (me.activeTab) { if (me.activeTab.isDestroyed) { me.previousTab = null; } else { me.previousTab = me.activeTab; me.activeTab.deactivate(); } } tab.activate(); me.activeTab = tab; me.fireEvent('change', me, tab, tab.card); // Ensure that after the currently in progress layout, the active tab is scrolled into view me.on({ afterlayout: me.afterTabActivate, scope: me, single: true }); me.updateLayout(); } }, afterTabActivate: function() { this.layout.overflowHandler.scrollToItem(this.activeTab); } });