Skip to content

Instantly share code, notes, and snippets.

@jcontonio
Created February 3, 2011 21:36
Show Gist options
  • Save jcontonio/810260 to your computer and use it in GitHub Desktop.
Save jcontonio/810260 to your computer and use it in GitHub Desktop.
A jQuery based content slider for use with carousels and the like
/*
* HFCSlider
*
* @author Jay Contonio - jcontonio.com
* @constructor
* @example (as seen on @link:http://sabin.org/)
var settings = {
'controller': this,
'mask': this._carouselContainer.find('.thumbnails .mask'),
'container': this._carouselContainer.find('.thumbnails ol'),
'listItems': this._carouselContainer.find('.thumbnails li'),
'arrowClass': this._carouselContainer.find('.thumbnails .arrow'),
'wrapping': false,
'slidesPer': this._itemsPerPage,
'spacing': this._spacing
}
this._slider = new HFCSlider(settings);
// Move the slider two the second space
this._slider.move(1);
* @param {Object} settings The settings object includes the following params
* @param {String} controller The object that contains the slider, usually Application or Carousel
* @param {String} mask The mask div that contains the _container element you're moving around
* @param {String} listItems The list items that make up each item in the slider
* @param {String} arrowClass The previous and next arrows should have this class on them
* @param {Boolean} wrapper Should the carousel be an infinite loop
* @param {Number} slidesPer How many list items per slide (optional)
* @param {Number} spacing The margin between each item (optional) (usually used with slidesPer)
* @param {String} animationStyle Can be dissolve or slide (defaults to slide)
* @returns {Object} Returns itself
*/
var HFCSlider = function(settings)
{
this._object = settings['controller'];
this._mask = settings['mask'];
this._container = settings['container'];
this._listItems = settings['listItems'];
this._arrowClass = settings['arrowClass'];
this._wrap = settings['wrapping'];
this._slidesPer = settings['slidesPer'] === undefined ? 1 : settings['slidesPer'];
this._spacing = settings['spacing'] === undefined ? 0 : settings['spacing'];
this._animationStyle = settings['animationStyle'] === undefined ? 'slide' : settings['animationStyle'];
this._currentIndex = 0;
this._clickEvent = jQuery.Event("HFC_CAROUSEL_CLICK_EVENT");
this._moveEvent = jQuery.Event("HFC_CAROUSEL_MOVED");
// If the mask doesn't have a position of relateive|absolute yet, give it one
if ($(this._mask).css('position') === 'static')
{
$(this._mask).css({ 'position':'relative' });
}
// Set it's overflow-x to hidden
$(this._mask).css({ 'overflow-x':'hidden' });
// Position the element we're moving to 0,0
$(this._container).css({ 'position':'absolute', 'top':'0', 'left':'0' });
this.init();
return this;
}
/**
* Initializes the view
*/
HFCSlider.prototype.init = function()
{
if(this._wrap) this.createWrappingItem();
// Set the number of slides
this._numSlides = this._listItems.length;
// Sets the container width to the width of each slide * the amount of slides. (should be very wide)
this._slideWidth = $(this._listItems[0]).width() + this._spacing;
this._container.width(this._numSlides * this._slideWidth);
this._slidesWidth = this._mask.width();
// Override the number of slides if we are passed a slidesPer variable
// ie: if there are 3 slides per Slide
this._numSlides = Math.ceil(this._numSlides / this._slidesPer);
// Enable the arrows
this.enableArrows();
// If wrapping is set to false, disable the previous arrow on start
if(!this._wrap) this.disableArrow('previous');
}
/**
* @returns {Number} Returns the current index of the active slide (starting with 0)
* @type Number
*/
HFCSlider.prototype.getCurrentIndex = function()
{
return this._currentIndex;
}
/**
* Disables an arrow
* @param {String} arrow Disables the 'previous' or 'next' arrow
*/
HFCSlider.prototype.disableArrow = function(arrow)
{
$(this._arrowClass + '[href=#' + arrow + ']').css('cursor','default').addClass('disabled');
}
/**
* Enables an arrow
* @param {String} arrow Enabled the 'previous' or 'next' arrow
*/
HFCSlider.prototype.enableArrow = function(arrow)
{
$(this._arrowClass + '[href=#' + arrow + ']').css('cursor','pointer').removeClass('disabled');
}
/**
* Enables both arrows and assigns the click event
* @event 'HFC_CAROUSEL_CLICK_EVENT' Broadcasts this event
*/
HFCSlider.prototype.enableArrows = function()
{
var that = this;
this._arrowClass.unbind('click');
$(this._arrowClass).click(function(e) {
e.preventDefault();
$(this).attr('href') == "#previous" ? that.move('previous') : that.move('next');
$(that._object).trigger(that._clickEvent);
return false;
});
}
/**
* Disables both arrows by unbinding the click event
*/
HFCSlider.prototype.disableArrows = function()
{
this._arrowClass.unbind('click');
this._arrowClass.click(function(e) { e.preventDefault(); });
}
/**
* Duplicates the first item in the slider and appends it as the last
* Results in an infinite looping carousel
*/
HFCSlider.prototype.createWrappingItem = function()
{
this._listItems[0].clone().appendTo(this._container);
this._listItems.push(this._listItems[0]);
}
/**
* Moves the _container back, forward, or to a specific index
* @param {String} direction 'previous' or 'next'
* @param {Number} direction Can also be an index starting with 0
*/
HFCSlider.prototype.move = function(direction)
{
var that = this;
switch(direction)
{
case 'previous':
if(this._wrap) {
// If wrapping is turned on, position the container to the duplicated list item, set the current index manually
if(this._currentIndex <= 0) {
var wrappingPosition = -this._container.width() - this._slideWidth;
this._container.css({'left':wrappingPosition + 'px'});
this._currentIndex = this._numSlides - 1;
}
} else {
if(this._currentIndex <= 0) { return; }
}
this._currentIndex--;
break;
case 'next':
if(this._wrap) {
// If wrapping is turned on, position the container to the first list item after the last move, set the current index manually
if(this._currentIndex >= this._numSlides - 1) {
$(_container).css({'left':'0'});
this._currentIndex = 0;
}
} else {
if(this._currentIndex >= this._numSlides - 1) { return; }
}
this._currentIndex++;
break;
default:
// If direction isn't 'previous' or 'next' then it is an integer index
this._currentIndex = direction;
this.enableArrow('previous');
this.enableArrow('next');
}
// Disable or enable arrows based on position
if(!this._wrap) {
if(this._currentIndex == 0) { this.disableArrow('previous'); }
if(this._currentIndex == this._numSlides - 1) { this.disableArrow('next'); }
}
// Calculate the next position of the _container
var currentPosition = this._container.css('left');
if(typeof direction == 'string') {
var calculation = direction == 'previous' ? (parseFloat(currentPosition) + this._slidesWidth) + this._spacing : parseFloat(currentPosition) - this._slidesWidth - this._spacing;
this.enableArrow(direction == 'next' ? 'previous' : 'next');
} else {
var calculation = -(direction * this._slideWidth) + this._spacing;
}
// Disable all arrows while the animation takes place
this.disableArrows();
switch(this._animationStyle)
{
case "dissolve":
// Fade out the container, adjust it's left position, then fade it in
$(this._container).fadeOut('fast', function() {
$(this).css({'left': calculation + 'px'});
$(this).fadeIn('medium');
});
break;
default:
$(this._container).animate({ left: (calculation) + 'px' }, "medium", function() { that.enableArrows() });
}
// If we're wrapping, let's send the currentIndex - 1 if we're on the last one
if(this._wrap && this._currentIndex >= this._numSlides - 1) {
this._moveEvent.frame = 0;
this._moveEvent.direction = direction;
this._object.trigger(this._moveEvent);
return;
}
this._moveEvent.caller = this._object;
this._moveEvent.frame = this._currentIndex;
this._moveEvent.direction = direction;
$(this._object).trigger(this._moveEvent);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment