commit extjs-2.2.1
[extjs.git] / source / widgets / SplitButton.js
1 /*\r
2  * Ext JS Library 2.2.1\r
3  * Copyright(c) 2006-2009, Ext JS, LLC.\r
4  * licensing@extjs.com\r
5  * \r
6  * http://extjs.com/license\r
7  */\r
8 \r
9 /**\r
10  * @class Ext.SplitButton\r
11  * @extends Ext.Button\r
12  * A split button that provides a built-in dropdown arrow that can fire an event separately from the default\r
13  * click event of the button.  Typically this would be used to display a dropdown menu that provides additional\r
14  * options to the primary button action, but any custom handler can provide the arrowclick implementation.  Example usage:\r
15  * <pre><code>\r
16 // display a dropdown menu:\r
17 new Ext.SplitButton({\r
18         renderTo: 'button-ct', // the container id\r
19         text: 'Options',\r
20         handler: optionsHandler, // handle a click on the button itself\r
21         menu: new Ext.menu.Menu({\r
22         items: [\r
23                 // these items will render as dropdown menu items when the arrow is clicked:\r
24                 {text: 'Item 1', handler: item1Handler},\r
25                 {text: 'Item 2', handler: item2Handler}\r
26         ]\r
27         })\r
28 });\r
29 \r
30 // Instead of showing a menu, you provide any type of custom\r
31 // functionality you want when the dropdown arrow is clicked:\r
32 new Ext.SplitButton({\r
33         renderTo: 'button-ct',\r
34         text: 'Options',\r
35         handler: optionsHandler,\r
36         arrowHandler: myCustomHandler\r
37 });\r
38 </code></pre>\r
39  * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)\r
40  * @cfg {String} arrowTooltip The title attribute of the arrow\r
41  * @constructor\r
42  * Create a new menu button\r
43  * @param {Object} config The config object\r
44  */\r
45 Ext.SplitButton = Ext.extend(Ext.Button, {\r
46         // private\r
47     arrowSelector : 'button:last',\r
48 \r
49     // private\r
50     initComponent : function(){\r
51         Ext.SplitButton.superclass.initComponent.call(this);\r
52         /**\r
53          * @event arrowclick\r
54          * Fires when this button's arrow is clicked\r
55          * @param {MenuButton} this\r
56          * @param {EventObject} e The click event\r
57          */\r
58         this.addEvents("arrowclick");\r
59     },\r
60 \r
61     // private\r
62     onRender : function(ct, position){\r
63         // this is one sweet looking template!\r
64         var tpl = new Ext.Template(\r
65             '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',\r
66             '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',\r
67             '<tr><td class="x-btn-left"><i>&#160;</i></td><td class="x-btn-center"><button class="x-btn-text" type="{1}">{0}</button></td></tr>',\r
68             "</tbody></table></td><td>",\r
69             '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',\r
70             '<tr><td class="x-btn-center"><button class="x-btn-menu-arrow-el" type="button">&#160;</button></td><td class="x-btn-right"><i>&#160;</i></td></tr>',\r
71             "</tbody></table></td></tr></table>"\r
72         );\r
73         var btn, targs = [this.text || '&#160;', this.type];\r
74         if(position){\r
75             btn = tpl.insertBefore(position, targs, true);\r
76         }else{\r
77             btn = tpl.append(ct, targs, true);\r
78         }\r
79         var btnEl = btn.child(this.buttonSelector);\r
80 \r
81         this.initButtonEl(btn, btnEl);\r
82         this.arrowBtnTable = btn.child("table:last");\r
83         if(this.arrowTooltip){\r
84             btn.child(this.arrowSelector).dom[this.tooltipType] = this.arrowTooltip;\r
85         }\r
86     },\r
87 \r
88     // private\r
89     autoWidth : function(){\r
90         if(this.el){\r
91             var tbl = this.el.child("table:first");\r
92             var tbl2 = this.el.child("table:last");\r
93             this.el.setWidth("auto");\r
94             tbl.setWidth("auto");\r
95             if(Ext.isIE7 && Ext.isStrict){\r
96                 var ib = this.el.child(this.buttonSelector);\r
97                 if(ib && ib.getWidth() > 20){\r
98                     ib.clip();\r
99                     ib.setWidth(Ext.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));\r
100                 }\r
101             }\r
102             if(this.minWidth){\r
103                 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){\r
104                     tbl.setWidth(this.minWidth-tbl2.getWidth());\r
105                 }\r
106             }\r
107             this.el.setWidth(tbl.getWidth()+tbl2.getWidth());\r
108         } \r
109     },\r
110 \r
111     /**\r
112      * Sets this button's arrow click handler.\r
113      * @param {Function} handler The function to call when the arrow is clicked\r
114      * @param {Object} scope (optional) Scope for the function passed above\r
115      */\r
116     setArrowHandler : function(handler, scope){\r
117         this.arrowHandler = handler;\r
118         this.scope = scope;  \r
119     },\r
120 \r
121     // private\r
122     onClick : function(e){\r
123         e.preventDefault();\r
124         if(!this.disabled){\r
125             if(e.getTarget(".x-btn-menu-arrow-wrap")){\r
126                 if(this.menu && !this.menu.isVisible() && !this.ignoreNextClick){\r
127                     this.showMenu();\r
128                 }\r
129                 this.fireEvent("arrowclick", this, e);\r
130                 if(this.arrowHandler){\r
131                     this.arrowHandler.call(this.scope || this, this, e);\r
132                 }\r
133             }else{\r
134                 if(this.enableToggle){\r
135                     this.toggle();\r
136                 }\r
137                 this.fireEvent("click", this, e);\r
138                 if(this.handler){\r
139                     this.handler.call(this.scope || this, this, e);\r
140                 }\r
141             }\r
142         }\r
143     },\r
144 \r
145     // private\r
146     getClickEl : function(e, isUp){\r
147         if(!isUp){\r
148             return (this.lastClickEl = e.getTarget("table", 10, true));\r
149         }\r
150         return this.lastClickEl;\r
151     },\r
152 \r
153     // private\r
154     onDisable : function(){\r
155         if(this.el){\r
156             if(!Ext.isIE6){\r
157                 this.el.addClass("x-item-disabled");\r
158             }\r
159             this.el.child(this.buttonSelector).dom.disabled = true;\r
160             this.el.child(this.arrowSelector).dom.disabled = true;\r
161         }\r
162         this.disabled = true;\r
163     },\r
164 \r
165     // private\r
166     onEnable : function(){\r
167         if(this.el){\r
168             if(!Ext.isIE6){\r
169                 this.el.removeClass("x-item-disabled");\r
170             }\r
171             this.el.child(this.buttonSelector).dom.disabled = false;\r
172             this.el.child(this.arrowSelector).dom.disabled = false;\r
173         }\r
174         this.disabled = false;\r
175     },\r
176 \r
177     // private\r
178     isMenuTriggerOver : function(e){\r
179         return this.menu && e.within(this.arrowBtnTable) && !e.within(this.arrowBtnTable, true);\r
180     },\r
181 \r
182     // private\r
183     isMenuTriggerOut : function(e, internal){\r
184         return this.menu && !e.within(this.arrowBtnTable);\r
185     },\r
186 \r
187     // private\r
188     onDestroy : function(){\r
189         Ext.destroy(this.arrowBtnTable);\r
190         Ext.SplitButton.superclass.onDestroy.call(this);\r
191     }\r
192 });\r
193 \r
194 // backwards compat\r
195 Ext.MenuButton = Ext.SplitButton;\r
196 \r
197 \r
198 Ext.reg('splitbutton', Ext.SplitButton);