/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. */
  91. Ext.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. componentLayout: 'field',
  97. childEls: [
  98. /**
  99. * @property {Ext.Element} boxLabelEl
  100. * A reference to the label element created for the {@link #boxLabel}. Only present if the component has been
  101. * rendered and has a boxLabel configured.
  102. */
  103. 'boxLabelEl'
  104. ],
  105. // note: {id} here is really {inputId}, but {cmpId} is available
  106. fieldSubTpl: [
  107. '<tpl if="boxLabel && boxLabelAlign == \'before\'">',
  108. '{beforeBoxLabelTpl}',
  109. '<label id="{cmpId}-boxLabelEl" {boxLabelAttrTpl} class="{boxLabelCls} {boxLabelCls}-{boxLabelAlign}" for="{id}">',
  110. '{beforeBoxLabelTextTpl}',
  111. '{boxLabel}',
  112. '{afterBoxLabelTextTpl}',
  113. '</label>',
  114. '{afterBoxLabelTpl}',
  115. '</tpl>',
  116. // Creates not an actual checkbox, but a button which is given aria role="checkbox" (If ARIA is required) and
  117. // styled with a custom checkbox image. This allows greater control and consistency in
  118. // styling, and using a button allows it to gain focus and handle keyboard nav properly.
  119. '<input type="button" id="{id}" {inputAttrTpl}',
  120. '<tpl if="tabIdx"> tabIndex="{tabIdx}"</tpl>',
  121. '<tpl if="disabled"> disabled="disabled"</tpl>',
  122. '<tpl if="fieldStyle"> style="{fieldStyle}"</tpl>',
  123. ' class="{fieldCls} {typeCls}" autocomplete="off" hidefocus="true" />',
  124. '<tpl if="boxLabel && boxLabelAlign == \'after\'">',
  125. '{beforeBoxLabelTpl}',
  126. '<label id="{cmpId}-boxLabelEl" {boxLabelAttrTpl} class="{boxLabelCls} {boxLabelCls}-{boxLabelAlign}" for="{id}">',
  127. '{beforeBoxLabelTextTpl}',
  128. '{boxLabel}',
  129. '{afterBoxLabelTextTpl}',
  130. '</label>',
  131. '{afterBoxLabelTpl}',
  132. '</tpl>',
  133. {
  134. disableFormats: true,
  135. compiled: true
  136. }
  137. ],
  138. subTplInsertions: [
  139. /**
  140. * @cfg {String/Array/Ext.XTemplate} beforeBoxLabelTpl
  141. * An optional string or `XTemplate` configuration to insert in the field markup
  142. * before the box label element. If an `XTemplate` is used, the component's
  143. * {@link Ext.form.field.Base#getSubTplData subTpl data} serves as the context.
  144. */
  145. 'beforeBoxLabelTpl',
  146. /**
  147. * @cfg {String/Array/Ext.XTemplate} afterBoxLabelTpl
  148. * An optional string or `XTemplate` configuration to insert in the field markup
  149. * after the box label element. If an `XTemplate` is used, the component's
  150. * {@link Ext.form.field.Base#getSubTplData subTpl data} serves as the context.
  151. */
  152. 'afterBoxLabelTpl',
  153. /**
  154. * @cfg {String/Array/Ext.XTemplate} beforeBoxLabelTextTpl
  155. * An optional string or `XTemplate` configuration to insert in the field markup
  156. * before the box label text. If an `XTemplate` is used, the component's
  157. * {@link Ext.form.field.Base#getSubTplData subTpl data} serves as the context.
  158. */
  159. 'beforeBoxLabelTextTpl',
  160. /**
  161. * @cfg {String/Array/Ext.XTemplate} afterBoxLabelTextTpl
  162. * An optional string or `XTemplate` configuration to insert in the field markup
  163. * after the box label text. If an `XTemplate` is used, the component's
  164. * {@link Ext.form.field.Base#getSubTplData subTpl data} serves as the context.
  165. */
  166. 'afterBoxLabelTextTpl',
  167. /**
  168. * @cfg {String/Array/Ext.XTemplate} boxLabelAttrTpl
  169. * An optional string or `XTemplate` configuration to insert in the field markup
  170. * inside the box label element (as attributes). If an `XTemplate` is used, the component's
  171. * {@link Ext.form.field.Base#getSubTplData subTpl data} serves as the context.
  172. */
  173. 'boxLabelAttrTpl',
  174. // inherited
  175. 'inputAttrTpl'
  176. ],
  177. /*
  178. * @property {Boolean} isCheckbox
  179. * `true` in this class to identify an objact as an instantiated Checkbox, or subclass thereof.
  180. */
  181. isCheckbox: true,
  182. /**
  183. * @cfg {String} [focusCls='x-form-cb-focus']
  184. * The CSS class to use when the checkbox receives focus
  185. */
  186. focusCls: Ext.baseCSSPrefix + 'form-cb-focus',
  187. /**
  188. * @cfg {String} [fieldCls='x-form-field']
  189. * The default CSS class for the checkbox
  190. */
  191. /**
  192. * @cfg {String} [fieldBodyCls='x-form-cb-wrap']
  193. * An extra CSS class to be applied to the body content element in addition to {@link #fieldBodyCls}.
  194. * .
  195. */
  196. fieldBodyCls: Ext.baseCSSPrefix + 'form-cb-wrap',
  197. /**
  198. * @cfg {Boolean} checked
  199. * true if the checkbox should render initially checked
  200. */
  201. checked: false,
  202. /**
  203. * @cfg {String} [checkedCls='x-form-cb-checked']
  204. * The CSS class added to the component's main element when it is in the checked state.
  205. */
  206. checkedCls: Ext.baseCSSPrefix + 'form-cb-checked',
  207. /**
  208. * @cfg {String} boxLabel
  209. * An optional text label that will appear next to the checkbox. Whether it appears before or after the checkbox is
  210. * determined by the {@link #boxLabelAlign} config.
  211. */
  212. /**
  213. * @cfg {String} [boxLabelCls='x-form-cb-label']
  214. * The CSS class to be applied to the {@link #boxLabel} element
  215. */
  216. boxLabelCls: Ext.baseCSSPrefix + 'form-cb-label',
  217. /**
  218. * @cfg {String} boxLabelAlign
  219. * The position relative to the checkbox where the {@link #boxLabel} should appear. Recognized values are 'before'
  220. * and 'after'.
  221. */
  222. boxLabelAlign: 'after',
  223. /**
  224. * @cfg {String} inputValue
  225. * The value that should go into the generated input element's value attribute and should be used as the parameter
  226. * value when submitting as part of a form.
  227. */
  228. inputValue: 'on',
  229. /**
  230. * @cfg {String} uncheckedValue
  231. * If configured, this will be submitted as the checkbox's value during form submit if the checkbox is unchecked. By
  232. * default this is undefined, which results in nothing being submitted for the checkbox field when the form is
  233. * submitted (the default behavior of HTML checkboxes).
  234. */
  235. /**
  236. * @cfg {Function} handler
  237. * A function called when the {@link #checked} value changes (can be used instead of handling the {@link #change
  238. * change event}).
  239. * @cfg {Ext.form.field.Checkbox} handler.checkbox The Checkbox being toggled.
  240. * @cfg {Boolean} handler.checked The new checked state of the checkbox.
  241. */
  242. /**
  243. * @cfg {Object} scope
  244. * An object to use as the scope ('this' reference) of the {@link #handler} function.
  245. *
  246. * Defaults to this Checkbox.
  247. */
  248. // private overrides
  249. checkChangeEvents: [],
  250. inputType: 'checkbox',
  251. // private
  252. onRe: /^on$/i,
  253. initComponent: function() {
  254. this.callParent(arguments);
  255. this.getManager().add(this);
  256. },
  257. initValue: function() {
  258. var me = this,
  259. checked = !!me.checked;
  260. /**
  261. * @property {Object} originalValue
  262. * The original value of the field as configured in the {@link #checked} configuration, or as loaded by the last
  263. * form load operation if the form's {@link Ext.form.Basic#trackResetOnLoad trackResetOnLoad} setting is `true`.
  264. */
  265. me.originalValue = me.lastValue = checked;
  266. // Set the initial checked state
  267. me.setValue(checked);
  268. },
  269. getElConfig: function() {
  270. var me = this;
  271. // Add the checked class if this begins checked
  272. if (me.isChecked(me.rawValue, me.inputValue)) {
  273. me.addCls(me.checkedCls);
  274. }
  275. return me.callParent();
  276. },
  277. getFieldStyle: function() {
  278. return Ext.isObject(this.fieldStyle) ? Ext.DomHelper.generateStyles(this.fieldStyle) : this.fieldStyle ||'';
  279. },
  280. getSubTplData: function() {
  281. var me = this;
  282. return Ext.apply(me.callParent(), {
  283. disabled : me.readOnly || me.disabled,
  284. boxLabel : me.boxLabel,
  285. boxLabelCls : me.boxLabelCls,
  286. boxLabelAlign : me.boxLabelAlign
  287. });
  288. },
  289. initEvents: function() {
  290. var me = this;
  291. me.callParent();
  292. me.mon(me.inputEl, 'click', me.onBoxClick, me);
  293. },
  294. /**
  295. * @private Handle click on the checkbox button
  296. */
  297. onBoxClick: function(e) {
  298. var me = this;
  299. if (!me.disabled && !me.readOnly) {
  300. this.setValue(!this.checked);
  301. }
  302. },
  303. /**
  304. * Returns the checked state of the checkbox.
  305. * @return {Boolean} True if checked, else false
  306. */
  307. getRawValue: function() {
  308. return this.checked;
  309. },
  310. /**
  311. * Returns the checked state of the checkbox.
  312. * @return {Boolean} True if checked, else false
  313. */
  314. getValue: function() {
  315. return this.checked;
  316. },
  317. /**
  318. * Returns the submit value for the checkbox which can be used when submitting forms.
  319. * @return {String} If checked the {@link #inputValue} is returned; otherwise the {@link #uncheckedValue}
  320. * (or null if the latter is not configured).
  321. */
  322. getSubmitValue: function() {
  323. var unchecked = this.uncheckedValue,
  324. uncheckedVal = Ext.isDefined(unchecked) ? unchecked : null;
  325. return this.checked ? this.inputValue : uncheckedVal;
  326. },
  327. isChecked: function(rawValue, inputValue) {
  328. return (rawValue === true || rawValue === 'true' || rawValue === '1' || rawValue === 1 ||
  329. (((Ext.isString(rawValue) || Ext.isNumber(rawValue)) && inputValue) ? rawValue == inputValue : this.onRe.test(rawValue)));
  330. },
  331. /**
  332. * Sets the checked state of the checkbox.
  333. *
  334. * @param {Boolean/String/Number} value The following values will check the checkbox:
  335. * `true, 'true', '1', 1, or 'on'`, as well as a String that matches the {@link #inputValue}.
  336. * Any other value will uncheck the checkbox.
  337. * @return {Boolean} the new checked state of the checkbox
  338. */
  339. setRawValue: function(value) {
  340. var me = this,
  341. inputEl = me.inputEl,
  342. checked = me.isChecked(value, me.inputValue);
  343. if (inputEl) {
  344. me[checked ? 'addCls' : 'removeCls'](me.checkedCls);
  345. }
  346. me.checked = me.rawValue = checked;
  347. return checked;
  348. },
  349. /**
  350. * Sets the checked state of the checkbox, and invokes change detection.
  351. * @param {Boolean/String} checked The following values will check the checkbox: `true, 'true', '1', or 'on'`, as
  352. * well as a String that matches the {@link #inputValue}. Any other value will uncheck the checkbox.
  353. * @return {Ext.form.field.Checkbox} this
  354. */
  355. setValue: function(checked) {
  356. var me = this,
  357. boxes, b, bLen, box;
  358. // If an array of strings is passed, find all checkboxes in the group with the same name as this
  359. // one and check all those whose inputValue is in the array, unchecking all the others. This is to
  360. // facilitate setting values from Ext.form.Basic#setValues, but is not publicly documented as we
  361. // don't want users depending on this behavior.
  362. if (Ext.isArray(checked)) {
  363. boxes = me.getManager().getByName(me.name).items,
  364. bLen = boxes.length;
  365. for (b = 0; b < bLen; b++) {
  366. box = boxes[b];
  367. box.setValue(Ext.Array.contains(checked, box.inputValue));
  368. }
  369. } else {
  370. me.callParent(arguments);
  371. }
  372. return me;
  373. },
  374. // private
  375. valueToRaw: function(value) {
  376. // No extra conversion for checkboxes
  377. return value;
  378. },
  379. /**
  380. * @private
  381. * Called when the checkbox's checked state changes. Invokes the {@link #handler} callback
  382. * function if specified.
  383. */
  384. onChange: function(newVal, oldVal) {
  385. var me = this,
  386. handler = me.handler;
  387. if (handler) {
  388. handler.call(me.scope || me, me, newVal);
  389. }
  390. me.callParent(arguments);
  391. },
  392. // inherit docs
  393. beforeDestroy: function(){
  394. this.callParent();
  395. this.getManager().removeAtKey(this.id);
  396. },
  397. // inherit docs
  398. getManager: function() {
  399. return Ext.form.CheckboxManager;
  400. },
  401. onEnable: function() {
  402. var me = this,
  403. inputEl = me.inputEl;
  404. me.callParent();
  405. if (inputEl) {
  406. // Can still be disabled if the field is readOnly
  407. inputEl.dom.disabled = me.readOnly;
  408. }
  409. },
  410. setReadOnly: function(readOnly) {
  411. var me = this,
  412. inputEl = me.inputEl;
  413. if (inputEl) {
  414. // Set the button to disabled when readonly
  415. inputEl.dom.disabled = !!readOnly || me.disabled;
  416. }
  417. me.callParent(arguments);
  418. }
  419. });