initial import
[roojs1] / Roo / TabPanel.js
1 /*
2  * Based on:
3  * Ext JS Library 1.1.1
4  * Copyright(c) 2006-2007, Ext JS, LLC.
5  *
6  * Originally Released Under LGPL - original licence link has changed is not relivant.
7  *
8  * Fork - LGPL
9  * <script type="text/javascript">
10  */
11 /**
12  * @class Roo.TabPanel
13  * @extends Roo.util.Observable
14  * A lightweight tab container.
15  * <br><br>
16  * Usage:
17  * <pre><code>
18 // basic tabs 1, built from existing content
19 var tabs = new Roo.TabPanel("tabs1");
20 tabs.addTab("script", "View Script");
21 tabs.addTab("markup", "View Markup");
22 tabs.activate("script");
23
24 // more advanced tabs, built from javascript
25 var jtabs = new Roo.TabPanel("jtabs");
26 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
27
28 // set up the UpdateManager
29 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
30 var updater = tab2.getUpdateManager();
31 updater.setDefaultUrl("ajax1.htm");
32 tab2.on('activate', updater.refresh, updater, true);
33
34 // Use setUrl for Ajax loading
35 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
36 tab3.setUrl("ajax2.htm", null, true);
37
38 // Disabled tab
39 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
40 tab4.disable();
41
42 jtabs.activate("jtabs-1");
43  * </code></pre>
44  * @constructor
45  * Create a new TabPanel.
46  * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
47  * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
48  */
49 Roo.TabPanel = function(container, config){
50     /**
51     * The container element for this TabPanel.
52     * @type Roo.Element
53     */
54     this.el = Roo.get(container, true);
55     if(config){
56         if(typeof config == "boolean"){
57             this.tabPosition = config ? "bottom" : "top";
58         }else{
59             Roo.apply(this, config);
60         }
61     }
62     if(this.tabPosition == "bottom"){
63         this.bodyEl = Roo.get(this.createBody(this.el.dom));
64         this.el.addClass("x-tabs-bottom");
65     }
66     this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
67     this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
68     this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
69     if(Roo.isIE){
70         Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
71     }
72     if(this.tabPosition != "bottom"){
73     /** The body element that contains {@link Roo.TabPanelItem} bodies.
74      * @type Roo.Element
75      */
76       this.bodyEl = Roo.get(this.createBody(this.el.dom));
77       this.el.addClass("x-tabs-top");
78     }
79     this.items = [];
80
81     this.bodyEl.setStyle("position", "relative");
82
83     this.active = null;
84     this.activateDelegate = this.activate.createDelegate(this);
85
86     this.addEvents({
87         /**
88          * @event tabchange
89          * Fires when the active tab changes
90          * @param {Roo.TabPanel} this
91          * @param {Roo.TabPanelItem} activePanel The new active tab
92          */
93         "tabchange": true,
94         /**
95          * @event beforetabchange
96          * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
97          * @param {Roo.TabPanel} this
98          * @param {Object} e Set cancel to true on this object to cancel the tab change
99          * @param {Roo.TabPanelItem} tab The tab being changed to
100          */
101         "beforetabchange" : true
102     });
103
104     Roo.EventManager.onWindowResize(this.onResize, this);
105     this.cpad = this.el.getPadding("lr");
106     this.hiddenCount = 0;
107
108     Roo.TabPanel.superclass.constructor.call(this);
109 };
110
111 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
112         /*
113          *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
114          */
115     tabPosition : "top",
116         /*
117          *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
118          */
119     currentTabWidth : 0,
120         /*
121          *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
122          */
123     minTabWidth : 40,
124         /*
125          *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
126          */
127     maxTabWidth : 250,
128         /*
129          *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
130          */
131     preferredTabWidth : 175,
132         /*
133          *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
134          */
135     resizeTabs : false,
136         /*
137          *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
138          */
139     monitorResize : true,
140
141     /**
142      * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
143      * @param {String} id The id of the div to use <b>or create</b>
144      * @param {String} text The text for the tab
145      * @param {String} content (optional) Content to put in the TabPanelItem body
146      * @param {Boolean} closable (optional) True to create a close icon on the tab
147      * @return {Roo.TabPanelItem} The created TabPanelItem
148      */
149     addTab : function(id, text, content, closable){
150         var item = new Roo.TabPanelItem(this, id, text, closable);
151         this.addTabItem(item);
152         if(content){
153             item.setContent(content);
154         }
155         return item;
156     },
157
158     /**
159      * Returns the {@link Roo.TabPanelItem} with the specified id/index
160      * @param {String/Number} id The id or index of the TabPanelItem to fetch.
161      * @return {Roo.TabPanelItem}
162      */
163     getTab : function(id){
164         return this.items[id];
165     },
166
167     /**
168      * Hides the {@link Roo.TabPanelItem} with the specified id/index
169      * @param {String/Number} id The id or index of the TabPanelItem to hide.
170      */
171     hideTab : function(id){
172         var t = this.items[id];
173         if(!t.isHidden()){
174            t.setHidden(true);
175            this.hiddenCount++;
176            this.autoSizeTabs();
177         }
178     },
179
180     /**
181      * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
182      * @param {String/Number} id The id or index of the TabPanelItem to unhide.
183      */
184     unhideTab : function(id){
185         var t = this.items[id];
186         if(t.isHidden()){
187            t.setHidden(false);
188            this.hiddenCount--;
189            this.autoSizeTabs();
190         }
191     },
192
193     /**
194      * Adds an existing {@link Roo.TabPanelItem}.
195      * @param {Roo.TabPanelItem} item The TabPanelItem to add
196      */
197     addTabItem : function(item){
198         this.items[item.id] = item;
199         this.items.push(item);
200         if(this.resizeTabs){
201            item.setWidth(this.currentTabWidth || this.preferredTabWidth);
202            this.autoSizeTabs();
203         }else{
204             item.autoSize();
205         }
206     },
207
208     /**
209      * Removes a {@link Roo.TabPanelItem}.
210      * @param {String/Number} id The id or index of the TabPanelItem to remove.
211      */
212     removeTab : function(id){
213         var items = this.items;
214         var tab = items[id];
215         if(!tab) return;
216         var index = items.indexOf(tab);
217         if(this.active == tab && items.length > 1){
218             var newTab = this.getNextAvailable(index);
219             if(newTab)newTab.activate();
220         }
221         this.stripEl.dom.removeChild(tab.pnode.dom);
222         if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
223             this.bodyEl.dom.removeChild(tab.bodyEl.dom);
224         }
225         items.splice(index, 1);
226         delete this.items[tab.id];
227         tab.fireEvent("close", tab);
228         tab.purgeListeners();
229         this.autoSizeTabs();
230     },
231
232     getNextAvailable : function(start){
233         var items = this.items;
234         var index = start;
235         // look for a next tab that will slide over to
236         // replace the one being removed
237         while(index < items.length){
238             var item = items[++index];
239             if(item && !item.isHidden()){
240                 return item;
241             }
242         }
243         // if one isn't found select the previous tab (on the left)
244         index = start;
245         while(index >= 0){
246             var item = items[--index];
247             if(item && !item.isHidden()){
248                 return item;
249             }
250         }
251         return null;
252     },
253
254     /**
255      * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
256      * @param {String/Number} id The id or index of the TabPanelItem to disable.
257      */
258     disableTab : function(id){
259         var tab = this.items[id];
260         if(tab && this.active != tab){
261             tab.disable();
262         }
263     },
264
265     /**
266      * Enables a {@link Roo.TabPanelItem} that is disabled.
267      * @param {String/Number} id The id or index of the TabPanelItem to enable.
268      */
269     enableTab : function(id){
270         var tab = this.items[id];
271         tab.enable();
272     },
273
274     /**
275      * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
276      * @param {String/Number} id The id or index of the TabPanelItem to activate.
277      * @return {Roo.TabPanelItem} The TabPanelItem.
278      */
279     activate : function(id){
280         var tab = this.items[id];
281         if(!tab){
282             return null;
283         }
284         if(tab == this.active || tab.disabled){
285             return tab;
286         }
287         var e = {};
288         this.fireEvent("beforetabchange", this, e, tab);
289         if(e.cancel !== true && !tab.disabled){
290             if(this.active){
291                 this.active.hide();
292             }
293             this.active = this.items[id];
294             this.active.show();
295             this.fireEvent("tabchange", this, this.active);
296         }
297         return tab;
298     },
299
300     /**
301      * Gets the active {@link Roo.TabPanelItem}.
302      * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
303      */
304     getActiveTab : function(){
305         return this.active;
306     },
307
308     /**
309      * Updates the tab body element to fit the height of the container element
310      * for overflow scrolling
311      * @param {Number} targetHeight (optional) Override the starting height from the elements height
312      */
313     syncHeight : function(targetHeight){
314         var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
315         var bm = this.bodyEl.getMargins();
316         var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
317         this.bodyEl.setHeight(newHeight);
318         return newHeight;
319     },
320
321     onResize : function(){
322         if(this.monitorResize){
323             this.autoSizeTabs();
324         }
325     },
326
327     /**
328      * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
329      */
330     beginUpdate : function(){
331         this.updating = true;
332     },
333
334     /**
335      * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
336      */
337     endUpdate : function(){
338         this.updating = false;
339         this.autoSizeTabs();
340     },
341
342     /**
343      * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
344      */
345     autoSizeTabs : function(){
346         var count = this.items.length;
347         var vcount = count - this.hiddenCount;
348         if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) return;
349         var w = Math.max(this.el.getWidth() - this.cpad, 10);
350         var availWidth = Math.floor(w / vcount);
351         var b = this.stripBody;
352         if(b.getWidth() > w){
353             var tabs = this.items;
354             this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
355             if(availWidth < this.minTabWidth){
356                 /*if(!this.sleft){    // incomplete scrolling code
357                     this.createScrollButtons();
358                 }
359                 this.showScroll();
360                 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
361             }
362         }else{
363             if(this.currentTabWidth < this.preferredTabWidth){
364                 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
365             }
366         }
367     },
368
369     /**
370      * Returns the number of tabs in this TabPanel.
371      * @return {Number}
372      */
373      getCount : function(){
374          return this.items.length;
375      },
376
377     /**
378      * Resizes all the tabs to the passed width
379      * @param {Number} The new width
380      */
381     setTabWidth : function(width){
382         this.currentTabWidth = width;
383         for(var i = 0, len = this.items.length; i < len; i++) {
384                 if(!this.items[i].isHidden())this.items[i].setWidth(width);
385         }
386     },
387
388     /**
389      * Destroys this TabPanel
390      * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
391      */
392     destroy : function(removeEl){
393         Roo.EventManager.removeResizeListener(this.onResize, this);
394         for(var i = 0, len = this.items.length; i < len; i++){
395             this.items[i].purgeListeners();
396         }
397         if(removeEl === true){
398             this.el.update("");
399             this.el.remove();
400         }
401     }
402 });
403
404 /**
405  * @class Roo.TabPanelItem
406  * @extends Roo.util.Observable
407  * Represents an individual item (tab plus body) in a TabPanel.
408  * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
409  * @param {String} id The id of this TabPanelItem
410  * @param {String} text The text for the tab of this TabPanelItem
411  * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
412  */
413 Roo.TabPanelItem = function(tabPanel, id, text, closable){
414     /**
415      * The {@link Roo.TabPanel} this TabPanelItem belongs to
416      * @type Roo.TabPanel
417      */
418     this.tabPanel = tabPanel;
419     /**
420      * The id for this TabPanelItem
421      * @type String
422      */
423     this.id = id;
424     /** @private */
425     this.disabled = false;
426     /** @private */
427     this.text = text;
428     /** @private */
429     this.loaded = false;
430     this.closable = closable;
431
432     /**
433      * The body element for this TabPanelItem.
434      * @type Roo.Element
435      */
436     this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
437     this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
438     this.bodyEl.setStyle("display", "block");
439     this.bodyEl.setStyle("zoom", "1");
440     this.hideAction();
441
442     var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
443     /** @private */
444     this.el = Roo.get(els.el, true);
445     this.inner = Roo.get(els.inner, true);
446     this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
447     this.pnode = Roo.get(els.el.parentNode, true);
448     this.el.on("mousedown", this.onTabMouseDown, this);
449     this.el.on("click", this.onTabClick, this);
450     /** @private */
451     if(closable){
452         var c = Roo.get(els.close, true);
453         c.dom.title = this.closeText;
454         c.addClassOnOver("close-over");
455         c.on("click", this.closeClick, this);
456      }
457
458     this.addEvents({
459          /**
460          * @event activate
461          * Fires when this tab becomes the active tab.
462          * @param {Roo.TabPanel} tabPanel The parent TabPanel
463          * @param {Roo.TabPanelItem} this
464          */
465         "activate": true,
466         /**
467          * @event beforeclose
468          * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
469          * @param {Roo.TabPanelItem} this
470          * @param {Object} e Set cancel to true on this object to cancel the close.
471          */
472         "beforeclose": true,
473         /**
474          * @event close
475          * Fires when this tab is closed.
476          * @param {Roo.TabPanelItem} this
477          */
478          "close": true,
479         /**
480          * @event deactivate
481          * Fires when this tab is no longer the active tab.
482          * @param {Roo.TabPanel} tabPanel The parent TabPanel
483          * @param {Roo.TabPanelItem} this
484          */
485          "deactivate" : true
486     });
487     this.hidden = false;
488
489     Roo.TabPanelItem.superclass.constructor.call(this);
490 };
491
492 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
493     purgeListeners : function(){
494        Roo.util.Observable.prototype.purgeListeners.call(this);
495        this.el.removeAllListeners();
496     },
497     /**
498      * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
499      */
500     show : function(){
501         this.pnode.addClass("on");
502         this.showAction();
503         if(Roo.isOpera){
504             this.tabPanel.stripWrap.repaint();
505         }
506         this.fireEvent("activate", this.tabPanel, this);
507     },
508
509     /**
510      * Returns true if this tab is the active tab.
511      * @return {Boolean}
512      */
513     isActive : function(){
514         return this.tabPanel.getActiveTab() == this;
515     },
516
517     /**
518      * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
519      */
520     hide : function(){
521         this.pnode.removeClass("on");
522         this.hideAction();
523         this.fireEvent("deactivate", this.tabPanel, this);
524     },
525
526     hideAction : function(){
527         this.bodyEl.hide();
528         this.bodyEl.setStyle("position", "absolute");
529         this.bodyEl.setLeft("-20000px");
530         this.bodyEl.setTop("-20000px");
531     },
532
533     showAction : function(){
534         this.bodyEl.setStyle("position", "relative");
535         this.bodyEl.setTop("");
536         this.bodyEl.setLeft("");
537         this.bodyEl.show();
538     },
539
540     /**
541      * Set the tooltip for the tab.
542      * @param {String} tooltip The tab's tooltip
543      */
544     setTooltip : function(text){
545         if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
546             this.textEl.dom.qtip = text;
547             this.textEl.dom.removeAttribute('title');
548         }else{
549             this.textEl.dom.title = text;
550         }
551     },
552
553     onTabClick : function(e){
554         e.preventDefault();
555         this.tabPanel.activate(this.id);
556     },
557
558     onTabMouseDown : function(e){
559         e.preventDefault();
560         this.tabPanel.activate(this.id);
561     },
562
563     getWidth : function(){
564         return this.inner.getWidth();
565     },
566
567     setWidth : function(width){
568         var iwidth = width - this.pnode.getPadding("lr");
569         this.inner.setWidth(iwidth);
570         this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
571         this.pnode.setWidth(width);
572     },
573
574     /**
575      * Show or hide the tab
576      * @param {Boolean} hidden True to hide or false to show.
577      */
578     setHidden : function(hidden){
579         this.hidden = hidden;
580         this.pnode.setStyle("display", hidden ? "none" : "");
581     },
582
583     /**
584      * Returns true if this tab is "hidden"
585      * @return {Boolean}
586      */
587     isHidden : function(){
588         return this.hidden;
589     },
590
591     /**
592      * Returns the text for this tab
593      * @return {String}
594      */
595     getText : function(){
596         return this.text;
597     },
598
599     autoSize : function(){
600         //this.el.beginMeasure();
601         this.textEl.setWidth(1);
602         this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr"));
603         //this.el.endMeasure();
604     },
605
606     /**
607      * Sets the text for the tab (Note: this also sets the tooltip text)
608      * @param {String} text The tab's text and tooltip
609      */
610     setText : function(text){
611         this.text = text;
612         this.textEl.update(text);
613         this.setTooltip(text);
614         if(!this.tabPanel.resizeTabs){
615             this.autoSize();
616         }
617     },
618     /**
619      * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
620      */
621     activate : function(){
622         this.tabPanel.activate(this.id);
623     },
624
625     /**
626      * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
627      */
628     disable : function(){
629         if(this.tabPanel.active != this){
630             this.disabled = true;
631             this.pnode.addClass("disabled");
632         }
633     },
634
635     /**
636      * Enables this TabPanelItem if it was previously disabled.
637      */
638     enable : function(){
639         this.disabled = false;
640         this.pnode.removeClass("disabled");
641     },
642
643     /**
644      * Sets the content for this TabPanelItem.
645      * @param {String} content The content
646      * @param {Boolean} loadScripts true to look for and load scripts
647      */
648     setContent : function(content, loadScripts){
649         this.bodyEl.update(content, loadScripts);
650     },
651
652     /**
653      * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
654      * @return {Roo.UpdateManager} The UpdateManager
655      */
656     getUpdateManager : function(){
657         return this.bodyEl.getUpdateManager();
658     },
659
660     /**
661      * Set a URL to be used to load the content for this TabPanelItem.
662      * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
663      * @param {String/Object} params (optional) The string params for the update call or an object of the params. See {@link Roo.UpdateManager#update} for more details. (Defaults to null)
664      * @param {Boolean} loadOnce (optional) Whether to only load the content once. If this is false it makes the Ajax call every time this TabPanelItem is activated. (Defaults to false)
665      * @return {Roo.UpdateManager} The UpdateManager
666      */
667     setUrl : function(url, params, loadOnce){
668         if(this.refreshDelegate){
669             this.un('activate', this.refreshDelegate);
670         }
671         this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
672         this.on("activate", this.refreshDelegate);
673         return this.bodyEl.getUpdateManager();
674     },
675
676     /** @private */
677     _handleRefresh : function(url, params, loadOnce){
678         if(!loadOnce || !this.loaded){
679             var updater = this.bodyEl.getUpdateManager();
680             updater.update(url, params, this._setLoaded.createDelegate(this));
681         }
682     },
683
684     /**
685      *   Forces a content refresh from the URL specified in the {@link #setUrl} method.
686      *   Will fail silently if the setUrl method has not been called.
687      *   This does not activate the panel, just updates its content.
688      */
689     refresh : function(){
690         if(this.refreshDelegate){
691            this.loaded = false;
692            this.refreshDelegate();
693         }
694     },
695
696     /** @private */
697     _setLoaded : function(){
698         this.loaded = true;
699     },
700
701     /** @private */
702     closeClick : function(e){
703         var o = {};
704         e.stopEvent();
705         this.fireEvent("beforeclose", this, o);
706         if(o.cancel !== true){
707             this.tabPanel.removeTab(this.id);
708         }
709     },
710     /**
711      * The text displayed in the tooltip for the close icon.
712      * @type String
713      */
714     closeText : "Close this tab"
715 });
716
717 /** @private */
718 Roo.TabPanel.prototype.createStrip = function(container){
719     var strip = document.createElement("div");
720     strip.className = "x-tabs-wrap";
721     container.appendChild(strip);
722     return strip;
723 };
724 /** @private */
725 Roo.TabPanel.prototype.createStripList = function(strip){
726     // div wrapper for retard IE
727     strip.innerHTML = '<div class="x-tabs-strip-wrap"><table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr></tr></tbody></table></div>';
728     return strip.firstChild.firstChild.firstChild.firstChild;
729 };
730 /** @private */
731 Roo.TabPanel.prototype.createBody = function(container){
732     var body = document.createElement("div");
733     Roo.id(body, "tab-body");
734     Roo.fly(body).addClass("x-tabs-body");
735     container.appendChild(body);
736     return body;
737 };
738 /** @private */
739 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
740     var body = Roo.getDom(id);
741     if(!body){
742         body = document.createElement("div");
743         body.id = id;
744     }
745     Roo.fly(body).addClass("x-tabs-item-body");
746     bodyEl.insertBefore(body, bodyEl.firstChild);
747     return body;
748 };
749 /** @private */
750 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
751     var td = document.createElement("td");
752     stripEl.appendChild(td);
753     if(closable){
754         td.className = "x-tabs-closable";
755         if(!this.closeTpl){
756             this.closeTpl = new Roo.Template(
757                '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
758                '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
759                '<div unselectable="on" class="close-icon">&#160;</div></em></span></a>'
760             );
761         }
762         var el = this.closeTpl.overwrite(td, {"text": text});
763         var close = el.getElementsByTagName("div")[0];
764         var inner = el.getElementsByTagName("em")[0];
765         return {"el": el, "close": close, "inner": inner};
766     } else {
767         if(!this.tabTpl){
768             this.tabTpl = new Roo.Template(
769                '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
770                '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
771             );
772         }
773         var el = this.tabTpl.overwrite(td, {"text": text});
774         var inner = el.getElementsByTagName("em")[0];
775         return {"el": el, "inner": inner};
776     }
777 };