<html>\r
<head>\r
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> \r
<title>The source code</title>\r
<link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />\r
<script type="text/javascript" src="../resources/prettify/prettify.js"></script>\r
* the active tab.</li>
* <li><tt><b>{@link Ext.Panel#deactivate deactivate}</b></tt> : Fires when the Component that
* was the active tab becomes deactivated.</li>
+ * <li><tt><b>{@link Ext.Panel#beforeclose beforeclose}</b></tt> : Fires when the user clicks on the close tool of a closeable tab.
+ * May be vetoed by returning <code>false</code> from a handler.</li>
+ * <li><tt><b>{@link Ext.Panel#close close}</b></tt> : Fires a closeable tab has been closed by the user.</li>
* </ul></div>
* <p><b><u>Creating TabPanels from Code</u></b></p>
* <p>TabPanels can be created and rendered completely in code, as in this example:</p>
* class name applied to the tab strip item representing the child Component, allowing special
* styling to be applied.
*/
- <div id="cfg-Ext.TabPanel-monitorResize"></div>/**
- * @cfg {Boolean} monitorResize True to automatically monitor window resize events and rerender the layout on
- * browser resize (defaults to true).
- */
- monitorResize : true,
<div id="cfg-Ext.TabPanel-deferredRender"></div>/**
* @cfg {Boolean} deferredRender
* <p><tt>true</tt> by default to defer the rendering of child <tt>{@link Ext.Container#items items}</tt>
autoTabSelector : 'div.x-tab',
<div id="cfg-Ext.TabPanel-activeTab"></div>/**
* @cfg {String/Number} activeTab A string id or the numeric index of the tab that should be initially
- * activated on render (defaults to none).
+ * activated on render (defaults to undefined).
*/
- activeTab : null,
+ activeTab : undefined,
<div id="cfg-Ext.TabPanel-tabMargin"></div>/**
* @cfg {Number} tabMargin The number of pixels of space to calculate into the sizing and scrolling of
* tabs. If you change the margin in CSS, you will need to update this value so calculations are correct
tag:'ul', cls:'x-tab-strip x-tab-strip-'+this.tabPosition}});
var beforeEl = (this.tabPosition=='bottom' ? this.stripWrap : null);
- this.stripSpacer = st.createChild({cls:'x-tab-strip-spacer'}, beforeEl);
+ st.createChild({cls:'x-tab-strip-spacer'}, beforeEl);
this.strip = new Ext.Element(this.stripWrap.dom.firstChild);
- this.edge = this.strip.createChild({tag:'li', cls:'x-tab-edge'});
+ // create an empty span with class x-tab-strip-text to force the height of the header element when there's no tabs.
+ this.edge = this.strip.createChild({tag:'li', cls:'x-tab-edge', cn: [{tag: 'span', cls: 'x-tab-strip-text', cn: ' '}]});
this.strip.createChild({cls:'x-clear'});
this.body.addClass('x-tab-panel-body-'+this.tabPosition);
itemTpl: new Ext.XTemplate(
'<li class="{cls}" id="{id}" style="overflow:hidden">',
'<tpl if="closable">',
- '<a class="x-tab-strip-close" onclick="return false;"></a>',
+ '<a class="x-tab-strip-close"></a>',
'</tpl>',
- '<a class="x-tab-right" href="#" onclick="return false;" style="padding-left:6px">',
+ '<a class="x-tab-right" href="#" style="padding-left:6px">',
'<em class="x-tab-left">',
'<span class="x-tab-strip-inner">',
'<img src="{src}" style="float:left;margin:3px 3px 0 0">',
*/
if(!this.itemTpl){
var tt = new Ext.Template(
- '<li class="{cls}" id="{id}"><a class="x-tab-strip-close" onclick="return false;"></a>',
- '<a class="x-tab-right" href="#" onclick="return false;"><em class="x-tab-left">',
+ '<li class="{cls}" id="{id}"><a class="x-tab-strip-close"></a>',
+ '<a class="x-tab-right" href="#"><em class="x-tab-left">',
'<span class="x-tab-strip-inner"><span class="x-tab-strip-text {iconCls}">{text}</span></span>',
'</em></a></li>'
);
// private
initEvents : function(){
Ext.TabPanel.superclass.initEvents.call(this);
- this.on('add', this.onAdd, this, {target: this});
- this.on('remove', this.onRemove, this, {target: this});
-
- this.mon(this.strip, 'mousedown', this.onStripMouseDown, this);
- this.mon(this.strip, 'contextmenu', this.onStripContextMenu, this);
+ this.mon(this.strip, {
+ scope: this,
+ mousedown: this.onStripMouseDown,
+ contextmenu: this.onStripContextMenu
+ });
if(this.enableTabScroll){
this.mon(this.strip, 'mousewheel', this.onWheel, this);
}
// private
findTargets : function(e){
- var item = null;
- var itemEl = e.getTarget('li', this.strip);
+ var item = null,
+ itemEl = e.getTarget('li:not(.x-tab-edge)', this.strip);
+
if(itemEl){
item = this.getComponent(itemEl.id.split(this.idDelimiter)[1]);
if(item.disabled){
}
var tabs = this.el.query(this.autoTabSelector);
for(var i = 0, len = tabs.length; i < len; i++){
- var tab = tabs[i];
- var title = tab.getAttribute('title');
+ var tab = tabs[i],
+ title = tab.getAttribute('title');
tab.removeAttribute('title');
this.add({
title: title,
// private
initTab : function(item, index){
- var before = this.strip.dom.childNodes[index];
- var p = this.getTemplateArgs(item);
- var el = before ?
+ var before = this.strip.dom.childNodes[index],
+ p = this.getTemplateArgs(item),
+ el = before ?
this.itemTpl.insertBefore(before, p) :
- this.itemTpl.append(this.strip, p);
+ this.itemTpl.append(this.strip, p),
+ cls = 'x-tab-strip-over',
+ tabEl = Ext.get(el);
- Ext.fly(el).addClassOnOver('x-tab-strip-over');
+ tabEl.hover(function(){
+ if(!item.disabled){
+ tabEl.addClass(cls);
+ }
+ }, function(){
+ tabEl.removeClass(cls);
+ });
if(item.tabTip){
- Ext.fly(el).child('span.x-tab-strip-text', true).qtip = item.tabTip;
+ tabEl.child('span.x-tab-strip-text', true).qtip = item.tabTip;
}
item.tabEl = el;
- item.on('disable', this.onItemDisabled, this);
- item.on('enable', this.onItemEnabled, this);
- item.on('titlechange', this.onItemTitleChanged, this);
- item.on('iconchange', this.onItemIconChanged, this);
- item.on('beforeshow', this.onBeforeShowItem, this);
+ // Route *keyboard triggered* click events to the tab strip mouse handler.
+ tabEl.select('a').on('click', function(e){
+ if(!e.getPageX()){
+ this.onStripMouseDown(e);
+ }
+ }, this, {preventDefault: true});
+
+ item.on({
+ scope: this,
+ disable: this.onItemDisabled,
+ enable: this.onItemEnabled,
+ titlechange: this.onItemTitleChanged,
+ iconchange: this.onItemIconChanged,
+ beforeshow: this.onBeforeShowItem
+ });
},
+
+
<div id="method-Ext.TabPanel-getTemplateArgs"></div>/**
* <p>Provides template arguments for rendering a tab selector item in the tab strip.</p>
* <p>This method returns an object hash containing properties used by the TabPanel's <tt>{@link #itemTpl}</tt>
},
// private
- onAdd : function(tp, item, index){
- this.initTab(item, index);
- if(this.items.getCount() == 1){
- this.syncSize();
+ onAdd : function(c){
+ Ext.TabPanel.superclass.onAdd.call(this, c);
+ if(this.rendered){
+ var items = this.items;
+ this.initTab(c, items.indexOf(c));
+ if(items.getCount() == 1){
+ this.syncSize();
+ }
+ this.delegateUpdates();
}
- this.delegateUpdates();
},
// private
},
// private
- onRemove : function(tp, item){
- Ext.destroy(Ext.get(this.getTabEl(item)));
- this.stack.remove(item);
- item.un('disable', this.onItemDisabled, this);
- item.un('enable', this.onItemEnabled, this);
- item.un('titlechange', this.onItemTitleChanged, this);
- item.un('iconchange', this.onItemIconChanged, this);
- item.un('beforeshow', this.onBeforeShowItem, this);
- if(item == this.activeTab){
+ onRemove : function(c){
+ var te = Ext.get(c.tabEl);
+ // check if the tabEl exists, it won't if the tab isn't rendered
+ if(te){
+ te.select('a').removeAllListeners();
+ Ext.destroy(te);
+ }
+ Ext.TabPanel.superclass.onRemove.call(this, c);
+ this.stack.remove(c);
+ delete c.tabEl;
+ c.un('disable', this.onItemDisabled, this);
+ c.un('enable', this.onItemEnabled, this);
+ c.un('titlechange', this.onItemTitleChanged, this);
+ c.un('iconchange', this.onItemIconChanged, this);
+ c.un('beforeshow', this.onBeforeShowItem, this);
+ if(c == this.activeTab){
var next = this.stack.next();
if(next){
this.setActiveTab(next);
}else if(this.items.getCount() > 0){
this.setActiveTab(0);
}else{
- this.activeTab = null;
+ this.setActiveTab(null);
}
}
- this.delegateUpdates();
+ if(!this.destroying){
+ this.delegateUpdates();
+ }
},
// private
onItemIconChanged : function(item, iconCls, oldCls){
var el = this.getTabEl(item);
if(el){
- Ext.fly(el).child('span.x-tab-strip-text').replaceClass(oldCls, iconCls);
+ el = Ext.get(el);
+ el.child('span.x-tab-strip-text').replaceClass(oldCls, iconCls);
+ el[Ext.isEmpty(iconCls) ? 'removeClass' : 'addClass']('x-tab-with-icon');
}
},
* @return {HTMLElement} The DOM node
*/
getTabEl : function(item){
- return document.getElementById(this.id + this.idDelimiter + this.getComponent(item).getItemId());
+ var c = this.getComponent(item);
+ return c ? c.tabEl : null;
},
// private
// private
autoSizeTabs : function(){
- var count = this.items.length;
- var ce = this.tabPosition != 'bottom' ? 'header' : 'footer';
- var ow = this[ce].dom.offsetWidth;
- var aw = this[ce].dom.clientWidth;
+ var count = this.items.length,
+ ce = this.tabPosition != 'bottom' ? 'header' : 'footer',
+ ow = this[ce].dom.offsetWidth,
+ aw = this[ce].dom.clientWidth;
if(!this.resizeTabs || count < 1 || !aw){ // !aw for display:none
return;
var each = Math.max(Math.min(Math.floor((aw-4) / count) - this.tabMargin, this.tabWidth), this.minTabWidth); // -4 for float errors in IE
this.lastTabWidth = each;
- var lis = this.strip.query("li:not([className^=x-tab-edge])");
+ var lis = this.strip.query('li:not(.x-tab-edge)');
for(var i = 0, len = lis.length; i < len; i++) {
- var li = lis[i];
- var inner = Ext.fly(li).child('.x-tab-strip-inner', true);
- var tw = li.offsetWidth;
- var iw = inner.offsetWidth;
+ var li = lis[i],
+ inner = Ext.fly(li).child('.x-tab-strip-inner', true),
+ tw = li.offsetWidth,
+ iw = inner.offsetWidth;
inner.style.width = (each - (tw-iw)) + 'px';
}
},
*/
setActiveTab : function(item){
item = this.getComponent(item);
- if(!item || this.fireEvent('beforetabchange', this, item, this.activeTab) === false){
+ if(this.fireEvent('beforetabchange', this, item, this.activeTab) === false){
return;
}
if(!this.rendered){
if(oldEl){
Ext.fly(oldEl).removeClass('x-tab-strip-active');
}
- this.activeTab.fireEvent('deactivate', this.activeTab);
}
- var el = this.getTabEl(item);
- Ext.fly(el).addClass('x-tab-strip-active');
- this.activeTab = item;
- this.stack.add(item);
-
- this.layout.setActiveItem(item);
- if(this.scrolling){
- this.scrollToTab(item, this.animScroll);
+ if(item){
+ var el = this.getTabEl(item);
+ Ext.fly(el).addClass('x-tab-strip-active');
+ this.activeTab = item;
+ this.stack.add(item);
+
+ this.layout.setActiveItem(item);
+ if(this.scrolling){
+ this.scrollToTab(item, this.animScroll);
+ }
}
-
- item.fireEvent('activate', item);
this.fireEvent('tabchange', this, item);
}
},
<div id="method-Ext.TabPanel-getActiveTab"></div>/**
- * Gets the currently active tab.
- * @return {Panel} The active tab
+ * Returns the Component which is the currently active tab. <b>Note that before the TabPanel
+ * first activates a child Component, this method will return whatever was configured in the
+ * {@link #activeTab} config option.</b>
+ * @return {BoxComponent} The currently active child Component if one <i>is</i> active, or the {@link #activeTab} config value.
*/
getActiveTab : function(){
return this.activeTab || null;
// private
autoScrollTabs : function(){
this.pos = this.tabPosition=='bottom' ? this.footer : this.header;
- var count = this.items.length;
- var ow = this.pos.dom.offsetWidth;
- var tw = this.pos.dom.clientWidth;
-
- var wrap = this.stripWrap;
- var wd = wrap.dom;
- var cw = wd.offsetWidth;
- var pos = this.getScrollPos();
- var l = this.edge.getOffsetsTo(this.stripWrap)[0] + pos;
+ var count = this.items.length,
+ ow = this.pos.dom.offsetWidth,
+ tw = this.pos.dom.clientWidth,
+ wrap = this.stripWrap,
+ wd = wrap.dom,
+ cw = wd.offsetWidth,
+ pos = this.getScrollPos(),
+ l = this.edge.getOffsetsTo(this.stripWrap)[0] + pos;
if(!this.enableTabScroll || count < 1 || cw < 20){ // 20 to prevent display:none issues
return;
*/
scrollToTab : function(item, animate){
- if(!item){ return; }
- var el = this.getTabEl(item);
- var pos = this.getScrollPos(), area = this.getScrollArea();
- var left = Ext.fly(el).getOffsetsTo(this.stripWrap)[0] + pos;
- var right = left + el.offsetWidth;
+ if(!item){
+ return;
+ }
+ var el = this.getTabEl(item),
+ pos = this.getScrollPos(),
+ area = this.getScrollArea(),
+ left = Ext.fly(el).getOffsetsTo(this.stripWrap)[0] + pos,
+ right = left + el.offsetWidth;
if(left < pos){
this.scrollTo(left, animate);
}else if(right > (pos + area)){
var d = e.getWheelDelta()*this.wheelIncrement*-1;
e.stopEvent();
- var pos = this.getScrollPos();
- var newpos = pos + d;
- var sw = this.getScrollWidth()-this.getScrollArea();
+ var pos = this.getScrollPos(),
+ newpos = pos + d,
+ sw = this.getScrollWidth()-this.getScrollArea();
var s = Math.max(0, Math.min(sw, newpos));
if(s != pos){
// private
onScrollRight : function(){
- var sw = this.getScrollWidth()-this.getScrollArea();
- var pos = this.getScrollPos();
- var s = Math.min(sw, pos + this.getScrollIncrement());
+ var sw = this.getScrollWidth()-this.getScrollArea(),
+ pos = this.getScrollPos(),
+ s = Math.min(sw, pos + this.getScrollIncrement());
if(s != pos){
this.scrollTo(s, this.animScroll);
}
// private
onScrollLeft : function(){
- var pos = this.getScrollPos();
- var s = Math.max(0, pos - this.getScrollIncrement());
+ var pos = this.getScrollPos(),
+ s = Math.max(0, pos - this.getScrollIncrement());
if(s != pos){
this.scrollTo(s, this.animScroll);
}
// private
beforeDestroy : function() {
- if(this.items){
- this.items.each(function(item){
- if(item && item.tabEl){
- Ext.get(item.tabEl).removeAllListeners();
- item.tabEl = null;
- }
- }, this);
- }
- if(this.strip){
- this.strip.removeAllListeners();
- }
+ Ext.destroy(this.leftRepeater, this.rightRepeater);
+ this.deleteMembers('strip', 'edge', 'scrollLeft', 'scrollRight', 'stripWrap');
+ this.activeTab = null;
Ext.TabPanel.superclass.beforeDestroy.apply(this);
}
* @property header
* @hide
*/
- <div id="prop-Ext.TabPanel-title"></div>/**
- * @property title
+ <div id="cfg-Ext.TabPanel-null"></div>/**
+ * @cfg title
* @hide
*/
<div id="cfg-Ext.TabPanel-tools"></div>/**
return items.pop();
}
};
-};</pre> \r
+};
+</pre> \r
</body>\r
</html>
\ No newline at end of file