CheckedMultiSelect.js 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  1. /*
  2. Copyright (c) 2004-2012, The Dojo Foundation All Rights Reserved.
  3. Available via Academic Free License >= 2.1 OR the modified BSD license.
  4. see: http://dojotoolkit.org/license for details
  5. */
  6. if(!dojo._hasResource["dojox.form.CheckedMultiSelect"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  7. dojo._hasResource["dojox.form.CheckedMultiSelect"] = true;
  8. dojo.provide("dojox.form.CheckedMultiSelect");
  9. dojo.require("dijit.form.CheckBox");
  10. dojo.require("dijit.Tooltip");
  11. dojo.require("dijit.form._FormSelectWidget");
  12. dojo.declare("dojox.form._CheckedMultiSelectItem",
  13. [dijit._Widget, dijit._Templated],
  14. {
  15. // summary:
  16. // The individual items for a CheckedMultiSelect
  17. widgetsInTemplate: true,
  18. templateString: dojo.cache("dojox.form", "resources/_CheckedMultiSelectItem.html", "<div class=\"dijitReset ${baseClass}\"\n\t><input class=\"${baseClass}Box\" dojoType=\"dijit.form.CheckBox\" dojoAttachPoint=\"checkBox\" \n\t\tdojoAttachEvent=\"_onClick:_changeBox\" type=\"${_type.type}\" data-dojo-props='disabled:${disabled}, readOnly:${readOnly}' baseClass=\"${_type.baseClass}\"\n\t/><div class=\"dijitInline ${baseClass}Label\" dojoAttachPoint=\"labelNode\" dojoAttachEvent=\"onclick:_onClick\"></div\n></div>\n"),
  19. baseClass: "dojoxMultiSelectItem",
  20. // option: dojox.form.__SelectOption
  21. // The option that is associated with this item
  22. option: null,
  23. parent: null,
  24. // disabled: boolean
  25. // Whether or not this widget is disabled
  26. disabled: false,
  27. // readOnly: boolean
  28. // Whether or not this widget is readOnly
  29. readOnly: false,
  30. postMixInProperties: function(){
  31. // summary:
  32. // Set the appropriate _subClass value - based on if we are multi-
  33. // or single-select
  34. this._type = this.parent.multiple ?
  35. {type: "checkbox", baseClass: "dijitCheckBox"} :
  36. {type: "radio", baseClass: "dijitRadio"};
  37. // use global disabled/readOnly if set to true, otherwise use per-option setting
  38. if(!this.disabled){
  39. this.disabled = this.option.disabled = this.option.disabled||false;
  40. }
  41. if(!this.readOnly){
  42. this.readOnly = this.option.readOnly = this.option.readOnly||false;
  43. }
  44. this.inherited(arguments);
  45. },
  46. postCreate: function(){
  47. // summary:
  48. // Set innerHTML here - since the template gets messed up sometimes
  49. // with rich text
  50. this.inherited(arguments);
  51. this.labelNode.innerHTML = this.option.label;
  52. },
  53. _changeBox: function(){
  54. // summary:
  55. // Called to force the select to match the state of the check box
  56. // (only on click of the checkbox) Radio-based calls _setValueAttr
  57. // instead.
  58. if(this.get("disabled") || this.get("readOnly")){ return; }
  59. if(this.parent.multiple){
  60. this.option.selected = this.checkBox.get('value') && true;
  61. }else{
  62. this.parent.set('value', this.option.value);
  63. }
  64. // fire the parent's change
  65. this.parent._updateSelection();
  66. // refocus the parent
  67. this.parent.focus();
  68. },
  69. _onClick: function(e){
  70. // summary:
  71. // Sets the click state (passes through to the check box)
  72. if(this.get("disabled") || this.get("readOnly")){
  73. dojo.stopEvent(e);
  74. }else{
  75. this.checkBox._onClick(e);
  76. }
  77. },
  78. _updateBox: function(){
  79. // summary:
  80. // Called to force the box to match the state of the select
  81. this.checkBox.set('value', this.option.selected);
  82. },
  83. _setDisabledAttr: function(value){
  84. // summary:
  85. // Disables (or enables) all the children as well
  86. this.disabled = value||this.option.disabled;
  87. this.checkBox.set("disabled", this.disabled);
  88. dojo.toggleClass(this.domNode, "dojoxMultiSelectDisabled", this.disabled);
  89. },
  90. _setReadOnlyAttr: function(value){
  91. // summary:
  92. // Sets read only (or unsets) all the children as well
  93. this.checkBox.set("readOnly", value);
  94. this.readOnly = value;
  95. }
  96. });
  97. dojo.declare("dojox.form.CheckedMultiSelect", dijit.form._FormSelectWidget, {
  98. // summary:
  99. // Extends the core dijit MultiSelect to provide a "checkbox" selector
  100. templateString: dojo.cache("dojox.form", "resources/CheckedMultiSelect.html", "<div class=\"dijit dijitReset dijitInline\" dojoAttachEvent=\"onmousedown:_onMouseDown,onclick:focus\"\n\t><select class=\"${baseClass}Select\" multiple=\"true\" dojoAttachPoint=\"containerNode,focusNode\"></select\n\t><div dojoAttachPoint=\"wrapperDiv\"></div\n></div>\n"),
  101. baseClass: "dojoxMultiSelect",
  102. // required: Boolean
  103. // User is required to check at least one item.
  104. required: false,
  105. // invalidMessage: String
  106. // The message to display if value is invalid.
  107. invalidMessage: "At least one item must be selected.",
  108. // _message: String
  109. // Currently displayed message
  110. _message: "",
  111. // tooltipPosition: String[]
  112. // See description of `dijit.Tooltip.defaultPosition` for details on this parameter.
  113. tooltipPosition: [],
  114. _onMouseDown: function(e){
  115. // summary:
  116. // Cancels the mousedown event to prevent others from stealing
  117. // focus
  118. dojo.stopEvent(e);
  119. },
  120. validator: function() {
  121. // summary:
  122. // Overridable function used to validate that an item is selected if required =
  123. // true.
  124. // tags:
  125. // protected
  126. if (!this.required){ return true; }
  127. return dojo.some(this.getOptions(), function(opt){
  128. return opt.selected && opt.value != null && opt.value.toString().length != 0;
  129. });
  130. },
  131. validate: function(isFocused) {
  132. dijit.hideTooltip(this.domNode);
  133. var isValid = this.isValid(isFocused);
  134. if(!isValid){ this.displayMessage(this.invalidMessage); }
  135. return isValid;
  136. },
  137. isValid: function(/*Boolean*/ isFocused) {
  138. // summary:
  139. // Tests if the required items are selected.
  140. // Can override with your own routine in a subclass.
  141. // tags:
  142. // protected
  143. return this.validator();
  144. },
  145. getErrorMessage: function(/*Boolean*/ isFocused) {
  146. // summary:
  147. // Return an error message to show if appropriate
  148. // tags:
  149. // protected
  150. return this.invalidMessage;
  151. },
  152. displayMessage: function(/*String*/ message) {
  153. // summary:
  154. // Overridable method to display validation errors/hints.
  155. // By default uses a tooltip.
  156. // tags:
  157. // extension
  158. dijit.hideTooltip(this.domNode);
  159. if(message){
  160. dijit.showTooltip(message, this.domNode, this.tooltipPosition);
  161. }
  162. },
  163. onAfterAddOptionItem: function(item, option){
  164. // summary:
  165. // a function that can be connected to in order to receive a
  166. // notification that an item as been added to this dijit.
  167. },
  168. _addOptionItem: function(/* dojox.form.__SelectOption */ option){
  169. var item = new dojox.form._CheckedMultiSelectItem({
  170. option: option,
  171. parent: this,
  172. disabled: this.disabled,
  173. readOnly: this.readOnly
  174. });
  175. this.wrapperDiv.appendChild(item.domNode);
  176. this.onAfterAddOptionItem(item, option);
  177. },
  178. _refreshState: function(){
  179. // summary:
  180. // Validate if selection changes.
  181. this.validate(this._focused);
  182. },
  183. onChange: function(newValue){
  184. // summary:
  185. // Validate if selection changes.
  186. this._refreshState();
  187. },
  188. reset: function(){
  189. // summary: Overridden so that the state will be cleared.
  190. this.inherited(arguments);
  191. dijit.hideTooltip(this.domNode);
  192. },
  193. _updateSelection: function(){
  194. this.inherited(arguments);
  195. this._handleOnChange(this.value);
  196. dojo.forEach(this._getChildren(), function(c){ c._updateBox(); });
  197. },
  198. _getChildren: function(){
  199. return dojo.map(this.wrapperDiv.childNodes, function(n){
  200. return dijit.byNode(n);
  201. });
  202. },
  203. invertSelection: function(onChange){
  204. // summary: Invert the selection
  205. // onChange: Boolean
  206. // If null, onChange is not fired.
  207. dojo.forEach(this.options, function(i){
  208. i.selected = !i.selected;
  209. });
  210. this._updateSelection();
  211. },
  212. _setDisabledAttr: function(value){
  213. // summary:
  214. // Disable (or enable) all the children as well
  215. this.inherited(arguments);
  216. dojo.forEach(this._getChildren(), function(node){
  217. if(node && node.set){
  218. node.set("disabled", value);
  219. }
  220. });
  221. },
  222. _setReadOnlyAttr: function(value){
  223. // summary:
  224. // Sets read only (or unsets) all the children as well
  225. if("readOnly" in this.attributeMap){
  226. this._attrToDom("readOnly", value);
  227. }
  228. this.readOnly = value;
  229. dojo.forEach(this._getChildren(), function(node){
  230. if(node && node.set){
  231. node.set("readOnly", value);
  232. }
  233. });
  234. },
  235. uninitialize: function(){
  236. dijit.hideTooltip(this.domNode);
  237. // Make sure these children are destroyed
  238. dojo.forEach(this._getChildren(), function(child){
  239. child.destroyRecursive();
  240. });
  241. this.inherited(arguments);
  242. }
  243. });
  244. }