/js/jquery.mobile.forms.checkboxradio.js

https://github.com/dannyc/jquery-mobile · JavaScript · 196 lines · 134 code · 41 blank · 21 comment · 17 complexity · 576ecdae24aa80071821749db42b2d53 MD5 · raw file

  1. /*
  2. * "checkboxradio" plugin
  3. */
  4. (function( $, undefined ) {
  5. $.widget( "mobile.checkboxradio", $.mobile.widget, {
  6. options: {
  7. theme: null,
  8. initSelector: "input[type='checkbox'],input[type='radio']"
  9. },
  10. _create: function() {
  11. var self = this,
  12. input = this.element,
  13. // NOTE: Windows Phone could not find the label through a selector
  14. // filter works though.
  15. label = input.closest( "form,fieldset,:jqmData(role='page')" ).find( "label" ).filter( "[for='" + input[ 0 ].id + "']" ),
  16. inputtype = input.attr( "type" ),
  17. checkedState = inputtype + "-on",
  18. uncheckedState = inputtype + "-off",
  19. icon = input.parents( ":jqmData(type='horizontal')" ).length ? undefined : uncheckedState,
  20. activeBtn = icon ? "" : " " + $.mobile.activeBtnClass,
  21. checkedClass = "ui-" + checkedState + activeBtn,
  22. uncheckedClass = "ui-" + uncheckedState,
  23. checkedicon = "ui-icon-" + checkedState,
  24. uncheckedicon = "ui-icon-" + uncheckedState;
  25. if ( inputtype !== "checkbox" && inputtype !== "radio" ) {
  26. return;
  27. }
  28. // Expose for other methods
  29. $.extend( this, {
  30. label: label,
  31. inputtype: inputtype,
  32. checkedClass: checkedClass,
  33. uncheckedClass: uncheckedClass,
  34. checkedicon: checkedicon,
  35. uncheckedicon: uncheckedicon
  36. });
  37. // If there's no selected theme...
  38. if( !this.options.theme ) {
  39. this.options.theme = this.element.jqmData( "theme" );
  40. }
  41. label.buttonMarkup({
  42. theme: this.options.theme,
  43. icon: icon,
  44. shadow: false
  45. });
  46. // Wrap the input + label in a div
  47. input.add( label )
  48. .wrapAll( "<div class='ui-" + inputtype + "'></div>" );
  49. label.bind({
  50. vmouseover: function( event ) {
  51. if ( $( this ).parent().is( ".ui-disabled" ) ) {
  52. event.stopPropagation();
  53. }
  54. },
  55. vclick: function( event ) {
  56. if ( input.is( ":disabled" ) ) {
  57. event.preventDefault();
  58. return;
  59. }
  60. self._cacheVals();
  61. input.prop( "checked", inputtype === "radio" && true || !input.prop( "checked" ) );
  62. // trigger click handler's bound directly to the input as a substitute for
  63. // how label clicks behave normally in the browsers
  64. // TODO: it would be nice to let the browser's handle the clicks and pass them
  65. // through to the associate input. we can swallow that click at the parent
  66. // wrapper element level
  67. input.triggerHandler( 'click' );
  68. // Input set for common radio buttons will contain all the radio
  69. // buttons, but will not for checkboxes. clearing the checked status
  70. // of other radios ensures the active button state is applied properly
  71. self._getInputSet().not( input ).prop( "checked", false );
  72. self._updateAll();
  73. return false;
  74. }
  75. });
  76. input
  77. .bind({
  78. vmousedown: function() {
  79. self._cacheVals();
  80. },
  81. vclick: function() {
  82. var $this = $(this);
  83. // Adds checked attribute to checked input when keyboard is used
  84. if ( $this.is( ":checked" ) ) {
  85. $this.prop( "checked", true);
  86. self._getInputSet().not($this).prop( "checked", false );
  87. } else {
  88. $this.prop( "checked", false );
  89. }
  90. self._updateAll();
  91. },
  92. focus: function() {
  93. label.addClass( "ui-focus" );
  94. },
  95. blur: function() {
  96. label.removeClass( "ui-focus" );
  97. }
  98. });
  99. this.refresh();
  100. },
  101. _cacheVals: function() {
  102. this._getInputSet().each(function() {
  103. var $this = $(this);
  104. $this.jqmData( "cacheVal", $this.is( ":checked" ) );
  105. });
  106. },
  107. //returns either a set of radios with the same name attribute, or a single checkbox
  108. _getInputSet: function(){
  109. if(this.inputtype == "checkbox") {
  110. return this.element;
  111. }
  112. return this.element.closest( "form,fieldset,:jqmData(role='page')" )
  113. .find( "input[name='"+ this.element.attr( "name" ) +"'][type='"+ this.inputtype +"']" );
  114. },
  115. _updateAll: function() {
  116. var self = this;
  117. this._getInputSet().each(function() {
  118. var $this = $(this);
  119. if ( $this.is( ":checked" ) || self.inputtype === "checkbox" ) {
  120. $this.trigger( "change" );
  121. }
  122. })
  123. .checkboxradio( "refresh" );
  124. },
  125. refresh: function() {
  126. var input = this.element,
  127. label = this.label,
  128. icon = label.find( ".ui-icon" );
  129. // input[0].checked expando doesn't always report the proper value
  130. // for checked='checked'
  131. if ( $( input[ 0 ] ).prop( "checked" ) ) {
  132. label.addClass( this.checkedClass ).removeClass( this.uncheckedClass );
  133. icon.addClass( this.checkedicon ).removeClass( this.uncheckedicon );
  134. } else {
  135. label.removeClass( this.checkedClass ).addClass( this.uncheckedClass );
  136. icon.removeClass( this.checkedicon ).addClass( this.uncheckedicon );
  137. }
  138. if ( input.is( ":disabled" ) ) {
  139. this.disable();
  140. } else {
  141. this.enable();
  142. }
  143. },
  144. disable: function() {
  145. this.element.prop( "disabled", true ).parent().addClass( "ui-disabled" );
  146. },
  147. enable: function() {
  148. this.element.prop( "disabled", false ).parent().removeClass( "ui-disabled" );
  149. }
  150. });
  151. //auto self-init widgets
  152. $( document ).bind( "pagecreate create", function( e ){
  153. $.mobile.checkboxradio.prototype.enhanceWithin( e.target );
  154. });
  155. })( jQuery );