Team:NCTU Formosa/slimscroll.js

/*! 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.2 (modified for fullpage.js)
*
*/

(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 = '
',
       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)
             {
               // clear slimscroll mouse event listeners
               detachWheel();
               // 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 = (options.height == 'auto') ? me.parent().height() : options.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 detachWheel()
       {
         if (window.removeEventListener)
         {
           this.removeEventListener('DOMMouseScroll', _onWheel);
           this.removeEventListener('mousewheel', _onWheel);
         }
         else
         {
           document.detachEvent('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);