471 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			471 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| /*! Copyright (c) 2011 Piotr Rochala (http://rocha.la)
 | |
|  * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)
 | |
|  * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.
 | |
|  *
 | |
|  * Version: 1.3.3
 | |
|  *
 | |
|  */
 | |
| (function($) {
 | |
| 
 | |
|   $.fn.extend({
 | |
|     slimScroll: function(options) {
 | |
| 
 | |
|       var defaults = {
 | |
| 
 | |
|         // width in pixels of the visible scroll area
 | |
|         width : 'auto',
 | |
| 
 | |
|         // height in pixels of the visible scroll area
 | |
|         height : '250px',
 | |
| 
 | |
|         // width in pixels of the scrollbar and rail
 | |
|         size : '7px',
 | |
| 
 | |
|         // scrollbar color, accepts any hex/color value
 | |
|         color: '#000',
 | |
| 
 | |
|         // scrollbar position - left/right
 | |
|         position : 'right',
 | |
| 
 | |
|         // distance in pixels between the side edge and the scrollbar
 | |
|         distance : '1px',
 | |
| 
 | |
|         // default scroll position on load - top / bottom / $('selector')
 | |
|         start : 'top',
 | |
| 
 | |
|         // sets scrollbar opacity
 | |
|         opacity : .4,
 | |
| 
 | |
|         // enables always-on mode for the scrollbar
 | |
|         alwaysVisible : false,
 | |
| 
 | |
|         // check if we should hide the scrollbar when user is hovering over
 | |
|         disableFadeOut : false,
 | |
| 
 | |
|         // sets visibility of the rail
 | |
|         railVisible : false,
 | |
| 
 | |
|         // sets rail color
 | |
|         railColor : '#333',
 | |
| 
 | |
|         // sets rail opacity
 | |
|         railOpacity : .2,
 | |
| 
 | |
|         // whether  we should use jQuery UI Draggable to enable bar dragging
 | |
|         railDraggable : true,
 | |
| 
 | |
|         // defautlt CSS class of the slimscroll rail
 | |
|         railClass : 'slimScrollRail',
 | |
| 
 | |
|         // defautlt CSS class of the slimscroll bar
 | |
|         barClass : 'slimScrollBar',
 | |
| 
 | |
|         // defautlt CSS class of the slimscroll wrapper
 | |
|         wrapperClass : 'slimScrollDiv',
 | |
| 
 | |
|         // check if mousewheel should scroll the window if we reach top/bottom
 | |
|         allowPageScroll : false,
 | |
| 
 | |
|         // scroll amount applied to each mouse wheel step
 | |
|         wheelStep : 20,
 | |
| 
 | |
|         // scroll amount applied when user is using gestures
 | |
|         touchScrollStep : 200,
 | |
| 
 | |
|         // sets border radius
 | |
|         borderRadius: '7px',
 | |
| 
 | |
|         // sets border radius of the rail
 | |
|         railBorderRadius : '7px'
 | |
|       };
 | |
| 
 | |
|       var o = $.extend(defaults, options);
 | |
| 
 | |
|       // do it for every element that matches selector
 | |
|       this.each(function(){
 | |
| 
 | |
|       var isOverPanel, isOverBar, isDragg, queueHide, touchDif,
 | |
|         barHeight, percentScroll, lastScroll,
 | |
|         divS = '<div></div>',
 | |
|         minBarHeight = 30,
 | |
|         releaseScroll = false;
 | |
| 
 | |
|         // used in event handlers and for better minification
 | |
|         var me = $(this);
 | |
| 
 | |
|         // ensure we are not binding it again
 | |
|         if (me.parent().hasClass(o.wrapperClass))
 | |
|         {
 | |
|             // start from last bar position
 | |
|             var offset = me.scrollTop();
 | |
| 
 | |
|             // find bar and rail
 | |
|             bar = me.parent().find('.' + o.barClass);
 | |
|             rail = me.parent().find('.' + o.railClass);
 | |
| 
 | |
|             getBarHeight();
 | |
| 
 | |
|             // check if we should scroll existing instance
 | |
|             if ($.isPlainObject(options))
 | |
|             {
 | |
|               // Pass height: auto to an existing slimscroll object to force a resize after contents have changed
 | |
|               if ( 'height' in options && options.height == 'auto' ) {
 | |
|                 me.parent().css('height', 'auto');
 | |
|                 me.css('height', 'auto');
 | |
|                 var height = me.parent().parent().height();
 | |
|                 me.parent().css('height', height);
 | |
|                 me.css('height', height);
 | |
|               }
 | |
| 
 | |
|               if ('scrollTo' in options)
 | |
|               {
 | |
|                 // jump to a static point
 | |
|                 offset = parseInt(o.scrollTo);
 | |
|               }
 | |
|               else if ('scrollBy' in options)
 | |
|               {
 | |
|                 // jump by value pixels
 | |
|                 offset += parseInt(o.scrollBy);
 | |
|               }
 | |
|               else if ('destroy' in options)
 | |
|               {
 | |
|                 // remove slimscroll elements
 | |
|                 bar.remove();
 | |
|                 rail.remove();
 | |
|                 me.unwrap();
 | |
|                 return;
 | |
|               }
 | |
| 
 | |
|               // scroll content by the given offset
 | |
|               scrollContent(offset, false, true);
 | |
|             }
 | |
| 
 | |
|             return;
 | |
|         }
 | |
|         else if ($.isPlainObject(options))
 | |
|         {
 | |
|             if ('destroy' in options)
 | |
|             {
 | |
|             	return;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         // optionally set height to the parent's height
 | |
|         o.height = (o.height == 'auto') ? me.parent().height() : o.height;
 | |
| 
 | |
|         // wrap content
 | |
|         var wrapper = $(divS)
 | |
|           .addClass(o.wrapperClass)
 | |
|           .css({
 | |
|             position: 'relative',
 | |
|             overflow: 'hidden',
 | |
|             width: o.width,
 | |
|             height: o.height
 | |
|           });
 | |
| 
 | |
|         // update style for the div
 | |
|         me.css({
 | |
|           overflow: 'hidden',
 | |
|           width: o.width,
 | |
|           height: o.height
 | |
|         });
 | |
| 
 | |
|         // create scrollbar rail
 | |
|         var rail = $(divS)
 | |
|           .addClass(o.railClass)
 | |
|           .css({
 | |
|             width: o.size,
 | |
|             height: '100%',
 | |
|             position: 'absolute',
 | |
|             top: 0,
 | |
|             display: (o.alwaysVisible && o.railVisible) ? 'block' : 'none',
 | |
|             'border-radius': o.railBorderRadius,
 | |
|             background: o.railColor,
 | |
|             opacity: o.railOpacity,
 | |
|             zIndex: 90
 | |
|           });
 | |
| 
 | |
|         // create scrollbar
 | |
|         var bar = $(divS)
 | |
|           .addClass(o.barClass)
 | |
|           .css({
 | |
|             background: o.color,
 | |
|             width: o.size,
 | |
|             position: 'absolute',
 | |
|             top: 0,
 | |
|             opacity: o.opacity,
 | |
|             display: o.alwaysVisible ? 'block' : 'none',
 | |
|             'border-radius' : o.borderRadius,
 | |
|             BorderRadius: o.borderRadius,
 | |
|             MozBorderRadius: o.borderRadius,
 | |
|             WebkitBorderRadius: o.borderRadius,
 | |
|             zIndex: 99
 | |
|           });
 | |
| 
 | |
|         // set position
 | |
|         var posCss = (o.position == 'right') ? { right: o.distance } : { left: o.distance };
 | |
|         rail.css(posCss);
 | |
|         bar.css(posCss);
 | |
| 
 | |
|         // wrap it
 | |
|         me.wrap(wrapper);
 | |
| 
 | |
|         // append to parent div
 | |
|         me.parent().append(bar);
 | |
|         me.parent().append(rail);
 | |
| 
 | |
|         // make it draggable and no longer dependent on the jqueryUI
 | |
|         if (o.railDraggable){
 | |
|           bar.bind("mousedown", function(e) {
 | |
|             var $doc = $(document);
 | |
|             isDragg = true;
 | |
|             t = parseFloat(bar.css('top'));
 | |
|             pageY = e.pageY;
 | |
| 
 | |
|             $doc.bind("mousemove.slimscroll", function(e){
 | |
|               currTop = t + e.pageY - pageY;
 | |
|               bar.css('top', currTop);
 | |
|               scrollContent(0, bar.position().top, false);// scroll content
 | |
|             });
 | |
| 
 | |
|             $doc.bind("mouseup.slimscroll", function(e) {
 | |
|               isDragg = false;hideBar();
 | |
|               $doc.unbind('.slimscroll');
 | |
|             });
 | |
|             return false;
 | |
|           }).bind("selectstart.slimscroll", function(e){
 | |
|             e.stopPropagation();
 | |
|             e.preventDefault();
 | |
|             return false;
 | |
|           });
 | |
|         }
 | |
| 
 | |
|         // on rail over
 | |
|         rail.hover(function(){
 | |
|           showBar();
 | |
|         }, function(){
 | |
|           hideBar();
 | |
|         });
 | |
| 
 | |
|         // on bar over
 | |
|         bar.hover(function(){
 | |
|           isOverBar = true;
 | |
|         }, function(){
 | |
|           isOverBar = false;
 | |
|         });
 | |
| 
 | |
|         // show on parent mouseover
 | |
|         me.hover(function(){
 | |
|           isOverPanel = true;
 | |
|           showBar();
 | |
|           hideBar();
 | |
|         }, function(){
 | |
|           isOverPanel = false;
 | |
|           hideBar();
 | |
|         });
 | |
| 
 | |
|         // support for mobile
 | |
|         me.bind('touchstart', function(e,b){
 | |
|           if (e.originalEvent.touches.length)
 | |
|           {
 | |
|             // record where touch started
 | |
|             touchDif = e.originalEvent.touches[0].pageY;
 | |
|           }
 | |
|         });
 | |
| 
 | |
|         me.bind('touchmove', function(e){
 | |
|           // prevent scrolling the page if necessary
 | |
|           if(!releaseScroll)
 | |
|           {
 | |
|   		      e.originalEvent.preventDefault();
 | |
| 		      }
 | |
|           if (e.originalEvent.touches.length)
 | |
|           {
 | |
|             // see how far user swiped
 | |
|             var diff = (touchDif - e.originalEvent.touches[0].pageY) / o.touchScrollStep;
 | |
|             // scroll content
 | |
|             scrollContent(diff, true);
 | |
|             touchDif = e.originalEvent.touches[0].pageY;
 | |
|           }
 | |
|         });
 | |
| 
 | |
|         // set up initial height
 | |
|         getBarHeight();
 | |
| 
 | |
|         // check start position
 | |
|         if (o.start === 'bottom')
 | |
|         {
 | |
|           // scroll content to bottom
 | |
|           bar.css({ top: me.outerHeight() - bar.outerHeight() });
 | |
|           scrollContent(0, true);
 | |
|         }
 | |
|         else if (o.start !== 'top')
 | |
|         {
 | |
|           // assume jQuery selector
 | |
|           scrollContent($(o.start).position().top, null, true);
 | |
| 
 | |
|           // make sure bar stays hidden
 | |
|           if (!o.alwaysVisible) { bar.hide(); }
 | |
|         }
 | |
| 
 | |
|         // attach scroll events
 | |
|         attachWheel();
 | |
| 
 | |
|         function _onWheel(e)
 | |
|         {
 | |
|           // use mouse wheel only when mouse is over
 | |
|           if (!isOverPanel) { return; }
 | |
| 
 | |
|           var e = e || window.event;
 | |
| 
 | |
|           var delta = 0;
 | |
|           if (e.wheelDelta) { delta = -e.wheelDelta/120; }
 | |
|           if (e.detail) { delta = e.detail / 3; }
 | |
| 
 | |
|           var target = e.target || e.srcTarget || e.srcElement;
 | |
|           if ($(target).closest('.' + o.wrapperClass).is(me.parent())) {
 | |
|             // scroll content
 | |
|             scrollContent(delta, true);
 | |
|           }
 | |
| 
 | |
|           // stop window scroll
 | |
|           if (e.preventDefault && !releaseScroll) { e.preventDefault(); }
 | |
|           if (!releaseScroll) { e.returnValue = false; }
 | |
|         }
 | |
| 
 | |
|         function scrollContent(y, isWheel, isJump)
 | |
|         {
 | |
|           releaseScroll = false;
 | |
|           var delta = y;
 | |
|           var maxTop = me.outerHeight() - bar.outerHeight();
 | |
| 
 | |
|           if (isWheel)
 | |
|           {
 | |
|             // move bar with mouse wheel
 | |
|             delta = parseInt(bar.css('top')) + y * parseInt(o.wheelStep) / 100 * bar.outerHeight();
 | |
| 
 | |
|             // move bar, make sure it doesn't go out
 | |
|             delta = Math.min(Math.max(delta, 0), maxTop);
 | |
| 
 | |
|             // if scrolling down, make sure a fractional change to the
 | |
|             // scroll position isn't rounded away when the scrollbar's CSS is set
 | |
|             // this flooring of delta would happened automatically when
 | |
|             // bar.css is set below, but we floor here for clarity
 | |
|             delta = (y > 0) ? Math.ceil(delta) : Math.floor(delta);
 | |
| 
 | |
|             // scroll the scrollbar
 | |
|             bar.css({ top: delta + 'px' });
 | |
|           }
 | |
| 
 | |
|           // calculate actual scroll amount
 | |
|           percentScroll = parseInt(bar.css('top')) / (me.outerHeight() - bar.outerHeight());
 | |
|           delta = percentScroll * (me[0].scrollHeight - me.outerHeight());
 | |
| 
 | |
|           if (isJump)
 | |
|           {
 | |
|             delta = y;
 | |
|             var offsetTop = delta / me[0].scrollHeight * me.outerHeight();
 | |
|             offsetTop = Math.min(Math.max(offsetTop, 0), maxTop);
 | |
|             bar.css({ top: offsetTop + 'px' });
 | |
|           }
 | |
| 
 | |
|           // scroll content
 | |
|           me.scrollTop(delta);
 | |
| 
 | |
|           // fire scrolling event
 | |
|           me.trigger('slimscrolling', ~~delta);
 | |
| 
 | |
|           // ensure bar is visible
 | |
|           showBar();
 | |
| 
 | |
|           // trigger hide when scroll is stopped
 | |
|           hideBar();
 | |
|         }
 | |
| 
 | |
|         function attachWheel()
 | |
|         {
 | |
|           if (window.addEventListener)
 | |
|           {
 | |
|             this.addEventListener('DOMMouseScroll', _onWheel, false );
 | |
|             this.addEventListener('mousewheel', _onWheel, false );
 | |
|           }
 | |
|           else
 | |
|           {
 | |
|             document.attachEvent("onmousewheel", _onWheel)
 | |
|           }
 | |
|         }
 | |
| 
 | |
|         function getBarHeight()
 | |
|         {
 | |
|           // calculate scrollbar height and make sure it is not too small
 | |
|           barHeight = Math.max((me.outerHeight() / me[0].scrollHeight) * me.outerHeight(), minBarHeight);
 | |
|           bar.css({ height: barHeight + 'px' });
 | |
| 
 | |
|           // hide scrollbar if content is not long enough
 | |
|           var display = barHeight == me.outerHeight() ? 'none' : 'block';
 | |
|           bar.css({ display: display });
 | |
|         }
 | |
| 
 | |
|         function showBar()
 | |
|         {
 | |
|           // recalculate bar height
 | |
|           getBarHeight();
 | |
|           clearTimeout(queueHide);
 | |
| 
 | |
|           // when bar reached top or bottom
 | |
|           if (percentScroll == ~~percentScroll)
 | |
|           {
 | |
|             //release wheel
 | |
|             releaseScroll = o.allowPageScroll;
 | |
| 
 | |
|             // publish approporiate event
 | |
|             if (lastScroll != percentScroll)
 | |
|             {
 | |
|                 var msg = (~~percentScroll == 0) ? 'top' : 'bottom';
 | |
|                 me.trigger('slimscroll', msg);
 | |
|             }
 | |
|           }
 | |
|           else
 | |
|           {
 | |
|             releaseScroll = false;
 | |
|           }
 | |
|           lastScroll = percentScroll;
 | |
| 
 | |
|           // show only when required
 | |
|           if(barHeight >= me.outerHeight()) {
 | |
|             //allow window scroll
 | |
|             releaseScroll = true;
 | |
|             return;
 | |
|           }
 | |
|           bar.stop(true,true).fadeIn('fast');
 | |
|           if (o.railVisible) { rail.stop(true,true).fadeIn('fast'); }
 | |
|         }
 | |
| 
 | |
|         function hideBar()
 | |
|         {
 | |
|           // only hide when options allow it
 | |
|           if (!o.alwaysVisible)
 | |
|           {
 | |
|             queueHide = setTimeout(function(){
 | |
|               if (!(o.disableFadeOut && isOverPanel) && !isOverBar && !isDragg)
 | |
|               {
 | |
|                 bar.fadeOut('slow');
 | |
|                 rail.fadeOut('slow');
 | |
|               }
 | |
|             }, 1000);
 | |
|           }
 | |
|         }
 | |
| 
 | |
|       });
 | |
| 
 | |
|       // maintain chainability
 | |
|       return this;
 | |
|     }
 | |
|   });
 | |
| 
 | |
|   $.fn.extend({
 | |
|     slimscroll: $.fn.slimScroll
 | |
|   });
 | |
| 
 | |
| })(jQuery);
 | 
