Skip to content

Commit 7b11deb

Browse files
author
Tyler Rick
committed
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).
1 parent d65b237 commit 7b11deb

File tree

1 file changed

+93
-46
lines changed

1 file changed

+93
-46
lines changed

src/scrollable/scrollable.js

Lines changed: 93 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
$.tools.scrollable = {
1818

1919
conf: {
20+
transition: 'scroll',
2021
activeClass: 'active',
2122
circular: false,
2223
clonedClass: 'cloned',
@@ -53,17 +54,17 @@
5354

5455
// constructor
5556
function Scrollable(root, conf) {
56-
5757
// current instance
5858
var self = this,
5959
fire = root.add(self),
6060
itemWrap = root.children(),
6161
index = 0,
62-
vertical = conf.vertical;
62+
vertical = conf.vertical,
63+
lastActiveItem = null;
6364

6465
if (!current) { current = self; }
6566
if (itemWrap.length > 1) { itemWrap = $(conf.items, root); }
66-
67+
6768
// methods
6869
$.extend(self, {
6970

@@ -94,9 +95,24 @@
9495
getItems: function() {
9596
return itemWrap.find(conf.item).not("." + conf.clonedClass);
9697
},
98+
99+
// Adjusts the given index for circular loops (if circular is enabled).
100+
// We only need to adjust the index if circular is enabled and the transition is 'fade'.
101+
// 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.
102+
getCorrectedIndex: function(i) {
103+
if (conf.circular && conf.transition == 'fade') {
104+
if (i < 0) {
105+
return self.getSize() - 1;
106+
} else if (i >= self.getSize()) {
107+
return 0;
108+
}
109+
} else {
110+
}
111+
return i;
112+
},
97113

98114
move: function(offset, time) {
99-
return self.seekTo(index + offset, time);
115+
return self.seekTo(self.getCorrectedIndex(index + offset), time);
100116
},
101117

102118
next: function(time) {
@@ -137,21 +153,23 @@
137153

138154
/* all seeking functions depend on this */
139155
seekTo: function(i, time, fn) {
156+
//console.debug("------------------------------------------------\nseekTo(", i, ")");
140157

141158
// ensure numeric index
142159
if (!i.jquery) { i *= 1; }
143160

144-
// avoid seeking from end clone to the beginning
145-
if (conf.circular && i === 0 && index == -1 && time !== 0) { return self; }
161+
if (conf.transition == 'scroll') {
162+
// avoid seeking from end clone to the beginning
163+
if (conf.circular && i === 0 && index == -1 && time !== 0) { return self; }
164+
}
146165

147166
// check that index is sane
148167
if (!conf.circular && i < 0 || i > self.getSize() || i < -1) { return self; }
149-
168+
150169
var item = i;
151170

152171
if (i.jquery) {
153-
i = self.getItems().index(i);
154-
172+
i = self.getItems().index(i);
155173
} else {
156174
item = self.getItems().eq(i);
157175
}
@@ -162,17 +180,28 @@
162180
fire.trigger(e, [i, time]);
163181
if (e.isDefaultPrevented() || !item.length) { return self; }
164182
}
165-
166-
var props = vertical ? {top: -item.position().top} : {left: -item.position().left};
167-
183+
168184
index = i;
169185
current = self;
170186
if (time === undefined) { time = conf.speed; }
171-
172-
itemWrap.animate(props, time, conf.easing, fn || function() {
173-
fire.trigger("onSeek", [i]);
174-
});
175-
187+
188+
if (conf.transition == 'scroll') {
189+
var props = vertical ? {top: -item.position().top} : {left: -item.position().left};
190+
191+
itemWrap.animate(props, time, conf.easing, fn || function() {
192+
fire.trigger("onSeek", [i]);
193+
});
194+
195+
} else if (conf.transition == 'fade') {
196+
// Note: passing in easing is only possible in jQuery >= 1.4.3
197+
if (lastActiveItem)
198+
lastActiveItem.fadeOut(time, conf.easing);
199+
item. fadeIn(time, conf.easing, fn || function() {
200+
fire.trigger("onSeek", [i]);
201+
});
202+
}
203+
204+
lastActiveItem = item;
176205
return self;
177206
}
178207

@@ -191,40 +220,60 @@
191220
return self;
192221
};
193222
});
223+
224+
if (conf.transition == 'fade') {
225+
self.getItems().each(function(i) {
226+
var item = $(this);
227+
item.css('z-index', String(self.getSize()-i)).
228+
css('position', 'absolute').
229+
hide();
230+
231+
});
232+
}
233+
194234

195235
// circular loop
196236
if (conf.circular) {
197-
198-
var cloned1 = self.getItems().slice(-1).clone().prependTo(itemWrap),
199-
cloned2 = self.getItems().eq(1).clone().appendTo(itemWrap);
200-
201-
cloned1.add(cloned2).addClass(conf.clonedClass);
202-
203-
self.onBeforeSeek(function(e, i, time) {
237+
if (conf.transition == 'fade') {
238+
self.onBeforeSeek(function(e, i, time) {
239+
if (i == self.getSize()) {
240+
self.seekTo(self.getCorrectedIndex(i+1), time, function() {
241+
self.begin(0);
242+
});
243+
}
244+
});
245+
} else {
246+
var clonedAtBegin = self.getItems().slice(-1).clone().prependTo(itemWrap);
247+
var clonedAtEnd = self.getItems().eq(1).clone().appendTo(itemWrap);
248+
249+
clonedAtBegin.add(clonedAtEnd).addClass(conf.clonedClass);
204250

205-
206-
if (e.isDefaultPrevented()) { return; }
207-
208-
/*
209-
1. animate to the clone without event triggering
210-
2. seek to correct position with 0 speed
211-
*/
212-
if (i == -1) {
213-
self.seekTo(cloned1, time, function() {
214-
self.end(0);
215-
});
216-
return e.preventDefault();
251+
self.onBeforeSeek(function(e, i, time) {
252+
if (e.isDefaultPrevented()) { return; }
217253

218-
} else if (i == self.getSize()) {
219-
self.seekTo(cloned2, time, function() {
220-
self.begin(0);
221-
});
222-
}
223-
224-
});
254+
/*
255+
1. animate to the clone without event triggering
256+
2. when animation finishes, immediately seek to correct position with 0 speed (no visible transition)
257+
*/
258+
if (i == -1) {
259+
// Head to the cloned element on the left, then seek immediately to the end
260+
self.seekTo(clonedAtBegin, time, function() {
261+
self.end(0);
262+
});
263+
return e.preventDefault();
264+
265+
} else if (i == self.getSize()) {
266+
// Head to the cloned element on the right, then seek immediately to the beginning
267+
self.seekTo(clonedAtEnd, time, function() {
268+
self.begin(0);
269+
});
270+
}
271+
272+
});
273+
}
225274

226275
// seek over the cloned item
227-
self.seekTo(0, 0, function() {});
276+
self.seekTo(conf.initialIndex, 0, function() {});
228277
}
229278

230279
// next/prev buttons
@@ -315,7 +364,6 @@
315364

316365
// jQuery plugin implementation
317366
$.fn.scrollable = function(conf) {
318-
319367
// already constructed --> return API
320368
var el = this.data("scrollable");
321369
if (el) { return el; }
@@ -328,7 +376,6 @@
328376
});
329377

330378
return conf.api ? el: this;
331-
332379
};
333380

334381

0 commit comments

Comments
 (0)