Upgrade to ExtJS 3.0.0 - Released 07/06/2009
[extjs.git] / source / widgets / TabPanel.js
diff --git a/source/widgets/TabPanel.js b/source/widgets/TabPanel.js
deleted file mode 100644 (file)
index a51be00..0000000
+++ /dev/null
@@ -1,1035 +0,0 @@
-/*\r
- * Ext JS Library 2.2.1\r
- * Copyright(c) 2006-2009, Ext JS, LLC.\r
- * licensing@extjs.com\r
- * \r
- * http://extjs.com/license\r
- */\r
-\r
-/**\r
- * @class Ext.TabPanel\r
- * <p>A basic tab container. TabPanels can be used exactly like a standard {@link Ext.Panel} for layout\r
- * purposes, but also have special support for containing child Components that are managed using a CardLayout\r
- * layout manager, and displayed as seperate tabs.</p>\r
- * <p>There is no actual tab class &mdash; each tab is simply an {@link Ext.BoxComponent Component} such\r
- * as a {@link Ext.Panel Panel}. However, when rendered in a TabPanel, each child Component can fire\r
- * additional events that only exist for tabs and are not available from other Component. These are:</p>\r
- * <ul>\r
- * <li><b>activate</b>: Fires when this Component becomes the active tab.\r
- * <div class="mdetail-params">\r
- *      <strong style="font-weight: normal;">Listeners will be called with the following arguments:</strong>\r
- *      <ul><li><code>tab</code> : Panel<div class="sub-desc">The tab that was activated</div></li></ul>\r
- *  </div></li>\r
- * <li><b>deactivate</b>: Fires when the Component that was the active tab becomes deactivated.\r
- * <div class="mdetail-params">\r
- *      <strong style="font-weight: normal;">Listeners will be called with the following arguments:</strong>\r
- *      <ul><li><code>tab</code> : Panel<div class="sub-desc">The tab that was deactivated</div></li></ul>\r
- *  </div></li>\r
- * </ul>\r
- * <p>To add Components to a TabPanel which are generated dynamically on the server, it is necessary to\r
- * create a server script to generate the Javascript to create the Component required.</p>\r
- * For example, to add a GridPanel to a TabPanel where the GridPanel is generated by the server\r
- * based on certain parameters, you would need to execute an Ajax request to invoke your the script,\r
- * and process the response object to add it to the TabPanel:</p><pre><code>\r
-Ext.Ajax.request({\r
-    url: 'gen-invoice-grid.php',\r
-    params: {\r
-        startDate = Ext.getCmp('start-date').getValue(),\r
-        endDate = Ext.getCmp('end-date').getValue()\r
-    },\r
-    success: function(xhr) {\r
-        var newComponent = eval(xhr.responseText);\r
-        myTabPanel.add(newComponent);\r
-        myTabPanel.setActiveTab(newComponent);\r
-    },\r
-    failure: function() {\r
-        Ext.Msg.alert("Grid create failed", "Server communication failure");\r
-    }\r
-});\r
-</code></pre>\r
- * <p>The server script would need to return an executable Javascript statement which, when processed\r
- * using <tt>eval()</tt> will return either a config object with an {@link Ext.Component#xtype xtype},\r
- * or an instantiated Component. For example:</p><pre><code>\r
-(function() {\r
-    function formatDate(value){\r
-        return value ? value.dateFormat('M d, Y') : '';\r
-    };\r
-\r
-    var store = new Ext.data.Store({\r
-        url: 'get-invoice-data.php',\r
-        baseParams: {\r
-            startDate: '01/01/2008',\r
-            endDate: '01/31/2008'\r
-        },\r
-        reader: new Ext.data.JsonReader({\r
-            record: 'transaction',\r
-            id: 'id',\r
-            totalRecords: 'total'\r
-        }, [\r
-           'customer',\r
-           'invNo',\r
-           {name: 'date', type: 'date', dateFormat: 'm/d/Y'},\r
-           {name: 'value', type: 'float'}\r
-        ])\r
-    });\r
-\r
-    var grid = new Ext.grid.GridPanel({\r
-        title: 'Invoice Report',\r
-        bbar: new Ext.PagingToolbar(store),\r
-        store: store,\r
-        columns: [\r
-            {header: "Customer", width: 250, dataIndex: 'customer', sortable: true},\r
-            {header: "Invoice Number", width: 120, dataIndex: 'invNo', sortable: true},\r
-            {header: "Invoice Date", width: 100, dataIndex: 'date', renderer: formatDate, sortable: true},\r
-            {header: "Value", width: 120, dataIndex: 'value', renderer: 'usMoney', sortable: true}\r
-        ],\r
-    });\r
-    store.load();\r
-    return grid;\r
-})();\r
-</code></pre>\r
- * <p>Since that code is <i>generated</i> by a server script, the <tt>baseParams</tt> for the Store\r
- * can be configured into the Store. The metadata to allow generation of the Record layout, and the\r
- * ColumnModel is also known on the server, so these can be generated into the code.</p>\r
- * <p>When that code fragment is passed through the <tt>eval</tt> function in the success handler\r
- * of the Ajax request, the code is executed by the Javascript processor, and the anonymous function\r
- * runs, and returns the grid.</p>\r
- * <p>There are several other methods available for creating TabPanels. The output of the following\r
- * examples should produce exactly the same appearance. The tabs can be created and rendered completely\r
- * in code, as in this example:</p>\r
- * <pre><code>\r
-var tabs = new Ext.TabPanel({\r
-    renderTo: Ext.getBody(),\r
-    activeTab: 0,\r
-    items: [{\r
-        title: 'Tab 1',\r
-        html: 'A simple tab'\r
-    },{\r
-        title: 'Tab 2',\r
-        html: 'Another one'\r
-    }]\r
-});\r
-</code></pre>\r
-  * <p>TabPanels can also be rendered from pre-existing markup in a couple of ways.  See the {@link #autoTabs} example for\r
-  * rendering entirely from markup that is already structured correctly as a TabPanel (a container div with\r
-  * one or more nested tab divs with class 'x-tab'). You can also render from markup that is not strictly\r
-  * structured by simply specifying by id which elements should be the container and the tabs. Using this method,\r
-  * tab content can be pulled from different elements within the page by id regardless of page structure.  Note\r
-  * that the tab divs in this example contain the class 'x-hide-display' so that they can be rendered deferred\r
-  * without displaying outside the tabs. You could alternately set {@link #deferredRender} to false to render all\r
-  * content tabs on page load. For example:\r
-  * <pre><code>\r
-var tabs = new Ext.TabPanel({\r
-    renderTo: 'my-tabs',\r
-    activeTab: 0,\r
-    items:[\r
-        {contentEl:'tab1', title:'Tab 1'},\r
-        {contentEl:'tab2', title:'Tab 2'}\r
-    ]\r
-});\r
-\r
-// Note that the tabs do not have to be nested within the container (although they can be)\r
-&lt;div id="my-tabs">&lt;/div>\r
-&lt;div id="tab1" class="x-hide-display">A simple tab&lt;/div>\r
-&lt;div id="tab2" class="x-hide-display">Another one&lt;/div>\r
-</code></pre>\r
- * @extends Ext.Panel\r
- * @constructor\r
- * @param {Object} config The configuration options\r
- */\r
-Ext.TabPanel = Ext.extend(Ext.Panel,  {\r
-    /**\r
-     * @cfg {Boolean} layoutOnTabChange Set to true to do a layout of tab items as tabs are changed.\r
-     */\r
-    /**\r
-     * @cfg {String} tabCls <b>This config option is used on <u>child Components</u> of ths TabPanel.</b> A CSS\r
-     * class name applied to the tab strip item representing the child Component, allowing special\r
-     * styling to be applied.\r
-     */\r
-    /**\r
-     * @cfg {Boolean} monitorResize True to automatically monitor window resize events and rerender the layout on\r
-     * browser resize (defaults to true).\r
-     */\r
-    monitorResize : true,\r
-    /**\r
-     * @cfg {Boolean} deferredRender Internally, the TabPanel uses a {@link Ext.layout.CardLayout} to manage its tabs.\r
-     * This property will be passed on to the layout as its {@link Ext.layout.CardLayout#deferredRender} config value,\r
-     * determining whether or not each tab is rendered only when first accessed (defaults to true).\r
-     * <p>Be aware that leaving deferredRender as <b><tt>true</tt></b> means that, if the TabPanel is within\r
-     * a {@link Ext.form.FormPanel form}, then until a tab is activated, any Fields within that tab will not\r
-     * be rendered, and will therefore not be submitted and will not be available to either\r
-     * {@link Ext.form.BasicForm#getValues getValues} or {@link Ext.form.BasicForm#setValues setValues}.</p>\r
-     */\r
-    deferredRender : true,\r
-    /**\r
-     * @cfg {Number} tabWidth The initial width in pixels of each new tab (defaults to 120).\r
-     */\r
-    tabWidth: 120,\r
-    /**\r
-     * @cfg {Number} minTabWidth The minimum width in pixels for each tab when {@link #resizeTabs} = true (defaults to 30).\r
-     */\r
-    minTabWidth: 30,\r
-    /**\r
-     * @cfg {Boolean} resizeTabs True to automatically resize each tab so that the tabs will completely fill the\r
-     * tab strip (defaults to false).  Setting this to true may cause specific widths that might be set per tab to\r
-     * be overridden in order to fit them all into view (although {@link #minTabWidth} will always be honored).\r
-     */\r
-    resizeTabs:false,\r
-    /**\r
-     * @cfg {Boolean} enableTabScroll True to enable scrolling to tabs that may be invisible due to overflowing the\r
-     * overall TabPanel width. Only available with tabPosition:'top' (defaults to false).\r
-     */\r
-    enableTabScroll: false,\r
-    /**\r
-     * @cfg {Number} scrollIncrement The number of pixels to scroll each time a tab scroll button is pressed (defaults\r
-     * to 100, or if {@link #resizeTabs} = true, the calculated tab width).  Only applies when {@link #enableTabScroll} = true.\r
-     */\r
-    scrollIncrement : 0,\r
-    /**\r
-     * @cfg {Number} scrollRepeatInterval Number of milliseconds between each scroll while a tab scroll button is\r
-     * continuously pressed (defaults to 400).\r
-     */\r
-    scrollRepeatInterval : 400,\r
-    /**\r
-     * @cfg {Float} scrollDuration The number of milliseconds that each scroll animation should last (defaults to .35).\r
-     * Only applies when {@link #animScroll} = true.\r
-     */\r
-    scrollDuration : .35,\r
-    /**\r
-     * @cfg {Boolean} animScroll True to animate tab scrolling so that hidden tabs slide smoothly into view (defaults\r
-     * to true).  Only applies when {@link #enableTabScroll} = true.\r
-     */\r
-    animScroll : true,\r
-    /**\r
-     * @cfg {String} tabPosition The position where the tab strip should be rendered (defaults to 'top').  The only\r
-     * other supported value is 'bottom'.  Note that tab scrolling is only supported for position 'top'.\r
-     */\r
-    tabPosition: 'top',\r
-    /**\r
-     * @cfg {String} baseCls The base CSS class applied to the panel (defaults to 'x-tab-panel').\r
-     */\r
-    baseCls: 'x-tab-panel',\r
-    /**\r
-     * @cfg {Boolean} autoTabs\r
-     * <p>True to query the DOM for any divs with a class of 'x-tab' to be automatically converted\r
-     * to tabs and added to this panel (defaults to false).  Note that the query will be executed within the scope of\r
-     * the container element only (so that multiple tab panels from markup can be supported via this method).</p>\r
-     * <p>This method is only possible when the markup is structured correctly as a container with nested\r
-     * divs containing the class 'x-tab'. To create TabPanels without these limitations, or to pull tab content from\r
-     * other elements on the page, see the example at the top of the class for generating tabs from markup.</p>\r
-     * <p>There are a couple of things to note when using this method:<ul>\r
-     * <li>When using the autoTabs config (as opposed to passing individual tab configs in the TabPanel's\r
-     * {@link #items} collection), you must use {@link #applyTo} to correctly use the specified id as the tab container.\r
-     * The autoTabs method <em>replaces</em> existing content with the TabPanel components.</li>\r
-     * <li>Make sure that you set {@link #deferredRender} to false so that the content elements for each tab will be\r
-     * rendered into the TabPanel immediately upon page load, otherwise they will not be transformed until each tab\r
-     * is activated and will be visible outside the TabPanel.</li>\r
-     * </ul>Example usage:</p>\r
-     * <pre><code>\r
-var tabs = new Ext.TabPanel({\r
-    applyTo: 'my-tabs',\r
-    activeTab: 0,\r
-    deferredRender: false,\r
-    autoTabs: true\r
-});\r
-\r
-// This markup will be converted to a TabPanel from the code above\r
-&lt;div id="my-tabs">\r
-    &lt;div class="x-tab" title="Tab 1">A simple tab&lt;/div>\r
-    &lt;div class="x-tab" title="Tab 2">Another one&lt;/div>\r
-&lt;/div>\r
-</code></pre>\r
-     */\r
-    autoTabs : false,\r
-    /**\r
-     * @cfg {String} autoTabSelector The CSS selector used to search for tabs in existing markup when {@link #autoTabs}\r
-     * = true (defaults to 'div.x-tab').  This can be any valid selector supported by {@link Ext.DomQuery#select}.\r
-     * Note that the query will be executed within the scope of this tab panel only (so that multiple tab panels from\r
-     * markup can be supported on a page).\r
-     */\r
-    autoTabSelector:'div.x-tab',\r
-    /**\r
-     * @cfg {String/Number} activeTab A string id or the numeric index of the tab that should be initially\r
-     * activated on render (defaults to none).\r
-     */\r
-    activeTab : null,\r
-    /**\r
-     * @cfg {Number} tabMargin The number of pixels of space to calculate into the sizing and scrolling of tabs. If you\r
-     * change the margin in CSS, you will need to update this value so calculations are correct with either resizeTabs\r
-     * or scrolling tabs. (defaults to 2)\r
-     */\r
-    tabMargin : 2,\r
-    /**\r
-     * @cfg {Boolean} plain True to render the tab strip without a background container image (defaults to false).\r
-     */\r
-    plain: false,\r
-    /**\r
-     * @cfg {Number} wheelIncrement For scrolling tabs, the number of pixels to increment on mouse wheel scrolling (defaults to 20).\r
-     */\r
-    wheelIncrement : 20,\r
-\r
-    /*\r
-     * This is a protected property used when concatenating tab ids to the TabPanel id for internal uniqueness.\r
-     * It does not generally need to be changed, but can be if external code also uses an id scheme that can\r
-     * potentially clash with this one.\r
-     */\r
-    idDelimiter : '__',\r
-\r
-    // private\r
-    itemCls : 'x-tab-item',\r
-\r
-    // private config overrides\r
-    elements: 'body',\r
-    headerAsText: false,\r
-    frame: false,\r
-    hideBorders:true,\r
-\r
-    // private\r
-    initComponent : function(){\r
-        this.frame = false;\r
-        Ext.TabPanel.superclass.initComponent.call(this);\r
-        this.addEvents(\r
-            /**\r
-             * @event beforetabchange\r
-             * Fires before the active tab changes. Handlers can return false to cancel the tab change.\r
-             * @param {TabPanel} this\r
-             * @param {Panel} newTab The tab being activated\r
-             * @param {Panel} currentTab The current active tab\r
-             */\r
-            'beforetabchange',\r
-            /**\r
-             * @event tabchange\r
-             * Fires after the active tab has changed.\r
-             * @param {TabPanel} this\r
-             * @param {Panel} tab The new active tab\r
-             */\r
-            'tabchange',\r
-            /**\r
-             * @event contextmenu\r
-             * Relays the contextmenu event from a tab selector element in the tab strip.\r
-             * @param {TabPanel} this\r
-             * @param {Panel} tab The target tab\r
-             * @param {EventObject} e\r
-             */\r
-            'contextmenu'\r
-        );\r
-        this.setLayout(new Ext.layout.CardLayout({\r
-            deferredRender: this.deferredRender\r
-        }));\r
-        if(this.tabPosition == 'top'){\r
-            this.elements += ',header';\r
-            this.stripTarget = 'header';\r
-        }else {\r
-            this.elements += ',footer';\r
-            this.stripTarget = 'footer';\r
-        }\r
-        if(!this.stack){\r
-            this.stack = Ext.TabPanel.AccessStack();\r
-        }\r
-        this.initItems();\r
-    },\r
-\r
-    // private\r
-    render : function(){\r
-        Ext.TabPanel.superclass.render.apply(this, arguments);\r
-        if(this.activeTab !== undefined){\r
-            var item = this.activeTab;\r
-            delete this.activeTab;\r
-            this.setActiveTab(item);\r
-        }\r
-    },\r
-\r
-    // private\r
-    onRender : function(ct, position){\r
-        Ext.TabPanel.superclass.onRender.call(this, ct, position);\r
-\r
-        if(this.plain){\r
-            var pos = this.tabPosition == 'top' ? 'header' : 'footer';\r
-            this[pos].addClass('x-tab-panel-'+pos+'-plain');\r
-        }\r
-\r
-        var st = this[this.stripTarget];\r
-\r
-        this.stripWrap = st.createChild({cls:'x-tab-strip-wrap', cn:{\r
-            tag:'ul', cls:'x-tab-strip x-tab-strip-'+this.tabPosition}});\r
-\r
-        var beforeEl = (this.tabPosition=='bottom' ? this.stripWrap : null);\r
-        this.stripSpacer = st.createChild({cls:'x-tab-strip-spacer'}, beforeEl);\r
-        this.strip = new Ext.Element(this.stripWrap.dom.firstChild);\r
-\r
-        this.edge = this.strip.createChild({tag:'li', cls:'x-tab-edge'});\r
-        this.strip.createChild({cls:'x-clear'});\r
-\r
-        this.body.addClass('x-tab-panel-body-'+this.tabPosition);\r
-\r
-        if(!this.itemTpl){\r
-            var tt = new Ext.Template(\r
-                 '<li class="{cls}" id="{id}"><a class="x-tab-strip-close" onclick="return false;"></a>',\r
-                 '<a class="x-tab-right" href="#" onclick="return false;"><em class="x-tab-left">',\r
-                 '<span class="x-tab-strip-inner"><span class="x-tab-strip-text {iconCls}">{text}</span></span>',\r
-                 '</em></a></li>'\r
-            );\r
-            tt.disableFormats = true;\r
-            tt.compile();\r
-            Ext.TabPanel.prototype.itemTpl = tt;\r
-        }\r
-\r
-        this.items.each(this.initTab, this);\r
-    },\r
-\r
-    // private\r
-    afterRender : function(){\r
-        Ext.TabPanel.superclass.afterRender.call(this);\r
-        if(this.autoTabs){\r
-            this.readTabs(false);\r
-        }\r
-    },\r
-\r
-    // private\r
-    initEvents : function(){\r
-        Ext.TabPanel.superclass.initEvents.call(this);\r
-        this.on('add', this.onAdd, this);\r
-        this.on('remove', this.onRemove, this);\r
-\r
-        this.strip.on('mousedown', this.onStripMouseDown, this);\r
-        this.strip.on('contextmenu', this.onStripContextMenu, this);\r
-        if(this.enableTabScroll){\r
-            this.strip.on('mousewheel', this.onWheel, this);\r
-        }\r
-    },\r
-\r
-    // private\r
-    findTargets : function(e){\r
-        var item = null;\r
-        var itemEl = e.getTarget('li', this.strip);\r
-        if(itemEl){\r
-            item = this.getComponent(itemEl.id.split(this.idDelimiter)[1]);\r
-            if(item.disabled){\r
-                return {\r
-                    close : null,\r
-                    item : null,\r
-                    el : null\r
-                };\r
-            }\r
-        }\r
-        return {\r
-            close : e.getTarget('.x-tab-strip-close', this.strip),\r
-            item : item,\r
-            el : itemEl\r
-        };\r
-    },\r
-\r
-    // private\r
-    onStripMouseDown : function(e){\r
-        if(e.button != 0){\r
-            return;\r
-        }\r
-        e.preventDefault();\r
-        var t = this.findTargets(e);\r
-        if(t.close){\r
-            this.remove(t.item);\r
-            return;\r
-        }\r
-        if(t.item && t.item != this.activeTab){\r
-            this.setActiveTab(t.item);\r
-        }\r
-    },\r
-\r
-    // private\r
-    onStripContextMenu : function(e){\r
-        e.preventDefault();\r
-        var t = this.findTargets(e);\r
-        if(t.item){\r
-            this.fireEvent('contextmenu', this, t.item, e);\r
-        }\r
-    },\r
-\r
-    /**\r
-     * True to scan the markup in this tab panel for autoTabs using the autoTabSelector\r
-     * @param {Boolean} removeExisting True to remove existing tabs\r
-     */\r
-    readTabs : function(removeExisting){\r
-        if(removeExisting === true){\r
-            this.items.each(function(item){\r
-                this.remove(item);\r
-            }, this);\r
-        }\r
-        var tabs = this.el.query(this.autoTabSelector);\r
-        for(var i = 0, len = tabs.length; i < len; i++){\r
-            var tab = tabs[i];\r
-            var title = tab.getAttribute('title');\r
-            tab.removeAttribute('title');\r
-            this.add({\r
-                title: title,\r
-                el: tab\r
-            });\r
-        }\r
-    },\r
-\r
-    // private\r
-    initTab : function(item, index){\r
-        var before = this.strip.dom.childNodes[index];\r
-        var cls = item.closable ? 'x-tab-strip-closable' : '';\r
-        if(item.disabled){\r
-            cls += ' x-item-disabled';\r
-        }\r
-        if(item.iconCls){\r
-            cls += ' x-tab-with-icon';\r
-        }\r
-        if(item.tabCls){\r
-            cls += ' ' + item.tabCls;\r
-        }\r
-\r
-        var p = {\r
-            id: this.id + this.idDelimiter + item.getItemId(),\r
-            text: item.title,\r
-            cls: cls,\r
-            iconCls: item.iconCls || ''\r
-        };\r
-        var el = before ?\r
-                 this.itemTpl.insertBefore(before, p) :\r
-                 this.itemTpl.append(this.strip, p);\r
-\r
-        Ext.fly(el).addClassOnOver('x-tab-strip-over');\r
-\r
-        if(item.tabTip){\r
-            Ext.fly(el).child('span.x-tab-strip-text', true).qtip = item.tabTip;\r
-        }\r
-        item.tabEl = el;\r
-\r
-        item.on('disable', this.onItemDisabled, this);\r
-        item.on('enable', this.onItemEnabled, this);\r
-        item.on('titlechange', this.onItemTitleChanged, this);\r
-        item.on('iconchange', this.onItemIconChanged, this);\r
-        item.on('beforeshow', this.onBeforeShowItem, this);\r
-    },\r
-\r
-    // private\r
-    onAdd : function(tp, item, index){\r
-        this.initTab(item, index);\r
-        if(this.items.getCount() == 1){\r
-            this.syncSize();\r
-        }\r
-        this.delegateUpdates();\r
-    },\r
-\r
-    // private\r
-    onBeforeAdd : function(item){\r
-        var existing = item.events ? (this.items.containsKey(item.getItemId()) ? item : null) : this.items.get(item);\r
-        if(existing){\r
-            this.setActiveTab(item);\r
-            return false;\r
-        }\r
-        Ext.TabPanel.superclass.onBeforeAdd.apply(this, arguments);\r
-        var es = item.elements;\r
-        item.elements = es ? es.replace(',header', '') : es;\r
-        item.border = (item.border === true);\r
-    },\r
-\r
-    // private\r
-    onRemove : function(tp, item){\r
-        Ext.destroy(Ext.get(this.getTabEl(item)));\r
-        this.stack.remove(item);\r
-        item.un('disable', this.onItemDisabled, this);\r
-        item.un('enable', this.onItemEnabled, this);\r
-        item.un('titlechange', this.onItemTitleChanged, this);\r
-        item.un('iconchange', this.onItemIconChanged, this);\r
-        item.un('beforeshow', this.onBeforeShowItem, this);\r
-        if(item == this.activeTab){\r
-            var next = this.stack.next();\r
-            if(next){\r
-                this.setActiveTab(next);\r
-            }else if(this.items.getCount() > 0){\r
-                this.setActiveTab(0);\r
-            }else{\r
-                this.activeTab = null;\r
-            }\r
-        }\r
-        this.delegateUpdates();\r
-    },\r
-\r
-    // private\r
-    onBeforeShowItem : function(item){\r
-        if(item != this.activeTab){\r
-            this.setActiveTab(item);\r
-            return false;\r
-        }\r
-    },\r
-\r
-    // private\r
-    onItemDisabled : function(item){\r
-        var el = this.getTabEl(item);\r
-        if(el){\r
-            Ext.fly(el).addClass('x-item-disabled');\r
-        }\r
-        this.stack.remove(item);\r
-    },\r
-\r
-    // private\r
-    onItemEnabled : function(item){\r
-        var el = this.getTabEl(item);\r
-        if(el){\r
-            Ext.fly(el).removeClass('x-item-disabled');\r
-        }\r
-    },\r
-\r
-    // private\r
-    onItemTitleChanged : function(item){\r
-        var el = this.getTabEl(item);\r
-        if(el){\r
-            Ext.fly(el).child('span.x-tab-strip-text', true).innerHTML = item.title;\r
-        }\r
-    },\r
-    \r
-    //private\r
-    onItemIconChanged: function(item, iconCls, oldCls){\r
-        var el = this.getTabEl(item);\r
-        if(el){\r
-            Ext.fly(el).child('span.x-tab-strip-text').replaceClass(oldCls, iconCls);\r
-        }\r
-    },\r
-\r
-    /**\r
-     * Gets the DOM element for tab strip item which activates the\r
-     * child panel with the specified ID. Access this to change the visual treatment of the\r
-     * item, for example by changing the CSS class name.\r
-     * @param {Panel/Number} tab The tab component, or the tab's index\r
-     * @return {HTMLElement} The DOM node\r
-     */\r
-    getTabEl : function(item){\r
-        var itemId = (typeof item === 'number')?this.items.items[item].getItemId() : item.getItemId();\r
-        return document.getElementById(this.id+this.idDelimiter+itemId);\r
-    },\r
-\r
-    // private\r
-    onResize : function(){\r
-        Ext.TabPanel.superclass.onResize.apply(this, arguments);\r
-        this.delegateUpdates();\r
-    },\r
-\r
-    /**\r
-     * Suspends any internal calculations or scrolling while doing a bulk operation. See {@link #endUpdate}\r
-     */\r
-    beginUpdate : function(){\r
-        this.suspendUpdates = true;\r
-    },\r
-\r
-    /**\r
-     * Resumes calculations and scrolling at the end of a bulk operation. See {@link #beginUpdate}\r
-     */\r
-    endUpdate : function(){\r
-        this.suspendUpdates = false;\r
-        this.delegateUpdates();\r
-    },\r
-\r
-    /**\r
-     * Hides the tab strip item for the passed tab\r
-     * @param {Number/String/Panel} item The tab index, id or item\r
-     */\r
-    hideTabStripItem : function(item){\r
-        item = this.getComponent(item);\r
-        var el = this.getTabEl(item);\r
-        if(el){\r
-            el.style.display = 'none';\r
-            this.delegateUpdates();\r
-        }\r
-        this.stack.remove(item);\r
-    },\r
-\r
-    /**\r
-     * Unhides the tab strip item for the passed tab\r
-     * @param {Number/String/Panel} item The tab index, id or item\r
-     */\r
-    unhideTabStripItem : function(item){\r
-        item = this.getComponent(item);\r
-        var el = this.getTabEl(item);\r
-        if(el){\r
-            el.style.display = '';\r
-            this.delegateUpdates();\r
-        }\r
-    },\r
-\r
-    // private\r
-    delegateUpdates : function(){\r
-        if(this.suspendUpdates){\r
-            return;\r
-        }\r
-        if(this.resizeTabs && this.rendered){\r
-            this.autoSizeTabs();\r
-        }\r
-        if(this.enableTabScroll && this.rendered){\r
-            this.autoScrollTabs();\r
-        }\r
-    },\r
-\r
-    // private\r
-    autoSizeTabs : function(){\r
-        var count = this.items.length;\r
-        var ce = this.tabPosition != 'bottom' ? 'header' : 'footer';\r
-        var ow = this[ce].dom.offsetWidth;\r
-        var aw = this[ce].dom.clientWidth;\r
-\r
-        if(!this.resizeTabs || count < 1 || !aw){ // !aw for display:none\r
-            return;\r
-        }\r
-\r
-        var each = Math.max(Math.min(Math.floor((aw-4) / count) - this.tabMargin, this.tabWidth), this.minTabWidth); // -4 for float errors in IE\r
-        this.lastTabWidth = each;\r
-        var lis = this.stripWrap.dom.getElementsByTagName('li');\r
-        for(var i = 0, len = lis.length-1; i < len; i++) { // -1 for the "edge" li\r
-            var li = lis[i];\r
-            var inner = li.childNodes[1].firstChild.firstChild;\r
-            var tw = li.offsetWidth;\r
-            var iw = inner.offsetWidth;\r
-            inner.style.width = (each - (tw-iw)) + 'px';\r
-        }\r
-    },\r
-\r
-    // private\r
-    adjustBodyWidth : function(w){\r
-        if(this.header){\r
-            this.header.setWidth(w);\r
-        }\r
-        if(this.footer){\r
-            this.footer.setWidth(w);\r
-        }\r
-        return w;\r
-    },\r
-\r
-    /**\r
-     * Sets the specified tab as the active tab. This method fires the {@link #beforetabchange} event which\r
-     * can return false to cancel the tab change.\r
-     * @param {String/Panel} tab The id or tab Panel to activate\r
-     */\r
-    setActiveTab : function(item){\r
-        item = this.getComponent(item);\r
-        if(!item || this.fireEvent('beforetabchange', this, item, this.activeTab) === false){\r
-            return;\r
-        }\r
-        if(!this.rendered){\r
-            this.activeTab = item;\r
-            return;\r
-        }\r
-        if(this.activeTab != item){\r
-            if(this.activeTab){\r
-                var oldEl = this.getTabEl(this.activeTab);\r
-                if(oldEl){\r
-                    Ext.fly(oldEl).removeClass('x-tab-strip-active');\r
-                }\r
-                this.activeTab.fireEvent('deactivate', this.activeTab);\r
-            }\r
-            var el = this.getTabEl(item);\r
-            Ext.fly(el).addClass('x-tab-strip-active');\r
-            this.activeTab = item;\r
-            this.stack.add(item);\r
-\r
-            this.layout.setActiveItem(item);\r
-            if(this.layoutOnTabChange && item.doLayout){\r
-                item.doLayout();\r
-            }\r
-            if(this.scrolling){\r
-                this.scrollToTab(item, this.animScroll);\r
-            }\r
-\r
-            item.fireEvent('activate', item);\r
-            this.fireEvent('tabchange', this, item);\r
-        }\r
-    },\r
-\r
-    /**\r
-     * Gets the currently active tab.\r
-     * @return {Panel} The active tab\r
-     */\r
-    getActiveTab : function(){\r
-        return this.activeTab || null;\r
-    },\r
-\r
-    /**\r
-     * Gets the specified tab by id.\r
-     * @param {String} id The tab id\r
-     * @return {Panel} The tab\r
-     */\r
-    getItem : function(item){\r
-        return this.getComponent(item);\r
-    },\r
-\r
-    // private\r
-    autoScrollTabs : function(){\r
-        this.pos = this.tabPosition=='bottom' ? this.footer : this.header;\r
-        var count = this.items.length;\r
-        var ow = this.pos.dom.offsetWidth;\r
-        var tw = this.pos.dom.clientWidth;\r
-\r
-        var wrap = this.stripWrap;\r
-        var wd = wrap.dom;\r
-        var cw = wd.offsetWidth;\r
-        var pos = this.getScrollPos();\r
-        var l = this.edge.getOffsetsTo(this.stripWrap)[0] + pos;\r
-\r
-        if(!this.enableTabScroll || count < 1 || cw < 20){ // 20 to prevent display:none issues\r
-            return;\r
-        }\r
-        if(l <= tw){\r
-            wd.scrollLeft = 0;\r
-            wrap.setWidth(tw);\r
-            if(this.scrolling){\r
-                this.scrolling = false;\r
-                this.pos.removeClass('x-tab-scrolling');\r
-                this.scrollLeft.hide();\r
-                this.scrollRight.hide();\r
-                if(Ext.isAir || Ext.isSafari){\r
-                    wd.style.marginLeft = '';\r
-                    wd.style.marginRight = '';\r
-                }\r
-            }\r
-        }else{\r
-            if(!this.scrolling){\r
-                this.pos.addClass('x-tab-scrolling');\r
-                if(Ext.isAir || Ext.isSafari){\r
-                    wd.style.marginLeft = '18px';\r
-                    wd.style.marginRight = '18px';\r
-                }\r
-            }\r
-            tw -= wrap.getMargins('lr');\r
-            wrap.setWidth(tw > 20 ? tw : 20);\r
-            if(!this.scrolling){\r
-                if(!this.scrollLeft){\r
-                    this.createScrollers();\r
-                }else{\r
-                    this.scrollLeft.show();\r
-                    this.scrollRight.show();\r
-                }\r
-            }\r
-            this.scrolling = true;\r
-            if(pos > (l-tw)){ // ensure it stays within bounds\r
-                wd.scrollLeft = l-tw;\r
-            }else{ // otherwise, make sure the active tab is still visible\r
-                this.scrollToTab(this.activeTab, false);\r
-            }\r
-            this.updateScrollButtons();\r
-        }\r
-    },\r
-\r
-    // private\r
-    createScrollers : function(){\r
-        this.pos.addClass('x-tab-scrolling-' + this.tabPosition);\r
-        var h = this.stripWrap.dom.offsetHeight;\r
-\r
-        // left\r
-        var sl = this.pos.insertFirst({\r
-            cls:'x-tab-scroller-left'\r
-        });\r
-        sl.setHeight(h);\r
-        sl.addClassOnOver('x-tab-scroller-left-over');\r
-        this.leftRepeater = new Ext.util.ClickRepeater(sl, {\r
-            interval : this.scrollRepeatInterval,\r
-            handler: this.onScrollLeft,\r
-            scope: this\r
-        });\r
-        this.scrollLeft = sl;\r
-\r
-        // right\r
-        var sr = this.pos.insertFirst({\r
-            cls:'x-tab-scroller-right'\r
-        });\r
-        sr.setHeight(h);\r
-        sr.addClassOnOver('x-tab-scroller-right-over');\r
-        this.rightRepeater = new Ext.util.ClickRepeater(sr, {\r
-            interval : this.scrollRepeatInterval,\r
-            handler: this.onScrollRight,\r
-            scope: this\r
-        });\r
-        this.scrollRight = sr;\r
-    },\r
-\r
-    // private\r
-    getScrollWidth : function(){\r
-        return this.edge.getOffsetsTo(this.stripWrap)[0] + this.getScrollPos();\r
-    },\r
-\r
-    // private\r
-    getScrollPos : function(){\r
-        return parseInt(this.stripWrap.dom.scrollLeft, 10) || 0;\r
-    },\r
-\r
-    // private\r
-    getScrollArea : function(){\r
-        return parseInt(this.stripWrap.dom.clientWidth, 10) || 0;\r
-    },\r
-\r
-    // private\r
-    getScrollAnim : function(){\r
-        return {duration:this.scrollDuration, callback: this.updateScrollButtons, scope: this};\r
-    },\r
-\r
-    // private\r
-    getScrollIncrement : function(){\r
-        return this.scrollIncrement || (this.resizeTabs ? this.lastTabWidth+2 : 100);\r
-    },\r
-\r
-    /**\r
-     * Scrolls to a particular tab if tab scrolling is enabled\r
-     * @param {Panel} item The item to scroll to\r
-     * @param {Boolean} animate True to enable animations\r
-     */\r
-\r
-    scrollToTab : function(item, animate){\r
-        if(!item){ return; }\r
-        var el = this.getTabEl(item);\r
-        var pos = this.getScrollPos(), area = this.getScrollArea();\r
-        var left = Ext.fly(el).getOffsetsTo(this.stripWrap)[0] + pos;\r
-        var right = left + el.offsetWidth;\r
-        if(left < pos){\r
-            this.scrollTo(left, animate);\r
-        }else if(right > (pos + area)){\r
-            this.scrollTo(right - area, animate);\r
-        }\r
-    },\r
-\r
-    // private\r
-    scrollTo : function(pos, animate){\r
-        this.stripWrap.scrollTo('left', pos, animate ? this.getScrollAnim() : false);\r
-        if(!animate){\r
-            this.updateScrollButtons();\r
-        }\r
-    },\r
-\r
-    onWheel : function(e){\r
-        var d = e.getWheelDelta()*this.wheelIncrement*-1;\r
-        e.stopEvent();\r
-\r
-        var pos = this.getScrollPos();\r
-        var newpos = pos + d;\r
-        var sw = this.getScrollWidth()-this.getScrollArea();\r
-\r
-        var s = Math.max(0, Math.min(sw, newpos));\r
-        if(s != pos){\r
-            this.scrollTo(s, false);\r
-        }\r
-    },\r
-\r
-    // private\r
-    onScrollRight : function(){\r
-        var sw = this.getScrollWidth()-this.getScrollArea();\r
-        var pos = this.getScrollPos();\r
-        var s = Math.min(sw, pos + this.getScrollIncrement());\r
-        if(s != pos){\r
-            this.scrollTo(s, this.animScroll);\r
-        }\r
-    },\r
-\r
-    // private\r
-    onScrollLeft : function(){\r
-        var pos = this.getScrollPos();\r
-        var s = Math.max(0, pos - this.getScrollIncrement());\r
-        if(s != pos){\r
-            this.scrollTo(s, this.animScroll);\r
-        }\r
-    },\r
-\r
-    // private\r
-    updateScrollButtons : function(){\r
-        var pos = this.getScrollPos();\r
-        this.scrollLeft[pos == 0 ? 'addClass' : 'removeClass']('x-tab-scroller-left-disabled');\r
-        this.scrollRight[pos >= (this.getScrollWidth()-this.getScrollArea()) ? 'addClass' : 'removeClass']('x-tab-scroller-right-disabled');\r
-    },\r
-\r
-    // private\r
-    beforeDestroy : function() {\r
-        if(this.items){\r
-            this.items.each(function(item){\r
-                if(item && item.tabEl){\r
-                    Ext.get(item.tabEl).removeAllListeners();\r
-                    item.tabEl = null;\r
-                }\r
-            }, this);\r
-        }\r
-        if(this.strip){\r
-            this.strip.removeAllListeners();\r
-        }\r
-        Ext.TabPanel.superclass.beforeDestroy.apply(this);\r
-    }\r
-\r
-    /**\r
-     * @cfg {Boolean} collapsible\r
-     * @hide\r
-     */\r
-    /**\r
-     * @cfg {String} header\r
-     * @hide\r
-     */\r
-    /**\r
-     * @cfg {Boolean} headerAsText\r
-     * @hide\r
-     */\r
-    /**\r
-     * @property header\r
-     * @hide\r
-     */\r
-    /**\r
-     * @property title\r
-     * @hide\r
-     */\r
-    /**\r
-     * @cfg {Array} tools\r
-     * @hide\r
-     */\r
-    /**\r
-     * @cfg {Boolean} hideCollapseTool\r
-     * @hide\r
-     */\r
-    /**\r
-     * @cfg {Boolean} titleCollapse\r
-     * @hide\r
-     */\r
-    /**\r
-     * @cfg {Boolean} collapsed\r
-     * @hide\r
-     */\r
-    /**\r
-     * @cfg {String} layout\r
-     * @hide\r
-     */\r
-    /**\r
-     * @cfg {Object} layoutConfig\r
-     * @hide\r
-     */\r
-\r
-});\r
-Ext.reg('tabpanel', Ext.TabPanel);\r
-\r
-/**\r
- * Sets the specified tab as the active tab. This method fires the {@link #beforetabchange} event which\r
- * can return false to cancel the tab change.\r
- * @param {String/Panel} tab The id or tab Panel to activate\r
- * @method activate\r
- */\r
-Ext.TabPanel.prototype.activate = Ext.TabPanel.prototype.setActiveTab;\r
-\r
-// private utility class used by TabPanel\r
-Ext.TabPanel.AccessStack = function(){\r
-    var items = [];\r
-    return {\r
-        add : function(item){\r
-            items.push(item);\r
-            if(items.length > 10){\r
-                items.shift();\r
-            }\r
-        },\r
-\r
-        remove : function(item){\r
-            var s = [];\r
-            for(var i = 0, len = items.length; i < len; i++) {\r
-                if(items[i] != item){\r
-                    s.push(items[i]);\r
-                }\r
-            }\r
-            items = s;\r
-        },\r
-\r
-        next : function(){\r
-            return items.pop();\r
-        }\r
-    };\r
-};\r
-\r