/** * @author Ed Spencer * * Represents a single Tab in a {@link Ext.tab.Panel TabPanel}. A Tab is simply a slightly customized {@link Ext.button.Button Button}, * styled to look like a tab. Tabs are optionally closable, and can also be disabled. 99% of the time you will not * need to create Tabs manually as the framework does so automatically when you use a {@link Ext.tab.Panel TabPanel} */ Ext.define('Ext.tab.Tab', { extend: 'Ext.button.Button', alias: 'widget.tab', requires: [ 'Ext.layout.component.Tab', 'Ext.util.KeyNav' ], componentLayout: 'tab', /** * @property {Boolean} isTab * `true` in this class to identify an object as an instantiated Tab, or subclass thereof. */ isTab: true, baseCls: Ext.baseCSSPrefix + 'tab', /** * @cfg {String} activeCls * The CSS class to be applied to a Tab when it is active. * Providing your own CSS for this class enables you to customize the active state. */ activeCls: 'active', /** * @cfg {String} [disabledCls='x-tab-disabled'] * The CSS class to be applied to a Tab when it is disabled. */ /** * @cfg {String} closableCls * The CSS class which is added to the tab when it is closable */ closableCls: 'closable', /** * @cfg {Boolean} closable * True to make the Tab start closable (the close icon will be visible). */ closable: true, /** * @cfg {String} closeText * The accessible text label for the close button link; only used when {@link #cfg-closable} = true. */ // closeText: 'Close Tab', // /** * @property {Boolean} active * Indicates that this tab is currently active. This is NOT a public configuration. * @readonly */ active: false, /** * @property {Boolean} closable * True if the tab is currently closable */ childEls: [ 'closeEl' ], scale: false, position: 'top', initComponent: function() { var me = this; me.addEvents( /** * @event activate * Fired when the tab is activated. * @param {Ext.tab.Tab} this */ 'activate', /** * @event deactivate * Fired when the tab is deactivated. * @param {Ext.tab.Tab} this */ 'deactivate', /** * @event beforeclose * Fires if the user clicks on the Tab's close button, but before the {@link #close} event is fired. Return * false from any listener to stop the close event being fired * @param {Ext.tab.Tab} tab The Tab object */ 'beforeclose', /** * @event close * Fires to indicate that the tab is to be closed, usually because the user has clicked the close button. * @param {Ext.tab.Tab} tab The Tab object */ 'close' ); me.callParent(arguments); if (me.card) { me.setCard(me.card); } }, getTemplateArgs: function() { var me = this, result = me.callParent(); result.closable = me.closable; result.closeText = me.closeText; return result; }, beforeRender: function() { var me = this, tabBar = me.up('tabbar'), tabPanel = me.up('tabpanel'); me.callParent(); me.addClsWithUI(me.position); // Set all the state classNames, as they need to include the UI // me.disabledCls = me.getClsWithUIs('disabled'); me.syncClosableUI(); // Propagate minTabWidth and maxTabWidth settings from the owning TabBar then TabPanel if (!me.minWidth) { me.minWidth = (tabBar) ? tabBar.minTabWidth : me.minWidth; if (!me.minWidth && tabPanel) { me.minWidth = tabPanel.minTabWidth; } if (me.minWidth && me.iconCls) { me.minWidth += 25; } } if (!me.maxWidth) { me.maxWidth = (tabBar) ? tabBar.maxTabWidth : me.maxWidth; if (!me.maxWidth && tabPanel) { me.maxWidth = tabPanel.maxTabWidth; } } }, onRender: function() { var me = this; me.callParent(arguments); me.keyNav = new Ext.util.KeyNav(me.el, { enter: me.onEnterKey, del: me.onDeleteKey, scope: me }); }, // inherit docs enable : function(silent) { var me = this; me.callParent(arguments); me.removeClsWithUI(me.position + '-disabled'); return me; }, // inherit docs disable : function(silent) { var me = this; me.callParent(arguments); me.addClsWithUI(me.position + '-disabled'); return me; }, onDestroy: function() { var me = this; Ext.destroy(me.keyNav); delete me.keyNav; me.callParent(arguments); }, /** * Sets the tab as either closable or not. * @param {Boolean} closable Pass false to make the tab not closable. Otherwise the tab will be made closable (eg a * close button will appear on the tab) */ setClosable: function(closable) { var me = this; // Closable must be true if no args closable = (!arguments.length || !!closable); if (me.closable != closable) { me.closable = closable; // set property on the user-facing item ('card'): if (me.card) { me.card.closable = closable; } me.syncClosableUI(); if (me.rendered) { me.syncClosableElements(); // Tab will change width to accommodate close icon me.updateLayout(); } } }, /** * This method ensures that the closeBtn element exists or not based on 'closable'. * @private */ syncClosableElements: function () { var me = this, closeEl = me.closeEl; if (me.closable) { if (!closeEl) { me.closeEl = me.btnWrap.insertSibling({ tag: 'a', cls: me.baseCls + '-close-btn', href: '#', title: me.closeText }, 'after'); } } else if (closeEl) { closeEl.remove(); delete me.closeEl; } }, /** * This method ensures that the UI classes are added or removed based on 'closable'. * @private */ syncClosableUI: function () { var me = this, classes = [me.closableCls, me.closableCls + '-' + me.position]; if (me.closable) { me.addClsWithUI(classes); } else { me.removeClsWithUI(classes); } }, /** * Sets this tab's attached card. Usually this is handled automatically by the {@link Ext.tab.Panel} that this Tab * belongs to and would not need to be done by the developer * @param {Ext.Component} card The card to set */ setCard: function(card) { var me = this; me.card = card; me.setText(me.title || card.title); me.setIconCls(me.iconCls || card.iconCls); me.setIcon(me.icon || card.icon); }, /** * @private * Listener attached to click events on the Tab's close button */ onCloseClick: function() { var me = this; if (me.fireEvent('beforeclose', me) !== false) { if (me.tabBar) { if (me.tabBar.closeTab(me) === false) { // beforeclose on the panel vetoed the event, stop here return; } } else { // if there's no tabbar, fire the close event me.fireClose(); } } }, /** * Fires the close event on the tab. * @private */ fireClose: function(){ this.fireEvent('close', this); }, /** * @private */ onEnterKey: function(e) { var me = this; if (me.tabBar) { me.tabBar.onClick(e, me.el); } }, /** * @private */ onDeleteKey: function(e) { if (this.closable) { this.onCloseClick(); } }, // @private activate : function(supressEvent) { var me = this; me.active = true; me.addClsWithUI([me.activeCls, me.position + '-' + me.activeCls]); if (supressEvent !== true) { me.fireEvent('activate', me); } }, // @private deactivate : function(supressEvent) { var me = this; me.active = false; me.removeClsWithUI([me.activeCls, me.position + '-' + me.activeCls]); if (supressEvent !== true) { me.fireEvent('deactivate', me); } } });