facebook-workplaceoutlookemailmicrosoft-teamsdiscordmessengercustom-servicesmacoslinuxwindowsinboxwhatsappicloudtweetdeckhipchattelegramhangoutsslackgmailskype
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
845 lines
27 KiB
845 lines
27 KiB
9 years ago
|
/**
|
||
|
* A basic tab container. TabPanels can be used exactly like a standard {@link Ext.panel.Panel} for
|
||
|
* layout purposes, but also have special support for containing child Components
|
||
|
* (`{@link Ext.container.Container#cfg-items items}`) that are managed using a
|
||
|
* {@link Ext.layout.container.Card CardLayout layout manager}, and displayed as separate tabs.
|
||
|
*
|
||
|
* **Note:** By default, a tab's close tool _destroys_ the child tab Component and all its descendants.
|
||
|
* This makes the child tab Component, and all its descendants **unusable**. To enable re-use of a tab,
|
||
|
* configure the TabPanel with `{@link #autoDestroy autoDestroy: false}`.
|
||
|
*
|
||
|
* ## TabPanel's layout
|
||
|
*
|
||
|
* TabPanels use a Dock layout to position the {@link Ext.tab.Bar TabBar} at the top of the widget.
|
||
|
* Panels added to the TabPanel will have their header hidden by default because the Tab will
|
||
|
* automatically take the Panel's configured title and icon.
|
||
|
*
|
||
|
* TabPanels use their {@link Ext.panel.Header header} or {@link Ext.panel.Panel#fbar footer}
|
||
|
* element (depending on the {@link #tabPosition} configuration) to accommodate the tab selector buttons.
|
||
|
* This means that a TabPanel will not display any configured title, and will not display any configured
|
||
|
* header {@link Ext.panel.Panel#tools tools}.
|
||
|
*
|
||
|
* To display a header, embed the TabPanel in a {@link Ext.panel.Panel Panel} which uses
|
||
|
* `{@link Ext.container.Container#layout layout: 'fit'}`.
|
||
|
*
|
||
|
* ## Controlling tabs
|
||
|
*
|
||
|
* Configuration options for the {@link Ext.tab.Tab} that represents the component can be passed in
|
||
|
* by specifying the tabConfig option:
|
||
|
*
|
||
|
* @example
|
||
|
* Ext.tip.QuickTipManager.init();
|
||
|
* Ext.create('Ext.tab.Panel', {
|
||
|
* width: 400,
|
||
|
* height: 400,
|
||
|
* renderTo: document.body,
|
||
|
* items: [{
|
||
|
* title: 'Foo'
|
||
|
* }, {
|
||
|
* title: 'Bar',
|
||
|
* tabConfig: {
|
||
|
* title: 'Custom Title',
|
||
|
* tooltip: 'A button tooltip'
|
||
|
* }
|
||
|
* }]
|
||
|
* });
|
||
|
*
|
||
|
* ## Vetoing Changes
|
||
|
*
|
||
|
* User interaction when changing the tabs can be vetoed by listening to the {@link #beforetabchange} event.
|
||
|
* By returning `false`, the tab change will not occur.
|
||
|
*
|
||
|
* @example
|
||
|
* Ext.create('Ext.tab.Panel', {
|
||
|
* renderTo: Ext.getBody(),
|
||
|
* width: 200,
|
||
|
* height: 200,
|
||
|
* listeners: {
|
||
|
* beforetabchange: function(tabs, newTab, oldTab) {
|
||
|
* return newTab.title != 'P2';
|
||
|
* }
|
||
|
* },
|
||
|
* items: [{
|
||
|
* title: 'P1'
|
||
|
* }, {
|
||
|
* title: 'P2'
|
||
|
* }, {
|
||
|
* title: 'P3'
|
||
|
* }]
|
||
|
* });
|
||
|
*
|
||
|
* # Examples
|
||
|
*
|
||
|
* Here is a basic TabPanel rendered to the body. This also shows the useful configuration {@link #activeTab},
|
||
|
* which allows you to set the active tab on render.
|
||
|
*
|
||
|
* @example
|
||
|
* Ext.create('Ext.tab.Panel', {
|
||
|
* width: 300,
|
||
|
* height: 200,
|
||
|
* activeTab: 0,
|
||
|
* items: [
|
||
|
* {
|
||
|
* title: 'Tab 1',
|
||
|
* bodyPadding: 10,
|
||
|
* html : 'A simple tab'
|
||
|
* },
|
||
|
* {
|
||
|
* title: 'Tab 2',
|
||
|
* html : 'Another one'
|
||
|
* }
|
||
|
* ],
|
||
|
* renderTo : Ext.getBody()
|
||
|
* });
|
||
|
*
|
||
|
* It is easy to control the visibility of items in the tab bar. Specify hidden: true to have the
|
||
|
* tab button hidden initially. Items can be subsequently hidden and show by accessing the
|
||
|
* tab property on the child item.
|
||
|
*
|
||
|
* @example
|
||
|
* var tabs = Ext.create('Ext.tab.Panel', {
|
||
|
* width: 400,
|
||
|
* height: 400,
|
||
|
* renderTo: document.body,
|
||
|
* items: [{
|
||
|
* title: 'Home',
|
||
|
* html: 'Home',
|
||
|
* itemId: 'home'
|
||
|
* }, {
|
||
|
* title: 'Users',
|
||
|
* html: 'Users',
|
||
|
* itemId: 'users',
|
||
|
* hidden: true
|
||
|
* }, {
|
||
|
* title: 'Tickets',
|
||
|
* html: 'Tickets',
|
||
|
* itemId: 'tickets'
|
||
|
* }]
|
||
|
* });
|
||
|
*
|
||
|
* Ext.defer(function(){
|
||
|
* tabs.child('#home').tab.hide();
|
||
|
* var users = tabs.child('#users');
|
||
|
* users.tab.show();
|
||
|
* tabs.setActiveTab(users);
|
||
|
* }, 1000);
|
||
|
*
|
||
|
* You can remove the background of the TabBar by setting the {@link #plain} property to `true`.
|
||
|
*
|
||
|
* @example
|
||
|
* Ext.create('Ext.tab.Panel', {
|
||
|
* width: 300,
|
||
|
* height: 200,
|
||
|
* activeTab: 0,
|
||
|
* plain: true,
|
||
|
* items: [
|
||
|
* {
|
||
|
* title: 'Tab 1',
|
||
|
* bodyPadding: 10,
|
||
|
* html : 'A simple tab'
|
||
|
* },
|
||
|
* {
|
||
|
* title: 'Tab 2',
|
||
|
* html : 'Another one'
|
||
|
* }
|
||
|
* ],
|
||
|
* renderTo : Ext.getBody()
|
||
|
* });
|
||
|
*
|
||
|
* Another useful configuration of TabPanel is {@link #tabPosition}. This allows you to change the
|
||
|
* position where the tabs are displayed. The available options for this are `'top'` (default) and
|
||
|
* `'bottom'`.
|
||
|
*
|
||
|
* @example
|
||
|
* Ext.create('Ext.tab.Panel', {
|
||
|
* width: 300,
|
||
|
* height: 200,
|
||
|
* activeTab: 0,
|
||
|
* bodyPadding: 10,
|
||
|
* tabPosition: 'bottom',
|
||
|
* items: [
|
||
|
* {
|
||
|
* title: 'Tab 1',
|
||
|
* html : 'A simple tab'
|
||
|
* },
|
||
|
* {
|
||
|
* title: 'Tab 2',
|
||
|
* html : 'Another one'
|
||
|
* }
|
||
|
* ],
|
||
|
* renderTo : Ext.getBody()
|
||
|
* });
|
||
|
*
|
||
|
* The {@link #setActiveTab} is a very useful method in TabPanel which will allow you to change the
|
||
|
* current active tab. You can either give it an index or an instance of a tab. For example:
|
||
|
*
|
||
|
* @example
|
||
|
* var tabs = Ext.create('Ext.tab.Panel', {
|
||
|
* items: [
|
||
|
* {
|
||
|
* id : 'my-tab',
|
||
|
* title: 'Tab 1',
|
||
|
* html : 'A simple tab'
|
||
|
* },
|
||
|
* {
|
||
|
* title: 'Tab 2',
|
||
|
* html : 'Another one'
|
||
|
* }
|
||
|
* ],
|
||
|
* renderTo : Ext.getBody()
|
||
|
* });
|
||
|
*
|
||
|
* var tab = Ext.getCmp('my-tab');
|
||
|
*
|
||
|
* Ext.create('Ext.button.Button', {
|
||
|
* renderTo: Ext.getBody(),
|
||
|
* text : 'Select the first tab',
|
||
|
* scope : this,
|
||
|
* handler : function() {
|
||
|
* tabs.setActiveTab(tab);
|
||
|
* }
|
||
|
* });
|
||
|
*
|
||
|
* Ext.create('Ext.button.Button', {
|
||
|
* text : 'Select the second tab',
|
||
|
* scope : this,
|
||
|
* handler : function() {
|
||
|
* tabs.setActiveTab(1);
|
||
|
* },
|
||
|
* renderTo : Ext.getBody()
|
||
|
* });
|
||
|
*
|
||
|
* The {@link #getActiveTab} is a another useful method in TabPanel which will return the current active tab.
|
||
|
*
|
||
|
* @example
|
||
|
* var tabs = Ext.create('Ext.tab.Panel', {
|
||
|
* items: [
|
||
|
* {
|
||
|
* title: 'Tab 1',
|
||
|
* html : 'A simple tab'
|
||
|
* },
|
||
|
* {
|
||
|
* title: 'Tab 2',
|
||
|
* html : 'Another one'
|
||
|
* }
|
||
|
* ],
|
||
|
* renderTo : Ext.getBody()
|
||
|
* });
|
||
|
*
|
||
|
* Ext.create('Ext.button.Button', {
|
||
|
* text : 'Get active tab',
|
||
|
* scope : this,
|
||
|
* handler : function() {
|
||
|
* var tab = tabs.getActiveTab();
|
||
|
* alert('Current tab: ' + tab.title);
|
||
|
* },
|
||
|
* renderTo : Ext.getBody()
|
||
|
* });
|
||
|
*
|
||
|
* Adding a new tab is very simple with a TabPanel. You simple call the {@link #method-add} method with an config
|
||
|
* object for a panel.
|
||
|
*
|
||
|
* @example
|
||
|
* var tabs = Ext.create('Ext.tab.Panel', {
|
||
|
* items: [
|
||
|
* {
|
||
|
* title: 'Tab 1',
|
||
|
* html : 'A simple tab'
|
||
|
* },
|
||
|
* {
|
||
|
* title: 'Tab 2',
|
||
|
* html : 'Another one'
|
||
|
* }
|
||
|
* ],
|
||
|
* renderTo : Ext.getBody()
|
||
|
* });
|
||
|
*
|
||
|
* Ext.create('Ext.button.Button', {
|
||
|
* text : 'New tab',
|
||
|
* scope : this,
|
||
|
* handler : function() {
|
||
|
* var tab = tabs.add({
|
||
|
* // we use the tabs.items property to get the length of current items/tabs
|
||
|
* title: 'Tab ' + (tabs.items.length + 1),
|
||
|
* html : 'Another one'
|
||
|
* });
|
||
|
*
|
||
|
* tabs.setActiveTab(tab);
|
||
|
* },
|
||
|
* renderTo : Ext.getBody()
|
||
|
* });
|
||
|
*
|
||
|
* Additionally, removing a tab is very also simple with a TabPanel. You simple call the {@link #method-remove} method
|
||
|
* with an config object for a panel.
|
||
|
*
|
||
|
* @example
|
||
|
* var tabs = Ext.create('Ext.tab.Panel', {
|
||
|
* items: [
|
||
|
* {
|
||
|
* title: 'Tab 1',
|
||
|
* html : 'A simple tab'
|
||
|
* },
|
||
|
* {
|
||
|
* id : 'remove-this-tab',
|
||
|
* title: 'Tab 2',
|
||
|
* html : 'Another one'
|
||
|
* }
|
||
|
* ],
|
||
|
* renderTo : Ext.getBody()
|
||
|
* });
|
||
|
*
|
||
|
* Ext.create('Ext.button.Button', {
|
||
|
* text : 'Remove tab',
|
||
|
* scope : this,
|
||
|
* handler : function() {
|
||
|
* var tab = Ext.getCmp('remove-this-tab');
|
||
|
* tabs.remove(tab);
|
||
|
* },
|
||
|
* renderTo : Ext.getBody()
|
||
|
* });
|
||
|
*/
|
||
|
Ext.define('Ext.tab.Panel', {
|
||
|
extend: 'Ext.panel.Panel',
|
||
|
alias: 'widget.tabpanel',
|
||
|
alternateClassName: ['Ext.TabPanel'],
|
||
|
|
||
|
requires: ['Ext.layout.container.Card', 'Ext.tab.Bar'],
|
||
|
|
||
|
config: {
|
||
|
// @cmd-auto-dependency { directRef: 'Ext.tab.Bar' }
|
||
|
/**
|
||
|
* @cfg {Object} tabBar
|
||
|
* Optional configuration object for the internal {@link Ext.tab.Bar}.
|
||
|
* If present, this is passed straight through to the TabBar's constructor
|
||
|
*/
|
||
|
tabBar: undefined,
|
||
|
|
||
|
/**
|
||
|
* @cfg {"top"/"bottom"/"left"/"right"} tabPosition
|
||
|
* The position where the tab strip should be rendered. Possible values are:
|
||
|
*
|
||
|
* - top
|
||
|
* - bottom
|
||
|
* - left
|
||
|
* - right
|
||
|
*/
|
||
|
tabPosition : 'top',
|
||
|
|
||
|
/**
|
||
|
* @cfg {'default'/0/1/2} tabRotation
|
||
|
* The rotation of the tabs. Can be one of the following values:
|
||
|
*
|
||
|
* - `'default'` use the default rotation, depending on {@link #tabPosition} (see below)
|
||
|
* - `0` - no rotation
|
||
|
* - `1` - rotate 90deg clockwise
|
||
|
* - `2` - rotate 90deg counter-clockwise
|
||
|
*
|
||
|
* The default behavior of this config depends on the {@link #tabPosition}:
|
||
|
*
|
||
|
* - `'top'` or `'bottom'` - `0`
|
||
|
* - `'right'` - `1`
|
||
|
* - `'left'` - `2`
|
||
|
*/
|
||
|
tabRotation: 'default',
|
||
|
|
||
|
/**
|
||
|
* @cfg {Boolean} tabStretchMax
|
||
|
* `true` to stretch all tabs to the height of the tallest tab when the tabBar
|
||
|
* is docked horizontally, or the width of the widest tab when the tabBar is
|
||
|
* docked vertically.
|
||
|
*/
|
||
|
tabStretchMax: true
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* @cfg {Number} tabBarHeaderPosition
|
||
|
* If specified, the {@link #tabBar} will be rendered as an item of the TabPanel's
|
||
|
* Header and the specified `tabBarHeaderPosition` will be used as the Panel header's
|
||
|
* {@link Ext.panel.Header#itemPosition}. If not specified, the {@link #tabBar}
|
||
|
* will be rendered as a docked item at {@link #tabPosition}.
|
||
|
*/
|
||
|
|
||
|
/**
|
||
|
* @cfg {String/Number} activeItem
|
||
|
* Doesn't apply for {@link Ext.tab.Panel TabPanel}, use {@link #activeTab} instead.
|
||
|
*/
|
||
|
|
||
|
/**
|
||
|
* @cfg {String/Number/Ext.Component} activeTab
|
||
|
* The tab to activate initially. Either an ID, index or the tab component itself. If null, no tab will be set as active.
|
||
|
*/
|
||
|
|
||
|
|
||
|
/**
|
||
|
* @cfg {Ext.enums.Layout/Object} layout
|
||
|
* Optional configuration object for the internal {@link Ext.layout.container.Card card layout}.
|
||
|
* If present, this is passed straight through to the layout's constructor
|
||
|
*/
|
||
|
|
||
|
/**
|
||
|
* @cfg {Boolean} removePanelHeader
|
||
|
* True to instruct each Panel added to the TabContainer to not render its header element.
|
||
|
* This is to ensure that the title of the panel does not appear twice.
|
||
|
*/
|
||
|
removePanelHeader: true,
|
||
|
|
||
|
/**
|
||
|
* @cfg {Boolean} plain
|
||
|
* True to not show the full background on the TabBar.
|
||
|
*/
|
||
|
plain: false,
|
||
|
|
||
|
/**
|
||
|
* @cfg {String} [itemCls='x-tabpanel-child']
|
||
|
* The class added to each child item of this TabPanel.
|
||
|
*/
|
||
|
itemCls: Ext.baseCSSPrefix + 'tabpanel-child',
|
||
|
|
||
|
/**
|
||
|
* @cfg {Number} minTabWidth
|
||
|
* The minimum width for a tab in the {@link #cfg-tabBar}.
|
||
|
*/
|
||
|
minTabWidth: undefined,
|
||
|
|
||
|
/**
|
||
|
* @cfg {Number} maxTabWidth The maximum width for each tab.
|
||
|
*/
|
||
|
maxTabWidth: undefined,
|
||
|
|
||
|
/**
|
||
|
* @cfg {Boolean} deferredRender
|
||
|
*
|
||
|
* True by default to defer the rendering of child {@link Ext.container.Container#cfg-items items} to the browsers DOM
|
||
|
* until a tab is activated. False will render all contained {@link Ext.container.Container#cfg-items items} as soon as
|
||
|
* the {@link Ext.layout.container.Card layout} is rendered. If there is a significant amount of content or a lot of
|
||
|
* heavy controls being rendered into panels that are not displayed by default, setting this to true might improve
|
||
|
* performance.
|
||
|
*
|
||
|
* The deferredRender property is internally passed to the layout manager for TabPanels ({@link
|
||
|
* Ext.layout.container.Card}) as its {@link Ext.layout.container.Card#deferredRender} configuration value.
|
||
|
*
|
||
|
* **Note**: leaving deferredRender as true means that the content within an unactivated tab will not be available
|
||
|
*/
|
||
|
deferredRender : true,
|
||
|
|
||
|
_defaultTabRotation: {
|
||
|
top: 0,
|
||
|
right: 1,
|
||
|
bottom: 0,
|
||
|
left: 2
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* @event beforetabchange
|
||
|
* Fires before a tab change (activated by {@link #setActiveTab}). Return false in any listener to cancel
|
||
|
* the tabchange
|
||
|
* @param {Ext.tab.Panel} tabPanel The TabPanel
|
||
|
* @param {Ext.Component} newCard The card that is about to be activated
|
||
|
* @param {Ext.Component} oldCard The card that is currently active
|
||
|
*/
|
||
|
|
||
|
/**
|
||
|
* @event tabchange
|
||
|
* Fires when a new tab has been activated (activated by {@link #setActiveTab}).
|
||
|
* @param {Ext.tab.Panel} tabPanel The TabPanel
|
||
|
* @param {Ext.Component} newCard The newly activated item
|
||
|
* @param {Ext.Component} oldCard The previously active item
|
||
|
*/
|
||
|
|
||
|
//inherit docs
|
||
|
initComponent: function() {
|
||
|
var me = this,
|
||
|
// Default to 0 if undefined and not null!
|
||
|
activeTab = me.activeTab !== null ? (me.activeTab || 0) : null,
|
||
|
dockedItems = me.dockedItems,
|
||
|
header = me.header,
|
||
|
tabBarHeaderPosition = me.tabBarHeaderPosition,
|
||
|
tabBar = me.getTabBar(),
|
||
|
headerItems;
|
||
|
|
||
|
// Configure the layout with our deferredRender, and with our activeTeb
|
||
|
me.layout = new Ext.layout.container.Card(Ext.apply({
|
||
|
owner: me,
|
||
|
deferredRender: me.deferredRender,
|
||
|
itemCls: me.itemCls,
|
||
|
activeItem: activeTab
|
||
|
}, me.layout));
|
||
|
|
||
|
if (tabBarHeaderPosition != null) {
|
||
|
header = me.header = Ext.apply({}, header);
|
||
|
|
||
|
headerItems = header.items = (header.items ? header.items.slice() : []);
|
||
|
header.itemPosition = tabBarHeaderPosition;
|
||
|
headerItems.push(tabBar);
|
||
|
header.hasTabBar = true;
|
||
|
} else {
|
||
|
dockedItems = [].concat(me.dockedItems || []);
|
||
|
dockedItems.push(tabBar);
|
||
|
me.dockedItems = dockedItems;
|
||
|
}
|
||
|
|
||
|
me.callParent(arguments);
|
||
|
|
||
|
// We have to convert the numeric index/string ID config into its component reference
|
||
|
activeTab = me.activeTab = me.getComponent(activeTab);
|
||
|
|
||
|
// Ensure that the active child's tab is rendered in the active UI state
|
||
|
if (activeTab) {
|
||
|
tabBar.setActiveTab(activeTab.tab, true);
|
||
|
}
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* @method getTabBar
|
||
|
* Returns the {@link Ext.tab.Bar} associated with this tabPanel.
|
||
|
* @return {Ext.tab.Bar} The tabBar for this tabPanel
|
||
|
*/
|
||
|
|
||
|
/**
|
||
|
* @method setTabBar
|
||
|
* @hide
|
||
|
*/
|
||
|
|
||
|
onRender: function() {
|
||
|
var items = this.items.items,
|
||
|
len = items.length,
|
||
|
i;
|
||
|
|
||
|
this.callParent(arguments);
|
||
|
|
||
|
// We want to force any view model for the panel to be created.
|
||
|
// This is because we capture various parts about the panel itself (title, icon, etc)
|
||
|
// So we need to be able to use that to populate the tabs.
|
||
|
// In the future, this could be optimized to be a bit smarter to prevent creation when
|
||
|
// not required.
|
||
|
for (i = 0; i < len; ++i) {
|
||
|
items[i].getBind();
|
||
|
}
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* Makes the given card active. Makes it the visible card in the TabPanel's CardLayout and highlights the Tab.
|
||
|
* @param {String/Number/Ext.Component} card The card to make active. Either an ID, index or the component itself.
|
||
|
* @return {Ext.Component} The resulting active child Component. The call may have been vetoed, or otherwise
|
||
|
* modified by an event listener.
|
||
|
*/
|
||
|
setActiveTab: function(card) {
|
||
|
var me = this,
|
||
|
previous;
|
||
|
|
||
|
// Check for a config object
|
||
|
if (!Ext.isObject(card) || card.isComponent) {
|
||
|
card = me.getComponent(card);
|
||
|
}
|
||
|
previous = me.getActiveTab();
|
||
|
if (card) {
|
||
|
Ext.suspendLayouts();
|
||
|
// We may be passed a config object, so add it.
|
||
|
// Without doing a layout!
|
||
|
if (!card.isComponent) {
|
||
|
card = me.add(card);
|
||
|
}
|
||
|
|
||
|
if (previous === card || me.fireEvent('beforetabchange', me, card, previous) === false) {
|
||
|
Ext.resumeLayouts(true);
|
||
|
return previous;
|
||
|
}
|
||
|
|
||
|
// MUST set the activeTab first so that the machinery which listens for show doesn't
|
||
|
// think that the show is "driving" the activation and attempt to recurse into here.
|
||
|
me.activeTab = card;
|
||
|
|
||
|
// Attempt to switch to the requested card. Suspend layouts because if that was successful
|
||
|
// we have to also update the active tab in the tab bar which is another layout operation
|
||
|
// and we must coalesce them.
|
||
|
me.layout.setActiveItem(card);
|
||
|
|
||
|
// Read the result of the card layout. Events dear boy, events!
|
||
|
card = me.activeTab = me.layout.getActiveItem();
|
||
|
|
||
|
// Card switch was not vetoed by an event listener
|
||
|
if (card && card !== previous) {
|
||
|
|
||
|
// Update the active tab in the tab bar and resume layouts.
|
||
|
me.tabBar.setActiveTab(card.tab);
|
||
|
Ext.resumeLayouts(true);
|
||
|
|
||
|
// previous will be undefined or this.activeTab at instantiation
|
||
|
if (previous !== card) {
|
||
|
me.fireEvent('tabchange', me, card, previous);
|
||
|
}
|
||
|
}
|
||
|
// Card switch was vetoed by an event listener. Resume layouts (Nothing should have changed on a veto).
|
||
|
else {
|
||
|
Ext.resumeLayouts(true);
|
||
|
}
|
||
|
return card;
|
||
|
}
|
||
|
return previous;
|
||
|
},
|
||
|
|
||
|
setActiveItem: function(item) {
|
||
|
return this.setActiveTab(item);
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* Returns the item that is currently active inside this TabPanel.
|
||
|
* @return {Ext.Component} The currently active item.
|
||
|
*/
|
||
|
getActiveTab: function() {
|
||
|
var me = this,
|
||
|
// Ensure the calculated result references a Component
|
||
|
result = me.getComponent(me.activeTab);
|
||
|
|
||
|
// Sanitize the result in case the active tab is no longer there.
|
||
|
if (result && me.items.indexOf(result) !== -1) {
|
||
|
me.activeTab = result;
|
||
|
} else {
|
||
|
me.activeTab = undefined;
|
||
|
}
|
||
|
|
||
|
return me.activeTab;
|
||
|
},
|
||
|
|
||
|
applyTabBar: function(tabBar) {
|
||
|
var me = this,
|
||
|
// if we are rendering the tabbar into the panel header, use same alignment
|
||
|
// as header position, and ignore tabPosition.
|
||
|
dock = (me.tabBarHeaderPosition != null) ? me.getHeaderPosition() : me.getTabPosition();
|
||
|
|
||
|
return new Ext.tab.Bar(Ext.apply({
|
||
|
ui: me.ui,
|
||
|
dock: dock,
|
||
|
tabRotation: me.getTabRotation(),
|
||
|
vertical: (dock === 'left' || dock === 'right'),
|
||
|
plain: me.plain,
|
||
|
tabStretchMax: me.getTabStretchMax(),
|
||
|
tabPanel: me
|
||
|
}, tabBar));
|
||
|
},
|
||
|
|
||
|
updateHeaderPosition: function(headerPosition, oldHeaderPosition) {
|
||
|
var tabBar = this.getTabBar();
|
||
|
|
||
|
if (tabBar && (this.tabBarHeaderPosition != null)) {
|
||
|
tabBar.setDock(headerPosition);
|
||
|
}
|
||
|
|
||
|
this.callParent([headerPosition, oldHeaderPosition]);
|
||
|
},
|
||
|
|
||
|
updateTabPosition: function(tabPosition) {
|
||
|
var tabBar = this.getTabBar();
|
||
|
|
||
|
if (tabBar && (this.tabBarHeaderPosition == null)) {
|
||
|
tabBar.setDock(tabPosition);
|
||
|
}
|
||
|
},
|
||
|
|
||
|
updateTabRotation: function(tabRotation) {
|
||
|
var tabBar = this.getTabBar();
|
||
|
|
||
|
if (tabBar) {
|
||
|
tabBar.setTabRotation(tabRotation);
|
||
|
}
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* @protected
|
||
|
* Makes sure we have a Tab for each item added to the TabPanel
|
||
|
*/
|
||
|
onAdd: function(item, index) {
|
||
|
var me = this,
|
||
|
cfg = Ext.apply({}, item.tabConfig),
|
||
|
tabBar = me.getTabBar(),
|
||
|
defaultConfig = {
|
||
|
xtype: 'tab',
|
||
|
title: item.title,
|
||
|
icon: item.icon,
|
||
|
iconCls: item.iconCls,
|
||
|
glyph: item.glyph,
|
||
|
ui: tabBar.ui,
|
||
|
card: item,
|
||
|
disabled: item.disabled,
|
||
|
closable: item.closable,
|
||
|
hidden: item.hidden && !item.hiddenByLayout, // only hide if it wasn't hidden by the layout itself
|
||
|
tooltip: item.tooltip,
|
||
|
tabBar: tabBar,
|
||
|
tabPosition: tabBar.dock,
|
||
|
rotation: tabBar.getTabRotation()
|
||
|
};
|
||
|
|
||
|
if (item.closeText !== undefined) {
|
||
|
defaultConfig.closeText = item.closeText;
|
||
|
}
|
||
|
|
||
|
cfg = Ext.applyIf(cfg, defaultConfig);
|
||
|
|
||
|
// Create the correspondiong tab in the tab bar
|
||
|
item.tab = me.tabBar.insert(index, cfg);
|
||
|
|
||
|
item.on({
|
||
|
scope : me,
|
||
|
enable: me.onItemEnable,
|
||
|
disable: me.onItemDisable,
|
||
|
beforeshow: me.onItemBeforeShow,
|
||
|
iconchange: me.onItemIconChange,
|
||
|
iconclschange: me.onItemIconClsChange,
|
||
|
glyphchange: me.onItemGlyphChange,
|
||
|
titlechange: me.onItemTitleChange
|
||
|
});
|
||
|
|
||
|
if (item.isPanel) {
|
||
|
if (me.removePanelHeader) {
|
||
|
if (item.rendered) {
|
||
|
if (item.header) {
|
||
|
item.header.hide();
|
||
|
}
|
||
|
} else {
|
||
|
item.header = false;
|
||
|
}
|
||
|
}
|
||
|
if (item.isPanel && me.border) {
|
||
|
item.setBorder(false);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Force the view model to be created, see onRender
|
||
|
if (me.rendered) {
|
||
|
item.getBind();
|
||
|
}
|
||
|
|
||
|
// Ensure that there is at least one active tab. This is only needed when adding tabs via a loader config, i.e., there
|
||
|
// may be no pre-existing tabs. Note that we need to check if activeTab was explicitly set to `null` in the tabpanel
|
||
|
// config (which tells the layout not to set an active item), as this is a valid value to mean 'do not set an active tab'.
|
||
|
if (me.rendered && me.loader && me.activeTab === undefined && me.layout.activeItem !== null) {
|
||
|
me.setActiveTab(0);
|
||
|
}
|
||
|
},
|
||
|
|
||
|
onMove: function(item, fromIdx, toIdx) {
|
||
|
var tabBar = this.getTabBar();
|
||
|
|
||
|
this.callParent([item, fromIdx, toIdx]);
|
||
|
|
||
|
// If the move of the item.tab triggered the movement of the child Panel,
|
||
|
// then we're done.
|
||
|
if (tabBar.items.indexOf(item.tab) !== toIdx) {
|
||
|
tabBar.move(item.tab, toIdx);
|
||
|
}
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* @private
|
||
|
* Enable corresponding tab when item is enabled.
|
||
|
*/
|
||
|
onItemEnable: function(item){
|
||
|
item.tab.enable();
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* @private
|
||
|
* Disable corresponding tab when item is enabled.
|
||
|
*/
|
||
|
onItemDisable: function(item){
|
||
|
item.tab.disable();
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* @private
|
||
|
* Sets activeTab before item is shown.
|
||
|
*/
|
||
|
onItemBeforeShow: function(item) {
|
||
|
if (item !== this.activeTab) {
|
||
|
this.setActiveTab(item);
|
||
|
return false;
|
||
|
}
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* @private
|
||
|
* Update the tab icon when panel glyph has been set or changed.
|
||
|
*/
|
||
|
onItemGlyphChange: function(item, newGlyph) {
|
||
|
item.tab.setGlyph(newGlyph);
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* @private
|
||
|
* Update the tab icon when panel icon has been set or changed.
|
||
|
*/
|
||
|
onItemIconChange: function(item, newIcon) {
|
||
|
item.tab.setIcon(newIcon);
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* @private
|
||
|
* Update the tab iconCls when panel iconCls has been set or changed.
|
||
|
*/
|
||
|
onItemIconClsChange: function(item, newIconCls) {
|
||
|
item.tab.setIconCls(newIconCls);
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* @private
|
||
|
* Update the tab title when panel title has been set or changed.
|
||
|
*/
|
||
|
onItemTitleChange: function(item, newTitle) {
|
||
|
item.tab.setText(newTitle);
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* @private
|
||
|
* Makes sure we remove the corresponding Tab when an item is removed
|
||
|
*/
|
||
|
onRemove: function(item, destroying) {
|
||
|
var me = this;
|
||
|
|
||
|
item.un({
|
||
|
scope : me,
|
||
|
enable: me.onItemEnable,
|
||
|
disable: me.onItemDisable,
|
||
|
beforeshow: me.onItemBeforeShow,
|
||
|
iconchange: me.onItemIconChange,
|
||
|
iconclschange: me.onItemIconClsChange,
|
||
|
glyphchange: me.onItemGlyphChange,
|
||
|
titlechange: me.onItemTitleChange
|
||
|
});
|
||
|
if (item.tab && !me.destroying && item.tab.ownerCt === me.tabBar) {
|
||
|
me.tabBar.remove(item.tab);
|
||
|
}
|
||
|
},
|
||
|
|
||
|
privates: {
|
||
|
/**
|
||
|
* @private
|
||
|
* Unlink the removed child item from its (@link Ext.tab.Tab Tab}.
|
||
|
*
|
||
|
* If we're removing the currently active tab, activate the nearest one. The item is removed when we call super,
|
||
|
* so we can do preprocessing before then to find the card's index
|
||
|
*/
|
||
|
doRemove: function (item, autoDestroy) {
|
||
|
var me = this,
|
||
|
toActivate;
|
||
|
|
||
|
// Destroying, or removing the last item, nothing to activate
|
||
|
if (me.removingAll || me.destroying || me.items.getCount() === 1) {
|
||
|
me.activeTab = null;
|
||
|
}
|
||
|
|
||
|
// Ask the TabBar which tab to activate next.
|
||
|
// Set the active child panel using the index of that tab
|
||
|
else if (item.tab && (toActivate = me.tabBar.items.indexOf(me.tabBar.findNextActivatable(item.tab))) !== -1) {
|
||
|
me.setActiveTab(toActivate);
|
||
|
}
|
||
|
this.callParent(arguments);
|
||
|
|
||
|
if (item.tab) {
|
||
|
// Remove the two references
|
||
|
delete item.tab.card;
|
||
|
delete item.tab;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
});
|