Skip to content

Commit 7b80caa

Browse files
committed
Slider: Click smartly selects best handle when multiple handles overlap by deferring choice until Move. #3736/3467 - some handles get stuck when using two or more handles
1 parent fb35d4e commit 7b80caa

File tree

1 file changed

+109
-49
lines changed

1 file changed

+109
-49
lines changed

ui/jquery.ui.slider.js

Lines changed: 109 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ $.widget( "ui.slider", $.ui.mouse, {
3333
value: 0,
3434
values: null
3535
},
36+
_overlap: { 'handles':[], 'eventX':-1, 'eventY':-1 },
3637

3738
_create: function() {
3839
var self = this,
@@ -126,7 +127,7 @@ $.widget( "ui.slider", $.ui.mouse, {
126127
.blur(function() {
127128
$( this ).removeClass( "ui-state-focus" );
128129
});
129-
130+
130131
this.handles.each(function( i ) {
131132
$( this ).data( "index.ui-slider-handle", i );
132133
});
@@ -248,7 +249,6 @@ $.widget( "ui.slider", $.ui.mouse, {
248249
position,
249250
normValue,
250251
distance,
251-
closestHandle,
252252
self,
253253
index,
254254
allowed,
@@ -265,65 +265,123 @@ $.widget( "ui.slider", $.ui.mouse, {
265265
};
266266
this.elementOffset = this.element.offset();
267267

268-
position = { x: event.pageX, y: event.pageY };
268+
position = { x: event.pageX, y: event.pageY };
269269
normValue = this._normValueFromMouse( position );
270+
271+
this._overlap = { 'handles':[], 'eventX':-1, 'eventY':-1 };
270272
distance = this._valueMax() - this._valueMin() + 1;
271-
self = this;
272-
this.handles.each(function( i ) {
273-
var thisDistance = Math.abs( normValue - self.values(i) );
274-
if ( distance > thisDistance ) {
275-
distance = thisDistance;
276-
closestHandle = $( this );
273+
self = this;
274+
this.handles.each(function( i )
275+
{
276+
if ( o.orientation === "vertical" )
277+
{
278+
low = $(this).offset().top;
279+
high = low + $(this).outerHeight(),
280+
check = position.y;
281+
} else {
282+
low = $(this).offset().left;
283+
high = low + $(this).outerWidth();
284+
check = position.x;
285+
}
286+
if ( low <= check && check <= high )
287+
{
288+
self._overlap.handles.push(i);
289+
}
290+
var thisDistance = normValue - self.values(i);
291+
var absDistance = Math.abs( thisDistance );
292+
if ( ( distance > absDistance ) ||
293+
( distance === absDistance && thisDistance > 0 ) )
294+
{
295+
distance = absDistance;
277296
index = i;
278-
}
297+
}
298+
279299
});
280-
281-
// workaround for bug #3736 (if both handles of a range are at 0,
282-
// the first is always used as the one with least distance,
283-
// and moving it is obviously prevented by preventing negative ranges)
284-
if( o.range === true && this.values(1) === o.min ) {
285-
index += 1;
286-
closestHandle = $( this.handles[index] );
287-
}
288-
289-
allowed = this._start( event, index );
300+
if( this._overlap.handles.length>1 )
301+
{
302+
var first_overlap = this._overlap.handles[0];
303+
var last_overlap = this._overlap.handles[this._overlap.handles.length-1];
304+
if ( this.values(last_overlap) === o.min )
305+
{
306+
index = last_overlap;
307+
} else if ( this.values(first_overlap) === o.max ) {
308+
index = first_overlap;
309+
} else {
310+
this._overlap.eventX = event.pageX;
311+
this._overlap.eventY = event.pageY;
312+
return true;
313+
}
314+
}
315+
316+
if ( !this._chooseHandle(event,index) )
317+
{
318+
return false;
319+
}
320+
321+
if ( !this.handles.hasClass("ui-state-hover") ) {
322+
this._slide( event, index, normValue );
323+
}
324+
325+
var $handle = $(this.handles[index]);
326+
var offset = $handle.offset();
327+
var mouseOverHandle = !$handle.parents().andSelf().is( ".ui-slider-handle" );
328+
this._clickOffset = mouseOverHandle ? { left: 0, top: 0 } : {
329+
left: event.pageX - offset.left - ( $handle.width() / 2 ),
330+
top: event.pageY - offset.top -
331+
( $handle.height() / 2 ) -
332+
( parseInt( $handle.css("borderTopWidth"), 10 ) || 0 ) -
333+
( parseInt( $handle.css("borderBottomWidth"), 10 ) || 0) +
334+
( parseInt( $handle.css("marginTop"), 10 ) || 0)
335+
};
336+
337+
this._animateOff = true;
338+
return true;
339+
},
340+
_chooseHandle: function ( event, index ) {
341+
var allowed = this._start( event, index );
290342
if ( allowed === false ) {
291343
return false;
292344
}
293345
this._mouseSliding = true;
294346

295-
self._handleIndex = index;
347+
this._handleIndex = index;
296348

297-
closestHandle
349+
$(this.handles[index])
298350
.addClass( "ui-state-active" )
299351
.focus();
300-
301-
offset = closestHandle.offset();
302-
mouseOverHandle = !$( event.target ).parents().andSelf().is( ".ui-slider-handle" );
303-
this._clickOffset = mouseOverHandle ? { left: 0, top: 0 } : {
304-
left: event.pageX - offset.left - ( closestHandle.width() / 2 ),
305-
top: event.pageY - offset.top -
306-
( closestHandle.height() / 2 ) -
307-
( parseInt( closestHandle.css("borderTopWidth"), 10 ) || 0 ) -
308-
( parseInt( closestHandle.css("borderBottomWidth"), 10 ) || 0) +
309-
( parseInt( closestHandle.css("marginTop"), 10 ) || 0)
310-
};
311-
312-
if ( !this.handles.hasClass( "ui-state-hover" ) ) {
313-
this._slide( event, index, normValue );
314-
}
315-
this._animateOff = true;
316-
return true;
317-
},
352+
353+
this._overlap = { 'handles':[], 'eventX':-1, 'eventY':-1 };
354+
return true;
355+
},
318356

319357
_mouseStart: function( event ) {
320358
return true;
321359
},
322360

323361
_mouseDrag: function( event ) {
324-
var position = { x: event.pageX, y: event.pageY },
325-
normValue = this._normValueFromMouse( position );
326-
362+
var position = { x: event.pageX, y: event.pageY },
363+
normValue = this._normValueFromMouse( position );
364+
if ( this._overlap.handles.length > 1 )
365+
{
366+
if ( this.options.orientation === "vertical" )
367+
{
368+
if ( ( this._overlap.eventY - position.y ) === 0 ) {
369+
return false;
370+
} if ( ( this._overlap.eventY - position.y ) < 0 ) {
371+
this._chooseHandle( event, this._overlap.handles[0] );
372+
} else {
373+
this._chooseHandle( event, this._overlap.handles[this._overlap.handles.length-1] );
374+
}
375+
} else {
376+
if ( ( this._overlap.eventX - position.x ) === 0 ) {
377+
return false;
378+
} if ( ( this._overlap.eventX - position.x ) > 0 ) {
379+
this._chooseHandle( event, this._overlap.handles[0] );
380+
} else {
381+
this._chooseHandle( event, this._overlap.handles[this._overlap.handles.length-1] );
382+
}
383+
}
384+
}
327385
this._slide( event, this._handleIndex, normValue );
328386

329387
return false;
@@ -339,7 +397,7 @@ $.widget( "ui.slider", $.ui.mouse, {
339397
this._handleIndex = null;
340398
this._clickOffset = null;
341399
this._animateOff = false;
342-
400+
this._overlap = { 'handles':[], 'eventX':-1, 'eventY':-1 };
343401
return false;
344402
},
345403

@@ -382,10 +440,10 @@ $.widget( "ui.slider", $.ui.mouse, {
382440
_start: function( event, index ) {
383441
var uiHash = {
384442
handle: this.handles[ index ],
385-
value: this.value()
443+
value: this.value()
386444
};
387445
if ( this.options.values && this.options.values.length ) {
388-
uiHash.value = this.values( index );
446+
uiHash.value = this.values( index );
389447
uiHash.values = this.values();
390448
}
391449
return this._trigger( "start", event, uiHash );
@@ -399,9 +457,11 @@ $.widget( "ui.slider", $.ui.mouse, {
399457
if ( this.options.values && this.options.values.length ) {
400458
otherVal = this.values( index ? 0 : 1 );
401459

402-
if ( ( this.options.values.length === 2 && this.options.range === true ) &&
460+
if (
461+
( this.options.values.length === 2 && this.options.range === true ) &&
403462
( ( index === 0 && newVal > otherVal) || ( index === 1 && newVal < otherVal ) )
404-
) {
463+
)
464+
{
405465
newVal = otherVal;
406466
}
407467

@@ -679,4 +739,4 @@ $.extend( $.ui.slider, {
679739
version: "@VERSION"
680740
});
681741

682-
}(jQuery));
742+
}(jQuery));

0 commit comments

Comments
 (0)