X-Git-Url: http://git.ithinksw.org/extjs.git/blobdiff_plain/0494b8d9b9bb03ab6c22b34dae81261e3cd7e3e6..7a654f8d43fdb43d78b63d90528bed6e86b608cc:/src/form/field/Checkbox.js?ds=inline diff --git a/src/form/field/Checkbox.js b/src/form/field/Checkbox.js new file mode 100644 index 00000000..2f8611ba --- /dev/null +++ b/src/form/field/Checkbox.js @@ -0,0 +1,403 @@ +/** + * @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 + * @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: [ + '', + '', + '', + // 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. + 'tabIndex="{tabIdx}" ', + 'class="{fieldCls} {typeCls}" autocomplete="off" hidefocus="true" />', + '', + '', + '', + { + disableFormats: true, + compiled: true + } + ], + + isCheckbox: true, + + /** + * @cfg {String} focusCls The CSS class to use when the checkbox receives focus + * (defaults to 'x-form-cb-focus') + */ + focusCls: Ext.baseCSSPrefix + 'form-cb-focus', + + /** + * @cfg {String} fieldCls The default CSS class for the checkbox (defaults to 'x-form-field') + */ + + /** + * @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 true if the checkbox should render initially checked (defaults to false) + */ + 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 'before' and 'after'. Defaults to 'after'. + */ + 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 "on". + */ + 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: + *
+ */ + + /** + * @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 true. + * @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: + * true, 'true', '1', or 'on', 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: + * true, 'true', '1', or 'on', 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; + } + +});