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