+++ /dev/null
-/*\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 — 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
-<div id="my-tabs"></div>\r
-<div id="tab1" class="x-hide-display">A simple tab</div>\r
-<div id="tab2" class="x-hide-display">Another one</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
-<div id="my-tabs">\r
- <div class="x-tab" title="Tab 1">A simple tab</div>\r
- <div class="x-tab" title="Tab 2">Another one</div>\r
-</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