MediaWiki:JQuery.Marquee.js

/**
 * author Remy Sharp
 * url http://remysharp.com/tag/marquee

(function ($) {   $.fn.marquee = function (klass) {        var newMarquee = [],            last = this.length;

// works out the left or right hand reset position, based on scroll // behavior, current direction and new direction function getReset(newDir, marqueeRedux, marqueeState) { var behavior = marqueeState.behavior, width = marqueeState.width, dir = marqueeState.dir; var r = 0; if (behavior == 'alternate') { r = newDir == 1 ? marqueeRedux[marqueeState.widthAxis] - (width*2) : width; } else if (behavior == 'slide') { if (newDir == -1) { r = dir == -1 ? marqueeRedux[marqueeState.widthAxis] : width; } else { r = dir == -1 ? marqueeRedux[marqueeState.widthAxis] - (width*2) : 0; }           } else { r = newDir == -1 ? marqueeRedux[marqueeState.widthAxis] : 0; }           return r;        }

// single "thread" animation function animateMarquee { var i = newMarquee.length, marqueeRedux = null, $marqueeRedux = null, marqueeState = {}, newMarqueeList = [], hitedge = false; while (i--) { marqueeRedux = newMarquee[i]; $marqueeRedux = $(marqueeRedux); marqueeState = $marqueeRedux.data('marqueeState'); if ($marqueeRedux.data('paused') !== true) { // TODO read scrollamount, dir, behavior, loops and last from data marqueeRedux[marqueeState.axis] += (marqueeState.scrollamount * marqueeState.dir);

// only true if it's hit the end hitedge = marqueeState.dir == -1 ? marqueeRedux[marqueeState.axis] <= getReset(marqueeState.dir * -1, marqueeRedux, marqueeState) : marqueeRedux[marqueeState.axis] >= getReset(marqueeState.dir * -1, marqueeRedux, marqueeState); if ((marqueeState.behavior == 'scroll' && marqueeState.last == marqueeRedux[marqueeState.axis]) || (marqueeState.behavior == 'alternate' && hitedge && marqueeState.last != -1) || (marqueeState.behavior == 'slide' && hitedge && marqueeState.last != -1)) { if (marqueeState.behavior == 'alternate') { marqueeState.dir *= -1; // flip }                       marqueeState.last = -1;

$marqueeRedux.trigger('stop');

marqueeState.loops--; if (marqueeState.loops === 0) { if (marqueeState.behavior != 'slide') { marqueeRedux[marqueeState.axis] = getReset(marqueeState.dir, marqueeRedux, marqueeState); } else { // corrects the position marqueeRedux[marqueeState.axis] = getReset(marqueeState.dir * -1, marqueeRedux, marqueeState); }

$marqueeRedux.trigger('end'); } else { // keep this marquee going newMarqueeList.push(marqueeRedux); $marqueeRedux.trigger('start'); marqueeRedux[marqueeState.axis] = getReset(marqueeState.dir, marqueeRedux, marqueeState); }                   } else { newMarqueeList.push(marqueeRedux); }                   marqueeState.last = marqueeRedux[marqueeState.axis];

// store updated state only if we ran an animation $marqueeRedux.data('marqueeState', marqueeState); } else { // even though it's paused, keep it in the list newMarqueeList.push(marqueeRedux); }           }

newMarquee = newMarqueeList; if (newMarquee.length) { setTimeout(animateMarquee, 25); }                   }        // TODO consider whether using .html in the wrapping process could lead to loosing predefined events... this.each(function (i) {           var $marquee = $(this),                width = $marquee.attr('width') || $marquee.width,                height = $marquee.attr('height') || $marquee.height,                $marqueeRedux = $marquee.after(' ' + $marquee.html + '  ').next,                marqueeRedux = $marqueeRedux.get(0),                hitedge = 0,                direction = ($marquee.attr('direction') || 'left').toLowerCase,                marqueeState = {                    dir : /down|right/.test(direction) ? -1 : 1,                    axis : /left|right/.test(direction) ? 'scrollLeft' : 'scrollTop',                    widthAxis : /left|right/.test(direction) ? 'scrollWidth' : 'scrollHeight',                    last : -1, loops : $marquee.attr('loop') || -1, scrollamount : $marquee.attr('scrollamount') || this.scrollAmount || 2, behavior : ($marquee.attr('behavior') || 'scroll').toLowerCase, width : /left|right/.test(direction) ? width : height };           // corrects a bug in Firefox - the default loops for slide is -1 if ($marquee.attr('loop') == -1 && marqueeState.behavior == 'slide') { marqueeState.loops = 1; }

$marquee.remove; // add padding if (/left|right/.test(direction)) { $marqueeRedux.find('> div').css('padding', '0 ' + width + 'px'); } else { $marqueeRedux.find('> div').css('padding', height + 'px 0'); }           // events $marqueeRedux.bind('stop', function {                $marqueeRedux.data('paused', true);            }).bind('pause', function  {                $marqueeRedux.data('paused', true);            }).bind('start', function  {                $marqueeRedux.data('paused', false);            }).bind('unpause', function  {                $marqueeRedux.data('paused', false);            }).data('marqueeState', marqueeState); // finally: store the state // todo - rerender event allowing us to do an ajax hit and redraw the marquee

newMarquee.push(marqueeRedux);

marqueeRedux[marqueeState.axis] = getReset(marqueeState.dir, marqueeRedux, marqueeState); $marqueeRedux.trigger('start'); // on the very last marquee, trigger the animation if (i+1 == last) { animateMarquee; }       });

return $(newMarquee); }; }(jQuery));