53fdc42ad17fcf445f94043e658b978fff3cdeed
2 * jQuery UI Slider 1.8.17
4 * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
5 * Dual licensed under the MIT or GPL Version 2 licenses.
6 * http://jquery.org/license
8 * http://docs.jquery.com/UI/Slider
15 (function( $, undefined ) {
17 // number of pages in a slider
18 // (how many times can you page up/down to go through the whole range)
21 $.widget( "ui.slider", $.ui
.mouse
, {
23 widgetEventPrefix
: "slide",
30 orientation
: "horizontal",
40 existingHandles
= this.element
.find( ".ui-slider-handle" ).addClass( "ui-state-default ui-corner-all" ),
41 handle
= "<a class='ui-slider-handle ui-state-default ui-corner-all' href='#'></a>",
42 handleCount
= ( o
.values
&& o
.values
.length
) || 1,
45 this._keySliding
= false;
46 this._mouseSliding
= false;
47 this._animateOff
= true;
48 this._handleIndex
= null;
49 this._detectOrientation();
53 .addClass( "ui-slider" +
54 " ui-slider-" + this.orientation
+
56 " ui-widget-content" +
58 ( o
.disabled
? " ui-slider-disabled ui-disabled" : "" ) );
63 if ( o
.range
=== true ) {
65 o
.values
= [ this._valueMin(), this._valueMin() ];
67 if ( o
.values
.length
&& o
.values
.length
!== 2 ) {
68 o
.values
= [ o
.values
[0], o
.values
[0] ];
72 this.range
= $( "<div></div>" )
73 .appendTo( this.element
)
74 .addClass( "ui-slider-range" +
75 // note: this isn't the most fittingly semantic framework class for this element,
76 // but worked best visually with a variety of themes
78 ( ( o
.range
=== "min" || o
.range
=== "max" ) ? " ui-slider-range-" + o
.range
: "" ) );
81 for ( var i
= existingHandles
.length
; i
< handleCount
; i
+= 1 ) {
82 handles
.push( handle
);
85 this.handles
= existingHandles
.add( $( handles
.join( "" ) ).appendTo( self
.element
) );
87 this.handle
= this.handles
.eq( 0 );
89 this.handles
.add( this.range
).filter( "a" )
90 .click(function( event
) {
91 event
.preventDefault();
95 $( this ).addClass( "ui-state-hover" );
98 $( this ).removeClass( "ui-state-hover" );
102 $( ".ui-slider .ui-state-focus" ).removeClass( "ui-state-focus" );
103 $( this ).addClass( "ui-state-focus" );
109 $( this ).removeClass( "ui-state-focus" );
112 this.handles
.each(function( i
) {
113 $( this ).data( "index.ui-slider-handle", i
);
117 .keydown(function( event
) {
119 index
= $( this ).data( "index.ui-slider-handle" ),
125 if ( self
.options
.disabled
) {
129 switch ( event
.keyCode
) {
130 case $.ui
.keyCode
.HOME
:
131 case $.ui
.keyCode
.END
:
132 case $.ui
.keyCode
.PAGE_UP
:
133 case $.ui
.keyCode
.PAGE_DOWN
:
134 case $.ui
.keyCode
.UP
:
135 case $.ui
.keyCode
.RIGHT
:
136 case $.ui
.keyCode
.DOWN
:
137 case $.ui
.keyCode
.LEFT
:
139 if ( !self
._keySliding
) {
140 self
._keySliding
= true;
141 $( this ).addClass( "ui-state-active" );
142 allowed
= self
._start( event
, index
);
143 if ( allowed
=== false ) {
150 step
= self
.options
.step
;
151 if ( self
.options
.values
&& self
.options
.values
.length
) {
152 curVal
= newVal
= self
.values( index
);
154 curVal
= newVal
= self
.value();
157 switch ( event
.keyCode
) {
158 case $.ui
.keyCode
.HOME
:
159 newVal
= self
._valueMin();
161 case $.ui
.keyCode
.END
:
162 newVal
= self
._valueMax();
164 case $.ui
.keyCode
.PAGE_UP
:
165 newVal
= self
._trimAlignValue( curVal
+ ( (self
._valueMax() - self
._valueMin()) / numPages
) );
167 case $.ui
.keyCode
.PAGE_DOWN
:
168 newVal
= self
._trimAlignValue( curVal
- ( (self
._valueMax() - self
._valueMin()) / numPages
) );
170 case $.ui
.keyCode
.UP
:
171 case $.ui
.keyCode
.RIGHT
:
172 if ( curVal
=== self
._valueMax() ) {
175 newVal
= self
._trimAlignValue( curVal
+ step
);
177 case $.ui
.keyCode
.DOWN
:
178 case $.ui
.keyCode
.LEFT
:
179 if ( curVal
=== self
._valueMin() ) {
182 newVal
= self
._trimAlignValue( curVal
- step
);
186 self
._slide( event
, index
, newVal
);
191 .keyup(function( event
) {
192 var index
= $( this ).data( "index.ui-slider-handle" );
194 if ( self
._keySliding
) {
195 self
._keySliding
= false;
196 self
._stop( event
, index
);
197 self
._change( event
, index
);
198 $( this ).removeClass( "ui-state-active" );
203 this._refreshValue();
205 this._animateOff
= false;
208 destroy: function() {
209 this.handles
.remove();
213 .removeClass( "ui-slider" +
214 " ui-slider-horizontal" +
215 " ui-slider-vertical" +
216 " ui-slider-disabled" +
218 " ui-widget-content" +
220 .removeData( "slider" )
221 .unbind( ".slider" );
223 this._mouseDestroy();
228 _mouseCapture: function( event
) {
229 var o
= this.options
,
245 width
: this.element
.outerWidth(),
246 height
: this.element
.outerHeight()
248 this.elementOffset
= this.element
.offset();
250 position
= { x
: event
.pageX
, y
: event
.pageY
};
251 normValue
= this._normValueFromMouse( position
);
252 distance
= this._valueMax() - this._valueMin() + 1;
254 this.handles
.each(function( i
) {
255 var thisDistance
= Math
.abs( normValue
- self
.values(i
) );
256 if ( distance
> thisDistance
) {
257 distance
= thisDistance
;
258 closestHandle
= $( this );
263 // workaround for bug #3736 (if both handles of a range are at 0,
264 // the first is always used as the one with least distance,
265 // and moving it is obviously prevented by preventing negative ranges)
266 if( o
.range
=== true && this.values(1) === o
.min
) {
268 closestHandle
= $( this.handles
[index
] );
271 allowed
= this._start( event
, index
);
272 if ( allowed
=== false ) {
275 this._mouseSliding
= true;
277 self
._handleIndex
= index
;
280 .addClass( "ui-state-active" )
283 offset
= closestHandle
.offset();
284 mouseOverHandle
= !$( event
.target
).parents().andSelf().is( ".ui-slider-handle" );
285 this._clickOffset
= mouseOverHandle
? { left
: 0, top
: 0 } : {
286 left
: event
.pageX
- offset
.left
- ( closestHandle
.width() / 2 ),
287 top
: event
.pageY
- offset
.top
-
288 ( closestHandle
.height() / 2 ) -
289 ( parseInt( closestHandle
.css("borderTopWidth"), 10 ) || 0 ) -
290 ( parseInt( closestHandle
.css("borderBottomWidth"), 10 ) || 0) +
291 ( parseInt( closestHandle
.css("marginTop"), 10 ) || 0)
294 if ( !this.handles
.hasClass( "ui-state-hover" ) ) {
295 this._slide( event
, index
, normValue
);
297 this._animateOff
= true;
301 _mouseStart: function( event
) {
305 _mouseDrag: function( event
) {
306 var position
= { x
: event
.pageX
, y
: event
.pageY
},
307 normValue
= this._normValueFromMouse( position
);
309 this._slide( event
, this._handleIndex
, normValue
);
314 _mouseStop: function( event
) {
315 this.handles
.removeClass( "ui-state-active" );
316 this._mouseSliding
= false;
318 this._stop( event
, this._handleIndex
);
319 this._change( event
, this._handleIndex
);
321 this._handleIndex
= null;
322 this._clickOffset
= null;
323 this._animateOff
= false;
328 _detectOrientation: function() {
329 this.orientation
= ( this.options
.orientation
=== "vertical" ) ? "vertical" : "horizontal";
332 _normValueFromMouse: function( position
) {
339 if ( this.orientation
=== "horizontal" ) {
340 pixelTotal
= this.elementSize
.width
;
341 pixelMouse
= position
.x
- this.elementOffset
.left
- ( this._clickOffset
? this._clickOffset
.left
: 0 );
343 pixelTotal
= this.elementSize
.height
;
344 pixelMouse
= position
.y
- this.elementOffset
.top
- ( this._clickOffset
? this._clickOffset
.top
: 0 );
347 percentMouse
= ( pixelMouse
/ pixelTotal
);
348 if ( percentMouse
> 1 ) {
351 if ( percentMouse
< 0 ) {
354 if ( this.orientation
=== "vertical" ) {
355 percentMouse
= 1 - percentMouse
;
358 valueTotal
= this._valueMax() - this._valueMin();
359 valueMouse
= this._valueMin() + percentMouse
* valueTotal
;
361 return this._trimAlignValue( valueMouse
);
364 _start: function( event
, index
) {
366 handle
: this.handles
[ index
],
369 if ( this.options
.values
&& this.options
.values
.length
) {
370 uiHash
.value
= this.values( index
);
371 uiHash
.values
= this.values();
373 return this._trigger( "start", event
, uiHash
);
376 _slide: function( event
, index
, newVal
) {
381 if ( this.options
.values
&& this.options
.values
.length
) {
382 otherVal
= this.values( index
? 0 : 1 );
384 if ( ( this.options
.values
.length
=== 2 && this.options
.range
=== true ) &&
385 ( ( index
=== 0 && newVal
> otherVal
) || ( index
=== 1 && newVal
< otherVal
) )
390 if ( newVal
!== this.values( index
) ) {
391 newValues
= this.values();
392 newValues
[ index
] = newVal
;
393 // A slide can be canceled by returning false from the slide callback
394 allowed
= this._trigger( "slide", event
, {
395 handle
: this.handles
[ index
],
399 otherVal
= this.values( index
? 0 : 1 );
400 if ( allowed
!== false ) {
401 this.values( index
, newVal
, true );
405 if ( newVal
!== this.value() ) {
406 // A slide can be canceled by returning false from the slide callback
407 allowed
= this._trigger( "slide", event
, {
408 handle
: this.handles
[ index
],
411 if ( allowed
!== false ) {
412 this.value( newVal
);
418 _stop: function( event
, index
) {
420 handle
: this.handles
[ index
],
423 if ( this.options
.values
&& this.options
.values
.length
) {
424 uiHash
.value
= this.values( index
);
425 uiHash
.values
= this.values();
428 this._trigger( "stop", event
, uiHash
);
431 _change: function( event
, index
) {
432 if ( !this._keySliding
&& !this._mouseSliding
) {
434 handle
: this.handles
[ index
],
437 if ( this.options
.values
&& this.options
.values
.length
) {
438 uiHash
.value
= this.values( index
);
439 uiHash
.values
= this.values();
442 this._trigger( "change", event
, uiHash
);
446 value: function( newValue
) {
447 if ( arguments
.length
) {
448 this.options
.value
= this._trimAlignValue( newValue
);
449 this._refreshValue();
450 this._change( null, 0 );
454 return this._value();
457 values: function( index
, newValue
) {
462 if ( arguments
.length
> 1 ) {
463 this.options
.values
[ index
] = this._trimAlignValue( newValue
);
464 this._refreshValue();
465 this._change( null, index
);
469 if ( arguments
.length
) {
470 if ( $.isArray( arguments
[ 0 ] ) ) {
471 vals
= this.options
.values
;
472 newValues
= arguments
[ 0 ];
473 for ( i
= 0; i
< vals
.length
; i
+= 1 ) {
474 vals
[ i
] = this._trimAlignValue( newValues
[ i
] );
475 this._change( null, i
);
477 this._refreshValue();
479 if ( this.options
.values
&& this.options
.values
.length
) {
480 return this._values( index
);
486 return this._values();
490 _setOption: function( key
, value
) {
494 if ( $.isArray( this.options
.values
) ) {
495 valsLength
= this.options
.values
.length
;
498 $.Widget
.prototype._setOption
.apply( this, arguments
);
503 this.handles
.filter( ".ui-state-focus" ).blur();
504 this.handles
.removeClass( "ui-state-hover" );
505 this.handles
.propAttr( "disabled", true );
506 this.element
.addClass( "ui-disabled" );
508 this.handles
.propAttr( "disabled", false );
509 this.element
.removeClass( "ui-disabled" );
513 this._detectOrientation();
515 .removeClass( "ui-slider-horizontal ui-slider-vertical" )
516 .addClass( "ui-slider-" + this.orientation
);
517 this._refreshValue();
520 this._animateOff
= true;
521 this._refreshValue();
522 this._change( null, 0 );
523 this._animateOff
= false;
526 this._animateOff
= true;
527 this._refreshValue();
528 for ( i
= 0; i
< valsLength
; i
+= 1 ) {
529 this._change( null, i
);
531 this._animateOff
= false;
536 //internal value getter
537 // _value() returns value trimmed by min and max, aligned by step
539 var val
= this.options
.value
;
540 val
= this._trimAlignValue( val
);
545 //internal values getter
546 // _values() returns array of values trimmed by min and max, aligned by step
547 // _values( index ) returns single value trimmed by min and max, aligned by step
548 _values: function( index
) {
553 if ( arguments
.length
) {
554 val
= this.options
.values
[ index
];
555 val
= this._trimAlignValue( val
);
559 // .slice() creates a copy of the array
560 // this copy gets trimmed by min and max and then returned
561 vals
= this.options
.values
.slice();
562 for ( i
= 0; i
< vals
.length
; i
+= 1) {
563 vals
[ i
] = this._trimAlignValue( vals
[ i
] );
570 // returns the step-aligned value that val is closest to, between (inclusive) min and max
571 _trimAlignValue: function( val
) {
572 if ( val
<= this._valueMin() ) {
573 return this._valueMin();
575 if ( val
>= this._valueMax() ) {
576 return this._valueMax();
578 var step
= ( this.options
.step
> 0 ) ? this.options
.step
: 1,
579 valModStep
= (val
- this._valueMin()) % step
,
580 alignValue
= val
- valModStep
;
582 if ( Math
.abs(valModStep
) * 2 >= step
) {
583 alignValue
+= ( valModStep
> 0 ) ? step
: ( -step
);
586 // Since JavaScript has problems with large floats, round
587 // the final value to 5 digits after the decimal point (see #4124)
588 return parseFloat( alignValue
.toFixed(5) );
591 _valueMin: function() {
592 return this.options
.min
;
595 _valueMax: function() {
596 return this.options
.max
;
599 _refreshValue: function() {
600 var oRange
= this.options
.range
,
603 animate
= ( !this._animateOff
) ? o
.animate
: false,
611 if ( this.options
.values
&& this.options
.values
.length
) {
612 this.handles
.each(function( i
, j
) {
613 valPercent
= ( self
.values(i
) - self
._valueMin() ) / ( self
._valueMax() - self
._valueMin() ) * 100;
614 _set
[ self
.orientation
=== "horizontal" ? "left" : "bottom" ] = valPercent
+ "%";
615 $( this ).stop( 1, 1 )[ animate
? "animate" : "css" ]( _set
, o
.animate
);
616 if ( self
.options
.range
=== true ) {
617 if ( self
.orientation
=== "horizontal" ) {
619 self
.range
.stop( 1, 1 )[ animate
? "animate" : "css" ]( { left
: valPercent
+ "%" }, o
.animate
);
622 self
.range
[ animate
? "animate" : "css" ]( { width
: ( valPercent
- lastValPercent
) + "%" }, { queue
: false, duration
: o
.animate
} );
626 self
.range
.stop( 1, 1 )[ animate
? "animate" : "css" ]( { bottom
: ( valPercent
) + "%" }, o
.animate
);
629 self
.range
[ animate
? "animate" : "css" ]( { height
: ( valPercent
- lastValPercent
) + "%" }, { queue
: false, duration
: o
.animate
} );
633 lastValPercent
= valPercent
;
636 value
= this.value();
637 valueMin
= this._valueMin();
638 valueMax
= this._valueMax();
639 valPercent
= ( valueMax
!== valueMin
) ?
640 ( value
- valueMin
) / ( valueMax
- valueMin
) * 100 :
642 _set
[ self
.orientation
=== "horizontal" ? "left" : "bottom" ] = valPercent
+ "%";
643 this.handle
.stop( 1, 1 )[ animate
? "animate" : "css" ]( _set
, o
.animate
);
645 if ( oRange
=== "min" && this.orientation
=== "horizontal" ) {
646 this.range
.stop( 1, 1 )[ animate
? "animate" : "css" ]( { width
: valPercent
+ "%" }, o
.animate
);
648 if ( oRange
=== "max" && this.orientation
=== "horizontal" ) {
649 this.range
[ animate
? "animate" : "css" ]( { width
: ( 100 - valPercent
) + "%" }, { queue
: false, duration
: o
.animate
} );
651 if ( oRange
=== "min" && this.orientation
=== "vertical" ) {
652 this.range
.stop( 1, 1 )[ animate
? "animate" : "css" ]( { height
: valPercent
+ "%" }, o
.animate
);
654 if ( oRange
=== "max" && this.orientation
=== "vertical" ) {
655 this.range
[ animate
? "animate" : "css" ]( { height
: ( 100 - valPercent
) + "%" }, { queue
: false, duration
: o
.animate
} );
662 $.extend( $.ui
.slider
, {