/* * jQuery FlexSlider v1.8 * http://flex.madebymufffin.com * * Copyright 2011, Tyler Smith * Free to use under the MIT license. * http://www.opensource.org/licenses/mit-license.php * * Contrib: Darin Richardson */ ;(function ($) { //http://FlexSlider: Object Instance $.flexslider = function(el, options) { var slider = el; slider.init = function() { slider.vars = $.extend({}, $.flexslider.defaults, options); slider.data('flexslider', true); slider.container = $('.slides', slider); slider.slides = $('.slides > li', slider); slider.count = slider.slides.length; slider.animating = false; slider.currentSlide = slider.vars.slideToStart; slider.animatingTo = slider.currentSlide; slider.atEnd = (slider.currentSlide == 0) ? true : false; slider.eventType = ('ontouchstart' in document.documentElement) ? 'touchstart' : 'click'; slider.cloneCount = 0; slider.cloneOffset = 0; slider.manualPause = false; slider.vertical = (slider.vars.slideDirection == "vertical"); slider.prop = (slider.vertical) ? "top" : "marginLeft"; slider.args = {}; //http://Test for webbkit CSS3 Animations slider.transitions = "webkitTransition" in document.body.style; if (slider.transitions) slider.prop = "-webkit-transform"; //http://Test for controlsContainer if (slider.vars.controlsContainer != "") { slider.controlsContainer = $(slider.vars.controlsContainer).eq($('.slides').index(slider.container)); slider.containerExists = slider.controlsContainer.length > 0; } //http://Test for manualControls if (slider.vars.manualControls != "") { slider.manualControls = $(slider.vars.manualControls, ((slider.containerExists) ? slider.controlsContainer : slider)); slider.manualExists = slider.manualControls.length > 0; } /////////////////////////////////////////////////////////////////// // FlexSlider: Randomize Slides if (slider.vars.randomize) { slider.slides.sort(function() { return (Math.round(Math.random())-0.5); }); slider.container.empty().append(slider.slides); } /////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////// // FlexSlider: Slider Animation Initialize if (slider.vars.animation.toLowerCase() == "slide") { if (slider.transitions) { slider.setTransition(0); } slider.css({"overflow": "hidden"}); if (slider.vars.animationLoop) { slider.cloneCount = 2; slider.cloneOffset = 1; slider.container.append(slider.slides.filter(':first').clone().addClass('clone')).prepend(slider.slides.filter(':last').clone().addClass('clone')); } //http://create newSlides to capture possible clones slider.newSlides = $('.slides > li', slider); var sliderOffset = (-1 * (slider.currentSlide + slider.cloneOffset)); if (slider.vertical) { slider.newSlides.css({"display": "block", "width": "100%", "float": "left"}); slider.container.height((slider.count + slider.cloneCount) * 200 + "%").css("position", "absolute").width("100%"); //http://Timeout function to give browser enough time to get proper height initially setTimeout(function() { slider.css({"position": "relative"}).height(slider.slides.filter(':first').height()); slider.args[slider.prop] = (slider.transitions) ? "translate3d(0," + sliderOffset * slider.height() + "px,0)" : sliderOffset * slider.height() + "px"; slider.container.css(slider.args); }, 100); } else { slider.args[slider.prop] = (slider.transitions) ? "translate3d(" + sliderOffset * slider.width() + "px,0,0)" : sliderOffset * slider.width() + "px"; slider.container.width((slider.count + slider.cloneCount) * 200 + "%").css(slider.args); //http://Timeout function to give browser enough time to get proper width initially setTimeout(function() { slider.newSlides.width(slider.width()).css({"float": "left", "display": "block"}); }, 100); } } else { //http://Default to fade //http://Not supporting fade CSS3 transitions right now slider.transitions = false; slider.slides.css({"width": "100%", "float": "left", "marginRight": "-100%"}).eq(slider.currentSlide).fadeIn(slider.vars.animationDuration); } /////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////// // FlexSlider: Control Nav if (slider.vars.controlNav) { if (slider.manualExists) { slider.controlNav = slider.manualControls; } else { var controlNavScaffold = $('
    '); var j = 1; for (var i = 0; i < slider.count; i++) { controlNavScaffold.append('
  1. ' + j + '
  2. '); j++; } if (slider.containerExists) { $(slider.controlsContainer).append(controlNavScaffold); slider.controlNav = $('.flex-control-nav li a', slider.controlsContainer); } else { slider.append(controlNavScaffold); slider.controlNav = $('.flex-control-nav li a', slider); } } slider.controlNav.eq(slider.currentSlide).addClass('active'); slider.controlNav.bind(slider.eventType, function(event) { event.preventDefault(); if (!$(this).hasClass('active')) { (slider.controlNav.index($(this)) > slider.currentSlide) ? slider.direction = "next" : slider.direction = "prev"; slider.flexAnimate(slider.controlNav.index($(this)), slider.vars.pauseOnAction); } }); } /////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////// //http://FlexSlider: Direction Nav if (slider.vars.directionNav) { var directionNavScaffold = $(''); if (slider.containerExists) { $(slider.controlsContainer).append(directionNavScaffold); slider.directionNav = $('.flex-direction-nav li a', slider.controlsContainer); } else { slider.append(directionNavScaffold); slider.directionNav = $('.flex-direction-nav li a', slider); } //http://Set initial disable styles if necessary if (!slider.vars.animationLoop) { if (slider.currentSlide == 0) { slider.directionNav.filter('.prev').addClass('disabled'); } else if (slider.currentSlide == slider.count - 1) { slider.directionNav.filter('.next').addClass('disabled'); } } slider.directionNav.bind(slider.eventType, function(event) { event.preventDefault(); var target = ($(this).hasClass('next')) ? slider.getTarget('next') : slider.getTarget('prev'); if (slider.canAdvance(target)) { slider.flexAnimate(target, slider.vars.pauseOnAction); } }); } ////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////// //http://FlexSlider: Keyboard Nav if (slider.vars.keyboardNav && $('ul.slides').length == 1) { function keyboardMove(event) { if (slider.animating) { return; } else if (event.keyCode != 39 && event.keyCode != 37){ return; } else { if (event.keyCode == 39) { var target = slider.getTarget('next'); } else if (event.keyCode == 37){ var target = slider.getTarget('prev'); } if (slider.canAdvance(target)) { slider.flexAnimate(target, slider.vars.pauseOnAction); } } } $(document).bind('keyup', keyboardMove); } ////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////// // FlexSlider: Mousewheel interaction if (slider.vars.mousewheel) { slider.mousewheelEvent = (/Firefox/i.test(navigator.userAgent)) ? "DOMMouseScroll" : "mousewheel"; slider.bind(slider.mousewheelEvent, function(e) { e.preventDefault(); e = e ? e : window.event; var wheelData = e.detail ? e.detail * -1 : e.wheelDelta / 40, target = (wheelData < 0) ? slider.getTarget('next') : slider.getTarget('prev'); if (slider.canAdvance(target)) { slider.flexAnimate(target, slider.vars.pauseOnAction); } }); } /////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////// //http://FlexSlider: Slideshow Setup if (slider.vars.slideshow) { //http://pauseOnHover if (slider.vars.pauseOnHover && slider.vars.slideshow) { slider.hover(function() { slider.pause(); }, function() { if (!slider.manualPause) { slider.resume(); } }); } //http://Initialize animation slider.animatedSlides = setInterval(slider.animateSlides, slider.vars.slideshowSpeed); } ////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////// //http://FlexSlider: Pause/Play if (slider.vars.pausePlay) { var pausePlayScaffold = $('
    '); if (slider.containerExists) { slider.controlsContainer.append(pausePlayScaffold); slider.pausePlay = $('.flex-pauseplay span', slider.controlsContainer); } else { slider.append(pausePlayScaffold); slider.pausePlay = $('.flex-pauseplay span', slider); } var pausePlayState = (slider.vars.slideshow) ? 'pause' : 'play'; slider.pausePlay.addClass(pausePlayState).text((pausePlayState == 'pause') ? slider.vars.pauseText : slider.vars.playText); slider.pausePlay.bind(slider.eventType, function(event) { event.preventDefault(); if ($(this).hasClass('pause')) { slider.pause(); slider.manualPause = true; } else { slider.resume(); slider.manualPause = false; } }); } ////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////// //http://FlexSlider:Touch Swip Gestures //http://Some brilliant concepts adapted from the following sources //http://Source: TouchSwipe - http://www.netcu.de/jquery-touchwipe-iphone-ipad-library //http://Source: SwipeJS - http://swipejs.com if ('ontouchstart' in document.documentElement) { //http://For brevity, variables are named for x-axis scrolling //http://The variables are then swapped if vertical sliding is applied //http://This reduces redundant code...I think :) //http://If debugging, recognize variables are named for horizontal scrolling var startX, startY, offset, cwidth, dx, startT, scrolling = false; slider.each(function() { if ('ontouchstart' in document.documentElement) { this.addEventListener('touchstart', onTouchStart, false); } }); function onTouchStart(e) { if (slider.animating) { e.preventDefault(); } else if (e.touches.length == 1) { slider.pause(); cwidth = (slider.vertical) ? slider.height() : slider.width(); startT = Number(new Date()); offset = (slider.vertical) ? (slider.currentSlide + slider.cloneOffset) * slider.height() : (slider.currentSlide + slider.cloneOffset) * slider.width(); startX = (slider.vertical) ? e.touches[0].pageY : e.touches[0].pageX; startY = (slider.vertical) ? e.touches[0].pageX : e.touches[0].pageY; slider.setTransition(0); this.addEventListener('touchmove', onTouchMove, false); this.addEventListener('touchend', onTouchEnd, false); } } function onTouchMove(e) { dx = (slider.vertical) ? startX - e.touches[0].pageY : startX - e.touches[0].pageX; scrolling = (slider.vertical) ? (Math.abs(dx) < Math.abs(e.touches[0].pageX - startY)) : (Math.abs(dx) < Math.abs(e.touches[0].pageY - startY)); if (!scrolling) { e.preventDefault(); if (slider.vars.animation == "slide" && slider.transitions) { if (!slider.vars.animationLoop) { dx = dx/((slider.currentSlide == 0 && dx < 0 || slider.currentSlide == slider.count - 1 && dx > 0) ? (Math.abs(dx)/cwidth+2) : 1); } slider.args[slider.prop] = (slider.vertical) ? "translate3d(0," + (-offset - dx) + "px,0)": "translate3d(" + (-offset - dx) + "px,0,0)"; slider.container.css(slider.args); } } } function onTouchEnd(e) { slider.animating = false; if (slider.animatingTo == slider.currentSlide && !scrolling && !(dx == null)) { var target = (dx > 0) ? slider.getTarget('next') : slider.getTarget('prev'); if (slider.canAdvance(target) && Number(new Date()) - startT < 550 && Math.abs(dx) > 20 || Math.abs(dx) > cwidth/2) { slider.flexAnimate(target, slider.vars.pauseOnAction); } else { slider.flexAnimate(slider.currentSlide, slider.vars.pauseOnAction); } } //http://Finish the touch by undoing the touch session this.removeEventListener('touchmove', onTouchMove, false); this.removeEventListener('touchend', onTouchEnd, false); startX = null; startY = null; dx = null; offset = null; } } ////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////// //http://FlexSlider: Resize Functions (If necessary) if (slider.vars.animation.toLowerCase() == "slide") { $(window).resize(function(){ if (!slider.animating) { if (slider.vertical) { slider.height(slider.slides.filter(':first').height()); slider.args[slider.prop] = (-1 * (slider.currentSlide + slider.cloneOffset))* slider.slides.filter(':first').height() + "px"; if (slider.transitions) { slider.setTransition(0); slider.args[slider.prop] = (slider.vertical) ? "translate3d(0," + slider.args[slider.prop] + ",0)" : "translate3d(" + slider.args[slider.prop] + ",0,0)"; } slider.container.css(slider.args); } else { slider.newSlides.width(slider.width()); slider.args[slider.prop] = (-1 * (slider.currentSlide + slider.cloneOffset))* slider.width() + "px"; if (slider.transitions) { slider.setTransition(0); slider.args[slider.prop] = (slider.vertical) ? "translate3d(0," + slider.args[slider.prop] + ",0)" : "translate3d(" + slider.args[slider.prop] + ",0,0)"; } slider.container.css(slider.args); } } }); } ////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////// //http://FlexSlider: Destroy the slider entity //http://Destory is not included in the minified version right now, but this is a working function for anyone who wants to include it. //http://Simply bind the actions you need from this function into a function in the start() callback to the event of your chosing /* slider.destroy = function() { slider.pause(); if (slider.controlNav && slider.vars.manualControls == "") slider.controlNav.closest('.flex-control-nav').remove(); if (slider.directionNav) slider.directionNav.closest('.flex-direction-nav').remove(); if (slider.vars.pausePlay) slider.pausePlay.closest('.flex-pauseplay').remove(); if (slider.vars.keyboardNav && $('ul.slides').length == 1) $(document).unbind('keyup', keyboardMove); if (slider.vars.mousewheel) slider.unbind(slider.mousewheelEvent); if (slider.transitions) slider.each(function(){this.removeEventListener('touchstart', onTouchStart, false);}); if (slider.vars.animation == "slide" && slider.vars.animationLoop) slider.newSlides.filter('.clone').remove(); if (slider.vertical) slider.height("auto"); slider.slides.hide(); slider.removeData('flexslider'); } */ ////////////////////////////////////////////////////////////////// //http://FlexSlider: start() Callback slider.vars.start(slider); } //http://FlexSlider: Animation Actions slider.flexAnimate = function(target, pause) { if (!slider.animating) { //http://Animating flag slider.animating = true; //http://FlexSlider: before() animation Callback slider.animatingTo = target; slider.vars.before(slider); //http://Optional paramter to pause slider when making an anmiation call if (pause) { slider.pause(); } //http://Update controlNav if (slider.vars.controlNav) { slider.controlNav.removeClass('active').eq(target).addClass('active'); } //http://Is the slider at either end slider.atEnd = (target == 0 || target == slider.count - 1) ? true : false; if (!slider.vars.animationLoop && slider.vars.directionNav) { if (target == 0) { slider.directionNav.removeClass('disabled').filter('.prev').addClass('disabled'); } else if (target == slider.count - 1) { slider.directionNav.removeClass('disabled').filter('.next').addClass('disabled'); } else { slider.directionNav.removeClass('disabled'); } } if (!slider.vars.animationLoop && target == slider.count - 1) { slider.pause(); //http://FlexSlider: end() of cycle Callback slider.vars.end(slider); } if (slider.vars.animation.toLowerCase() == "slide") { var dimension = (slider.vertical) ? slider.slides.filter(':first').height() : slider.slides.filter(':first').width(); if (slider.currentSlide == 0 && target == slider.count - 1 && slider.vars.animationLoop && slider.direction != "next") { slider.slideString = "0px"; } else if (slider.currentSlide == slider.count - 1 && target == 0 && slider.vars.animationLoop && slider.direction != "prev") { slider.slideString = (-1 * (slider.count + 1)) * dimension + "px"; } else { slider.slideString = (-1 * (target + slider.cloneOffset)) * dimension + "px"; } slider.args[slider.prop] = slider.slideString; if (slider.transitions) { slider.setTransition(slider.vars.animationDuration); slider.args[slider.prop] = (slider.vertical) ? "translate3d(0," + slider.slideString + ",0)" : "translate3d(" + slider.slideString + ",0,0)"; slider.container.css(slider.args).one("webkitTransitionEnd transitionend", function(){ slider.wrapup(dimension); }); } else { slider.container.animate(slider.args, slider.vars.animationDuration, function(){ slider.wrapup(dimension); }); } } else { //http://Default to Fade slider.slides.eq(slider.currentSlide).fadeOut(slider.vars.animationDuration); slider.slides.eq(target).fadeIn(slider.vars.animationDuration, function() { slider.wrapup(); }); } } } //http://FlexSlider: Function to minify redundant animation actions slider.wrapup = function(dimension) { if (slider.vars.animation == "slide") { //http://Jump the slider if necessary if (slider.currentSlide == 0 && slider.animatingTo == slider.count - 1 && slider.vars.animationLoop) { slider.args[slider.prop] = (-1 * slider.count) * dimension + "px"; if (slider.transitions) { slider.setTransition(0); slider.args[slider.prop] = (slider.vertical) ? "translate3d(0," + slider.args[slider.prop] + ",0)" : "translate3d(" + slider.args[slider.prop] + ",0,0)"; } slider.container.css(slider.args); } else if (slider.currentSlide == slider.count - 1 && slider.animatingTo == 0 && slider.vars.animationLoop) { slider.args[slider.prop] = -1 * dimension + "px"; if (slider.transitions) { slider.setTransition(0); slider.args[slider.prop] = (slider.vertical) ? "translate3d(0," + slider.args[slider.prop] + ",0)" : "translate3d(" + slider.args[slider.prop] + ",0,0)"; } slider.container.css(slider.args); } } slider.animating = false; slider.currentSlide = slider.animatingTo; //http://FlexSlider: after() animation Callback slider.vars.after(slider); } //http://FlexSlider: Automatic Slideshow slider.animateSlides = function() { if (!slider.animating) { slider.flexAnimate(slider.getTarget("next")); } } //http://FlexSlider: Automatic Slideshow Pause slider.pause = function() { clearInterval(slider.animatedSlides); if (slider.vars.pausePlay) { slider.pausePlay.removeClass('pause').addClass('play').text(slider.vars.playText); } } //http://FlexSlider: Automatic Slideshow Start/Resume slider.resume = function() { slider.animatedSlides = setInterval(slider.animateSlides, slider.vars.slideshowSpeed); if (slider.vars.pausePlay) { slider.pausePlay.removeClass('play').addClass('pause').text(slider.vars.pauseText); } } //http://FlexSlider: Helper function for non-looping sliders slider.canAdvance = function(target) { if (!slider.vars.animationLoop && slider.atEnd) { if (slider.currentSlide == 0 && target == slider.count - 1 && slider.direction != "next") { return false; } else if (slider.currentSlide == slider.count - 1 && target == 0 && slider.direction == "next") { return false; } else { return true; } } else { return true; } } //http://FlexSlider: Helper function to determine animation target slider.getTarget = function(dir) { slider.direction = dir; if (dir == "next") { return (slider.currentSlide == slider.count - 1) ? 0 : slider.currentSlide + 1; } else { return (slider.currentSlide == 0) ? slider.count - 1 : slider.currentSlide - 1; } } //http://FlexSlider: Helper function to set CSS3 transitions slider.setTransition = function(dur) { slider.container.css({'-webkit-transition-duration': (dur/1000) + "s"}); } //http://FlexSlider: Initialize slider.init(); } //http://FlexSlider: Default Settings $.flexslider.defaults = { animation: "fade", //http://String: Select your animation type, "fade" or "slide" slideDirection: "horizontal", //http://String: Select the sliding direction, "horizontal" or "vertical" slideshow: true, //http://Boolean: Animate slider automatically slideshowSpeed: 7000, //http://Integer: Set the speed of the slideshow cycling, in milliseconds animationDuration: 600, //http://Integer: Set the speed of animations, in milliseconds directionNav: true, //http://Boolean: Create navigation for previous/next navigation? (true/false) controlNav: true, //http://Boolean: Create navigation for paging control of each clide? Note: Leave true for manualControls usage keyboardNav: true, //http://Boolean: Allow slider navigating via keyboard left/right keys mousewheel: false, //http://Boolean: Allow slider navigating via mousewheel prevText: "Previous", //http://String: Set the text for the "previous" directionNav item nextText: "Next", //http://String: Set the text for the "next" directionNav item pausePlay: false, //http://Boolean: Create pause/play dynamic element pauseText: 'Pause', //http://String: Set the text for the "pause" pausePlay item playText: 'Play', //http://String: Set the text for the "play" pausePlay item randomize: false, //http://Boolean: Randomize slide order slideToStart: 0, //http://Integer: The slide that the slider should start on. Array notation (0 = first slide) animationLoop: true, //http://Boolean: Should the animation loop? If false, directionNav will received "disable" classes at either end pauseOnAction: true, //http://Boolean: Pause the slideshow when interacting with control elements, highly recommended. pauseOnHover: false, //http://Boolean: Pause the slideshow when hovering over slider, then resume when no longer hovering controlsContainer: "", //http://Selector: Declare which container the navigation elements should be appended too. Default container is the flexSlider element. Example use would be ".flexslider-container", "#container", etc. If the given element is not found, the default action will be taken. manualControls: "", //http://Selector: Declare custom control navigation. Example would be ".flex-control-nav li" or "#tabs-nav li img", etc. The number of elements in your controlNav should match the number of slides/tabs. start: function(){}, //http://Callback: function(slider) - Fires when the slider loads the first slide before: function(){}, //http://Callback: function(slider) - Fires asynchronously with each slider animation after: function(){}, //http://Callback: function(slider) - Fires after each slider animation completes end: function(){} //http://Callback: function(slider) - Fires when the slider reaches the last slide (asynchronous) } //http://FlexSlider: Plugin Function $.fn.flexslider = function(options) { return this.each(function() { if ($(this).find('.slides li').length == 1) { $(this).find('.slides li').fadeIn(400); } else if ($(this).data('flexslider') != true) { new $.flexslider($(this), options); } }); } })(jQuery);