Suite à ce sujet qui donne une solution en utilisant jquery, j'ai pensé que c'était un exercice intéressant de faire la même fonction sans utiliser de librairie externe. Les débutants y trouveront quelques notions de javascript, et ceux qui n'utilisent pas jquery un code plus facilement évolutif et compréhensible.
- Pour afficher / masquer les Div (ou blocs) et mémoriser leur état, j'ai pris l'option d'utiliser un tableau. Pour chaque Div dont l'affichage a été modifié, son état d'affichage est enregistré dans un élément du tableau, dont l'index est l'identifiant (id) du Div et la valeur est son état 'block' ou 'none'. Le tableau est ensuite sérialisé pour être enregistré dans un cookie.
- Le nom du cookie est donné par la fonction SetNomCookie() qui récupère le nom de la page en cours. Il y a donc un cookie (et un seul) pour chaque page qui utilise ce script. Cette solution permet d'afficher/masquer des Div dans des pages différentes qui pourraient avoir des id html identiques.
Attention toutefois pour ceux qui utilisent des url dynamiques auquel cas il faudra peut-être modifier cette fonction "SetNomCookie()" selon les besoins en intégrant par exemple certains éléments du query string dans le nom du cookie pour différencier les pages, ou alors n'utiliser qu'un seul nom (donc un seul cookie) pour toutes les pages mais en prenant soin que tous les id concernés soient différents dans toutes les pages.
- Les fonctions ShowDiv() et InitShowDiv() qui sont le moteur du système sont documentées au fil de l'eau.
Elles font appel à des fonctions "génériques" trouvées sur le web (l'adresse est sous leur nom) qui ont été légèrement modifiées pour répondre aux besoins du script :
SetCoockie() : utilisation de "escape" sur la valeur du cookie afin de convertir les caractères spéciaux inhérents à la sérialisation.
GetCookie() : return false en cas d'échec parce que c'est plus pratique.
Serialize() et Unserialize() : j'ai viré les messages d'alerte en cas d'erreur car des vérifications sont faites après leur utilisation.
Particularités :
- L'état d'affichage des Div est vérifié à l'aide de "id.offsetWidth" qui retourne la largeur d'un bloc et possède la caractéristique de retourner 0 si le bloc est caché avec un style display:none. En effet la propriété javascript id.style.display retourne l'état d'affichage uniquement si le style est intégré directement dans le code ou s'il a été modifié précédemment par javascript.
L'avantage d'utiliser cette méthode est donc de pouvoir facilement inverser l'état d'affichage défini dans une feuille de style interne (Div_B et Div_D dans l'exemple) ou externe sans avoir à parser les feuilles de style.
- Les fonctions javascript de sérialisation sont compatibles avec php. On peut donc facilement récupérer en php la valeur d'affichage des blocs modifiés, lors du chargement ou du rafraichissement de la page comme le montre le code php pour exemple.
Syntaxe: [ Télécharger ] [ Masquer ]
Code php
<?php
header('Content-type: text/html; charset=UTF-8');
$fichier_courant = substr($_SERVER['PHP_SELF'],0,strrpos($_SERVER['PHP_SELF'],'.'));
$name_cookie = $fichier_courant == '/index' ? $_SERVER['SERVER_NAME'] : $fichier_courant;
if(isset($_COOKIE[$name_cookie]))
{
$cookie_affiche_div = (get_magic_quotes_gpc())? stripslashes($_COOKIE[$name_cookie]) : $_COOKIE[$name_cookie];
$tab_affiche_div = unserialize($cookie_affiche_div);
if(is_array($tab_affiche_div))
{
natsort($tab_affiche_div);
foreach ($tab_affiche_div as $key => $value)
echo $key. ' = ' .$value. '<br />';
}
}
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Afficher ou masquer un DIV et garder son état en mémoire en Javascript</title>
<script type="text/javascript">
<!--
function ShowDiv (id) {
var id_show;
//Si l'id correspond à un id existant
if (id_show = document.getElementById(id))
{
// Inverse l'état du div : s'il est à "display : none", sa largeur id_show.offsetWidth = 0
var showHide = id_show.offsetWidth > 0 ? 'none' : 'block';
id_show.style.display = showHide;
var tab_cook_showDiv;
// Cherche le cookie affecté à cette page et s'il existe le désérialise
tab_cook_showDiv = (tab_cook_showDiv = GetCookie(SetNomCookie())) ? Unserialize(tab_cook_showDiv) : null;
// Vérifie que le résultat tab_cook_showDiv est un tableau sinon initialise cette variable en tableau
tab_cook_showDiv = (typeof tab_cook_showDiv == 'object' && tab_cook_showDiv instanceof Array) ? tab_cook_showDiv : new Array();
// Enregistre l'état de la div avec l'id comme index de l'élément dans le tableau (crée l'élément ou le remplace)
tab_cook_showDiv[id] = showHide;
// Envoi le tableau sérialisé dans un cookie dont le nom est "SetNomCookie()"
SetCoockie (SetNomCookie(), Serialize(tab_cook_showDiv));
}
}
function InitShowDiv () {
var cookie_showDiv;
// Cherche le cookie affecté à cette page (ayant pour nom SetNomCookie()) et s'il existe ...
if (cookie_showDiv = GetCookie(SetNomCookie()))
{
// Désérialise le tableau enregistré dans le cookie
var tab_cook_showDiv = Unserialize(cookie_showDiv);
// Si tab_cook_showDiv est un objet et un tableau
if(typeof tab_cook_showDiv == 'object' && tab_cook_showDiv instanceof Array)
{
// Affiche les div suivant leur état "block" ou "none" enregistrés dans le tableau du cookie de la page
// Liste le tableau associatif
for (var id in tab_cook_showDiv)
{
var affiche_id;
// Si l'index de l'élément du tableau correspond à un id existant de la page en cours, affecte son affichage "style.display" avec la valeur enregistrée
if (affiche_id = document.getElementById(id)) affiche_id.style.display = tab_cook_showDiv[id];
}
// Et renvoie le même cookie pour prolongation de sa durée de vie dès le chargement de la page
SetCoockie (SetNomCookie(), cookie_showDiv);
}
}
}
function SetNomCookie() {
var fich = window.location.pathname;
if (fich != '/')
{
//Enlève tout ce qu'il y a après de dernier point
fich = fich.substr(0,fich.lastIndexOf('.'));
//Si fich = "/index" on est sur la page d'accueil et l'on renvoie le nom de domaine
var name = (fich == '/index')? window.location.host : fich;
}
else
{
//si fich == '/' on est sur la page d'accueil et l'on renvoie le nom de domaine
var name = window.location.host;
}
return (name);
}
function SetCoockie (nom, valeur) {
//http://fr.selfhtml.org/javascript/exemples/visites_pages.htm ... script légèrement modifié
var peremption = 1000*60*60*24*365;//durée de validité : 1an
var maintenant = new Date();
var temps = new Date(maintenant.getTime() + peremption);
document.cookie = nom+"="+escape(valeur)+"; expires="+temps.toGMTString()+";";
}
function GetCookie(nom) {
//http://www.asp-php.net/tutorial/scripting/cookies.php ... script légèrement modifié
var deb,fin;
deb = document.cookie.indexOf(nom + "=");
if (deb >= 0)
{
deb += nom.length + 1;
fin = document.cookie.indexOf(";",deb);
if (fin < 0) fin = document.cookie.length;
return unescape(document.cookie.substring(deb,fin));
}
else return false;
}
function Serialize (txt) {
/*auteur : XoraX
info : http://www.xorax.info/blog/programmatio ... e-php.html ... script légèrement modifié*/
switch(typeof(txt))
{
case 'string':
return 's:'+txt.length+':"'+txt+'";';
case 'number':
if(txt>=0 && String(txt).indexOf('.') == -1 && txt < 65536) return 'i:'+txt+';';
return 'd:'+txt+';';
case 'boolean':
return 'b:'+( (txt)?'1':'0' )+';';
case 'object':
var i=0,k,ret='';
for(k in txt)
{
//alert(isNaN(k));
if(!isNaN(k)) k = Number(k);
ret += Serialize(k)+Serialize(txt[k]);
i++;
}
return 'a:'+i+':{'+ret+'}';
default:
return 'N;';
//alert('var undefined: '+typeof(txt));return undefined;
}
}
function Unserialize(txt){
/*auteur : XoraX
info : http://www.xorax.info/blog/programmatio ... e-php.html ... script légèrement modifié*/
var level=0,arrlen=new Array(),del=0,final=new Array(),key=new Array(),save=txt;
while(1)
{
switch(txt.substr(0,1))
{
case 'N':
del = 2;
ret = null;
break;
case 'b':
del = txt.indexOf(';')+1;
ret = (txt.substring(2,del-1) == '1')?true:false;
break;
case 'i':
del = txt.indexOf(';')+1;
ret = Number(txt.substring(2,del-1));
break;
case 'd':
del = txt.indexOf(';')+1;
ret = Number(txt.substring(2,del-1));
break;
case 's':
del = txt.substr(2,txt.substr(2).indexOf(':'));
ret = txt.substr( 1+txt.indexOf('"'),del);
del = txt.indexOf('"')+ 1 + ret.length + 2;
break;
case 'a':
del = txt.indexOf(':{')+2;
ret = new Array();
arrlen[level+1] = Number(txt.substring(txt.indexOf(':')+1, del-2))*2;
break;
case 'O':
txt = txt.substr(2);
var tmp = txt.indexOf(':"')+2;
var nlen = Number(txt.substring(0, txt.indexOf(':')));
name = txt.substring(tmp, tmp+nlen );
//alert(name);
txt = txt.substring(tmp+nlen+2);
del = txt.indexOf(':{')+2;
ret = new Object();
arrlen[level+1] = Number(txt.substring(0, del-2))*2;
break;
case '}':
txt = txt.substr(1);
if(arrlen[level] != 0)
{
//alert('var missed : '+save);
return undefined;
}
//alert(arrlen[level]);
level--;
continue;
default:
if(level==0) return final;
//alert('syntax invalid(1) : '+save+"\nat\n"+txt+"level is at "+level);
return undefined;
}
if(arrlen[level]%2 == 0)
{
if(typeof(ret) == 'object')
{
//alert('array index object no accepted : '+save);
return undefined;
}
if(ret == undefined)
{
//alert('syntax invalid(2) : '+save);
return undefined;
}
key[level] = ret;
}
else
{
var ev = '';
for(var i=1;i<=level;i++)
{
if(typeof(key[i]) == 'number')
{
ev += '['+key[i]+']';
}
else
{
ev += '["'+key[i]+'"]';
}
}
eval('final'+ev+'= ret;');
}
arrlen[level]--;//alert(arrlen[level]-1);
if(typeof(ret) == 'object') level++;
txt = txt.substr(del);
continue;
}
}
-->
</script>
<style type="text/css">
#div_B {
display:none;
}
#div_D {
display:none;
}
.inverse_aff {
cursor:pointer;
text-decoration:underline;
}
#conteneur {
margin-top:2em;
padding:2em;
border:3px solid green;
}
#conteneur div {
border:1px solid #CCCCCC;
}
</style>
</head>
<body onload = "InitShowDiv()">
<p class="inverse_aff" onclick = "ShowDiv('conteneur')">Afficher / masquer Tout</p>
<div id = "conteneur">
<p class="inverse_aff" onclick = "ShowDiv('div_A')">Afficher / masquer div A</p>
<div id = "div_A" >AAAAAAAAAAAAA </div>
<p class="inverse_aff" onclick = "ShowDiv('div_B')">Afficher / masquer div B</p>
<div id = "div_B" >BBBBBBBBBBBBB </div>
<p class="inverse_aff" onclick = "ShowDiv('div_C')">Afficher / masquer div C</p>
<div id = "div_C" >CCCCCCCCCCCCC </div>
<p class="inverse_aff" onclick = "ShowDiv('div_D')">Afficher / masquer div D</p>
<div id = "div_D" >DDDDDDDDDDDDD </div>
<p class="inverse_aff" onclick = "ShowDiv('div_E')">Afficher / masquer div E</p>
<div id = "div_E" >EEEEEEEEEEEEE </div>
</div>
<p>Autre bloc de texte</p>
</body>
</html>
header('Content-type: text/html; charset=UTF-8');
$fichier_courant = substr($_SERVER['PHP_SELF'],0,strrpos($_SERVER['PHP_SELF'],'.'));
$name_cookie = $fichier_courant == '/index' ? $_SERVER['SERVER_NAME'] : $fichier_courant;
if(isset($_COOKIE[$name_cookie]))
{
$cookie_affiche_div = (get_magic_quotes_gpc())? stripslashes($_COOKIE[$name_cookie]) : $_COOKIE[$name_cookie];
$tab_affiche_div = unserialize($cookie_affiche_div);
if(is_array($tab_affiche_div))
{
natsort($tab_affiche_div);
foreach ($tab_affiche_div as $key => $value)
echo $key. ' = ' .$value. '<br />';
}
}
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Afficher ou masquer un DIV et garder son état en mémoire en Javascript</title>
<script type="text/javascript">
<!--
function ShowDiv (id) {
var id_show;
//Si l'id correspond à un id existant
if (id_show = document.getElementById(id))
{
// Inverse l'état du div : s'il est à "display : none", sa largeur id_show.offsetWidth = 0
var showHide = id_show.offsetWidth > 0 ? 'none' : 'block';
id_show.style.display = showHide;
var tab_cook_showDiv;
// Cherche le cookie affecté à cette page et s'il existe le désérialise
tab_cook_showDiv = (tab_cook_showDiv = GetCookie(SetNomCookie())) ? Unserialize(tab_cook_showDiv) : null;
// Vérifie que le résultat tab_cook_showDiv est un tableau sinon initialise cette variable en tableau
tab_cook_showDiv = (typeof tab_cook_showDiv == 'object' && tab_cook_showDiv instanceof Array) ? tab_cook_showDiv : new Array();
// Enregistre l'état de la div avec l'id comme index de l'élément dans le tableau (crée l'élément ou le remplace)
tab_cook_showDiv[id] = showHide;
// Envoi le tableau sérialisé dans un cookie dont le nom est "SetNomCookie()"
SetCoockie (SetNomCookie(), Serialize(tab_cook_showDiv));
}
}
function InitShowDiv () {
var cookie_showDiv;
// Cherche le cookie affecté à cette page (ayant pour nom SetNomCookie()) et s'il existe ...
if (cookie_showDiv = GetCookie(SetNomCookie()))
{
// Désérialise le tableau enregistré dans le cookie
var tab_cook_showDiv = Unserialize(cookie_showDiv);
// Si tab_cook_showDiv est un objet et un tableau
if(typeof tab_cook_showDiv == 'object' && tab_cook_showDiv instanceof Array)
{
// Affiche les div suivant leur état "block" ou "none" enregistrés dans le tableau du cookie de la page
// Liste le tableau associatif
for (var id in tab_cook_showDiv)
{
var affiche_id;
// Si l'index de l'élément du tableau correspond à un id existant de la page en cours, affecte son affichage "style.display" avec la valeur enregistrée
if (affiche_id = document.getElementById(id)) affiche_id.style.display = tab_cook_showDiv[id];
}
// Et renvoie le même cookie pour prolongation de sa durée de vie dès le chargement de la page
SetCoockie (SetNomCookie(), cookie_showDiv);
}
}
}
function SetNomCookie() {
var fich = window.location.pathname;
if (fich != '/')
{
//Enlève tout ce qu'il y a après de dernier point
fich = fich.substr(0,fich.lastIndexOf('.'));
//Si fich = "/index" on est sur la page d'accueil et l'on renvoie le nom de domaine
var name = (fich == '/index')? window.location.host : fich;
}
else
{
//si fich == '/' on est sur la page d'accueil et l'on renvoie le nom de domaine
var name = window.location.host;
}
return (name);
}
function SetCoockie (nom, valeur) {
//http://fr.selfhtml.org/javascript/exemples/visites_pages.htm ... script légèrement modifié
var peremption = 1000*60*60*24*365;//durée de validité : 1an
var maintenant = new Date();
var temps = new Date(maintenant.getTime() + peremption);
document.cookie = nom+"="+escape(valeur)+"; expires="+temps.toGMTString()+";";
}
function GetCookie(nom) {
//http://www.asp-php.net/tutorial/scripting/cookies.php ... script légèrement modifié
var deb,fin;
deb = document.cookie.indexOf(nom + "=");
if (deb >= 0)
{
deb += nom.length + 1;
fin = document.cookie.indexOf(";",deb);
if (fin < 0) fin = document.cookie.length;
return unescape(document.cookie.substring(deb,fin));
}
else return false;
}
function Serialize (txt) {
/*auteur : XoraX
info : http://www.xorax.info/blog/programmatio ... e-php.html ... script légèrement modifié*/
switch(typeof(txt))
{
case 'string':
return 's:'+txt.length+':"'+txt+'";';
case 'number':
if(txt>=0 && String(txt).indexOf('.') == -1 && txt < 65536) return 'i:'+txt+';';
return 'd:'+txt+';';
case 'boolean':
return 'b:'+( (txt)?'1':'0' )+';';
case 'object':
var i=0,k,ret='';
for(k in txt)
{
//alert(isNaN(k));
if(!isNaN(k)) k = Number(k);
ret += Serialize(k)+Serialize(txt[k]);
i++;
}
return 'a:'+i+':{'+ret+'}';
default:
return 'N;';
//alert('var undefined: '+typeof(txt));return undefined;
}
}
function Unserialize(txt){
/*auteur : XoraX
info : http://www.xorax.info/blog/programmatio ... e-php.html ... script légèrement modifié*/
var level=0,arrlen=new Array(),del=0,final=new Array(),key=new Array(),save=txt;
while(1)
{
switch(txt.substr(0,1))
{
case 'N':
del = 2;
ret = null;
break;
case 'b':
del = txt.indexOf(';')+1;
ret = (txt.substring(2,del-1) == '1')?true:false;
break;
case 'i':
del = txt.indexOf(';')+1;
ret = Number(txt.substring(2,del-1));
break;
case 'd':
del = txt.indexOf(';')+1;
ret = Number(txt.substring(2,del-1));
break;
case 's':
del = txt.substr(2,txt.substr(2).indexOf(':'));
ret = txt.substr( 1+txt.indexOf('"'),del);
del = txt.indexOf('"')+ 1 + ret.length + 2;
break;
case 'a':
del = txt.indexOf(':{')+2;
ret = new Array();
arrlen[level+1] = Number(txt.substring(txt.indexOf(':')+1, del-2))*2;
break;
case 'O':
txt = txt.substr(2);
var tmp = txt.indexOf(':"')+2;
var nlen = Number(txt.substring(0, txt.indexOf(':')));
name = txt.substring(tmp, tmp+nlen );
//alert(name);
txt = txt.substring(tmp+nlen+2);
del = txt.indexOf(':{')+2;
ret = new Object();
arrlen[level+1] = Number(txt.substring(0, del-2))*2;
break;
case '}':
txt = txt.substr(1);
if(arrlen[level] != 0)
{
//alert('var missed : '+save);
return undefined;
}
//alert(arrlen[level]);
level--;
continue;
default:
if(level==0) return final;
//alert('syntax invalid(1) : '+save+"\nat\n"+txt+"level is at "+level);
return undefined;
}
if(arrlen[level]%2 == 0)
{
if(typeof(ret) == 'object')
{
//alert('array index object no accepted : '+save);
return undefined;
}
if(ret == undefined)
{
//alert('syntax invalid(2) : '+save);
return undefined;
}
key[level] = ret;
}
else
{
var ev = '';
for(var i=1;i<=level;i++)
{
if(typeof(key[i]) == 'number')
{
ev += '['+key[i]+']';
}
else
{
ev += '["'+key[i]+'"]';
}
}
eval('final'+ev+'= ret;');
}
arrlen[level]--;//alert(arrlen[level]-1);
if(typeof(ret) == 'object') level++;
txt = txt.substr(del);
continue;
}
}
-->
</script>
<style type="text/css">
#div_B {
display:none;
}
#div_D {
display:none;
}
.inverse_aff {
cursor:pointer;
text-decoration:underline;
}
#conteneur {
margin-top:2em;
padding:2em;
border:3px solid green;
}
#conteneur div {
border:1px solid #CCCCCC;
}
</style>
</head>
<body onload = "InitShowDiv()">
<p class="inverse_aff" onclick = "ShowDiv('conteneur')">Afficher / masquer Tout</p>
<div id = "conteneur">
<p class="inverse_aff" onclick = "ShowDiv('div_A')">Afficher / masquer div A</p>
<div id = "div_A" >AAAAAAAAAAAAA </div>
<p class="inverse_aff" onclick = "ShowDiv('div_B')">Afficher / masquer div B</p>
<div id = "div_B" >BBBBBBBBBBBBB </div>
<p class="inverse_aff" onclick = "ShowDiv('div_C')">Afficher / masquer div C</p>
<div id = "div_C" >CCCCCCCCCCCCC </div>
<p class="inverse_aff" onclick = "ShowDiv('div_D')">Afficher / masquer div D</p>
<div id = "div_D" >DDDDDDDDDDDDD </div>
<p class="inverse_aff" onclick = "ShowDiv('div_E')">Afficher / masquer div E</p>
<div id = "div_E" >EEEEEEEEEEEEE </div>
</div>
<p>Autre bloc de texte</p>
</body>
</html>






