--- /dev/null
+/**
+ * @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()
+ });
+
+ * @constructor
+ * Creates a new Checkbox
+ * @param {Object} config Configuration options
+ * @xtype checkboxfield
+ * @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() {
+ return this.checked ? this.inputValue : (this.uncheckedValue || null);
+ },
+
+ getModelData: function() {
+ return this.getSubmitData();
+ },
+
+ /**
+ * 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;
+ }
+
+});