Afficher/masquer un DIV et mémoriser son état en Javascript

2 messages   •   Page 1 sur 1
Avatar de l’utilisateur
ViPHP
AB
ViPHP | 5818 Messages

24 Fév 2010, 02:03

Bonjour,

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.


[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>
[/php]

Avatar de l’utilisateur
ViPHP
AB
ViPHP | 5818 Messages

16 Mars 2010, 23:12

Bonjour,

Suite à cette demande :

dahooo2 a écrit :... Mais il y a encore une chose que je n'arrive pas à faire : c'est avoir un bouton "afficher / masquer tout" mais qui laisserait afficher les titres. Dans cet exemple cela donnerait lorsque l'on cache tout :
Afficher / masquer div A
Afficher / masquer div B
Afficher / masquer div C

et lorsque l'on affiche tout :
Afficher / masquer div A
AAAAAAAAAAAAA
Afficher / masquer div B
BBBBBBBBBBBBB
Afficher / masquer div C
CCCCCCCCCCCCC


j'ai créé une fonction "AmtShowDiv()" compatible avec les fonctions précédentes et dont le principe de fonctionnement est le suivant :

- Quand on clique sur le bouton pour afficher/masquer un bloc de div, on mémorise l'état du bouton (ex : afficher)

- Au prochain clic, on inverse l'état du bouton (ex : masquer), excepté si les div ont été modifiés individuellement et ont déjà tous l'état inverse (ex : masquer). Dans ce cas le bouton garde son état initial (ex : afficher) pour éviter un clic inutile.

Voici donc le code documenté au fil de l'eau :

[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 affich_id;
// Si l'index de l'élément du tableau correspond à un id existant de la page en cours => affecte son affichage avec sa valeur enregistrée
if (affich_id = document.getElementById(id)) affich_id.style.display = tab_cook_showDiv[id];
}


// 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 AmtShowDiv () {

//Tableau des arguments (=id des div) passés lors de l'appel de la fonction AmtShowDiv
var tab_argumemts = AmtShowDiv.arguments;

/* Crée une variable composée de la concaténation des id des div passés en paramètre lors de l'appel de la fonction.
Cette variable permet de différencier des appels à la fonction provenant de blocs différents (dans l'exemple d'utilisation : AmtShowDiv('div_C','div_D','div_E') et AmtShowDiv('div_F','div_G','div_H') */
var div_concat = '';
for (var i=0; i < tab_argumemts.length; i++) {div_concat += tab_argumemts[i];}


/* Création d'une propriété (avec le mot-clé this) se référent à elle-même, ce qui revient à créer une variable qui mémorisera sa dernière valeur définie lors d'appels succesifs.
Cela permet la mémorisation lors d'appels successifs dans une même session y compris sans les cookies activés dans le navigateur, mais dans le cas la mémorisation de l'état sera perdue au rechargement de la page puisque c'est un cookie qui mémorise l'état d'une session à un autre. */

this.EtatAmt = typeof this.EtatAmt != 'undefined' ? this.EtatAmt : new Array;
this.EtatAmt[div_concat] = typeof this.EtatAmt[div_concat] != 'undefined' ? this.EtatAmt[div_concat] : 'none';



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;

// Cherche l'élément 'div_concat' du tableau du cookie sinon le crée et lui affecte la valeur this.EtatAmt[div_concat]
tab_cook_showDiv[div_concat] = (typeof tab_cook_showDiv[div_concat] != 'undefined')? tab_cook_showDiv[div_concat] : this.EtatAmt[div_concat];


// Cherche si les div passés en argument dans la fonction AmtShowDiv ne sont pas tous déjà dans l'état inverse de la valeur de tab_cook_showDiv[div_concat] (si modifiés individuellement par la fonction ShowDiv ou par css)

var affiche_id;

// Valeur témoin
var verif = false;

// Liste les arguments passés en paramètres lors de l'appel de la fonction AmtShowDiv
for (var i=0; i < tab_argumemts.length; i++)

{
// Si l'argument passé dans la fonction correspond à un id existant de la page en cours
if (affiche_id = document.getElementById(tab_argumemts[i]))
{
// Si cet élément est dans le même état que tab_cook_showDiv[div_concat], verif = true
//(si au moins un élément est dans le même état, alors tous ne sont pas dans l'état inverse)
if ((tab_cook_showDiv[div_concat] == 'block' && affiche_id.offsetWidth > 0) || (tab_cook_showDiv[div_concat] == 'none' && !(affiche_id.offsetWidth > 0))) verif = true;

}

}

// si vérif = true => redéfini tab_cook_showDiv[div_concat] pour inverser l'affichage
if (verif === true) tab_cook_showDiv[div_concat] = tab_cook_showDiv[div_concat] == 'block' ? 'none' : 'block';



// Défini l'affichage des blocs (en utilisant les id des div passés en paramètres lors de l'appel de la fonction)

// Liste les arguments passés dans la fonction AmtShowDiv
for (var i=0; i < tab_argumemts.length; i++)

{

// Si l'argument passé en paramètre dans la fonction AmtShowDiv correspond à un id existant de la page en cours => affecte son affichage "style.display" avec la valeur de tab_cook_showDiv[div_concat]
if (affiche_id = document.getElementById(tab_argumemts[i]))
{
affiche_id.style.display = tab_cook_showDiv[div_concat];

// Et enregistre son état dans le tableau
tab_cook_showDiv[tab_argumemts[i]] = tab_cook_showDiv[div_concat];
}
}


// Enregistre la valeur de tab_cook_showDiv[div_concat] dans this.EtatAmt[div_concat] (pour mémorisation de l'état dans une même session y compris sans les cookies activés)
this.EtatAmt[div_concat] = tab_cook_showDiv[div_concat];


// Envoi le tableau sérialisé dans un cookie dont le nom est "SetNomCookie()"
SetCoockie (SetNomCookie(), Serialize(tab_cook_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">

.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 le bloc conteneur</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">BBBBBBBBBBBBBB </div><br />

<p class="inverse_aff" onclick = "AmtShowDiv('div_C','div_D','div_E')">Afficher / masquer les div C, D, E</p>
<br />

<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>
<br />

<p class="inverse_aff" onclick = "AmtShowDiv('div_F','div_G','div_H')">Afficher / masquer les div F, G, H</p>
<br />

<p class="inverse_aff" onclick = "ShowDiv('div_F')">Afficher / masquer div F</p>
<div id = "div_F" >FFFFFFFFFFFFF </div>
<p class="inverse_aff" onclick = "ShowDiv('div_G')">Afficher / masquer div G</p>
<div id = "div_G" >GGGGGGGGGGGGG </div>
<p class="inverse_aff" onclick = "ShowDiv('div_H')">Afficher / masquer div H</p>
<div id = "div_H" >HHHHHHHHHHHHH </div>

</div>

<p>Autre bloc de texte</p>
</body>
</html>

[/php]


Optimisation :

Pour une écriture html plus simple on pourrait appeler la même fonction pour un ou plusieurs blocs à afficher/masquer.

Il suffit pour cela de compter le nombre d'arguments passés à la fonction et d'appeler ShowDiv (la fonction initiale) si un seul id est passé à la fonction, sinon d'appeler AmtShowDiv, dernière fonction créée pour afficher/masquer simultanémént plusieurs blocs.

Ce qui implique les modifications suivantes dans les fonctions ShowDiv et AmtShowDiv :


[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 () {

//tab_argumemts = tableau des arguments (=id des div) passés lors de l'appel de la fonction ShowDiv
var tab_argumemts = ShowDiv.arguments;

// Si plus d'un id donné en argument on appelle la fonction AmtShowDiv en lui passant le tableau des arguments sinon l'id correspond au premier (et dernier) élément du tableau.
if (tab_argumemts.length > 1) AmtShowDiv (tab_argumemts); else var id = tab_argumemts[0];

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 affich_id;
// Si l'index de l'élément du tableau correspond à un id existant de la page en cours => affecte son affichage avec sa valeur enregistrée
if (affich_id = document.getElementById(id)) affich_id.style.display = tab_cook_showDiv[id];
}


// 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 addLoadInitShowDiv(func) {
//http://www.alsacreations.com/article/lire/565-JavaScript-organiser-son-code-en-modules.html
if (window.addEventListener)
{
window.addEventListener("load", func, false);
}
else if (document.addEventListener)
{
document.addEventListener("load", func, false);
}
else if (window.attachEvent)
{
window.attachEvent("onload", func);
}
}

addLoadInitShowDiv(InitShowDiv);



function AmtShowDiv (tab_argumemts) {

//tab_argumemts = Tableau des arguments (=id des div) transmis par la fonction ShowDiv (si le nombre des arguments > 1)


// Crée une variable composée de la concaténation des id des div passés en paramètre lors de l'appel de la fonction.
//Cette variable permet d'identifier des appels à la fonction provenant de blocs différents
var div_concat = '';
for (var i=0; i < tab_argumemts.length; i++) {div_concat += tab_argumemts[i];}


/* Création d'une propriété (avec le mot-clé this) se référent à elle-même, ce qui revient à créer une variable qui mémorisera sa dernière valeur définie lors d'appels succesifs.
Cela permettra la mémorisation lors d'appels successifs dans une même session y compris sans les cookies activés dans le navigateur, mais dans ce cas la mémorisation de l'état sera perdue au rechargement de la page puisque c'est un cookie qui mémorise l'état d'une session à un autre. */

this.EtatAmt = typeof this.EtatAmt != 'undefined' ? this.EtatAmt : new Array;
this.EtatAmt[div_concat] = typeof this.EtatAmt[div_concat] != 'undefined' ? this.EtatAmt[div_concat] : 'none';



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;

// Cherche l'élément 'div_concat' du tableau du cookie sinon le crée et lui affecte la valeur this.EtatAmt[div_concat]
tab_cook_showDiv[div_concat] = (typeof tab_cook_showDiv[div_concat] != 'undefined')? tab_cook_showDiv[div_concat] : this.EtatAmt[div_concat];


// Cherche si les div passés en argument dans la fonction AmtShowDiv ne sont pas tous déjà dans l'état inverse de la valeur de tab_cook_showDiv[div_concat] (si modifiés individuellement par la fonction ShowDiv ou par css)

var affiche_id;

// Valeur témoin
var verif = false;

// Liste les arguments passés en paramètres lors de l'appel de la fonction AmtShowDiv
for (var i=0; i < tab_argumemts.length; i++)

{
// Si l'argument passé dans la fonction correspond à un id existant de la page en cours
if (affiche_id = document.getElementById(tab_argumemts[i]))
{
// Si cet élément est dans le même état que tab_cook_showDiv[div_concat], verif = true
//(si au moins un élément est dans le même état, alors tous ne sont pas dans l'état inverse)
if ((tab_cook_showDiv[div_concat] == 'block' && affiche_id.offsetWidth > 0) || (tab_cook_showDiv[div_concat] == 'none' && !(affiche_id.offsetWidth > 0))) verif = true;

}

}

// si vérif = true => redéfini tab_cook_showDiv[div_concat] pour inverser l'affichage
if (verif === true) tab_cook_showDiv[div_concat] = tab_cook_showDiv[div_concat] == 'block' ? 'none' : 'block';



// Défini l'affichage des blocs (en utilisant les id des div passés en paramètres lors de l'appel de la fonction)

// Liste les arguments passés dans la fonction AmtShowDiv
for (var i=0; i < tab_argumemts.length; i++)

{

// Si l'argument passé en paramètre dans la fonction AmtShowDiv correspond à un id existant de la page en cours => affecte son affichage "style.display" avec la valeur de tab_cook_showDiv[div_concat]
if (affiche_id = document.getElementById(tab_argumemts[i]))
{
affiche_id.style.display = tab_cook_showDiv[div_concat];

// Et enregistre son état dans le tableau
tab_cook_showDiv[tab_argumemts[i]] = tab_cook_showDiv[div_concat];
}
}


// Enregistre la valeur de tab_cook_showDiv[div_concat] dans this.EtatAmt[div_concat] (pour mémorisation de l'état dans une même session y compris sans les cookies activés)
this.EtatAmt[div_concat] = tab_cook_showDiv[div_concat];


// Envoi le tableau sérialisé dans un cookie dont le nom est "SetNomCookie()"

SetCoockie (SetNomCookie(), Serialize(tab_cook_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">

.inverse_aff {
cursor:pointer;
text-decoration:underline;
}
#conteneur {
margin-top:2em;
padding:2em;
border:5px solid green;
}
#conteneur div {
border:1px solid #CCCCCC;
}
</style>

</head>

<body>

<p class="inverse_aff" onclick = "ShowDiv('conteneur')"><strong>Afficher / masquer le bloc conteneur</strong></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">BBBBBBBBBBBBBB </div>
<p class="inverse_aff" onclick = "ShowDiv('div_C')">Afficher / masquer div C</p>
<div id = "div_C" >CCCCCCCCCCCCC </div>

<br />

<p class="inverse_aff" onclick = "ShowDiv('div_D','div_E','div_F')"><strong>Afficher / masquer les div D, E, F</strong></p>


<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>
<p class="inverse_aff" onclick = "ShowDiv('div_F')">Afficher / masquer div F</p>
<div id = "div_F" >FFFFFFFFFFFFF </div>

<br />

<p class="inverse_aff" onclick = "ShowDiv('div_G','div_H')"><strong>Afficher / masquer les div G, H</strong></p>


<p class="inverse_aff" onclick = "ShowDiv('div_G')">Afficher / masquer div G</p>
<div id = "div_G" >GGGGGGGGGGGGG </div>
<p class="inverse_aff" onclick = "ShowDiv('div_H')">Afficher / masquer div H</p>
<div id = "div_H" >HHHHHHHHHHHHH </div>

</div>

<p>Autre bloc de texte</p>
</body>
</html>
[/php]

Voir le résultat du code

A noter qu'on emploie maintenant (c'était le but de la modif) la fonction ShowDiv pour afficher/masquer un ou plusieurs blocs dans le code html.

J'en ai profité pour ajouter également la fonction addLoadInitShowDiv qui est un gestionnaire de chargement et qui permet de lancer la fonction InitShowDiv au chargement de la page même si l'évènement onlaod est déjà utilisé dans un autre script. De ce fait, l'évènement onload n'est plus nécessaire et donc n'est plus présent dans la balise <body>.

note : j'ai gardé distinctes les deux fonctions ShowDiv et AmtShowDiv parce que c'est plus clair dans le déroulement du tuto, mais vous pouvez bien entendu les fusionner en une seule fonction.

Si vous avez des questions, merci d'ouvrir un sujet dans le forum javascript :wink:

2 messages   •   Page 1 sur 1