Note de ce sujet :
  • Moyenne : 0 (0 vote(s))
  • 1
  • 2
  • 3
  • 4
  • 5

[TUTO] Le gestionnaire de menu : menumanager
#1

Suite au post et aux fréquentes requêtes, j'ai décidé de vous faire un tuto.

Contexte : nous souhaitons un menu ajoutant plusieurs classes et en particulier "last" pour chaque derniers li d'un niveau, "dropdown-menu" pour chaque <ul>, plus "submenu" sur les <ul> à partir du niveau 3, et quelques autres...
Au lieu de vous expliquer comment le coder, je vous explique ce qu'il fait.
Je vous conseille de copier le gabarit suivant dans votre notepad pour bien voir les imbrications des boucles if.
Gabarit :
Code :
{if $count > 0}
    <nav class="navbar navbar-fixed-top" id="menutop">
        <div class="navbar-inner">
            <div class="container"><h1 class="brand" >Nom du projet</h1>
            {* 1er niveau de menu ds son ul *}    
                <ul class="nav">
                {foreach $nodelist as $node}
                    {capture class assign=class}index{$node->index} lev{$node->depth} prevLev{$node->prevdepth}{/capture}
                    {capture title assign=title}{$node->pagetitle}{if $node->titleattribute neq ""}, {$node->titleattribute}{/if}{/capture}
                    {if $node->depth > $node->prevdepth}{* on est au moins ul>ul node->depth *}    
                        {if $node->depth > 2}
                            {repeat string='<ul class="dropdown-menu submenu">' times=$node->depth-$node->prevdepth}
                        {else}
                            {repeat string='<ul class="dropdown-menu">' times=$node->depth-$node->prevdepth}
                        {/if}
                    {elseif $node->depth < $node->prevdepth}{* si on descend de niveau *}
                    {repeat string='</li></ul>' times=$node->prevdepth-$node->depth}    
                    {elseif $node->index > 0}
                        </li>{* si on reste sur le même niveau que l'élément précédent}
                        {/if}
                    {/if}
                    {if $node->first == true}{* si on est sur le 1er élément d'un niveau, on concatène $class avec 'first' *}
                        {capture class assign=class}{$class|cat:" first"}{/capture}
                    {/if}
                    {if $node->last == true}{* si on est sur le dernier élément d'un niveau, on concatène $class avec 'last' *}
                        {capture class assign=class}{$class|cat:" last"}{/capture}
                    {/if}
                    {if $node->haschildren == true and $node->type != 'sectionheader' and $node->type != 'separator'}
                        {capture class assign=class}{$class|cat:" haschildren dropdown"}{/capture}
                        <li class='{$class}'><a rel="tooltip" href="{$node->url}" data-toggle="dropdown" title="{$title}">{$node->menutext}<b></b></a>
                    {elseif $node->type == 'sectionheader'}
                        <li class='{$class} sectionheader'><span>{$node->menutext}</span>
                    {else}
                        <li class='{$class}'><a rel="tooltip" href="{$node->url}" title="{$title}">{$node->menutext}</a>
                    {/if}
                {/foreach}
                        {repeat string="</li></ul>" times=$node->depth-1}
                    </li>
                </ul>
            </div>
        </div>
    </nav>
{/if}

[h]Préambule[/h]
$count est le nombre de pages actives à afficher. Dans notre exemple, il sera de 3.
L'index commence toujours à 0 (la page par défaut du site).
Le niveau ($node->depth) commence à 1 et augmente de 1 à chaque nouvelle imbrication d'<ul>.

[h]Le foreach[/h]
{foreach $nodelist as $node} $node est une tableau comprenant toutes les pages et ses propriétés sauf les inactives si paramètres par défaut. Vous pouvez l'afficher sur le frontend en insérant <pre>{$node|print_r}</pre> juste après.
Voir http://www.smarty.net/docs/en/language.f...oreach.tpl

[h]Capture[/h]
Ici, nous allons créer une variable $class pour l'utiliser comme valeur pour class="" de vos balises.
{capture class assign=class}index{$node->index} lev{$node->depth} prevLev{$node->prevdepth}{/capture}
En français, ça donne : capture le contenu qui se trouve entre la balise {capture} et sa fermeture {/capture}, crée une variable $class, évalue le contenu (s'il y a des variables comme {$qqchose}) et remplis-la avec ce contenu.
Donc ici, le contenu est index{$node->index} lev{$node->depth} prevLev{$node->prevdepth}.
$class reçoit l'index et le niveau de la page actuellement processée par le manager de menu et le niveau de la page précédemment processée.
Si on est sur le premier élément de la boucle foreach, donc la page d'accueil, $class aura pour valeur : index0 lev1 prevLev1
Voir http://www.smarty.net/docs/en/language.f...apture.tpl

{capture title assign=title}{$node->pagetitle}{if $node->titleattribute neq ""}, - {$node->titleattribute}{/if}{/capture} on crée une variable $title comprenant le title de l'élément actuel et on concatène ", {$node->titleattribute}" s'il existe. neq "" est équivalent à !="".
Même principe que pour $class, sauf qu'il y a une sous-condition dans le contenu : y-a-t-il une description ? Si oui, on l'ajoute.

[h]C'est parti[/h]
Prenons l'exemple suivant :
1 Accueil
2 Actualités
2.1 Archives

Suivons le cheminement de nos pages dans la boucle foreach, en commençant par la première : l'index 0 (page d'accueil) :
Le moteur PHP écrit <ul class="nav">

Première condition : {if $node->depth > $node->prevdepth}
Si le node actuel est d'un niveau supérieur à celui du node précédent, il est donc son enfant.
Ce n'est pas notre cas, on saute à la condition suivante.

Seconde condition :{elseif $node->depth < $node->prevdepth}
Si le node actuel est d'un niveau inférieur à celui du node précédent. Non, on saute à la condition suivante.

Troisième condition : {elseif $node->index > 0}
L'index de ma page est 0, donc non, on passe à la condition suivante.

Quatrième condition : {if $node->first == true}
Est-ce que je suis le premier node du niveau 1 ? Bin oui, donc on ajoute " first" à $class qui contenait déjà index0 lev1 prevLev1.
{capture class assign=class}{$class|cat:" first"}{/capture} : le modificateur smarty cat (un modificateur est appelé en ajoutant une | juste après la variable à traiter) permet de concaténer une string à une variable.
Voir http://www.smarty.net/docs/en/language.modifier.cat.tpl

Cinquième condition : {if $node->last == true}
Est-ce que je suis le dernier node du niveau 1 ? Oui, on ajoute " last" à $class qui contenait déjà index0 lev1 prevLev1 first.

Sixième condition : {if $node->haschildren == true and $node->type != 'sectionheader' and $node->type != 'separator'}
Ai-je des enfants ET ne suis pas un sectionheader ET ne suis pas un separator ? Non, je n'ai pas d'enfant, on saute à la condition suivante.

Septième condition SI on a dit non à la condition 6 : {elseif $node->type == 'sectionheader'}
Est-ce que je suis un sectionheader ? Non, on passe à la condition suivante.

Huitième et dernière condition SI on a dit non aux conditions 6 et 7 : {else}
C'est le cas, le moteur php écrit <li class='{$class}'><a rel="tooltip" href="{$node->url}" title="{$titel}">{$node->menutext}</a> dans le gabarit.
Ce qui donne après que smarty a évalué le gabarit :
<ul class="nav">
<li class='index0 lev1 prevLev1 first last'><a rel="tooltip" href="http://www.mondomaine.com/accueil" title="Accueil, bienvenue sur mon site">Accueil</a>

Fin de l'évaluation du premier node. Vous remarquez que nous n'avons pas encore fermé le <li>.

[h]On passe au node page 2 qui a un enfant et pas de frère[/h]
Les variables et title sont réassignées avec les nouvelles valeurs : index1 lev1 prevLev1.

Première condition : {if $node->depth > $node->prevdepth}
Non, je suis au même niveau que la page d'accueil, on saute à la condition suivante.

Seconde condition :{elseif $node->depth < $node->prevdepth}
Non, on saute à la condition suivante.

Troisième condition : {elseif $node->index > 0}
L'index de ma page est 1, donc oui. On peut fermer le li de la page précédente : </li>
Nous avons donc maintenant :
<ul class="nav">
<li class='index0 lev1 prevLev1 first last'><a rel="tooltip" href="http://www.mondomaine.com/accueil" title="Accueil, bienvenue sur mon site">Accueil</a></li>

Quatrième condition : {if $node->first == true}
Oui, on ajoute " last" à $class qui contenait déjà index1 lev1 prevLev1.

Cinquième condition : {if $node->last == true}
Est-ce que je suis le dernier node du niveau 1 ? Oui, on ajoute " last" à $class qui contenait déjà index1 lev1 prevLev1 first.

Sixième condition : {if $node->haschildren == true and $node->type != 'sectionheader' and $node->type != 'separator'}
Ai-je des enfants ET ne suis pas un sectionheader ET ne suit pas un separator ? Oui, on ajoute haschildren et dropdown à la variable $class.
PHP écrit <li class='{$class}'><a rel="tooltip" href="{$node->url}" data-toggle="dropdown" title="{$title}">{$node->menutext}<b></b></a>
Ce qui donne après que smarty a évalué le gabarit :
<ul class="nav">
<li class='index0 lev1 prevLev1 first last'><a rel="tooltip" href="http://www.mondomaine.com/accueil" title="Accueil, bienvenue sur mon site">Accueil</a></li>
<li class='index1 lev1 prevLev1 first last haschildren dropdown'><a rel="tooltip" href="http://www.mondomaine.com/accueil" title="Actualités, toutes les news et événements du mois">Actualités</a>
Et on sort de la boucle foreach puisque la condition 6 empêche 7 et 8.

[h]On passe au node page 3, les archives[/h]
Les variables et title sont réassignées avec les nouvelles valeurs : index2 lev2 prevLev1.

Première condition : {if $node->depth > $node->prevdepth}
Oui, on continue.

Sous-condition 1 : {if $node->depth > 2}
Non, on passe à la suivante

Seconde condition : {elseif $node->depth < $node->prevdepth}
Non, on passe dans le {else} :
{repeat string='<ul class="dropdown-menu">' times=$node->depth-$node->prevdepth}
Ah, ça c'est du chinois LOL
Meuh non, décryptons tout ça :
repeat string='<ul class="dropdown-menu">' veux dire "écris plusieurs fois '<ul class="dropdown-menu">'
Combien de fois ? times = $node->depth - $node->prevdepth
Donc 2 - 1 = 1
PHP écrit <ul class="dropdown-menu">' 1 seule fois.
Ce qui donne après que smarty a évalué le gabarit :
<ul class="nav">
<li class='index0 lev1 prevLev1 first last'><a rel="tooltip" href="http://www.mondomaine.com/accueil" title="Accueil, bienvenue sur mon site">Accueil</a></li>
<li class='index1 lev1 prevLev1 first last haschildren dropdown'><a rel="tooltip" href="http://www.mondomaine.com/accueil" title="Actualités, toutes les news et événements du mois">Actualités</a>
<ul class="dropdown-menu">
Comme nous avons réalisé la condition 1, on saute les elseif.

Quatrième condition : {if $node->first == true}
Oui, on ajoute " last" à $class qui contenait déjà index2 lev2 prevLev1.

Cinquième condition : {if $node->last == true}
Est-ce que je suis le dernier node du niveau 1 ? Oui, on ajoute " last" à $class qui contenait déjà index2 lev2 prevLev1 first.

Sixième condition : {if $node->haschildren == true and $node->type != 'sectionheader' and $node->type != 'separator'}
Ai-je des enfants ET ne suis pas un sectionheader ET ne suit pas un separator ? Non, on passe.

Septième condition SI on a dit non à la condition 6 : {elseif $node->type == 'sectionheader'}
Est-ce que je suis un sectionheader ? Non, on passe à la condition suivante.

Huitième et dernière condition SI on a dit non aux conditions 6 et 7 : {else}
C'est le cas, le moteur php écrit <li class='{$class}'><a rel="tooltip" href="{$node->url}" title="{$titel}">{$node->menutext}</a> dans le gabarit.
Ce qui donne après que smarty a évalué le gabarit :
<ul class="nav">
<li class='index0 lev1 prevLev1 first last'><a rel="tooltip" href="http://www.mondomaine.com/accueil" title="Accueil, bienvenue sur mon site">Accueil</a></li>
<li class='index1 lev1 prevLev1 first last haschildren dropdown'><a rel="tooltip" href="http://www.mondomaine.com/actualites" title="Actualités, toutes les news et événements du mois">Actualités</a>
<ul class="dropdown-menu">
<li class='index2 lev2 prevLev1 first last'><a rel="tooltip" href="http://www.mondomaine.com/actualites/archives" title="Archives, retrouvez toutes les news et événements archivées">Actualités</a>

Fin de l'évaluation du troisième et dernier node. Vous remarquez qu'il manque des fermetures de balises.

[h]On sort du foreach et de nouveau du chinois Wink[/h]
{repeat string="</li></ul>" times=$node->depth-1}
Ici, de nouveau, times vaut 2 - 1 = 1 et PHP écrit </li></ul> et suit par </li></ul> et les fermetures des balises <div> et <nav>.
Notre code est devenu :
Code :
<nav class="navbar navbar-fixed-top" id="menutop">
    <div class="navbar-inner">
        <div class="container"><h1 class="brand" >Nom du projet</h1>
        {* 1er niveau de menu ds son ul *}    
            <ul class="nav">
                <li class='index0 lev1 prevLev1 first last'><a rel="tooltip" href="http://www.mondomaine.com/accueil" title="Accueil, bienvenue sur mon site">Accueil</a>
                </li>
                <li class='index1 lev1 prevLev1 first last haschildren dropdown'><a rel="tooltip" href="http://www.mondomaine.com/actualites" title="Actualités, toutes les news et événements du mois">Actualités</a>
                    <ul class="dropdown-menu">
                        <li class='index2 lev2 prevLev1 first last'><a rel="tooltip" href="http://www.mondomaine.com/actualites/archives" title="Archives, retrouvez toutes les news et événements archivées">Actualités</a>
                        </li>
                    </ul>
                </li>
            </ul>
        </div>
    </div>
</nav>

Vous ne voyez pas de $node->parent ou current, je vous laisse le plaisir de le découvrir dans les gabarits par défaut et l'aide du module.
Mais, attention, $node->parent n'est true QUE pour la page parentles pages parent du $node en cours. Donc, il y a zéro ou une page répondant à la condition {if $node->parent == true}.

Enjoy Smile
Répondre


Messages dans ce sujet

Atteindre :


Utilisateur(s) parcourant ce sujet : 1 visiteur(s)