123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464 |
- /*! 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.0
- *
- */
- (function($) {
- jQuery.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;
- }
- // 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 );
- this.addEventListener('MozMousePixelScroll', _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;
- }
- });
- jQuery.fn.extend({
- slimscroll: jQuery.fn.slimScroll
- });
- })(jQuery);
|