ui.checkbox.js 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. /**
  2. * @author alexander.farkas
  3. * @version 1.4.3
  4. */
  5. (function($){
  6. var supportsValidity;
  7. (function(){
  8. if(!$.prop || supportsValidity){return;}
  9. var supportTest = function(){
  10. supportsValidity = !!$('<input />').prop('validity');
  11. };
  12. supportTest();
  13. $(supportTest);
  14. })();
  15. $.widget('ui.checkBox', {
  16. options: {
  17. hideInput: true,
  18. addVisualElement: true,
  19. addLabel: true
  20. },
  21. _create: function(){
  22. var that = this,
  23. opts = this.options
  24. ;
  25. if(!this.element.is(':radio,:checkbox')){
  26. if(this.element[0].elements && $.nodeName(this.element[0], 'form')){
  27. $(this.element[0].elements).filter(':radio,:checkbox').checkBox(opts);
  28. }
  29. return false;
  30. }
  31. this._proxiedReflectUI = $.proxy(this, 'reflectUI');
  32. this.labels = $([]);
  33. this.checkedStatus = false;
  34. this.disabledStatus = false;
  35. this.hoverStatus = false;
  36. this.inputType = this.element[0].type;
  37. this.radio = this.inputType == 'radio';
  38. this.visualElement = $([]);
  39. if (opts.hideInput) {
  40. this.element.addClass('ui-helper-hidden-accessible');
  41. if(opts.addVisualElement){
  42. this.visualElement = $('<span />')
  43. .addClass('ui-'+this.inputType)
  44. ;
  45. this.element.after(this.visualElement[0]);
  46. }
  47. }
  48. if(opts.addLabel){
  49. var id = this.element[0].id;
  50. if(id){
  51. this.labels = $('label[for="' + id + '"]', this.element[0].form || this.element[0].ownerDocument).add(this.element.parent('label'));
  52. }
  53. if(!this.labels[0]){
  54. this.labels = this.element.closest('label', this.element[0].form);
  55. }
  56. this.labels.addClass(this.radio ? 'ui-radio' : 'ui-checkbox');
  57. }
  58. this.visualGroup = this.visualElement.add(this.labels);
  59. this._addEvents();
  60. this.initialized = true;
  61. this.reflectUI({type: 'initialreflect'});
  62. return undefined;
  63. },
  64. _addEvents: function(){
  65. var that = this,
  66. opts = this.options,
  67. toggleHover = function(e){
  68. if(that.disabledStatus){
  69. return false;
  70. }
  71. that.hover = (e.type == 'focus' || e.type == 'mouseenter');
  72. if(e.type == 'focus'){
  73. that.visualGroup.addClass(that.inputType +'-focused');
  74. } else if(e.type == 'blur'){
  75. that.visualGroup.removeClass(that.inputType +'-focused');
  76. }
  77. that._changeStateClassChain();
  78. return undefined;
  79. }
  80. ;
  81. this.element
  82. .bind('click.checkBox invalid.checkBox', this._proxiedReflectUI)
  83. .bind('focus.checkBox blur.checkBox', toggleHover)
  84. ;
  85. if (opts.hideInput){
  86. this.element
  87. .bind('usermode', function(e){
  88. (e.enabled &&
  89. that.destroy.call(that, true));
  90. })
  91. ;
  92. }
  93. if(opts.addVisualElement){
  94. this.visualElement
  95. .bind('click.checkBox', function(e){
  96. that.element[0].click();
  97. return false;
  98. })
  99. ;
  100. }
  101. this.visualGroup.bind('mouseenter.checkBox mouseleave.checkBox', toggleHover);
  102. },
  103. _changeStateClassChain: function(){
  104. var allElements = this.labels.add(this.visualElement),
  105. stateClass = '',
  106. baseClass = 'ui-'+ this.inputType
  107. ;
  108. if(this.checkedStatus){
  109. stateClass += '-checked';
  110. allElements.addClass(baseClass+'-checked');
  111. } else {
  112. allElements.removeClass(baseClass+'-checked');
  113. }
  114. if(this.disabledStatus){
  115. stateClass += '-disabled';
  116. allElements.addClass(baseClass+'-disabled');
  117. } else {
  118. allElements.removeClass(baseClass+'-disabled');
  119. }
  120. if(this.hover){
  121. stateClass += '-hover';
  122. allElements.addClass(baseClass+'-hover');
  123. } else {
  124. allElements.removeClass(baseClass+'-hover');
  125. }
  126. baseClass += '-state';
  127. if(stateClass){
  128. stateClass = baseClass + stateClass;
  129. }
  130. function switchStateClass(){
  131. var classes = this.className.split(' '),
  132. found = false;
  133. $.each(classes, function(i, classN){
  134. if(classN.indexOf(baseClass) === 0){
  135. found = true;
  136. classes[i] = stateClass;
  137. return false;
  138. }
  139. return undefined;
  140. });
  141. if(!found){
  142. classes.push(stateClass);
  143. }
  144. this.className = classes.join(' ');
  145. }
  146. this.visualGroup.each(switchStateClass);
  147. },
  148. destroy: function(onlyCss){
  149. this.element.removeClass('ui-helper-hidden-accessible');
  150. this.visualElement.addClass('ui-helper-hidden');
  151. if (!onlyCss) {
  152. var o = this.options;
  153. this.element.unbind('.checkBox');
  154. this.visualElement.remove();
  155. this.labels
  156. .unbind('.checkBox')
  157. .removeClass('ui-state-hover ui-state-checked ui-state-disabled')
  158. ;
  159. }
  160. },
  161. disable: function(status){
  162. if(status === undefined){
  163. status = true;
  164. }
  165. this.element[0].disabled = status;
  166. this.reflectUI({type: 'manuallydisabled'});
  167. },
  168. enable: function(){
  169. this.element[0].disabled = false;
  170. this.reflectUI({type: 'manuallyenabled'});
  171. },
  172. toggle: function(e){
  173. this.changeCheckStatus(!(this.element.is(':checked')), e);
  174. },
  175. changeCheckStatus: function(status, e){
  176. if(e && e.type == 'click' && this.element[0].disabled){
  177. return false;
  178. }
  179. this.element[0].checked = !!status;
  180. this.reflectUI(e || {
  181. type: 'changecheckstatus'
  182. });
  183. return undefined;
  184. },
  185. propagate: function(n, e, _noGroupReflect){
  186. if(!e || e.type != 'initialreflect'){
  187. if (this.radio && !_noGroupReflect) {
  188. var elem = this.element[0];
  189. //dynamic
  190. $('[name="'+ elem.name +'"]', elem.form || elem.ownerDocument).checkBox('reflectUI', e, true);
  191. }
  192. return this._trigger(n, e, {
  193. options: this.options,
  194. checked: this.checkedStatus,
  195. labels: this.labels,
  196. disabled: this.disabledStatus
  197. });
  198. }
  199. return undefined;
  200. },
  201. changeValidityState: function(){
  202. if(supportsValidity){
  203. this.visualGroup[ !this.element.prop('willValidate') || (this.element.prop('validity') || {valid: true}).valid ? 'removeClass' : 'addClass' ](this.inputType +'-invalid');
  204. }
  205. },
  206. reflectUI: function(e){
  207. var oldChecked = this.checkedStatus,
  208. oldDisabledStatus = this.disabledStatus
  209. ;
  210. this.disabledStatus = this.element.is(':disabled');
  211. this.checkedStatus = this.element.is(':checked');
  212. if(!e || e.type !== 'initialreflect'){
  213. this.changeValidityState();
  214. }
  215. if (this.disabledStatus != oldDisabledStatus || this.checkedStatus !== oldChecked) {
  216. this._changeStateClassChain();
  217. (this.disabledStatus != oldDisabledStatus &&
  218. this.propagate('disabledchange', e));
  219. (this.checkedStatus !== oldChecked &&
  220. this.propagate('change', e));
  221. }
  222. }
  223. });
  224. if($.propHooks){
  225. $.each({checked: 'changeCheckStatus', disabled: 'disable'}, function(name, fn){
  226. //be hook friendly
  227. if(!$.propHooks[name]){
  228. $.propHooks[name] = {};
  229. }
  230. var oldSetHook = $.propHooks[name].set;
  231. $.propHooks[name].set = function(elem, value){
  232. var widget = $.data(elem, 'checkBox');
  233. if(widget){
  234. widget[fn](!!value);
  235. }
  236. return oldSetHook && oldSetHook(elem, value) ;
  237. };
  238. });
  239. }
  240. })(jQuery);