forked from ganeshmax/jcarousellite
-
Notifications
You must be signed in to change notification settings - Fork 0
/
jquery.jcarousellite.js
281 lines (229 loc) · 12.2 KB
/
jquery.jcarousellite.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
/*!
* jCarouselLite - v1.1 - 2014-09-28
* http://www.gmarwaha.com/jquery/jcarousellite/
* Copyright (c) 2014 Ganeshji Marwaha
* Licensed MIT (https://github.com/ganeshmax/jcarousellite/blob/master/LICENSE)
*/
(function($) { // Compliant with jquery.noConflict()
$.jCarouselLite = {
version: '1.1'
};
$.fn.jCarouselLite = function(options) {
options = $.extend({}, $.fn.jCarouselLite.options, options || {});
return this.each(function() { // Returns the element collection. Chainable.
var running,
animCss, sizeCss,
div = $(this), ul, initialLi, li,
liSize, ulSize, divSize,
numVisible, initialItemLength, itemLength, calculatedTo, autoTimeout;
initVariables(); // Set the above variables after initial calculations
initStyles(); // Set the appropriate styles for the carousel div, ul and li
initSizes(); // Set appropriate sizes for the carousel div, ul and li
attachEventHandlers(); // Attach event handlers for carousel to respond
function go(to) {
if(!running) {
clearTimeout(autoTimeout); // Prevents multiple clicks while auto-scrolling - edge case
calculatedTo = to;
if(options.beforeStart) { // Call the beforeStart() callback
options.beforeStart.call(this, visibleItems());
}
if(options.circular) { // If circular, and "to" is going OOB, adjust it
adjustOobForCircular(to);
} else { // If non-circular and "to" is going OOB, adjust it.
adjustOobForNonCircular(to);
} // If neither overrides "calculatedTo", we are not in edge cases.
animateToPosition({ // Animate carousel item to position based on calculated values.
start: function() {
running = true;
},
done: function() {
if(options.afterEnd) {
options.afterEnd.call(this, visibleItems());
}
if(options.auto) {
setupAutoScroll();
}
running = false;
}
});
if(!options.circular) { // Enabling / Disabling buttons is applicable in non-circular mode only.
disableOrEnableButtons();
}
}
return false;
}
function initVariables() {
running = false;
animCss = options.vertical ? "top" : "left";
sizeCss = options.vertical ? "height" : "width";
ul = div.find(">ul");
initialLi = ul.find(">li");
initialItemLength = initialLi.size();
// To avoid a scenario where number of items is just 1 and visible is 3 for example.
numVisible = initialItemLength < options.visible ? initialItemLength : options.visible;
if(options.circular) {
var $lastItemSet = initialLi.slice(initialItemLength-numVisible).clone();
var $firstItemSet = initialLi.slice(0,numVisible).clone();
ul.prepend($lastItemSet) // Prepend the lis with final items so that the user can click the back button to start with
.append($firstItemSet); // Append the lis with first items so that the user can click the next button even after reaching the end
options.start += numVisible; // Since we have a few artificial lis in the front, we will have to move the pointer to point to the real first item
}
li = $("li", ul);
itemLength = li.size();
calculatedTo = options.start;
}
function initStyles() {
div.css("visibility", "visible"); // If the div was set to hidden in CSS, make it visible now
li.css({
overflow: "hidden",
"float": options.vertical ? "none" : "left" // Some minification tools fail if "" is not used
});
ul.css({
margin: "0",
padding: "0",
position: "relative",
"list-style": "none",
"z-index": "1"
});
div.css({
overflow: "hidden",
position: "relative",
"z-index": "2",
left: "0px"
});
// For a non-circular carousel, if the start is 0 and btnPrev is supplied, disable the prev button
if(!options.circular && options.btnPrev && options.start == 0) {
$(options.btnPrev).addClass("disabled");
}
}
function initSizes() {
liSize = options.vertical ? // Full li size(incl margin)-Used for animation and to set ulSize
li.outerHeight(true) :
li.outerWidth(true);
ulSize = liSize * itemLength; // size of full ul(total length, not just for the visible items)
divSize = liSize * numVisible; // size of entire div(total length for just the visible items)
// Generally, LI's dimensions should be specified explicitly in a style-sheet
// But in the case of img (with width and height attr), we can derive LI's dimensions and set here
// May be applicable for other types of LI children if their dimensions are explicitly specified
// Individual LI dimensions
li.css({
width: li.width(),
height: li.height()
});
// Size of the entire UL. Including hidden and visible elements
// Will include LI's (width + padding + border + margin) * itemLength - Using outerwidth(true)
ul.css(sizeCss, ulSize+"px")
.css(animCss, -(calculatedTo * liSize));
// Width of the DIV. Only the width of the visible elements
// Will include LI's (width + padding + border + margin) * numVisible - Using outerwidth(true)
div.css(sizeCss, divSize+"px");
}
function attachEventHandlers() {
if(options.btnPrev) {
$(options.btnPrev).click(function() {
return go(calculatedTo - options.scroll);
});
}
if(options.btnNext) {
$(options.btnNext).click(function() {
return go(calculatedTo + options.scroll);
});
}
if(options.btnGo) {
$.each(options.btnGo, function(i, val) {
$(val).click(function() {
return go(options.circular ? numVisible + i : i);
});
});
}
if(options.mouseWheel && div.mousewheel) {
div.mousewheel(function(e, d) {
return d > 0 ?
go(calculatedTo - options.scroll) :
go(calculatedTo + options.scroll);
});
}
if(options.auto) {
setupAutoScroll();
}
}
function setupAutoScroll() {
autoTimeout = setTimeout(function() {
go(calculatedTo + options.scroll);
}, options.auto);
}
function visibleItems() {
return li.slice(calculatedTo).slice(0,numVisible);
}
function adjustOobForCircular(to) {
var newPosition;
// If first, then goto last
if(to <= options.start - numVisible - 1) {
newPosition = to + initialItemLength + options.scroll;
ul.css(animCss, -(newPosition * liSize) + "px");
calculatedTo = newPosition - options.scroll;
console.log("Before - Positioned at: " + newPosition + " and Moving to: " + calculatedTo);
}
// If last, then goto first
else if(to >= itemLength - numVisible + 1) {
newPosition = to - initialItemLength - options.scroll;
ul.css(animCss, -(newPosition * liSize) + "px");
calculatedTo = newPosition + options.scroll;
console.log("After - Positioned at: " + newPosition + " and Moving to: " + calculatedTo);
}
}
function adjustOobForNonCircular(to) {
// If user clicks "prev" and tries to go before the first element, reset it to first element.
if(to < 0) {
calculatedTo = 0;
}
// If "to" is greater than the max index that we can use to show another set of elements
// it means that we will have to reset "to" to a smallest possible index that can show it
else if(to > itemLength - numVisible) {
calculatedTo = itemLength - numVisible;
}
console.log("Item Length: " + itemLength + "; " +
"To: " + to + "; " +
"CalculatedTo: " + calculatedTo + "; " +
"Num Visible: " + numVisible);
}
function disableOrEnableButtons() {
$(options.btnPrev + "," + options.btnNext).removeClass("disabled");
$( (calculatedTo-options.scroll<0 && options.btnPrev)
||
(calculatedTo+options.scroll > itemLength-numVisible && options.btnNext)
||
[]
).addClass("disabled");
}
function animateToPosition(animationOptions) {
running = true;
ul.animate(
animCss == "left" ?
{ left: -(calculatedTo*liSize) } :
{ top: -(calculatedTo*liSize) },
$.extend({
duration: options.speed,
easing: options.easing
}, animationOptions)
);
}
});
};
$.fn.jCarouselLite.options = {
btnPrev: null, // CSS Selector for the previous button
btnNext: null, // CSS Selector for the next button
btnGo: null, // CSS Selector for the go button
mouseWheel: false, // Set "true" if you want the carousel scrolled using mouse wheel
auto: null, // Set to a numeric value (800) in millis. Time period between auto scrolls
speed: 200, // Set to a numeric value in millis. Speed of scroll
easing: null, // Set to easing (bounceout) to specify the animation easing
vertical: false, // Set to "true" to make the carousel scroll vertically
circular: true, // Set to "true" to make it an infinite carousel
visible: 3, // Set to a numeric value to specify the number of visible elements at a time
start: 0, // Set to a numeric value to specify which item to start from
scroll: 1, // Set to a numeric value to specify how many items to scroll for one scroll event
beforeStart: null, // Set to a function to receive a callback before every scroll start
afterEnd: null // Set to a function to receive a callback after every scroll end
};
})(jQuery);