// mislider // copyright 2014 john bowyer-smyth // this file is part of mislider. // mislider is free software: you can redistribute it and/or modify // it under the terms of the gnu general public license as published by // the free software foundation, either version 3 of the license, or // (at your option) any later version. // mislider is distributed in the hope that it will be useful, // but without any warranty; without even the implied warranty of // merchantability or fitness for a particular purpose. see the // gnu general public license for more details. // you should have received a copy of the gnu general public license // along with this program. if not, see http://www.gnu.org/licenses/ ; (function ($, window, document, math, undefined) { var mislider = function (stageel, options) { // clone mislider object var o = this; // initialize option defaults ------------------------------------------------------------------------ o.optionsinit = { // the speed of the slide transition in milliseconds. options: positive integer. speed: 700, // slide pause time between transitions in milliseconds. options: false, positive integer. false = autoplay off. pause: 4000, // the number of slides to increment with autoplay and nav buttons. options: positive or negative integer. positive integer = slide left. negative integer = slide right. increment: 1, // the height of the stage in px. options: false or positive integer. false = height is calculated using maximum slide heights. stageheight: false, // number of slides visible at one time. options: false or positive integer. false = fit as many as possible. slidesonstage: 1, // continuous motion - boolean. true = slides loop in one direction if possible. slidescontinuous: true, // the location of the current slide on the stage. options: 'left', 'right', 'center'. slideposition: 'left', // the slide to start on. options: 'beg', 'mid', 'end' or slide number starting at 1 - '1','2','3', etc. slidestart: 'beg', // the width of the current slide in px. options: false or positive integer. false = width is the maximum of the existing slide widths. slidewidth: false, // the relative percentage scaling factor of the current slide - other slides are scaled down. options: positive number 100 or higher. 100 = no scaling. slidescaling: 100, // the vertical offset of the slide center as a percentage of slide height. options: positive or negative number. neg value = up. pos value = down. 0 = no offset. offsetv: 0, // center slide contents vertically - boolean. centerv: false, // enable numbered list navigation - boolean. navlist: true, // enable prev and next button navigation - boolean. navbuttons: true, // always show prev and next button navigation except when transitioning - boolean. navbuttonsshow: false, // opacity of the prev and next button navigation when not transitioning. options: number between 0 and 1. 0 (transparent) - 1 (opaque). navbuttonsopacity: 0.5, // randomize the order of the slides - boolean. randomize: false, // the slides loaded call back function - called when slides have loaded. slidesloaded: false, // the slide transition before call back function - called before the slide transition. beforetrans: false, // the slide transition complete call back function - called at the end of a slide transition. aftertrans: false, // the css class that will be applied to the stage element. classstage: 'mis-stage', // the css class that will be applied to the slider element. classslider: 'mis-slider', // the css class that will be applied to each slide element. classslide: 'mis-slide', // the css class that will be applied to the parent of the prev and next button navigation elements. classnavbuttons: 'mis-nav-buttons', // the css class that will be applied to the parent of the numbered list navigation elements classnavlist: 'mis-nav-list', // the selector used to select the slider element - descendant of the stage selectorslider: 'ol', // the selector used to select each slide element - descendant of the slider selectorslide: 'li', // use modernizr to test feature support - csstransforms modernizrbool: false, }; // define objects and vars ------------------------------------------------------------------------------ // objects o.options = {}; // merged options o.stage = false; // slider container element o.slider = false; // slider element - container for slides o.slides = false; // the collection of slides o.navbuttons = false; // the nav buttons element o.prev = false; // the 'previous' nav button o.next = false; // the 'next' nav button o.navlist = false; // the nav list element o.navlistitems = false; // the nav list items collection o.slidecurrent = false; // current slide o.animatedelements = $(); // a collection of all the elements that animate // calculated widths and heights o.stagewidth = 0; // the existing width of the stage o.stageheight = 0; // the calculated height of stage o.sliderwidth = 0; // the calculated width of slider o.slidewidth = 0; // slide calculated width of non-current slides o.slidewidthcurrent = 0; // slide calculated width of current slide // calculated scaling vars o.slidescaling = o.optionsinit.slidescaling; // the calculated relative percentage scaling factor of the current slide o.scalingwidth = 0; // the calculated scaling width o.scalingmargin = 0; // the calculated scaling margin o.offsetv = o.optionsinit.offsetv; // the vertical offset of the slide center // slide counts o.slideslengthorig = 0; // the original number of slides in collection o.slideslength = 0; // the number of slides in collection including cloned slides o.indexcurrent = 0; // current slide index o.indexfirst = 0; // the index of the first unique slide o.indexlast = 0; // the index of the last unique slide o.increment = o.optionsinit.increment; // the calculated number of slides to increment with autoplay and nav buttons o.slidesonstage = o.optionsinit.slidesonstage; // the calculated number of slides on stage // slider settings o.speed = o.optionsinit.speed; // the calculated speed o.navbuttonsopacity = o.optionsinit.navbuttonsopacity; // the calculted nav buttons opacity o.navbuttonsfade = false; // the calculated prev and next button navigation fade boolean o.slidescontinuous = o.optionsinit.slidescontinuous; // the calculated continuous motion boolean. o.pause = o.optionsinit.pause; // the normalized pause value // functions o.timer = false; // interval timer function o.resizetimer = false; // window resize timer function o.after = false; // temporary after transition callback function // classes o.classslideclone = 'mis-clone'; // class applied to the cloned slides o.classslidecontainer = 'mis-container'; // class of slide container - inserted around the contents of each slide o.classcurrent = 'mis-current'; // class applied to the the current slides and current nav list item o.classprev = 'mis-prev'; // class applied to the the 'previous' button o.classnext = 'mis-next'; // class applied to the the 'next' button // initiate slider ================================================================================== o.init = function (stageel, options) { // must only be called once // set options o.options = $.extend({}, o.optionsinit, options); // initiate elements o.stage = $(stageel); o.stage.fadeto(0, 0); // hide everything while we get setup o.slider = o.stage.children(o.options.selectorslider).first(); // only one slider per stage o.slides = o.slider.children(o.options.selectorslide); o.slideslengthorig = o.slides.length; o.animatedelements = o.animatedelements.add(o.slider); // initiate current index if (string(o.options.slidestart) === 'beg') { o.indexcurrent = 0; } else if (string(o.options.slidestart) === 'mid') { o.indexcurrent = math.ceil(o.slideslengthorig / 2) - 1; } else if (string(o.options.slidestart) === 'end') { o.indexcurrent = o.slideslengthorig - 1; } else if ($.isnumeric(o.options.slidestart) && parseint(o.options.slidestart) <= o.slideslengthorig && parseint(o.options.slidestart) > 0) { o.indexcurrent = parseint(o.options.slidestart) - 1; } else { o.indexcurrent = 0; } // randomize slides if (o.options.randomize) { o.randomize(); } // add classes to stage and slider if (!o.stage.hasclass(o.options.classstage)) { o.stage.addclass(o.options.classstage); } if (!o.slider.hasclass(o.options.classslider)) { o.slider.addclass(o.options.classslider); } // normalize static options if (o.options.speed && $.isnumeric(o.options.speed)) { o.speed = math.abs(parseint(o.options.speed)); } if (o.options.pause === false) { // note: 0 must return true o.pause = false; } else if ($.isnumeric(o.options.pause)) { o.pause = math.abs(parseint(o.options.pause)); } if ($.isnumeric(o.options.offsetv)) { o.offsetv = number(o.options.offsetv); } if ($.isnumeric(o.options.navbuttonsopacity) && number(o.options.navbuttonsopacity) >= 0 && number(o.options.navbuttonsopacity) <= 1) { o.navbuttonsopacity = number(o.options.navbuttonsopacity); } // initiate calculated scaling factor if ($.isnumeric(o.options.slidescaling) && number(o.options.slidescaling) >= 100) { o.slidescaling = number(o.options.slidescaling); } if (!o.supporttransform(o.options.modernizrbool, stageel)) { // css transforms are not supported o.slidescaling = 100; } o.optionsinit.slidescaling = o.slidescaling; // initiate the calculated increment if ($.isnumeric(o.options.increment) && parseint(o.options.increment) !== 0) { o.increment = parseint(o.options.increment); o.optionsinit.increment = o.increment; } // add previous and next nav buttons if (o.options.navbuttons) { o.addnavbuttons(o.stage); o.animatedelements = o.animatedelements.add(o.navbuttons); if (!o.options.navbuttonsshow) { o.navbuttonsfade = true; } } // add numbered list navigation if (o.options.navlist) { o.addnavlist(); } // set up the slider o.setup(); // add event handlers ---------------------------------------------------------------------------- // add click events to slides if (o.slidesonstage > 1) { o.slider.on('click', o.options.selectorslide, function (e) { if ($(this).index() !== o.indexcurrent) { e.preventdefault(); o.autoplayoff(); o.transition($(this).index(), false, o.autoplayon(o.increment)); } }); } // add hover events for controling autoplay and nav button opacity if (o.pause !== false || o.navbuttonsfade) { // note: 0 must return true for o.pause o.stage.on({ 'mouseenter': function () { if (o.pause !== false) { o.autoplayoff(); } if (o.navbuttonsfade) { if (!o.animatedelements.is(':animated')) { o.navbuttons.fadeto(400, o.navbuttonsopacity); } else { if ($.isfunction(o.after)) { var after = o.after; o.after = function () { after(); o.navbuttons.fadeto(400, o.navbuttonsopacity); }; } else { o.after = function () { o.navbuttons.fadeto(400, o.navbuttonsopacity); }; } } } }, 'mouseleave': function () { if (o.pause !== false) { o.autoplayon(o.increment); } if (o.navbuttonsfade) { o.navbuttons.fadeto(100, 0); } } }); } // window events $(window).on({ // wait for slides to load before setting up slides and nav buttons 'load': function () { // setup slides and nav buttons o.slidesetup(); o.updatenavbuttons(); // fade in everything o.stage.fadeto(600, 1); // autoplay slides if enabled o.autoplayon(o.increment); // slides loaded callback if ($.isfunction(o.options.slidesloaded)) { o.options.slidesloaded(); } }, // reset slider on screen resize 'resize': function () { o.autoplayoff(); cleartimeout(o.resizetimer); o.resizetimer = settimeout(function () { o.resetslider(); }, 500); } }); return this; }; // setup slider ====================================================================================== o.setup = function () { // set slides length o.slideslength = o.slideslengthorig; o.indexlast = o.slideslength - 1; // get widths, heights, add slide class and container o.slides.each(function () { var slide = $(this); // add slide class to slide if (!slide.hasclass(o.options.classslide)) { slide.addclass(o.options.classslide); } // add slide container to slide if (!slide.children().hasclass(o.classslidecontainer)) { slide.wrapinner('
'); } // get widths and heights var width = slide.outerwidth(); var height = slide.outerheight(); if (width > o.slidewidthcurrent) { o.slidewidthcurrent = width; } if (height > o.stageheight) { o.stageheight = height; } }); // apply presets if they exist if ($.isnumeric(o.options.slidewidth) && parseint(o.options.slidewidth) > 0) { o.slidewidthcurrent = parseint(o.options.slidewidth); } if ($.isnumeric(o.options.stageheight) && parseint(o.options.stageheight) > 0) { o.stageheight = parseint(o.options.stageheight); } // use modulus hack to ensure current index is within range o.indexcurrent = o.normalizeindex(o.indexcurrent); // set the stage ---------------------------------------------------------------------------------- // set css o.stage.css({ 'height': o.stageheight, }); // get stage width - must do this after setting height o.stagewidth = o.stage.outerwidth(); // calculate slide scaling, widths, increment and slides on and off stage ------------------ // determine the maximum number of slides that fit on the stage var slidesmaxnum = math.floor((o.stagewidth - o.slidewidthcurrent) / (o.slidewidthcurrent * 100 / o.slidescaling)) + 1; slidesmaxnum = (slidesmaxnum < 1) ? 1 : slidesmaxnum; // must have at least 1 // calculate the number of slides visible on the stage o.slidesonstage = slidesmaxnum; // fit as many as possible if ($.isnumeric(o.options.slidesonstage) && parseint(o.options.slidesonstage) >= 1 && parseint(o.options.slidesonstage) <= slidesmaxnum) { o.slidesonstage = parseint(o.options.slidesonstage); // use existing options value } if (o.options.slideposition === 'center') { // need odd number for centered layout o.slidesonstage = (math.ceil(o.slidesonstage / 2) * 2) - 1; } // the absolute increment number should not be greater than slides on stage var x = (o.increment + o.slidesonstage) / 2; if (x > o.slidesonstage) { // increment is positive and more than slides on stage o.increment = o.slidesonstage; } else if (x < 0) { // increment is negative and more than slides on stage o.increment = -o.slidesonstage; } // calculate the current and non-current slide widths if (o.slidesonstage > 1) { // modify non-current slide width to accommodate correct number of slides on the stage o.slidewidth = (o.stagewidth - o.slidewidthcurrent) / (o.slidesonstage - 1); if (o.slidewidthcurrent < o.slidewidth && !o.options.slidewidth) { // set slidewidth and slidewidthcurrent to be the same o.slidewidth = o.stagewidth / o.slidesonstage; o.slidewidthcurrent = o.slidewidth; } } else { // make slide widths full width of stage o.slidewidth = o.stagewidth; o.slidewidthcurrent = o.slidewidth; o.slidescaling = 100; } // set scaling width and margin o.scalingwidth = o.slidewidth * o.slidescaling / 100; o.scalingmargin = (o.slidewidth - o.scalingwidth) / 2; // determine the number of slides off stage var slidesoffstage = o.slideslengthorig - o.slidesonstage; // clone last slidestoclone slides to beginning and first slidestoclone slides to end --------------- if ((slidesoffstage >= 0) && (o.options.slidescontinuous)) { // set calculated continuous motion boolean to true o.slidescontinuous = true; // determine the number of slides to clone o.slidestoclone = o.slidesonstage + math.abs(o.increment) - 1; // prepend last slidestoclone slides o.slides.slice(o.slideslength - o.slidestoclone) .clone() .addclass(o.classslideclone) .removeattr('id') .prependto(o.slider) .find('*').removeattr('id'); // append first slidestoclone slides o.slides.slice(0, o.slidestoclone) .clone() .addclass(o.classslideclone) .removeattr('id') .appendto(o.slider) .find('*').removeattr('id'); // adjust indexes o.indexfirst = o.slidestoclone; o.indexlast = o.slideslength + o.slidestoclone - 1; o.indexcurrent = o.indexcurrent + o.slidestoclone; // refresh slides o.slides = o.slider.children(o.options.selectorslide); o.slideslength = o.slides.length; } else { o.slidescontinuous = false; } // update current slide o.slidecurrent = o.slides.eq(o.indexcurrent); o.animatedelements = o.animatedelements.add(o.slides); // set the horizontal position, width and other css of the slider --------------------------------- // calculate the width of the slider o.sliderwidth = o.slidewidthcurrent + (o.slidewidth * (o.slideslength - 1)) + 1; // set css of slider o.slider .css({ 'left': o.leftoffset(o.indexcurrent), 'width': o.sliderwidth, }) ; // update navlist o.updatenavlist(o.indexcurrent); return this; }; // transition control function ========================================================================= o.transition = function (indexto, beforetrans, aftertrans, navbuttonsfadein) { // if slider is not animated and indexto != current index - continue if (!o.animatedelements.is(':animated') && indexto !== o.indexcurrent) { // define indexes that might be adjusted var indextoadjusted = indexto; var indexcurrentadjusted = o.indexcurrent; // update indexes and slides if continuous and slides are out of bounds ------------------------ if (o.slidescontinuous) { // get adjusted indexto if slides are out of bounds if (indexto < o.indexfirst) { indextoadjusted = indexto + o.slideslengthorig; } else if (indexto > o.indexlast) { indextoadjusted = indexto - o.slideslengthorig; } if (indextoadjusted !== indexto) { // indexto is out of bounds // adjust current index indexcurrentadjusted = o.indexcurrent + o.slideslengthorig; if (indextoadjusted < indexto) { indexcurrentadjusted = o.indexcurrent - o.slideslengthorig; } } } else { // use modulus hack to ensure adjusted index is within range indextoadjusted = o.normalizeindex(indexto); } // get the normalized difference between indexes var indexdiff = o.normalizeindex(indextoadjusted) - o.normalizeindex(indexcurrentadjusted); // if adjusted indexto != adjusted current index - do move -------------------------------------- if (indexdiff) { // call 'before transition' functions if ($.isfunction(beforetrans)) { beforetrans(); } if ($.isfunction(o.options.beforetrans)) { o.options.beforetrans(); } // construct after transition function var after = function () { // call aftertrans local function if ($.isfunction(aftertrans)) { aftertrans(); } // call aftertrans pre-defined function if ($.isfunction(o.options.aftertrans)) { o.options.aftertrans(); } // call temporary callback function if ($.isfunction(o.after)) { o.after(); o.after = false; } }; // swap current slide if continuous and current index needs to be adjusted -------------------- if (o.slidescontinuous && indexcurrentadjusted !== o.indexcurrent) { var slidecurrentadjusted = o.slides.eq(indexcurrentadjusted); // prepare current slide's clone if (o.slidescaling !== 100) { // scale slide slidecurrentadjusted.css({ 'transform': 'scale(1)', 'width': o.slidewidthcurrent, 'marginleft': '0', 'marginright': '0', 'borderspacing': '100px', // value placeholder used with step function to animate tranform }); // vertically center slide if enabled if (o.options.centerv) { slidecurrentadjusted.children().first().css('margintop', slidecurrentadjusted.data('slidemargintopcurrent')); } } // add current class to current slide slidecurrentadjusted .addclass(o.classcurrent) .siblings() .removeclass(o.classcurrent) ; // jump to clone o.slider.css('left', o.leftoffset(indexcurrentadjusted)); // reset original if (o.slidescaling !== 100) { // scale slide o.slidecurrent.css({ 'transform': 'scale(' + (100 / o.slidescaling) + ')', 'width': o.scalingwidth, 'marginleft': o.scalingmargin, 'marginright': o.scalingmargin, 'borderspacing': o.slidescaling, // value placeholder used with step function to animate tranform }); // vertically center slide if enabled if (o.options.centerv) { o.slidecurrent.children().first().css('margintop', o.slidecurrent.data('slidemargintop')); } } // update current index and slide o.indexcurrent = indexcurrentadjusted; o.slidecurrent = o.slides.eq(o.indexcurrent); } // transition ---------------------------------------------------------------------------- if (o.navbuttons) { // fadein nav buttons before move if fadein bool true o.navbuttons.fadeto(100, (navbuttonsfadein) ? o.navbuttonsopacity : 0, function () { // fadeout nav buttons before move o.navbuttons.fadeto(100, 0, // fadeout nav buttons before move function () { // do transition o.animateslides(indextoadjusted, function () { if (o.stage.find(':hover').length || o.options.navbuttonsshow) { // fadein nav buttons after move o.navbuttons.fadeto(400, o.navbuttonsopacity, after); } else { after(); } } ); } ); } ); } else { // do transition o.animateslides(indextoadjusted, after); } } } return this; }; // animate slide transition ========================================================================== o.animateslides = function (indexto, aftertrans) { // remove current class from current slide o.slidecurrent.removeclass(o.classcurrent); // define the slide to move to var slideto = o.slides.eq(indexto); if (o.slidescaling !== 100) { // only scale if needed // scale new slide --------------------------------------------------------------------------- slideto .animate({ 'marginleft': '0', 'marginright': '0', 'width': o.slidewidthcurrent }, { duration: o.speed, queue: false, }) .animate({ 'borderspacing': '100px' }, { // must use step function to animate scaling step: function (now) { $(this).css({ 'transform': 'scale(' + 100 / now + ')', }); }, duration: o.speed, queue: false, }) ; // scale current slide --------------------------------------------------------------------- o.slidecurrent .animate({ 'marginleft': o.scalingmargin, 'marginright': o.scalingmargin, 'width': o.scalingwidth }, { duration: o.speed, queue: false, }) .animate({ 'borderspacing': o.slidescaling }, { // must use step function to animate scaling step: function (now) { $(this).css({ 'transform': 'scale(' + 100 / now + ')', }); }, duration: o.speed, queue: false, }) ; // animate slide contents margin if vertically center slide is enabled --------------------- if (o.options.centerv) { // animate new slide content slideto.children().first() .animate({ 'margintop': slideto.data('slidemargintopcurrent'), }, { duration: o.speed, queue: false, }) ; // animate current slide content o.slidecurrent.children().first() .animate({ 'margintop': o.slidecurrent.data('slidemargintop'), }, { duration: o.speed, queue: false, }) ; } } // move to new slide --------------------------------------------------------------------------- o.slider.animate({ 'left': o.leftoffset(indexto) }, { duration: o.speed, queue: false, complete: function () { // transition complete // update current index and slide o.indexcurrent = indexto; o.slidecurrent = slideto; // update navlist o.updatenavlist(indexto); // add current class to current slide o.slidecurrent .addclass(o.classcurrent) .siblings() .removeclass(o.classcurrent) ; // execute callbacks if ($.isfunction(aftertrans)) { aftertrans(); } } }); return this; }; // playback control functions ====================================================================== // autoplay on ------------------------------------------------------------------------------------- o.autoplayon = function (incr) { if (o.pause !== false) { // autoplay is enabled // reset timer o.timer = clearinterval(o.timer); if (!o.stage.find(':hover').length) { // slider is not in hover state o.timer = setinterval(function () { // if not transitioning do transition if (!o.animatedelements.is(':animated')) { o.transition(o.indexcurrent + incr); } }, o.pause); } } return this; }; // autoplay off ------------------------------------------------------------------------------------ o.autoplayoff = function () { o.timer = clearinterval(o.timer); return this; }; // add navbuttons ------------------------------------------------------------------------------------ o.addnavbuttons = function (element) { // parent element to append nav buttons to var $el = $(element); // construct html var navbuttons = $('
prevnext
'); // apply css and click events to buttons navbuttons .css({ 'opacity': ((o.options.navbuttonsshow) ? o.navbuttonsopacity : 0), }) .children('a') .on('click', function (e) { e.preventdefault(); if (this.classname === o.classprev) { o.autoplayoff(); o.transition(o.indexcurrent - math.abs(o.increment), false, o.autoplayon(o.increment), true); } else if (this.classname === o.classnext) { o.autoplayoff(); o.transition(o.indexcurrent + math.abs(o.increment), false, o.autoplayon(o.increment), true); } }) ; // append buttons to stage $el.append(navbuttons); // define cached objects o.navbuttons = $el.find('.' + o.options.classnavbuttons); o.prev = o.navbuttons.find('.' + o.classprev); o.next = o.navbuttons.find('.' + o.classnext); return this; }; // update nav buttons -------------------------------------------------------------------------------- o.updatenavbuttons = function () { if (o.navbuttons) { // apply css to buttons o.navbuttons .css({ 'width': o.slidewidthcurrent, 'left': (o.slidecurrent.offset().left - o.stage.offset().left), }) .children('a') .css({ 'height': o.stageheight, 'paddingtop': (50 + o.offsetv) * o.stageheight / 100, }) ; } }; // add navlist -------------------------------------------------------------------------------------- o.addnavlist = function () { // define list var listhtml = '
    '; // create each list item o.slides.each(function (index) { // define the text for the list item var itemtext = index + 1; // use header, figcaption, or img title as list item text instead var caption = $(this).find(':header').sort(function (a,b) { var atag = $(a).prop('tagname'), btag = $(b).prop('tagname'); return parseint(atag.match(/\d+/), 10) - parseint(btag.match(/\d+/), 10); }).eq(0).html(); if (caption) { itemtext = caption; } else { caption = $(this).find('figcaption').eq(0).html(); if (caption) { itemtext = caption; } else { caption = $(this).find('img').eq(0).attr('title'); if (caption) { itemtext = caption; } } } // add list item to list listhtml += '
  1. ' + itemtext + '
  2. '; }); // close list listhtml += '
'; // create temporary list object and add click events var navlist = $(listhtml) .on('click', 'li', function (e) { e.preventdefault(); if ($(this).index() !== (o.indexcurrent - o.indexfirst)) { o.autoplayoff(); o.transition($(this).index() + o.indexfirst, false, o.autoplayon(o.increment)); } }) ; // prepend list to slider and update cached objects o.stage.prepend(navlist); o.navlist = o.stage.children().first(); o.navlistitems = o.navlist.children('li'); return this; }; // update navlist ------------------------------------------------------------------------------------ o.updatenavlist = function (index) { if (o.navlistitems.length) { o.navlistitems .eq(index - o.indexfirst) .addclass(o.classcurrent) .siblings() .removeclass(o.classcurrent) ; } }; // assorted functions ============================================================================== // randomizer -------------------------------------------------------------------------------------- o.randomize = function () { // randomize cached slides o.slides.sort(function () { return (0.5 - math.random()); }); // apply randomized slides to page o.slides.detach().appendto(o.slider); return this; }; // slider left offset calculator ------------------------------------------------------------------ o.leftoffset = function (index) { var indexoffset = o.slidewidth * index * -1; var leftoffset = indexoffset; // slide position = left if (o.options.slideposition === 'center') { leftoffset = (indexoffset + (math.floor(o.slidesonstage / 2) * o.slidewidth)); } else if (o.options.slideposition === 'right') { leftoffset = (indexoffset + ((o.slidesonstage - 1) * o.slidewidth)); } return leftoffset; }; // reset slider ---------------------------------------------------------------------------------- o.resetslider = function () { if (o.animatedelements.is(':animated')) { // reset slider after transition has finished if ($.isfunction(o.after)) { var after = o.after; o.after = function () { after(); o.resetslider; }; } else { o.after = o.resetslider; } } else { // resets o.autoplayoff(); o.stage.removeattr('style'); o.slider.removeattr('style'); o.slides.removeattr('style'); o.slides.filter('.' + o.classslideclone).remove(); o.slides = o.slider.children(o.options.selectorslide); o.stageheight = 0; o.slidewidthcurrent = 0; o.slidescaling = o.optionsinit.slidescaling; o.indexcurrent -= o.slidestoclone; o.indexfirst = 0; o.increment = o.optionsinit.increment; o.after = false; // setup o.setup(); o.slidesetup(); o.updatenavbuttons(); o.autoplayon(o.increment); } return this; }; // use modulus hack to make sure index is within range ----------------------------------------------------- o.normalizeindex = function (index) { index = ((index % o.slideslengthorig) + o.slideslengthorig) % o.slideslengthorig; return index; }; // setup slides function ----------------------------------------------------------------------------------- o.slidesetup = function () { o.slides.each(function (i) { var slide = $(this); // set transform origin and current width slide.css({ 'transform-origin': '50% ' + string(50 + o.offsetv) + '%', 'width': o.slidewidthcurrent, }); // get vertical slide offset if enabled if (o.options.centerv) { o.getmargintop(slide, 'slidemargintopcurrent'); } // set non-current slides slide.css({ 'width': o.scalingwidth, }); if (o.slidescaling !== 100) { slide.css({ 'marginleft': o.scalingmargin, // compensation for scaling transform 'marginright': o.scalingmargin, // compensation for scaling transform 'transform': 'scale(' + (100 / o.slidescaling) + ')', 'borderspacing': o.slidescaling // value placeholder used with step function to animate tranform }); } // vertically center slide if enabled if (o.options.centerv) { slide.children().first().css('margintop', o.getmargintop(slide, 'slidemargintop')); } // set current slides if (i === o.indexcurrent) { slide .css({ 'borderspacing': '100px', // value placeholder used with step function to animate tranform 'width': o.slidewidthcurrent, 'marginleft': 0, // compensation for scaling transform 'marginright': 0, // compensation for scaling transform 'transform': 'scale(1)', }) .addclass(o.classcurrent) .siblings() .removeclass(o.classcurrent) ; // vertically center slide if enabled if (o.options.centerv) { slide.children().first().css('margintop', o.getmargintop(slide, 'slidemargintopcurrent')); } } }); }; // get offset for centering slide contents vertically within stage // must be called after contents (images) have loaded to get correct height o.getmargintop = function (slide, datakey) { var slidemargintop = 0; // get height of slide container var height = slide.children().first().outerheight(); // add negative top margin if slide height is bigger than stage height if (height > o.stageheight) { slidemargintop = (o.stageheight - height) / 2; } // store slide's top margin value for re-use slide.data(datakey, slidemargintop); return slidemargintop; }; // test transform feature support o.supporttransform = function (modernizrbool, element) { var test = false; // user modernizr if it exists if (modernizrbool && modernizr) { if (modernizr.csstransforms) { test = true; } } else { var style = element.style; if (typeof style.transform !== "undefined" || typeof style.webkittransform !== "undefined" || typeof style.mstransform !== "undefined") { test = true; } } return test; }; // initialize ------------------------------------------------------------------------------------ o.init(stageel, options); return this; }; // create a jquery plugin ========================================================================== $.fn.mislider = function (options) { // enable multiple-slider support return this.each(function () { var stage = $(this); if (!stage.data('mislider')) { stage.data('mislider', new mislider(this, options)); } }); }; })(jquery, window, document, math);