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