|
17 | 17 | $.tools.scrollable = { |
18 | 18 |
|
19 | 19 | conf: { |
| 20 | + transition: 'scroll', |
20 | 21 | activeClass: 'active', |
21 | 22 | circular: false, |
22 | 23 | clonedClass: 'cloned', |
|
53 | 54 |
|
54 | 55 | // constructor |
55 | 56 | function Scrollable(root, conf) { |
56 | | - |
57 | 57 | // current instance |
58 | 58 | var self = this, |
59 | 59 | fire = root.add(self), |
60 | 60 | itemWrap = root.children(), |
61 | 61 | index = 0, |
62 | | - vertical = conf.vertical; |
| 62 | + vertical = conf.vertical, |
| 63 | + lastActiveItem = null; |
63 | 64 |
|
64 | 65 | if (!current) { current = self; } |
65 | 66 | if (itemWrap.length > 1) { itemWrap = $(conf.items, root); } |
66 | | - |
| 67 | + |
67 | 68 | // methods |
68 | 69 | $.extend(self, { |
69 | 70 |
|
|
94 | 95 | getItems: function() { |
95 | 96 | return itemWrap.find(conf.item).not("." + conf.clonedClass); |
96 | 97 | }, |
| 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 | + }, |
97 | 113 |
|
98 | 114 | move: function(offset, time) { |
99 | | - return self.seekTo(index + offset, time); |
| 115 | + return self.seekTo(self.getCorrectedIndex(index + offset), time); |
100 | 116 | }, |
101 | 117 |
|
102 | 118 | next: function(time) { |
|
137 | 153 |
|
138 | 154 | /* all seeking functions depend on this */ |
139 | 155 | seekTo: function(i, time, fn) { |
| 156 | + //console.debug("------------------------------------------------\nseekTo(", i, ")"); |
140 | 157 |
|
141 | 158 | // ensure numeric index |
142 | 159 | if (!i.jquery) { i *= 1; } |
143 | 160 |
|
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 | + } |
146 | 165 |
|
147 | 166 | // check that index is sane |
148 | 167 | if (!conf.circular && i < 0 || i > self.getSize() || i < -1) { return self; } |
149 | | - |
| 168 | + |
150 | 169 | var item = i; |
151 | 170 |
|
152 | 171 | if (i.jquery) { |
153 | | - i = self.getItems().index(i); |
154 | | - |
| 172 | + i = self.getItems().index(i); |
155 | 173 | } else { |
156 | 174 | item = self.getItems().eq(i); |
157 | 175 | } |
|
162 | 180 | fire.trigger(e, [i, time]); |
163 | 181 | if (e.isDefaultPrevented() || !item.length) { return self; } |
164 | 182 | } |
165 | | - |
166 | | - var props = vertical ? {top: -item.position().top} : {left: -item.position().left}; |
167 | | - |
| 183 | + |
168 | 184 | index = i; |
169 | 185 | current = self; |
170 | 186 | 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; |
176 | 205 | return self; |
177 | 206 | } |
178 | 207 |
|
|
191 | 220 | return self; |
192 | 221 | }; |
193 | 222 | }); |
| 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 | + |
194 | 234 |
|
195 | 235 | // circular loop |
196 | 236 | 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); |
204 | 250 |
|
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; } |
217 | 253 |
|
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 | + } |
225 | 274 |
|
226 | 275 | // seek over the cloned item |
227 | | - self.seekTo(0, 0, function() {}); |
| 276 | + self.seekTo(conf.initialIndex, 0, function() {}); |
228 | 277 | } |
229 | 278 |
|
230 | 279 | // next/prev buttons |
|
315 | 364 |
|
316 | 365 | // jQuery plugin implementation |
317 | 366 | $.fn.scrollable = function(conf) { |
318 | | - |
319 | 367 | // already constructed --> return API |
320 | 368 | var el = this.data("scrollable"); |
321 | 369 | if (el) { return el; } |
|
328 | 376 | }); |
329 | 377 |
|
330 | 378 | return conf.api ? el: this; |
331 | | - |
332 | 379 | }; |
333 | 380 |
|
334 | 381 |
|
|
0 commit comments