Skip to content

Instantly share code, notes, and snippets.

@ginlime
Created January 9, 2015 01:49
Show Gist options
  • Save ginlime/1c3899aea48ca29cc80f to your computer and use it in GitHub Desktop.
Save ginlime/1c3899aea48ca29cc80f to your computer and use it in GitHub Desktop.
jQuery UI widget version of jCarouselLite
/*!
* jQuery UI jCarouselLite
*
* Copyright 2015, Startia Lab
* Dual licensed under the MIT or GPL Version 2 licenses.
* http://jquery.org/license
*
* Ported from jCarouselLite v1.1 to UI widget
* http://www.gmarwaha.com/jquery/jcarousellite/
*
* Depends:
* jquery.ui.core.js
* jquery.ui.widget.js
*/
(function($) {
var nameSpaceCnt = 0,
elemBaseCSSProp = ['visibility','overflow','position','z-index','left'],
ulBaseCSSProp = ['margin','padding','position','list-style','z-index'],
liBaseCSSProp = ['overflow','float','width','height'];
$.widget('ui.jCarouselLite', {
version: '1.0.0',
options: {
disableClass: 'disabled', // Class Selector which prevents button action
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
},
isRunning: false,
animCss: 'left',
sizeCss: 'width',
initialItemLength: 0,
numVisible: 0,
li: null,
calculatedTo: 0,
itemLength: 0,
liSize: 0,
nameSpace: '',
autoTimeout: null,
elemCss: {},
ulCss: {},
liCss: {},
_create: function(){
var self = this,
options = self.options,
elem = self.element,
ul = elem.find('>ul');
self.nameSpace = 'jCarouselLite' + nameSpaceCnt;
nameSpaceCnt++;
/* initVariables */
if(options.vertical) {
self.animCss = 'top';
self.sizeCss = 'height';
}
if(ul.length == 0){
return false; /* Not valid */
}
var _initialLI = ul.find('>li');
self.initialItemLength = _initialLI.length;
self.numVisible = self.initialItemLength < options.visible ? self.initialItemLength : options.visible;
if(options.circular) {
var $lastItemSet = _initialLI.slice(self.initialItemLength-self.numVisible).clone();
var $firstItemSet = _initialLI.slice(0,self.numVisible).clone();
_initialLI.each(function(){
$(this).attr('data-default','1')
});
ul.prepend($lastItemSet)
.append($firstItemSet);
options.start += self.numVisible;
}
self.li = $('li', ul);
self.itemLength = self.li.length;
self.calculatedTo = options.start;
/* initStyles */
var _elemCSSLen = elemBaseCSSProp.length;
self.elemCss[self.sizeCss] = elem.css(self.sizeCss);
for(var i = 0; i < _elemCSSLen; i++){
self.elemCss[elemBaseCSSProp[i]] = elem.css(elemBaseCSSProp[i]);
}
elem.css('visibility', 'visible');
var _ulCSSLen = ulBaseCSSProp.length;
self.ulCss[self.sizeCss] = ul.css(self.sizeCss);
self.ulCss[self.animCss] = ul.css(self.animCss);
for(var i = 0; i < _ulCSSLen; i++){
self.ulCss[ulBaseCSSProp[i]] = ul.css(ulBaseCSSProp[i]);
}
var _liCSSLen = liBaseCSSProp.length;
self.liCss[self.sizeCss] = self.li.css(self.sizeCss);
self.liCss[self.animCss] = self.li.css(self.animCss);
for(var i = 0; i < _liCSSLen; i++){
self.liCss[liBaseCSSProp[i]] = self.li.css(liBaseCSSProp[i]);
}
self.li.css({
'overflow':'hidden',
'float':options.vertical ? 'none':'left'
});
ul.css({
'margin':'0',
'padding':'0',
'position':'relative',
'list-style':'none',
'z-index':'1'
});
elem.css({
'overflow':'hidden',
'position':'relative',
'z-index':'2',
'left':'0px'
});
if(!options.circular && options.btnPrev && options.start == 0) {
$(options.btnPrev).addClass('disabled');
}
/* initSizes */
self.liSize = options.vertical ? self.li.outerHeight(true) : self.li.outerWidth(true);
var ulSize = self.liSize * self.itemLength,
divSize = self.liSize * self.numVisible;
self.li.css({
width: self.li.width(),
height: self.li.height()
});
ul.css(self.sizeCss, ulSize+'px')
.css(self.animCss, -(self.calculatedTo * self.liSize));
elem.css(self.sizeCss, divSize+'px');
/* attachEventHandlers */
if(options.btnPrev && $(options.btnPrev).length > 0) {
$(options.btnPrev).on('click.'+self.nameSpace,function() {
if(!$(this).hasClass(options.disableClass)){
return self._go(self.calculatedTo - options.scroll);
}
});
}
if(options.btnNext && $(options.btnNext).length > 0) {
$(options.btnNext).on('click.'+self.nameSpace,function() {
if(!$(this).hasClass(options.disableClass)){
return self._go(self.calculatedTo + options.scroll);
}
});
}
if(options.btnGo && $(options.btnGo).length > 0) {
$.each(options.btnGo, function(i, val) {
$(val).on('click.'+self.nameSpace,function() {
return self._go(options.circular ? self.numVisible + i : i);
});
});
}
if(options.mouseWheel && elem.mousewheel) {
elem.on('mousewheel.'+self.nameSpace,function(e, d) {
console.log('moving');
return d > 0 ?
self._go(self.calculatedTo - options.scroll) :
self._go(self.calculatedTo + options.scroll);
});
}
if(options.auto) {
self._setupAutoScroll();
}
},
_init: function(){
},
_destroy: function(){
var self = this,
elem = self.element,
options = self.options;
elem.css(self.elemCss)
.find('>ul').css(self.ulCss)
.find('>li').css(self.liCss).each(function(){
if($(this).attr('data-default') === undefined){
$(this).remove();
} else {
$(this).removeAttr('data-default');
}
});
if(options.btnPrev && $(options.btnPrev).length > 0) {
$(options.btnPrev).off('click.'+self.nameSpace);
}
if(options.btnNext && $(options.btnNext).length > 0) {
$(options.btnNext).off('click.'+self.nameSpace);
}
if(options.btnGo && $(options.btnGo).length > 0) {
$.each(options.btnGo, function(i, val) {
$(val).off('click.'+self.nameSpace);
});
}
return self;
},
widget: function(){
return this.element;
},
ver: function(){
return this.version;
},
visibleItems: function(){
return this.options.visible;
},
_refreshView: function(){
var self = this;
self._destroy();
self._create();
},
_setOptions: function(options){
var self = this;
if(options['visible'] !== undefined && options['start'] === undefined){
options['start'] = 0;
}
$.each(options, function(key, value){
self._setOption(key, value);
});
self._refreshView();
},
_setOption: function(key, value){
var self = this;
$.Widget.prototype._setOption.apply(self, arguments);
},
_setupAutoScroll: function(){
var self = this;
self.autoTimeout = setTimeout(function() {
self._go(self.calculatedTo + options.scroll);
}, self.options.auto);
},
_visibleItems: function(){
var self = this;
return self.li.slice(self.calculatedTo).slice(0,self.numVisible);
},
_go: function(to){
var self = this,
options = self.options;
if(!self.isRunning) {
clearTimeout(self.autoTimeout);
self.calculatedTo = to;
if(options.beforeStart) {
options.beforeStart.call(this, self._visibleItems());
}
if(options.circular) {
self._adjustOobForCircular(to);
} else {
self._adjustOobForNonCircular(to);
}
self._animateToPosition({
start: function() {
self.isRunning = true;
},
done: function() {
if(options.afterEnd) {
options.afterEnd.call(this, self._visibleItems());
}
if(options.auto) {
self._setupAutoScroll();
}
self.isRunning = false;
}
});
if(!options.circular) {
self._disableOrEnableButtons();
}
}
return false;
},
_adjustOobForCircular: function(to){
var self = this,
elem = self.element,
ul = elem.find('>ul'),
options = self.options,
newPosition;
// If first, then goto last
if(to <= options.start - self.numVisible - 1) {
newPosition = to + self.initialItemLength + options.scroll;
ul.css(self.animCss, -(newPosition * self.liSize) + 'px');
self.calculatedTo = newPosition - options.scroll;
/* console.log('Before - Positioned at: ' + newPosition + ' and Moving to: ' + self.calculatedTo); */
}
// If last, then goto first
else if(to >= self.itemLength - self.numVisible + 1) {
newPosition = to - self.initialItemLength - options.scroll;
ul.css(self.animCss, -(newPosition * self.liSize) + 'px');
self.calculatedTo = newPosition + options.scroll;
/* console.log('After - Positioned at: ' + newPosition + ' and Moving to: ' + self.calculatedTo); */
}
},
_adjustOobForNonCircular: function(to){
var self = this;
// If user clicks "prev" and tries to go before the first element, reset it to first element.
if(to < 0) {
self.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 > self.itemLength - self.numVisible) {
self.calculatedTo = self.itemLength - self.numVisible;
}
/* console.log('Item Length: ' + self.itemLength + '; ' +
'To: ' + to + '; ' +
'CalculatedTo: ' + self.calculatedTo + '; ' +
'Num Visible: ' + self.numVisible); */
},
_disableOrEnableButtons: function(){
var self = this,
options = self.options;
$(options.btnPrev + ',' + options.btnNext).removeClass('disabled');
$( (self.calculatedTo - options.scroll < 0 && options.btnPrev)
||
(self.calculatedTo + options.scroll > self.itemLength - self.numVisible && options.btnNext)
||
[]
).addClass('disabled');
},
_animateToPosition: function(animationOptions){
var self = this,
options = self.options;
self.isRunning = true;
self.element.find('>ul').animate(
self.animCss == 'left' ?
{ left: -(self.calculatedTo * self.liSize) } :
{ top: -(self.calculatedTo * self.liSize) },
$.extend({
duration: options.speed,
easing: options.easing
}, animationOptions)
);
}
});
})(jQuery);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment