diff --git a/tests/unit/slider/slider_events.js b/tests/unit/slider/slider_events.js index cc5546a9f6f..340c2501866 100644 --- a/tests/unit/slider/slider_events.js +++ b/tests/unit/slider/slider_events.js @@ -7,28 +7,47 @@ module( "slider: events" ); // value (even if same as previous value), via mouse(mouseup) or keyboard(keyup) // or value method/option" test( "mouse based interaction", function() { - expect( 4 ); + expect( 5 ); - var element = $( "#slider1" ) + var handlePosition, + element = $( "#slider1" ) + .slider({ + start: function( event ) { + equal( event.originalEvent.type, "mousedown", "start triggered by mousedown" ); + }, + slide: function( event) { + equal( event.originalEvent.type, "mousemove", "slider triggered by mousemove" ); + }, + stop: function( event ) { + equal( event.originalEvent.type, "mouseup", "stop triggered by mouseup" ); + }, + change: function( event ) { + equal( event.originalEvent.type, "mouseup", "change triggered by mouseup" ); + } + }), + handles = element.find( ".ui-slider-handle" ); + + handles.eq( 0 ).simulate( "drag", { dx: 10, dy: 10 } ); + element.slider( "destroy" ); + + element = $( "#slider1" ) .slider({ - start: function( event ) { - equal( event.originalEvent.type, "mousedown", "start triggered by mousedown" ); - }, - slide: function( event) { - equal( event.originalEvent.type, "mousemove", "slider triggered by mousemove" ); - }, - stop: function( event ) { - equal( event.originalEvent.type, "mouseup", "stop triggered by mouseup" ); - }, - change: function( event ) { - equal( event.originalEvent.type, "mouseup", "change triggered by mouseup" ); - } + range: true, + min: 0, + max: 100, + values: [ 20, 80 ] }); + handles = element.find( ".ui-slider-handle" ); + element.slider( "values", 0, 79 ); + handlePosition = handles.eq( 1 ).offset(); + element.on( "slidestart", function( event, ui ) { + equal( ui.handleIndex, 1, "drag selected instead of closest handle" ); + }); - element.find( ".ui-slider-handle" ).eq( 0 ) - .simulate( "drag", { dx: 10, dy: 10 } ); - + handles.eq( 1 ).simulate( "mousedown", { clientX: handlePosition.left } ); + handles.eq( 1 ).simulate( "mouseup" ); }); + test( "keyboard based interaction", function() { expect( 3 ); diff --git a/ui/slider.js b/ui/slider.js index 4ca9c60022b..8bf315084e2 100644 --- a/ui/slider.js +++ b/ui/slider.js @@ -72,6 +72,7 @@ return $.widget( "ui.slider", $.ui.mouse, { this._mouseSliding = false; this._animateOff = true; this._handleIndex = null; + this._lastChangedIndex = null; this._detectOrientation(); this._mouseInit(); this._calculateNewMax(); @@ -176,9 +177,41 @@ return $.widget( "ui.slider", $.ui.mouse, { this._mouseDestroy(); }, + _closestHandleIndex: function( value, activeHandleIndex ) { + var that = this, + index = activeHandleIndex, + breakLoop = false, + activeSet = activeHandleIndex !== -1, + max = this._valueMax(), min = this._valueMin(), + distance = activeSet ? value - this.values( activeHandleIndex ) : max - min + 1; + + this.handles.each( function( i ) { + var handleDistance = Math.abs( value - that.values( i ) ); + if ( ( breakLoop && handleDistance >= distance ) || handleDistance > distance || !that._canBeDrag( i ) ) { + return; + } + index = i; + distance = handleDistance; + breakLoop = breakLoop ? breakLoop : i === that._lastChangedIndex; + }); + + return index; + }, + + _canBeDrag: function( index ) { + var val = this.values( index ), + prev = this.values( index - 1 ), + next = this.values( index + 1 ); + + prev = isNaN( prev ) ? this._valueMin() : prev; + next = isNaN( next ) ? this._valueMax() : next; + + return !( prev === val && val === next ); + }, + _mouseCapture: function( event ) { - var position, normValue, distance, closestHandle, index, allowed, offset, mouseOverHandle, - that = this, + var position, normValue, handle, index, allowed, offset, mouseOverHandle, + capturedElementIndex = this.handles.index( $( event.target ) ), o = this.options; if ( o.disabled ) { @@ -190,20 +223,11 @@ return $.widget( "ui.slider", $.ui.mouse, { height: this.element.outerHeight() }; this.elementOffset = this.element.offset(); - position = { x: event.pageX, y: event.pageY }; normValue = this._normValueFromMouse( position ); - distance = this._valueMax() - this._valueMin() + 1; - this.handles.each(function( i ) { - var thisDistance = Math.abs( normValue - that.values(i) ); - if (( distance > thisDistance ) || - ( distance === thisDistance && - (i === that._lastChangedValue || that.values(i) === o.min ))) { - distance = thisDistance; - closestHandle = $( this ); - index = i; - } - }); + + index = this._closestHandleIndex( normValue, capturedElementIndex ); + handle = this.handles.eq( index ); allowed = this._start( event, index ); if ( allowed === false ) { @@ -213,18 +237,18 @@ return $.widget( "ui.slider", $.ui.mouse, { this._handleIndex = index; - this._addClass( closestHandle, null, "ui-state-active" ); - closestHandle.focus(); + this._addClass( handle, null, "ui-state-active" ); + handle.focus(); - offset = closestHandle.offset(); + offset = handle.offset(); mouseOverHandle = !$( event.target ).parents().addBack().is( ".ui-slider-handle" ); this._clickOffset = mouseOverHandle ? { left: 0, top: 0 } : { - left: event.pageX - offset.left - ( closestHandle.width() / 2 ), + left: event.pageX - offset.left - ( handle.width() / 2 ), top: event.pageY - offset.top - - ( closestHandle.height() / 2 ) - - ( parseInt( closestHandle.css("borderTopWidth"), 10 ) || 0 ) - - ( parseInt( closestHandle.css("borderBottomWidth"), 10 ) || 0) + - ( parseInt( closestHandle.css("marginTop"), 10 ) || 0) + ( handle.height() / 2 ) - + ( parseInt( handle.css("borderTopWidth"), 10 ) || 0 ) - + ( parseInt( handle.css("borderBottomWidth"), 10 ) || 0) + + ( parseInt( handle.css("marginTop"), 10 ) || 0) }; if ( !this.handles.hasClass( "ui-state-hover" ) ) { @@ -361,7 +385,7 @@ return $.widget( "ui.slider", $.ui.mouse, { _change: function( event, index ) { if ( !this._keySliding && !this._mouseSliding ) { //store the last changed value index for reference when handles overlap - this._lastChangedValue = index; + this._lastChangedIndex = index; this._trigger( "change", event, this._uiHash( index ) ); } }, @@ -455,7 +479,7 @@ return $.widget( "ui.slider", $.ui.mouse, { this._refreshValue(); // Start from the last handle to prevent unreachable handles (#9046) - for ( i = valsLength - 1; i >= 0; i-- ) { + for ( i = 0; i < valsLength; i++ ) { this._change( null, i ); } this._animateOff = false;