/* * * 2011 www.g-u-i.net * */ (function($){ jQuery.extend({ mouse: { x: 0, y: 0 }, clickNScroll: { mousedown:false, emaX: 0, emaY: 0, started : false } }); var methods = { init : function(options){ var settings = { scroller:'', allowHiliting:false, acceleration:.65, deceleration:.85, decelRate:64, reverse:false, rightMouse:false, allowThrowing:true, throwOnOut:true, stepableparent:false, changeLimit:3, stepInSpeed:500, axis:false, distance:0, easing:'linear', disabled : false, started:false, }; return this.each(function(){ var $this = $(this), ops = $.extend({}, settings, options || {}); ops.scroller = ops.scroller != '' ? $(ops.scroller, $this) : $this; ops.id = $this.attr('id'); $this.data("clicknscroll", ops); if(!ops.allowHiliting) { if (jQuery.browser.msie) { $this.get(0).onselectstart = function () { return false; }; } else { $this.get(0).onmousedown = function(e){e.preventDefault()} } } this.addEventListener('mouseup', function(e) { if($(this).data('clicknscroll').disabled) return; if($(this).hasClass('cns-scrolling')){ e.stopPropagation(); // stopPropagation to prevent mouseUp on dom children when just scrolling $(document).trigger('mouseup'); if(ops.allowThrowing) sling($(this)); } $.clickNScroll.mousedown = false; }, true); // add this event listener with addEventListener because of useCapture = true, that is impossible yet with jQuery bind() … $this .mousedown(function(e) { // $this.bind('mousedown click name', function(e) { // $.log('mousedown | $(this)',$(this)); if($(this).data('clicknscroll').disabled) return false; $this.stop().clearQueue(); $.clickNScroll.startX = e.pageX; $.clickNScroll.startY = e.pageY; $.clickNScroll.mousedown = $this; }) .mouseout(function(e) { if($(this).data('clicknscroll').disabled) return; var from = e.relatedTarget || e.toElement; if (!from || from.nodeName == "HTML") { if($.clickNScroll.mousedown && ops.allowThrowing && ops.throwOnOut) sling($(this)); $.clickNScroll.mousedown = false; } }); }); }, enable : function(){ // $.log('clickNScroll | enable | this',this); return this.each(function() { $(this).data('clicknscroll').disabled = false; }); }, disable : function(){ // $.log('clickNScroll | disable | this',this); return this.each(function() { $(this).data('clicknscroll').disabled = true; }); }, isStarted : function(){ return $(this).data('clicknscroll').started; }, stop : function(){ return this.each(function() { if(!$(this).data('clicknscroll').started){ $.clickNScroll.mousedown = false; $(this).data('clicknscroll').started = false; } }); }, scrollTo : function(delta){ // $.log('scrollTo | delta = '+delta); return this.each(function() { $(this).data('clicknscroll').scroller.scrollLeft(delta); }); } }; jQuery.fn.extend({ clickNScroll: function(options) { // Method calling logic if ( methods[options] ) { return methods[ options ].apply( this, Array.prototype.slice.call( arguments, 1 )); } else if ( typeof options === 'object' || ! options ) { return methods.init.apply( this, arguments ); } else { $.error( 'Method ' + options + ' does not exist on jQuery.clickNScroll' ); } } }); /** * sling($this) */ function sling($this) { var data = $this.data("clicknscroll"), $scroller = data.scroller, changeX = ($.clickNScroll.emaX)*data.deceleration, changeY = ($.clickNScroll.emaY)*data.deceleration; if( Math.abs(changeX) > 0 && Math.abs(changeX) <= data.changeLimit && data.stepableparent) { // $.log('ClicknScroll :: end sling X'); var scrollPos = $scroller.scrollLeft()+$scroller.width()*.5; $(data.stepableparent, $scroller).children(':visible').each(function(i) { var $child = $(this), childPos = $child.position(); if(scrollPos >= childPos.left && scrollPos <= childPos.left+$child.width() ){ var stepLeft = childPos.left + $child.width()*.5 - $scroller.width()*.5; var e = jQuery.Event('stepInLeft'); e.options = data; e.stepIndex = i; e.stepTarget = $child; e.direction = changeX < 0 ? -1 : 1; $this.trigger(e); $scroller.animate({scrollLeft: stepLeft}, {easing:data.easing, duration:data.stepInSpeed, queue:false , complete:function() { $this.trigger('stepedInLeft',data); } }); $.clickNScroll.emaX = 0; changeX = 0; return; } }); } if( Math.abs(changeY) > 0 && Math.abs(changeY) <= data.changeLimit && data.stepableparent) { // $.log('ClicknScroll :: end sling Y'); var scrollPos = $scroller.scrollTop()+$scroller.height()*.5; $(data.stepableparent, $scroller).children(':visible').each(function(i) { var $child = $(this), childPos = $child.position(); if(scrollPos >= childPos.top && scrollPos <= childPos.top+$child.height() ){ var stepTop = childPos.top + $child.height()*.5 - $scroller.height()*.5; var e = jQuery.Event('stepInTop'); e.options = data; e.stepIndex = i; e.stepTarget = $child; e.direction = changeY < 0 ? -1 : 1; $this.trigger(e); $scroller.animate({scrollTop: stepTop}, {easing:data.easing, duration:data.stepInSpeed, queue:false , complete:function() { $this.trigger('stepedInTop',data); } }); $.clickNScroll.emaY = 0; changeY = 0; return; } }); } if(Math.abs(changeX) < .01 && Math.abs(changeY) < .01 && $this.hasClass('cns-scrolling')){ $this.removeClass('cns-scrolling').trigger('clickNScrollStop'); return; } // return; move($this, changeX, changeY); setTimeout(function() { sling($this); }, 1000/data.decelRate); }; /** * move($scroller, changeX, changeY) */ function move($this, changeX, changeY) { $.log('clicknscroll | move'); // if(!$this.data('clicknscroll').started){ // $this.trigger('clickNScrollStart').data('clicknscroll').started = true; // } if(!$this.hasClass('cns-scrolling')){ $this.addClass('cns-scrolling').trigger('clickNScrollStart'); } $this.trigger('clickNScrollMove'); if(($.clickNScroll.emaX < 0 && changeX > 0) || ($.clickNScroll.emaX > 0 && changeX < 0)) $.clickNScroll.emaX = 0; if(($.clickNScroll.emaY < 0 && changeY > 0) || ($.clickNScroll.emaY > 0 && changeY < 0)) $.clickNScroll.emaY = 0; var ops = $this.data("clicknscroll"), $scroller = ops.scroller, amntX = ops.acceleration * changeX + (1 - ops.acceleration) * $.clickNScroll.emaX, amntY = ops.acceleration * changeY + (1 - ops.acceleration) * $.clickNScroll.emaY, scrollRight = $scroller[0].scrollWidth ? $scroller[0].scrollWidth - $scroller[0].clientWidth : $scroller[0].body.scrollWidth - $scroller[0].body.clientWidth, scrollBottom = $scroller[0].scrollHeight ? $scroller[0].scrollHeight - $scroller[0].clientHeight : $scroller[0].body.scrollHeight - $scroller[0].body.clientHeight; if(($scroller.scrollLeft() >= 0 && changeX >= 0) || ($scroller.scrollLeft() <= scrollRight && changeX <= 0)) $scroller.scrollLeft($scroller.scrollLeft() + (amntX)); if(($scroller.scrollTop() >= 0 && changeY >= 0) || ($scroller.scrollTop() <= scrollBottom && changeY <= 0)) $scroller.scrollTop($scroller.scrollTop() + (amntY)); $.clickNScroll.emaX = amntX; $.clickNScroll.emaY = amntY; }; /** * mousemove event */ $(document).mousemove(function(e) { if($.clickNScroll.mousedown) { var $this = $.clickNScroll.mousedown, ops = $this.data("clicknscroll"); if(ops.rightMouse && e.button != 2) return; else if(!ops.rightMouse && e.button == 2) return; var changeX = ops.axis != 'y' ? e.pageX - $.mouse.x : 0, changeY = ops.axis != 'x' ? e.pageY - $.mouse.y : 0; if(!ops.reverse) { changeX = 0-changeX; changeY = 0-changeY; } if((Math.abs($.clickNScroll.startX - e.pageX) > ops.distance && ops.axis != 'y') || (Math.abs($.clickNScroll.startY - e.pageY) > ops.distance && ops.axis != 'x')) move($this, changeX, changeY); } $.mouse = { x: e.pageX, y: e.pageY }; }); })(jQuery);