/* * jQuery SmoothDivScroll 1.3 * * Copyright (c) 2012 Thomas Kahn * Licensed under the GPL license. * * http://www.smoothdivscroll.com/ * * Depends: * jquery-1.8.x.min.js Please use https://ajax.googleapis.com/ajax/libs/jquery/1.8.1/jquery.min.js ...or later * jquery.ui.widget.js * jquery.ui.effects.min.js Make your own custom download at http://jqueryui.com/download. First deselect all components. Then check just "Widget" and "Effects Core". Download the file and put it in your javascript folder. * jquery.mousewheel.min.js Used for mousewheel functionality. Download the latest version at http://brandonaaron.net/code/mousewheel/demos * * jquery.kinetic.js Used for scrolling by dragging, mainly used on touch devices. Download the latest version at https://github.com/davetayls/jquery.kinetic * */ (function ($) { $.widget("thomaskahn.smoothDivScroll", { // Default options options: { // Classes for elements added by Smooth Div Scroll scrollingHotSpotLeftClass: "scrollingHotSpotLeft", // String scrollingHotSpotRightClass: "scrollingHotSpotRight", // String scrollableAreaClass: "scrollableArea", // String scrollWrapperClass: "scrollWrapper", // String // Misc settings hiddenOnStart: false, // Boolean getContentOnLoad: {}, // Object countOnlyClass: "", // String startAtElementId: "", // String // Hotspot scrolling hotSpotScrolling: true, // Boolean hotSpotScrollingStep: 15, // Pixels hotSpotScrollingInterval: 10, // Milliseconds hotSpotMouseDownSpeedBooster: 3, // Integer visibleHotSpotBackgrounds: "hover", // always, onStart, hover or empty (no visible hotspots) hotSpotsVisibleTime: 5000, // Milliseconds easingAfterHotSpotScrolling: true, // Boolean easingAfterHotSpotScrollingDistance: 10, // Pixels easingAfterHotSpotScrollingDuration: 300, // Milliseconds easingAfterHotSpotScrollingFunction: "easeOutQuart", // String // Mousewheel scrolling mousewheelScrolling: "", // vertical, horizontal, allDirections or empty (no mousewheel scrolling) String mousewheelScrollingStep: 70, // Pixels easingAfterMouseWheelScrolling: true, // Boolean easingAfterMouseWheelScrollingDuration: 300, // Milliseconds easingAfterMouseWheelScrollingFunction: "easeOutQuart", // String // Manual scrolling (hotspot and/or mousewheel scrolling) manualContinuousScrolling: false, // Boolean // Autoscrolling autoScrollingMode: "", // always, onStart or empty (no auto scrolling) String autoScrollingDirection: "endlessLoopRight", // right, left, backAndForth, endlessLoopRight, endlessLoopLeft String autoScrollingStep: 1, // Pixels autoScrollingInterval: 10, // Milliseconds // Touch scrolling touchScrolling: false, // Easing for when the scrollToElement method is used scrollToAnimationDuration: 1000, // Milliseconds scrollToEasingFunction: "easeOutQuart" // String }, _create: function () { var self = this, o = this.options, el = this.element; // Create variables for any existing or not existing // scroller elements on the page. el.data("scrollWrapper", el.find("." + o.scrollWrapperClass)); el.data("scrollingHotSpotRight", el.find("." + o.scrollingHotSpotRightClass)); el.data("scrollingHotSpotLeft", el.find("." + o.scrollingHotSpotLeftClass)); el.data("scrollableArea", el.find("." + o.scrollableAreaClass)); // Check which elements are already present on the page. // Create any elements needed by the plugin if // the user hasn't already created them. // First detach any present hot spots if (el.data("scrollingHotSpotRight").length > 0) { el.data("scrollingHotSpotRight").detach(); } if (el.data("scrollingHotSpotLeft").length > 0) { el.data("scrollingHotSpotLeft").detach(); } // Both the scrollable area and the wrapper are missing if (el.data("scrollableArea").length === 0 && el.data("scrollWrapper").length === 0) { el.wrapInner("
").wrapInner("
"); el.data("scrollWrapper", el.find("." + o.scrollWrapperClass)); el.data("scrollableArea", el.find("." + o.scrollableAreaClass)); } // Only the wrapper is missing else if (el.data("scrollWrapper").length === 0) { el.wrapInner("
"); el.data("scrollWrapper", el.find("." + o.scrollWrapperClass)); } // Only the scrollable area is missing else if (el.data("scrollableArea").length === 0) { el.data("scrollWrapper").wrapInner("
"); el.data("scrollableArea", el.find("." + o.scrollableAreaClass)); } // Put the right and left hot spot back into the scroller again // or create them if they where not present from the beginning. if (el.data("scrollingHotSpotRight").length === 0) { el.prepend("
"); el.data("scrollingHotSpotRight", el.find("." + o.scrollingHotSpotRightClass)); } else { el.prepend(el.data("scrollingHotSpotRight")); } if (el.data("scrollingHotSpotLeft").length === 0) { el.prepend("
"); el.data("scrollingHotSpotLeft", el.find("." + o.scrollingHotSpotLeftClass)); } else { el.prepend(el.data("scrollingHotSpotLeft")); } // Create variables in the element data storage el.data("speedBooster", 1); el.data("scrollXPos", 0); el.data("hotSpotWidth", el.data("scrollingHotSpotLeft").innerWidth()); el.data("scrollableAreaWidth", 0); el.data("startingPosition", 0); el.data("rightScrollingInterval", null); el.data("leftScrollingInterval", null); el.data("autoScrollingInterval", null); el.data("hideHotSpotBackgroundsInterval", null); el.data("previousScrollLeft", 0); el.data("pingPongDirection", "right"); el.data("getNextElementWidth", true); el.data("swapAt", null); el.data("startAtElementHasNotPassed", true); el.data("swappedElement", null); el.data("originalElements", el.data("scrollableArea").children(o.countOnlyClass)); el.data("visible", true); el.data("enabled", true); el.data("scrollableAreaHeight", el.data("scrollableArea").height()); el.data("scrollerOffset", el.offset()); /***************************************** SET UP EVENTS FOR TOUCH SCROLLING *****************************************/ if (o.touchScrolling && el.data("enabled")) { // Use jquery.kinetic.js for touch scrolling // Vertical scrolling disabled el.data("scrollWrapper").kinetic({ y: false, moved: function (settings) { if (o.manualContinuousScrolling) { if (el.data("scrollWrapper").scrollLeft() <= 0) { self._checkContinuousSwapLeft(); } else { self._checkContinuousSwapRight(); } } }, stopped: function (settings) { // Stop any ongoing animations el.data("scrollWrapper").stop(true, false); // Stop any ongoing auto scrolling self.stopAutoScrolling(); } }); } /***************************************** SET UP EVENTS FOR SCROLLING RIGHT *****************************************/ // Check the mouse X position and calculate // the relative X position inside the right hotspot el.data("scrollingHotSpotRight").bind("mousemove", function (e) { if (o.hotSpotScrolling) { var x = e.pageX - (this.offsetLeft + el.data("scrollerOffset").left); el.data("scrollXPos", Math.round((x / el.data("hotSpotWidth")) * o.hotSpotScrollingStep)); // If the position is less then 1, it's set to 1 if (el.data("scrollXPos") === Infinity || el.data("scrollXPos") < 1) { el.data("scrollXPos", 1); } } }); // Mouseover right hotspot - scrolling el.data("scrollingHotSpotRight").bind("mouseover", function () { if (o.hotSpotScrolling) { // Stop any ongoing animations el.data("scrollWrapper").stop(true, false); // Stop any ongoing auto scrolling self.stopAutoScrolling(); // Start the scrolling interval el.data("rightScrollingInterval", setInterval(function () { if (el.data("scrollXPos") > 0 && el.data("enabled")) { el.data("scrollWrapper").scrollLeft(el.data("scrollWrapper").scrollLeft() + (el.data("scrollXPos") * el.data("speedBooster"))); if (o.manualContinuousScrolling) { self._checkContinuousSwapRight(); } self._showHideHotSpots(); } }, o.hotSpotScrollingInterval)); // Callback self._trigger("mouseOverRightHotSpot"); } }); // Mouseout right hotspot - stop scrolling el.data("scrollingHotSpotRight").bind("mouseout", function () { if (o.hotSpotScrolling) { clearInterval(el.data("rightScrollingInterval")); el.data("scrollXPos", 0); // Easing out after scrolling if (o.easingAfterHotSpotScrolling && el.data("enabled")) { el.data("scrollWrapper").animate({ scrollLeft: el.data("scrollWrapper").scrollLeft() + o.easingAfterHotSpotScrollingDistance }, { duration: o.easingAfterHotSpotScrollingDuration, easing: o.easingAfterHotSpotScrollingFunction }); } } }); // mousedown right hotspot (add scrolling speed booster) el.data("scrollingHotSpotRight").bind("mousedown", function () { el.data("speedBooster", o.hotSpotMouseDownSpeedBooster); }); // mouseup anywhere (stop boosting the scrolling speed) $("body").bind("mouseup", function () { el.data("speedBooster", 1); }); /***************************************** SET UP EVENTS FOR SCROLLING LEFT *****************************************/ // Check the mouse X position and calculate // the relative X position inside the left hotspot el.data("scrollingHotSpotLeft").bind("mousemove", function (e) { if (o.hotSpotScrolling) { var x = ((this.offsetLeft + el.data("scrollerOffset").left + el.data("hotSpotWidth")) - e.pageX); el.data("scrollXPos", Math.round((x / el.data("hotSpotWidth")) * o.hotSpotScrollingStep)); // If the position is less then 1, it's set to 1 if (el.data("scrollXPos") === Infinity || el.data("scrollXPos") < 1) { el.data("scrollXPos", 1); } } }); // Mouseover left hotspot el.data("scrollingHotSpotLeft").bind("mouseover", function () { if (o.hotSpotScrolling) { // Stop any ongoing animations el.data("scrollWrapper").stop(true, false); // Stop any ongoing auto scrolling self.stopAutoScrolling(); el.data("leftScrollingInterval", setInterval(function () { if (el.data("scrollXPos") > 0 && el.data("enabled")) { el.data("scrollWrapper").scrollLeft(el.data("scrollWrapper").scrollLeft() - (el.data("scrollXPos") * el.data("speedBooster"))); if (o.manualContinuousScrolling) { self._checkContinuousSwapLeft(); } self._showHideHotSpots(); } }, o.hotSpotScrollingInterval)); // Callback self._trigger("mouseOverLeftHotSpot"); } }); // mouseout left hotspot el.data("scrollingHotSpotLeft").bind("mouseout", function () { if (o.hotSpotScrolling) { clearInterval(el.data("leftScrollingInterval")); el.data("scrollXPos", 0); // Easing out after scrolling if (o.easingAfterHotSpotScrolling && el.data("enabled")) { el.data("scrollWrapper").animate({ scrollLeft: el.data("scrollWrapper").scrollLeft() - o.easingAfterHotSpotScrollingDistance }, { duration: o.easingAfterHotSpotScrollingDuration, easing: o.easingAfterHotSpotScrollingFunction }); } } }); // mousedown left hotspot (add scrolling speed booster) el.data("scrollingHotSpotLeft").bind("mousedown", function () { el.data("speedBooster", o.hotSpotMouseDownSpeedBooster); }); /***************************************** SET UP EVENT FOR MOUSEWHEEL SCROLLING *****************************************/ el.data("scrollableArea").mousewheel(function (event, delta, deltaX, deltaY) { if (el.data("enabled") && o.mousewheelScrolling.length > 0) { var pixels; // Can be either positive or negative // Is multiplied/inverted by minus one since you want it to scroll // left when moving the wheel down/right and right when moving the wheel up/left if (o.mousewheelScrolling === "vertical" && deltaY !== 0) { // Stop any ongoing auto scrolling if it's running self.stopAutoScrolling(); event.preventDefault(); pixels = Math.round((o.mousewheelScrollingStep * deltaY) * -1); self.move(pixels); } else if (o.mousewheelScrolling === "horizontal" && deltaX !== 0) { // Stop any ongoing auto scrolling if it's running self.stopAutoScrolling(); event.preventDefault(); pixels = Math.round((o.mousewheelScrollingStep * deltaX) * -1); self.move(pixels); } else if (o.mousewheelScrolling === "allDirections") { // Stop any ongoing auto scrolling if it's running self.stopAutoScrolling(); event.preventDefault(); pixels = Math.round((o.mousewheelScrollingStep * delta) * -1); self.move(pixels); } } }); // Capture and disable mousewheel events when the pointer // is over any of the hotspots if (o.mousewheelScrolling) { el.data("scrollingHotSpotLeft").add(el.data("scrollingHotSpotRight")).mousewheel(function (event) { event.preventDefault(); }); } /***************************************** SET UP EVENT FOR RESIZING THE BROWSER WINDOW *****************************************/ $(window).bind("resize", function () { self._showHideHotSpots(); self._trigger("windowResized"); }); /***************************************** FETCHING CONTENT ON INITIALIZATION *****************************************/ // If getContentOnLoad is present in the options, // sort out the method and parameters and get the content if (!(jQuery.isEmptyObject(o.getContentOnLoad))) { self[o.getContentOnLoad.method](o.getContentOnLoad.content, o.getContentOnLoad.manipulationMethod, o.getContentOnLoad.addWhere, o.getContentOnLoad.filterTag); } // Should it be hidden on start? if (o.hiddenOnStart) { self.hide(); } /***************************************** AUTOSCROLLING *****************************************/ // The $(window).load event handler is used because the width of the elements are not calculated // properly until then, at least not in Google Chrome. The start of the auto scrolling and the // setting of the hotspot backgrounds is started here as well for the same reason. // If the auto scrolling is not started in $(window).load, it won't start because it // will interpret the scrollable areas as too short. $(window).load(function () { // If scroller is not hidden, recalculate the scrollable area if (!(o.hiddenOnStart)) { self.recalculateScrollableArea(); } // Autoscrolling is active if ((o.autoScrollingMode.length > 0) && !(o.hiddenOnStart)) { self.startAutoScrolling(); } // If the user wants to have visible hotspot backgrounds, // here is where it's taken care of if (o.autoScrollingMode !== "always") { switch (o.visibleHotSpotBackgrounds) { case "always": self.showHotSpotBackgrounds(); break; case "onStart": self.showHotSpotBackgrounds(); el.data("hideHotSpotBackgroundsInterval", setTimeout(function () { self.hideHotSpotBackgrounds(250); }, o.hotSpotsVisibleTime)); break; case "hover": el.mouseenter(function (event) { if (o.hotSpotScrolling) { event.stopPropagation(); self.showHotSpotBackgrounds(250); } }).mouseleave(function (event) { if (o.hotSpotScrolling) { event.stopPropagation(); self.hideHotSpotBackgrounds(250); } }); break; default: break; } } self._showHideHotSpots(); self._trigger("setupComplete"); }); }, /********************************************************** Override _setOption and handle altered options **********************************************************/ _setOption: function (key, value) { var self = this, o = this.options, el = this.element; // Update option o[key] = value; if (key === "hotSpotScrolling") { // Handler if the option hotSpotScrolling is altered if (value === true) { self._showHideHotSpots(); } else { el.data("scrollingHotSpotLeft").hide(); el.data("scrollingHotSpotRight").hide(); } } else if (key === "autoScrollingStep" || // Make sure that certain values are integers, otherwise // they will summon bad spirits in the plugin key === "easingAfterHotSpotScrollingDistance" || key === "easingAfterHotSpotScrollingDuration" || key === "easingAfterMouseWheelScrollingDuration") { o[key] = parseInt(value, 10); } else if (key === "autoScrollingInterval") { // Handler if the autoScrollingInterval is altered o[key] = parseInt(value, 10); self.startAutoScrolling(); } }, /********************************************************** Hotspot functions **********************************************************/ showHotSpotBackgrounds: function (fadeSpeed) { // Alter the CSS (SmoothDivScroll.css) if you want to customize // the look'n'feel of the visible hotspots var self = this, el = this.element, o = this.option; // Fade in the hotspot backgrounds if (fadeSpeed !== undefined) { // Before the fade-in starts, we need to make sure the opacity is zero //el.data("scrollingHotSpotLeft").add(el.data("scrollingHotSpotRight")).css("opacity", "0.0"); el.data("scrollingHotSpotLeft").addClass("scrollingHotSpotLeftVisible"); el.data("scrollingHotSpotRight").addClass("scrollingHotSpotRightVisible"); // Fade in the hotspots el.data("scrollingHotSpotLeft").add(el.data("scrollingHotSpotRight")).fadeTo(fadeSpeed, 0.35); } // Don't fade, just show them else { // The left hotspot el.data("scrollingHotSpotLeft").addClass("scrollingHotSpotLeftVisible"); el.data("scrollingHotSpotLeft").removeAttr("style"); // The right hotspot el.data("scrollingHotSpotRight").addClass("scrollingHotSpotRightVisible"); el.data("scrollingHotSpotRight").removeAttr("style"); } self._showHideHotSpots(); }, hideHotSpotBackgrounds: function (fadeSpeed) { var el = this.element, o = this.option; // Fade out the hotspot backgrounds if (fadeSpeed !== undefined) { // Fade out the left hotspot el.data("scrollingHotSpotLeft").fadeTo(fadeSpeed, 0.0, function () { el.data("scrollingHotSpotLeft").removeClass("scrollingHotSpotLeftVisible"); }); // Fade out the right hotspot el.data("scrollingHotSpotRight").fadeTo(fadeSpeed, 0.0, function () { el.data("scrollingHotSpotRight").removeClass("scrollingHotSpotRightVisible"); }); } // Don't fade, just hide them else { el.data("scrollingHotSpotLeft").removeClass("scrollingHotSpotLeftVisible").removeAttr("style"); el.data("scrollingHotSpotRight").removeClass("scrollingHotSpotRightVisible").removeAttr("style"); } }, // Function for showing and hiding hotspots depending on the // offset of the scrolling _showHideHotSpots: function () { var self = this, el = this.element, o = this.options; // Hot spot scrolling is not enabled so show no hot spots if (!(o.hotSpotScrolling)) { el.data("scrollingHotSpotLeft").hide(); el.data("scrollingHotSpotRight").hide(); } else { // If the manual continuous scrolling option is set show both if (o.manualContinuousScrolling && o.hotSpotScrolling && o.autoScrollingMode !== "always") { el.data("scrollingHotSpotLeft").show(); el.data("scrollingHotSpotRight").show(); } // Autoscrolling not set to always and hotspot scrolling enabled. // Regular hot spot scrolling. else if (o.autoScrollingMode !== "always" && o.hotSpotScrolling) { // If the scrollable area is shorter than the scroll wrapper, both hotspots // should be hidden if (el.data("scrollableAreaWidth") <= (el.data("scrollWrapper").innerWidth())) { el.data("scrollingHotSpotLeft").hide(); el.data("scrollingHotSpotRight").hide(); } // When you can't scroll further left the left scroll hotspot should be hidden // and the right hotspot visible. else if (el.data("scrollWrapper").scrollLeft() === 0) { el.data("scrollingHotSpotLeft").hide(); el.data("scrollingHotSpotRight").show(); // Callback self._trigger("scrollerLeftLimitReached"); // Clear interval clearInterval(el.data("leftScrollingInterval")); el.data("leftScrollingInterval", null); } // When you can't scroll further right // the right scroll hotspot should be hidden // and the left hotspot visible else if (el.data("scrollableAreaWidth") <= (el.data("scrollWrapper").innerWidth() + el.data("scrollWrapper").scrollLeft())) { el.data("scrollingHotSpotLeft").show(); el.data("scrollingHotSpotRight").hide(); // Callback self._trigger("scrollerRightLimitReached"); // Clear interval clearInterval(el.data("rightScrollingInterval")); el.data("rightScrollingInterval", null); } // If you are somewhere in the middle of your // scrolling, both hotspots should be visible else { el.data("scrollingHotSpotLeft").show(); el.data("scrollingHotSpotRight").show(); } } // If auto scrolling is set to always, there should be no hotspots else { el.data("scrollingHotSpotLeft").hide(); el.data("scrollingHotSpotRight").hide(); } } }, // Function for calculating the scroll position of a certain element _setElementScrollPosition: function (method, element) { var el = this.element, o = this.options, tempScrollPosition = 0; switch (method) { case "first": el.data("scrollXPos", 0); return true; case "start": // Check to see if there is a specified start element in the options // and that the element exists in the DOM if (o.startAtElementId !== "") { if (el.data("scrollableArea").has("#" + o.startAtElementId)) { tempScrollPosition = $("#" + o.startAtElementId).position().left; el.data("scrollXPos", tempScrollPosition); return true; } } return false; case "last": el.data("scrollXPos", (el.data("scrollableAreaWidth") - el.data("scrollWrapper").innerWidth())); return true; case "number": // Check to see that an element number is passed if (!(isNaN(element))) { tempScrollPosition = el.data("scrollableArea").children(o.countOnlyClass).eq(element - 1).position().left; el.data("scrollXPos", tempScrollPosition); return true; } return false; case "id": // Check that an element id is passed and that the element exists in the DOM if (element.length > 0) { if (el.data("scrollableArea").has("#" + element)) { tempScrollPosition = $("#" + element).position().left; el.data("scrollXPos", tempScrollPosition); return true; } } return false; default: return false; } }, /********************************************************** Jumping to a certain element **********************************************************/ jumpToElement: function (jumpTo, element) { var self = this, el = this.element; // Check to see that the scroller is enabled if (el.data("enabled")) { // Get the position of the element to scroll to if (self._setElementScrollPosition(jumpTo, element)) { // Jump to the element el.data("scrollWrapper").scrollLeft(el.data("scrollXPos")); // Check the hotspots self._showHideHotSpots(); // Trigger the right callback switch (jumpTo) { case "first": self._trigger("jumpedToFirstElement"); break; case "start": self._trigger("jumpedToStartElement"); break; case "last": self._trigger("jumpedToLastElement"); break; case "number": self._trigger("jumpedToElementNumber", null, { "elementNumber": element }); break; case "id": self._trigger("jumpedToElementId", null, { "elementId": element }); break; default: break; } } } }, /********************************************************** Scrolling to a certain element **********************************************************/ scrollToElement: function (scrollTo, element) { var self = this, el = this.element, o = this.options, autoscrollingWasRunning = false; if (el.data("enabled")) { // Get the position of the element to scroll to if (self._setElementScrollPosition(scrollTo, element)) { // Stop any ongoing auto scrolling if (el.data("autoScrollingInterval") !== null) { self.stopAutoScrolling(); autoscrollingWasRunning = true; } // Stop any other running animations // (clear queue but don't jump to the end) el.data("scrollWrapper").stop(true, false); // Do the scolling animation el.data("scrollWrapper").animate({ scrollLeft: el.data("scrollXPos") }, { duration: o.scrollToAnimationDuration, easing: o.scrollToEasingFunction, complete: function () { // If auto scrolling was running before, start it again if (autoscrollingWasRunning) { self.startAutoScrolling(); } self._showHideHotSpots(); // Trigger the right callback switch (scrollTo) { case "first": self._trigger("scrolledToFirstElement"); break; case "start": self._trigger("scrolledToStartElement"); break; case "last": self._trigger("scrolledToLastElement"); break; case "number": self._trigger("scrolledToElementNumber", null, { "elementNumber": element }); break; case "id": self._trigger("scrolledToElementId", null, { "elementId": element }); break; default: break; } } }); } } }, move: function (pixels) { var self = this, el = this.element, o = this.options; // clear queue, move to end el.data("scrollWrapper").stop(true, true); // Only run this code if it's possible to scroll left or right, if ((pixels < 0 && el.data("scrollWrapper").scrollLeft() > 0) || (pixels > 0 && el.data("scrollableAreaWidth") > (el.data("scrollWrapper").innerWidth() + el.data("scrollWrapper").scrollLeft()))) { if (o.easingAfterMouseWheelScrolling) { el.data("scrollWrapper").animate({ scrollLeft: el.data("scrollWrapper").scrollLeft() + pixels }, { duration: o.easingAfterMouseWheelScrollingDuration, easing: o.easingAfterMouseWheelFunction, complete: function () { self._showHideHotSpots(); if (o.manualContinuousScrolling) { if (pixels > 0) { self._checkContinuousSwapRight(); } else { self._checkContinuousSwapLeft(); } } } }); } else { el.data("scrollWrapper").scrollLeft(el.data("scrollWrapper").scrollLeft() + pixels); self._showHideHotSpots(); if (o.manualContinuousScrolling) { if (pixels > 0) { self._checkContinuousSwapRight(); } else { self._checkContinuousSwapLeft(); } } } } }, /********************************************************** Adding or replacing content **********************************************************/ /* Arguments are: content - a valid URL to a Flickr feed - string manipulationMethod - addFirst, addLast or replace (default) - string */ getFlickrContent: function (content, manipulationMethod) { var self = this, el = this.element; $.getJSON(content, function (data) { // small square - size is 75x75 // thumbnail -> large - size is the longest side var flickrImageSizes = [{ size: "small square", pixels: 75, letter: "_s" }, { size: "thumbnail", pixels: 100, letter: "_t" }, { size: "small", pixels: 240, letter: "_m" }, { size: "medium", pixels: 500, letter: "" }, { size: "medium 640", pixels: 640, letter: "_z" }, { size: "large", pixels: 1024, letter: "_b"}]; var loadedFlickrImages = []; var imageIdStringBuffer = []; var startingIndex; var numberOfFlickrItems = data.items.length; var loadedFlickrImagesCounter = 0; // Determine a plausible starting value for the // image height if (el.data("scrollableAreaHeight") <= 75) { startingIndex = 0; } else if (el.data("scrollableAreaHeight") <= 100) { startingIndex = 1; } else if (el.data("scrollableAreaHeight") <= 240) { startingIndex = 2; } else if (el.data("scrollableAreaHeight") <= 500) { startingIndex = 3; } else if (el.data("scrollableAreaHeight") <= 640) { startingIndex = 4; } else { startingIndex = 5; } // Put all items from the feed in an array. // This is necessary $.each(data.items, function (index, item) { loadFlickrImage(item, startingIndex); }); function loadFlickrImage(item, sizeIndex) { var path = item.media.m; var imgSrc = path.replace("_m", flickrImageSizes[sizeIndex].letter); var tempImg = $("").attr("src", imgSrc); tempImg.load(function () { // Is it still smaller? Load next size if (this.height < el.data("scrollableAreaHeight")) { // Load a bigger image, if possible if ((sizeIndex + 1) < flickrImageSizes.length) { loadFlickrImage(item, sizeIndex + 1); } else { addImageToLoadedImages(this); } } else { addImageToLoadedImages(this); } // Finishing stuff to do when all images have been loaded if (loadedFlickrImagesCounter === numberOfFlickrItems) { switch (manipulationMethod) { case "addFirst": // Add the loaded content first in the scrollable area el.data("scrollableArea").children(":first").before(loadedFlickrImages); break; case "addLast": // Add the loaded content last in the scrollable area el.data("scrollableArea").children(":last").after(loadedFlickrImages); break; default: // Replace the content in the scrollable area el.data("scrollableArea").html(loadedFlickrImages); break; } // Recalculate the total width of the elements inside the scrollable area self.recalculateScrollableArea(); // Determine which hotspots to show self._showHideHotSpots(); // Trigger callback self._trigger("addedFlickrContent", null, { "addedElementIds": imageIdStringBuffer }); } }); } // Add the loaded content first or last in the scrollable area function addImageToLoadedImages(imageObj) { // Calculate the scaled width var widthScalingFactor = el.data("scrollableAreaHeight") / imageObj.height; var tempWidth = Math.round(imageObj.width * widthScalingFactor); // Set an id for the image - the filename is used as an id var tempIdArr = $(imageObj).attr("src").split("/"); var lastElemIndex = (tempIdArr.length - 1); tempIdArr = tempIdArr[lastElemIndex].split("."); $(imageObj).attr("id", tempIdArr[0]); // Set the height of the image to the height of the scrollable area and add the width $(imageObj).css({ "height": el.data("scrollableAreaHeight"), "width": tempWidth }); // Add the id of the image to the array of id's - this // is used as a parameter when the callback is triggered imageIdStringBuffer.push(tempIdArr[0]); // Add the image to the array of loaded images loadedFlickrImages.push(imageObj); // Increment counter for loaded images loadedFlickrImagesCounter++; } }); }, /* Arguments are: content - a valid URL to an AJAX content source - string manipulationMethod - addFirst, addLast or replace (default) - string filterTag - a jQuery selector that matches the elements from the AJAX content source that you want, for example ".myClass" or "#thisDiv" or "div" - string */ getAjaxContent: function (content, manipulationMethod, filterTag) { var self = this, el = this.element; $.ajaxSetup({ cache: false }); $.get(content, function (data) { var filteredContent; if (filterTag !== undefined) { if (filterTag.length > 0) { // A bit of a hack since I can't know if the element // that the user wants is a direct child of body (= use filter) // or other types of elements (= use find) filteredContent = $("
").html(data).find(filterTag); } else { filteredContent = content; } } else { filteredContent = data; } switch (manipulationMethod) { case "addFirst": // Add the loaded content first in the scrollable area el.data("scrollableArea").children(":first").before(filteredContent); break; case "addLast": // Add the loaded content last in the scrollable area el.data("scrollableArea").children(":last").after(filteredContent); break; default: // Replace the content in the scrollable area el.data("scrollableArea").html(filteredContent); break; } // Recalculate the total width of the elements inside the scrollable area self.recalculateScrollableArea(); // Determine which hotspots to show self._showHideHotSpots(); // Trigger callback self._trigger("addedAjaxContent"); }); }, getHtmlContent: function (content, manipulationMethod, filterTag) { var self = this, el = this.element; // No AJAX involved at all - just add raw HTML-content /* Arguments are: content - any raw HTML that you want - string manipulationMethod - addFirst, addLast or replace (default) - string filterTag - a jQuery selector that matches the elements from the AJAX content source that you want, for example ".myClass" or "#thisDiv" or "div" - string */ var filteredContent; if (filterTag !== undefined) { if (filterTag.length > 0) { // A bit of a hack since I can't know if the element // that the user wants is a direct child of body (= use filter) // or other types of elements (= use find) filteredContent = $("
").html(content).find(filterTag); } else { filteredContent = content; } } else { filteredContent = content; } switch (manipulationMethod) { case "addFirst": // Add the loaded content first in the scrollable area el.data("scrollableArea").children(":first").before(filteredContent); break; case "addLast": // Add the loaded content last in the scrollable area el.data("scrollableArea").children(":last").after(filteredContent); break; default: // Replace the content in the scrollable area el.data("scrollableArea").html(filteredContent); break; } // Recalculate the total width of the elements inside the scrollable area self.recalculateScrollableArea(); // Determine which hotspots to show self._showHideHotSpots(); // Trigger callback self._trigger("addedHtmlContent"); }, /********************************************************** Recalculate the scrollable area **********************************************************/ recalculateScrollableArea: function () { var tempScrollableAreaWidth = 0, foundStartAtElement = false, o = this.options, el = this.element; // Add up the total width of all the items inside the scrollable area el.data("scrollableArea").children(o.countOnlyClass).each(function () { // Check to see if the current element in the loop is the one where the scrolling should start if ((o.startAtElementId.length > 0) && (($(this).attr("id")) === o.startAtElementId)) { el.data("startingPosition", tempScrollableAreaWidth); foundStartAtElement = true; } tempScrollableAreaWidth = tempScrollableAreaWidth + $(this).outerWidth(true); }); // If the element with the ID specified by startAtElementId // is not found, reset it if (!(foundStartAtElement)) { el.data("startAtElementId", ""); } // Set the width of the scrollable area el.data("scrollableAreaWidth", tempScrollableAreaWidth); el.data("scrollableArea").width(el.data("scrollableAreaWidth")); // Move to the starting position el.data("scrollWrapper").scrollLeft(el.data("startingPosition")); el.data("scrollXPos", el.data("startingPosition")); }, /********************************************************** Get current scrolling left offset **********************************************************/ getScrollerOffset: function () { var el = this.element; // Returns the current left offset // Please remember that if the scroller is in continuous // mode, the offset is not that relevant anymore since // the plugin will swap the elements inside the scroller // around and manipulate the offset in this process. return el.data("scrollWrapper").scrollLeft(); }, /********************************************************** Stopping, starting and doing the auto scrolling **********************************************************/ stopAutoScrolling: function () { var self = this, el = this.element; if (el.data("autoScrollingInterval") !== null) { clearInterval(el.data("autoScrollingInterval")); el.data("autoScrollingInterval", null); // Check to see which hotspots should be active // in the position where the scroller has stopped self._showHideHotSpots(); self._trigger("autoScrollingStopped"); } }, /********************************************************** Start Autoscrolling **********************************************************/ startAutoScrolling: function () { var self = this, el = this.element, o = this.options; if (el.data("enabled")) { self._showHideHotSpots(); // Stop any running interval clearInterval(el.data("autoScrollingInterval")); el.data("autoScrollingInterval", null); // Callback self._trigger("autoScrollingStarted"); // Start interval el.data("autoScrollingInterval", setInterval(function () { // If the scroller is not visible or // if the scrollable area is shorter than the scroll wrapper // any running auto scroll interval should stop. if (!(el.data("visible")) || (el.data("scrollableAreaWidth") <= (el.data("scrollWrapper").innerWidth()))) { // Stop any running interval clearInterval(el.data("autoScrollingInterval")); el.data("autoScrollingInterval", null); } else { // Store the old scrollLeft value to see if the scrolling has reached the end el.data("previousScrollLeft", el.data("scrollWrapper").scrollLeft()); switch (o.autoScrollingDirection) { case "right": el.data("scrollWrapper").scrollLeft(el.data("scrollWrapper").scrollLeft() + o.autoScrollingStep); if (el.data("previousScrollLeft") === el.data("scrollWrapper").scrollLeft()) { self._trigger("autoScrollingRightLimitReached"); clearInterval(el.data("autoScrollingInterval")); el.data("autoScrollingInterval", null); self._trigger("autoScrollingIntervalStopped"); } break; case "left": el.data("scrollWrapper").scrollLeft(el.data("scrollWrapper").scrollLeft() - o.autoScrollingStep); if (el.data("previousScrollLeft") === el.data("scrollWrapper").scrollLeft()) { self._trigger("autoScrollingLeftLimitReached"); clearInterval(el.data("autoScrollingInterval")); el.data("autoScrollingInterval", null); self._trigger("autoScrollingIntervalStopped"); } break; case "backAndForth": if (el.data("pingPongDirection") === "right") { el.data("scrollWrapper").scrollLeft(el.data("scrollWrapper").scrollLeft() + (o.autoScrollingStep)); } else { el.data("scrollWrapper").scrollLeft(el.data("scrollWrapper").scrollLeft() - (o.autoScrollingStep)); } // If the scrollLeft hasnt't changed it means that the scrolling has reached // the end and the direction should be switched if (el.data("previousScrollLeft") === el.data("scrollWrapper").scrollLeft()) { if (el.data("pingPongDirection") === "right") { el.data("pingPongDirection", "left"); self._trigger("autoScrollingRightLimitReached"); } else { el.data("pingPongDirection", "right"); self._trigger("autoScrollingLeftLimitReached"); } } break; case "endlessLoopRight": // Do the auto scrolling el.data("scrollWrapper").scrollLeft(el.data("scrollWrapper").scrollLeft() + o.autoScrollingStep); self._checkContinuousSwapRight(); break; case "endlessLoopLeft": // Do the auto scrolling el.data("scrollWrapper").scrollLeft(el.data("scrollWrapper").scrollLeft() - o.autoScrollingStep); self._checkContinuousSwapLeft(); break; default: break; } } }, o.autoScrollingInterval)); } }, /********************************************************** Check Continuos Swap Right **********************************************************/ _checkContinuousSwapRight: function () { var el = this.element, o = this.options; // Get the width of the first element. When it has scrolled out of view, // the element swapping should be executed. A true/false variable is used // as a flag variable so the swapAt value doesn't have to be recalculated // in each loop. if (el.data("getNextElementWidth")) { if ((o.startAtElementId.length > 0) && (el.data("startAtElementHasNotPassed"))) { // If the user has set a certain element to start at, set swapAt // to that element width. This happens once. el.data("swapAt", $("#" + o.startAtElementId).outerWidth(true)); el.data("startAtElementHasNotPassed", false); } else { // Set swapAt to the first element in the scroller el.data("swapAt", el.data("scrollableArea").children(":first").outerWidth(true)); } el.data("getNextElementWidth", false); } // Check to see if the swap should be done if (el.data("swapAt") <= el.data("scrollWrapper").scrollLeft()) { el.data("swappedElement", el.data("scrollableArea").children(":first").detach()); el.data("scrollableArea").append(el.data("swappedElement")); var wrapperLeft = el.data("scrollWrapper").scrollLeft(); el.data("scrollWrapper").scrollLeft(wrapperLeft - el.data("swappedElement").outerWidth(true)); el.data("getNextElementWidth", true); } }, /********************************************************** Check Continuos Swap Left **********************************************************/ _checkContinuousSwapLeft: function () { var el = this.element, o = this.options; // Get the width of the first element. When it has scrolled out of view, // the element swapping should be executed. A true/false variable is used // as a flag variable so the swapAt value doesn't have to be recalculated // in each loop. if (el.data("getNextElementWidth")) { if ((o.startAtElementId.length > 0) && (el.data("startAtElementHasNotPassed"))) { el.data("swapAt", $("#" + o.startAtElementId).outerWidth(true)); el.data("startAtElementHasNotPassed", false); } else { el.data("swapAt", el.data("scrollableArea").children(":first").outerWidth(true)); } el.data("getNextElementWidth", false); } // Check to see if the swap should be done if (el.data("scrollWrapper").scrollLeft() === 0) { el.data("swappedElement", el.data("scrollableArea").children(":last").detach()); el.data("scrollableArea").prepend(el.data("swappedElement")); el.data("scrollWrapper").scrollLeft(el.data("scrollWrapper").scrollLeft() + el.data("swappedElement").outerWidth(true)); el.data("getNextElementWidth", true); } }, restoreOriginalElements: function () { var self = this, el = this.element; // Restore the original content of the scrollable area el.data("scrollableArea").html(el.data("originalElements")); self.recalculateScrollableArea(); self.jumpToElement("first"); }, show: function () { var el = this.element; el.data("visible", true); el.show(); }, hide: function () { var el = this.element; el.data("visible", false); el.hide(); }, enable: function () { var el = this.element; // Set enabled to true el.data("enabled", true); }, disable: function () { var self = this, el = this.element; // Clear all running intervals self.stopAutoScrolling(); clearInterval(el.data("rightScrollingInterval")); clearInterval(el.data("leftScrollingInterval")); clearInterval(el.data("hideHotSpotBackgroundsInterval")); // Set enabled to false el.data("enabled", false); }, destroy: function () { var self = this, el = this.element; // Clear all running intervals self.stopAutoScrolling(); clearInterval(el.data("rightScrollingInterval")); clearInterval(el.data("leftScrollingInterval")); clearInterval(el.data("hideHotSpotBackgroundsInterval")); // Remove all element specific events el.data("scrollingHotSpotRight").unbind("mouseover"); el.data("scrollingHotSpotRight").unbind("mouseout"); el.data("scrollingHotSpotRight").unbind("mousedown"); el.data("scrollingHotSpotLeft").unbind("mouseover"); el.data("scrollingHotSpotLeft").unbind("mouseout"); el.data("scrollingHotSpotLeft").unbind("mousedown"); el.unbind("mousenter"); el.unbind("mouseleave"); // Remove all elements created by the plugin el.data("scrollingHotSpotRight").remove(); el.data("scrollingHotSpotLeft").remove(); el.data("scrollableArea").remove(); el.data("scrollWrapper").remove(); // Restore the original content of the scrollable area el.html(el.data("originalElements")); // Call the base destroy function $.Widget.prototype.destroy.apply(this, arguments); } }); })(jQuery);