﻿/**
* jQuery.smoothDivScroll - Smooth div scrolling using jQuery.
* This plugin is for turning a set of HTML elements's into a smooth scrolling area.
*
* Copyright (c) 2009 Thomas Kahn - thomas.kahn(at)karnhuset(dot)net
* 
* Date: 2009-05-23
* @author Thomas Kahn
* @version 0.8
*
* New version with prototype framework
*/
// Calculer la somme des valeurs d'un array
Array.prototype.sum = function(){
	for(var i=0,sum=0;i<this.length;sum+=this[i++]);
	return sum;
}
// retourne la largeur réelle d'un conteneur
Element.prototype.getInnerWidth = function(){
	return this.childElements().invoke("getWidth").sum();
}
Element.prototype.getInnerHeight = function(){
	return this.childElements().invoke("getHeight").sum();
}




var ScrollBox = Class.create();

Object.extend(ScrollBox.prototype,{
	initialize: function(elem,options){
		var defaults = {
		scrollingHotSpotLeft: ".scrollingHotSpotLeft", // The hot spot that triggers scrolling left.
		scrollingHotSpotRight: ".scrollingHotSpotRight", // The hot spot that triggers scrolling right.
		scrollWrapper: ".scrollWrapper", // The wrapper element that surrounds the scrollable area
		scrollableArea: ".scrollableArea", // The actual element that is scrolled left or right
		hiddenOnStart: false, // True or false. Determines whether the element should be visible or hidden on start
		ajaxContentURL: "", // Optional. If supplied, content is fetched through AJAX using the supplied URL
		countOnlyClass: "", // Optional. If supplied, the function that calculates the width of the scrollable area will only count elements of this class
		scrollingSpeed: 25, // A way of controlling the scrolling speed. 1=slowest and 100= fastest.
		mouseDownSpeedBooster: 3, // 1 is normal speed (no speed boost), 2 is twice as fast, 3 is three times as fast, and so on
		autoScroll: "", // Optional. Leave it blank if you don't want any autoscroll. 
						// Otherwise use the values "onstart" or "always". 
						// onstart - the scrolling will start automatically after 
						// the page has loaded and scroll according to the method you've selected 
						// using the autoScrollDirection parameter. When the user moves the mouse 
						// over the left or right hot spot the autoscroll will stop. After that 
						// the scrolling will only be triggered by the host spots.
						// always - the hot spots are disabled alltogether and the scrollable area 
						// will only scroll automatically.
		autoScrollDirection: "right", 	// This parameter controls the direction and behavior of the autoscrolling.	
										// Optional. The values are:
										// right - autoscrolls right and stops when it reaches the end
										// left - autoscrolls left and stops when it reaches the end 
										// (only relevant if you have set the parameter startAtElementId).
										// backandforth - starts autoscrolling right and when it reaches 
										// the end, switches to autoscrolling left and so on. Ping-pong style.
										// endlessloop - continuous scrolling right. An endless loop of elements.
		autoScrollSpeed: 1,	//  1-2 = slow, 3-4 = medium, 5-13 = fast -- anything higher = superfast
		pauseAutoScroll: "", // Optional. Values mousedown and mouseover. Leave blank for no pausing abilities.
		visibleHotSpots: "", 	// Optional. Leave it blank for invisible hot spots. 
								// Otherwise use the values  "onstart" or "always". 
								// onstart - makes the hot spots visible for X-number of seconds 
								// after tha page has loaded and then they become invisible. 
								// always - hot spots are visible all the time.
		hotSpotsVisibleTime: 5, // If you have selected "onstart" as the value for visibleHotSpots, 
								// you set the number of seconds that you want the hot spots to be 
								// visible after the page has loaded. After this time they will fade 
								// away and become invisible again.
		startAtElementId: ""	// Optional. Use this parameter if you want the offset of the 
								// scrollable area to be positioned at a specific element directly 
								// after the page has loaded. First give your element an ID in the 
								// HTML code and then provide this ID as a parameter.
		};

		Object.extend(defaults,options);

		/* Identify global variables so JSLint won't raise errors when verifying the code */
		/*global autoScrollInterval, autoScroll, clearInterval, doScrollLeft, doScrollRight, hideHotSpotBackgrounds, hideHotSpotBackgroundsInterval, hideLeftHotSpot, hideRightHotSpot, jQuery, makeHotSpotBackgroundsVisible, setHotSpotHeightForIE, setInterval, showHideHotSpots, window, windowIsResized */
		var elements = new Array(elem);

		// Iterate and make each matched element a SmoothDivScroll
		return elements.each(function(item) {
			// Create a variable for the current "mother element"
			var $mom = $(item);
			
			/*****
		 *   START FUNCTIONS DEFINITION
		 */
		// The function that does the actual scrolling left
			function doScrollLeft()
			{	
				if(scrollXpos > 0) {
					$mom.down(defaults.scrollWrapper).scrollLeft = $mom.down(defaults.scrollWrapper).scrollLeft - (scrollXpos*booster);
				}
				showHideHotSpots();
			};
			
			// **************************************************
			// Hot spot functions
			// **************************************************
			
			// Function for showing and hiding hot spots depending on the
			// offset of the scrolling
			function showHideHotSpots()
			{
				// When you can't scroll further left
				// the left scroll hot spot should be hidden
				// and the right hot spot visible
				if($mom.down(defaults.scrollWrapper).scrollLeft === 0)
				{
					hideLeftHotSpot();
					showRightHotSpot();
				}
				// When you can't scroll further right
				// the right scroll hot spot should be hidden
				// and the left hot spot visible
				else if(($mom.scrollableAreaWidth) <= ($mom.down(defaults.scrollWrapper).getInnerWidth() + $mom.down(defaults.scrollWrapper).scrollLeft))
				{
					hideRightHotSpot();
					showLeftHotSpot();
				}
				// If you are somewhere in the middle of your
				// scrolling, both hot spots should be visible
				else
				{
					showRightHotSpot();
					showLeftHotSpot();
				}

			}
			
			// Function for making the hot spot background visible
			function makeHotSpotBackgroundsVisible()
			{
				// Alter the CSS (SmoothDivScroll.css) if you want to customize
				// the look'n'feel of the visible hot spots
				
				// The left hot spot
				$mom.down(defaults.scrollingHotSpotLeft).addClass("scrollingHotSpotLeftVisible");

				// The right hot spot
				$mom.down(defaults.scrollingHotSpotRight).addClass("scrollingHotSpotRightVisible");
			}
			
			// Hide the hot spot backgrounds.
			function hideHotSpotBackgrounds()
			{
				clearInterval($mom.hideHotSpotBackgroundsInterval);
				
				// Fade out the left hot spot
				$mom.down(defaults.scrollingHotSpotLeft).fade({ duration: 0.5, onComplete: function(){
					$mom.down(defaults.scrollingHotSpotLeft).removeClass("scrollingHotSpotLeftVisible");
				}});

				// Fade out the right hot spot
				$mom.down(defaults.scrollingHotSpotRight).fade({ duration: 0.5, onComplete: function(){
					$mom.down(defaults.scrollingHotSpotRight).removeClass("scrollingHotSpotRightVisible");
				}});
			}
			
			
			// A function for doing the stuff that needs to be
			// done when the browser window is resized
			function windowIsResized() {
			
				// If the scrollable area is not hidden on start, reset and recalculate the
				// width of the scrollable area
				if(!(defaults.hiddenOnStart))
				{
					$mom.scrollableAreaWidth = 0;
					var elems = defaults.countOnlyClass !='' ?  $$("."+defaults.countOnlyClass) : $mom.down(defaults.scrollableArea).childElements();
					elems.each(function(item) {
						$mom.scrollableAreaWidth = $mom.scrollableAreaWidth + $(item).getInnerWidth();
					});
					
					$mom.down(defaults.scrollableArea).setStyle({width: $mom.scrollableAreaWidth + 'px'});
				}

				// Reset the left offset of the scroll wrapper
				$mom.down(defaults.scrollWrapper).scrollLeft = 0;
				
				// Get the width of the page (body)
				var bodyWidth = $("body").innerWidth;
				
				// If the scrollable area is shorter than the current
				// window width, both scroll hot spots should be hidden.
				// Otherwise, check which hot spots should be shown.
				if(defaults.autoScroll !== "always")
				{
					if($mom.scrollableAreaWidth < bodyWidth)
					{	
						hideLeftHotSpot();
						hideRightHotSpot();
					}
					else
					{
						showHideHotSpots();
					}
				}
			}
			
			// HELPER FUNCTIONS FOR SHOWING AND HIDING HOT SPOTS
			function hideLeftHotSpot(){
				$mom.down(defaults.scrollingHotSpotLeft).hide();
			}
			
			function hideRightHotSpot(){
				$mom.down(defaults.scrollingHotSpotRight).hide();
			}
			
			function showLeftHotSpot(){
				$mom.down(defaults.scrollingHotSpotLeft).show();
				// Recalculate the hot spot width. Do it here because you can
				// be sure that the hot spot is visible and has a width
				if(hotSpotWidth <= 0) {
					hotSpotWidth = $mom.down(defaults.scrollingHotSpotLeft).getWidth();
				}
			}
			
			function showRightHotSpot(){
				$mom.down(defaults.scrollingHotSpotRight).show();
				// Recalculate the hot spot width. Do it here because you can
				// be sure that the hot spot is visible and has a width
				if(hotSpotWidth <= 0) {
					hotSpotWidth = $mom.down(defaults.scrollingHotSpotRight).getWidth();
				}
			}
			
			function setHotSpotHeightForIE()
			{
				// Some bugfixing for IE 6
				if(Prototype.Browser.IE6)
				{
					$mom.down(defaults.scrollingHotSpotLeft).setStyle({height : $mom.down(defaults.scrollableArea).childElements().invoke("getHeight").sum()});
					$mom.down(defaults.scrollingHotSpotRight).setStyle({height : $mom.down(defaults.scrollableArea).childElements().invoke("getHeight").sum()});		
				}
			}
			
			function moveTo(div, value){
				new Effect.Move( div, {x: value, y: 0});
			}
			
			// The function that does the actual scrolling right
			function doScrollRight()
			{	
				if(scrollXpos > 0) {
					$mom.down(defaults.scrollWrapper).scrollLeft = $mom.down(defaults.scrollWrapper).scrollLeft + (scrollXpos*booster);
				}
				showHideHotSpots();
			};
			// The autoScroll function
			function autoScroll()
			{	
				if (defaults.autoScroll == "onstart") {
					showHideHotSpots();
				}
				
				switch(defaults.autoScrollDirection)
				{
					case "right":
						$mom.down(defaults.scrollWrapper).scrollLeft = $mom.down(defaults.scrollWrapper).scrollLeft + defaults.autoScrollSpeed;
						break;
						
					case "left":
						$mom.down(defaults.scrollWrapper).scrollLeft = $mom.down(defaults.scrollWrapper).scrollLeft - defaults.autoScrollSpeed;
						break;
						
					case "backandforth":
						// Store the old scrollLeft value to see if the scrolling has reached the end
						$mom.previousScrollLeft = $mom.down(defaults.scrollWrapper).scrollLeft;
						
						if($mom.pingPongDirection == "right") {
							$mom.down(defaults.scrollWrapper).scrollLeft = $mom.down(defaults.scrollWrapper).scrollLeft + defaults.autoScrollSpeed;
						}
						else {
							$mom.down(defaults.scrollWrapper).scrollLeft = $mom.down(defaults.scrollWrapper).scrollLeft - defaults.autoScrollSpeed;
						}
						
						// If the scrollLeft hasnt't changed it means that the scrolling has reached
						// the end and the direction should be switched
						if($mom.previousScrollLeft === $mom.down(defaults.scrollWrapper).scrollLeft)
						{
							if($mom.pingPongDirection == "right") {
								$mom.pingPongDirection = "left";
							}
							else {
								$mom.pingPongDirection = "right";
							}
						}
						break;
		
					case "endlessloop":
						// 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($mom.getNextElementWidth)
						{
							if(defaults.startAtElementId !== "") {
								$mom.swapAt = $(defaults.startAtElementId).childElements().invoke("getWidth").sum();
							}
							else {
								$mom.swapAt = $mom.down(defaults.scrollableArea).firstDescendant().childElements().invoke("getWidth").sum();
							}
							
							$mom.getNextElementWidth = false;
						}
 
						// Do the autoscrolling
						$mom.down(defaults.scrollWrapper).scrollLeft += defaults.autoScrollSpeed;
//						if(Prototype.Browser.IE){
//							var plus = 0;
//						}else{
							var plus = 25;
//						}
						// Check to see if the swap should be done
						if(($mom.swapAt+plus <= $mom.down(defaults.scrollWrapper).scrollLeft))
						{ 
							var first = $mom.down(defaults.scrollableArea).firstDescendant();
							var elt = first.remove();
							// Clone the first element and append it last in the scrollableArea
							$mom.down(defaults.scrollableArea).insert({bottom:elt});

							// Compensate for the removal of the first element by
							$mom.down(defaults.scrollWrapper).scrollLeft = 0 /* $mom.down(defaults.scrollWrapper).scrollLeft - elt.getInnerWidth()*/;
							
							// Remove it from its original position as the first element
							
							
							$mom.getNextElementWidth = true;
						}
						break;
					default:
						break;
						
				}

			};
			
			/*****
			 *   END FUNCTIONS DEFINITION
			 */
			
			// Load the content of the scrollable area using the optional URL.
			// If no ajaxContentURL is supplied, we assume that the content of
			// the scrolling area is already in place.
			if(defaults.ajaxContentURL.length !== 0){
				$mom.scrollableAreaWidth = 0;
				new Ajax.Updater(defaults.ajaxContentURL,$mom.down(defaults.scrollableArea) ,{ 
					onComplete: function(){
						var elems = defaults.countOnlyClass !='' ?  $$("."+defaults.countOnlyClass) : $mom.down(defaults.scrollableArea).childElements();
						elems.each(function() {
							$mom.scrollableAreaWidth = $mom.scrollableAreaWidth + $(this).getInnerWidth();
						});
						// Set the width of the scrollable area
						$mom.down(defaults.scrollableArea).setStyle({width: $mom.scrollableAreaWidth + "px"});
						
						// Hide the mother element if it shouldn't be visible on start
						if(defaults.hiddenOnStart) {
							$mom.hide();
						}
						windowIsResized();
						setHotSpotHeightForIE();
					}
				});		
			}
			
			// Some variables used for working with the scrolling
			var scrollXpos;
			var booster;
			
			// The left offset of the container on which you place 
			// the scrolling behavior.
			// This offset is used when calculating the mouse x-position 
			// in relation to scroll hot spots
			var motherElementOffset = Element.positionedOffset($mom);
			
			// A variable used for storing the current hot spot width.
			// It is used when calculating the scroll speed
			var hotSpotWidth = 0;
			
			// Set the booster value to normal (doesn't change until the user
			// holds down the mouse button over one of the hot spots)
			booster = 1;
			
			var hasExtended = false;
			
									// Stuff to do once on load
//			Event.observe(document,"dom:loaded",function(){
				// If the content of the scrolling area is not loaded through ajax,
				// we assume it's already there and can run the code to calculate
				// the width of the scrolling area, resize it to that width
				if(defaults.ajaxContentURL.length === 0) {
					$mom.scrollableAreaWidth = 0;
					$mom.tempStartingPosition = 0;
					
					var elems = defaults.countOnlyClass !='' ?  $$("."+defaults.countOnlyClass) : $mom.down(defaults.scrollableArea).childElements();
						elems.each(function(it) {
						
						// Check to see if the current element in the loop is the one where the scrolling should start
						if( (defaults.startAtElementId.length !== 0) && ($(it).id == defaults.startAtElementId) ) {
						$mom.tempStartingPosition = $mom.scrollableAreaWidth;
						}

						var width = $(it).childElements().invoke("getWidth").sum();
						// Add the width of the current element in the loop to the total width
						$mom.scrollableAreaWidth  += width;
						
					});
					
					// Set the width of the scrollableArea to the accumulated width
					$mom.down(defaults.scrollableArea).setStyle({width : $mom.scrollableAreaWidth + "px"});
					
					// Check to see if the whole thing should be hidden at start
					if(defaults.hiddenOnStart) {
						$mom.hide();
					}
				}
				
				// Set the starting position of the scrollable area. If no startAtElementId is set, the starting position
				// will be the default value (zero)
				$mom.down(defaults.scrollWrapper).setStyle({scrollLeft : $mom.tempStartingPosition});
				
				// If the user has set the option autoScroll, the scollable area will
				// start scrolling automatically
				if(defaults.autoScroll !== "") {
					$mom.autoScrollInterval = setInterval(function(){ autoScroll(); }, 6);
				}

				// If autoScroll is set to always, the hot spots should be disabled
				if(defaults.autoScroll == "always")
				{
					hideLeftHotSpot();
					hideRightHotSpot();
				}
	
				// If the user wants to have visible hot spots, here is where it's taken care of
				switch(defaults.visibleHotSpots)
				{
					case "always":
						makeHotSpotBackgroundsVisible();
						break;
					case "onstart":
						makeHotSpotBackgroundsVisible();
						$mom.hideHotSpotBackgroundsInterval = setInterval(function(){ hideHotSpotBackgrounds(); }, (defaults.hotSpotsVisibleTime * 1000));
						break;
					default:
						break;	
				}
//			});
			
			// If autoScroll is running, here's where it's stopped when the user positions the mouse over one of the hot spots
			$mom.down(defaults.scrollingHotSpotRight).observe('mouseover',function(){
				if(defaults.autoScroll == "onstart") {
					clearInterval($mom.autoScrollInterval);
				}
			});	
			$mom.down(defaults.scrollingHotSpotLeft).observe('mouseover',function(){
				if(defaults.autoScroll == "onstart") {
					clearInterval($mom.autoScrollInterval);
				}
			});	

			
			// EVENT - window resize
			document.observe("resize",function(){
				windowIsResized();
			});

			
			
			
			// **************************************************
			// EVENTS - scroll right
			// **************************************************
			
			// Check the mouse X position and calculate the relative X position inside the right hot spot
			$mom.down(defaults.scrollingHotSpotRight).observe('mousemove',function(e){
				var x = e.pageX - (this.offsetLeft + motherElementOffset);
				scrollXpos = Math.round((x/hotSpotWidth) * defaults.scrollingSpeed);
				if(scrollXpos === Infinity) {
					scrollXpos = 0;
				}

			});

			// mouseover right hot spot
			$mom.down(defaults.scrollingHotSpotRight).observe('mouseover',function(){
				if(defaults.autoScroll == "onstart") {
					clearInterval($mom.autoScrollInterval);
				}
				$mom.rightScrollInterval = setInterval(function(){ doScrollRight(); }, 6);
			});	
			
			// mouseout right hot spot
			$mom.down(defaults.scrollingHotSpotRight).observe('mouseout',function(){
				clearInterval($mom.rightScrollInterval);
				scrollXpos = 0;
			});
			
			// scrolling speed booster right
			$mom.down(defaults.scrollingHotSpotRight).observe('mousedown',function(){
				booster = defaults.mouseDownSpeedBooster;
			});
			
			// stop boosting the scrolling speed
			elem.observe('mouseup',function(){
				booster = 1;
			});
	
			
			
			
			// **************************************************
			// Autoscrolling
			// **************************************************

			if(defaults.pauseAutoScroll == "mousedown" && defaults.autoScroll == "always")
			{
				$mom.down(defaults.scrollWrapper).observe('mousedown',function(){
					clearInterval($mom.autoScrollInterval);
				});
				
				$mom.down(defaults.scrollWrapper).observe('mouseup',function(){
					$mom.autoScrollInterval = setInterval(function(){ autoScroll();}, 6);
				});
			}
			else if(defaults.pauseAutoScroll == "mouseover" && defaults.autoScroll == "always")
			{
				$mom.down(defaults.scrollWrapper).observe('mouseover',function(){
					clearInterval($mom.autoScrollInterval);
				});
				
				$mom.down(defaults.scrollWrapper).observe('mouseout',function(){
					$mom.autoScrollInterval = setInterval(function(){ autoScroll();}, 6);
				});
			}
			
			$mom.previousScrollLeft = 0;
			$mom.pingPongDirection = "right";
			$mom.swapAt;
			$mom.getNextElementWidth = true;			
			
			// **************************************************
			// EVENTS - scroll left
			// **************************************************
		
			// Check the mouse X position and calculate the relative X position inside the left hot spot
			$mom.down(defaults.scrollingHotSpotLeft).observe('mousemove',function(e){
				var x = $mom.down(defaults.scrollingHotSpotLeft).getInnerWidth() - (e.pageX - motherElementOffset);
				scrollXpos = Math.round((x/hotSpotWidth) * defaults.scrollingSpeed);
				if(scrollXpos === Infinity)
				{
					scrollXpos = 0;
				}
			});
			
			// mouseover left hot spot
			$mom.down(defaults.scrollingHotSpotLeft).observe('mouseover',function(){
				if(defaults.autoScroll == "onstart") {
					clearInterval($mom.autoScrollInterval);
				}
				
				$mom.leftScrollInterval = setInterval(function(){ doScrollLeft();}, 6);
			});	
			
			// mouseout left hot spot
			$mom.down(defaults.scrollingHotSpotLeft).observe('mouseout',function(){
				clearInterval($mom.leftScrollInterval);
				scrollXpos = 0;
			});
			
			// scrolling speed booster left
			$mom.down(defaults.scrollingHotSpotLeft).observe('mousedown',function(){
				booster = defaults.mouseDownSpeedBooster;
			});
	});
}});
