JAL-1807 update
[jalviewjs.git] / site / swingjs / jquery / jquery-ui-slider.js
1 /*! jQuery UI - v1.9.2 - 2015-05-28
2 * http://jqueryui.com
3 * Includes: jquery.ui.slider.js
4 * Copyright 2015 jQuery Foundation and other contributors; Licensed MIT */
5
6
7 // requires: core, widget, mouse, position
8
9 (function( $, undefined ) {
10
11 // number of pages in a slider
12 // (how many times can you page up/down to go through the whole range)
13 var numPages = 5;
14
15 $.widget( "ui.slider", $.ui.mouse, {
16         version: "1.9.2",
17         widgetEventPrefix: "slide",
18
19         options: {
20                 animate: false,
21                 distance: 0,
22                 max: 100,
23                 min: 0,
24                 orientation: "horizontal",
25                 range: false,
26                 step: 1,
27                 value: 0,
28                 values: null
29         },
30
31         _create: function() {
32                 var i, handleCount,
33                         o = this.options,
34                         existingHandles = this.element.find( ".ui-slider-handle" ).addClass( "ui-state-default ui-corner-all" ),
35                         handle = "<a class='ui-slider-handle ui-state-default ui-corner-all' href='#'></a>",
36                         handles = [];
37
38                 this._keySliding = false;
39                 this._mouseSliding = false;
40                 this._animateOff = true;
41                 this._handleIndex = null;
42                 this._detectOrientation();
43                 this._mouseInit();
44
45                 this.element
46                         .addClass( "ui-slider" +
47                                 " ui-slider-" + this.orientation +
48                                 " ui-widget" +
49                                 " ui-widget-content" +
50                                 " ui-corner-all" +
51                                 ( o.disabled ? " ui-slider-disabled ui-disabled" : "" ) );
52
53                 this.range = $([]);
54
55                 if ( o.range ) {
56                         if ( o.range === true ) {
57                                 if ( !o.values ) {
58                                         o.values = [ this._valueMin(), this._valueMin() ];
59                                 }
60                                 if ( o.values.length && o.values.length !== 2 ) {
61                                         o.values = [ o.values[0], o.values[0] ];
62                                 }
63                         }
64
65                         this.range = $( "<div></div>" )
66                                 .appendTo( this.element )
67                                 .addClass( "ui-slider-range" +
68                                 // note: this isn't the most fittingly semantic framework class for this element,
69                                 // but worked best visually with a variety of themes
70                                 " ui-widget-header" +
71                                 ( ( o.range === "min" || o.range === "max" ) ? " ui-slider-range-" + o.range : "" ) );
72                 }
73
74                 handleCount = ( o.values && o.values.length ) || 1;
75
76                 for ( i = existingHandles.length; i < handleCount; i++ ) {
77                         handles.push( handle );
78                 }
79
80                 this.handles = existingHandles.add( $( handles.join( "" ) ).appendTo( this.element ) );
81
82                 this.handle = this.handles.eq( 0 );
83
84                 this.handles.add( this.range ).filter( "a" )
85                         .click(function( event ) {
86                                 event.preventDefault();
87                         })
88                         .mouseenter(function() {
89                                 if ( !o.disabled ) {
90                                         $( this ).addClass( "ui-state-hover" );
91                                 }
92                         })
93                         .mouseleave(function() {
94                                 $( this ).removeClass( "ui-state-hover" );
95                         })
96                         .focus(function() {
97                                 if ( !o.disabled ) {
98                                         $( ".ui-slider .ui-state-focus" ).removeClass( "ui-state-focus" );
99                                         $( this ).addClass( "ui-state-focus" );
100                                 } else {
101                                         $( this ).blur();
102                                 }
103                         })
104                         .blur(function() {
105                                 $( this ).removeClass( "ui-state-focus" );
106                         });
107
108                 this.handles.each(function( i ) {
109                         $( this ).data( "ui-slider-handle-index", i );
110                 });
111
112                 this._on( this.handles, {
113                         keydown: function( event ) {
114                                 var allowed, curVal, newVal, step,
115                                         index = $( event.target ).data( "ui-slider-handle-index" );
116
117                                 switch ( event.keyCode ) {
118                                         case $.ui.keyCode.HOME:
119                                         case $.ui.keyCode.END:
120                                         case $.ui.keyCode.PAGE_UP:
121                                         case $.ui.keyCode.PAGE_DOWN:
122                                         case $.ui.keyCode.UP:
123                                         case $.ui.keyCode.RIGHT:
124                                         case $.ui.keyCode.DOWN:
125                                         case $.ui.keyCode.LEFT:
126                                                 event.preventDefault();
127                                                 if ( !this._keySliding ) {
128                                                         this._keySliding = true;
129                                                         $( event.target ).addClass( "ui-state-active" );
130                                                         allowed = this._start( event, index );
131                                                         if ( allowed === false ) {
132                                                                 return;
133                                                         }
134                                                 }
135                                                 break;
136                                 }
137
138                                 step = this.options.step;
139                                 if ( this.options.values && this.options.values.length ) {
140                                         curVal = newVal = this.values( index );
141                                 } else {
142                                         curVal = newVal = this.value();
143                                 }
144
145                                 switch ( event.keyCode ) {
146                                         case $.ui.keyCode.HOME:
147                                                 newVal = this._valueMin();
148                                                 break;
149                                         case $.ui.keyCode.END:
150                                                 newVal = this._valueMax();
151                                                 break;
152                                         case $.ui.keyCode.PAGE_UP:
153                                                 newVal = this._trimAlignValue( curVal + ( (this._valueMax() - this._valueMin()) / numPages ) );
154                                                 break;
155                                         case $.ui.keyCode.PAGE_DOWN:
156                                                 newVal = this._trimAlignValue( curVal - ( (this._valueMax() - this._valueMin()) / numPages ) );
157                                                 break;
158                                         case $.ui.keyCode.UP:
159                                         case $.ui.keyCode.RIGHT:
160                                                 if ( curVal === this._valueMax() ) {
161                                                         return;
162                                                 }
163                                                 newVal = this._trimAlignValue( curVal + step );
164                                                 break;
165                                         case $.ui.keyCode.DOWN:
166                                         case $.ui.keyCode.LEFT:
167                                                 if ( curVal === this._valueMin() ) {
168                                                         return;
169                                                 }
170                                                 newVal = this._trimAlignValue( curVal - step );
171                                                 break;
172                                 }
173
174                                 this._slide( event, index, newVal );
175                         },
176                         keyup: function( event ) {
177                                 var index = $( event.target ).data( "ui-slider-handle-index" );
178
179                                 if ( this._keySliding ) {
180                                         this._keySliding = false;
181                                         this._stop( event, index );
182                                         this._change( event, index );
183                                         $( event.target ).removeClass( "ui-state-active" );
184                                 }
185                         }
186                 });
187
188                 this._refreshValue();
189
190                 this._animateOff = false;
191         },
192
193         _destroy: function() {
194                 this.handles.remove();
195                 this.range.remove();
196
197                 this.element
198                         .removeClass( "ui-slider" +
199                                 " ui-slider-horizontal" +
200                                 " ui-slider-vertical" +
201                                 " ui-slider-disabled" +
202                                 " ui-widget" +
203                                 " ui-widget-content" +
204                                 " ui-corner-all" );
205
206                 this._mouseDestroy();
207         },
208
209         _mouseCapture: function( event ) {
210                 var position, normValue, distance, closestHandle, index, allowed, offset, mouseOverHandle,
211                         that = this,
212                         o = this.options;
213
214                 if ( o.disabled ) {
215                         return false;
216                 }
217
218                 this.elementSize = {
219                         width: this.element.outerWidth(),
220                         height: this.element.outerHeight()
221                 };
222                 this.elementOffset = this.element.offset();
223
224                 position = { x: event.pageX, y: event.pageY };
225                 normValue = this._normValueFromMouse( position );
226                 distance = this._valueMax() - this._valueMin() + 1;
227                 this.handles.each(function( i ) {
228                         var thisDistance = Math.abs( normValue - that.values(i) );
229                         if ( distance > thisDistance ) {
230                                 distance = thisDistance;
231                                 closestHandle = $( this );
232                                 index = i;
233                         }
234                 });
235
236                 // workaround for bug #3736 (if both handles of a range are at 0,
237                 // the first is always used as the one with least distance,
238                 // and moving it is obviously prevented by preventing negative ranges)
239                 if( o.range === true && this.values(1) === o.min ) {
240                         index += 1;
241                         closestHandle = $( this.handles[index] );
242                 }
243
244                 allowed = this._start( event, index );
245                 if ( allowed === false ) {
246                         return false;
247                 }
248                 this._mouseSliding = true;
249
250                 this._handleIndex = index;
251
252                 closestHandle
253                         .addClass( "ui-state-active" )
254                         .focus();
255
256                 offset = closestHandle.offset();
257                 mouseOverHandle = !$( event.target ).parents().andSelf().is( ".ui-slider-handle" );
258                 this._clickOffset = mouseOverHandle ? { left: 0, top: 0 } : {
259                         left: event.pageX - offset.left - ( closestHandle.width() / 2 ),
260                         top: event.pageY - offset.top -
261                                 ( closestHandle.height() / 2 ) -
262                                 ( parseInt( closestHandle.css("borderTopWidth"), 10 ) || 0 ) -
263                                 ( parseInt( closestHandle.css("borderBottomWidth"), 10 ) || 0) +
264                                 ( parseInt( closestHandle.css("marginTop"), 10 ) || 0)
265                 };
266
267                 if ( !this.handles.hasClass( "ui-state-hover" ) ) {
268                         this._slide( event, index, normValue );
269                 }
270                 this._animateOff = true;
271                 return true;
272         },
273
274         _mouseStart: function() {
275                 return true;
276         },
277
278         _mouseDrag: function( event ) {
279                 var position = { x: event.pageX, y: event.pageY },
280                         normValue = this._normValueFromMouse( position );
281
282                 this._slide( event, this._handleIndex, normValue );
283
284                 return false;
285         },
286
287         _mouseStop: function( event ) {
288                 this.handles.removeClass( "ui-state-active" );
289                 this._mouseSliding = false;
290
291                 this._stop( event, this._handleIndex );
292                 this._change( event, this._handleIndex );
293
294                 this._handleIndex = null;
295                 this._clickOffset = null;
296                 this._animateOff = false;
297
298                 return false;
299         },
300
301         _detectOrientation: function() {
302                 this.orientation = ( this.options.orientation === "vertical" ) ? "vertical" : "horizontal";
303         },
304
305         _normValueFromMouse: function( position ) {
306                 var pixelTotal,
307                         pixelMouse,
308                         percentMouse,
309                         valueTotal,
310                         valueMouse;
311
312                 if ( this.orientation === "horizontal" ) {
313                         pixelTotal = this.elementSize.width;
314                         pixelMouse = position.x - this.elementOffset.left - ( this._clickOffset ? this._clickOffset.left : 0 );
315                 } else {
316                         pixelTotal = this.elementSize.height;
317                         pixelMouse = position.y - this.elementOffset.top - ( this._clickOffset ? this._clickOffset.top : 0 );
318                 }
319
320                 percentMouse = ( pixelMouse / pixelTotal );
321                 if ( percentMouse > 1 ) {
322                         percentMouse = 1;
323                 }
324                 if ( percentMouse < 0 ) {
325                         percentMouse = 0;
326                 }
327                 if ( this.orientation === "vertical" ) {
328                         percentMouse = 1 - percentMouse;
329                 }
330
331                 valueTotal = this._valueMax() - this._valueMin();
332                 valueMouse = this._valueMin() + percentMouse * valueTotal;
333
334                 return this._trimAlignValue( valueMouse );
335         },
336
337         _start: function( event, index ) {
338                 var uiHash = {
339                         handle: this.handles[ index ],
340                         value: this.value()
341                 };
342                 if ( this.options.values && this.options.values.length ) {
343                         uiHash.value = this.values( index );
344                         uiHash.values = this.values();
345                 }
346                 return this._trigger( "start", event, uiHash );
347         },
348
349         _slide: function( event, index, newVal ) {
350                 var otherVal,
351                         newValues,
352                         allowed;
353
354                 if ( this.options.values && this.options.values.length ) {
355                         otherVal = this.values( index ? 0 : 1 );
356
357                         if ( ( this.options.values.length === 2 && this.options.range === true ) &&
358                                         ( ( index === 0 && newVal > otherVal) || ( index === 1 && newVal < otherVal ) )
359                                 ) {
360                                 newVal = otherVal;
361                         }
362
363                         if ( newVal !== this.values( index ) ) {
364                                 newValues = this.values();
365                                 newValues[ index ] = newVal;
366                                 // A slide can be canceled by returning false from the slide callback
367                                 allowed = this._trigger( "slide", event, {
368                                         handle: this.handles[ index ],
369                                         value: newVal,
370                                         values: newValues
371                                 } );
372                                 otherVal = this.values( index ? 0 : 1 );
373                                 if ( allowed !== false ) {
374                                         this.values( index, newVal, true );
375                                 }
376                         }
377                 } else {
378                         if ( newVal !== this.value() ) {
379                                 // A slide can be canceled by returning false from the slide callback
380                                 allowed = this._trigger( "slide", event, {
381                                         handle: this.handles[ index ],
382                                         value: newVal
383                                 } );
384                                 if ( allowed !== false ) {
385                                         this.value( newVal );
386                                 }
387                         }
388                 }
389         },
390
391         _stop: function( event, index ) {
392                 var uiHash = {
393                         handle: this.handles[ index ],
394                         value: this.value()
395                 };
396                 if ( this.options.values && this.options.values.length ) {
397                         uiHash.value = this.values( index );
398                         uiHash.values = this.values();
399                 }
400
401                 this._trigger( "stop", event, uiHash );
402         },
403
404         _change: function( event, index ) {
405                 if ( !this._keySliding && !this._mouseSliding ) {
406                         var uiHash = {
407                                 handle: this.handles[ index ],
408                                 value: this.value()
409                         };
410                         if ( this.options.values && this.options.values.length ) {
411                                 uiHash.value = this.values( index );
412                                 uiHash.values = this.values();
413                         }
414
415                         this._trigger( "change", event, uiHash );
416                 }
417         },
418
419         value: function( newValue ) {
420                 if ( arguments.length ) {
421                         this.options.value = this._trimAlignValue( newValue );
422                         this._refreshValue();
423                         this._change( null, 0 );
424                         return;
425                 }
426
427                 return this._value();
428         },
429
430         values: function( index, newValue ) {
431                 var vals,
432                         newValues,
433                         i;
434
435                 if ( arguments.length > 1 ) {
436                         this.options.values[ index ] = this._trimAlignValue( newValue );
437                         this._refreshValue();
438                         this._change( null, index );
439                         return;
440                 }
441
442                 if ( arguments.length ) {
443                         if ( $.isArray( arguments[ 0 ] ) ) {
444                                 vals = this.options.values;
445                                 newValues = arguments[ 0 ];
446                                 for ( i = 0; i < vals.length; i += 1 ) {
447                                         vals[ i ] = this._trimAlignValue( newValues[ i ] );
448                                         this._change( null, i );
449                                 }
450                                 this._refreshValue();
451                         } else {
452                                 if ( this.options.values && this.options.values.length ) {
453                                         return this._values( index );
454                                 } else {
455                                         return this.value();
456                                 }
457                         }
458                 } else {
459                         return this._values();
460                 }
461         },
462
463         _setOption: function( key, value ) {
464                 var i,
465                         valsLength = 0;
466
467                 if ( $.isArray( this.options.values ) ) {
468                         valsLength = this.options.values.length;
469                 }
470
471                 $.Widget.prototype._setOption.apply( this, arguments );
472
473                 switch ( key ) {
474                         case "disabled":
475                                 if ( value ) {
476                                         this.handles.filter( ".ui-state-focus" ).blur();
477                                         this.handles.removeClass( "ui-state-hover" );
478                                         this.handles.prop( "disabled", true );
479                                         this.element.addClass( "ui-disabled" );
480                                 } else {
481                                         this.handles.prop( "disabled", false );
482                                         this.element.removeClass( "ui-disabled" );
483                                 }
484                                 break;
485                         case "orientation":
486                                 this._detectOrientation();
487                                 this.element
488                                         .removeClass( "ui-slider-horizontal ui-slider-vertical" )
489                                         .addClass( "ui-slider-" + this.orientation );
490                                 this._refreshValue();
491                                 break;
492                         case "value":
493                                 this._animateOff = true;
494                                 this._refreshValue();
495                                 this._change( null, 0 );
496                                 this._animateOff = false;
497                                 break;
498                         case "values":
499                                 this._animateOff = true;
500                                 this._refreshValue();
501                                 for ( i = 0; i < valsLength; i += 1 ) {
502                                         this._change( null, i );
503                                 }
504                                 this._animateOff = false;
505                                 break;
506                         case "min":
507                         case "max":
508                                 this._animateOff = true;
509                                 this._refreshValue();
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 ) {
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));