Roo/Toolbar.js
[roojs1] / Roo / Toolbar.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 /**
13  * @class Roo.Toolbar
14  * Basic Toolbar class.
15  * @constructor
16  * Creates a new Toolbar
17  * @param {Object} container The config object
18  */ 
19 Roo.Toolbar = function(container, buttons, config)
20 {
21     /// old consturctor format still supported..
22     if(container instanceof Array){ // omit the container for later rendering
23         buttons = container;
24         config = buttons;
25         container = null;
26     }
27     if (typeof(container) == 'object' && container.xtype) {
28         config = container;
29         container = config.container;
30         buttons = config.buttons || []; // not really - use items!!
31     }
32     var xitems = [];
33     if (config && config.items) {
34         xitems = config.items;
35         delete config.items;
36     }
37     Roo.apply(this, config);
38     this.buttons = buttons;
39     
40     if(container){
41         this.render(container);
42     }
43     this.xitems = xitems;
44     Roo.each(xitems, function(b) {
45         this.add(b);
46     }, this);
47     
48 };
49
50 Roo.Toolbar.prototype = {
51     /**
52      * @cfg {Array} items
53      * array of button configs or elements to add (will be converted to a MixedCollection)
54      */
55     
56     /**
57      * @cfg {String/HTMLElement/Element} container
58      * The id or element that will contain the toolbar
59      */
60     // private
61     render : function(ct){
62         this.el = Roo.get(ct);
63         if(this.cls){
64             this.el.addClass(this.cls);
65         }
66         // using a table allows for vertical alignment
67         // 100% width is needed by Safari...
68         this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
69         this.tr = this.el.child("tr", true);
70         var autoId = 0;
71         this.items = new Roo.util.MixedCollection(false, function(o){
72             return o.id || ("item" + (++autoId));
73         });
74         if(this.buttons){
75             this.add.apply(this, this.buttons);
76             delete this.buttons;
77         }
78     },
79
80     /**
81      * Adds element(s) to the toolbar -- this function takes a variable number of 
82      * arguments of mixed type and adds them to the toolbar.
83      * @param {Mixed} arg1 The following types of arguments are all valid:<br />
84      * <ul>
85      * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
86      * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
87      * <li>Field: Any form field (equivalent to {@link #addField})</li>
88      * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
89      * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
90      * Note that there are a few special strings that are treated differently as explained nRoo.</li>
91      * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
92      * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
93      * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
94      * </ul>
95      * @param {Mixed} arg2
96      * @param {Mixed} etc.
97      */
98     add : function(){
99         var a = arguments, l = a.length;
100         for(var i = 0; i < l; i++){
101             this._add(a[i]);
102         }
103     },
104     // private..
105     _add : function(el) {
106         
107         if (el.xtype) {
108             el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
109         }
110         
111         if (el.applyTo){ // some kind of form field
112             return this.addField(el);
113         } 
114         if (el.render){ // some kind of Toolbar.Item
115             return this.addItem(el);
116         }
117         if (typeof el == "string"){ // string
118             if(el == "separator" || el == "-"){
119                 return this.addSeparator();
120             }
121             if (el == " "){
122                 return this.addSpacer();
123             }
124             if(el == "->"){
125                 return this.addFill();
126             }
127             return this.addText(el);
128             
129         }
130         if(el.tagName){ // element
131             return this.addElement(el);
132         }
133         if(typeof el == "object"){ // must be button config?
134             return this.addButton(el);
135         }
136         // and now what?!?!
137         return false;
138         
139     },
140     
141     /**
142      * Add an Xtype element
143      * @param {Object} xtype Xtype Object
144      * @return {Object} created Object
145      */
146     addxtype : function(e){
147         return this.add(e);  
148     },
149     
150     /**
151      * Returns the Element for this toolbar.
152      * @return {Roo.Element}
153      */
154     getEl : function(){
155         return this.el;  
156     },
157     
158     /**
159      * Adds a separator
160      * @return {Roo.Toolbar.Item} The separator item
161      */
162     addSeparator : function(){
163         return this.addItem(new Roo.Toolbar.Separator());
164     },
165
166     /**
167      * Adds a spacer element
168      * @return {Roo.Toolbar.Spacer} The spacer item
169      */
170     addSpacer : function(){
171         return this.addItem(new Roo.Toolbar.Spacer());
172     },
173
174     /**
175      * Adds a fill element that forces subsequent additions to the right side of the toolbar
176      * @return {Roo.Toolbar.Fill} The fill item
177      */
178     addFill : function(){
179         return this.addItem(new Roo.Toolbar.Fill());
180     },
181
182     /**
183      * Adds any standard HTML element to the toolbar
184      * @param {String/HTMLElement/Element} el The element or id of the element to add
185      * @return {Roo.Toolbar.Item} The element's item
186      */
187     addElement : function(el){
188         return this.addItem(new Roo.Toolbar.Item(el));
189     },
190     /**
191      * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
192      * @type Roo.util.MixedCollection  
193      */
194     items : false,
195      
196     /**
197      * Adds any Toolbar.Item or subclass
198      * @param {Roo.Toolbar.Item} item
199      * @return {Roo.Toolbar.Item} The item
200      */
201     addItem : function(item){
202         var td = this.nextBlock();
203         item.render(td);
204         this.items.add(item);
205         return item;
206     },
207     
208     /**
209      * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
210      * @param {Object/Array} config A button config or array of configs
211      * @return {Roo.Toolbar.Button/Array}
212      */
213     addButton : function(config){
214         if(config instanceof Array){
215             var buttons = [];
216             for(var i = 0, len = config.length; i < len; i++) {
217                 buttons.push(this.addButton(config[i]));
218             }
219             return buttons;
220         }
221         var b = config;
222         if(!(config instanceof Roo.Toolbar.Button)){
223             b = config.split ?
224                 new Roo.Toolbar.SplitButton(config) :
225                 new Roo.Toolbar.Button(config);
226         }
227         var td = this.nextBlock();
228         b.render(td);
229         this.items.add(b);
230         return b;
231     },
232     
233     /**
234      * Adds text to the toolbar
235      * @param {String} text The text to add
236      * @return {Roo.Toolbar.Item} The element's item
237      */
238     addText : function(text){
239         return this.addItem(new Roo.Toolbar.TextItem(text));
240     },
241     
242     /**
243      * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
244      * @param {Number} index The index where the item is to be inserted
245      * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
246      * @return {Roo.Toolbar.Button/Item}
247      */
248     insertButton : function(index, item){
249         if(item instanceof Array){
250             var buttons = [];
251             for(var i = 0, len = item.length; i < len; i++) {
252                buttons.push(this.insertButton(index + i, item[i]));
253             }
254             return buttons;
255         }
256         if (!(item instanceof Roo.Toolbar.Button)){
257            item = new Roo.Toolbar.Button(item);
258         }
259         var td = document.createElement("td");
260         this.tr.insertBefore(td, this.tr.childNodes[index]);
261         item.render(td);
262         this.items.insert(index, item);
263         return item;
264     },
265     
266     /**
267      * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
268      * @param {Object} config
269      * @return {Roo.Toolbar.Item} The element's item
270      */
271     addDom : function(config, returnEl){
272         var td = this.nextBlock();
273         Roo.DomHelper.overwrite(td, config);
274         var ti = new Roo.Toolbar.Item(td.firstChild);
275         ti.render(td);
276         this.items.add(ti);
277         return ti;
278     },
279
280     /**
281      * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
282      * @type Roo.util.MixedCollection  
283      */
284     fields : false,
285     
286     /**
287      * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc).
288      * Note: the field should not have been rendered yet. For a field that has already been
289      * rendered, use {@link #addElement}.
290      * @param {Roo.form.Field} field
291      * @return {Roo.ToolbarItem}
292      */
293      
294       
295     addField : function(field) {
296         if (!this.fields) {
297             var autoId = 0;
298             this.fields = new Roo.util.MixedCollection(false, function(o){
299                 return o.id || ("item" + (++autoId));
300             });
301
302         }
303         
304         var td = this.nextBlock();
305         field.render(td);
306         var ti = new Roo.Toolbar.Item(td.firstChild);
307         ti.render(td);
308         this.items.add(ti);
309         this.fields.add(field);
310         return ti;
311     },
312     /**
313      * Hide the toolbar
314      * @method hide
315      */
316      
317       
318     hide : function()
319     {
320         this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
321         this.el.child('div').hide();
322     },
323     /**
324      * Show the toolbar
325      * @method show
326      */
327     show : function()
328     {
329         this.el.child('div').show();
330     },
331       
332     // private
333     nextBlock : function(){
334         var td = document.createElement("td");
335         this.tr.appendChild(td);
336         return td;
337     },
338
339     // private
340     destroy : function(){
341         if(this.items){ // rendered?
342             Roo.destroy.apply(Roo, this.items.items);
343         }
344         if(this.fields){ // rendered?
345             Roo.destroy.apply(Roo, this.fields.items);
346         }
347         Roo.Element.uncache(this.el, this.tr);
348     }
349 };
350
351 /**
352  * @class Roo.Toolbar.Item
353  * The base class that other classes should extend in order to get some basic common toolbar item functionality.
354  * @constructor
355  * Creates a new Item
356  * @param {HTMLElement} el 
357  */
358 Roo.Toolbar.Item = function(el){
359     this.el = Roo.getDom(el);
360     this.id = Roo.id(this.el);
361     this.hidden = false;
362     
363     this.addEvents({
364          /**
365              * @event render
366              * Fires when the button is rendered
367              * @param {Button} this
368              */
369         'render': true
370     });
371     Roo.Toolbar.Item.superclass.constructor.call(this);
372 };
373 Roo.extend(Roo.Toolbar.Item, Roo.util.Observable, {
374 //Roo.Toolbar.Item.prototype = {
375     
376     /**
377      * Get this item's HTML Element
378      * @return {HTMLElement}
379      */
380     getEl : function(){
381        return this.el;  
382     },
383
384     // private
385     render : function(td){
386         
387         Roo.log("Toolbar Item - render");
388         this.td = td;
389         td.appendChild(this.el);
390         
391         this.fireEvent('render', this);
392     },
393     
394     /**
395      * Removes and destroys this item.
396      */
397     destroy : function(){
398         this.td.parentNode.removeChild(this.td);
399     },
400     
401     /**
402      * Shows this item.
403      */
404     show: function(){
405         this.hidden = false;
406         this.td.style.display = "";
407     },
408     
409     /**
410      * Hides this item.
411      */
412     hide: function(){
413         this.hidden = true;
414         this.td.style.display = "none";
415     },
416     
417     /**
418      * Convenience function for boolean show/hide.
419      * @param {Boolean} visible true to show/false to hide
420      */
421     setVisible: function(visible){
422         if(visible) {
423             this.show();
424         }else{
425             this.hide();
426         }
427     },
428     
429     /**
430      * Try to focus this item.
431      */
432     focus : function(){
433         Roo.fly(this.el).focus();
434     },
435     
436     /**
437      * Disables this item.
438      */
439     disable : function(){
440         Roo.fly(this.td).addClass("x-item-disabled");
441         this.disabled = true;
442         this.el.disabled = true;
443     },
444     
445     /**
446      * Enables this item.
447      */
448     enable : function(){
449         Roo.fly(this.td).removeClass("x-item-disabled");
450         this.disabled = false;
451         this.el.disabled = false;
452     }
453 });
454
455
456 /**
457  * @class Roo.Toolbar.Separator
458  * @extends Roo.Toolbar.Item
459  * A simple toolbar separator class
460  * @constructor
461  * Creates a new Separator
462  */
463 Roo.Toolbar.Separator = function(){
464     var s = document.createElement("span");
465     s.className = "ytb-sep";
466     Roo.Toolbar.Separator.superclass.constructor.call(this, s);
467 };
468 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
469     enable:Roo.emptyFn,
470     disable:Roo.emptyFn,
471     focus:Roo.emptyFn
472 });
473
474 /**
475  * @class Roo.Toolbar.Spacer
476  * @extends Roo.Toolbar.Item
477  * A simple element that adds extra horizontal space to a toolbar.
478  * @constructor
479  * Creates a new Spacer
480  */
481 Roo.Toolbar.Spacer = function(){
482     var s = document.createElement("div");
483     s.className = "ytb-spacer";
484     Roo.Toolbar.Spacer.superclass.constructor.call(this, s);
485 };
486 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
487     enable:Roo.emptyFn,
488     disable:Roo.emptyFn,
489     focus:Roo.emptyFn
490 });
491
492 /**
493  * @class Roo.Toolbar.Fill
494  * @extends Roo.Toolbar.Spacer
495  * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
496  * @constructor
497  * Creates a new Spacer
498  */
499 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
500     // private
501     render : function(td){
502         td.style.width = '100%';
503         Roo.Toolbar.Fill.superclass.render.call(this, td);
504     }
505 });
506
507 /**
508  * @class Roo.Toolbar.TextItem
509  * @extends Roo.Toolbar.Item
510  * A simple class that renders text directly into a toolbar.
511  * @constructor
512  * Creates a new TextItem
513  * @param {String} text
514  */
515 Roo.Toolbar.TextItem = function(text){
516     if (typeof(text) == 'object') {
517         text = text.text;
518     }
519     var s = document.createElement("span");
520     s.className = "ytb-text";
521     s.innerHTML = text;
522     Roo.Toolbar.TextItem.superclass.constructor.call(this, s);
523 };
524 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
525     
526      
527     enable:Roo.emptyFn,
528     disable:Roo.emptyFn,
529     focus:Roo.emptyFn
530 });
531
532 /**
533  * @class Roo.Toolbar.Button
534  * @extends Roo.Button
535  * A button that renders into a toolbar.
536  * @constructor
537  * Creates a new Button
538  * @param {Object} config A standard {@link Roo.Button} config object
539  */
540 Roo.Toolbar.Button = function(config){
541     Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
542 };
543 Roo.extend(Roo.Toolbar.Button, Roo.Button, {
544     render : function(td){
545         this.td = td;
546         Roo.Toolbar.Button.superclass.render.call(this, td);
547     },
548     
549     /**
550      * Removes and destroys this button
551      */
552     destroy : function(){
553         Roo.Toolbar.Button.superclass.destroy.call(this);
554         this.td.parentNode.removeChild(this.td);
555     },
556     
557     /**
558      * Shows this button
559      */
560     show: function(){
561         this.hidden = false;
562         this.td.style.display = "";
563     },
564     
565     /**
566      * Hides this button
567      */
568     hide: function(){
569         this.hidden = true;
570         this.td.style.display = "none";
571     },
572
573     /**
574      * Disables this item
575      */
576     disable : function(){
577         Roo.fly(this.td).addClass("x-item-disabled");
578         this.disabled = true;
579     },
580
581     /**
582      * Enables this item
583      */
584     enable : function(){
585         Roo.fly(this.td).removeClass("x-item-disabled");
586         this.disabled = false;
587     }
588 });
589 // backwards compat
590 Roo.ToolbarButton = Roo.Toolbar.Button;
591
592 /**
593  * @class Roo.Toolbar.SplitButton
594  * @extends Roo.SplitButton
595  * A menu button that renders into a toolbar.
596  * @constructor
597  * Creates a new SplitButton
598  * @param {Object} config A standard {@link Roo.SplitButton} config object
599  */
600 Roo.Toolbar.SplitButton = function(config){
601     Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
602 };
603 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
604     render : function(td){
605         this.td = td;
606         Roo.Toolbar.SplitButton.superclass.render.call(this, td);
607     },
608     
609     /**
610      * Removes and destroys this button
611      */
612     destroy : function(){
613         Roo.Toolbar.SplitButton.superclass.destroy.call(this);
614         this.td.parentNode.removeChild(this.td);
615     },
616     
617     /**
618      * Shows this button
619      */
620     show: function(){
621         this.hidden = false;
622         this.td.style.display = "";
623     },
624     
625     /**
626      * Hides this button
627      */
628     hide: function(){
629         this.hidden = true;
630         this.td.style.display = "none";
631     }
632 });
633
634 // backwards compat
635 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;