commit extjs-2.2.1
[extjs.git] / source / widgets / form / CheckboxGroup.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.form.CheckboxGroup\r
11  * @extends Ext.form.Field\r
12  * A grouping container for {@link Ext.form.Checkbox} controls.\r
13  * @constructor\r
14  * Creates a new CheckboxGroup\r
15  * @param {Object} config Configuration options\r
16  */\r
17 Ext.form.CheckboxGroup = Ext.extend(Ext.form.Field, {\r
18     /**\r
19      * @cfg {Array} items An Array of {@link Ext.form.Checkbox Checkbox}es or Checkbox config objects\r
20      * to arrange in the group.\r
21      */\r
22     /**\r
23      * @cfg {String/Number/Array} columns Specifies the number of columns to use when displaying grouped\r
24      * checkbox/radio controls using automatic layout.  This config can take several types of values:\r
25      * <ul><li><b>'auto'</b> : <p class="sub-desc">The controls will be rendered one per column on one row and the width\r
26      * of each column will be evenly distributed based on the width of the overall field container. This is the default.</p></li>\r
27      * <li><b>Number</b> : <p class="sub-desc">If you specific a number (e.g., 3) that number of columns will be \r
28      * created and the contained controls will be automatically distributed based on the value of {@link #vertical}.</p></li>\r
29      * <li><b>Array</b> : Object<p class="sub-desc">You can also specify an array of column widths, mixing integer\r
30      * (fixed width) and float (percentage width) values as needed (e.g., [100, .25, .75]). Any integer values will\r
31      * be rendered first, then any float values will be calculated as a percentage of the remaining space. Float\r
32      * values do not have to add up to 1 (100%) although if you want the controls to take up the entire field\r
33      * container you should do so.</p></li></ul>\r
34      */\r
35     columns : 'auto',\r
36     /**\r
37      * @cfg {Boolean} vertical True to distribute contained controls across columns, completely filling each column \r
38      * top to bottom before starting on the next column.  The number of controls in each column will be automatically\r
39      * calculated to keep columns as even as possible.  The default value is false, so that controls will be added\r
40      * to columns one at a time, completely filling each row left to right before starting on the next row.\r
41      */\r
42     vertical : false,\r
43     /**\r
44      * @cfg {Boolean} allowBlank False to validate that at least one item in the group is checked (defaults to true).\r
45      * If no items are selected at validation time, {@link @blankText} will be used as the error text.\r
46      */\r
47     allowBlank : true,\r
48     /**\r
49      * @cfg {String} blankText Error text to display if the {@link #allowBlank} validation fails (defaults to "You must \r
50      * select at least one item in this group")\r
51      */\r
52     blankText : "You must select at least one item in this group",\r
53     \r
54     // private\r
55     defaultType : 'checkbox',\r
56     \r
57     // private\r
58     groupCls: 'x-form-check-group',\r
59     \r
60     // private\r
61     onRender : function(ct, position){\r
62         if(!this.el){\r
63             var panelCfg = {\r
64                 cls: this.groupCls,\r
65                 layout: 'column',\r
66                 border: false,\r
67                 renderTo: ct\r
68             };\r
69             var colCfg = {\r
70                 defaultType: this.defaultType,\r
71                 layout: 'form',\r
72                 border: false,\r
73                 defaults: {\r
74                     hideLabel: true,\r
75                     anchor: '100%'\r
76                 }\r
77             }\r
78             \r
79             if(this.items[0].items){\r
80                 \r
81                 // The container has standard ColumnLayout configs, so pass them in directly\r
82                 \r
83                 Ext.apply(panelCfg, {\r
84                     layoutConfig: {columns: this.items.length},\r
85                     defaults: this.defaults,\r
86                     items: this.items\r
87                 })\r
88                 for(var i=0, len=this.items.length; i<len; i++){\r
89                     Ext.applyIf(this.items[i], colCfg);\r
90                 };\r
91                 \r
92             }else{\r
93                 \r
94                 // The container has field item configs, so we have to generate the column\r
95                 // panels first then move the items into the columns as needed.\r
96                 \r
97                 var numCols, cols = [];\r
98                 \r
99                 if(typeof this.columns == 'string'){ // 'auto' so create a col per item\r
100                     this.columns = this.items.length;\r
101                 }\r
102                 if(!Ext.isArray(this.columns)){\r
103                     var cs = [];\r
104                     for(var i=0; i<this.columns; i++){\r
105                         cs.push((100/this.columns)*.01); // distribute by even %\r
106                     }\r
107                     this.columns = cs;\r
108                 }\r
109                 \r
110                 numCols = this.columns.length;\r
111                 \r
112                 // Generate the column configs with the correct width setting\r
113                 for(var i=0; i<numCols; i++){\r
114                     var cc = Ext.apply({items:[]}, colCfg);\r
115                     cc[this.columns[i] <= 1 ? 'columnWidth' : 'width'] = this.columns[i];\r
116                     if(this.defaults){\r
117                         cc.defaults = Ext.apply(cc.defaults || {}, this.defaults)\r
118                     }\r
119                     cols.push(cc);\r
120                 };\r
121                 \r
122                 // Distribute the original items into the columns\r
123                 if(this.vertical){\r
124                     var rows = Math.ceil(this.items.length / numCols), ri = 0;\r
125                     for(var i=0, len=this.items.length; i<len; i++){\r
126                         if(i>0 && i%rows==0){\r
127                             ri++;\r
128                         }\r
129                         if(this.items[i].fieldLabel){\r
130                             this.items[i].hideLabel = false;\r
131                         }\r
132                         cols[ri].items.push(this.items[i]);\r
133                     };\r
134                 }else{\r
135                     for(var i=0, len=this.items.length; i<len; i++){\r
136                         var ci = i % numCols;\r
137                         if(this.items[i].fieldLabel){\r
138                             this.items[i].hideLabel = false;\r
139                         }\r
140                         cols[ci].items.push(this.items[i]);\r
141                     };\r
142                 }\r
143                 \r
144                 Ext.apply(panelCfg, {\r
145                     layoutConfig: {columns: numCols},\r
146                     items: cols\r
147                 });\r
148             }\r
149             \r
150             this.panel = new Ext.Panel(panelCfg);\r
151             this.el = this.panel.getEl();\r
152             \r
153             if(this.forId && this.itemCls){\r
154                 var l = this.el.up(this.itemCls).child('label', true);\r
155                 if(l){\r
156                     l.setAttribute('htmlFor', this.forId);\r
157                 }\r
158             }\r
159             \r
160             var fields = this.panel.findBy(function(c){\r
161                 return c.isFormField;\r
162             }, this);\r
163             \r
164             this.items = new Ext.util.MixedCollection();\r
165             this.items.addAll(fields);\r
166         }\r
167         Ext.form.CheckboxGroup.superclass.onRender.call(this, ct, position);\r
168     },\r
169     \r
170     // private\r
171     validateValue : function(value){\r
172         if(!this.allowBlank){\r
173             var blank = true;\r
174             this.items.each(function(f){\r
175                 if(f.checked){\r
176                     return blank = false;\r
177                 }\r
178             }, this);\r
179             if(blank){\r
180                 this.markInvalid(this.blankText);\r
181                 return false;\r
182             }\r
183         }\r
184         return true;\r
185     },\r
186     \r
187     // private\r
188     onDisable : function(){\r
189         this.items.each(function(item){\r
190             item.disable();\r
191         })\r
192     },\r
193 \r
194     // private\r
195     onEnable : function(){\r
196         this.items.each(function(item){\r
197             item.enable();\r
198         })\r
199     },\r
200     \r
201     // private\r
202     onResize : function(w, h){\r
203         this.panel.setSize(w, h);\r
204         this.panel.doLayout();\r
205     },\r
206     \r
207     // inherit docs from Field\r
208     reset : function(){\r
209         Ext.form.CheckboxGroup.superclass.reset.call(this);\r
210         this.items.each(function(c){\r
211             if(c.reset){\r
212                 c.reset();\r
213             }\r
214         }, this);\r
215     },\r
216     \r
217     /**\r
218      * @cfg {String} name\r
219      * @hide\r
220      */\r
221     /**\r
222      * @method initValue\r
223      * @hide\r
224      */\r
225     initValue : Ext.emptyFn,\r
226     /**\r
227      * @method getValue\r
228      * @hide\r
229      */\r
230     getValue : Ext.emptyFn,\r
231     /**\r
232      * @method getRawValue\r
233      * @hide\r
234      */\r
235     getRawValue : Ext.emptyFn,\r
236     /**\r
237      * @method setValue\r
238      * @hide\r
239      */\r
240     setValue : Ext.emptyFn,\r
241     /**\r
242      * @method setRawValue\r
243      * @hide\r
244      */\r
245     setRawValue : Ext.emptyFn\r
246     \r
247 });\r
248 \r
249 Ext.reg('checkboxgroup', Ext.form.CheckboxGroup);\r