/*
ce script permet de récupérer précisément la position d un élément dans le document...

3 fonction disponible :

getOffset(element, from) -> récupere la position a partir du document
getPosition(element, from) -> récupere la position a partir du dernier élément non static( la position relative n'est pas pris en charge bcp tros de beug, sur ie surtout)
getSize (element, from) -> retourne la taille de l'élément

l'argument from peux prendre 4 valeurs:
margin ou border, ou padding, ou content, et définit ou la mesure doit commencer

getOffset et getPosition commene leur mesure par default à border, getSize à content

si l'élément n'est pas visible , alors, les méthodes forceront sont affichage pour récupérer les données.
getOffset et getPosition, renvoient les valeurs sans les scroll

n'utiliser pas de tableau en position absolue, et préciser les bordure avec l'attribut style et non border 

 */
 (function(){//on encapusle nos donné grace a une fonction anonyme , pour eviter tros de vriables globale ou de faire un namespace
	
	 /*------------------------------------fonction privée-------------------------------------------------*/
	
	 //definit les versions du navigateur, peux etre mit en globale
	 var ua=navigator.userAgent.toLowerCase(),
	 isIE=/msie/.test(ua),
	 isIE6=/msie 6/.test(ua),
	 isIE7=/msie 7/.test(ua),
	 isIE8=/msie 8/.test(ua),
	 isWebKit = /webkit/.test(ua),
	 isGecko = /gecko/.test(ua) && !isWebKit,
	 isOpera = /presto/.test(ua);
	
	
	 var getStyle = function(/*DOMObject*/element, /*string*/rule){//peux etre definit en globale car très utilise, aucune dépendance...
	 var camelRule=rule.replace(/\-(\w)/g, function (strMatch, p1){return p1.toUpperCase();}),//supprime les tiré et met en majuscule la lettre suivante
	 value = element.style[camelRule];
	
	 if (!value){
	 if(document.defaultView && document.defaultView.getComputedStyle){
	 value = document.defaultView.getComputedStyle(element, "").getPropertyValue(/*fait l inverse de camelRule*/rule.replace(/[A-Z]/g, function(match){return '-'+match.charAt(0).toLowerCase();}));
	 }else{//specifique ie
	 value = element.currentStyle[camelRule] ;
	 }
	 }
	
	 return value == 'auto' ? undefined : value;
	 };
	
	 var toNum = function(el,rule){// convertie une valeur avec des px
	 return parseInt(getStyle(el,rule) ,10) || 0;
	 };
	
	 var manageBox = function(element, of, op, dim, co){//ajoute ou enleve les élement du modele de boite (bordure padding margin)
	 for(var i=0,a;(a=op[i]);i++){
	 of[0]+=toNum(element,a+'-left'+(a=='border'?'-width':''))*co;
	 of[1]+=toNum(element,a+'-top'+(a=='border'?'-width':''))*co;
	 if(dim){
	 of[0]+=toNum(element,a+'-right'+(a=='border'?'-width':''))*co;
	 of[1]+=toNum(element,a+'-bottom'+(a=='border'?'-width':''))*co;
	 }
	 }
	 };
	
	 var displayParent = function(el){//recuepre les parents pas affiché et affiche les, en position absolue (-> plus tard ) et invisible
	 var p=[];
	 while((el=el.parentNode) && el!=document.documentElement){
	 var d=getStyle(el,'display');
	 if(d=='none')
	 p.push(el);
	 }
	 if(p.length){
	 for(var i=0,el;(el=p[i]);i++){
	 el.style.display='';
	 }
	 var last=p[p.length-1];
	 last.__visibility__=getStyle(last,'visibility');
	 last.style.visibility='hidden';//on devrait passer en absolue le dernier parrent avec un display none, mais bcp de travaille ... faut modifier les valeurs pour correspondre à la position d'orgine , vue que le taux de rafraichissement (~= 20 millisec) est plus élévé que le temp d'execution de la fonction, on peux faire sans
	 /* last.__position__=getStyle(last,'position');
	 last.style.position='absolute';*/
	 }
	 return p;
	 };
	
	 var unDisplayParent = function(p,of,abs){//retablie l'affichage des parents
	 if(p.length){
	 var l=p[p.length-1];
	 /*if(of && l.__position__=='static'){
	 if(abs && (!isIE8 && !isOpera)){
	 of[0] -= toNum(l,'border-left-width');
	 of[1] -= toNum(l,'border-top-width');
	 }
	 if(abs){
	 of[0] -= l.offsetLeft || 0;
	 of[1] -= l.offsetTop || 0;
	 }
	 }
	 l.style.position=l.__position__;
	 l.__position__=null;*/
	 l.style.visibility=l.__visibility__;
	 l.__visibility__=null;
	 for(var i=0,el;(el=p[i]);i++){
	 el.style.display='none';
	 }
	 }
	 };
	
	 var getOffset = function(/*DOMObject*/element, /*bool*/byPos, /*string*/from){
	
	 var of=[0,0],//tab de coordonnées à retourner
	 from = from || 'border',//par default offset de la bordure (sasns les marges) , car la définition des position se fait a partir des bordures
	 el=element,//réferene a element pour boucler dessus
	 manageWith,//variable pour ajouter des elements du modele de boite
	 manageLess,//variable pour enlever des elements du modele de boite
	 abs,//si l'element est en absolue (utile seulement pour ie6 et 7 geko et webkit, mais déclarer pour tous pourr éviter tros e test conditionnelle)
	 dp=displayParent(element);//affiche les parents si néccessaire
	
	 //definit abs
	 if(!isIE8 || !isOpera)
	 abs=_abs=getStyle(element,'position')!='static'?element:false;
	
	
	 //ajoute au tab de coor les offsetparent, + break la boucle si un parent opu l'element en position absolue et byPos définit
	 while (el){
	 of[0] += el.offsetLeft || 0;
	 of[1] += el.offsetTop || 0;
	 el = el.offsetParent;
	 if(el && byPos && ((getStyle(el,'position')!='static' && (!el.__position__ || el.__position__!='static')) || abs)){
	 //ie8 et opera beug
	 if(isIE8 || isOpera){
	 of[0] -= toNum(el,'border-left-width');
	 of[1] -= toNum(el,'border-top-width');
	 }
	 break;
	 }
	 };
	
	 if(!isIE8 && !isOpera){
	 //si l'element est en absolue et que byPos définit, pas besoin de réctifier les valeurs
	 if(!byPos || !abs){
	 var _el=el || document.documentElement,//dernir element parent définit
	 el=element.parentNode;//on commence au 1er parent
	
	 //beug ie , concerne les prop width, height,et overflow
	 if(isIE)
	 var h=false;
	
	 do{
	 if(el.tagName=='TR' || el.tagName=='TBODY')//pas de beug sur ses éléments
	 continue;
	
	 if(el.tagName=='TD' || (isWebKit && el.tagName=='TABLE')){
	 //retranche les bordure si pas en absolue avant
	 if(!abs ){
	 of[0] += toNum(el,'border-left-width');
	 of[1] += toNum(el,'border-top-width');
	 }
	 h=false;
	 continue;
	 }
	
	 if(!byPos && getStyle(el,'position')!='static'){//si l'élément est pas en static, et que l'oin cherche l'offset depuis le body, en ajoute les bordure (beug)
	 of[0] += toNum(el,'border-left-width');
	 of[1] += toNum(el,'border-top-width');
	 abs=el;
	 }
	
	 // ajoute les scroll si pas ie6 qui le fait déja ,
	 if(!isIE6 && el!=document.body){
	 of[0] = of[0]-el.scrollLeft || 0;
	 of[1] = of[1]-el.scrollTop || 0;
	 }
	
	 if(isIE){
	 //si beug de style ie
	 if(!abs && (getStyle(el,'height') || getStyle(el,'width') || (isIE7 && getStyle(el,'overflow')!='visible') )){
	 h=el;
	 }
	 // si beug de style et pas en absolue ajoute les bordure
	 if(!abs && h==el){
	 of[0] += toNum(el,'border-left-width');
	 of[1] += toNum(el,'border-top-width');
	 }
	 }
	
	 }while((el=el.parentNode) && el!=_el);
	 }
	 }
	
	 //réctifie les valeurs si le dernier parent visible est body
	 if(!el || el==document.documentElement){
	 if((!isIE8 && !isOpera) && (!abs || isWebKit || isGecko)){
	 of[0] += toNum(document.body,'border-left-width')*(isGecko && !abs?2:1);
	 of[1] += toNum(document.body,'border-top-width')*(isGecko && !abs?2:1);
	 }
	 }
	
	 //définit les tableau des prop du modele de boite a enlever ou ajouter
	 switch(from){
	 case 'content':
	 manageWith=['padding','border'];
	 break;
	 case 'padding':
	 manageWith=['border'];
	 break;
	 case 'margin':
	 manageLess=['margin'];
	 break;
	 }
	
	 //enleve ou ajoute les prop du modele de boite
	 if(manageWith)
	 manageBox(element, of, manageWith, false, 1);
	 if(manageLess)
	 manageBox(element, of, manageLess, false, -1);
	
	 //rétatblie le display des parent
	 unDisplayParent(dp,of,_abs );
	
	 return of;
	 };
	
	 /*------------------------------------fonction publique-------------------------------------------------*/
	
	 window.getOffset=function(/*DOMObject*/element, /*string*/from){
	 return getOffset(element,false,from);
	 };
	
	 window.getPosition=function(/*DOMObject*/element, /*string*/from){
	 return getOffset(element,true,from);
	 };
	
	 window.absolutize = function(/*DOMObject*/element){
	 //si pas deja en absolue
	 if (getStyle(element,'position') == 'absolute')
	 return;
	
	 var es=element.style,//racourcit
	 dp=displayParent(element);//affiche les parents si néccessaire
	
	
	 var of=getPosition(element,'margin'),//position de l'élément
	 dim=getSize(element);//dimension de l'élément
	
	 //rétatblie le display des parent
	 unDisplayParent(dp,of,true);
	
	 es.position = 'absolute';
	 es.left = of[0] + 'px';
	 es.top = of[1] + 'px';
	 es.width =dim[0] + 'px';
	 es.height = dim[1] + 'px';
	
	 };
	
	 window.getSize = function(/*DOMObject*/element, /*string*/from){
	 var dim=[0,0],//tableau de coor à retourné
	 from = from || 'content',//par default taille du contenue (sasn les padding) , car la définition des taille se fait a partir de là
	 manageWith,//variable pour ajouter des elements du modele de boite
	 manageLess,//variable pour enlever des elements du modele de boite
	 op=from=='content' || from=='padding'?'client':'offset',//operation pour récupérer les dimension, utilise la meilleur fonction native
	 dp=displayParent(element);//affiche les parents si néccessaire
	
	 dim[0] += element[op+'Width'];
	 dim[1] += element[op+'Height'];
	
	 //définit le tableau des prop du modele de boite a enlever ou ajouter
	 switch(from){
	 case 'margin':
	 manageLess=['margin'];
	 break;
	 case 'content':
	 manageWith=['padding'];
	 break;
	 }
	
	 //enleve ou ajoute les prop du modele de boite
	 if(manageWith || manageLess)
	 manageBox(element, dim, manageWith || manageLess, true,manageLess?1:-1);
	
	 //rétatblie le display des parent
	 unDisplayParent(dp);
	
	 return dim;
	 };
	
	 })()
	 
