Upgrade to ExtJS 3.1.0 - Released 12/16/2009
[extjs.git] / src / widgets / Toolbar.js
1 /*!
2  * Ext JS Library 3.1.0
3  * Copyright(c) 2006-2009 Ext JS, LLC
4  * licensing@extjs.com
5  * http://www.extjs.com/license
6  */
7 /**
8  * @class Ext.layout.ToolbarLayout
9  * @extends Ext.layout.ContainerLayout
10  * Layout manager implicitly used by Ext.Toolbar.
11  */
12 Ext.layout.ToolbarLayout = Ext.extend(Ext.layout.ContainerLayout, {
13     monitorResize : true,
14     triggerWidth : 18,
15     lastOverflow : false,
16     forceLayout: true,
17
18     noItemsMenuText : '<div class="x-toolbar-no-items">(None)</div>',
19     // private
20     onLayout : function(ct, target){
21         if(!this.leftTr){
22             var align = ct.buttonAlign == 'center' ? 'center' : 'left';
23             target.addClass('x-toolbar-layout-ct');
24             target.insertHtml('beforeEnd',
25                  '<table cellspacing="0" class="x-toolbar-ct"><tbody><tr><td class="x-toolbar-left" align="' + align + '"><table cellspacing="0"><tbody><tr class="x-toolbar-left-row"></tr></tbody></table></td><td class="x-toolbar-right" align="right"><table cellspacing="0" class="x-toolbar-right-ct"><tbody><tr><td><table cellspacing="0"><tbody><tr class="x-toolbar-right-row"></tr></tbody></table></td><td><table cellspacing="0"><tbody><tr class="x-toolbar-extras-row"></tr></tbody></table></td></tr></tbody></table></td></tr></tbody></table>');
26             this.leftTr = target.child('tr.x-toolbar-left-row', true);
27             this.rightTr = target.child('tr.x-toolbar-right-row', true);
28             this.extrasTr = target.child('tr.x-toolbar-extras-row', true);
29         }
30         var side = ct.buttonAlign == 'right' ? this.rightTr : this.leftTr,
31             pos = 0,
32             items = ct.items.items;
33
34         for(var i = 0, len = items.length, c; i < len; i++, pos++) {
35             c = items[i];
36             if(c.isFill){
37                 side = this.rightTr;
38                 pos = -1;
39             }else if(!c.rendered){
40                 c.render(this.insertCell(c, side, pos));
41             }else{
42                 if(!c.xtbHidden && !this.isValidParent(c, side.childNodes[pos])){
43                     var td = this.insertCell(c, side, pos);
44                     td.appendChild(c.getPositionEl().dom);
45                     c.container = Ext.get(td);
46                 }
47             }
48         }
49         //strip extra empty cells
50         this.cleanup(this.leftTr);
51         this.cleanup(this.rightTr);
52         this.cleanup(this.extrasTr);
53         this.fitToSize(target);
54     },
55
56     cleanup : function(row){
57         var cn = row.childNodes;
58         for(var i = cn.length-1, c; i >= 0 && (c = cn[i]); i--){
59             if(!c.firstChild){
60                 row.removeChild(c);
61             }
62         }
63     },
64
65     insertCell : function(c, side, pos){
66         var td = document.createElement('td');
67         td.className='x-toolbar-cell';
68         side.insertBefore(td, side.childNodes[pos]||null);
69         return td;
70     },
71
72     hideItem : function(item){
73         var h = (this.hiddens = this.hiddens || []);
74         h.push(item);
75         item.xtbHidden = true;
76         item.xtbWidth = item.getPositionEl().dom.parentNode.offsetWidth;
77         item.hide();
78     },
79
80     unhideItem : function(item){
81         item.show();
82         item.xtbHidden = false;
83         this.hiddens.remove(item);
84         if(this.hiddens.length < 1){
85             delete this.hiddens;
86         }
87     },
88
89     getItemWidth : function(c){
90         return c.hidden ? (c.xtbWidth || 0) : c.getPositionEl().dom.parentNode.offsetWidth;
91     },
92
93     fitToSize : function(t){
94         if(this.container.enableOverflow === false){
95             return;
96         }
97         var w = t.dom.clientWidth,
98             lw = this.lastWidth || 0,
99             iw = t.dom.firstChild.offsetWidth,
100             clipWidth = w - this.triggerWidth,
101             hideIndex = -1;
102
103         this.lastWidth = w;
104
105         if(iw > w || (this.hiddens && w >= lw)){
106             var i, items = this.container.items.items,
107                 len = items.length, c,
108                 loopWidth = 0;
109
110             for(i = 0; i < len; i++) {
111                 c = items[i];
112                 if(!c.isFill){
113                     loopWidth += this.getItemWidth(c);
114                     if(loopWidth > clipWidth){
115                         if(!(c.hidden || c.xtbHidden)){
116                             this.hideItem(c);
117                         }
118                     }else if(c.xtbHidden){
119                         this.unhideItem(c);
120                     }
121                 }
122             }
123         }
124         if(this.hiddens){
125             this.initMore();
126             if(!this.lastOverflow){
127                 this.container.fireEvent('overflowchange', this.container, true);
128                 this.lastOverflow = true;
129             }
130         }else if(this.more){
131             this.clearMenu();
132             this.more.destroy();
133             delete this.more;
134             if(this.lastOverflow){
135                 this.container.fireEvent('overflowchange', this.container, false);
136                 this.lastOverflow = false;
137             }
138         }
139     },
140
141     createMenuConfig : function(c, hideOnClick){
142         var cfg = Ext.apply({}, c.initialConfig),
143             group = c.toggleGroup;
144
145         Ext.apply(cfg, {
146             text: c.overflowText || c.text,
147             iconCls: c.iconCls,
148             icon: c.icon,
149             itemId: c.itemId,
150             disabled: c.disabled,
151             handler: c.handler,
152             scope: c.scope,
153             menu: c.menu,
154             hideOnClick: hideOnClick
155         });
156         if(group || c.enableToggle){
157             Ext.apply(cfg, {
158                 group: group,
159                 checked: c.pressed,
160                 listeners: {
161                     checkchange: function(item, checked){
162                         c.toggle(checked);
163                     }
164                 }
165             });
166         }
167         delete cfg.ownerCt;
168         delete cfg.xtype;
169         delete cfg.id;
170         return cfg;
171     },
172
173     // private
174     addComponentToMenu : function(m, c){
175         if(c instanceof Ext.Toolbar.Separator){
176             m.add('-');
177         }else if(Ext.isFunction(c.isXType)){
178             if(c.isXType('splitbutton')){
179                 m.add(this.createMenuConfig(c, true));
180             }else if(c.isXType('button')){
181                 m.add(this.createMenuConfig(c, !c.menu));
182             }else if(c.isXType('buttongroup')){
183                 c.items.each(function(item){
184                      this.addComponentToMenu(m, item);
185                 }, this);
186             }
187         }
188     },
189
190     clearMenu : function(){
191         var m = this.moreMenu;
192         if(m && m.items){
193             m.items.each(function(item){
194                 delete item.menu;
195             });
196         }
197     },
198
199     // private
200     beforeMoreShow : function(m){
201         var h = this.container.items.items,
202             len = h.length,
203             c,
204             prev,
205             needsSep = function(group, item){
206                 return group.isXType('buttongroup') && !(item instanceof Ext.Toolbar.Separator);
207             };
208
209         this.clearMenu();
210         m.removeAll();
211         for(var i = 0; i < len; i++){
212             c = h[i];
213             if(c.xtbHidden){
214                 if(prev && (needsSep(c, prev) || needsSep(prev, c))){
215                     m.add('-');
216                 }
217                 this.addComponentToMenu(m, c);
218                 prev = c;
219             }
220         }
221         // put something so the menu isn't empty
222         // if no compatible items found
223         if(m.items.length < 1){
224             m.add(this.noItemsMenuText);
225         }
226     },
227
228     initMore : function(){
229         if(!this.more){
230             this.moreMenu = new Ext.menu.Menu({
231                 listeners: {
232                     beforeshow: this.beforeMoreShow,
233                     scope: this
234                 }
235             });
236             this.moreMenu.ownerCt = this.container;
237             this.more = new Ext.Button({
238                 iconCls: 'x-toolbar-more-icon',
239                 cls: 'x-toolbar-more',
240                 menu: this.moreMenu
241             });
242             var td = this.insertCell(this.more, this.extrasTr, 100);
243             this.more.render(td);
244         }
245     },
246
247     onRemove : function(c){
248         delete this.leftTr;
249         delete this.rightTr;
250         delete this.extrasTr;
251         Ext.layout.ToolbarLayout.superclass.onRemove.call(this, c);
252     },
253
254     destroy : function(){
255         Ext.destroy(this.more, this.moreMenu);
256         delete this.leftTr;
257         delete this.rightTr;
258         delete this.extrasTr;
259         Ext.layout.ToolbarLayout.superclass.destroy.call(this);
260     }
261     /**
262      * @property activeItem
263      * @hide
264      */
265 });
266
267 Ext.Container.LAYOUTS.toolbar = Ext.layout.ToolbarLayout;
268
269 /**
270  * @class Ext.Toolbar
271  * @extends Ext.Container
272  * <p>Basic Toolbar class. Although the <tt>{@link Ext.Container#defaultType defaultType}</tt> for Toolbar
273  * is <tt>{@link Ext.Button button}</tt>, Toolbar elements (child items for the Toolbar container) may
274  * be virtually any type of Component. Toolbar elements can be created explicitly via their constructors,
275  * or implicitly via their xtypes, and can be <tt>{@link #add}</tt>ed dynamically.</p>
276  * <p>Some items have shortcut strings for creation:</p>
277  * <pre>
278 <u>Shortcut</u>  <u>xtype</u>          <u>Class</u>                  <u>Description</u>
279 '->'      'tbfill'       {@link Ext.Toolbar.Fill}       begin using the right-justified button container
280 '-'       'tbseparator'  {@link Ext.Toolbar.Separator}  add a vertical separator bar between toolbar items
281 ' '       'tbspacer'     {@link Ext.Toolbar.Spacer}     add horiztonal space between elements
282  * </pre>
283  *
284  * Example usage of various elements:
285  * <pre><code>
286 var tb = new Ext.Toolbar({
287     renderTo: document.body,
288     width: 600,
289     height: 100,
290     items: [
291         {
292             // xtype: 'button', // default for Toolbars, same as 'tbbutton'
293             text: 'Button'
294         },
295         {
296             xtype: 'splitbutton', // same as 'tbsplitbutton'
297             text: 'Split Button'
298         },
299         // begin using the right-justified button container
300         '->', // same as {xtype: 'tbfill'}, // Ext.Toolbar.Fill
301         {
302             xtype: 'textfield',
303             name: 'field1',
304             emptyText: 'enter search term'
305         },
306         // add a vertical separator bar between toolbar items
307         '-', // same as {xtype: 'tbseparator'} to create Ext.Toolbar.Separator
308         'text 1', // same as {xtype: 'tbtext', text: 'text1'} to create Ext.Toolbar.TextItem
309         {xtype: 'tbspacer'},// same as ' ' to create Ext.Toolbar.Spacer
310         'text 2',
311         {xtype: 'tbspacer', width: 50}, // add a 50px space
312         'text 3'
313     ]
314 });
315  * </code></pre>
316  * Example adding a ComboBox within a menu of a button:
317  * <pre><code>
318 // ComboBox creation
319 var combo = new Ext.form.ComboBox({
320     store: new Ext.data.ArrayStore({
321         autoDestroy: true,
322         fields: ['initials', 'fullname'],
323         data : [
324             ['FF', 'Fred Flintstone'],
325             ['BR', 'Barney Rubble']
326         ]
327     }),
328     displayField: 'fullname',
329     typeAhead: true,
330     mode: 'local',
331     forceSelection: true,
332     triggerAction: 'all',
333     emptyText: 'Select a name...',
334     selectOnFocus: true,
335     width: 135,
336     getListParent: function() {
337         return this.el.up('.x-menu');
338     },
339     iconCls: 'no-icon' //use iconCls if placing within menu to shift to right side of menu
340 });
341
342 // put ComboBox in a Menu
343 var menu = new Ext.menu.Menu({
344     id: 'mainMenu',
345     items: [
346         combo // A Field in a Menu
347     ]
348 });
349
350 // add a Button with the menu
351 tb.add({
352         text:'Button w/ Menu',
353         menu: menu  // assign menu by instance
354     });
355 tb.doLayout();
356  * </code></pre>
357  * @constructor
358  * Creates a new Toolbar
359  * @param {Object/Array} config A config object or an array of buttons to <tt>{@link #add}</tt>
360  * @xtype toolbar
361  */
362 Ext.Toolbar = function(config){
363     if(Ext.isArray(config)){
364         config = {items: config, layout: 'toolbar'};
365     } else {
366         config = Ext.apply({
367             layout: 'toolbar'
368         }, config);
369         if(config.buttons) {
370             config.items = config.buttons;
371         }
372     }
373     Ext.Toolbar.superclass.constructor.call(this, config);
374 };
375
376 (function(){
377
378 var T = Ext.Toolbar;
379
380 Ext.extend(T, Ext.Container, {
381
382     defaultType: 'button',
383
384     /**
385      * @cfg {String/Object} layout
386      * This class assigns a default layout (<code>layout:'<b>toolbar</b>'</code>).
387      * Developers <i>may</i> override this configuration option if another layout
388      * is required (the constructor must be passed a configuration object in this
389      * case instead of an array).
390      * See {@link Ext.Container#layout} for additional information.
391      */
392     /**
393      * @cfg {Boolean} enableOverflow
394      * Defaults to false. Configure <code>true<code> to make the toolbar provide a button
395      * which activates a dropdown Menu to show items which overflow the Toolbar's width.
396      */
397
398     trackMenus : true,
399     internalDefaults: {removeMode: 'container', hideParent: true},
400     toolbarCls: 'x-toolbar',
401
402     initComponent : function(){
403         T.superclass.initComponent.call(this);
404
405         /**
406          * @event overflowchange
407          * Fires after the overflow state has changed.
408          * @param {Object} c The Container
409          * @param {Boolean} lastOverflow overflow state
410          */
411         this.addEvents('overflowchange');
412     },
413
414     // private
415     onRender : function(ct, position){
416         if(!this.el){
417             if(!this.autoCreate){
418                 this.autoCreate = {
419                     cls: this.toolbarCls + ' x-small-editor'
420                 };
421             }
422             this.el = ct.createChild(Ext.apply({ id: this.id },this.autoCreate), position);
423             Ext.Toolbar.superclass.onRender.apply(this, arguments);
424         }
425     },
426
427     /**
428      * <p>Adds element(s) to the toolbar -- this function takes a variable number of
429      * arguments of mixed type and adds them to the toolbar.</p>
430      * <br><p><b>Note</b>: See the notes within {@link Ext.Container#add}.</p>
431      * @param {Mixed} arg1 The following types of arguments are all valid:<br />
432      * <ul>
433      * <li>{@link Ext.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
434      * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
435      * <li>Field: Any form field (equivalent to {@link #addField})</li>
436      * <li>Item: Any subclass of {@link Ext.Toolbar.Item} (equivalent to {@link #addItem})</li>
437      * <li>String: Any generic string (gets wrapped in a {@link Ext.Toolbar.TextItem}, equivalent to {@link #addText}).
438      * Note that there are a few special strings that are treated differently as explained next.</li>
439      * <li>'-': Creates a separator element (equivalent to {@link #addSeparator})</li>
440      * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
441      * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
442      * </ul>
443      * @param {Mixed} arg2
444      * @param {Mixed} etc.
445      * @method add
446      */
447
448     // private
449     lookupComponent : function(c){
450         if(Ext.isString(c)){
451             if(c == '-'){
452                 c = new T.Separator();
453             }else if(c == ' '){
454                 c = new T.Spacer();
455             }else if(c == '->'){
456                 c = new T.Fill();
457             }else{
458                 c = new T.TextItem(c);
459             }
460             this.applyDefaults(c);
461         }else{
462             if(c.isFormField || c.render){ // some kind of form field, some kind of Toolbar.Item
463                 c = this.createComponent(c);
464             }else if(c.tag){ // DomHelper spec
465                 c = new T.Item({autoEl: c});
466             }else if(c.tagName){ // element
467                 c = new T.Item({el:c});
468             }else if(Ext.isObject(c)){ // must be button config?
469                 c = c.xtype ? this.createComponent(c) : this.constructButton(c);
470             }
471         }
472         return c;
473     },
474
475     // private
476     applyDefaults : function(c){
477         if(!Ext.isString(c)){
478             c = Ext.Toolbar.superclass.applyDefaults.call(this, c);
479             var d = this.internalDefaults;
480             if(c.events){
481                 Ext.applyIf(c.initialConfig, d);
482                 Ext.apply(c, d);
483             }else{
484                 Ext.applyIf(c, d);
485             }
486         }
487         return c;
488     },
489
490     /**
491      * Adds a separator
492      * <br><p><b>Note</b>: See the notes within {@link Ext.Container#add}.</p>
493      * @return {Ext.Toolbar.Item} The separator {@link Ext.Toolbar.Item item}
494      */
495     addSeparator : function(){
496         return this.add(new T.Separator());
497     },
498
499     /**
500      * Adds a spacer element
501      * <br><p><b>Note</b>: See the notes within {@link Ext.Container#add}.</p>
502      * @return {Ext.Toolbar.Spacer} The spacer item
503      */
504     addSpacer : function(){
505         return this.add(new T.Spacer());
506     },
507
508     /**
509      * Forces subsequent additions into the float:right toolbar
510      * <br><p><b>Note</b>: See the notes within {@link Ext.Container#add}.</p>
511      */
512     addFill : function(){
513         this.add(new T.Fill());
514     },
515
516     /**
517      * Adds any standard HTML element to the toolbar
518      * <br><p><b>Note</b>: See the notes within {@link Ext.Container#add}.</p>
519      * @param {Mixed} el The element or id of the element to add
520      * @return {Ext.Toolbar.Item} The element's item
521      */
522     addElement : function(el){
523         return this.addItem(new T.Item({el:el}));
524     },
525
526     /**
527      * Adds any Toolbar.Item or subclass
528      * <br><p><b>Note</b>: See the notes within {@link Ext.Container#add}.</p>
529      * @param {Ext.Toolbar.Item} item
530      * @return {Ext.Toolbar.Item} The item
531      */
532     addItem : function(item){
533         return this.add.apply(this, arguments);
534     },
535
536     /**
537      * Adds a button (or buttons). See {@link Ext.Button} for more info on the config.
538      * <br><p><b>Note</b>: See the notes within {@link Ext.Container#add}.</p>
539      * @param {Object/Array} config A button config or array of configs
540      * @return {Ext.Button/Array}
541      */
542     addButton : function(config){
543         if(Ext.isArray(config)){
544             var buttons = [];
545             for(var i = 0, len = config.length; i < len; i++) {
546                 buttons.push(this.addButton(config[i]));
547             }
548             return buttons;
549         }
550         return this.add(this.constructButton(config));
551     },
552
553     /**
554      * Adds text to the toolbar
555      * <br><p><b>Note</b>: See the notes within {@link Ext.Container#add}.</p>
556      * @param {String} text The text to add
557      * @return {Ext.Toolbar.Item} The element's item
558      */
559     addText : function(text){
560         return this.addItem(new T.TextItem(text));
561     },
562
563     /**
564      * Adds a new element to the toolbar from the passed {@link Ext.DomHelper} config
565      * <br><p><b>Note</b>: See the notes within {@link Ext.Container#add}.</p>
566      * @param {Object} config
567      * @return {Ext.Toolbar.Item} The element's item
568      */
569     addDom : function(config){
570         return this.add(new T.Item({autoEl: config}));
571     },
572
573     /**
574      * Adds a dynamically rendered Ext.form field (TextField, ComboBox, etc). Note: the field should not have
575      * been rendered yet. For a field that has already been rendered, use {@link #addElement}.
576      * <br><p><b>Note</b>: See the notes within {@link Ext.Container#add}.</p>
577      * @param {Ext.form.Field} field
578      * @return {Ext.Toolbar.Item}
579      */
580     addField : function(field){
581         return this.add(field);
582     },
583
584     /**
585      * Inserts any {@link Ext.Toolbar.Item}/{@link Ext.Button} at the specified index.
586      * <br><p><b>Note</b>: See the notes within {@link Ext.Container#add}.</p>
587      * @param {Number} index The index where the item is to be inserted
588      * @param {Object/Ext.Toolbar.Item/Ext.Button/Array} item The button, or button config object to be
589      * inserted, or an array of buttons/configs.
590      * @return {Ext.Button/Item}
591      */
592     insertButton : function(index, item){
593         if(Ext.isArray(item)){
594             var buttons = [];
595             for(var i = 0, len = item.length; i < len; i++) {
596                buttons.push(this.insertButton(index + i, item[i]));
597             }
598             return buttons;
599         }
600         return Ext.Toolbar.superclass.insert.call(this, index, item);
601     },
602
603     // private
604     trackMenu : function(item, remove){
605         if(this.trackMenus && item.menu){
606             var method = remove ? 'mun' : 'mon';
607             this[method](item, 'menutriggerover', this.onButtonTriggerOver, this);
608             this[method](item, 'menushow', this.onButtonMenuShow, this);
609             this[method](item, 'menuhide', this.onButtonMenuHide, this);
610         }
611     },
612
613     // private
614     constructButton : function(item){
615         var b = item.events ? item : this.createComponent(item, item.split ? 'splitbutton' : this.defaultType);
616         return b;
617     },
618
619     // private
620     onAdd : function(c){
621         Ext.Toolbar.superclass.onAdd.call(this);
622         this.trackMenu(c);
623     },
624
625     // private
626     onRemove : function(c){
627         Ext.Toolbar.superclass.onRemove.call(this);
628         this.trackMenu(c, true);
629     },
630
631     // private
632     onDisable : function(){
633         this.items.each(function(item){
634              if(item.disable){
635                  item.disable();
636              }
637         });
638     },
639
640     // private
641     onEnable : function(){
642         this.items.each(function(item){
643              if(item.enable){
644                  item.enable();
645              }
646         });
647     },
648
649     // private
650     onButtonTriggerOver : function(btn){
651         if(this.activeMenuBtn && this.activeMenuBtn != btn){
652             this.activeMenuBtn.hideMenu();
653             btn.showMenu();
654             this.activeMenuBtn = btn;
655         }
656     },
657
658     // private
659     onButtonMenuShow : function(btn){
660         this.activeMenuBtn = btn;
661     },
662
663     // private
664     onButtonMenuHide : function(btn){
665         delete this.activeMenuBtn;
666     }
667 });
668 Ext.reg('toolbar', Ext.Toolbar);
669
670 /**
671  * @class Ext.Toolbar.Item
672  * @extends Ext.BoxComponent
673  * The base class that other non-interacting Toolbar Item classes should extend in order to
674  * get some basic common toolbar item functionality.
675  * @constructor
676  * Creates a new Item
677  * @param {HTMLElement} el
678  * @xtype tbitem
679  */
680 T.Item = Ext.extend(Ext.BoxComponent, {
681     hideParent: true, //  Hiding a Toolbar.Item hides its containing TD
682     enable:Ext.emptyFn,
683     disable:Ext.emptyFn,
684     focus:Ext.emptyFn
685     /**
686      * @cfg {String} overflowText Text to be used for the menu if the item is overflowed.
687      */
688 });
689 Ext.reg('tbitem', T.Item);
690
691 /**
692  * @class Ext.Toolbar.Separator
693  * @extends Ext.Toolbar.Item
694  * A simple class that adds a vertical separator bar between toolbar items
695  * (css class:<tt>'xtb-sep'</tt>). Example usage:
696  * <pre><code>
697 new Ext.Panel({
698     tbar : [
699         'Item 1',
700         {xtype: 'tbseparator'}, // or '-'
701         'Item 2'
702     ]
703 });
704 </code></pre>
705  * @constructor
706  * Creates a new Separator
707  * @xtype tbseparator
708  */
709 T.Separator = Ext.extend(T.Item, {
710     onRender : function(ct, position){
711         this.el = ct.createChild({tag:'span', cls:'xtb-sep'}, position);
712     }
713 });
714 Ext.reg('tbseparator', T.Separator);
715
716 /**
717  * @class Ext.Toolbar.Spacer
718  * @extends Ext.Toolbar.Item
719  * A simple element that adds extra horizontal space between items in a toolbar.
720  * By default a 2px wide space is added via css specification:<pre><code>
721 .x-toolbar .xtb-spacer {
722     width:2px;
723 }
724  * </code></pre>
725  * <p>Example usage:</p>
726  * <pre><code>
727 new Ext.Panel({
728     tbar : [
729         'Item 1',
730         {xtype: 'tbspacer'}, // or ' '
731         'Item 2',
732         // space width is also configurable via javascript
733         {xtype: 'tbspacer', width: 50}, // add a 50px space
734         'Item 3'
735     ]
736 });
737 </code></pre>
738  * @constructor
739  * Creates a new Spacer
740  * @xtype tbspacer
741  */
742 T.Spacer = Ext.extend(T.Item, {
743     /**
744      * @cfg {Number} width
745      * The width of the spacer in pixels (defaults to 2px via css style <tt>.x-toolbar .xtb-spacer</tt>).
746      */
747
748     onRender : function(ct, position){
749         this.el = ct.createChild({tag:'div', cls:'xtb-spacer', style: this.width?'width:'+this.width+'px':''}, position);
750     }
751 });
752 Ext.reg('tbspacer', T.Spacer);
753
754 /**
755  * @class Ext.Toolbar.Fill
756  * @extends Ext.Toolbar.Spacer
757  * A non-rendering placeholder item which instructs the Toolbar's Layout to begin using
758  * the right-justified button container.
759  * <pre><code>
760 new Ext.Panel({
761     tbar : [
762         'Item 1',
763         {xtype: 'tbfill'}, // or '->'
764         'Item 2'
765     ]
766 });
767 </code></pre>
768  * @constructor
769  * Creates a new Fill
770  * @xtype tbfill
771  */
772 T.Fill = Ext.extend(T.Item, {
773     // private
774     render : Ext.emptyFn,
775     isFill : true
776 });
777 Ext.reg('tbfill', T.Fill);
778
779 /**
780  * @class Ext.Toolbar.TextItem
781  * @extends Ext.Toolbar.Item
782  * A simple class that renders text directly into a toolbar
783  * (with css class:<tt>'xtb-text'</tt>). Example usage:
784  * <pre><code>
785 new Ext.Panel({
786     tbar : [
787         {xtype: 'tbtext', text: 'Item 1'} // or simply 'Item 1'
788     ]
789 });
790 </code></pre>
791  * @constructor
792  * Creates a new TextItem
793  * @param {String/Object} text A text string, or a config object containing a <tt>text</tt> property
794  * @xtype tbtext
795  */
796 T.TextItem = Ext.extend(T.Item, {
797     /**
798      * @cfg {String} text The text to be used as innerHTML (html tags are accepted)
799      */
800
801     constructor: function(config){
802         T.TextItem.superclass.constructor.call(this, Ext.isString(config) ? {text: config} : config);
803     },
804
805     // private
806     onRender : function(ct, position) {
807         this.autoEl = {cls: 'xtb-text', html: this.text || ''};
808         T.TextItem.superclass.onRender.call(this, ct, position);
809     },
810
811     /**
812      * Updates this item's text, setting the text to be used as innerHTML.
813      * @param {String} t The text to display (html accepted).
814      */
815     setText : function(t) {
816         if(this.rendered){
817             this.el.update(t);
818         }else{
819             this.text = t;
820         }
821     }
822 });
823 Ext.reg('tbtext', T.TextItem);
824
825 // backwards compat
826 T.Button = Ext.extend(Ext.Button, {});
827 T.SplitButton = Ext.extend(Ext.SplitButton, {});
828 Ext.reg('tbbutton', T.Button);
829 Ext.reg('tbsplit', T.SplitButton);
830
831 })();