Upgrade to ExtJS 3.0.0 - Released 07/06/2009
[extjs.git] / docs / source / Button.html
1 <html>\r
2 <head>\r
3   <title>The source code</title>\r
4     <link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />\r
5     <script type="text/javascript" src="../resources/prettify/prettify.js"></script>\r
6 </head>\r
7 <body  onload="prettyPrint();">\r
8     <pre class="prettyprint lang-js"><div id="cls-Ext.Button"></div>/**
9  * @class Ext.Button
10  * @extends Ext.BoxComponent
11  * Simple Button class
12  * @cfg {String} text The button text to be used as innerHTML (html tags are accepted)
13  * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
14  * CSS property of the button by default, so if you want a mixed icon/text button, set cls:'x-btn-text-icon')
15  * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event).
16  * The handler is passed the following parameters:<div class="mdetail-params"><ul>
17  * <li><code>b</code> : Button<div class="sub-desc">This Button.</div></li>
18  * <li><code>e</code> : EventObject<div class="sub-desc">The click event.</div></li>
19  * </ul></div>
20  * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width).
21  * See also {@link Ext.Panel}.<tt>{@link Ext.Panel#minButtonWidth minButtonWidth}</tt>.
22  * @cfg {String/Object} tooltip The tooltip for the button - can be a string to be used as innerHTML (html tags are accepted) or QuickTips config object
23  * @cfg {Boolean} hidden True to start hidden (defaults to false)
24  * @cfg {Boolean} disabled True to start disabled (defaults to false)
25  * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
26  * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed)
27  * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
28  * a {@link Ext.util.ClickRepeater ClickRepeater} config object (defaults to false).
29  * @constructor
30  * Create a new button
31  * @param {Object} config The config object
32  * @xtype button
33  */
34 Ext.Button = Ext.extend(Ext.BoxComponent, {
35     /**
36      * Read-only. True if this button is hidden
37      * @type Boolean
38      */
39     hidden : false,
40     /**
41      * Read-only. True if this button is disabled
42      * @type Boolean
43      */
44     disabled : false,
45     /**
46      * Read-only. True if this button is pressed (only if enableToggle = true)
47      * @type Boolean
48      */
49     pressed : false,
50     /**
51      * The Button's owner {@link Ext.Panel} (defaults to undefined, and is set automatically when
52      * the Button is added to a container).  Read-only.
53      * @type Ext.Panel
54      * @property ownerCt
55      */
56
57     /**
58      * @cfg {Number} tabIndex Set a DOM tabIndex for this button (defaults to undefined)
59      */
60
61     /**
62      * @cfg {Boolean} allowDepress
63      * False to not allow a pressed Button to be depressed (defaults to undefined). Only valid when {@link #enableToggle} is true.
64      */
65
66     /**
67      * @cfg {Boolean} enableToggle
68      * True to enable pressed/not pressed toggling (defaults to false)
69      */
70     enableToggle : false,
71     /**
72      * @cfg {Function} toggleHandler
73      * Function called when a Button with {@link #enableToggle} set to true is clicked. Two arguments are passed:<ul class="mdetail-params">
74      * <li><b>button</b> : Ext.Button<div class="sub-desc">this Button object</div></li>
75      * <li><b>state</b> : Boolean<div class="sub-desc">The next state if the Button, true means pressed.</div></li>
76      * </ul>
77      */
78     /**
79      * @cfg {Mixed} menu
80      * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
81      */
82     /**
83      * @cfg {String} menuAlign
84      * The position to align the menu to (see {@link Ext.Element#alignTo} for more details, defaults to 'tl-bl?').
85      */
86     menuAlign : 'tl-bl?',
87
88     /**
89      * @cfg {String} overflowText If used in a {@link Ext.Toolbar Toolbar}, the
90      * text to be used if this item is shown in the overflow menu. See also
91      * {@link Ext.Toolbar.Item}.<code>{@link Ext.Toolbar.Item#overflowText overflowText}</code>.
92      */
93     /**
94      * @cfg {String} iconCls
95      * A css class which sets a background image to be used as the icon for this button
96      */
97     /**
98      * @cfg {String} type
99      * submit, reset or button - defaults to 'button'
100      */
101     type : 'button',
102
103     // private
104     menuClassTarget : 'tr:nth(2)',
105
106     /**
107      * @cfg {String} clickEvent
108      * The type of event to map to the button's event handler (defaults to 'click')
109      */
110     clickEvent : 'click',
111
112     /**
113      * @cfg {Boolean} handleMouseEvents
114      * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
115      */
116     handleMouseEvents : true,
117
118     /**
119      * @cfg {String} tooltipType
120      * The type of tooltip to use. Either 'qtip' (default) for QuickTips or 'title' for title attribute.
121      */
122     tooltipType : 'qtip',
123
124     /**
125      * @cfg {String} buttonSelector
126      * <p>(Optional) A {@link Ext.DomQuery DomQuery} selector which is used to extract the active, clickable element from the
127      * DOM structure created.</p>
128      * <p>When a custom {@link #template} is used, you  must ensure that this selector results in the selection of
129      * a focussable element.</p>
130      * <p>Defaults to <b><tt>'button:first-child'</tt></b>.</p>
131      */
132     buttonSelector : 'button:first-child',
133
134     /**
135      * @cfg {String} scale
136      * <p>(Optional) The size of the Button. Three values are allowed:</p>
137      * <ul class="mdetail-params">
138      * <li>'small'<div class="sub-desc">Results in the button element being 16px high.</div></li>
139      * <li>'medium'<div class="sub-desc">Results in the button element being 24px high.</div></li>
140      * <li>'large'<div class="sub-desc">Results in the button element being 32px high.</div></li>
141      * </ul>
142      * <p>Defaults to <b><tt>'small'</tt></b>.</p>
143      */
144     scale : 'small',
145
146     /**
147      * @cfg {Object} scope The scope (<tt><b>this</b></tt> reference) in which the
148      * <code>{@link #handler}</code> and <code>{@link #toggleHandler}</code> is
149      * executed. Defaults to this Button.
150      */
151
152     /**
153      * @cfg {String} iconAlign
154      * <p>(Optional) The side of the Button box to render the icon. Four values are allowed:</p>
155      * <ul class="mdetail-params">
156      * <li>'top'<div class="sub-desc"></div></li>
157      * <li>'right'<div class="sub-desc"></div></li>
158      * <li>'bottom'<div class="sub-desc"></div></li>
159      * <li>'left'<div class="sub-desc"></div></li>
160      * </ul>
161      * <p>Defaults to <b><tt>'left'</tt></b>.</p>
162      */
163     iconAlign : 'left',
164
165     /**
166      * @cfg {String} arrowAlign
167      * <p>(Optional) The side of the Button box to render the arrow if the button has an associated {@link #menu}.
168      * Two values are allowed:</p>
169      * <ul class="mdetail-params">
170      * <li>'right'<div class="sub-desc"></div></li>
171      * <li>'bottom'<div class="sub-desc"></div></li>
172      * </ul>
173      * <p>Defaults to <b><tt>'right'</tt></b>.</p>
174      */
175     arrowAlign : 'right',
176
177     /**
178      * @cfg {Ext.Template} template (Optional)
179      * <p>A {@link Ext.Template Template} used to create the Button's DOM structure.</p>
180      * Instances, or subclasses which need a different DOM structure may provide a different
181      * template layout in conjunction with an implementation of {@link #getTemplateArgs}.
182      * @type Ext.Template
183      * @property template
184      */
185     /**
186      * @cfg {String} cls
187      * A CSS class string to apply to the button's main element.
188      */
189     /**
190      * @property menu
191      * @type Menu
192      * The {@link Ext.menu.Menu Menu} object associated with this Button when configured with the {@link #menu} config option.
193      */
194
195     initComponent : function(){
196         Ext.Button.superclass.initComponent.call(this);
197
198         this.addEvents(
199             /**
200              * @event click
201              * Fires when this button is clicked
202              * @param {Button} this
203              * @param {EventObject} e The click event
204              */
205             'click',
206             /**
207              * @event toggle
208              * Fires when the 'pressed' state of this button changes (only if enableToggle = true)
209              * @param {Button} this
210              * @param {Boolean} pressed
211              */
212             'toggle',
213             /**
214              * @event mouseover
215              * Fires when the mouse hovers over the button
216              * @param {Button} this
217              * @param {Event} e The event object
218              */
219             'mouseover',
220             /**
221              * @event mouseout
222              * Fires when the mouse exits the button
223              * @param {Button} this
224              * @param {Event} e The event object
225              */
226             'mouseout',
227             /**
228              * @event menushow
229              * If this button has a menu, this event fires when it is shown
230              * @param {Button} this
231              * @param {Menu} menu
232              */
233             'menushow',
234             /**
235              * @event menuhide
236              * If this button has a menu, this event fires when it is hidden
237              * @param {Button} this
238              * @param {Menu} menu
239              */
240             'menuhide',
241             /**
242              * @event menutriggerover
243              * If this button has a menu, this event fires when the mouse enters the menu triggering element
244              * @param {Button} this
245              * @param {Menu} menu
246              * @param {EventObject} e
247              */
248             'menutriggerover',
249             /**
250              * @event menutriggerout
251              * If this button has a menu, this event fires when the mouse leaves the menu triggering element
252              * @param {Button} this
253              * @param {Menu} menu
254              * @param {EventObject} e
255              */
256             'menutriggerout'
257         );
258         if(this.menu){
259             this.menu = Ext.menu.MenuMgr.get(this.menu);
260         }
261         if(Ext.isString(this.toggleGroup)){
262             this.enableToggle = true;
263         }
264     },
265
266 /**
267   * <p>This method returns an object which provides substitution parameters for the {@link #template Template} used
268   * to create this Button's DOM structure.</p>
269   * <p>Instances or subclasses which use a different Template to create a different DOM structure may need to provide their
270   * own implementation of this method.</p>
271   * <p>The default implementation which provides data for the default {@link #template} returns an Array containing the
272   * following items:</p><div class="mdetail-params"><ul>
273   * <li>The Button's {@link #text}</li>
274   * <li>The &lt;button&gt;'s {@link #type}</li>
275   * <li>The {@link iconCls} applied to the &lt;button&gt; {@link #btnEl element}</li>
276   * <li>The {@link #cls} applied to the Button's main {@link #getEl Element}</li>
277   * <li>A CSS class name controlling the Button's {@link #scale} and {@link #iconAlign icon alignment}</li>
278   * <li>A CSS class name which applies an arrow to the Button if configured with a {@link #menu}</li>
279   * </ul></div>
280   * @return {Object} Substitution data for a Template.
281  */
282     getTemplateArgs : function(){
283         var cls = (this.cls || '');
284         cls += (this.iconCls || this.icon) ? (this.text ? ' x-btn-text-icon' : ' x-btn-icon') : ' x-btn-noicon';
285         if(this.pressed){
286             cls += ' x-btn-pressed';
287         }
288         return [this.text || '&#160;', this.type, this.iconCls || '', cls, 'x-btn-' + this.scale + ' x-btn-icon-' + this.scale + '-' + this.iconAlign, this.getMenuClass()];
289     },
290
291     // protected
292     getMenuClass : function(){
293         return this.menu ? (this.arrowAlign != 'bottom' ? 'x-btn-arrow' : 'x-btn-arrow-bottom') : '';
294     },
295
296     // private
297     onRender : function(ct, position){
298         if(!this.template){
299             if(!Ext.Button.buttonTemplate){
300                 // hideous table template
301                 Ext.Button.buttonTemplate = new Ext.Template(
302                     '<table cellspacing="0" class="x-btn {3}"><tbody class="{4}">',
303                     '<tr><td class="x-btn-tl"><i>&#160;</i></td><td class="x-btn-tc"></td><td class="x-btn-tr"><i>&#160;</i></td></tr>',
304                     '<tr><td class="x-btn-ml"><i>&#160;</i></td><td class="x-btn-mc"><em class="{5}" unselectable="on"><button class="x-btn-text {2}" type="{1}">{0}</button></em></td><td class="x-btn-mr"><i>&#160;</i></td></tr>',
305                     '<tr><td class="x-btn-bl"><i>&#160;</i></td><td class="x-btn-bc"></td><td class="x-btn-br"><i>&#160;</i></td></tr>',
306                     "</tbody></table>");
307                 Ext.Button.buttonTemplate.compile();
308             }
309             this.template = Ext.Button.buttonTemplate;
310         }
311
312         var btn, targs = this.getTemplateArgs();
313
314         if(position){
315             btn = this.template.insertBefore(position, targs, true);
316         }else{
317             btn = this.template.append(ct, targs, true);
318         }
319         /**
320          * An {@link Ext.Element Element} encapsulating the Button's clickable element. By default,
321          * this references a <tt>&lt;button&gt;</tt> element. Read only.
322          * @type Ext.Element
323          * @property btnEl
324          */
325         this.btnEl = btn.child(this.buttonSelector);
326         this.mon(this.btnEl, {
327             scope: this,
328             focus: this.onFocus,
329             blur: this.onBlur
330         });
331
332         this.initButtonEl(btn, this.btnEl);
333
334         Ext.ButtonToggleMgr.register(this);
335     },
336
337     // private
338     initButtonEl : function(btn, btnEl){
339         this.el = btn;
340
341         if(this.id){
342             this.el.dom.id = this.el.id = this.id;
343         }
344         if(this.icon){
345             btnEl.setStyle('background-image', 'url(' +this.icon +')');
346         }
347         if(this.tabIndex !== undefined){
348             btnEl.dom.tabIndex = this.tabIndex;
349         }
350         if(this.tooltip){
351             this.setTooltip(this.tooltip, true);
352         }
353
354         if(this.handleMouseEvents){
355             this.mon(btn, {
356                 scope: this,
357                 mouseover: this.onMouseOver,
358                 mousedown: this.onMouseDown
359             });
360
361             // new functionality for monitoring on the document level
362             //this.mon(btn, 'mouseout', this.onMouseOut, this);
363         }
364
365         if(this.menu){
366             this.mon(this.menu, {
367                 scope: this,
368                 show: this.onMenuShow,
369                 hide: this.onMenuHide
370             });
371         }
372
373         if(this.repeat){
374             var repeater = new Ext.util.ClickRepeater(btn, Ext.isObject(this.repeat) ? this.repeat : {});
375             this.mon(repeater, 'click', this.onClick, this);
376         }
377
378         this.mon(btn, this.clickEvent, this.onClick, this);
379     },
380
381     // private
382     afterRender : function(){
383         Ext.Button.superclass.afterRender.call(this);
384         this.doAutoWidth();
385     },
386
387     /**
388      * Sets the CSS class that provides a background image to use as the button's icon.  This method also changes
389      * the value of the {@link iconCls} config internally.
390      * @param {String} cls The CSS class providing the icon image
391      * @return {Ext.Button} this
392      */
393     setIconClass : function(cls){
394         if(this.el){
395             this.btnEl.replaceClass(this.iconCls, cls);
396         }
397         this.iconCls = cls;
398         return this;
399     },
400
401     /**
402      * Sets the tooltip for this Button.
403      * @param {String/Object} tooltip. This may be:<div class="mdesc-details"><ul>
404      * <li><b>String</b> : A string to be used as innerHTML (html tags are accepted) to show in a tooltip</li>
405      * <li><b>Object</b> : A configuration object for {@link Ext.QuickTips#register}.</li>
406      * </ul></div>
407      * @return {Ext.Button} this
408      */
409     setTooltip : function(tooltip, /* private */ initial){
410         if(this.rendered){
411             if(!initial){
412                 this.clearTip();
413             }
414             if(Ext.isObject(tooltip)){
415                 Ext.QuickTips.register(Ext.apply({
416                       target: this.btnEl.id
417                 }, tooltip));
418                 this.tooltip = tooltip;
419             }else{
420                 this.btnEl.dom[this.tooltipType] = tooltip;
421             }
422         }else{
423             this.tooltip = tooltip;
424         }
425         return this;
426     },
427
428     // private
429     clearTip : function(){
430         if(Ext.isObject(this.tooltip)){
431             Ext.QuickTips.unregister(this.btnEl);
432         }
433     },
434
435     // private
436     beforeDestroy : function(){
437         if(this.rendered){
438             this.clearTip();
439         }
440         Ext.destroy(this.menu, this.repeater);
441     },
442
443     // private
444     onDestroy : function(){
445         var doc = Ext.getDoc();
446         doc.un('mouseover', this.monitorMouseOver, this);
447         doc.un('mouseup', this.onMouseUp, this);
448         if(this.rendered){
449             Ext.ButtonToggleMgr.unregister(this);
450         }
451     },
452
453     // private
454     doAutoWidth : function(){
455         if(this.el && this.text && this.width === undefined){
456             this.el.setWidth('auto');
457             if(Ext.isIE7 && Ext.isStrict){
458                 var ib = this.btnEl;
459                 if(ib && ib.getWidth() > 20){
460                     ib.clip();
461                     ib.setWidth(Ext.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
462                 }
463             }
464             if(this.minWidth){
465                 if(this.el.getWidth() < this.minWidth){
466                     this.el.setWidth(this.minWidth);
467                 }
468             }
469         }
470     },
471
472     /**
473      * Assigns this Button's click handler
474      * @param {Function} handler The function to call when the button is clicked
475      * @param {Object} scope (optional) Scope for the function passed in. Defaults to this Button.
476      * @return {Ext.Button} this
477      */
478     setHandler : function(handler, scope){
479         this.handler = handler;
480         this.scope = scope;
481         return this;
482     },
483
484     /**
485      * Sets this Button's text
486      * @param {String} text The button text
487      * @return {Ext.Button} this
488      */
489     setText : function(text){
490         this.text = text;
491         if(this.el){
492             this.el.child('td.x-btn-mc ' + this.buttonSelector).update(text);
493         }
494         this.doAutoWidth();
495         return this;
496     },
497
498     /**
499      * Gets the text for this Button
500      * @return {String} The button text
501      */
502     getText : function(){
503         return this.text;
504     },
505
506     /**
507      * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
508      * @param {Boolean} state (optional) Force a particular state
509      * @param {Boolean} supressEvent (optional) True to stop events being fired when calling this method.
510      * @return {Ext.Button} this
511      */
512     toggle : function(state, suppressEvent){
513         state = state === undefined ? !this.pressed : !!state;
514         if(state != this.pressed){
515             if(this.rendered){
516                 this.el[state ? 'addClass' : 'removeClass']('x-btn-pressed');
517             }
518             this.pressed = state;
519             if(!suppressEvent){
520                 this.fireEvent('toggle', this, state);
521                 if(this.toggleHandler){
522                     this.toggleHandler.call(this.scope || this, this, state);
523                 }
524             }
525         }
526         return this;
527     },
528
529     /**
530      * Focus the button
531      */
532     focus : function(){
533         this.btnEl.focus();
534     },
535
536     // private
537     onDisable : function(){
538         this.onDisableChange(true);
539     },
540
541     // private
542     onEnable : function(){
543         this.onDisableChange(false);
544     },
545
546     onDisableChange : function(disabled){
547         if(this.el){
548             if(!Ext.isIE6 || !this.text){
549                 this.el[disabled ? 'addClass' : 'removeClass'](this.disabledClass);
550             }
551             this.el.dom.disabled = disabled;
552         }
553         this.disabled = disabled;
554     },
555
556     /**
557      * Show this button's menu (if it has one)
558      */
559     showMenu : function(){
560         if(this.rendered && this.menu){
561             if(this.tooltip){
562                 Ext.QuickTips.getQuickTip().cancelShow(this.btnEl);
563             }
564             this.menu.show(this.el, this.menuAlign);
565         }
566         return this;
567     },
568
569     /**
570      * Hide this button's menu (if it has one)
571      */
572     hideMenu : function(){
573         if(this.menu){
574             this.menu.hide();
575         }
576         return this;
577     },
578
579     /**
580      * Returns true if the button has a menu and it is visible
581      * @return {Boolean}
582      */
583     hasVisibleMenu : function(){
584         return this.menu && this.menu.isVisible();
585     },
586
587     // private
588     onClick : function(e){
589         if(e){
590             e.preventDefault();
591         }
592         if(e.button !== 0){
593             return;
594         }
595         if(!this.disabled){
596             if(this.enableToggle && (this.allowDepress !== false || !this.pressed)){
597                 this.toggle();
598             }
599             if(this.menu && !this.menu.isVisible() && !this.ignoreNextClick){
600                 this.showMenu();
601             }
602             this.fireEvent('click', this, e);
603             if(this.handler){
604                 //this.el.removeClass('x-btn-over');
605                 this.handler.call(this.scope || this, this, e);
606             }
607         }
608     },
609
610     // private
611     isMenuTriggerOver : function(e, internal){
612         return this.menu && !internal;
613     },
614
615     // private
616     isMenuTriggerOut : function(e, internal){
617         return this.menu && !internal;
618     },
619
620     // private
621     onMouseOver : function(e){
622         if(!this.disabled){
623             var internal = e.within(this.el,  true);
624             if(!internal){
625                 this.el.addClass('x-btn-over');
626                 if(!this.monitoringMouseOver){
627                     Ext.getDoc().on('mouseover', this.monitorMouseOver, this);
628                     this.monitoringMouseOver = true;
629                 }
630                 this.fireEvent('mouseover', this, e);
631             }
632             if(this.isMenuTriggerOver(e, internal)){
633                 this.fireEvent('menutriggerover', this, this.menu, e);
634             }
635         }
636     },
637
638     // private
639     monitorMouseOver : function(e){
640         if(e.target != this.el.dom && !e.within(this.el)){
641             if(this.monitoringMouseOver){
642                 Ext.getDoc().un('mouseover', this.monitorMouseOver, this);
643                 this.monitoringMouseOver = false;
644             }
645             this.onMouseOut(e);
646         }
647     },
648
649     // private
650     onMouseOut : function(e){
651         var internal = e.within(this.el) && e.target != this.el.dom;
652         this.el.removeClass('x-btn-over');
653         this.fireEvent('mouseout', this, e);
654         if(this.isMenuTriggerOut(e, internal)){
655             this.fireEvent('menutriggerout', this, this.menu, e);
656         }
657     },
658     // private
659     onFocus : function(e){
660         if(!this.disabled){
661             this.el.addClass('x-btn-focus');
662         }
663     },
664     // private
665     onBlur : function(e){
666         this.el.removeClass('x-btn-focus');
667     },
668
669     // private
670     getClickEl : function(e, isUp){
671        return this.el;
672     },
673
674     // private
675     onMouseDown : function(e){
676         if(!this.disabled && e.button === 0){
677             this.getClickEl(e).addClass('x-btn-click');
678             Ext.getDoc().on('mouseup', this.onMouseUp, this);
679         }
680     },
681     // private
682     onMouseUp : function(e){
683         if(e.button === 0){
684             this.getClickEl(e, true).removeClass('x-btn-click');
685             Ext.getDoc().un('mouseup', this.onMouseUp, this);
686         }
687     },
688     // private
689     onMenuShow : function(e){
690         this.ignoreNextClick = 0;
691         this.el.addClass('x-btn-menu-active');
692         this.fireEvent('menushow', this, this.menu);
693     },
694     // private
695     onMenuHide : function(e){
696         this.el.removeClass('x-btn-menu-active');
697         this.ignoreNextClick = this.restoreClick.defer(250, this);
698         this.fireEvent('menuhide', this, this.menu);
699     },
700
701     // private
702     restoreClick : function(){
703         this.ignoreNextClick = 0;
704     }
705
706
707
708     /**
709      * @cfg {String} autoEl @hide
710      */
711 });
712 Ext.reg('button', Ext.Button);
713
714 // Private utility class used by Button
715 Ext.ButtonToggleMgr = function(){
716    var groups = {};
717
718    function toggleGroup(btn, state){
719        if(state){
720            var g = groups[btn.toggleGroup];
721            for(var i = 0, l = g.length; i < l; i++){
722                if(g[i] != btn){
723                    g[i].toggle(false);
724                }
725            }
726        }
727    }
728
729    return {
730        register : function(btn){
731            if(!btn.toggleGroup){
732                return;
733            }
734            var g = groups[btn.toggleGroup];
735            if(!g){
736                g = groups[btn.toggleGroup] = [];
737            }
738            g.push(btn);
739            btn.on('toggle', toggleGroup);
740        },
741
742        unregister : function(btn){
743            if(!btn.toggleGroup){
744                return;
745            }
746            var g = groups[btn.toggleGroup];
747            if(g){
748                g.remove(btn);
749                btn.un('toggle', toggleGroup);
750            }
751        },
752
753        /**
754         * Gets the pressed button in the passed group or null
755         * @param {String} group
756         * @return Button
757         */
758        getPressed : function(group){
759            var g = groups[group];
760            if(g){
761                for(var i = 0, len = g.length; i < len; i++){
762                    if(g[i].pressed === true){
763                        return g[i];
764                    }
765                }
766            }
767            return null;
768        }
769    };
770 }();</pre>    \r
771 </body>\r
772 </html>