    /**
     * @class Ext.form.field.Checkbox
     * @extends Ext.form.field.Base

    Single checkbox field. Can be used as a direct replacement for traditional checkbox fields. Also serves as a
    parent class for {@link Ext.form.field.Radio radio buttons}.

    __Labeling:__ In addition to the {@link Ext.form.Labelable standard field labeling options}, checkboxes
    may be given an optional {@link #boxLabel} which will be displayed immediately after checkbox. Also see
    {@link Ext.form.CheckboxGroup} for a convenient method of grouping related checkboxes.

    __Values:__
    The main value of a checkbox is a boolean, indicating whether or not the checkbox is checked.
    The following values will check the checkbox:
    * `true`
    * `'true'`
    * `'1'`
    * `'on'`

    Any other value will uncheck the checkbox.

    In addition to the main boolean value, you may also specify a separate {@link #inputValue}. This will be
    sent as the parameter value when the form is {@link Ext.form.Basic#submit submitted}. You will want to set
    this value if you have multiple checkboxes with the same {@link #name}. If not specified, the value `on`
    will be used.
    {@img Ext.form.Checkbox/Ext.form.Checkbox.png Ext.form.Checkbox Checkbox component}
    __Example usage:__

        Ext.create('Ext.form.Panel', {
            bodyPadding: 10,
            width      : 300,
            title      : 'Pizza Order',
            items: [
                {
                    xtype      : 'fieldcontainer',
                    fieldLabel : 'Toppings',
                    defaultType: 'checkboxfield',
                    items: [
                        {
                            boxLabel  : 'Anchovies',
                            name      : 'topping',
                            inputValue: '1',
                            id        : 'checkbox1'
                        }, {
                            boxLabel  : 'Artichoke Hearts',
                            name      : 'topping',
                            inputValue: '2',
                            checked   : true,
                            id        : 'checkbox2'
                        }, {
                            boxLabel  : 'Bacon',
                            name      : 'topping',
                            inputValue: '3',
                            id        : 'checkbox3'
                        }
                    ]
                }
            ],
            bbar: [
                {
                    text: 'Select Bacon',
                    handler: function() {
                        var checkbox = Ext.getCmp('checkbox3');
                        checkbox.setValue(true);
                    }
                },
                '-',
                {
                    text: 'Select All',
                    handler: function() {
                        var checkbox1 = Ext.getCmp('checkbox1'),
                            checkbox2 = Ext.getCmp('checkbox2'),
                            checkbox3 = Ext.getCmp('checkbox3');

                        checkbox1.setValue(true);
                        checkbox2.setValue(true);
                        checkbox3.setValue(true);
                    }
                },
                {
                    text: 'Deselect All',
                    handler: function() {
                        var checkbox1 = Ext.getCmp('checkbox1'),
                            checkbox2 = Ext.getCmp('checkbox2'),
                            checkbox3 = Ext.getCmp('checkbox3');

                        checkbox1.setValue(false);
                        checkbox2.setValue(false);
                        checkbox3.setValue(false);
                    }
                }
            ],
            renderTo: Ext.getBody()
        });

     * @docauthor Robert Dougan <rob@sencha.com>
     * @markdown
     */
    Ext.define('Ext.form.field.Checkbox', {
        extend: 'Ext.form.field.Base',
        alias: ['widget.checkboxfield', 'widget.checkbox'],
        alternateClassName: 'Ext.form.Checkbox',
        requires: ['Ext.XTemplate', 'Ext.form.CheckboxManager'],

        fieldSubTpl: [
            '<tpl if="boxLabel && boxLabelAlign == \'before\'">',
                '<label class="{boxLabelCls} {boxLabelCls}-{boxLabelAlign}" for="{id}">{boxLabel}</label>',
            '</tpl>',
            // Creates not an actual checkbox, but a button which is given aria role="checkbox" and
            // styled with a custom checkbox image. This allows greater control and consistency in
            // styling, and using a button allows it to gain focus and handle keyboard nav properly.
            '<input type="button" id="{id}" ',
                '<tpl if="tabIdx">tabIndex="{tabIdx}" </tpl>',
                'class="{fieldCls} {typeCls}" autocomplete="off" hidefocus="true" />',
            '<tpl if="boxLabel && boxLabelAlign == \'after\'">',
                '<label class="{boxLabelCls} {boxLabelCls}-{boxLabelAlign}" for="{id}">{boxLabel}</label>',
            '</tpl>',
            {
                disableFormats: true,
                compiled: true
            }
        ],

        isCheckbox: true,

        /**
         * @cfg {String} focusCls The CSS class to use when the checkbox receives focus
         * (defaults to <tt>'x-form-cb-focus'</tt>)
         */
        focusCls: Ext.baseCSSPrefix + 'form-cb-focus',

        /**
         * @cfg {String} fieldCls The default CSS class for the checkbox (defaults to <tt>'x-form-field'</tt>)
         */

        /**
         * @cfg {String} fieldBodyCls
         * An extra CSS class to be applied to the body content element in addition to {@link #fieldBodyCls}.
         * Defaults to 'x-form-cb-wrap.
         */
        fieldBodyCls: Ext.baseCSSPrefix + 'form-cb-wrap',

        /**
         * @cfg {Boolean} checked <tt>true</tt> if the checkbox should render initially checked (defaults to <tt>false</tt>)
         */
        checked: false,

        /**
         * @cfg {String} checkedCls The CSS class added to the component's main element when it is in the checked state.
         */
        checkedCls: Ext.baseCSSPrefix + 'form-cb-checked',

        /**
         * @cfg {String} boxLabel An optional text label that will appear next to the checkbox. Whether it appears before
         * or after the checkbox is determined by the {@link #boxLabelAlign} config (defaults to after).
         */

        /**
         * @cfg {String} boxLabelCls The CSS class to be applied to the {@link #boxLabel} element
         */
        boxLabelCls: Ext.baseCSSPrefix + 'form-cb-label',

        /**
         * @cfg {String} boxLabelAlign The position relative to the checkbox where the {@link #boxLabel} should
         * appear. Recognized values are <tt>'before'</tt> and <tt>'after'</tt>. Defaults to <tt>'after'</tt>.
         */
        boxLabelAlign: 'after',

        /**
         * @cfg {String} inputValue The value that should go into the generated input element's value attribute and
         * should be used as the parameter value when submitting as part of a form. Defaults to <tt>"on"</tt>.
         */
        inputValue: 'on',

        /**
         * @cfg {String} uncheckedValue If configured, this will be submitted as the checkbox's value during form
         * submit if the checkbox is unchecked. By default this is undefined, which results in nothing being
         * submitted for the checkbox field when the form is submitted (the default behavior of HTML checkboxes).
         */

        /**
         * @cfg {Function} handler A function called when the {@link #checked} value changes (can be used instead of
         * handling the {@link #change change event}). The handler is passed the following parameters:
         * <div class="mdetail-params"><ul>
         * <li><b>checkbox</b> : Ext.form.field.Checkbox<div class="sub-desc">The Checkbox being toggled.</div></li>
         * <li><b>checked</b> : Boolean<div class="sub-desc">The new checked state of the checkbox.</div></li>
         * </ul></div>
         */

        /**
         * @cfg {Object} scope An object to use as the scope ('this' reference) of the {@link #handler} function
         * (defaults to this Checkbox).
         */

        // private overrides
        checkChangeEvents: [],
        inputType: 'checkbox',
        ariaRole: 'checkbox',

        // private
        onRe: /^on$/i,

        initComponent: function(){
            this.callParent(arguments);
            this.getManager().add(this);
        },

        initValue: function() {
            var me = this,
                checked = !!me.checked;

            /**
             * The original value of the field as configured in the {@link #checked} configuration, or
             * as loaded by the last form load operation if the form's {@link Ext.form.Basic#trackResetOnLoad trackResetOnLoad}
             * setting is <code>true</code>.
             * @type Mixed
             * @property originalValue
             */
            me.originalValue = me.lastValue = checked;

            // Set the initial checked state
            me.setValue(checked);
        },

        // private
        onRender : function(ct, position) {
            var me = this;
            Ext.applyIf(me.renderSelectors, {
                /**
                 * @property boxLabelEl
                 * @type Ext.core.Element
                 * A reference to the label element created for the {@link #boxLabel}. Only present if the
                 * component has been rendered and has a boxLabel configured.
                 */
                boxLabelEl: 'label.' + me.boxLabelCls
            });
            Ext.applyIf(me.subTplData, {
                boxLabel: me.boxLabel,
                boxLabelCls: me.boxLabelCls,
                boxLabelAlign: me.boxLabelAlign
            });

            me.callParent(arguments);
        },

        initEvents: function() {
            var me = this;
            me.callParent();
            me.mon(me.inputEl, 'click', me.onBoxClick, me);
        },

        /**
         * @private Handle click on the checkbox button
         */
        onBoxClick: function(e) {
            var me = this;
            if (!me.disabled && !me.readOnly) {
                this.setValue(!this.checked);
            }
        },

        /**
         * Returns the checked state of the checkbox.
         * @return {Boolean} True if checked, else false
         */
        getRawValue: function() {
            return this.checked;
        },

        /**
         * Returns the checked state of the checkbox.
         * @return {Boolean} True if checked, else false
         */
        getValue: function() {
            return this.checked;
        },

        /**
         * Returns the submit value for the checkbox which can be used when submitting forms.
         * @return {Boolean/null} True if checked; otherwise either the {@link #uncheckedValue} or null.
         */
        getSubmitValue: function() {
            var unchecked = this.uncheckedValue,
                uncheckedVal = Ext.isDefined(unchecked) ? unchecked : null;
            return this.checked ? this.inputValue : uncheckedVal;
        },

        /**
         * Sets the checked state of the checkbox.
         * @param {Boolean/String} value The following values will check the checkbox:
         * <code>true, 'true', '1', or 'on'</code>, as well as a String that matches the {@link #inputValue}.
         * Any other value will uncheck the checkbox.
         * @return {Boolean} the new checked state of the checkbox
         */
        setRawValue: function(value) {
            var me = this,
                inputEl = me.inputEl,
                inputValue = me.inputValue,
                checked = (value === true || value === 'true' || value === '1' ||
                          ((Ext.isString(value) && inputValue) ? value == inputValue : me.onRe.test(value)));

            if (inputEl) {
                inputEl.dom.setAttribute('aria-checked', checked);
                me[checked ? 'addCls' : 'removeCls'](me.checkedCls);
            }

            me.checked = me.rawValue = checked;
            return checked;
        },

        /**
         * Sets the checked state of the checkbox, and invokes change detection.
         * @param {Boolean/String} checked The following values will check the checkbox:
         * <code>true, 'true', '1', or 'on'</code>, as well as a String that matches the {@link #inputValue}.
         * Any other value will uncheck the checkbox.
         * @return {Ext.form.field.Checkbox} this
         */
        setValue: function(checked) {
            var me = this;

            // If an array of strings is passed, find all checkboxes in the group with the same name as this
            // one and check all those whose inputValue is in the array, unchecking all the others. This is to
            // facilitate setting values from Ext.form.Basic#setValues, but is not publicly documented as we
            // don't want users depending on this behavior.
            if (Ext.isArray(checked)) {
                me.getManager().getByName(me.name).each(function(cb) {
                    cb.setValue(Ext.Array.contains(checked, cb.inputValue));
                });
            } else {
                me.callParent(arguments);
            }

            return me;
        },

        // private
        valueToRaw: function(value) {
            // No extra conversion for checkboxes
            return value;
        },

        /**
         * @private
         * Called when the checkbox's checked state changes. Invokes the {@link #handler} callback
         * function if specified.
         */
        onChange: function(newVal, oldVal) {
            var me = this,
                handler = me.handler;
            if (handler) {
                handler.call(me.scope || me, me, newVal);
            }
            me.callParent(arguments);
        },

        // inherit docs
        getManager: function() {
            return Ext.form.CheckboxManager;
        },

        onEnable: function() {
            var me = this,
                inputEl = me.inputEl;
            me.callParent();
            if (inputEl) {
                // Can still be disabled if the field is readOnly
                inputEl.dom.disabled = me.readOnly;
            }
        },

        setReadOnly: function(readOnly) {
            var me = this,
                inputEl = me.inputEl;
            if (inputEl) {
                // Set the button to disabled when readonly
                inputEl.dom.disabled = readOnly || me.disabled;
            }
            me.readOnly = readOnly;
        },

        /**
         * @protected Calculate and return the natural width of the bodyEl. It's possible that the initial
         * rendering will cause the boxLabel to wrap and give us a bad width, so we must prevent wrapping
         * while measuring.
         */
        getBodyNaturalWidth: function() {
            var me = this,
                bodyEl = me.bodyEl,
                ws = 'white-space',
                width;
            bodyEl.setStyle(ws, 'nowrap');
            width = bodyEl.getWidth();
            bodyEl.setStyle(ws, '');
            return width;
        }

    });