diff options
Diffstat (limited to 'public/marquee.js')
-rw-r--r-- | public/marquee.js | 155 |
1 files changed, 155 insertions, 0 deletions
diff --git a/public/marquee.js b/public/marquee.js new file mode 100644 index 0000000..9e046d5 --- /dev/null +++ b/public/marquee.js @@ -0,0 +1,155 @@ +/** +* 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('<div ' + (klass ? 'class="' + klass + '" ' : '') + 'style="display: block-inline; width: ' + width + 'px; height: ' + height + 'px; overflow: hidden;"><div style="float: left; white-space: nowrap;">' + $marquee.html() + '</div></div>').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));
\ No newline at end of file |