PageRenderTime 47ms CodeModel.GetById 31ms app.highlight 11ms RepoModel.GetById 1ms app.codeStats 0ms

/ext-4.1.0_b3/src/form/field/Checkbox.js

https://bitbucket.org/srogerf/javascript
JavaScript | 470 lines | 172 code | 51 blank | 247 comment | 19 complexity | cd270de0ca3b0248fcd8b224f1e77bd5 MD5 | raw file
  1/**
  2 * @docauthor Robert Dougan <rob@sencha.com>
  3 *
  4 * Single checkbox field. Can be used as a direct replacement for traditional checkbox fields. Also serves as a
  5 * parent class for {@link Ext.form.field.Radio radio buttons}.
  6 *
  7 * # Labeling
  8 *
  9 * In addition to the {@link Ext.form.Labelable standard field labeling options}, checkboxes
 10 * may be given an optional {@link #boxLabel} which will be displayed immediately after checkbox. Also see
 11 * {@link Ext.form.CheckboxGroup} for a convenient method of grouping related checkboxes.
 12 *
 13 * # Values
 14 *
 15 * The main value of a checkbox is a boolean, indicating whether or not the checkbox is checked.
 16 * The following values will check the checkbox:
 17 *
 18 * - `true`
 19 * - `'true'`
 20 * - `'1'`
 21 * - `'on'`
 22 *
 23 * Any other value will uncheck the checkbox.
 24 *
 25 * In addition to the main boolean value, you may also specify a separate {@link #inputValue}. This will be
 26 * sent as the parameter value when the form is {@link Ext.form.Basic#submit submitted}. You will want to set
 27 * this value if you have multiple checkboxes with the same {@link #name}. If not specified, the value `on`
 28 * will be used.
 29 *
 30 * # Example usage
 31 *
 32 *     @example
 33 *     Ext.create('Ext.form.Panel', {
 34 *         bodyPadding: 10,
 35 *         width: 300,
 36 *         title: 'Pizza Order',
 37 *         items: [
 38 *             {
 39 *                 xtype: 'fieldcontainer',
 40 *                 fieldLabel: 'Toppings',
 41 *                 defaultType: 'checkboxfield',
 42 *                 items: [
 43 *                     {
 44 *                         boxLabel  : 'Anchovies',
 45 *                         name      : 'topping',
 46 *                         inputValue: '1',
 47 *                         id        : 'checkbox1'
 48 *                     }, {
 49 *                         boxLabel  : 'Artichoke Hearts',
 50 *                         name      : 'topping',
 51 *                         inputValue: '2',
 52 *                         checked   : true,
 53 *                         id        : 'checkbox2'
 54 *                     }, {
 55 *                         boxLabel  : 'Bacon',
 56 *                         name      : 'topping',
 57 *                         inputValue: '3',
 58 *                         id        : 'checkbox3'
 59 *                     }
 60 *                 ]
 61 *             }
 62 *         ],
 63 *         bbar: [
 64 *             {
 65 *                 text: 'Select Bacon',
 66 *                 handler: function() {
 67 *                     Ext.getCmp('checkbox3').setValue(true);
 68 *                 }
 69 *             },
 70 *             '-',
 71 *             {
 72 *                 text: 'Select All',
 73 *                 handler: function() {
 74 *                     Ext.getCmp('checkbox1').setValue(true);
 75 *                     Ext.getCmp('checkbox2').setValue(true);
 76 *                     Ext.getCmp('checkbox3').setValue(true);
 77 *                 }
 78 *             },
 79 *             {
 80 *                 text: 'Deselect All',
 81 *                 handler: function() {
 82 *                     Ext.getCmp('checkbox1').setValue(false);
 83 *                     Ext.getCmp('checkbox2').setValue(false);
 84 *                     Ext.getCmp('checkbox3').setValue(false);
 85 *                 }
 86 *             }
 87 *         ],
 88 *         renderTo: Ext.getBody()
 89 *     });
 90 */
 91Ext.define('Ext.form.field.Checkbox', {
 92    extend: 'Ext.form.field.Base',
 93    alias: ['widget.checkboxfield', 'widget.checkbox'],
 94    alternateClassName: 'Ext.form.Checkbox',
 95    requires: ['Ext.XTemplate', 'Ext.form.CheckboxManager' ],
 96
 97    componentLayout: 'field',
 98
 99    childEls: [
100        /**
101         * @property {Ext.Element} boxLabelEl
102         * A reference to the label element created for the {@link #boxLabel}. Only present if the component has been
103         * rendered and has a boxLabel configured.
104         */
105        'boxLabelEl'
106    ],
107
108    // note: {id} here is really {inputId}, but {cmpId} is available
109    fieldSubTpl: [
110        '<tpl if="boxLabel && boxLabelAlign == \'before\'">',
111            '{beforeBoxLabelTpl}',
112            '<label id="{cmpId}-boxLabelEl" {boxLabelAttrTpl} class="{boxLabelCls} {boxLabelCls}-{boxLabelAlign}" for="{id}">',
113                '{beforeBoxLabelTextTpl}',
114                '{boxLabel}',
115                '{afterBoxLabelTextTpl}',
116            '</label>',
117            '{afterBoxLabelTpl}',
118        '</tpl>',
119        // Creates not an actual checkbox, but a button which is given aria role="checkbox" (If ARIA is required) and
120        // styled with a custom checkbox image. This allows greater control and consistency in
121        // styling, and using a button allows it to gain focus and handle keyboard nav properly.
122        '<input type="button" id="{id}" {inputAttrTpl}',
123            '<tpl if="tabIdx"> tabIndex="{tabIdx}"</tpl>',
124            '<tpl if="disabled"> disabled="disabled"</tpl>',
125            '<tpl if="fieldStyle"> style="{fieldStyle}"</tpl>',
126            ' class="{fieldCls} {typeCls}" autocomplete="off" hidefocus="true" />',
127        '<tpl if="boxLabel && boxLabelAlign == \'after\'">',
128            '{beforeBoxLabelTpl}',
129            '<label id="{cmpId}-boxLabelEl" {boxLabelAttrTpl} class="{boxLabelCls} {boxLabelCls}-{boxLabelAlign}" for="{id}">',
130                '{beforeBoxLabelTextTpl}',
131                '{boxLabel}',
132                '{afterBoxLabelTextTpl}',
133            '</label>',
134            '{afterBoxLabelTpl}',
135        '</tpl>',
136        {
137            disableFormats: true,
138            compiled: true
139        }
140    ],
141
142    subTplInsertions: [
143        /**
144         * @cfg {String/Array/Ext.XTemplate} beforeBoxLabelTpl
145         * An optional string or `XTemplate` configuration to insert in the field markup
146         * before the box label element. If an `XTemplate` is used, the component's
147         * {@link Ext.form.field.Base#getSubTplData subTpl data} serves as the context.
148         */
149        'beforeBoxLabelTpl',
150
151        /**
152         * @cfg {String/Array/Ext.XTemplate} afterBoxLabelTpl
153         * An optional string or `XTemplate` configuration to insert in the field markup
154         * after the box label element. If an `XTemplate` is used, the component's
155         * {@link Ext.form.field.Base#getSubTplData subTpl data} serves as the context.
156         */
157        'afterBoxLabelTpl',
158
159        /**
160         * @cfg {String/Array/Ext.XTemplate} beforeBoxLabelTextTpl
161         * An optional string or `XTemplate` configuration to insert in the field markup
162         * before the box label text. If an `XTemplate` is used, the component's
163         * {@link Ext.form.field.Base#getSubTplData subTpl data} serves as the context.
164         */
165        'beforeBoxLabelTextTpl',
166
167        /**
168         * @cfg {String/Array/Ext.XTemplate} afterBoxLabelTextTpl
169         * An optional string or `XTemplate` configuration to insert in the field markup
170         * after the box label text. If an `XTemplate` is used, the component's
171         * {@link Ext.form.field.Base#getSubTplData subTpl data} serves as the context.
172         */
173        'afterBoxLabelTextTpl',
174
175        /**
176         * @cfg {String/Array/Ext.XTemplate} boxLabelAttrTpl
177         * An optional string or `XTemplate` configuration to insert in the field markup
178         * inside the box label element (as attributes). If an `XTemplate` is used, the component's
179         * {@link Ext.form.field.Base#getSubTplData subTpl data} serves as the context.
180         */
181        'boxLabelAttrTpl',
182
183        // inherited
184        'inputAttrTpl'
185    ],
186
187    /*
188     * @property {Boolean} isCheckbox
189     * `true` in this class to identify an objact as an instantiated Checkbox, or subclass thereof.
190     */
191    isCheckbox: true,
192
193    /**
194     * @cfg {String} [focusCls='x-form-cb-focus']
195     * The CSS class to use when the checkbox receives focus
196     */
197    focusCls: Ext.baseCSSPrefix + 'form-cb-focus',
198
199    /**
200     * @cfg {String} [fieldCls='x-form-field']
201     * The default CSS class for the checkbox
202     */
203
204    /**
205     * @cfg {String} [fieldBodyCls='x-form-cb-wrap']
206     * An extra CSS class to be applied to the body content element in addition to {@link #fieldBodyCls}.
207     * .
208     */
209    fieldBodyCls: Ext.baseCSSPrefix + 'form-cb-wrap',
210
211    /**
212     * @cfg {Boolean} checked
213     * true if the checkbox should render initially checked
214     */
215    checked: false,
216
217    /**
218     * @cfg {String} [checkedCls='x-form-cb-checked']
219     * The CSS class added to the component's main element when it is in the checked state.
220     */
221    checkedCls: Ext.baseCSSPrefix + 'form-cb-checked',
222
223    /**
224     * @cfg {String} boxLabel
225     * An optional text label that will appear next to the checkbox. Whether it appears before or after the checkbox is
226     * determined by the {@link #boxLabelAlign} config.
227     */
228
229    /**
230     * @cfg {String} [boxLabelCls='x-form-cb-label']
231     * The CSS class to be applied to the {@link #boxLabel} element
232     */
233    boxLabelCls: Ext.baseCSSPrefix + 'form-cb-label',
234
235    /**
236     * @cfg {String} boxLabelAlign
237     * The position relative to the checkbox where the {@link #boxLabel} should appear. Recognized values are 'before'
238     * and 'after'.
239     */
240    boxLabelAlign: 'after',
241
242    /**
243     * @cfg {String} inputValue
244     * The value that should go into the generated input element's value attribute and should be used as the parameter
245     * value when submitting as part of a form.
246     */
247    inputValue: 'on',
248
249    /**
250     * @cfg {String} uncheckedValue
251     * If configured, this will be submitted as the checkbox's value during form submit if the checkbox is unchecked. By
252     * default this is undefined, which results in nothing being submitted for the checkbox field when the form is
253     * submitted (the default behavior of HTML checkboxes).
254     */
255
256    /**
257     * @cfg {Function} handler
258     * A function called when the {@link #checked} value changes (can be used instead of handling the {@link #change
259     * change event}).
260     * @cfg {Ext.form.field.Checkbox} handler.checkbox The Checkbox being toggled.
261     * @cfg {Boolean} handler.checked The new checked state of the checkbox.
262     */
263
264    /**
265     * @cfg {Object} scope
266     * An object to use as the scope ('this' reference) of the {@link #handler} function.
267     *
268     * Defaults to this Checkbox.
269     */
270
271    // private overrides
272    checkChangeEvents: [],
273    inputType: 'checkbox',
274
275    // private
276    onRe: /^on$/i,
277
278    initComponent: function() {
279        this.callParent(arguments);
280        this.getManager().add(this);
281    },
282
283    initValue: function() {
284        var me = this,
285            checked = !!me.checked;
286
287        /**
288         * @property {Object} originalValue
289         * The original value of the field as configured in the {@link #checked} configuration, or as loaded by the last
290         * form load operation if the form's {@link Ext.form.Basic#trackResetOnLoad trackResetOnLoad} setting is `true`.
291         */
292        me.originalValue = me.lastValue = checked;
293
294        // Set the initial checked state
295        me.setValue(checked);
296    },
297
298    getElConfig: function() {
299        var me = this;
300
301        // Add the checked class if this begins checked
302        if (me.isChecked(me.rawValue, me.inputValue)) {
303            me.addCls(me.checkedCls);
304        }
305        return me.callParent();
306    },
307
308    getFieldStyle: function() {
309        return Ext.isObject(this.fieldStyle) ? Ext.DomHelper.generateStyles(this.fieldStyle) : this.fieldStyle ||'';
310    },
311
312    getSubTplData: function() {
313        var me = this;
314        return Ext.apply(me.callParent(), {
315            disabled      : me.readOnly || me.disabled,
316            boxLabel      : me.boxLabel,
317            boxLabelCls   : me.boxLabelCls,
318            boxLabelAlign : me.boxLabelAlign
319        });
320    },
321
322    initEvents: function() {
323        var me = this;
324        me.callParent();
325        me.mon(me.inputEl, 'click', me.onBoxClick, me);
326    },
327
328    /**
329     * @private Handle click on the checkbox button
330     */
331    onBoxClick: function(e) {
332        var me = this;
333        if (!me.disabled && !me.readOnly) {
334            this.setValue(!this.checked);
335        }
336    },
337
338    /**
339     * Returns the checked state of the checkbox.
340     * @return {Boolean} True if checked, else false
341     */
342    getRawValue: function() {
343        return this.checked;
344    },
345
346    /**
347     * Returns the checked state of the checkbox.
348     * @return {Boolean} True if checked, else false
349     */
350    getValue: function() {
351        return this.checked;
352    },
353
354    /**
355     * Returns the submit value for the checkbox which can be used when submitting forms.
356     * @return {String} If checked the {@link #inputValue} is returned; otherwise the {@link #uncheckedValue}
357     * (or null if the latter is not configured).
358     */
359    getSubmitValue: function() {
360        var unchecked = this.uncheckedValue,
361            uncheckedVal = Ext.isDefined(unchecked) ? unchecked : null;
362        return this.checked ? this.inputValue : uncheckedVal;
363    },
364
365    isChecked: function(rawValue, inputValue) {
366        return (rawValue === true || rawValue === 'true' || rawValue === '1' || rawValue === 1 ||
367                      (((Ext.isString(rawValue) || Ext.isNumber(rawValue)) && inputValue) ? rawValue == inputValue : this.onRe.test(rawValue)));
368    },
369
370    /**
371     * Sets the checked state of the checkbox.
372     *
373     * @param {Boolean/String/Number} value The following values will check the checkbox:
374     * `true, 'true', '1', 1, or 'on'`, as well as a String that matches the {@link #inputValue}.
375     * Any other value will uncheck the checkbox.
376     * @return {Boolean} the new checked state of the checkbox
377     */
378    setRawValue: function(value) {
379        var me = this,
380            inputEl = me.inputEl,
381            checked = me.isChecked(value, me.inputValue);
382
383        if (inputEl) {
384            me[checked ? 'addCls' : 'removeCls'](me.checkedCls);
385        }
386
387        me.checked = me.rawValue = checked;
388        return checked;
389    },
390
391    /**
392     * Sets the checked state of the checkbox, and invokes change detection.
393     * @param {Boolean/String} checked The following values will check the checkbox: `true, 'true', '1', or 'on'`, as
394     * well as a String that matches the {@link #inputValue}. Any other value will uncheck the checkbox.
395     * @return {Ext.form.field.Checkbox} this
396     */
397    setValue: function(checked) {
398        var me = this,
399        	boxes, b, bLen, box;
400
401        // If an array of strings is passed, find all checkboxes in the group with the same name as this
402        // one and check all those whose inputValue is in the array, unchecking all the others. This is to
403        // facilitate setting values from Ext.form.Basic#setValues, but is not publicly documented as we
404        // don't want users depending on this behavior.
405        if (Ext.isArray(checked)) {
406            boxes = me.getManager().getByName(me.name).items,
407            bLen  = boxes.length;
408
409            for (b = 0; b < bLen; b++) {
410                box = boxes[b];
411                box.setValue(Ext.Array.contains(checked, box.inputValue));
412            }
413        } else {
414            me.callParent(arguments);
415        }
416
417        return me;
418    },
419
420    // private
421    valueToRaw: function(value) {
422        // No extra conversion for checkboxes
423        return value;
424    },
425
426    /**
427     * @private
428     * Called when the checkbox's checked state changes. Invokes the {@link #handler} callback
429     * function if specified.
430     */
431    onChange: function(newVal, oldVal) {
432        var me = this,
433            handler = me.handler;
434        if (handler) {
435            handler.call(me.scope || me, me, newVal);
436        }
437        me.callParent(arguments);
438    },
439
440    // inherit docs
441    beforeDestroy: function(){
442        this.callParent();
443        this.getManager().removeAtKey(this.id);
444    },
445
446    // inherit docs
447    getManager: function() {
448        return Ext.form.CheckboxManager;
449    },
450
451    onEnable: function() {
452        var me = this,
453            inputEl = me.inputEl;
454        me.callParent();
455        if (inputEl) {
456            // Can still be disabled if the field is readOnly
457            inputEl.dom.disabled = me.readOnly;
458        }
459    },
460
461    setReadOnly: function(readOnly) {
462        var me = this,
463            inputEl = me.inputEl;
464        if (inputEl) {
465            // Set the button to disabled when readonly
466            inputEl.dom.disabled = !!readOnly || me.disabled;
467        }
468        me.callParent(arguments);
469    }
470});