/** * jQuery bxSlider v3.0 * http://bxslider.com * * Copyright 2011, Steven Wanderski * http://bxcreative.com * * Free to use and abuse under the MIT license. * http://www.opensource.org/licenses/mit-license.php * */ (function ($) { $.fn.bxSlider = function (options) { var defaults = { mode: 'horizontal', // 'horizontal', 'vertical', 'fade' infiniteLoop: true, // true, false - display first slide after last hideControlOnEnd: false, // true, false - if true, will hide 'next' control on last slide and 'prev' control on first controls: true, // true, false - previous and next controls speed: 500, // integer - in ms, duration of time slide transitions will occupy easing: 'swing', // used with jquery.easing.1.3.js - see http://gsgd.co.uk/sandbox/jquery/easing/ for available options pager: false, // true / false - display a pager pagerSelector: null, // jQuery selector - element to contain the pager. ex: '#pager' pagerType: 'full', // 'full', 'short' - if 'full' pager displays 1,2,3... if 'short' pager displays 1 / 4 pagerLocation: 'bottom', // 'bottom', 'top' - location of pager pagerShortSeparator: '/', // string - ex: 'of' pager would display 1 of 4 pagerActiveClass: 'pager-active', // string - classname attached to the active pager link nextText: 'next', // string - text displayed for 'next' control nextImage: '', // string - filepath of image used for 'next' control. ex: 'images/next.jpg' nextSelector: null, // jQuery selector - element to contain the next control. ex: '#next' prevText: 'prev', // string - text displayed for 'previous' control prevImage: '', // string - filepath of image used for 'previous' control. ex: 'images/prev.jpg' prevSelector: null, // jQuery selector - element to contain the previous control. ex: '#next' captions: false, // true, false - display image captions (reads the image 'title' tag) captionsSelector: null, // jQuery selector - element to contain the captions. ex: '#captions' auto: false, // true, false - make slideshow change automatically autoDirection: 'next', // 'next', 'prev' - direction in which auto show will traverse autoControls: false, // true, false - show 'start' and 'stop' controls for auto show autoControlsSelector: null, // jQuery selector - element to contain the auto controls. ex: '#auto-controls' autoStart: true, // true, false - if false show will wait for 'start' control to activate autoHover: false, // true, false - if true show will pause on mouseover autoDelay: 0, // integer - in ms, the amount of time before starting the auto show pause: 3000, // integer - in ms, the duration between each slide transition startText: 'start', // string - text displayed for 'start' control startImage: '', // string - filepath of image used for 'start' control. ex: 'images/start.jpg' stopText: 'stop', // string - text displayed for 'stop' control stopImage: '', // string - filepath of image used for 'stop' control. ex: 'images/stop.jpg' ticker: false, // true, false - continuous motion ticker mode (think news ticker) // note: autoControls, autoControlsSelector, and autoHover apply to ticker! tickerSpeed: 5000, // float - use value between 1 and 5000 to determine ticker speed - the smaller the value the faster the ticker speed tickerDirection: 'next', // 'next', 'prev' - direction in which ticker show will traverse tickerHover: false, // true, false - if true ticker will pause on mouseover wrapperClass: 'bx-wrapper', // string - classname attached to the slider wraper startingSlide: 0, // integer - show will start on specified slide. note: slides are zero based! displaySlideQty: 1, // integer - number of slides to display at once moveSlideQty: 1, // integer - number of slides to move at once randomStart: false, // true, false - if true show will start on a random slide onBeforeSlide: function () { }, // function(currentSlideNumber, totalSlideQty, currentSlideHtmlObject) - advanced use only! see the tutorial here: http://bxslider.com/custom-pager onAfterSlide: function () { }, // function(currentSlideNumber, totalSlideQty, currentSlideHtmlObject) - advanced use only! see the tutorial here: http://bxslider.com/custom-pager onLastSlide: function () { }, // function(currentSlideNumber, totalSlideQty, currentSlideHtmlObject) - advanced use only! see the tutorial here: http://bxslider.com/custom-pager onFirstSlide: function () { }, // function(currentSlideNumber, totalSlideQty, currentSlideHtmlObject) - advanced use only! see the tutorial here: http://bxslider.com/custom-pager onNextSlide: function () { }, // function(currentSlideNumber, totalSlideQty, currentSlideHtmlObject) - advanced use only! see the tutorial here: http://bxslider.com/custom-pager onPrevSlide: function () { }, // function(currentSlideNumber, totalSlideQty, currentSlideHtmlObject) - advanced use only! see the tutorial here: http://bxslider.com/custom-pager buildPager: null // function(slideIndex, slideHtmlObject){ return string; } - advanced use only! see the tutorial here: http://bxslider.com/custom-pager } var options = $.extend(defaults, options); // cache the base element var base = this; // initialize (and localize) all variables var $parent = ''; var $origElement = ''; var $children = ''; var $outerWrapper = ''; var $firstChild = ''; var childrenWidth = ''; var childrenOuterWidth = ''; var wrapperWidth = ''; var wrapperHeight = ''; var $pager = ''; var interval = ''; var $autoControls = ''; var $stopHtml = ''; var $startContent = ''; var $stopContent = ''; var autoPlaying = true; var loaded = false; var childrenMaxWidth = 0; var childrenMaxHeight = 0; var currentSlide = 0; var origLeft = 0; var origTop = 0; var origShowWidth = 0; var origShowHeight = 0; var tickerLeft = 0; var tickerTop = 0; var isWorking = false; var firstSlide = 0; var lastSlide = $children.length - 1; // PUBLIC FUNCTIONS /** * Go to specified slide */ this.goToSlide = function (number, stopAuto) { if (!isWorking) { isWorking = true; // set current slide to argument currentSlide = number; options.onBeforeSlide(currentSlide, $children.length, $children.eq(currentSlide)); // check if stopAuto argument is supplied if (typeof (stopAuto) == 'undefined') { var stopAuto = true; } if (stopAuto) { // if show is auto playing, stop it if (options.auto) { base.stopShow(true); } } slide = number; // check for first slide callback if (slide == firstSlide) { options.onFirstSlide(currentSlide, $children.length, $children.eq(currentSlide)); } // check for last slide callback if (slide == lastSlide) { options.onLastSlide(currentSlide, $children.length, $children.eq(currentSlide)); } // horizontal if (options.mode == 'horizontal') { $parent.animate({ 'left': '-' + getSlidePosition(slide, 'left') + 'px' }, options.speed, options.easing, function () { isWorking = false; // perform the callback function options.onAfterSlide(currentSlide, $children.length, $children.eq(currentSlide)); }); // vertical } else if (options.mode == 'vertical') { $parent.animate({ 'top': '-' + getSlidePosition(slide, 'top') + 'px' }, options.speed, options.easing, function () { isWorking = false; // perform the callback function options.onAfterSlide(currentSlide, $children.length, $children.eq(currentSlide)); }); // fade } else if (options.mode == 'fade') { setChildrenFade(); } // check to remove controls on last/first slide checkEndControls(); // accomodate multi slides if (options.moveSlideQty > 1) { number = Math.floor(number / options.moveSlideQty); } // make the current slide active makeSlideActive(number); // display the caption showCaptions(); } } /** * Go to next slide */ this.goToNextSlide = function (stopAuto) { // check if stopAuto argument is supplied if (typeof (stopAuto) == 'undefined') { var stopAuto = true; } if (stopAuto) { // if show is auto playing, stop it if (options.auto) { base.stopShow(true); } } // makes slideshow finite if (!options.infiniteLoop) { if (!isWorking) { var slideLoop = false; // make current slide the old value plus moveSlideQty currentSlide = (currentSlide + (options.moveSlideQty)); // if current slide has looped on itself if (currentSlide <= lastSlide) { checkEndControls(); // next slide callback options.onNextSlide(currentSlide, $children.length, $children.eq(currentSlide)); // move to appropriate slide base.goToSlide(currentSlide); } else { currentSlide -= options.moveSlideQty; } } // end if(!isWorking) } else { if (!isWorking) { isWorking = true; var slideLoop = false; // make current slide the old value plus moveSlideQty currentSlide = (currentSlide + options.moveSlideQty); // if current slide has looped on itself if (currentSlide > lastSlide) { currentSlide = currentSlide % $children.length; slideLoop = true; } // next slide callback options.onNextSlide(currentSlide, $children.length, $children.eq(currentSlide)); // slide before callback options.onBeforeSlide(currentSlide, $children.length, $children.eq(currentSlide)); if (options.mode == 'horizontal') { // get the new 'left' property for $parent var parentLeft = (options.moveSlideQty * childrenOuterWidth); // animate to the new 'left' $parent.animate({ 'left': '-=' + parentLeft + 'px' }, options.speed, options.easing, function () { isWorking = false; // if its time to loop, reset the $parent if (slideLoop) { $parent.css('left', '-' + getSlidePosition(currentSlide, 'left') + 'px'); } // perform the callback function options.onAfterSlide(currentSlide, $children.length, $children.eq(currentSlide)); }); } else if (options.mode == 'vertical') { // get the new 'left' property for $parent var parentTop = (options.moveSlideQty * childrenMaxHeight); // animate to the new 'left' $parent.animate({ 'top': '-=' + parentTop + 'px' }, options.speed, options.easing, function () { isWorking = false; // if its time to loop, reset the $parent if (slideLoop) { $parent.css('top', '-' + getSlidePosition(currentSlide, 'top') + 'px'); } // perform the callback function options.onAfterSlide(currentSlide, $children.length, $children.eq(currentSlide)); }); } else if (options.mode == 'fade') { setChildrenFade(); } // make the current slide active if (options.moveSlideQty > 1) { makeSlideActive(Math.ceil(currentSlide / options.moveSlideQty)); } else { makeSlideActive(currentSlide); } // display the caption showCaptions(); } // end if(!isWorking) } } // end function /** * Go to previous slide */ this.goToPreviousSlide = function (stopAuto) { // check if stopAuto argument is supplied if (typeof (stopAuto) == 'undefined') { var stopAuto = true; } if (stopAuto) { // if show is auto playing, stop it if (options.auto) { base.stopShow(true); } } // makes slideshow finite if (!options.infiniteLoop) { if (!isWorking) { var slideLoop = false; // make current slide the old value plus moveSlideQty currentSlide = currentSlide - options.moveSlideQty; // if current slide has looped on itself if (currentSlide < 0) { currentSlide = 0; // if specified, hide the control on the last slide if (options.hideControlOnEnd) { $('.bx-prev', $outerWrapper).hide(); } } checkEndControls(); // next slide callback options.onPrevSlide(currentSlide, $children.length, $children.eq(currentSlide)); // move to appropriate slide base.goToSlide(currentSlide); } } else { if (!isWorking) { isWorking = true; var slideLoop = false; // make current slide the old value plus moveSlideQty currentSlide = (currentSlide - (options.moveSlideQty)); // if current slide has looped on itself if (currentSlide < 0) { negativeOffset = (currentSlide % $children.length); if (negativeOffset == 0) { currentSlide = 0; } else { currentSlide = ($children.length) + negativeOffset; } slideLoop = true; } // next slide callback options.onPrevSlide(currentSlide, $children.length, $children.eq(currentSlide)); // slide before callback options.onBeforeSlide(currentSlide, $children.length, $children.eq(currentSlide)); if (options.mode == 'horizontal') { // get the new 'left' property for $parent var parentLeft = (options.moveSlideQty * childrenOuterWidth); // animate to the new 'left' $parent.animate({ 'left': '+=' + parentLeft + 'px' }, options.speed, options.easing, function () { isWorking = false; // if its time to loop, reset the $parent if (slideLoop) { $parent.css('left', '-' + getSlidePosition(currentSlide, 'left') + 'px'); } // perform the callback function options.onAfterSlide(currentSlide, $children.length, $children.eq(currentSlide)); }); } else if (options.mode == 'vertical') { // get the new 'left' property for $parent var parentTop = (options.moveSlideQty * childrenMaxHeight); // animate to the new 'left' $parent.animate({ 'top': '+=' + parentTop + 'px' }, options.speed, options.easing, function () { isWorking = false; // if its time to loop, reset the $parent if (slideLoop) { $parent.css('top', '-' + getSlidePosition(currentSlide, 'top') + 'px'); } // perform the callback function options.onAfterSlide(currentSlide, $children.length, $children.eq(currentSlide)); }); } else if (options.mode == 'fade') { setChildrenFade(); } // make the current slide active if (options.moveSlideQty > 1) { makeSlideActive(Math.ceil(currentSlide / options.moveSlideQty)); } else { makeSlideActive(currentSlide); } // display the caption showCaptions(); } // end if(!isWorking) } } // end function /** * Go to first slide */ this.goToFirstSlide = function (stopAuto) { // check if stopAuto argument is supplied if (typeof (stopAuto) == 'undefined') { var stopAuto = true; } base.goToSlide(firstSlide, stopAuto); } /** * Go to last slide */ this.goToLastSlide = function () { // check if stopAuto argument is supplied if (typeof (stopAuto) == 'undefined') { var stopAuto = true; } base.goToSlide(lastSlide, stopAuto); } /** * Get the current slide */ this.getCurrentSlide = function () { return currentSlide; } /** * Get the total slide count */ this.getSlideCount = function () { return $children.length; } /** * Stop the slideshow */ this.stopShow = function (changeText) { clearInterval(interval); // check if changeText argument is supplied if (typeof (changeText) == 'undefined') { var changeText = true; } if (changeText && options.autoControls) { $autoControls.html($startContent).removeClass('stop').addClass('start'); autoPlaying = false; } } /** * Start the slideshow */ this.startShow = function (changeText) { // check if changeText argument is supplied if (typeof (changeText) == 'undefined') { var changeText = true; } setAutoInterval(); if (changeText && options.autoControls) { $autoControls.html($stopContent).removeClass('start').addClass('stop'); autoPlaying = true; } } /** * Stops the ticker */ this.stopTicker = function (changeText) { $parent.stop(); // check if changeText argument is supplied if (typeof (changeText) == 'undefined') { var changeText = true; } if (changeText && options.ticker) { $autoControls.html($startContent).removeClass('stop').addClass('start'); autoPlaying = false; } } /** * Starts the ticker */ this.startTicker = function (changeText) { if (options.mode == 'horizontal') { if (options.tickerDirection == 'next') { // get the 'left' property where the ticker stopped var stoppedLeft = parseInt($parent.css('left')); // calculate the remaining distance the show must travel until the loop var remainingDistance = (origShowWidth + stoppedLeft) + $children.eq(0).width(); } else if (options.tickerDirection == 'prev') { // get the 'left' property where the ticker stopped var stoppedLeft = -parseInt($parent.css('left')); // calculate the remaining distance the show must travel until the loop var remainingDistance = (stoppedLeft) - $children.eq(0).width(); } // calculate the speed ratio to seamlessly finish the loop var finishingSpeed = (remainingDistance * options.tickerSpeed) / origShowWidth; // call the show moveTheShow(tickerLeft, remainingDistance, finishingSpeed); } else if (options.mode == 'vertical') { if (options.tickerDirection == 'next') { // get the 'top' property where the ticker stopped var stoppedTop = parseInt($parent.css('top')); // calculate the remaining distance the show must travel until the loop var remainingDistance = (origShowHeight + stoppedTop) + $children.eq(0).height(); } else if (options.tickerDirection == 'prev') { // get the 'left' property where the ticker stopped var stoppedTop = -parseInt($parent.css('top')); // calculate the remaining distance the show must travel until the loop var remainingDistance = (stoppedTop) - $children.eq(0).height(); } // calculate the speed ratio to seamlessly finish the loop var finishingSpeed = (remainingDistance * options.tickerSpeed) / origShowHeight; // call the show moveTheShow(tickerTop, remainingDistance, finishingSpeed); // check if changeText argument is supplied if (typeof (changeText) == 'undefined') { var changeText = true; } if (changeText && options.ticker) { $autoControls.html($stopContent).removeClass('start').addClass('stop'); autoPlaying = true; } } } /** * Initialize a new slideshow */ this.initShow = function () { // reinitialize all variables // base = this; $parent = $(this); $origElement = $parent.clone(); $children = $parent.children(); $outerWrapper = ''; $firstChild = $parent.children(':first'); childrenWidth = 145; childrenMaxWidth = 0; childrenOuterWidth = $firstChild.outerWidth(); childrenMaxHeight = 0; wrapperWidth = getWrapperWidth(); wrapperHeight = getWrapperHeight(); isWorking = false; $pager = ''; currentSlide = 0; origLeft = 0; origTop = 0; interval = ''; $autoControls = ''; $stopHtml = ''; $startContent = ''; $stopContent = ''; autoPlaying = true; loaded = false; origShowWidth = 0; origShowHeight = 0; tickerLeft = 0; tickerTop = 0; firstSlide = 0; lastSlide = $children.length - 1; // get the largest child's height and width $children.each(function (index) { if ($(this).outerHeight() > childrenMaxHeight) { childrenMaxHeight = $(this).outerHeight(); } if ($(this).outerWidth() > childrenMaxWidth) { childrenMaxWidth = $(this).outerWidth(); } }); // get random slide number if (options.randomStart) { var randomNumber = Math.floor(Math.random() * $children.length); currentSlide = randomNumber; origLeft = childrenOuterWidth * (options.moveSlideQty + randomNumber); origTop = childrenMaxHeight * (options.moveSlideQty + randomNumber); // start show at specific slide } else { currentSlide = options.startingSlide; origLeft = childrenOuterWidth * (options.moveSlideQty + options.startingSlide); origTop = childrenMaxHeight * (options.moveSlideQty + options.startingSlide); } // set initial css initCss(); // check to show pager if (options.pager && !options.ticker) { if (options.pagerType == 'full') { showPager('full'); } else if (options.pagerType == 'short') { showPager('short'); } } // check to show controls if (options.controls && !options.ticker) { setControlsVars(); } // check if auto if (options.auto || options.ticker) { // check if auto controls are displayed if (options.autoControls) { setAutoControlsVars(); } // check if show should auto start if (options.autoStart) { // check if autostart should delay setTimeout(function () { base.startShow(true); }, options.autoDelay); } else { base.stopShow(true); } // check if show should pause on hover if (options.autoHover && !options.ticker) { setAutoHover(); } } // make the starting slide active if (options.moveSlideQty > 1) { makeSlideActive(Math.ceil(currentSlide / options.moveSlideQty)); } else { makeSlideActive(currentSlide); } // check for finite show and if controls should be hidden checkEndControls(); // show captions if (options.captions) { showCaptions(); } // perform the callback function options.onAfterSlide(currentSlide, $children.length, $children.eq(currentSlide)); if (options.displaySlideQty < 4) { $('#prev').hide(); $('#next').hide(); } } /** * Destroy the current slideshow */ this.destroyShow = function () { // stop the auto show clearInterval(interval); // remove any controls / pagers that have been appended $('.bx-next, .bx-prev, .bx-pager, .bx-auto', $outerWrapper).remove(); // unwrap all bx-wrappers $parent.unwrap().unwrap().removeAttr('style'); // remove any styles that were appended $parent.children().removeAttr('style').not('.pager').remove(); // remove any childrent that were appended $children.removeClass('pager'); } /** * Reload the current slideshow */ this.reloadShow = function () { base.destroyShow(); base.initShow(); } // PRIVATE FUNCTIONS /** * Creates all neccessary styling for the slideshow */ function initCss() { // layout the children setChildrenLayout(options.startingSlide); // CSS for horizontal mode if (options.mode == 'horizontal') { // wrap the