﻿ (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;
 };

 })()