/* * simplyscroll 2 - a scroll-tastic jquery plugin * * http://logicbox.net/jquery/simplyscroll/ * * copyright (c) 2009-2012 will kelly - http://logicbox.net * * dual licensed under the mit and gpl licenses. * * version: 2.0.5 last revised: 10/05/2012 * */ (function($,window,undefined) { $.fn.simplyscroll = function(options) { return this.each(function() { new $.simplyscroll(this,options); }); }; var defaults = { customclass: 'simply-scroll', framerate: 24, //no of movements per second speed: 1, //no of pixels per frame orientation: 'horizontal', //'horizontal or 'vertical' - not to be confused with device orientation auto: true, automode: 'loop', //auto = true, 'loop' or 'bounce', manualmode: 'end', //auto = false, 'loop' or 'end' direction: 'forwards', //'forwards' or 'backwards'. pauseonhover: true, //automode = loop|bounce only pauseontouch: true, //" touch device only pausebutton: false, //" generates an extra element to allow manual pausing startonload: false //use this to delay starting of plugin until all page assets have loaded }; $.simplyscroll = function(el,options) { var self = this; this.o = $.extend({}, defaults, options || {}); this.isauto = this.o.auto!==false && this.o.automode.match(/^loop|bounce$/)!==null; this.ishorizontal = this.o.orientation.match(/^horizontal|vertical$/)!==null && this.o.orientation==defaults.orientation; this.isrtl = this.ishorizontal && $("html").attr('dir') == 'rtl'; this.isforwards = !this.isauto || (this.isauto && this.o.direction.match(/^forwards|backwards$/)!==null && this.o.direction==defaults.direction) && !this.isrtl; this.isloop = this.isauto && this.o.automode == 'loop' || !this.isauto && this.o.manualmode == 'loop'; this.supportstouch = ('createtouch' in document); this.events = this.supportstouch ? {start:'touchstart moztouchdown',move:'touchmove moztouchmove',end:'touchend touchcancel moztouchrelease'} : {start:'mouseenter',end:'mouseleave'}; this.$list = $(el); //called on ul/ol/div etc var $items = this.$list.children(); //generate extra markup this.$list.addclass('simply-scroll-list') .wrap('
') .parent().wrap('
'); if (!this.isauto) { //button placeholders this.$list.parent().parent() .prepend('
') .prepend('
'); } else { if (this.o.pausebutton) { this.$list.parent().parent() .prepend('
'); this.o.pauseonhover = false; } } //wrap an extra div around the whole lot if elements scrolled aren't equal if ($items.length > 1) { var extra_wrap = false, total = 0; if (this.ishorizontal) { $items.each(function() { total+=$(this).outerwidth(true); }); extra_wrap = $items.eq(0).outerwidth(true) * $items.length !== total; } else { $items.each(function() { total+=$(this).outerheight(true); }); extra_wrap = $items.eq(0).outerheight(true) * $items.length !== total; } if (extra_wrap) { this.$list = this.$list.wrap('
').parent().addclass('simply-scroll-list'); if (this.ishorizontal) { this.$list.children().css({"float":'left',width: total + 'px'}); } else { this.$list.children().css({height: total + 'px'}); } } } if (!this.o.startonload) { this.init(); } else { //wait for load before completing setup $(window).load(function() { self.init(); }); } }; $.simplyscroll.fn = $.simplyscroll.prototype = {}; $.simplyscroll.fn.extend = $.simplyscroll.extend = $.extend; $.simplyscroll.fn.extend({ init: function() { this.$items = this.$list.children(); this.$clip = this.$list.parent(); //this is the element that scrolls this.$container = this.$clip.parent(); this.$btnback = $('.simply-scroll-back',this.$container); this.$btnforward = $('.simply-scroll-forward',this.$container); if (!this.ishorizontal) { this.itemmax = this.$items.eq(0).outerheight(true); this.clipmax = this.$clip.height(); this.dimension = 'height'; this.movebackclass = 'simply-scroll-btn-up'; this.moveforwardclass = 'simply-scroll-btn-down'; this.scrollpos = 'top'; } else { this.itemmax = this.$items.eq(0).outerwidth(true); this.clipmax = this.$clip.width(); this.dimension = 'width'; this.movebackclass = 'simply-scroll-btn-left'; this.moveforwardclass = 'simply-scroll-btn-right'; this.scrollpos = 'left'; } this.posmin = 0; this.posmax = this.$items.length * this.itemmax; var additems = math.ceil(this.clipmax / this.itemmax); //auto scroll loop & manual scroll bounce or end(to-end) if (this.isauto && this.o.automode=='loop') { this.$list.css(this.dimension,this.posmax+(this.itemmax*additems) +'px'); this.posmax += (this.clipmax - this.o.speed); if (this.isforwards) { this.$items.slice(0,additems).clone(true).appendto(this.$list); this.resetposition = 0; } else { this.$items.slice(-additems).clone(true).prependto(this.$list); this.resetposition = this.$items.length * this.itemmax; //due to inconsistent rtl implementation force back to ltr then fake if (this.isrtl) { this.$clip[0].dir = 'ltr'; //based on feedback seems a good idea to force float right this.$items.css('float','right'); } } //manual and loop } else if (!this.isauto && this.o.manualmode=='loop') { this.posmax += this.itemmax * additems; this.$list.css(this.dimension,this.posmax+(this.itemmax*additems) +'px'); this.posmax += (this.clipmax - this.o.speed); var items_append = this.$items.slice(0,additems).clone(true).appendto(this.$list); var items_prepend = this.$items.slice(-additems).clone(true).prependto(this.$list); this.resetpositionforwards = this.resetposition = additems * this.itemmax; this.resetpositionbackwards = this.$items.length * this.itemmax; //extra events to force scroll direction change var self = this; this.$btnback.bind(this.events.start,function() { self.isforwards = false; self.resetposition = self.resetpositionbackwards; }); this.$btnforward.bind(this.events.start,function() { self.isforwards = true; self.resetposition = self.resetpositionforwards; }); } else { //(!this.isauto && this.o.manualmode=='end') this.$list.css(this.dimension,this.posmax +'px'); if (this.isforwards) { this.resetposition = 0; } else { this.resetposition = this.$items.length * this.itemmax; //due to inconsistent rtl implementation force back to ltr then fake if (this.isrtl) { this.$clip[0].dir = 'ltr'; //based on feedback seems a good idea to force float right this.$items.css('float','right'); } } } this.resetpos() //ensure scroll position is reset this.interval = null; this.intervaldelay = math.floor(1000 / this.o.framerate); if (!(!this.isauto && this.o.manualmode=='end')) { //loop mode //ensure that speed is divisible by item width. helps to always make images even not odd widths! while (this.itemmax % this.o.speed !== 0) { this.o.speed--; if (this.o.speed===0) { this.o.speed=1; break; } } } var self = this; this.trigger = null; this.funcmoveback = function(e) { if (e !== undefined) { e.preventdefault(); } self.trigger = !self.isauto && self.o.manualmode=='end' ? this : null; if (self.isauto) { self.isforwards ? self.moveback() : self.moveforward(); } else { self.moveback(); } }; this.funcmoveforward = function(e) { if (e !== undefined) { e.preventdefault(); } self.trigger = !self.isauto && self.o.manualmode=='end' ? this : null; if (self.isauto) { self.isforwards ? self.moveforward() : self.moveback(); } else { self.moveforward(); } }; this.funcmovepause = function() { self.movepause(); }; this.funcmovestop = function() { self.movestop(); }; this.funcmoveresume = function() { self.moveresume(); }; if (this.isauto) { this.paused = false; function togglepause() { if (self.paused===false) { self.paused=true; self.funcmovepause(); } else { self.paused=false; self.funcmoveresume(); } return self.paused; }; //disable pausetouch when links are present if (this.supportstouch && this.$items.find('a').length) { this.supportstouch=false; } if (this.isauto && this.o.pauseonhover && !this.supportstouch) { this.$clip.bind(this.events.start,this.funcmovepause).bind(this.events.end,this.funcmoveresume); } else if (this.isauto && this.o.pauseontouch && !this.o.pausebutton && this.supportstouch) { var touchstartpos, scrollstartpos; this.$clip.bind(this.events.start,function(e) { togglepause(); var touch = e.originalevent.touches[0]; touchstartpos = self.ishorizontal ? touch.pagex : touch.pagey; scrollstartpos = self.$clip[0]['scroll' + self.scrollpos]; e.stoppropagation(); e.preventdefault(); }).bind(this.events.move,function(e) { e.stoppropagation(); e.preventdefault(); var touch = e.originalevent.touches[0], endtouchpos = self.ishorizontal ? touch.pagex : touch.pagey, pos = (touchstartpos - endtouchpos) + scrollstartpos; if (pos < 0) pos = 0; else if (pos > self.posmax) pos = self.posmax; self.$clip[0]['scroll' + self.scrollpos] = pos; //force pause self.funcmovepause(); self.paused = true; }); } else { if (this.o.pausebutton) { this.$btnpause = $(".simply-scroll-btn-pause",this.$container) .bind('click',function(e) { e.preventdefault(); togglepause() ? $(this).addclass('active') : $(this).removeclass('active'); }); } } this.funcmoveforward(); } else { this.$btnback .addclass('simply-scroll-btn' + ' ' + this.movebackclass) .bind(this.events.start,this.funcmoveback).bind(this.events.end,this.funcmovestop); this.$btnforward .addclass('simply-scroll-btn' + ' ' + this.moveforwardclass) .bind(this.events.start,this.funcmoveforward).bind(this.events.end,this.funcmovestop); if (this.o.manualmode == 'end') { !this.isrtl ? this.$btnback.addclass('disabled') : this.$btnforward.addclass('disabled'); } } }, moveforward: function() { var self = this; this.movement = 'forward'; if (this.trigger !== null) { this.$btnback.removeclass('disabled'); } self.interval = setinterval(function() { if (self.$clip[0]['scroll' + self.scrollpos] < (self.posmax-self.clipmax)) { self.$clip[0]['scroll' + self.scrollpos] += self.o.speed; } else if (self.isloop) { self.resetpos(); } else { self.movestop(self.movement); } },self.intervaldelay); }, moveback: function() { var self = this; this.movement = 'back'; if (this.trigger !== null) { this.$btnforward.removeclass('disabled'); } self.interval = setinterval(function() { if (self.$clip[0]['scroll' + self.scrollpos] > self.posmin) { self.$clip[0]['scroll' + self.scrollpos] -= self.o.speed; } else if (self.isloop) { self.resetpos(); } else { self.movestop(self.movement); } },self.intervaldelay); }, movepause: function() { clearinterval(this.interval); }, movestop: function(movedir) { this.movepause(); if (this.trigger!==null) { if (typeof movedir !== 'undefined') { $(this.trigger).addclass('disabled'); } this.trigger = null; } if (this.isauto) { if (this.o.automode=='bounce') { movedir == 'forward' ? this.moveback() : this.moveforward(); } } }, moveresume: function() { this.movement=='forward' ? this.moveforward() : this.moveback(); }, resetpos: function() { this.$clip[0]['scroll' + this.scrollpos] = this.resetposition; } }); })(jquery,window);