/**
 * scroller
 * =============================================================================
 * d�filement doux de la page, notamment pour les liens vers des ancres
 * 
 * @author      Erwan Lef�vre <erwan.lefevre@aposte.net>
 * @copyright   Erwan Lef�vre 2009
 * @license     Creative Commons - Paternit� 2.0 France - http://creativecommons.org/licenses/by/2.0/fr/
 * @version     v2.1
 * @see			http://www.webbricks.org/bricks/scroller/
 * 
 */



/**
 * exemples d'utilisation :

-	pour appliquer l'effet automatiquement � tous les liens �ligibles de la page :

		scroller.auto();
		
-	pour appliquer l'effet � une liste de liens (les liens non �ligibles seront ignor�s) :

		scroller.applyTo(mes_liens);
		
-	pour appliquer d�clencher un scroll vers un �l�ment quelconque de la page :

		scroller.goTo(element_destination);

*/





/** 
 * getPos() v1.0
 * =============================================================================
 * retourne la position (dans la page) de chacun des c�t�s de l'�l�ment /elem/,
 * dispatch� dans un tableau associatif contenant les cl�s t|b|l|r
 * (la valeur retourn�e est donn�e en pixels)
 * (tient compte des diff�rences de fonctionnement des navigateur)
 *
 * @param           Object          elem            l'�l�ment inspect�
 * @return          Integer         
 * @access          public
 */

function getPos(elem) {
    var pos={'r':0,'l':0,'t':0,'b':0};
    var tmp=elem;
    
    // on proc�de de parent en parent car IE fonctionne comme �a
    // (les autres donnent directement la position par rapport � la page)
    
    do {
        pos.l += tmp.offsetLeft;
        tmp = tmp.offsetParent;
    } while( tmp !== null );
    pos.r = pos.l + elem.offsetWidth;
    
    tmp=elem;
    do {
        pos.t += tmp.offsetTop;
        tmp = tmp.offsetParent;
    } while( tmp !== null );
    pos.b = pos.t + elem.offsetHeight;
    
    return pos;
}





/** 
 * winDim() v2.0
 * =============================================================================
 * retourne les dimentions int�rieurs de la fen�tre
 *
 * @return		{Object}
 */

function winDim() {
	var w,h;
	if ( window.innerWidth ) { // autres que IE
		w = window.innerWidth;
		h = window.innerHeight;
	} else if ( document.documentElement.clientWidth ) { // IE8
		w = document.documentElement.clientWidth;
		h = document.documentElement.clientHeight;
	} else if ( document.body.clientWidth ) { // IE6
		w = document.body.clientWidth;
		h = document.body.clientHeight;
	} else { alert("winDim() n'est pas parvenu � lire les dimentions de la fen�tre"); }

	return {'w':w, 'h':h} ;
}





/** 
 * pageDim() v1.0
 * =============================================================================
 * retourne les dimentions de la page
 *
 * @return		{Object}		{'w','h'}
 */

function pageDim() {
	var w, h;
	
	// firefox is ok
	h = document.documentElement.scrollHeight;
	w = document.documentElement.scrollWidth;
	
	// now IE 7 + Opera with "min window"
	if ( document.documentElement.clientHeight > h ) { h  = document.documentElement.clientHeight; }
	if ( document.documentElement.clientWidth > w ) { w  = document.documentElement.clientWidth; }
	
	// last for safari
	if ( document.body.scrollHeight > h ) { h = document.body.scrollHeight; }
	if ( document.body.scrollWidth > w ) { w = document.body.scrollWidth; }

	return {'w':w, 'h':h} ;
}





/** scrolled() v1.0
 * =============================================================================
 * retoune les valeurs (horizontale et verticale) de d�filement de la fen�tre
 * (en tenant compte du navigateur)
 *
 * @return          Object      {'x','y'}         
 */

function scrolled () {
    var x,y;
    
    // vrais navigateurs
    if ( window.pageXOffset!==undefined) {
        x = window.pageXOffset;
        y = window.pageYOffset;
    }
    // ie
    else {
        x = document.documentElement.scrollLeft ? document.documentElement.scrollLeft : (document.body.scrollLeft?document.body.scrollLeft:0) ;
        y = document.documentElement.scrollTop ? document.documentElement.scrollTop : (document.body.scrollTop?document.body.scrollTop:0) ;
    }
    
    return {'x':x, 'y':y};
}






/** 
 * scroller() v2.1
 * =============================================================================
 */
var scroller = {
  
	nextStep : null, // re�oit les setTimeout
	delay : 1000/25, // dur�e des frames
	
	/** goTo() 
	 * -------------------------------------------------------------------------
	 * initialise et lance le scrolling
	 *
	 * @param		{HTMLelement}		target		l'�l�ment html, ou bien les coordonn�es {'x','y'} jusqu'o� scroller
	 * @return		{void}
	 */   
	goTo : function (target) {
		
		// lecture des coordonn�es de la destination du scroll
			if (window.opera && !target.innerHTML) { target.innerHTML=' &nbsp; '; } // opera ne sait pas retourner la position des <a> sans childNodes
			this.targetPos = getPos(target);
			if (window.opera && !target.innerHTML==' &nbsp; ') { target.innerHTML=''; } // pour opera, retour � la normale
		
		// en cas de destination trop proche du bord de la page, red�finir la position d�sir�e, pour ne pas "buter" contre le bord
			var pageHeight = pageDim().h;
			if ( this.targetPos.t + winDim().h > pageHeight ) {
				this.targetPos.t = pageHeight - winDim().h;
			}
			var pageWidth = pageDim().w;
			if ( this.targetPos.l + winDim().w > pageWidth ) {
				this.targetPos.l = pageWidth - winDim().w;
			}
		
		// lancer l'animation
			clearTimeout(this.nextStep);
			this.frame();
	},
	
	
	/** frame() 
	 * -------------------------------------------------------------------------
	 * effectue une �tape de l'animation
	 *
	 * @return		{void}
	 */   
	frame : function () {
		this.lastPos = scrolled();
		
		var movesSize = {
			'x' : Math.ceil ( (this.targetPos.l - scrolled().x ) / 3 ),
			'y' : Math.ceil ( (this.targetPos.t - scrolled().y ) / 3 )
		};
		this.proceeding = 1; // permet de dissocier le scroll g�n�r� par scroller du scroll g�n�r� autrement
		window.scrollBy (movesSize.x, movesSize.y);
		setTimeout(function(){scroller.proceeding = 0;},1); // setTimeout necessaire pour que le scrolling soit pass�
		
		// si on a boug� (horiz ou vert) depuis le dernier frame, alors faire un frame de plus
		if ( (this.lastPos.x != scrolled().x) || (this.lastPos.y != scrolled().y) ) { 
			clearTimeout(this.nextStep) ;
			this.nextStep = setTimeout ( 
				function() { scroller.frame(); }, 
				this.delay
			);	
		}
		// sinon c'est fini
		else { /* alert('fini'); */ }
	},
	
	
	/** stop() 
	 * -------------------------------------------------------------------------
	 * arr�te le scrolling
	 *
	 * @return		{void}
	 */   
	stop : function () {
		if (!scroller.proceeding) { clearTimeout(scroller.nextStep) ; }
	},

	
	
	/** applyTo() 
	 * -------------------------------------------------------------------------
	 * applique l'effet � tous les liens donn�s pointant vers des ancres
	 *
	 * @return		{void}
	 */   
	applyTo : function (linksList) {
		
		if (typeof linksList.length===undefined) { linksList = [linksList]; } // si un seul �l�ment, le placer dans une liste
		
		var link, i, targetName, noHash,
			nbLinks = linksList.length,
			thisPage = window.location.href.replace(window.location.hash, ''); // page actuelle (sans l'ancre)
		
		// pour chaque lien
		for (i=0; i<nbLinks; i++) { 
			link = linksList[i];
			targetName=link.href.match(/#.+/);
			// s'il y a une ancre dans le lien
			if (targetName) { 
				targetName = targetName[0].substring(1);
				noHash = link.href.replace(link.hash, ''); // page cibl�e (sans l'ancre)
				// si l'ancre concerne bien la page actuelle
				if (noHash==thisPage) { 
					link.onclick = new Function("scroller.goTo(document.getElementsByName('"+targetName+"')[0]); return false;");
				}
			}
		}
	},

	
	
	/** auto() 
	 * -------------------------------------------------------------------------
	 * applique l'effet � tous les liens de la page pointant vers des ancres
	 *
	 * @return		{void}
	 */   
	auto : function () {
		this.applyTo(document.getElementsByTagName('a'));
	}
};


// en cas de scroll manuel (� la roulette, par exemple), arr�ter scroller
if (window.addEventListener) { window.addEventListener('scroll', scroller.stop, false); } // pour les vrais navigateurs
else { window.attachEvent('onscroll', scroller.stop); } // pour IE
