From 7b11deb0213a7901b5b558a747a8da872b6286d6 Mon Sep 17 00:00:00 2001 From: Tyler Rick Date: Fri, 25 Mar 2011 14:21:25 -0700 Subject: [PATCH] Added a transition option (default 'scroll') and a new 'fade' transition. When transition: 'fade' is passed in, the Scrollable plugin will cross-fade from one slide to the next (animating the opacity) instead of scrolling from one slide to the next (animating the position). --- src/scrollable/scrollable.js | 139 +++++++++++++++++++++++------------ 1 file changed, 93 insertions(+), 46 deletions(-) diff --git a/src/scrollable/scrollable.js b/src/scrollable/scrollable.js index a297f47..f9823c0 100644 --- a/src/scrollable/scrollable.js +++ b/src/scrollable/scrollable.js @@ -17,6 +17,7 @@ $.tools.scrollable = { conf: { + transition: 'scroll', activeClass: 'active', circular: false, clonedClass: 'cloned', @@ -53,17 +54,17 @@ // constructor function Scrollable(root, conf) { - // current instance var self = this, fire = root.add(self), itemWrap = root.children(), index = 0, - vertical = conf.vertical; + vertical = conf.vertical, + lastActiveItem = null; if (!current) { current = self; } if (itemWrap.length > 1) { itemWrap = $(conf.items, root); } - + // methods $.extend(self, { @@ -94,9 +95,24 @@ getItems: function() { return itemWrap.find(conf.item).not("." + conf.clonedClass); }, + + // Adjusts the given index for circular loops (if circular is enabled). + // We only need to adjust the index if circular is enabled and the transition is 'fade'. + // When the transition is 'scroll', we don't want to adjust the index because we actually want to go *beyond* the last index to the cloned slide just beyond. Then it adjusts it to the true index in the onBeforeSeek callback. + getCorrectedIndex: function(i) { + if (conf.circular && conf.transition == 'fade') { + if (i < 0) { + return self.getSize() - 1; + } else if (i >= self.getSize()) { + return 0; + } + } else { + } + return i; + }, move: function(offset, time) { - return self.seekTo(index + offset, time); + return self.seekTo(self.getCorrectedIndex(index + offset), time); }, next: function(time) { @@ -137,21 +153,23 @@ /* all seeking functions depend on this */ seekTo: function(i, time, fn) { + //console.debug("------------------------------------------------\nseekTo(", i, ")"); // ensure numeric index if (!i.jquery) { i *= 1; } - // avoid seeking from end clone to the beginning - if (conf.circular && i === 0 && index == -1 && time !== 0) { return self; } + if (conf.transition == 'scroll') { + // avoid seeking from end clone to the beginning + if (conf.circular && i === 0 && index == -1 && time !== 0) { return self; } + } // check that index is sane if (!conf.circular && i < 0 || i > self.getSize() || i < -1) { return self; } - + var item = i; if (i.jquery) { - i = self.getItems().index(i); - + i = self.getItems().index(i); } else { item = self.getItems().eq(i); } @@ -162,17 +180,28 @@ fire.trigger(e, [i, time]); if (e.isDefaultPrevented() || !item.length) { return self; } } - - var props = vertical ? {top: -item.position().top} : {left: -item.position().left}; - + index = i; current = self; if (time === undefined) { time = conf.speed; } - - itemWrap.animate(props, time, conf.easing, fn || function() { - fire.trigger("onSeek", [i]); - }); - + + if (conf.transition == 'scroll') { + var props = vertical ? {top: -item.position().top} : {left: -item.position().left}; + + itemWrap.animate(props, time, conf.easing, fn || function() { + fire.trigger("onSeek", [i]); + }); + + } else if (conf.transition == 'fade') { + // Note: passing in easing is only possible in jQuery >= 1.4.3 + if (lastActiveItem) + lastActiveItem.fadeOut(time, conf.easing); + item. fadeIn(time, conf.easing, fn || function() { + fire.trigger("onSeek", [i]); + }); + } + + lastActiveItem = item; return self; } @@ -191,40 +220,60 @@ return self; }; }); + + if (conf.transition == 'fade') { + self.getItems().each(function(i) { + var item = $(this); + item.css('z-index', String(self.getSize()-i)). + css('position', 'absolute'). + hide(); + + }); + } + // circular loop if (conf.circular) { - - var cloned1 = self.getItems().slice(-1).clone().prependTo(itemWrap), - cloned2 = self.getItems().eq(1).clone().appendTo(itemWrap); - - cloned1.add(cloned2).addClass(conf.clonedClass); - - self.onBeforeSeek(function(e, i, time) { + if (conf.transition == 'fade') { + self.onBeforeSeek(function(e, i, time) { + if (i == self.getSize()) { + self.seekTo(self.getCorrectedIndex(i+1), time, function() { + self.begin(0); + }); + } + }); + } else { + var clonedAtBegin = self.getItems().slice(-1).clone().prependTo(itemWrap); + var clonedAtEnd = self.getItems().eq(1).clone().appendTo(itemWrap); + + clonedAtBegin.add(clonedAtEnd).addClass(conf.clonedClass); - - if (e.isDefaultPrevented()) { return; } - - /* - 1. animate to the clone without event triggering - 2. seek to correct position with 0 speed - */ - if (i == -1) { - self.seekTo(cloned1, time, function() { - self.end(0); - }); - return e.preventDefault(); + self.onBeforeSeek(function(e, i, time) { + if (e.isDefaultPrevented()) { return; } - } else if (i == self.getSize()) { - self.seekTo(cloned2, time, function() { - self.begin(0); - }); - } - - }); + /* + 1. animate to the clone without event triggering + 2. when animation finishes, immediately seek to correct position with 0 speed (no visible transition) + */ + if (i == -1) { + // Head to the cloned element on the left, then seek immediately to the end + self.seekTo(clonedAtBegin, time, function() { + self.end(0); + }); + return e.preventDefault(); + + } else if (i == self.getSize()) { + // Head to the cloned element on the right, then seek immediately to the beginning + self.seekTo(clonedAtEnd, time, function() { + self.begin(0); + }); + } + + }); + } // seek over the cloned item - self.seekTo(0, 0, function() {}); + self.seekTo(conf.initialIndex, 0, function() {}); } // next/prev buttons @@ -315,7 +364,6 @@ // jQuery plugin implementation $.fn.scrollable = function(conf) { - // already constructed --> return API var el = this.data("scrollable"); if (el) { return el; } @@ -328,7 +376,6 @@ }); return conf.api ? el: this; - };