diff --git a/jquery.scroll.js b/jquery.scroll.js index fd80020..cea200e 100644 --- a/jquery.scroll.js +++ b/jquery.scroll.js @@ -4,9 +4,9 @@ Version 0.4 https://github.com/thomd/jquery-scroll Copyright (c) 2011 Thomas Duerr (me-at-thomd-dot-net) Licensed under the MIT license (https://raw.github.com/thomd/jquery-scroll/master/MIT-LICENSE) +Modified version at http://github.com/akmjenkins/jquery-scroll +Further fixes at http://github.com/pkeeper/jquery-scroll */ - -; /* Usage Examples: @@ -168,10 +168,15 @@ Changelog: // $('selector').scrollbar("scrollto", "middle"); // scroll to vertically middle of content // $('selector').scrollbar("scrollto", "bottom"); // scroll to bottom of content // $('selector').scrollbar("scrollto", $('item')); // scroll to first content item identified by selector $('item') + // $('selector').scrollbar("scrollto", $('item'),speed,easing); // scroll to first content item identified by selector $('item') // - scrollto: function(to){ + scrollto: function(to,speed,easing){ + var speed = (speed || false), + easing = easing || false; return this.each(function(){ - this.scrollbar.scrollto(to); + if(this.scrollbar) { + this.scrollbar.scrollto(to,speed,easing); + } }); }, @@ -184,6 +189,7 @@ Changelog: return this.each(function() { if(this.scrollbar) { this.scrollbar.unscrollbar(); + this.scrollbar = null; } }); } @@ -418,6 +424,9 @@ Changelog: // appendEvents: function(){ + //need this for added event listeners + var self = this; + // append drag-drop event on scrollbar-handle // the events 'mousemove.handle' and 'mouseup.handle' are dynamically appended in the startOfHandleMove-function this.handle.bind('mousedown.handle', $.proxy(this, 'startOfHandleMove')); @@ -436,6 +445,42 @@ Changelog: // append hover event on content container this.container.bind('mouseenter.container mouseleave.container', $.proxy(this, 'onContentHover')); + + //handle the key events + $(document).bind('keydown',function(e) { + if(self.container.hasClass('focused') || self.container.hasClass('hover')) { + var timer = false; + //bind the arrow keys + switch(e.keyCode) { + case 38 : //up arrow + e.preventDefault(); + self.handle.direction = -1; + self.handle.step = self.opts.scrollStepArrows; + timer = setTimeout($.proxy(self.moveHandle, self), self.opts.scrollTimeoutArrows); + break; + case 40 : //down arrow + e.preventDefault(); + self.handle.direction = 1; + self.handle.step = self.opts.scrollStepArrows; + timer = setTimeout($.proxy(self.moveHandle, self), self.opts.scrollTimeoutArrows); + break; + case 33 : //pgup + e.preventDefault(); + self.handle.direction = -1; + self.handle.step = self.opts.scrollStepArrows*15; + timer = setTimeout($.proxy(self.moveHandle, self), self.opts.scrollTimeoutArrows); + break; + case 34 : //pgdn + e.preventDefault(); + self.handle.direction = 1; + self.handle.step = self.opts.scrollStepArrows*15; + timer = setTimeout($.proxy(self.moveHandle, self), self.opts.scrollTimeoutArrows); + break; + } + + } + + }); // do not bubble down click events into content container this.handle.bind('click.scrollbar', this.preventClickBubbling); @@ -455,18 +500,21 @@ Changelog: // - // repaint scrollbar height and position + // repaint scrollbar height and position - if required!!! Otherwise, remove this // repaint: function(){ - this.setHandle(); - this.setHandlePosition(); + if(this.pane.height() <= this.props.containerHeight) { + this.unscrollbar(); + } else { + this.setHandle(); + this.setHandlePosition(); + } }, - // // scroll to a specific distance from the top // - scrollto: function(to){ + scrollto: function(to,speed,easing){ var distance = 0; @@ -486,18 +534,20 @@ Changelog: } this.handle.top = distance; - this.setHandlePosition(); - this.setContentPosition(); + this.setHandlePosition(speed,easing); + this.setContentPosition(speed,easing); }, // // Remove scrollbar dom elements // unscrollbar: function() { - var holder = this.container.find('.scrollbar-pane').find('*'); - this.container.empty(); - this.container.append(holder); - this.container.attr('style',''); + var holder = this.container.find('.scrollbar-pane').html(); + if(holder !== null) { + this.container.empty(); + this.container.append(holder); + this.container.attr('style',''); + } }, @@ -560,25 +610,39 @@ Changelog: // // set position of handle // - setHandlePosition: function(){ + setHandlePosition: function(speed,easing){ + var speed = (speed || false), + easing = ((easing) ? ($.fn.easing ? easing : 'swing') : false); // stay within range [handlePosition.min, handlePosition.max] this.handle.top = (this.handle.top > this.props.handlePosition.max) ? this.props.handlePosition.max : this.handle.top; this.handle.top = (this.handle.top < this.props.handlePosition.min) ? this.props.handlePosition.min : this.handle.top; - this.handle[0].style.top = this.handle.top + 'px'; + if(speed && !isNaN(speed)) { + this.handle.stop().animate({top:this.handle.top+'px'},speed,easing); + } else { + this.handle[0].style.top = this.handle.top + 'px'; + } }, // // set position of content // - setContentPosition: function(){ + setContentPosition: function(speed,easing){ + var speed = (speed || false), + easing = ((easing) ? ($.fn.easing ? easing : 'swing') : false); // derive position of content from position of handle this.pane.top = -1 * this.props.handleContentRatio * this.handle.top; - - this.pane[0].style.top = this.pane.top + 'px'; + + if(speed && !isNaN(speed)) { + this.pane.stop().animate({top:this.pane.top+'px'},speed,easing); + } else { + this.pane[0].style.top = this.pane.top + 'px'; + } + + this.container.trigger('scrolled'); }, @@ -586,15 +650,17 @@ Changelog: // mouse wheel movement // onMouseWheel: function(ev, delta){ - + if(!this.container.hasClass('focused') && !this.container.hasClass('hover')) { return; } + + delta *= 2.5; + // calculate new handle position this.handle.top -= delta; this.setHandlePosition(); this.setContentPosition(); - // prevent default scrolling of the entire document if handle is within [min, max]-range - if(this.handle.top > this.props.handlePosition.min && this.handle.top < this.props.handlePosition.max){ + if(this.handle.top > this.props.handlePosition.min && this.handle.top <= this.props.handlePosition.max){ ev.preventDefault(); } }, @@ -672,6 +738,7 @@ Changelog: this.handle[0].style.top = this.handle.top + 'px'; this.setContentPosition(); + this.container.trigger('scrolled'); }, @@ -679,13 +746,27 @@ Changelog: // add class attribute on content while interacting with content // onContentHover: function(ev){ + if(ev.type === 'mouseenter'){ this.container.addClass('hover'); this.handleContainer.addClass('hover'); + + //remove the hover from parent scroll panes + this.container.closest('div.scrollbar-pane').each(function() { + $(this).parent().removeClass('hover focused'); + }); + } else { this.container.removeClass('hover'); this.handleContainer.removeClass('hover'); + + //remove the hover from parent scroll panes + this.container.closest('div.scrollbar-pane').each(function() { + $(this).parent().addClass('hover focused'); + }); + } + }, @@ -719,8 +800,11 @@ Changelog: // inner-wrap content temporarily and meassure content height. // wrapper container need to have an overflow set to 'hidden' to respect margin collapsing - var wrapper = container.wrapInner('
').find(':first'); + + //add style="zoom:1" to fix IE7 bug where the scrollbar doesn't work if the content has floated elements + var wrapper = container.wrapInner('').find(':first'); var height = wrapper.css({overflow:'hidden'}).height(); + wrapper.replaceWith(wrapper.contents()); return height; }; @@ -752,81 +836,4 @@ Changelog: }); }; - - // - // ----- mousewheel event --------------------------------------------------------------------- - // based on jquery.mousewheel.js from Brandon Aaron (brandon.aaron@gmail.com || http://brandonaaron.net) - // - $.event.special.mousewheel = { - - setup: function(){ - if (this.addEventListener){ - this.addEventListener('mousewheel', $.fn.scrollbar.mouseWheelHandler, false); - this.addEventListener('DOMMouseScroll', $.fn.scrollbar.mouseWheelHandler, false); - } else { - this.onmousewheel = $.fn.scrollbar.mouseWheelHandler; - } - }, - - teardown: function(){ - if (this.removeEventListener){ - this.removeEventListener('mousewheel', $.fn.scrollbar.mouseWheelHandler, false); - this.removeEventListener('DOMMouseScroll', $.fn.scrollbar.mouseWheelHandler, false); - } else { - this.onmousewheel = null; - } - } - }; - - - $.fn.extend({ - mousewheel: function(fn){ - return fn ? this.bind("mousewheel", fn) : this.trigger("mousewheel"); - }, - - unmousewheel: function(fn){ - return this.unbind("mousewheel", fn); - } - }); - - - $.fn.scrollbar.mouseWheelHandler = function(event) { - var orgEvent = event || window.event, - args = [].slice.call(arguments, 1), - delta = 0, - returnValue = true, - deltaX = 0, - deltaY = 0; - - event = $.event.fix(orgEvent); - event.type = "mousewheel"; - - // Old school scrollwheel delta - if(event.wheelDelta){ - delta = event.wheelDelta / 120; - } - if(event.detail){ - delta = -event.detail / 3; - } - - // Gecko - if(orgEvent.axis !== undefined && orgEvent.axis === orgEvent.HORIZONTAL_AXIS){ - deltaY = 0; - deltaX = -1 * delta; - } - - // Webkit - if(orgEvent.wheelDeltaY !== undefined){ - deltaY = orgEvent.wheelDeltaY / 120; - } - if(orgEvent.wheelDeltaX !== undefined){ - deltaX = -1 * orgEvent.wheelDeltaX / 120; - } - - // Add event and delta to the front of the arguments - args.unshift(event, delta, deltaX, deltaY); - - return $.event.handle.apply(this, args); - }; - -})(jQuery, document); // inject global jQuery object +})(jQuery, document); // inject global jQuery object \ No newline at end of file diff --git a/jquery.scroll.min.js b/jquery.scroll.min.js index b8656b8..d7966ba 100644 --- a/jquery.scroll.min.js +++ b/jquery.scroll.min.js @@ -4,4 +4,5 @@ Version 0.4 https://github.com/thomd/jquery-scroll Copyright (c) 2011 Thomas Duerr (me-at-thomd-dot-net) Licensed under the MIT license (https://raw.github.com/thomd/jquery-scroll/master/MIT-LICENSE) -*/(function($,document){var methods={init:function(fn,opts){var options=$.extend({},$.fn.scrollbar.defaults,opts);return this.each(function(){var container=$(this),props={arrows:options.arrows};options.containerHeight!="auto"&&container.height(options.containerHeight),props.containerHeight=container.height(),props.contentHeight=$.fn.scrollbar.contentHeight(container);if(props.contentHeight<=props.containerHeight)return!0;this.scrollbar=new $.fn.scrollbar.Scrollbar(container,props,options),this.scrollbar.buildHtml().setHandle().appendEvents(),typeof fn=="function"&&fn(container.find(".scrollbar-pane"),this.scrollbar)})},repaint:function(){return this.each(function(){this.scrollbar.repaint()})},scrollto:function(to){return this.each(function(){this.scrollbar.scrollto(to)})}};$.fn.scrollbar=function(method){if(methods[method])return methods[method].apply(this,Array.prototype.slice.call(arguments,1));if(typeof method=="function"||method===undefined)return methods.init.apply(this,arguments);if(typeof method=="object")return methods.init.apply(this,[null,method]);$.error("method '"+method+"' does not exist for $.fn.scrollbar")},$.fn.scrollbar.defaults={containerHeight:"auto",arrows:!0,handleHeight:"auto",handleMinHeight:30,scrollTimeout:50,scrollStep:20,scrollTimeoutArrows:40,scrollStepArrows:3},$.fn.scrollbar.Scrollbar=function(container,props,options){this.container=container,this.props=props,this.opts=options,this.mouse={},this.props.arrows=this.container.hasClass("no-arrows")?!1:this.props.arrows},$.fn.scrollbar.Scrollbar.prototype={buildHtml:function(){this.container.wrapInner(''),this.container.append(''),this.props.arrows&&this.container.append('').append('');var height=this.container.height();return this.pane=this.container.find(".scrollbar-pane"),this.handle=this.container.find(".scrollbar-handle"),this.handleContainer=this.container.find(".scrollbar-handle-container"),this.handleArrows=this.container.find(".scrollbar-handle-up, .scrollbar-handle-down"),this.handleArrowUp=this.container.find(".scrollbar-handle-up"),this.handleArrowDown=this.container.find(".scrollbar-handle-down"),this.pane.defaultCss({top:0,left:0}),this.handleContainer.defaultCss({right:0}),this.handle.defaultCss({top:0,right:0}),this.handleArrows.defaultCss({right:0}),this.handleArrowUp.defaultCss({top:0}),this.handleArrowDown.defaultCss({bottom:0}),this.container.css({position:this.container.css("position")==="absolute"?"absolute":"relative",overflow:"hidden",height:height}),this.pane.css({position:"absolute",overflow:"visible",height:"auto"}),this.handleContainer.css({position:"absolute",top:this.handleArrowUp.outerHeight(!0),height:this.props.containerHeight-this.handleArrowUp.outerHeight(!0)-this.handleArrowDown.outerHeight(!0)+"px"}),this.handle.css({position:"absolute",cursor:"pointer"}),this.handleArrows.css({position:"absolute",cursor:"pointer"}),this.pane.top=0,this},setHandle:function(){return this.props.handleContainerHeight=this.handleContainer.height(),this.props.contentHeight=this.pane.height(),this.props.handleHeight=this.opts.handleHeight=="auto"?Math.max(Math.ceil(this.props.containerHeight*this.props.handleContainerHeight/this.props.contentHeight),this.opts.handleMinHeight):this.opts.handleHeight,this.handle.height(this.props.handleHeight),this.handle.height(2*this.handle.height()-this.handle.outerHeight(!0)),this.props.handlePosition={min:0,max:this.props.handleContainerHeight-this.props.handleHeight},this.props.handleContentRatio=(this.props.contentHeight-this.props.containerHeight)/(this.props.handleContainerHeight-this.props.handleHeight),this.handle.top==undefined?this.handle.top=0:this.handle.top=-1*this.pane.top/this.props.handleContentRatio,this},appendEvents:function(){return this.handle.bind("mousedown.handle",$.proxy(this,"startOfHandleMove")),this.handleContainer.bind("mousedown.handle",$.proxy(this,"onHandleContainerMousedown")),this.handleContainer.bind("mouseenter.container mouseleave.container",$.proxy(this,"onHandleContainerHover")),this.handleArrows.bind("mousedown.arrows",$.proxy(this,"onArrowsMousedown")),this.container.bind("mousewheel.container",$.proxy(this,"onMouseWheel")),this.container.bind("mouseenter.container mouseleave.container",$.proxy(this,"onContentHover")),this.handle.bind("click.scrollbar",this.preventClickBubbling),this.handleContainer.bind("click.scrollbar",this.preventClickBubbling),this.handleArrows.bind("click.scrollbar",this.preventClickBubbling),this},mousePosition:function(ev){return ev.pageY||ev.clientY+(document.documentElement.scrollTop||document.body.scrollTop)||0},repaint:function(){this.setHandle(),this.setHandlePosition()},scrollto:function(to){var distance=0;typeof to=="number"?distance=(to<0?0:to)/this.props.handleContentRatio:typeof to=="string"?(to=="bottom"&&(distance=this.props.handlePosition.max),to=="middle"&&(distance=Math.ceil(this.props.handlePosition.max/2))):typeof to=="object"&&!$.isPlainObject(to)&&(distance=Math.ceil(to.position().top/this.props.handleContentRatio)),this.handle.top=distance,this.setHandlePosition(),this.setContentPosition()},startOfHandleMove:function(ev){ev.preventDefault(),ev.stopPropagation(),this.mouse.start=this.mousePosition(ev),this.handle.start=this.handle.top,$(document).bind("mousemove.handle",$.proxy(this,"onHandleMove")).bind("mouseup.handle",$.proxy(this,"endOfHandleMove")),this.handle.addClass("move"),this.handleContainer.addClass("move")},onHandleMove:function(ev){ev.preventDefault();var distance=this.mousePosition(ev)-this.mouse.start;this.handle.top=this.handle.start+distance,this.setHandlePosition(),this.setContentPosition()},endOfHandleMove:function(ev){$(document).unbind(".handle"),this.handle.removeClass("move"),this.handleContainer.removeClass("move")},setHandlePosition:function(){this.handle.top=this.handle.top>this.props.handlePosition.max?this.props.handlePosition.max:this.handle.top,this.handle.top=this.handle.top