UNPKG

sudoslider

Version:

An extremely versitile content-slider

1,200 lines (1,030 loc) 124 kB
/**@preserve * Sudo Slider version 3.5.1 - jQuery plugin * Written by Erik Krogh Kristensen erik@webbies.dk. * http://webbies.dk/SudoSlider/ * * Dual licensed under the MIT and GPL licenses. * * Based on EasySlider http://cssglobe.com/easy-slider-17-numeric-navigation-jquery-slider/ * But bear little resemblance at this point. * * Built for jQuery library * http://jquery.com * */ (function(factory) { // window/root object. var root = (typeof self == 'object' && self.self == self && self) || (typeof global == 'object' && global.global == global && global); // AMD if (typeof define === 'function' && define.amd) { define(['jquery'], function($) { factory($, root); }); // CommonJS } else if (typeof exports !== 'undefined') { var $ = require('jquery'); factory($, root); // Finally, as a browser global. } else { factory(root.jQuery, root); } })(function ($, win) { // Saves space in the minified version. var undefined; // Makes sure that undefined really is undefined within this scope. var FALSE = false; var TRUE = true; // Constants var PAGES_MARKER_STRING = "pages"; var NEXT_STRING = "next"; var PREV_STRING = "prev"; var LAST_STRING = "last"; var FIRST_STRING = "first"; var ABSOLUTE_STRING = "absolute"; var RELATIVE_STRING = "relative"; var HIDDEN_STRING = "hidden"; var SWING = "swing"; var EMPTY_FUNCTION = function () { }; var ANIMATION_CLONE_MARKER_CLASS = "sudo-box"; var DIV_TAG = "<div>"; var CSSVendorPrefix = getCSSVendorPrefix(); var jWin = $(win); var doc = $(document); var TOUCHSTART = "touchstart"; var TOUCHMOVE = "touchmove"; var TOUCHCANCEL = "touchcancel"; var TOUCHEND = "touchend"; var MOUSEDOWN = "mousedown"; var MOUSEMOVE = "mousemove"; var MOUSEUP = "mouseup"; var SLIDES_CONTAINER = "slidesContainer"; var SUDO_DRAGGING_CLASS = "sudoSlider-dragging"; $.fn.sudoSlider = function (optionsOrg) { // Defining the base element. var baseSlider = this; optionsOrg = $.extend(objectToLowercase(getDefaultOptions()), objectToLowercase(optionsOrg)); if (CSSVendorPrefix === FALSE || !minJQueryVersion([1, 8, 0])) { optionsOrg.usecss = FALSE; } return this.each(function () { var init, fullyInitialized = FALSE, isSlideContainerUl, slidesContainer, slides, imagesInSlidesLoaded, totalSlides, currentSlide, previousSlide, clickable, currentlyAnimatingTowards, numericControls, numericContainer, destroyed, slideNumberBeforeDestroy = FALSE, controls, nextbutton, prevbutton, autoTimeout, autoOn, numberOfVisibleSlides, asyncDelayedSlideLoadTimeout, obj = $(this), finishedAdjustingTo = FALSE, // This variable tells if the slider is currently adjusted (height and width) to any specific slide. This is usefull when ajax-loading stuff. adjustingTo, // This one tells what slide we are adjusting to, to make sure that we do not adjust to something we shouldn't. adjustTargetTime = 0, // This one holds the time that the autoadjust animation should complete. currentlyAnimating = FALSE, currentAnimation, currentAnimationCallback, currentAnimationObject, runAfterAnimationCallbacks, awaitingAjaxCallbacks, startedAjaxLoads, finishedAjaxLoads, animateToAfterCompletion = FALSE, animateToAfterCompletionClicked, animateToAfterCompletionSpeed, slideContainerCreated = FALSE, option = [], options = $.extend(TRUE, {}, optionsOrg), currentSliderPositionTop, currentSliderPositionLeft, unBindCallbacks = [], autoStartedWithPause = FALSE, animationWasInterrupted = FALSE; // The call to the init function is after the definition of all the functions. function initSudoSlider() { // Storing the public options in an array. var optionIndex = 0; for (var key in options) { option[optionIndex] = options[key]; optionIndex++; } init = TRUE; fullyInitialized = FALSE; imagesInSlidesLoaded = []; runAfterAnimationCallbacks = []; awaitingAjaxCallbacks = []; startedAjaxLoads = []; finishedAjaxLoads = []; // Fix for nested list items slidesContainer = childrenNotAnimationClones(obj); // Is the ul element there? var ulLength = slidesContainer.length; var newUl = $(DIV_TAG); if (!ulLength) { obj.append(slidesContainer = newUl); isSlideContainerUl = FALSE; } else if (!((isSlideContainerUl = slidesContainer.is("ul")) || slidesContainer.hasClass(SLIDES_CONTAINER)) && !slideContainerCreated) { newUl.append(slidesContainer); obj.append(slidesContainer = newUl); } slideContainerCreated = TRUE; var slidesJquery = childrenNotAnimationClones(slidesContainer); slides = []; totalSlides = slidesJquery.length; slidesJquery.each(function (index, elem) { var that = $(elem); slides[index] = that; that.css({position: RELATIVE_STRING}); if (that.css("display") == "none") { that.css("display", "inline"); } }); // Adding CSS classes slidesContainer.addClass(SLIDES_CONTAINER); slidesJquery.addClass("slide"); slidesJquery.each(function (index, elem) { $(elem).attr("data-slide", index + 1); }); // Now we are going to fix the document, if it's 'broken'. (No <li>). // I assume that it's can only be broken, if ajax is enabled. If it's broken without Ajax being enabled, the script doesn't have anything to fill the holes. if (option[30]/*ajax*/) { // Do we have enough list elements to fill out all the ajax documents. var numerOfAjaxUrls = option[30]/*ajax*/.length; if (numerOfAjaxUrls > totalSlides) { for (var a = 1; a <= numerOfAjaxUrls - totalSlides; a++) { var tag; if (isSlideContainerUl) { tag = "li"; } else { tag = "div"; } var slide = $("<" + tag + ">" + option[32]/*loadingtext*/ + "</" + tag + ">"); slidesContainer.append(slide); slides[totalSlides + (a - 1)] = slide; } slidesJquery = childrenNotAnimationClones(slidesContainer); totalSlides = numerOfAjaxUrls; } } slidesJquery.each(function (index, elem) { imagesInSlidesLoaded[index] = FALSE; runOnImagesLoaded($(elem), TRUE, function () { imagesInSlidesLoaded[index] = TRUE; }); }); if (slideNumberBeforeDestroy === FALSE) { currentSlide = 0; } else { currentSlide = slideNumberBeforeDestroy; } currentSlide = currentSlide || 0; previousSlide = currentSlide; clickable = TRUE; numericControls = []; destroyed = FALSE; // Set obj overflow to hidden (and position to relative <strike>, if fade is enabled. </strike>) obj.css({overflow: HIDDEN_STRING}); if (obj.css("position") == "static") obj.css({position: RELATIVE_STRING}); // Fixed a lot of IE6 + IE7 bugs. // Float items to the left, and make sure that all elements are shown. slidesJquery.css({"float": "left", listStyle: "none"}); // The last CSS to make it work. slidesContainer.add(slidesJquery).css({display: "block", position: RELATIVE_STRING, margin: "0"}); adjustPositionToPosition(0, 0); option[7]/*slidecount*/ = parseInt10(option[7]/*slidecount*/); // Lets just redefine slidecount numberOfVisibleSlides = option[7]/*slidecount*/; option[7]/*slidecount*/ += option[8]/*movecount*/ - 1; // startslide can only be a number (and not 0). Converting from 1 index to 0 index. // unless it is the string "random". if (typeof option[9]/*startslide*/ == "string" && option[9]/*startslide*/.toLowerCase() == "random") { option[9]/*startslide*/ = (Math.random() * totalSlides) | 0; } option[9]/*startslide*/ = parseInt10(option[9]/*startslide*/) - 1 || 0; option[0]/*effect*/ = getEffectMethod(option[0]/*effect*/); // Cloning numericText, so the array same array can be modifed outside SudoSlider without doing weird things. option[18]/*numerictext*/ = option[18]/*numerictext*/.slice(0); for (var a = 0; a < totalSlides; a++) { if (!option[18]/*numerictext*/[a] && option[18]/*numerictext*/[a] != "") { option[18]/*numerictext*/[a] = (a + 1); } if (option[30]/*ajax*/) { option[30]/*ajax*/[a] = option[30]/*ajax*/[a] || FALSE; } } option[4]/*controlsfade*/ = option[4]/*controlsfade*/ && !option[15]/*continuous*/; if (option[10]/*responsive*/) { adjustResponsiveLayout(TRUE); } // Making sure that i have enough room in the <ul> (Through testing, i found out that the max supported size (height or width) in Firefox is 17895697px, Chrome supports up to 134217726px, and i didn't find any limits in IE (6/7/8/9)). // 9000000px gives room for about 12500 slides of 700px each (and works in every browser i tested). Down to 9000000 from 10000000 because the later might not work perfectly in FireFox on OSX. slidesContainer[option[6]/*vertical*/ ? "height" : "width"](9000000)[option[6]/*vertical*/ ? "width" : "height"]("100%"); // If responsive is turned on, autowidth doesn't work. option[28]/*autowidth*/ = option[28]/*autowidth*/ && !option[10]/*responsive*/; if (option[10]/*responsive*/) { bindAndRegisterOff(jWin, "resize focus", adjustResponsiveLayout, ""); } if (option[17]/*numeric*/ || option[16]/*prevnext*/) { controls = $("<span " + option[35]/*controlsattr*/ + "></span>"); obj[option[5]/*insertafter*/ ? "after" : "before"](controls); if (option[17]/*numeric*/) { numericContainer = $("<ol " + option[36]/*numericattr*/ + "></ol>"); controls.prepend(numericContainer); var usePages = option[17]/*numeric*/ == PAGES_MARKER_STRING; var distanceBetweenPages = usePages ? numberOfVisibleSlides : 1; for (var a = 0; a < totalSlides - ((option[15]/*continuous*/ || usePages) ? 1 : numberOfVisibleSlides) + 1; a += distanceBetweenPages) { numericControls[a] = $("<li data-target=\"" + (a + 1) + "\"><a href=\"#\"><span>" + option[18]/*numerictext*/[a] + "</span></a></li>") .appendTo(numericContainer) .click(function () { enqueueAnimation(getTargetAttribute(this) - 1, TRUE); return FALSE; }); } } if (option[16]/*prevnext*/) { nextbutton = makecontrol(option[34]/*nexthtml*/, NEXT_STRING); prevbutton = makecontrol(option[33]/*prevhtml*/, PREV_STRING); } if (option[4]/*controlsfade*/) { fadeControls(currentSlide, 0); } } // Lets make those fast/normal/fast into some numbers we can make calculations with. var optionsToConvert = [4/*controlsfadespeed*/, 1/*speed*/, 14/*pause*/]; for (var i = 0; i < optionsToConvert.length; i++) { option[optionsToConvert[i]] = textSpeedToNumber(option[optionsToConvert[i]]); } if (option[2]/*customlink*/) { var filter = stringTrim(option[2]/*customlink*/); if (filter.charAt(0) == ">") { bindAndRegisterOff(obj, "click", customLinkClickHandler, filter.substr(1, filter.length)); } else { bindAndRegisterOff(doc, "click", customLinkClickHandler, filter); } } runOnImagesLoaded(getSlides(option[9]/*startslide*/, option[7]/*slidecount*/), TRUE, function () { if (slideNumberBeforeDestroy !== FALSE) { goToSlide(slideNumberBeforeDestroy, FALSE); } else if (option[26]/*history*/) { // I support the jquery.address plugin, Ben Alman's hashchange plugin and Ben Alman's jQuery.BBQ. var hashPlugin; if (hashPlugin = jWin.hashchange) { hashPlugin(URLChange); } else if (hashPlugin = $.address) { hashPlugin.change(URLChange); } else { // This assumes that jQuery BBQ is included. If not, stuff won't work in old browsers. bindAndRegisterOff(jWin, "hashchange", URLChange); } URLChange(); } else { goToSlide(option[9]/*startslide*/, FALSE); } setCurrent(currentSlide); }); if (option[30]/*ajax*/[option[9]/*startslide*/]) { ajaxLoad(option[9]/*startslide*/); } if (option[31]/*preloadajax*/ === TRUE) { for (var i = 0; i < totalSlides; i++) { if (option[30]/*ajax*/[i] && option[9]/*startslide*/ != i) { ajaxLoad(i); } } } else { startAsyncDelayedLoad(); } } /* * The functions do the magic. */ function customLinkClickHandler() { var target; if (target = getTargetAttribute(this)) { if (target == 'stop') { option[12]/*auto*/ = FALSE; stopAuto(); } else if (target == "start") { startAuto(); option[12]/*auto*/ = TRUE; } else if (target == 'block') { clickable = FALSE; } else if (target == 'unblock') { clickable = TRUE; } else { enqueueAnimation((target == parseInt10(target)) ? target - 1 : target, TRUE); } } return FALSE; } // Adjusts the slider when a change in layout has happened. var previousAdjustedResponsiveWidth = -1; function adjustResponsiveLayout(forced) { function doTheAdjustment() { if ((cantDoAdjustments() && !(forced === TRUE)) || totalSlides == 0) { return; } var subPixelNewWidth = getResponsiveWidth(); var newWidth = parseInt10(subPixelNewWidth); var addAPixelEvery = 1 / (subPixelNewWidth - newWidth); if (previousAdjustedResponsiveWidth !== subPixelNewWidth || (forced === TRUE)) { previousAdjustedResponsiveWidth = subPixelNewWidth; var slideCounter = 1; for (var i = 0; i < totalSlides; i++) { slideCounter++; if (slideCounter >= addAPixelEvery) { slideCounter = 0; slides[i].width(newWidth + 1); } else { slides[i].width(newWidth); } } if (autoStartedWithPause !== FALSE) { startAuto(autoStartedWithPause); } stopAnimation(); ensureSliderContainerCSSDurationReset(); adjustPositionTo(currentSlide); autoadjust(currentSlide, 0); } } doTheAdjustment(); callAsync(doTheAdjustment); // Fixing invisible scrollbar. schedule(doTheAdjustment, 20); } // Returns the width of a single <li> if the page layout is responsive. function getResponsiveWidth() { var width = obj.width(); if (option[6]/*vertical*/) { return width; } else { return width / numberOfVisibleSlides; } } // For backwards compability, the rel attribute is used as a fallback. function getTargetAttribute(that) { that = $(that); return that.attr("data-target") || that.attr("rel"); } // Triggered when the URL changes. function URLChange() { var target = getUrlHashTarget(); if (init) { goToSlide(target, FALSE); } else { enqueueAnimation(target, FALSE); } } function startAsyncDelayedLoad() { if (option[31]/*preloadajax*/ !== FALSE) { var preloadAjaxTime = parseInt10(option[31]/*preloadajax*/); if (option[30]/*ajax*/) { for (var i = 0; i < option[30]/*ajax*/.length; i++) { if (option[30]/*ajax*/[i]) { clearTimeout(asyncDelayedSlideLoadTimeout); asyncDelayedSlideLoadTimeout = schedule(function () { if (option[30]/*ajax*/[i]) { ajaxLoad(i); } else { startAsyncDelayedLoad(); } }, preloadAjaxTime); break; } } } } } function startAuto(pause) { if (pause === undefined) { var dataPause = slides[currentSlide].attr("data-pause"); if (dataPause !== undefined) { pause = parseInt10(dataPause); } else { pause = option[13]/*pause*/; } } if (animationWasInterrupted) { pause = mathMax(pause, 100); } stopAuto(); autoOn = TRUE; autoStartedWithPause = pause; autoTimeout = schedule(function () { if (autoOn && !currentlyAnimating) { enqueueAnimation(NEXT_STRING, FALSE); autoStartedWithPause = FALSE; } }, pause); } function stopAuto(autoPossibleStillOn) { if (autoTimeout) { clearTimeout(autoTimeout); } if (!autoPossibleStillOn) autoOn = FALSE; } function textSpeedToNumber(speed) { if (parseInt10(speed) || speed == 0) { return parseInt10(speed); } if (speed == "fast") { return 200; } if (speed == "normal" || speed == "medium") { return 400; } if (speed == "slow") { return 600; } return 600; } function makecontrol(html, action) { return $(html).prependTo(controls).click(function () { enqueueAnimation(action, TRUE); return FALSE; }); } function enqueueAnimation(direction, clicked, speed) { if (clickable && !init) { // Stopping, because if its needed then its restarted after the end of the animation. stopAuto(TRUE); if (!destroyed) { loadSlidesAndAnimate(direction, clicked, speed); } } else { if (option[37]/*interruptible*/ && currentlyAnimating) { if (getRealPos(filterDir(direction)) !== currentlyAnimatingTowards) { stopAnimation(); enqueueAnimation(direction, clicked, speed); } } else { animateToAfterCompletion = direction; animateToAfterCompletionClicked = clicked; animateToAfterCompletionSpeed = speed; // I can just as well start the ajax loads if (option[30]/*ajax*/) { var targetSlide = filterDir(direction); for (var loadSlide = targetSlide; loadSlide < targetSlide + numberOfVisibleSlides; loadSlide++) { if (option[30]/*ajax*/[loadSlide]) { ajaxLoad(getRealPos(loadSlide)); } } } } } } // It may not sound like it, but the variable fadeOpacity is only for TRUE/FALSE. function fadeControl(fadeOpacity, fadetime, nextcontrol) { fadeOpacity = fadeOpacity ? 1 : 0; var fadeElement = $(); if (option[16]/*prevnext*/) { fadeElement = nextcontrol ? nextbutton : prevbutton; } if (option[2]/*customlink*/) { var customLink = $(option[2]/*customlink*/); var filterString = "=\"" + (nextcontrol ? NEXT_STRING : PREV_STRING) + "\"]"; var filtered = customLink.filter("[rel" + filterString + ", [data-target" + filterString + ""); fadeElement = fadeElement.add(filtered); } var adjustObject = {opacity: fadeOpacity}; function callback() { if (!fadeOpacity && fadeElement.css("opacity") == 0) { fadeElement.css({visibility: HIDDEN_STRING}); } } if (fadeOpacity) { fadeElement.css({visibility: "visible"}); } if (option[38]/*useCSS*/) { animate(fadeElement, adjustObject, fadetime, option[46]/*CSSease*/, callback); } else { fadeElement.animate( adjustObject, { queue: FALSE, duration: fadetime, easing: option[11]/*ease*/, callback: callback } ); } } // Fade the controls, if we are at the end of the slide. // It's all the different kind of controls. function fadeControls(slide, fadetime) { fadeControl(slide, fadetime, FALSE); // abusing that the number 0 == FALSE. // The new way of doing it. fadeControl(slide < totalSlides - numberOfVisibleSlides, fadetime, TRUE); } // Updating the 'current' class function setCurrent(i) { i = getRealPos(i) + 1; // Fixing that the last numeric control isn't marked when we are at the last possible position. if (option[17]/*numeric*/ == PAGES_MARKER_STRING && i == totalSlides - numberOfVisibleSlides + 1 && !option[15]/*continuous*/) { i = totalSlides; } if (option[17]/*numeric*/) { for (var control = 0; control < numericControls.length; ++control) { var element = numericControls[control]; setCurrentElement(element, i) } } if (option[2]/*customlink*/) setCurrentElement($(option[2]/*customlink*/), i); } function setCurrentElement(element, i) { if (element && element.filter) { element .filter(".current") .removeClass("current"); element .filter(function () { var elementTarget = getTargetAttribute(this); if (option[17]/*numeric*/ == PAGES_MARKER_STRING) { for (var a = numberOfVisibleSlides - 1; a >= 0; a--) { if (elementTarget == i - a) { return TRUE; } } } else { return elementTarget == i; } return FALSE; }) .addClass("current"); } } function getUrlHashTarget() { var hashString = location.hash.substr(1) for (var i = 0; i < option[18]/*numerictext*/.length; i++) { if (option[18]/*numerictext*/[i] == hashString) { return i; } } if (hashString && !init) { return currentSlide; } else { return option[9]/*startslide*/; } } function autoadjust(i, speed) { i = getRealPos(i); // I assume that the continuous clones, and the original element is the same height. So i always adjust according to the original element. adjustingTo = i; adjustTargetTime = getTimeInMillis() + speed; if (speed == 0) { finishedAdjustingTo = i; } else { finishedAdjustingTo = FALSE; } if (option[27]/*autoheight*/ || option[28]/*autowidth*/) { autoHeightWidth(i); } } function autoHeightWidth(i) { obj.ready(function () { adjustHeightWidth(i); runOnImagesLoaded(slides[i], FALSE, makeCallback(adjustHeightWidth, [i])); }); } // Axis: TRUE == height, FALSE == width. function getSliderDimensions(fromSlide, vertical) { var pixels = 0; for (var slide = fromSlide; slide < fromSlide + numberOfVisibleSlides; slide++) { var targetSlide = slides[getRealPos(slide)]; if (targetSlide) { var targetPixels = targetSlide['outer' + (vertical ? "Height" : "Width")](TRUE); if (vertical == option[6]/*vertical*/) { pixels += targetPixels; } else { pixels = mathMax(targetPixels, pixels); } } } return pixels; } var prevHeightWidthAdjustObject = {}; function adjustHeightWidth(i) { if (i != adjustingTo || cantDoAdjustments()) { return; } var speed = adjustTargetTime - getTimeInMillis(); speed = mathMax(speed, 0); var adjustObject = {}; if (option[27]/*autoheight*/) { adjustObject.height = getSliderDimensions(i, TRUE) || 1; // Making it completely invisible gives trouble. } if (option[28]/*autowidth*/) { adjustObject.width = getSliderDimensions(i, FALSE) || 1; } if (simpleObjectEquals(prevHeightWidthAdjustObject, adjustObject)) { return; } else { prevHeightWidthAdjustObject = adjustObject; } if (option[38]/*useCSS*/) { animate(obj, adjustObject, speed, option[46]/*CSSease*/) } else { if (speed == 0) { // Doing CSS if speed == 0, 1: its faster. 2: it fixes bugs. obj.stop().css(adjustObject); } else { obj.animate( adjustObject, { queue: FALSE, duration: speed, easing: option[11]/*ease*/ } ); } } } function adjustPositionTo(slide) { var left = getSlidePosition(slide, FALSE); var top = getSlidePosition(slide, TRUE); adjustPositionToPosition(left, top); } function adjustPositionToPosition(left, top) { currentSliderPositionLeft = left; currentSliderPositionTop = top; function setMargins(left, top) { slidesContainer.css({ marginLeft: left, marginTop: top }); } setMargins(0, 0); setMargins(left, top); } function getSlidePosition(slide, vertical) { if (vertical == undefined) { vertical = option[6]/*vertical*/; } var targetSlide = slides[getRealPos(slide)]; return (targetSlide && targetSlide.length) ? -targetSlide.position()[vertical ? "top" : "left"] : 0; } function callQueuedAnimation() { if (animateToAfterCompletion !== FALSE) { var animateTo = animateToAfterCompletion; animateToAfterCompletion = FALSE; callAsync(makeCallback(enqueueAnimation, [animateTo, animateToAfterCompletionClicked, animateToAfterCompletionSpeed])); } } function adjust(clicked) { ensureSliderContainerCSSDurationReset(); autoadjust(currentSlide, 0); currentSlide = getRealPos(currentSlide); // Going to the real slide, away from the clone. if (!option[29]/*updateBefore*/) setCurrent(currentSlide); adjustPositionTo(currentSlide); clickable = TRUE; currentlyAnimatingTowards = FALSE; hideExcess(); if (option[12]/*auto*/) { // Stopping auto if clicked. And also continuing after X seconds of inactivity. if (clicked) { stopAuto(); if (option[14]/*resumepause*/) startAuto(option[14]/*resumepause*/); } else if (!init) { startAuto(); } } callQueuedAnimation(); } var excessHasBeenHidden = false; function hideExcess() { var performanceMode = option[48]/*performanceMode*/; if (excessHasBeenHidden || !performanceMode) { return; } if (!slidesContainer.is("div")) { return; } excessHasBeenHidden = TRUE; for (var i = 0; i < totalSlides; i++) { var slide = slides[i]; if (performanceMode === 2) { slide.css({position: "static"}); } if (!((i >= currentSlide && i < currentSlide + option[7]/*slidecount*/) || (i + totalSlides >= currentSlide && i + totalSlides < currentSlide + option[7]/*slidecount*/))) { slide.hide(); } } if (performanceMode === 2) { slidesContainer.css({ display: "inline", position: "static" }); } } function showAll() { if (!excessHasBeenHidden) { return; } excessHasBeenHidden = FALSE; for (var i = 0; i < totalSlides; i++) { slides[i].css({position: "relative"}).show(); } slidesContainer.css({ display: "block", position: "relative" }); adjustPositionTo(currentSlide); } // This function is called when i need a callback on the current element and it's continuous clones (if they are there). // after: TRUE == afteranimation : FALSE == beforeanimation; function aniCall(i, after, synchronous, speed) { i = getRealPos(i); // Wierd fix to let IE accept the existance of the sudoSlider object. var func = makeCallback(after ? afterAniCall : beforeAniCall, [slides[i], i + 1, speed]); if (synchronous) { func(); } else { callAsync(func); } } function afterAniCall(el, a) { option[25]/*afteranimation*/.call(el, a, baseSlider); } function beforeAniCall(el, a, speed) { option[24]/*beforeanimation*/.call(el, a, baseSlider, speed); } // Convert the direction into a usefull number. function filterDir(dir) { if (dir == NEXT_STRING) { return limitDir(currentSlide + option[8]/*movecount*/, dir); } else if (dir == PREV_STRING) { return limitDir(currentSlide - option[8]/*movecount*/, dir); } else if (dir == FIRST_STRING) { return 0; } else if (dir == LAST_STRING) { return totalSlides - 1; } else { return limitDir(parseInt10(dir), dir); } } // If continuous is off, we sometimes do not want to move to far. // This method was added in 2.1.8, se the changelog as to why. function limitDir(i, dir) { if (option[15]/*continuous*/) { if (dir == NEXT_STRING || dir == PREV_STRING) { return i; } else { return getRealPos(i); } } else { var maxSlide = totalSlides - numberOfVisibleSlides; if (i > maxSlide) { if (currentSlide == maxSlide && dir == NEXT_STRING) { return 0; } else { return maxSlide; } } else if (i < 0) { if (currentSlide == 0 && dir == PREV_STRING) { return maxSlide; } else { return 0; } } else { return i; } } } // Load a ajax document (or image) into a slide. // If testing this locally (loading everything from a harddisk instead of the internet), it may not work. // But then try to upload it to a server, and see it shine. function ajaxLoad(slide, ajaxCallBack) { if (ajaxCallBack) { var callbackList = awaitingAjaxCallbacks[slide]; if (!callbackList) { callbackList = awaitingAjaxCallbacks[slide] = []; } callbackList.push(ajaxCallBack); } if (finishedAjaxLoads[slide]) { if (ajaxCallBack) { runOnImagesLoaded(slides[slide], TRUE, makeCallback(callAsync, [ajaxCallBack])); } return; } if (startedAjaxLoads[slide]) { return; } startedAjaxLoads[slide] = TRUE; var target = option[30]/*ajax*/[slide]; if (!target) { callAsync(ajaxCallBack); return; } if (asyncDelayedSlideLoadTimeout) clearTimeout(asyncDelayedSlideLoadTimeout);// I dont want it to run to often. var targetslide = slides[slide]; // Loads the url as an image, either if it is an image, or if everything else failed. function loadImage() { var image = new Image(); image.src = target; var thatImage = $(image); runOnImagesLoaded(thatImage, TRUE, function () { targetslide.empty().append(image); ajaxAdjust(slide, TRUE); }); } // It is loaded, we dont need to do that again. option[30]/*ajax*/[slide] = FALSE; // It is the only option that i need to change for good. options.ajax[slide] = FALSE; if (option[47]/*AjaxHasHTML*/) { var succesRan = FALSE; $.ajax({ url: target, success: function (data, textStatus, jqXHR) { succesRan = TRUE; runWhenNotAnimating(function () { var type = jqXHR.getResponseHeader('Content-Type'); if (type && type.substr(0, 1) != "i") { targetslide.html(data); ajaxAdjust(slide, FALSE); } else { loadImage(); } }); }, complete: function () { // Some browsers wont load images this way, so i treat an error as an image. // There is no stable way of determining if it's a real error or if i tried to load an image in a old browser, so i do it this way. if (!succesRan) { loadImage(); } } }); } else { loadImage(); } } // Performs the callback immediately if no animation is running. // Otherwise waits for the animation to complete in a FIFO queue. function runWhenNotAnimating(completeFunction) { if (currentlyAnimating) { runAfterAnimationCallbacks.push(completeFunction); } else { callAsync(completeFunction); } } function ajaxAdjust(i, img) { var target = slides[i]; if (!currentlyAnimating) { adjustPositionTo(currentSlide); autoadjust(currentSlide, 0); } runOnImagesLoaded(target, TRUE, makeCallback(runWhenNotAnimating, [ function () { adjustPositionTo(currentSlide); autoadjust(currentSlide, 0); finishedAjaxLoads[i] = TRUE; performCallbacks(awaitingAjaxCallbacks[i]); startAsyncDelayedLoad(); callAsync(function () { option[23]/*ajaxload*/.call(slides[i], i + 1, img, baseSlider); }); if (init) { init = FALSE; callAsync(performInitCallback); } } ])); } function performInitCallback() { fullyInitialized = TRUE; if (option[15]/*continuous*/) { centerTargetSlideAfter(currentSlide); } autoadjust(currentSlide, 0); adjustPositionTo(currentSlide); callQueuedAnimation(); if (option[10]/*responsive*/) { adjustResponsiveLayout(); } if (option[12]/*auto*/) { startAuto(); } option[22]/*initCallback*/.call(baseSlider); if (option[41]/*touch*/) { setUpTouch(); } // Fixing once and for all that the wrong slide is shown on init. runOnImagesLoaded(getSlides(currentSlide, totalSlides), FALSE, makeCallback(runWhenNotAnimating, [ function () { autoadjust(currentSlide, 0); adjustPositionTo(currentSlide); } ])); } function setUpTouch() { var body = $("body"); var easingToUse; var runningTouchEffect = FALSE; var prevEffect = option[0]/*effect*/; option[0]/*effect*/ = function (obj) { if (runningTouchEffect) { runningTouchEffect = FALSE; var options = obj.options; options.ease = easingToUse; options.cssease = easingToUse; return slide(obj); } else { return prevEffect(obj); } }; var initialOffsetLeft; var initialOffsetTop; var startTime; var lastTime; var lastDistance; var bufferSize = 3; var positionsBuffer = []; var timeBuffer = []; var bufferIndex = 0; var currentTouchSlide; var baseDistance; function touchStart(x, y) { body.addClass(SUDO_DRAGGING_CLASS); currentTouchSlide = currentSlide; baseDistance = 0; currentlyAnimating = TRUE; ensureSliderContainerCSSDurationReset(); initialOffsetTop = currentSliderPositionTop; initialOffsetLeft = currentSliderPositionLeft; var distance; if (option[6]/*vertical*/) { distance = mathAbs(y); } else { distance = mathAbs(x); } lastDistance = distance; startTime = getTimeInMillis(); lastTime = startTime; var currentSlidePosition = getSlidePosition(currentTouchSlide); distanceToRightSlide = getSlidePosition(currentTouchSlide + 1) - currentSlidePosition; correctionWhenCalculatingWhereToMoveTouchDistance = FALSE; } var distanceToRightSlide; var correctionWhenCalculatingWhereToMoveTouchDistance; function touchMove(x, y) { var distance; if (option[6]/*vertical*/) { distance = y; } else { distance = x; } var distanceAbs = mathAbs(distance); positionsBuffer[bufferIndex] = distanceAbs - lastDistance; var newTime = getTimeInMillis(); timeBuffer[bufferIndex] = newTime - lastTime; bufferIndex = (bufferIndex + 1) % bufferSize; lastTime = newTime; lastDistance = distanceAbs; if (option[15]/*continuous*/ && totalSlides >= numberOfVisibleSlides + 1) { // Moving everything to the right var direction = 0; if ((distance - baseDistance) < distanceToRightSlide) { correctionWhenCalculatingWhereToMoveTouchDistance = FALSE; baseDistance += distanceToRightSlide; direction = 1; var rightSlidePositionBefore = getSlidePosition(currentTouchSlide + direction); centerTargetSlideAfter(currentTouchSlide + direction); var rightSlidePositionAfter = getSlidePosition(currentTouchSlide + direction); } // Moving everything to the left. if ((distance - baseDistance) > 0) { direction = -1; var rightSlidePositionBefore = getSlidePosition(currentTouchSlide); centerTargetSlideAfter(currentTouchSlide + direction); rightSlidePositionAfter = getSlidePosition(currentTouchSlide); var moveBaseDistance = getSlidePosition(currentTouchSlide - 1) - rightSlidePositionAfter; baseDistance += moveBaseDistance; correctionWhenCalculatingWhereToMoveTouchDistance = -moveBaseDistance; } if (direction != 0) { currentTouchSlide += direction; if (option[6]/*vertical*/) { initialOffsetTop -= rightSlidePositionBefore - rightSlidePositionAfter; } else { initialOffsetLeft -= rightSlidePositionBefore - rightSlidePositionAfter; } distanceToRightSlide = getSlidePosition(currentTouchSlide + 1) - getSlidePosition(currentTouchSlide); } } if (option[6]/*vertical*/) { x = 0; } else { y = 0; }