Created
April 28, 2017 16:45
-
-
Save sposmen/88f42a616c7a41fffa1efd764da021e4 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/*! | |
* jQuery UI Slider 1.12.1 RTL Based on the Original 1.12.1 | |
* and Keith Wood wood.keith{at}optusnet.com.au version based on 1.8.9 which help for this one | |
* | |
* http://jqueryui.com and http://keith-wood.name/rtlsliders.html | |
* | |
* Copyright jQuery Foundation and other contributors | |
* Released under the MIT license. | |
* http://jquery.org/license | |
*/ | |
//>>label: Slider | |
//>>group: Widgets | |
//>>description: Displays a flexible slider with ranges and accessibility via keyboard. | |
//>>docs: http://api.jqueryui.com/slider/ | |
//>>demos: http://jqueryui.com/slider/ | |
//>>css.structure: ../../themes/base/core.css | |
//>>css.structure: ../../themes/base/slider.css | |
//>>css.theme: ../../themes/base/theme.css | |
( function( factory ) { | |
if ( typeof define === "function" && define.amd ) { | |
// AMD. Register as an anonymous module. | |
define( [ | |
"jquery", | |
"./mouse", | |
"../keycode", | |
"../version", | |
"../widget" | |
], factory ); | |
} else { | |
// Browser globals | |
factory( jQuery ); | |
} | |
}( function( $ ) { | |
return $.widget( "ui.slider", $.ui.mouse, { | |
version: "1.12.1", | |
widgetEventPrefix: "slide", | |
options: { | |
animate: false, | |
classes: { | |
"ui-slider": "ui-corner-all", | |
"ui-slider-handle": "ui-corner-all", | |
// Note: ui-widget-header isn't the most fittingly semantic framework class for this | |
// element, but worked best visually with a variety of themes | |
"ui-slider-range": "ui-corner-all ui-widget-header" | |
}, | |
distance: 0, | |
max: 100, | |
min: 0, | |
orientation: "horizontal", | |
isRTL: false, // RTL | |
range: false, | |
step: 1, | |
value: 0, | |
values: null, | |
// Callbacks | |
change: null, | |
slide: null, | |
start: null, | |
stop: null | |
}, | |
// Number of pages in a slider | |
// (how many times can you page up/down to go through the whole range) | |
numPages: 5, | |
_create: function() { | |
var o = this.options; | |
this._keySliding = false; | |
this._mouseSliding = false; | |
this._animateOff = true; | |
this._handleIndex = null; | |
this._detectOrientation(); | |
this._mouseInit(); | |
this._calculateNewMax(); | |
this._addClass( "ui-slider ui-slider-" + this.orientation + ( o.isRTL ? " ui-slider-rtl" : "" ) + // RTL, | |
"ui-widget ui-widget-content" ); | |
this._refresh(); | |
this._animateOff = false; | |
}, | |
_refresh: function() { | |
this._createRange(); | |
this._createHandles(); | |
this._setupEvents(); | |
this._refreshValue(); | |
}, | |
_createHandles: function() { | |
var i, handleCount, | |
options = this.options, | |
existingHandles = this.element.find( ".ui-slider-handle" ), | |
handle = "<span tabindex='0'></span>", | |
handles = []; | |
handleCount = ( options.values && options.values.length ) || 1; | |
if ( existingHandles.length > handleCount ) { | |
existingHandles.slice( handleCount ).remove(); | |
existingHandles = existingHandles.slice( 0, handleCount ); | |
} | |
for ( i = existingHandles.length; i < handleCount; i++ ) { | |
handles.push( handle ); | |
} | |
this.handles = existingHandles.add( $( handles.join( "" ) ).appendTo( this.element ) ); | |
this._addClass( this.handles, "ui-slider-handle", "ui-state-default" ); | |
this.handle = this.handles.eq( 0 ); | |
this.handles.each( function( i ) { | |
$( this ) | |
.data( "ui-slider-handle-index", i ) | |
.attr( "tabIndex", 0 ); | |
} ); | |
}, | |
_createRange: function() { | |
var options = this.options; | |
if ( options.range ) { | |
if ( options.range === true ) { | |
if ( !options.values ) { | |
options.values = [ this._valueMin(), this._valueMin() ]; | |
} else if ( options.values.length && options.values.length !== 2 ) { | |
options.values = [ options.values[ 0 ], options.values[ 0 ] ]; | |
} else if ( $.isArray( options.values ) ) { | |
options.values = options.values.slice( 0 ); | |
} | |
} | |
if ( !this.range || !this.range.length ) { | |
this.range = $( "<div>" ) | |
.appendTo( this.element ); | |
this._addClass( this.range, "ui-slider-range" ); | |
} else { | |
this._removeClass( this.range, "ui-slider-range-min ui-slider-range-max" ); | |
// Handle range switching from true to min/max | |
this.range.css( { | |
"left": "", | |
"bottom": "" | |
} ); | |
} | |
if ( options.range === "min" || options.range === "max" ) { | |
this._addClass( this.range, "ui-slider-range-" + options.range ); | |
} | |
} else { | |
if ( this.range ) { | |
this.range.remove(); | |
} | |
this.range = null; | |
} | |
}, | |
_setupEvents: function() { | |
this._off( this.handles ); | |
this._on( this.handles, this._handleEvents ); | |
this._hoverable( this.handles ); | |
this._focusable( this.handles ); | |
}, | |
_destroy: function() { | |
this.handles.remove(); | |
if ( this.range ) { | |
this.range.remove(); | |
} | |
this._mouseDestroy(); | |
}, | |
_mouseCapture: function( event ) { | |
var position, normValue, distance, closestHandle, index, allowed, offset, mouseOverHandle, | |
that = this, | |
o = this.options; | |
if ( o.disabled ) { | |
return false; | |
} | |
this.elementSize = { | |
width: this.element.outerWidth(), | |
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; | |
} | |
} ); | |
allowed = this._start( event, index ); | |
if ( allowed === false ) { | |
return false; | |
} | |
this._mouseSliding = true; | |
this._handleIndex = index; | |
this._addClass( closestHandle, null, "ui-state-active" ); | |
closestHandle.trigger( "focus" ); | |
offset = closestHandle.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 ), | |
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 ) | |
}; | |
if ( !this.handles.hasClass( "ui-state-hover" ) ) { | |
this._slide( event, index, normValue ); | |
} | |
this._animateOff = true; | |
return true; | |
}, | |
_mouseStart: function() { | |
return true; | |
}, | |
_mouseDrag: function( event ) { | |
var position = { x: event.pageX, y: event.pageY }, | |
normValue = this._normValueFromMouse( position ); | |
this._slide( event, this._handleIndex, normValue ); | |
return false; | |
}, | |
_mouseStop: function( event ) { | |
this._removeClass( this.handles, null, "ui-state-active" ); | |
this._mouseSliding = false; | |
this._stop( event, this._handleIndex ); | |
this._change( event, this._handleIndex ); | |
this._handleIndex = null; | |
this._clickOffset = null; | |
this._animateOff = false; | |
return false; | |
}, | |
_detectOrientation: function() { | |
this.orientation = ( this.options.orientation === "vertical" ) ? "vertical" : "horizontal"; | |
}, | |
_normValueFromMouse: function( position ) { | |
var pixelTotal, | |
pixelMouse, | |
percentMouse, | |
valueTotal, | |
valueMouse; | |
if ( this.orientation === "horizontal" ) { | |
pixelTotal = this.elementSize.width; | |
pixelMouse = position.x - this.elementOffset.left - | |
( this._clickOffset ? this._clickOffset.left : 0 ); | |
} else { | |
pixelTotal = this.elementSize.height; | |
pixelMouse = position.y - this.elementOffset.top - | |
( this._clickOffset ? this._clickOffset.top : 0 ); | |
} | |
percentMouse = ( pixelMouse / pixelTotal ); | |
if ( percentMouse > 1 ) { | |
percentMouse = 1; | |
} | |
if ( percentMouse < 0 ) { | |
percentMouse = 0; | |
} | |
if ( this.orientation === "vertical" ) { | |
percentMouse = 1 - percentMouse; | |
} | |
if ( this.options.isRTL ) { // RTL | |
percentMouse = 1 - percentMouse; | |
} | |
valueTotal = this._valueMax() - this._valueMin(); | |
valueMouse = this._valueMin() + percentMouse * valueTotal; | |
return this._trimAlignValue( valueMouse ); | |
}, | |
_uiHash: function( index, value, values ) { | |
var uiHash = { | |
handle: this.handles[ index ], | |
handleIndex: index, | |
value: value !== undefined ? value : this.value() | |
}; | |
if ( this._hasMultipleValues() ) { | |
uiHash.value = value !== undefined ? value : this.values( index ); | |
uiHash.values = values || this.values(); | |
} | |
return uiHash; | |
}, | |
_hasMultipleValues: function() { | |
return this.options.values && this.options.values.length; | |
}, | |
_start: function( event, index ) { | |
return this._trigger( "start", event, this._uiHash( index ) ); | |
}, | |
_slide: function( event, index, newVal ) { | |
var allowed, otherVal, | |
currentValue = this.value(), | |
newValues = this.values(); | |
if ( this._hasMultipleValues() ) { | |
otherVal = this.values( index ? 0 : 1 ); | |
currentValue = this.values( index ); | |
if ( this.options.values.length === 2 && this.options.range === true ) { | |
newVal = index === 0 ? Math.min( otherVal, newVal ) : Math.max( otherVal, newVal ); | |
} | |
newValues[ index ] = newVal; | |
} | |
if ( newVal === currentValue ) { | |
return; | |
} | |
allowed = this._trigger( "slide", event, this._uiHash( index, newVal, newValues ) ); | |
// A slide can be canceled by returning false from the slide callback | |
if ( allowed === false ) { | |
return; | |
} | |
if ( this._hasMultipleValues() ) { | |
this.values( index, newVal ); | |
} else { | |
this.value( newVal ); | |
} | |
}, | |
_stop: function( event, index ) { | |
this._trigger( "stop", event, this._uiHash( index ) ); | |
}, | |
_change: function( event, index ) { | |
if ( !this._keySliding && !this._mouseSliding ) { | |
//store the last changed value index for reference when handles overlap | |
this._lastChangedValue = index; | |
this._trigger( "change", event, this._uiHash( index ) ); | |
} | |
}, | |
value: function( newValue ) { | |
if ( arguments.length ) { | |
this.options.value = this._trimAlignValue( newValue ); | |
this._refreshValue(); | |
this._change( null, 0 ); | |
return; | |
} | |
return this._value(); | |
}, | |
values: function( index, newValue ) { | |
var vals, | |
newValues, | |
i; | |
if ( arguments.length > 1 ) { | |
this.options.values[ index ] = this._trimAlignValue( newValue ); | |
this._refreshValue(); | |
this._change( null, index ); | |
return; | |
} | |
if ( arguments.length ) { | |
if ( $.isArray( arguments[ 0 ] ) ) { | |
vals = this.options.values; | |
newValues = arguments[ 0 ]; | |
for ( i = 0; i < vals.length; i += 1 ) { | |
vals[ i ] = this._trimAlignValue( newValues[ i ] ); | |
this._change( null, i ); | |
} | |
this._refreshValue(); | |
} else { | |
if ( this._hasMultipleValues() ) { | |
return this._values( index ); | |
} else { | |
return this.value(); | |
} | |
} | |
} else { | |
return this._values(); | |
} | |
}, | |
_setOption: function( key, value ) { | |
var i, | |
valsLength = 0; | |
if ( key === "range" && this.options.range === true ) { | |
if ( value === "min" ) { | |
this.options.value = this._values( 0 ); | |
this.options.values = null; | |
} else if ( value === "max" ) { | |
this.options.value = this._values( this.options.values.length - 1 ); | |
this.options.values = null; | |
} | |
} | |
if ( $.isArray( this.options.values ) ) { | |
valsLength = this.options.values.length; | |
} | |
this._super( key, value ); | |
switch ( key ) { | |
case "orientation": | |
this._detectOrientation(); | |
this._removeClass( "ui-slider-horizontal ui-slider-vertical" ) | |
._addClass( "ui-slider-" + this.orientation ); | |
this._refreshValue(); | |
if ( this.options.range ) { | |
this._refreshRange( value ); | |
} | |
// Reset positioning from previous orientation | |
this.handles.css( value === "horizontal" ? "bottom" : "left", "" ); | |
break; | |
case "isRTL": // RTL | |
this.element.toggleClass( "ui-slider-rtl", value ); | |
this._refreshValue(); | |
break; | |
case "value": | |
this._animateOff = true; | |
this._refreshValue(); | |
this._change( null, 0 ); | |
this._animateOff = false; | |
break; | |
case "values": | |
this._animateOff = true; | |
this._refreshValue(); | |
// Start from the last handle to prevent unreachable handles (#9046) | |
for ( i = valsLength - 1; i >= 0; i-- ) { | |
this._change( null, i ); | |
} | |
this._animateOff = false; | |
break; | |
case "step": | |
case "min": | |
case "max": | |
this._animateOff = true; | |
this._calculateNewMax(); | |
this._refreshValue(); | |
this._animateOff = false; | |
break; | |
case "range": | |
this._animateOff = true; | |
this._refresh(); | |
this._animateOff = false; | |
break; | |
} | |
}, | |
_setOptionDisabled: function( value ) { | |
this._super( value ); | |
this._toggleClass( null, "ui-state-disabled", !!value ); | |
}, | |
//internal value getter | |
// _value() returns value trimmed by min and max, aligned by step | |
_value: function() { | |
var val = this.options.value; | |
val = this._trimAlignValue( val ); | |
return val; | |
}, | |
//internal values getter | |
// _values() returns array of values trimmed by min and max, aligned by step | |
// _values( index ) returns single value trimmed by min and max, aligned by step | |
_values: function( index ) { | |
var val, | |
vals, | |
i; | |
if ( arguments.length ) { | |
val = this.options.values[ index ]; | |
val = this._trimAlignValue( val ); | |
return val; | |
} else if ( this._hasMultipleValues() ) { | |
// .slice() creates a copy of the array | |
// this copy gets trimmed by min and max and then returned | |
vals = this.options.values.slice(); | |
for ( i = 0; i < vals.length; i += 1 ) { | |
vals[ i ] = this._trimAlignValue( vals[ i ] ); | |
} | |
return vals; | |
} else { | |
return []; | |
} | |
}, | |
// Returns the step-aligned value that val is closest to, between (inclusive) min and max | |
_trimAlignValue: function( val ) { | |
if ( val <= this._valueMin() ) { | |
return this._valueMin(); | |
} | |
if ( val >= this._valueMax() ) { | |
return this._valueMax(); | |
} | |
var step = ( this.options.step > 0 ) ? this.options.step : 1, | |
valModStep = ( val - this._valueMin() ) % step, | |
alignValue = val - valModStep; | |
if ( Math.abs( valModStep ) * 2 >= step ) { | |
alignValue += ( valModStep > 0 ) ? step : ( -step ); | |
} | |
// Since JavaScript has problems with large floats, round | |
// the final value to 5 digits after the decimal point (see #4124) | |
return parseFloat( alignValue.toFixed( 5 ) ); | |
}, | |
_calculateNewMax: function() { | |
var max = this.options.max, | |
min = this._valueMin(), | |
step = this.options.step, | |
aboveMin = Math.round( ( max - min ) / step ) * step; | |
max = aboveMin + min; | |
if ( max > this.options.max ) { | |
//If max is not divisible by step, rounding off may increase its value | |
max -= step; | |
} | |
this.max = parseFloat( max.toFixed( this._precision() ) ); | |
}, | |
_precision: function() { | |
var precision = this._precisionOf( this.options.step ); | |
if ( this.options.min !== null ) { | |
precision = Math.max( precision, this._precisionOf( this.options.min ) ); | |
} | |
return precision; | |
}, | |
_precisionOf: function( num ) { | |
var str = num.toString(), | |
decimal = str.indexOf( "." ); | |
return decimal === -1 ? 0 : str.length - decimal - 1; | |
}, | |
_valueMin: function() { | |
return this.options.min; | |
}, | |
_valueMax: function() { | |
return this.max; | |
}, | |
_refreshRange: function( orientation ) { | |
if ( orientation === "vertical" ) { | |
this.range.css( { "width": "", "left": "" } ); | |
} | |
if ( orientation === "horizontal" ) { | |
this.range.css( { "height": "", "bottom": "" } ); | |
} | |
}, | |
_refreshValue: function() { | |
var lastValPercent, valPercent, value, valueMin, valueMax, | |
oRange = this.options.range, | |
o = this.options, | |
that = this, | |
animate = ( !this._animateOff ) ? o.animate : false, | |
_set = {}; | |
if ( this._hasMultipleValues() ) { | |
this.handles.each( function( i ) { | |
valPercent = ( that.values( i ) - that._valueMin() ) / ( that._valueMax() - | |
that._valueMin() ) * 100; | |
valPercent = ( that.options.isRTL ? 100 - valPercent : valPercent ); // RTL | |
_set[ that.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%"; | |
$( this ).stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate ); | |
if ( that.options.range === true ) { | |
if ( that.orientation === "horizontal" ) { | |
if ( i === 0 ) { | |
that.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( | |
( that.options.isRTL ? { right: ( 100 - valPercent ) + "%"} : // RTL | |
{ left: valPercent + "%" } ), o.animate ); | |
} | |
if ( i === 1 ) { | |
that.range[ animate ? "animate" : "css" ]( { | |
width: ( ( that.options.isRTL ? -1 : +1 ) * ( valPercent - lastValPercent ) ) + "%" // RTL | |
}, { | |
queue: false, | |
duration: o.animate | |
} ); | |
} | |
} else { | |
if ( i === 0 ) { | |
that.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( | |
that.options.isRTL ? { top: ( 100 - valPercent ) + "%" } : // RTL | |
{ bottom: ( valPercent ) + "%" }, o.animate ); | |
} | |
if ( i === 1 ) { | |
that.range[ animate ? "animate" : "css" ]( { | |
height: ( ( that.options.isRTL ? -1 : +1 ) * ( valPercent - lastValPercent ) ) + "%" //RTL | |
}, { | |
queue: false, | |
duration: o.animate | |
} ); | |
} | |
} | |
} | |
lastValPercent = valPercent; | |
} ); | |
} else { | |
value = this.value(); | |
valueMin = this._valueMin(); | |
valueMax = this._valueMax(); | |
valPercent = ( valueMax !== valueMin ) ? | |
( value - valueMin ) / ( valueMax - valueMin ) * 100 : | |
0; | |
valPercent = ( that.options.isRTL ? 100 - valPercent : valPercent ); // RTL | |
_set[ this.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%"; | |
this.handle.stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate ); | |
if ( oRange === "min" && this.orientation === "horizontal" ) { | |
this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { | |
width: ( that.options.isRTL ? 100 - valPercent : valPercent ) + "%" // RTL | |
}, o.animate ); | |
} | |
if ( oRange === "max" && this.orientation === "horizontal" ) { | |
this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { | |
width: (that.options.isRTL ? valPercent : 100 - valPercent ) + "%" // RTL | |
}, o.animate ); | |
} | |
if ( oRange === "min" && this.orientation === "vertical" ) { | |
this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { | |
height: ( that.options.isRTL ? 100 - valPercent : valPercent ) + "%" // RTL | |
}, o.animate ); | |
} | |
if ( oRange === "max" && this.orientation === "vertical" ) { | |
this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { | |
height: ( that.options.isRTL ? valPercent : 100 - valPercent ) + "%" // RTL | |
}, o.animate ); | |
} | |
} | |
}, | |
_handleEvents: { | |
keydown: function( event ) { | |
var allowed, curVal, newVal, step, | |
index = $( event.target ).data( "ui-slider-handle-index" ); | |
switch ( event.keyCode ) { | |
case $.ui.keyCode.HOME: | |
case $.ui.keyCode.END: | |
case $.ui.keyCode.PAGE_UP: | |
case $.ui.keyCode.PAGE_DOWN: | |
case $.ui.keyCode.UP: | |
case $.ui.keyCode.RIGHT: | |
case $.ui.keyCode.DOWN: | |
case $.ui.keyCode.LEFT: | |
event.preventDefault(); | |
if ( !this._keySliding ) { | |
this._keySliding = true; | |
this._addClass( $( event.target ), null, "ui-state-active" ); | |
allowed = this._start( event, index ); | |
if ( allowed === false ) { | |
return; | |
} | |
} | |
break; | |
} | |
step = this.options.step; | |
if ( this._hasMultipleValues() ) { | |
curVal = newVal = this.values( index ); | |
} else { | |
curVal = newVal = this.value(); | |
} | |
var adjust = function( minMax, offset ) { // RTL | |
if ( curVal === minMax ) { | |
return; | |
} | |
newVal = self._trimAlignValue( curVal + offset ); | |
}; | |
switch ( event.keyCode ) { | |
case $.ui.keyCode.HOME: | |
newVal = this._valueMin(); | |
break; | |
case $.ui.keyCode.END: | |
newVal = this._valueMax(); | |
break; | |
case $.ui.keyCode.PAGE_UP: | |
newVal = this._trimAlignValue( | |
curVal + ( ( this._valueMax() - this._valueMin() ) / this.numPages ) | |
); | |
break; | |
case $.ui.keyCode.PAGE_DOWN: | |
newVal = this._trimAlignValue( | |
curVal - ( ( this._valueMax() - this._valueMin() ) / this.numPages ) ); | |
break; | |
case $.ui.keyCode.UP: | |
case $.ui.keyCode.RIGHT: | |
adjust( self.options.isRTL ? self._valueMin() : self._valueMax(), self.options.isRTL ? -step : step); // RTL | |
break; | |
case $.ui.keyCode.DOWN: | |
case $.ui.keyCode.LEFT: | |
adjust( self.options.isRTL ? self._valueMax(): self._valueMin(), self.options.isRTL ? step : -step ); // RTL | |
break; | |
} | |
this._slide( event, index, newVal ); | |
}, | |
keyup: function( event ) { | |
var index = $( event.target ).data( "ui-slider-handle-index" ); | |
if ( this._keySliding ) { | |
this._keySliding = false; | |
this._stop( event, index ); | |
this._change( event, index ); | |
this._removeClass( $( event.target ), null, "ui-state-active" ); | |
} | |
} | |
} | |
} ); | |
} ) ); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Tks to @kbwood for his initial work on this here.