Add Intel copyright header.
[profile/ivi/cowhide.git] / lib / jquery.ui.slider.js
1 /*!
2  * jQuery UI Slider @VERSION
3  * http://jqueryui.com
4  *
5  * Copyright 2012 jQuery Foundation and other contributors
6  * Released under the MIT license.
7  * http://jquery.org/license
8  *
9  * http://api.jqueryui.com/slider/
10  *
11  * Depends:
12  *      jquery.ui.core.js
13  *      jquery.ui.mouse.js
14  *      jquery.ui.widget.js
15  */
16 (function( $, undefined ) {
17
18 // number of pages in a slider
19 // (how many times can you page up/down to go through the whole range)
20 var numPages = 5;
21
22 $.widget( "ui.slider", $.ui.mouse, {
23         version: "@VERSION",
24         widgetEventPrefix: "slide",
25
26         options: {
27                 animate: false,
28                 distance: 0,
29                 max: 100,
30                 min: 0,
31                 orientation: "horizontal",
32                 range: false,
33                 step: 1,
34                 value: 0,
35                 values: null
36         },
37
38         _create: function() {
39                 var i,
40                         o = this.options,
41                         existingHandles = this.element.find( ".ui-slider-handle" ).addClass( "ui-state-default ui-corner-all" ),
42                         handle = "<a class='ui-slider-handle ui-state-default ui-corner-all' href='#'></a>",
43                         handleCount = ( o.values && o.values.length ) || 1,
44                         handles = [];
45
46                 this._keySliding = false;
47                 this._mouseSliding = false;
48                 this._animateOff = true;
49                 this._handleIndex = null;
50                 this._detectOrientation();
51                 this._mouseInit();
52
53                 this.element
54                         .addClass( "ui-slider" +
55                                 " ui-slider-" + this.orientation +
56                                 " ui-widget" +
57                                 " ui-widget-content" +
58                                 " ui-corner-all" +
59                                 ( o.disabled ? " ui-slider-disabled ui-disabled" : "" ) );
60
61                 this.range = $([]);
62
63                 if ( o.range ) {
64                         if ( o.range === true ) {
65                                 if ( !o.values ) {
66                                         o.values = [ this._valueMin(), this._valueMin() ];
67                                 }
68                                 if ( o.values.length && o.values.length !== 2 ) {
69                                         o.values = [ o.values[0], o.values[0] ];
70                                 }
71                         }
72
73                         this.range = $( "<div></div>" )
74                                 .appendTo( this.element )
75                                 .addClass( "ui-slider-range" +
76                                 // note: this isn't the most fittingly semantic framework class for this element,
77                                 // but worked best visually with a variety of themes
78                                 " ui-widget-header" +
79                                 ( ( o.range === "min" || o.range === "max" ) ? " ui-slider-range-" + o.range : "" ) );
80                 }
81
82                 for ( i = existingHandles.length; i < handleCount; i++ ) {
83                         handles.push( handle );
84                 }
85
86                 this.handles = existingHandles.add( $( handles.join( "" ) ).appendTo( this.element ) );
87
88                 this.handle = this.handles.eq( 0 );
89
90                 this.handles.add( this.range ).filter( "a" )
91                         .click(function( event ) {
92                                 event.preventDefault();
93                         })
94                         .mouseenter(function() {
95                                 if ( !o.disabled ) {
96                                         $( this ).addClass( "ui-state-hover" );
97                                 }
98                         })
99                         .mouseleave(function() {
100                                 $( this ).removeClass( "ui-state-hover" );
101                         })
102                         .focus(function() {
103                                 if ( !o.disabled ) {
104                                         $( ".ui-slider .ui-state-focus" ).removeClass( "ui-state-focus" );
105                                         $( this ).addClass( "ui-state-focus" );
106                                 } else {
107                                         $( this ).blur();
108                                 }
109                         })
110                         .blur(function() {
111                                 $( this ).removeClass( "ui-state-focus" );
112                         });
113
114                 this.handles.each(function( i ) {
115                         $( this ).data( "ui-slider-handle-index", i );
116                 });
117
118                 this._on( this.handles, {
119                         keydown: function( event ) {
120                                 var allowed, curVal, newVal, step,
121                                         index = $( event.target ).data( "ui-slider-handle-index" );
122
123                                 switch ( event.keyCode ) {
124                                         case $.ui.keyCode.HOME:
125                                         case $.ui.keyCode.END:
126                                         case $.ui.keyCode.PAGE_UP:
127                                         case $.ui.keyCode.PAGE_DOWN:
128                                         case $.ui.keyCode.UP:
129                                         case $.ui.keyCode.RIGHT:
130                                         case $.ui.keyCode.DOWN:
131                                         case $.ui.keyCode.LEFT:
132                                                 event.preventDefault();
133                                                 if ( !this._keySliding ) {
134                                                         this._keySliding = true;
135                                                         $( event.target ).addClass( "ui-state-active" );
136                                                         allowed = this._start( event, index );
137                                                         if ( allowed === false ) {
138                                                                 return;
139                                                         }
140                                                 }
141                                                 break;
142                                 }
143
144                                 step = this.options.step;
145                                 if ( this.options.values && this.options.values.length ) {
146                                         curVal = newVal = this.values( index );
147                                 } else {
148                                         curVal = newVal = this.value();
149                                 }
150
151                                 switch ( event.keyCode ) {
152                                         case $.ui.keyCode.HOME:
153                                                 newVal = this._valueMin();
154                                                 break;
155                                         case $.ui.keyCode.END:
156                                                 newVal = this._valueMax();
157                                                 break;
158                                         case $.ui.keyCode.PAGE_UP:
159                                                 newVal = this._trimAlignValue( curVal + ( (this._valueMax() - this._valueMin()) / numPages ) );
160                                                 break;
161                                         case $.ui.keyCode.PAGE_DOWN:
162                                                 newVal = this._trimAlignValue( curVal - ( (this._valueMax() - this._valueMin()) / numPages ) );
163                                                 break;
164                                         case $.ui.keyCode.UP:
165                                         case $.ui.keyCode.RIGHT:
166                                                 if ( curVal === this._valueMax() ) {
167                                                         return;
168                                                 }
169                                                 newVal = this._trimAlignValue( curVal + step );
170                                                 break;
171                                         case $.ui.keyCode.DOWN:
172                                         case $.ui.keyCode.LEFT:
173                                                 if ( curVal === this._valueMin() ) {
174                                                         return;
175                                                 }
176                                                 newVal = this._trimAlignValue( curVal - step );
177                                                 break;
178                                 }
179
180                                 this._slide( event, index, newVal );
181                         },
182                         keyup: function( event ) {
183                                 var index = $( event.target ).data( "ui-slider-handle-index" );
184
185                                 if ( this._keySliding ) {
186                                         this._keySliding = false;
187                                         this._stop( event, index );
188                                         this._change( event, index );
189                                         $( event.target ).removeClass( "ui-state-active" );
190                                 }
191                         }
192                 });
193
194                 this._refreshValue();
195
196                 this._animateOff = false;
197         },
198
199         _destroy: function() {
200                 this.handles.remove();
201                 this.range.remove();
202
203                 this.element
204                         .removeClass( "ui-slider" +
205                                 " ui-slider-horizontal" +
206                                 " ui-slider-vertical" +
207                                 " ui-slider-disabled" +
208                                 " ui-widget" +
209                                 " ui-widget-content" +
210                                 " ui-corner-all" );
211
212                 this._mouseDestroy();
213         },
214
215         _mouseCapture: function( event ) {
216                 var position, normValue, distance, closestHandle, index, allowed, offset, mouseOverHandle,
217                         that = this,
218                         o = this.options;
219
220                 if ( o.disabled ) {
221                         return false;
222                 }
223
224                 this.elementSize = {
225                         width: this.element.outerWidth(),
226                         height: this.element.outerHeight()
227                 };
228                 this.elementOffset = this.element.offset();
229
230                 position = { x: event.pageX, y: event.pageY };
231                 normValue = this._normValueFromMouse( position );
232                 distance = this._valueMax() - this._valueMin() + 1;
233                 this.handles.each(function( i ) {
234                         var thisDistance = Math.abs( normValue - that.values(i) );
235                         if ( distance > thisDistance ) {
236                                 distance = thisDistance;
237                                 closestHandle = $( this );
238                                 index = i;
239                         }
240                 });
241
242                 // workaround for bug #3736 (if both handles of a range are at 0,
243                 // the first is always used as the one with least distance,
244                 // and moving it is obviously prevented by preventing negative ranges)
245                 if( o.range === true && this.values(1) === o.min ) {
246                         index += 1;
247                         closestHandle = $( this.handles[index] );
248                 }
249
250                 allowed = this._start( event, index );
251                 if ( allowed === false ) {
252                         return false;
253                 }
254                 this._mouseSliding = true;
255
256                 this._handleIndex = index;
257
258                 closestHandle
259                         .addClass( "ui-state-active" )
260                         .focus();
261
262                 offset = closestHandle.offset();
263                 mouseOverHandle = !$( event.target ).parents().andSelf().is( ".ui-slider-handle" );
264                 this._clickOffset = mouseOverHandle ? { left: 0, top: 0 } : {
265                         left: event.pageX - offset.left - ( closestHandle.width() / 2 ),
266                         top: event.pageY - offset.top -
267                                 ( closestHandle.height() / 2 ) -
268                                 ( parseInt( closestHandle.css("borderTopWidth"), 10 ) || 0 ) -
269                                 ( parseInt( closestHandle.css("borderBottomWidth"), 10 ) || 0) +
270                                 ( parseInt( closestHandle.css("marginTop"), 10 ) || 0)
271                 };
272
273                 if ( !this.handles.hasClass( "ui-state-hover" ) ) {
274                         this._slide( event, index, normValue );
275                 }
276                 this._animateOff = true;
277                 return true;
278         },
279
280         _mouseStart: function( event ) {
281                 return true;
282         },
283
284         _mouseDrag: function( event ) {
285                 var position = { x: event.pageX, y: event.pageY },
286                         normValue = this._normValueFromMouse( position );
287
288                 this._slide( event, this._handleIndex, normValue );
289
290                 return false;
291         },
292
293         _mouseStop: function( event ) {
294                 this.handles.removeClass( "ui-state-active" );
295                 this._mouseSliding = false;
296
297                 this._stop( event, this._handleIndex );
298                 this._change( event, this._handleIndex );
299
300                 this._handleIndex = null;
301                 this._clickOffset = null;
302                 this._animateOff = false;
303
304                 return false;
305         },
306
307         _detectOrientation: function() {
308                 this.orientation = ( this.options.orientation === "vertical" ) ? "vertical" : "horizontal";
309         },
310
311         _normValueFromMouse: function( position ) {
312                 var pixelTotal,
313                         pixelMouse,
314                         percentMouse,
315                         valueTotal,
316                         valueMouse;
317
318                 if ( this.orientation === "horizontal" ) {
319                         pixelTotal = this.elementSize.width;
320                         pixelMouse = position.x - this.elementOffset.left - ( this._clickOffset ? this._clickOffset.left : 0 );
321                 } else {
322                         pixelTotal = this.elementSize.height;
323                         pixelMouse = position.y - this.elementOffset.top - ( this._clickOffset ? this._clickOffset.top : 0 );
324                 }
325
326                 percentMouse = ( pixelMouse / pixelTotal );
327                 if ( percentMouse > 1 ) {
328                         percentMouse = 1;
329                 }
330                 if ( percentMouse < 0 ) {
331                         percentMouse = 0;
332                 }
333                 if ( this.orientation === "vertical" ) {
334                         percentMouse = 1 - percentMouse;
335                 }
336
337                 valueTotal = this._valueMax() - this._valueMin();
338                 valueMouse = this._valueMin() + percentMouse * valueTotal;
339
340                 return this._trimAlignValue( valueMouse );
341         },
342
343         _start: function( event, index ) {
344                 var uiHash = {
345                         handle: this.handles[ index ],
346                         value: this.value()
347                 };
348                 if ( this.options.values && this.options.values.length ) {
349                         uiHash.value = this.values( index );
350                         uiHash.values = this.values();
351                 }
352                 return this._trigger( "start", event, uiHash );
353         },
354
355         _slide: function( event, index, newVal ) {
356                 var otherVal,
357                         newValues,
358                         allowed;
359
360                 if ( this.options.values && this.options.values.length ) {
361                         otherVal = this.values( index ? 0 : 1 );
362
363                         if ( ( this.options.values.length === 2 && this.options.range === true ) &&
364                                         ( ( index === 0 && newVal > otherVal) || ( index === 1 && newVal < otherVal ) )
365                                 ) {
366                                 newVal = otherVal;
367                         }
368
369                         if ( newVal !== this.values( index ) ) {
370                                 newValues = this.values();
371                                 newValues[ index ] = newVal;
372                                 // A slide can be canceled by returning false from the slide callback
373                                 allowed = this._trigger( "slide", event, {
374                                         handle: this.handles[ index ],
375                                         value: newVal,
376                                         values: newValues
377                                 } );
378                                 otherVal = this.values( index ? 0 : 1 );
379                                 if ( allowed !== false ) {
380                                         this.values( index, newVal, true );
381                                 }
382                         }
383                 } else {
384                         if ( newVal !== this.value() ) {
385                                 // A slide can be canceled by returning false from the slide callback
386                                 allowed = this._trigger( "slide", event, {
387                                         handle: this.handles[ index ],
388                                         value: newVal
389                                 } );
390                                 if ( allowed !== false ) {
391                                         this.value( newVal );
392                                 }
393                         }
394                 }
395         },
396
397         _stop: function( event, index ) {
398                 var uiHash = {
399                         handle: this.handles[ index ],
400                         value: this.value()
401                 };
402                 if ( this.options.values && this.options.values.length ) {
403                         uiHash.value = this.values( index );
404                         uiHash.values = this.values();
405                 }
406
407                 this._trigger( "stop", event, uiHash );
408         },
409
410         _change: function( event, index ) {
411                 if ( !this._keySliding && !this._mouseSliding ) {
412                         var uiHash = {
413                                 handle: this.handles[ index ],
414                                 value: this.value()
415                         };
416                         if ( this.options.values && this.options.values.length ) {
417                                 uiHash.value = this.values( index );
418                                 uiHash.values = this.values();
419                         }
420
421                         this._trigger( "change", event, uiHash );
422                 }
423         },
424
425         value: function( newValue ) {
426                 if ( arguments.length ) {
427                         this.options.value = this._trimAlignValue( newValue );
428                         this._refreshValue();
429                         this._change( null, 0 );
430                         return;
431                 }
432
433                 return this._value();
434         },
435
436         values: function( index, newValue ) {
437                 var vals,
438                         newValues,
439                         i;
440
441                 if ( arguments.length > 1 ) {
442                         this.options.values[ index ] = this._trimAlignValue( newValue );
443                         this._refreshValue();
444                         this._change( null, index );
445                         return;
446                 }
447
448                 if ( arguments.length ) {
449                         if ( $.isArray( arguments[ 0 ] ) ) {
450                                 vals = this.options.values;
451                                 newValues = arguments[ 0 ];
452                                 for ( i = 0; i < vals.length; i += 1 ) {
453                                         vals[ i ] = this._trimAlignValue( newValues[ i ] );
454                                         this._change( null, i );
455                                 }
456                                 this._refreshValue();
457                         } else {
458                                 if ( this.options.values && this.options.values.length ) {
459                                         return this._values( index );
460                                 } else {
461                                         return this.value();
462                                 }
463                         }
464                 } else {
465                         return this._values();
466                 }
467         },
468
469         _setOption: function( key, value ) {
470                 var i,
471                         valsLength = 0;
472
473                 if ( $.isArray( this.options.values ) ) {
474                         valsLength = this.options.values.length;
475                 }
476
477                 $.Widget.prototype._setOption.apply( this, arguments );
478
479                 switch ( key ) {
480                         case "disabled":
481                                 if ( value ) {
482                                         this.handles.filter( ".ui-state-focus" ).blur();
483                                         this.handles.removeClass( "ui-state-hover" );
484                                         this.handles.prop( "disabled", true );
485                                         this.element.addClass( "ui-disabled" );
486                                 } else {
487                                         this.handles.prop( "disabled", false );
488                                         this.element.removeClass( "ui-disabled" );
489                                 }
490                                 break;
491                         case "orientation":
492                                 this._detectOrientation();
493                                 this.element
494                                         .removeClass( "ui-slider-horizontal ui-slider-vertical" )
495                                         .addClass( "ui-slider-" + this.orientation );
496                                 this._refreshValue();
497                                 break;
498                         case "value":
499                                 this._animateOff = true;
500                                 this._refreshValue();
501                                 this._change( null, 0 );
502                                 this._animateOff = false;
503                                 break;
504                         case "values":
505                                 this._animateOff = true;
506                                 this._refreshValue();
507                                 for ( i = 0; i < valsLength; i += 1 ) {
508                                         this._change( null, i );
509                                 }
510                                 this._animateOff = false;
511                                 break;
512                 }
513         },
514
515         //internal value getter
516         // _value() returns value trimmed by min and max, aligned by step
517         _value: function() {
518                 var val = this.options.value;
519                 val = this._trimAlignValue( val );
520
521                 return val;
522         },
523
524         //internal values getter
525         // _values() returns array of values trimmed by min and max, aligned by step
526         // _values( index ) returns single value trimmed by min and max, aligned by step
527         _values: function( index ) {
528                 var val,
529                         vals,
530                         i;
531
532                 if ( arguments.length ) {
533                         val = this.options.values[ index ];
534                         val = this._trimAlignValue( val );
535
536                         return val;
537                 } else {
538                         // .slice() creates a copy of the array
539                         // this copy gets trimmed by min and max and then returned
540                         vals = this.options.values.slice();
541                         for ( i = 0; i < vals.length; i+= 1) {
542                                 vals[ i ] = this._trimAlignValue( vals[ i ] );
543                         }
544
545                         return vals;
546                 }
547         },
548
549         // returns the step-aligned value that val is closest to, between (inclusive) min and max
550         _trimAlignValue: function( val ) {
551                 if ( val <= this._valueMin() ) {
552                         return this._valueMin();
553                 }
554                 if ( val >= this._valueMax() ) {
555                         return this._valueMax();
556                 }
557                 var step = ( this.options.step > 0 ) ? this.options.step : 1,
558                         valModStep = (val - this._valueMin()) % step,
559                         alignValue = val - valModStep;
560
561                 if ( Math.abs(valModStep) * 2 >= step ) {
562                         alignValue += ( valModStep > 0 ) ? step : ( -step );
563                 }
564
565                 // Since JavaScript has problems with large floats, round
566                 // the final value to 5 digits after the decimal point (see #4124)
567                 return parseFloat( alignValue.toFixed(5) );
568         },
569
570         _valueMin: function() {
571                 return this.options.min;
572         },
573
574         _valueMax: function() {
575                 return this.options.max;
576         },
577
578         _refreshValue: function() {
579                 var lastValPercent, valPercent, value, valueMin, valueMax,
580                         oRange = this.options.range,
581                         o = this.options,
582                         that = this,
583                         animate = ( !this._animateOff ) ? o.animate : false,
584                         _set = {};
585
586                 if ( this.options.values && this.options.values.length ) {
587                         this.handles.each(function( i, j ) {
588                                 valPercent = ( that.values(i) - that._valueMin() ) / ( that._valueMax() - that._valueMin() ) * 100;
589                                 _set[ that.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%";
590                                 $( this ).stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate );
591                                 if ( that.options.range === true ) {
592                                         if ( that.orientation === "horizontal" ) {
593                                                 if ( i === 0 ) {
594                                                         that.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { left: valPercent + "%" }, o.animate );
595                                                 }
596                                                 if ( i === 1 ) {
597                                                         that.range[ animate ? "animate" : "css" ]( { width: ( valPercent - lastValPercent ) + "%" }, { queue: false, duration: o.animate } );
598                                                 }
599                                         } else {
600                                                 if ( i === 0 ) {
601                                                         that.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { bottom: ( valPercent ) + "%" }, o.animate );
602                                                 }
603                                                 if ( i === 1 ) {
604                                                         that.range[ animate ? "animate" : "css" ]( { height: ( valPercent - lastValPercent ) + "%" }, { queue: false, duration: o.animate } );
605                                                 }
606                                         }
607                                 }
608                                 lastValPercent = valPercent;
609                         });
610                 } else {
611                         value = this.value();
612                         valueMin = this._valueMin();
613                         valueMax = this._valueMax();
614                         valPercent = ( valueMax !== valueMin ) ?
615                                         ( value - valueMin ) / ( valueMax - valueMin ) * 100 :
616                                         0;
617                         _set[ this.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%";
618                         this.handle.stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate );
619
620                         if ( oRange === "min" && this.orientation === "horizontal" ) {
621                                 this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { width: valPercent + "%" }, o.animate );
622                         }
623                         if ( oRange === "max" && this.orientation === "horizontal" ) {
624                                 this.range[ animate ? "animate" : "css" ]( { width: ( 100 - valPercent ) + "%" }, { queue: false, duration: o.animate } );
625                         }
626                         if ( oRange === "min" && this.orientation === "vertical" ) {
627                                 this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { height: valPercent + "%" }, o.animate );
628                         }
629                         if ( oRange === "max" && this.orientation === "vertical" ) {
630                                 this.range[ animate ? "animate" : "css" ]( { height: ( 100 - valPercent ) + "%" }, { queue: false, duration: o.animate } );
631                         }
632                 }
633         }
634
635 });
636
637 }(jQuery));