sudoslider
Version:
An extremely versitile content-slider
1,200 lines (1,030 loc) • 124 kB
JavaScript
/**@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;
}