source: Dev/branches/jQueryUI/client/js/jquery/ui/jquery.ui.slider.js @ 249

Last change on this file since 249 was 249, checked in by hendrikvanantwerpen, 13 years ago

This one's for Subversion, because it's so close...

First widget (stripped down sequencer).
Seperated client and server code in two direcotry trees.

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