@@ -70,6 +70,7 @@ $.fn.slider = function(parameters) {
7070
7171 $module = $ ( this ) ,
7272 $currThumb ,
73+ touchIdentifier ,
7374 $thumb ,
7475 $secondThumb ,
7576 $track ,
@@ -86,7 +87,6 @@ $.fn.slider = function(parameters) {
8687 secondPos ,
8788 offset ,
8889 precision ,
89- isTouch ,
9090 gapRatio = 1 ,
9191 previousValue ,
9292
@@ -104,7 +104,6 @@ $.fn.slider = function(parameters) {
104104 currentRange += 1 ;
105105 documentEventID = currentRange ;
106106
107- isTouch = module . setup . testOutTouch ( ) ;
108107 module . setup . layout ( ) ;
109108 module . setup . labels ( ) ;
110109
@@ -175,14 +174,6 @@ $.fn.slider = function(parameters) {
175174 }
176175 }
177176 } ,
178- testOutTouch : function ( ) {
179- try {
180- document . createEvent ( 'TouchEvent' ) ;
181- return true ;
182- } catch ( e ) {
183- return false ;
184- }
185- } ,
186177 customLabel : function ( ) {
187178 var
188179 $children = $labels . find ( '.label' ) ,
@@ -236,9 +227,6 @@ $.fn.slider = function(parameters) {
236227 module . bind . globalKeyboardEvents ( ) ;
237228 module . bind . keyboardEvents ( ) ;
238229 module . bind . mouseEvents ( ) ;
239- if ( module . is . touch ( ) ) {
240- module . bind . touchEvents ( ) ;
241- }
242230 if ( settings . autoAdjustLabels ) {
243231 module . bind . windowEvents ( ) ;
244232 }
@@ -251,7 +239,7 @@ $.fn.slider = function(parameters) {
251239 $ ( document ) . on ( 'keydown' + eventNamespace + documentEventID , module . event . activateFocus ) ;
252240 } ,
253241 mouseEvents : function ( ) {
254- module . verbose ( 'Binding mouse events' ) ;
242+ module . verbose ( 'Binding mouse and touch events' ) ;
255243 $module . find ( '.track, .thumb, .inner' ) . on ( 'mousedown' + eventNamespace , function ( event ) {
256244 event . stopImmediatePropagation ( ) ;
257245 event . preventDefault ( ) ;
@@ -264,27 +252,20 @@ $.fn.slider = function(parameters) {
264252 $module . on ( 'mouseleave' + eventNamespace , function ( event ) {
265253 isHover = false ;
266254 } ) ;
267- } ,
268- touchEvents : function ( ) {
269- module . verbose ( 'Binding touch events' ) ;
270- $module . find ( '.track, .thumb, .inner' ) . on ( 'touchstart' + eventNamespace , function ( event ) {
271- event . stopImmediatePropagation ( ) ;
272- event . preventDefault ( ) ;
273- module . event . down ( event ) ;
274- } ) ;
275- $module . on ( 'touchstart' + eventNamespace , module . event . down ) ;
255+ // All touch events are invoked on the element where the touch *started*. Thus, we can bind them all
256+ // on the thumb(s) and don't need to worry about interference with other components, i.e. no dynamic binding
257+ // and unbinding required.
258+ $module . find ( '.thumb' )
259+ . on ( 'touchstart' + eventNamespace , module . event . touchDown )
260+ . on ( 'touchmove' + eventNamespace , module . event . move )
261+ . on ( 'touchend' + eventNamespace , module . event . up )
262+ . on ( 'touchcancel' + eventNamespace , module . event . touchCancel ) ;
276263 } ,
277264 slidingEvents : function ( ) {
278265 // these don't need the identifier because we only ever want one of them to be registered with document
279266 module . verbose ( 'Binding page wide events while handle is being draged' ) ;
280- if ( module . is . touch ( ) ) {
281- $ ( document ) . on ( 'touchmove' + eventNamespace , module . event . move ) ;
282- $ ( document ) . on ( 'touchend' + eventNamespace , module . event . up ) ;
283- }
284- else {
285- $ ( document ) . on ( 'mousemove' + eventNamespace , module . event . move ) ;
286- $ ( document ) . on ( 'mouseup' + eventNamespace , module . event . up ) ;
287- }
267+ $ ( document ) . on ( 'mousemove' + eventNamespace , module . event . move ) ;
268+ $ ( document ) . on ( 'mouseup' + eventNamespace , module . event . up ) ;
288269 } ,
289270 windowEvents : function ( ) {
290271 $window . on ( 'resize' + eventNamespace , module . event . resize ) ;
@@ -294,24 +275,22 @@ $.fn.slider = function(parameters) {
294275 unbind : {
295276 events : function ( ) {
296277 $module . find ( '.track, .thumb, .inner' ) . off ( 'mousedown' + eventNamespace ) ;
297- $module . find ( '.track, .thumb, .inner' ) . off ( 'touchstart' + eventNamespace ) ;
298278 $module . off ( 'mousedown' + eventNamespace ) ;
299279 $module . off ( 'mouseenter' + eventNamespace ) ;
300280 $module . off ( 'mouseleave' + eventNamespace ) ;
301- $module . off ( 'touchstart' + eventNamespace ) ;
281+ $module . find ( '.thumb' )
282+ . off ( 'touchstart' + eventNamespace )
283+ . off ( 'touchmove' + eventNamespace )
284+ . off ( 'touchend' + eventNamespace )
285+ . off ( 'touchcancel' + eventNamespace ) ;
302286 $module . off ( 'keydown' + eventNamespace ) ;
303287 $module . off ( 'focusout' + eventNamespace ) ;
304288 $ ( document ) . off ( 'keydown' + eventNamespace + documentEventID , module . event . activateFocus ) ;
305289 $window . off ( 'resize' + eventNamespace ) ;
306290 } ,
307291 slidingEvents : function ( ) {
308- if ( module . is . touch ( ) ) {
309- $ ( document ) . off ( 'touchmove' + eventNamespace ) ;
310- $ ( document ) . off ( 'touchend' + eventNamespace ) ;
311- } else {
312- $ ( document ) . off ( 'mousemove' + eventNamespace ) ;
313- $ ( document ) . off ( 'mouseup' + eventNamespace ) ;
314- }
292+ $ ( document ) . off ( 'mousemove' + eventNamespace ) ;
293+ $ ( document ) . off ( 'mouseup' + eventNamespace ) ;
315294 } ,
316295 } ,
317296
@@ -341,10 +320,31 @@ $.fn.slider = function(parameters) {
341320 module . bind . slidingEvents ( ) ;
342321 }
343322 } ,
323+ touchDown : function ( event ) {
324+ event . preventDefault ( ) ; // disable mouse emulation and touch-scrolling
325+ event . stopImmediatePropagation ( ) ;
326+ if ( touchIdentifier !== undefined ) {
327+ // ignore multiple touches on the same slider --
328+ // we cannot handle changing both thumbs at once due to shared state
329+ return ;
330+ }
331+ $currThumb = $ ( event . target ) ;
332+ var touchEvent = event . touches ? event : event . originalEvent ;
333+ touchIdentifier = touchEvent . targetTouches [ 0 ] . identifier ;
334+ if ( previousValue === undefined ) {
335+ previousValue = module . get . currentThumbValue ( ) ;
336+ }
337+ } ,
344338 move : function ( event ) {
345- event . preventDefault ( ) ;
339+ if ( event . type == 'mousemove' ) {
340+ event . preventDefault ( ) ; // prevent text selection etc.
341+ }
342+ if ( module . is . disabled ( ) ) {
343+ // touch events are always bound, so we need to prevent touch-sliding on disabled sliders here
344+ return ;
345+ }
346346 var value = module . determine . valueFromEvent ( event ) ;
347- if ( $currThumb === undefined ) {
347+ if ( event . type == 'mousemove' && $currThumb === undefined ) {
348348 var
349349 eventPos = module . determine . eventPos ( event ) ,
350350 newPos = module . determine . pos ( eventPos )
@@ -381,13 +381,26 @@ $.fn.slider = function(parameters) {
381381 } ,
382382 up : function ( event ) {
383383 event . preventDefault ( ) ;
384+ if ( module . is . disabled ( ) ) {
385+ // touch events are always bound, so we need to prevent touch-sliding on disabled sliders here
386+ return ;
387+ }
384388 var value = module . determine . valueFromEvent ( event ) ;
385389 module . set . value ( value ) ;
386390 module . unbind . slidingEvents ( ) ;
391+ touchIdentifier = undefined ;
387392 if ( previousValue !== undefined ) {
388393 previousValue = undefined ;
389394 }
390395 } ,
396+ touchCancel : function ( event ) {
397+ event . preventDefault ( ) ;
398+ touchIdentifier = undefined ;
399+ if ( previousValue !== undefined ) {
400+ module . update . value ( previousValue ) ;
401+ previousValue = undefined ;
402+ }
403+ } ,
391404 keydown : function ( event , first ) {
392405 if ( settings . preventCrossover && module . is . range ( ) && module . thumbVal === module . secondThumbVal ) {
393406 $currThumb = undefined ;
@@ -500,9 +513,6 @@ $.fn.slider = function(parameters) {
500513 } ,
501514 smooth : function ( ) {
502515 return settings . smooth || $module . hasClass ( settings . className . smooth ) ;
503- } ,
504- touch : function ( ) {
505- return isTouch ;
506516 }
507517 } ,
508518
@@ -766,12 +776,19 @@ $.fn.slider = function(parameters) {
766776 return value ;
767777 } ,
768778 eventPos : function ( event ) {
769- if ( module . is . touch ( ) ) {
779+ if ( event . type === "touchmove" || event . type === "touchend" ) {
780+ var
781+ touchEvent = event . touches ? event : event . originalEvent ,
782+ touch = touchEvent . changedTouches [ 0 ] ; // fall back to first touch if correct touch not found
783+ for ( var i = 0 ; i < touchEvent . touches . length ; i ++ ) {
784+ if ( touchEvent . touches [ i ] . identifier === touchIdentifier ) {
785+ touch = touchEvent . touches [ i ] ;
786+ break ;
787+ }
788+ }
770789 var
771- touchEvent = event . changedTouches ? event : event . originalEvent ,
772- touches = touchEvent . changedTouches [ 0 ] ? touchEvent . changedTouches : touchEvent . touches ,
773- touchY = touches [ 0 ] . pageY ,
774- touchX = touches [ 0 ] . pageX
790+ touchY = touch . pageY ,
791+ touchX = touch . pageX
775792 ;
776793 return module . is . vertical ( ) ? touchY : touchX ;
777794 }
0 commit comments