/js/widgets/forms/rangeslider.js

https://bitbucket.org/zachjarvinen/jquery-mobile · JavaScript · 249 lines · 194 code · 34 blank · 21 comment · 18 complexity · e064cd2d8cd6b440174c4d0f0693fe6e MD5 · raw file

  1. //>>excludeStart("jqmBuildExclude", pragmas.jqmBuildExclude);
  2. //>>description: Range Slider form widget
  3. //>>label: Range Slider
  4. //>>group: Forms
  5. //>>css.structure: ../css/structure/jquery.mobile.forms.rangeslider.css
  6. //>>css.theme: ../css/themes/default/jquery.mobile.theme.css
  7. define( [ "jquery",
  8. "../../jquery.mobile.core",
  9. "../../jquery.mobile.widget",
  10. "./textinput",
  11. "./reset",
  12. "../optionDemultiplexer",
  13. "./slider" ], function( jQuery ) {
  14. //>>excludeEnd("jqmBuildExclude");
  15. (function( $, undefined ) {
  16. $.widget( "mobile.rangeslider", $.mobile.widget, $.extend( {
  17. options: {
  18. theme: null,
  19. trackTheme: null,
  20. corners: true,
  21. mini: false,
  22. highlight: true
  23. },
  24. _create: function() {
  25. var $el = this.element,
  26. elClass = this.options.mini ? "ui-rangeslider ui-mini" : "ui-rangeslider",
  27. _inputFirst = $el.find( "input" ).first(),
  28. _inputLast = $el.find( "input" ).last(),
  29. _label = $el.find( "label" ).first(),
  30. _sliderFirst = $.data( _inputFirst.get(0), "mobile-slider" ).slider,
  31. _sliderLast = $.data( _inputLast.get(0), "mobile-slider" ).slider,
  32. firstHandle = $.data( _inputFirst.get(0), "mobile-slider" ).handle,
  33. _sliders = $( "<div class='ui-rangeslider-sliders' />" ).appendTo( $el );
  34. _inputFirst.addClass( "ui-rangeslider-first" );
  35. _inputLast.addClass( "ui-rangeslider-last" );
  36. $el.addClass( elClass );
  37. _sliderFirst.appendTo( _sliders );
  38. _sliderLast.appendTo( _sliders );
  39. _label.insertBefore( $el );
  40. firstHandle.prependTo( _sliderLast );
  41. $.extend( this, {
  42. _inputFirst: _inputFirst,
  43. _inputLast: _inputLast,
  44. _sliderFirst: _sliderFirst,
  45. _sliderLast: _sliderLast,
  46. _label: _label,
  47. _targetVal: null,
  48. _sliderTarget: false,
  49. _sliders: _sliders,
  50. _proxy: false
  51. });
  52. this.refresh();
  53. this._on( this.element.find( "input.ui-slider-input" ), {
  54. "slidebeforestart": "_slidebeforestart",
  55. "slidestop": "_slidestop",
  56. "slidedrag": "_slidedrag",
  57. "slidebeforechange": "_change",
  58. "blur": "_change",
  59. "keyup": "_change"
  60. });
  61. this._on({
  62. "mousedown":"_change"
  63. });
  64. this._on( this.element.closest( "form" ), {
  65. "reset":"_handleReset"
  66. });
  67. this._on( firstHandle, {
  68. "vmousedown": "_dragFirstHandle"
  69. });
  70. },
  71. _handleReset: function(){
  72. var self = this;
  73. //we must wait for the stack to unwind before updateing other wise sliders will not have updated yet
  74. setTimeout( function(){
  75. self._updateHighlight();
  76. },0);
  77. },
  78. _dragFirstHandle: function( event ) {
  79. //if the first handle is dragged send the event to the first slider
  80. $.data( this._inputFirst.get(0), "mobile-slider" ).dragging = true;
  81. $.data( this._inputFirst.get(0), "mobile-slider" ).refresh( event );
  82. return false;
  83. },
  84. _slidedrag: function( event ) {
  85. var first = $( event.target ).is( this._inputFirst ),
  86. otherSlider = ( first ) ? this._inputLast : this._inputFirst;
  87. this._sliderTarget = false;
  88. //if the drag was initiated on an extreme and the other handle is focused send the events to
  89. //the closest handle
  90. if ( ( this._proxy === "first" && first ) || ( this._proxy === "last" && !first ) ) {
  91. $.data( otherSlider.get(0), "mobile-slider" ).dragging = true;
  92. $.data( otherSlider.get(0), "mobile-slider" ).refresh( event );
  93. return false;
  94. }
  95. },
  96. _slidestop: function( event ) {
  97. var first = $( event.target ).is( this._inputFirst );
  98. this._proxy = false;
  99. //this stops dragging of the handle and brings the active track to the front
  100. //this makes clicks on the track go the the last handle used
  101. this.element.find( "input" ).trigger( "vmouseup" );
  102. this._sliderFirst.css( "z-index", first ? 1 : "" );
  103. },
  104. _slidebeforestart: function( event ) {
  105. this._sliderTarget = false;
  106. //if the track is the target remember this and the original value
  107. if ( $( event.originalEvent.target ).hasClass( "ui-slider-track" ) ) {
  108. this._sliderTarget = true;
  109. this._targetVal = $( event.target ).val();
  110. }
  111. },
  112. _setOption: function( options ) {
  113. this._superApply( options );
  114. this.refresh();
  115. },
  116. refresh: function() {
  117. var $el = this.element,
  118. o = this.options;
  119. $el.find( "input" ).slider({
  120. theme: o.theme,
  121. trackTheme: o.trackTheme,
  122. disabled: o.disabled,
  123. corners: o.corners,
  124. mini: o.mini,
  125. highlight: o.highlight
  126. }).slider( "refresh" );
  127. this._updateHighlight();
  128. },
  129. _change: function( event ) {
  130. if ( event.type === "keyup" ) {
  131. this._updateHighlight();
  132. return false;
  133. }
  134. var self = this,
  135. min = parseFloat( this._inputFirst.val(), 10 ),
  136. max = parseFloat( this._inputLast.val(), 10 ),
  137. first = $( event.target ).hasClass( "ui-rangeslider-first" ),
  138. thisSlider = first ? this._inputFirst : this._inputLast,
  139. otherSlider = first ? this._inputLast : this._inputFirst;
  140. if( ( this._inputFirst.val() > this._inputLast.val() && event.type === "mousedown" && !$(event.target).hasClass("ui-slider-handle")) ){
  141. thisSlider.blur();
  142. } else if( event.type === "mousedown" ){
  143. return;
  144. }
  145. if ( min > max && !this._sliderTarget ) {
  146. //this prevents min from being greater then max
  147. thisSlider.val( first ? max: min ).slider( "refresh" );
  148. this._trigger( "normalize" );
  149. } else if ( min > max ) {
  150. //this makes it so clicks on the target on either extreme go to the closest handle
  151. thisSlider.val( this._targetVal ).slider( "refresh" );
  152. //You must wait for the stack to unwind so first slider is updated before updating second
  153. setTimeout( function() {
  154. otherSlider.val( first ? min: max ).slider( "refresh" );
  155. $.data( otherSlider.get(0), "mobile-slider" ).handle.focus();
  156. self._sliderFirst.css( "z-index", first ? "" : 1 );
  157. self._trigger( "normalize" );
  158. }, 0 );
  159. this._proxy = ( first ) ? "first" : "last";
  160. }
  161. //fixes issue where when both _sliders are at min they cannot be adjusted
  162. if ( min === max ) {
  163. $.data( thisSlider.get(0), "mobile-slider" ).handle.css( "z-index", 1 );
  164. $.data( otherSlider.get(0), "mobile-slider" ).handle.css( "z-index", 0 );
  165. } else {
  166. $.data( otherSlider.get(0), "mobile-slider" ).handle.css( "z-index", "" );
  167. $.data( thisSlider.get(0), "mobile-slider" ).handle.css( "z-index", "" );
  168. }
  169. this._updateHighlight();
  170. if ( min >= max ) {
  171. return false;
  172. }
  173. },
  174. _updateHighlight: function() {
  175. var min = parseInt( $.data( this._inputFirst.get(0), "mobile-slider" ).handle.get(0).style.left, 10 ),
  176. max = parseInt( $.data( this._inputLast.get(0), "mobile-slider" ).handle.get(0).style.left, 10 ),
  177. width = (max - min);
  178. this.element.find( ".ui-slider-bg" ).css({
  179. "margin-left": min + "%",
  180. "width": width + "%"
  181. });
  182. },
  183. _setTheme: function( value ) {
  184. this._inputFirst.slider( "option", "theme", value );
  185. this._inputLast.slider( "option", "theme", value );
  186. },
  187. _setTrackTheme: function( value ) {
  188. this._inputFirst.slider( "option", "trackTheme", value );
  189. this._inputLast.slider( "option", "trackTheme", value );
  190. },
  191. _setMini: function( value ) {
  192. this._inputFirst.slider( "option", "mini", value );
  193. this._inputLast.slider( "option", "mini", value );
  194. this.element.toggleClass( "ui-mini", !!value );
  195. },
  196. _setHighlight: function( value ) {
  197. this._inputFirst.slider( "option", "highlight", value );
  198. this._inputLast.slider( "option", "highlight", value );
  199. },
  200. _destroy: function() {
  201. this._label.prependTo( this.element );
  202. this.element.removeClass( "ui-rangeslider ui-mini" );
  203. this._inputFirst.after( this._sliderFirst );
  204. this._inputLast.after( this._sliderLast );
  205. this._sliders.remove();
  206. this.element.find( "input" ).removeClass( "ui-rangeslider-first ui-rangeslider-last" ).slider( "destroy" );
  207. }
  208. }, $.mobile.behaviors.formReset, $.mobile.behaviors.optionDemultiplexer ) );
  209. $.mobile.rangeslider.initSelector = ":jqmData(role='rangeslider')";
  210. //auto self-init widgets
  211. $.mobile._enhancer.add( "mobile.rangeslider", { dependencies: [ "mobile.slider" ] } );
  212. })( jQuery );
  213. //>>excludeStart("jqmBuildExclude", pragmas.jqmBuildExclude);
  214. });
  215. //>>excludeEnd("jqmBuildExclude");