Right-to-left jQuery UI Sliders

For those localities whose languages read right-to-left, it would be great if the jQuery UI components supported that. jQuery UI Datepicker provides an isRTL option that switches the orientation of its calendar. Now you can do the same thing for jQuery UI Slider.

At the moment you need to use a modified version of the slider module, but perhaps these changes could be incorporated into the main jQuery UI code.

Right-to-left slider: 0

$('#sliderRTL').slider({isRTL: true, slide: showValue, change: showValue});

Right-to-left range slider: 0

$('#sliderRTLRange').slider({isRTL: true, range: true, slide: showValue, change: showValue});

Left-to-right slider: 0

$('#sliderLTR').slider({slide: showValue, change: showValue});

Left-to-right range slider: 0

$('#sliderLTRRange').slider({range: true, slide: showValue, change: showValue});

Vertical sliders: Right-to-left


0
Right-to-left range


0
Left-to-right


0
Left-to-right range


0

$('#sliderVRTL').slider({orientation: 'vertical', isRTL: true, slide: showValue, change: showValue});
$('#sliderVRTLRange').slider({orientation: 'vertical', isRTL: true, range: true, slide: showValue, change: showValue});
$('#sliderVLTR').slider({orientation: 'vertical', slide: showValue, change: showValue});
$('#sliderVLTRRange').slider({orientation: 'vertical', range: true, slide: showValue, change: showValue});
Usage
  1. Include the jQuery and jQuery UI libraries in the head section of your page.
    <link type="text/css" href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.23/themes/south-street/jquery-ui.css" rel="stylesheet">
    <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
    <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.23/jquery-ui.min.js"></script>
  2. Download and include the Right-to-left jQuery UI Sliders JavaScript and CSS in the head section of your page.
    <link type="text/css" href="css/jquery.ui.slider-rtl.css" rel="stylesheet">
    <script type="text/javascript" src="jquery.ui.slider-rtl.js"></script>
    Alternately, you can use the packed version jquery.ui.slider-rtl.pack.js (6.9K vs 17.7K), or the minified version jquery.ui.slider-rtl.min.js (11.6K, 3.1K when zipped).
  3. Connect the right-to-left slider functionality to your divisions.
    $(selector).slider({isRTL: true});
Changes

Make the following changes to the jQuery UI slider module.

First add the isRTL option to the set of default options for the slider.

	options: {
		animate: false,
		distance: 0,
		max: 100,
		min: 0,
		orientation: "horizontal",
		isRTL: false, // RTL
		range: false,
		step: 1,
		value: 0,
		values: null
	},

When creating the slider note that it has the alternate language direction by adding a class in the _create function.

		this.element
			.addClass( "ui-slider" +
				" ui-slider-" + this.orientation +
				( o.isRTL ? " ui-slider-rtl" : "" ) + // RTL
				" ui-widget" +
				" ui-widget-content" +
				" ui-corner-all" );

Next handle keystrokes differently depending on the isRTL setting. Update the keydown processing to change the orientation of the LEFT and RIGHT keys when this setting is true. To make the processing a little easier, introduce a common function (adjust) that handles the details.

				var adjust = function(minMax, offset) { // RTL
					if ( curVal === minMax ) {
						return;
					}
					newVal = self._trimAlignValue( curVal + offset );
				};
				switch ( event.keyCode ) {
					case $.ui.keyCode.HOME:
						newVal = self._valueMin();
						break;
					case $.ui.keyCode.END:
						newVal = self._valueMax();
						break;
					case $.ui.keyCode.PAGE_UP:
						newVal = self._trimAlignValue( curVal + ( (self._valueMax() - self._valueMin()) / numPages ) );
						break;
					case $.ui.keyCode.PAGE_DOWN:
						newVal = self._trimAlignValue( curVal - ( (self._valueMax() - self._valueMin()) / numPages ) );
						break;
					case $.ui.keyCode.UP:
						adjust( self._valueMax(), step ); // RTL
						break;
					case $.ui.keyCode.RIGHT:
						adjust( self._valueMax(), self.options.isRTL ? -step : step ); // RTL
						break;
					case $.ui.keyCode.DOWN:
						adjust( self._valueMin(), -step ); // RTL
						break;
					case $.ui.keyCode.LEFT:
						adjust( self._valueMin(), self.options.isRTL ? step : -step ); // RTL
						break;
				}

When the slider handle is dragged or the bar is clicked the new position is calculated and is normalised to a percentage. Update this to reverse the orientation for the right-to-left case. Within the _normValueFromMouse function add the appropriate test. Note that right-to-left in combination with a vertical orientation results in the minimum value appearing at the top.

		if ( this.orientation === "vertical" ) {
			percentMouse = 1 - percentMouse;
		}
		if ( this.options.isRTL ) { // RTL
			percentMouse = 1 - percentMouse;
		}

Reconfigure the slider in _setOption if the isRTL setting is changed.

			case "isRTL": // RTL
				this.element.toggleClass( "ui-slider-rtl", value );
				this._refreshValue();
				break;

And finally, update the _refreshValue function to correctly adjust the handles and range display on the screen.

		if ( this.options.values && this.options.values.length ) {
			this.handles.each(function( i, j ) {
				valPercent = ( self.values( i ) - self._valueMin() ) / ( self._valueMax() - self._valueMin() ) * 100;
				valPercent = ( self.options.isRTL ? 100 - valPercent : valPercent ); // RTL
				_set[ self.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%";
				$( this ).stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate );
				if ( self.options.range === true ) {
					if ( self.orientation === "horizontal" ) {
						if ( i === 0 ) {
							self.range.stop( 1, 1 )[ animate ? "animate" : "css" ](
								self.options.isRTL ? { right: ( 100 - valPercent ) + "%"} : // RTL
								{ left: valPercent + "%" }, o.animate );
						}
						if ( i === 1 ) {
							self.range[ animate ? "animate" : "css" ]( {
								width: ( ( self.options.isRTL ? -1 : +1 ) * ( valPercent - lastValPercent ) ) + "%" }, // RTL
								{ queue: false, duration: o.animate } );
						}
					} else {
						if ( i === 0 ) {
							self.range.stop( 1, 1 )[ animate ? "animate" : "css" ](
								self.options.isRTL ? { top: ( 100 - valPercent ) + "%" } : // RTL
								{ bottom: ( valPercent ) + "%" }, o.animate );
						}
						if ( i === 1 ) {
							self.range[ animate ? "animate" : "css" ]( {
								height: ( ( self.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 = ( self.options.isRTL ? 100 - valPercent : valPercent ); // RTL
			_set[ self.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: ( self.options.isRTL ? 100 - valPercent : valPercent ) + "%" }, o.animate ); // RTL
			}
			if ( oRange === "max" && this.orientation === "horizontal" ) {
				this.range[ animate ? "animate" : "css" ]( {
					width: ( self.options.isRTL ? valPercent : 100 - valPercent ) + "%" }, // RTL
					{ queue: false, duration: o.animate } );
			}
			if ( oRange === "min" && this.orientation === "vertical" ) {
				this.range.stop( 1, 1 )[ animate ? "animate" : "css" ](
					{ height: ( self.options.isRTL ? 100 - valPercent : valPercent ) + "%" }, o.animate ); // RTL
			}
			if ( oRange === "max" && this.orientation === "vertical" ) {
				this.range[ animate ? "animate" : "css" ](
					{ height: ( self.options.isRTL ? valPercent : 100 - valPercent ) + "%" }, // RTL
					{ queue: false, duration: o.animate } );
			}
		}

The updated slider module (based on jQuery UI 1.8.9) is available for download, along with a patch file detailing the changes from the original module.