/*
Version 2.6.3
The MIT License (MIT)
Simple jQuery Slider is just what is says it is: a simple but powerfull jQuery slider.
Copyright (c) 2014 Dirk Groenen - Bitlabs Development
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
*/
(function($){
var simpleSlider = function(element, useroptions){
// Set some variables
var obj = this,
sliderInterval = null,
movecontainer = null,
instanceID = Math.floor(Math.random() * 100) + Date.now(); // Create a unique ID for this slider
obj.currentSlide = 0;
obj.totalSlides = 0;
// Extend default options with user options
useroptions = (useroptions === undefined) ? {} : useroptions;
var options = $.extend({
slidesContainer: element,
slides: '.slide',
slideTracker: true,
slideTrackerID: 'slideposition',
slideOnInterval: true,
interval: 5000,
swipe: true,
magneticSwipe: true,
transition: "slide",
animateDuration: 1000,
animationEasing: 'ease',
pauseOnHover: false,
updateTransit: true, // Change this to false is you dont want the slider to update the transit useTransitionEnd to true
useDefaultCSS: true,
neverEnding: true
}, useroptions);
/*
* Method to build and init the slider
*/
obj.init = function(){
// Disable some options when transition fade has been selected
if(options.transition == "fade"){
options.neverEnding = false;
options.magneticSwipe = false;
}
// If transit is included and useTransitionEnd == false we will change this to true (better animation performance).
// Unless the user changed updateTransit to false
if(options.updateTransit && $.support.transition && jQuery().transition && !$.transit.useTransitionEnd){
$.transit.useTransitionEnd = true;
}
var movecontainerclass = "jss-slideswrap-" + instanceID;
// Wrap the slides in a new container which will be used to move the slides
$(options.slidesContainer).wrapInner("
");
movecontainer = "." + movecontainerclass;
if(options.neverEnding){
if ($.support.transition && jQuery().transition)
$(movecontainer).stop().css({x: '-100%'});
else
$(movecontainer).stop().css({left: '-100%'});
}
// Count the total slides
obj.totalSlides = $(options.slidesContainer).find(options.slides).length;
// Check if the neverEnding options has been enabled
// If it is; clone the first and last slide
if(options.neverEnding){
var $first = $(options.slidesContainer).find(options.slides).first().clone(true, true);
var $last = $(options.slidesContainer).find(options.slides).last().clone(true, true);
$(movecontainer).prepend($last);
$(movecontainer).append($first);
}
var cacheWidth = 0;
// Add default positioning css when enabled
if(options.useDefaultCSS){
$(options.slidesContainer).css({
position: "relative",
overflow: "hidden"
});
}
// Find the slides in the sliderdom and add the index attribute
$(options.slidesContainer).find(options.slides).each(function(index){
// Give each slide a data-index so we can control it later on
if(options.neverEnding){
if(index === 0)
$(this).attr('data-index', obj.totalSlides - 1);
else if(index == obj.totalSlides + 1)
$(this).attr('data-index', 0);
else
$(this).attr('data-index', index - 1);
}
else{
$(this).attr('data-index', index);
}
cacheWidth = ($(this).outerWidth() > cacheWidth) ? $(this).outerWidth() : cacheWidth;
// Add css for slide transition
if(options.transition == "slide"){
// A fixed width is needed for the IE left animation. Here we give each slide a width
if($.support.transition !== undefined){
$(this).css({
x: index * 100 + '%',
'z-index': (obj.totalSlides * 2) - index,
width: cacheWidth
});
}
else{
$(this).css({
left: index * 100 + '%',
'z-index': (obj.totalSlides * 2) - index,
width: cacheWidth
});
}
}
// Add css for fade transition
if(options.transition == "fade"){
// A fixed width is needed for the IE left animation. Here we give each slide a width
var alpha = (index === 0) ? 1 : 0;
$(this).css({
left: 0,
top: 0,
'z-index': obj.totalSlides - index,
width: cacheWidth,
opacity: alpha
});
}
// Add default positioning css when enabled
if(options.useDefaultCSS){
$(this).css({
position: "absolute",
float: "left",
height: "100%",
top: 0
});
}
});
// Place the slideTracker after the container if enabled in the options
if(options.slideTracker){
// Add the slideposition div and add the indicators
$(options.slidesContainer).after("");
for(var x = 0; x < obj.totalSlides; x++){
var index = (obj.neverEnding && x == obj.totalSlides - 1) ? 0 : x;
$('div[data-slider="' + instanceID + '"] ul').append('');
}
$('div[data-slider="' + instanceID + '"] ul li[data-index="'+obj.currentSlide+'"]').addClass('active');
// Make the slide indicators clickable
$("div[data-slider='" + instanceID + "'] ul li").click(function(){
if(!($(this).hasClass("active")))
obj.nextSlide($(this).data('index'));
});
}
// Start the slider interval if enabled in options
if(options.slideOnInterval){
setSliderInterval();
}
// Change the cursor with a grabbing hand that simulates the swiping on desktops
if(options.swipe || options.magneticSwipe){
// Set grabbing mouse cursor
$(options.slidesContainer).css('cursor','-webkit-grab');
$(options.slidesContainer).css('cursor','-moz-grab');
$(options.slidesContainer).css('cursor','grab');
// Set vars for swiping
var isDragging = false;
var startPosition = {x: 0, y: 0};
var percentageMove = 0;
var slideWidth = $(options.slidesContainer).width();
// Check which touch events to use
var touchstartEvent = (window.navigator.msPointerEnabled) ? "MSPointerDown" : "touchstart";
var touchmoveEvent = (window.navigator.msPointerEnabled) ? "MSPointerMove" : "touchmove";
var touchendEvent = (window.navigator.msPointerEnabled) ? "MSPointerUp" : "touchend";
// Bind the mousedown or touchstart event
$(options.slidesContainer).on(touchstartEvent + " mousedown", function(e){
// Set isDragging on true
isDragging = true;
// Save start coordinates
startPosition = {
x: (e.pageX !== undefined) ? e.pageX : e.originalEvent.touches[0].pageX,
y: (e.pageY !== undefined) ? e.pageY : e.originalEvent.touches[0].pageY
};
// Reset transition animation
if(options.magneticSwipe)
$(options.slidesContainer).find(options.slides).css('transition', 'none');
// Reset percentage move
percentageMove = 0;
// Set mouse cursor
$(options.slidesContainer).css('cursor','-webkit-grabbing');
$(options.slidesContainer).css('cursor','-moz-grabbing');
$(options.slidesContainer).css('cursor','grabbing');
});
// Bind the mousemove or touchmove event
$(options.slidesContainer).on(touchmoveEvent + " mousemove", function(e){
// Prevent default action on touchmove event
// This solves the bug with Android phones
// https://github.com/dirkgroenen/simple-jQuery-slider/issues/11
if(e.type == touchmoveEvent)
e.preventDefault();
if(isDragging){
// Calculate given distance in pixels to percentage
var x = (e.pageX !== undefined) ? e.pageX : e.originalEvent.touches[0].pageX;
percentageMove = ((startPosition.x - x) / slideWidth) * 100;
// Check if magnetic swipe is on
if(options.magneticSwipe){
// Move slides
obj.manualSlide(percentageMove);
}
}
});
// Bind the mouseup or touchend event
$(options.slidesContainer).on(touchendEvent + " mouseup", function(e){
isDragging = false;
// Check if we have to call the next or previous slide, or reset the slides.
if(percentageMove > 25 && (obj.currentSlide < (obj.totalSlides - 1) || options.neverEnding))
obj.nextSlide();
else if(percentageMove < -25 && (obj.currentSlide > 0 || options.neverEnding))
obj.prevSlide();
else
obj.resetSlides();
// Reset mouse cursor
$(options.slidesContainer).css('cursor','-webkit-grab');
$(options.slidesContainer).css('cursor','-moz-grab');
$(options.slidesContainer).css('cursor','grab');
});
}
// Add on init event
$(element).trigger({
type: "init",
totalSlides: obj.totalSlides
});
}();
// Bind the function that recalculates the width of each slide on a resize.
$(window).resize(function(){
var cacheWidth = 0;
$(options.slidesContainer).find(options.slides).each(function(index){
// Reset width; otherwise it will keep the same width as before
$(this).css('width','');
cacheWidth = ($(this).outerWidth() > cacheWidth) ? $(this).outerWidth() : cacheWidth;
if(options.transition == "fade")
$(this).css({width: cacheWidth});
else
$(this).css({x: ($(this).data('index') - obj.currentSlideindex) * 100 + '%', width: cacheWidth});
});
});
/*
* Set the slider interval
*/
function setSliderInterval(){
clearInterval(sliderInterval);
sliderInterval = setInterval(function(){
obj.nextSlide();
},options.interval);
}
/*
* Manual offset the slider with the given percentage
*
* @param int percentage
*/
obj.manualSlide = function(percentage){
// Move the slides based on the calculated percentage
if(options.transition == "slide"){
// Remove the previous transition effect
$(movecontainer).css("-webkit-transition", "none");
$(movecontainer).css("-moz-transition", "none");
$(movecontainer).css("-ms-transition", "none");
$(movecontainer).css("transition", "none");
var movepercentage = -((obj.currentSlide * 100) + percentage);
if(options.neverEnding)
movepercentage = -(((obj.currentSlide + 1) * 100) + percentage);
if ($.support.transition && jQuery().transition)
$(movecontainer).css({x: movepercentage + '%'});
else
$(movecontainer).css({left: movepercentage + '%'});
}
};
/*
* Reset slides to their given position. Used after a manualSlide action
*/
obj.resetSlides = function(){
if(options.transition == "slide"){
var movepercentage = (options.neverEnding) ? -((obj.currentSlide + 1) * 100) : -(obj.currentSlide * 100);
if ($.support.transition && jQuery().transition)
$(movecontainer).stop().transition({x: movepercentage + '%'}, options.animateDuration, options.animationEasing);
else
$(movecontainer).stop().animate({left: movepercentage + '%'}, options.animateDuration);
}
};
/*
* Go to the previous slide, calls the last slide when no previous slides
*/
obj.prevSlide = function(){
var slide = (obj.currentSlide > 0) ? obj.currentSlide -= 1 : (obj.totalSlides - 1);
obj.nextSlide(slide);
};
/*
* Go to a next slide (function is also used for the previous slide and goto slide functions).
* If a paramater is given it will go to the given slide
*
* @param1 int slide
*/
obj.nextSlide = function(slide){
// Cache the previous slide number and set slided to false
var prevSlide = obj.currentSlide,
slided = false;
// Auto define the next slide
if(slide === undefined)
obj.currentSlide = (obj.currentSlide < (obj.totalSlides-1)) ? obj.currentSlide += 1 : 0 ;
else
obj.currentSlide = slide;
// Create event object which will contain the previous end next slide number
var beforeSlidingEvent = jQuery.Event("beforeSliding", {
prevSlide: prevSlide,
newSlide: obj.currentSlide
});
$(element).trigger(beforeSlidingEvent);
// Stop the action when the user has prevented the default action
// and reset the obj.currentSlide to the previous number
if(beforeSlidingEvent.isDefaultPrevented()){
obj.currentSlide = prevSlide;
return false;
}
// Calculate the move percentage
var movepercentage = -(obj.currentSlide * 100);
if(options.neverEnding){
if(obj.currentSlide == obj.totalSlides - 1 && prevSlide === 0){
movepercentage = 0;
}
else if(obj.currentSlide === 0 && obj.totalSlides - 1 == prevSlide){
movepercentage = -(obj.totalSlides + 1) * 100;
}
else{
movepercentage = -((obj.currentSlide + 1) * 100);
}
}
// Move the container
if(options.transition == "slide"){
if ($.support.transition && jQuery().transition)
$(movecontainer).stop().transition({x: movepercentage + '%'}, options.animateDuration, options.animationEasing);
else
$(movecontainer).stop().animate({left: movepercentage + '%'}, options.animateDuration, triggerSlideEnd);
}
// Hide and show the correct slides
if(options.transition == "fade"){
$(options.slidesContainer).find(options.slides).each(function(index){
var alpha = (index == obj.currentSlide) ? 1 : 0;
if(index == obj.currentSlide){
$(this).show();
}
if ($.support.transition && jQuery().transition)
$(this).stop().transition({opacity: alpha}, options.animateDuration, triggerSlideEnd);
else
$(this).stop().animate({opacity: alpha}, options.animateDuration, triggerSlideEnd);
});
}
// Somehow the callback from $.transition doesn't work, so we create ow custom bind here
$(options.slidesContainer).on('oTransitionEnd webkitTransitionEnd oTransitionEnd otransitionend transitionend', triggerSlideEnd);
// Create trigger point after a slide slides. All the slides return a TransitionEnd; to prevent a repeating trigger we keep a slided var
function triggerSlideEnd(){
if(!slided){
if(options.transition == "fade"){
$(options.slidesContainer).find(options.slides).each(function(index){
if($(this).data('index') == obj.currentSlide){
$(this).show();
}
else{
$(this).hide();
}
});
}
// Reset to the first slide when neverEnding has been enabled and the 'faked' last slide is active
if(options.transition == "slide" && options.neverEnding){
// Check if it's the 'last' slide
if(obj.currentSlide == obj.totalSlides - 1 && prevSlide === 0){
if ($.support.transition && jQuery().transition)
$(movecontainer).stop().transition({x: -(obj.totalSlides) * 100 + "%"}, 1, 'linear');
else
$(movecontainer).css({left: -(obj.totalSlides) * 100 + "%"});
}
// Check if it's the 'first' slide
if(obj.currentSlide === 0 && prevSlide == obj.totalSlides - 1){
if ($.support.transition && jQuery().transition)
$(movecontainer).stop().transition({x: "-100%"}, 1, 'linear');
else
$(movecontainer).css({left: "-100%"});
}
}
// Trigger event
var afterSlidingEvent = jQuery.Event("afterSliding", {
prevSlide: prevSlide,
newSlide: obj.currentSlide
});
$(element).trigger(afterSlidingEvent);
slided = true;
}
}
// Show current slide bulb
$('div[data-slider="' + instanceID + '"] ul li').removeClass('active');
$('div[data-slider="' + instanceID + '"] ul li[data-index="'+obj.currentSlide+'"]').addClass('active');
// (Re)set the slider interval
if(options.slideOnInterval){
setSliderInterval();
}
};
// Function for the pauseOnHover.
//The function will clear the interval and restart it after the mouse disappears from the container
if(options.pauseOnHover){
$(options.slidesContainer).hover(function(){
clearInterval(sliderInterval);
}, function(){
setSliderInterval();
});
}
};
// Create a plugin
$.fn.simpleSlider = function(options){
return this.each(function(){
var element = $(this);
// Return early if this element already has a plugin instance
if (element.data('simpleslider')) return;
// Pass options and element to the plugin constructer
var simpleslider = new simpleSlider(this, options);
// Store the plugin object in this element's data
element.data('simpleslider', simpleslider);
});
};
})(jQuery);