Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Function : Advanced Mulit Level Treewalker Navigation
#1
[h]Rationale[/h]

Initially I posted this in another thread about a very similar topic, however in order to keep the discussion focused on the code block posted in that thread I moved my version over to here.

Reasons for creating this variation are,

One: UL is ambigous, LI is the real focus.

Class names on the UL element seem pointless to me, i consider all <ul> to be of submenu types anyway. what we were really interested in to begin with was if a UL element was nested or not... this can be easily verified with :
Code:
.navigation li > ul { something something something ... complete }
Second reason for this is that since I stack relevant classname descriptors on the common items (LI) we can target individual UL via the LI.className :

Code:
.navigation .current > ul { something something something ... complete }
.navigation .odd > ul { something something something ... complete }
.navigation .menu-item-45 > ul { something something something ... complete }

Two : Positional classNames
I wanted to be able to apply attributes to the first, last, odd and even items of a submenu :

Code:
.navigation .odd > a{ border-right:.1em solid #ccc; }
.navigation .even > a{ border-left:.1em solid #fff; }
.navigation .first > a{ border-left:none; }
.navigation .last > a{ border-right:none; }

Three : Obsessive Compulsive Disorder
separation of the individual aspects of the menu creation function into three main parts provides easy modification to those aspects. In addition to using string format replacement method it becomes clear what the output of a particular step will be, allowing developers to quickly modify the output of a "step" without modifying logic.

Four : Tree Walking
lastly, if and when getSimple starts supporting a page tree deeper than 2 levels, this setup will continue to walk down the tree.


[h]Setup[/h]

You need :

$themedir$/functions.php
Code:
<?php include("./includes/navigation.php"); ?>

$themedir$/includes/navigation.php
Code:
<?php
    function template_zebra_row($array, $index,$total){

        array_push($array, ( $index%2 > 0)? "odd":"even");

        if( $index == 1 ){ array_push($array,"first"); }
        if( $index == $total ){ array_push($array,"last"); }
        
        return $array;
    }
      
    function template_menu_item_is_active($array, $test){
        if($test) array_push($array, 'current');
        return $array;
    }
    
    
    
    function template_tiered_menu(&$menu=false, &$id=false, &menuOnly=true){
        $template = "<ul>%s</ul>";
        $output = "";
    $id = "";//($id==false)? "" : $id;
    $menuOnly = "Y";//($menuOnly==false)? "N" :$menuOnly;
        $data = simplexml_load_string(menu_data("",true));

        if(!$menu){
            $menu = $data->xpath('//*[menuStatus="'.$menuOnly.'"][parent="'.$id.'"]');
        }
        if(!empty($menu)){
            $menu_count = count($menu);
            $step = 1;
        foreach ($menu as $link) {
                $class = array();
                if ($link->slug=='') $link->slug = "index";
                $submenu = $data->xpath('//*[menuStatus="Y"][parent="'.$link->slug.'/"]');
        $class = template_menu_item_is_active(template_zebra_row($class, $step, $menu_count), "$link->slug" == return_page_slug());
        array_push($class,"menu-item-id-$step");
                $output .= template_tiered_menu_item($link,join($class, " "),$submenu);
                $step++;
            }
        }
        return sprintf($template, $output);
    }
    
    function template_tiered_menu_item($link,$class,$submenu){
        $template = '<li class="%s"><div class="inner">%s</div></li>';
        if(strpos($class,"current")<=0){
      if(!$THEME_NONACTIVE_SUBMENUS){ $submenu = array(); }
    }
        return sprintf($template, $class, template_tiered_menu_link($link,$submenu) );
    }

    function template_tiered_menu_link($link,$submenu){
        $template = '<a href="%s" title="%s"><span>%s</span></a>%s';
        $title = ($link->menu!="")?$link->menu:$link->title;
        return sprintf($template, $link->url, $title, $title,(count($submenu)>0)?template_tiered_menu($submenu):"");
    }
    

?>

$themedir$/css/navigation.css
This is an example of my css I use. Attributes would vary, however I would still be using the same selectors.
Code:
.site-header .navigation{
    margin:0;
    padding:0 1px;
    height:6em;
    
}
.site-header .navigation > div.inner{
    margin:0    ;
    padding:.5em 0;
    display:inline;
    float:left;
}

.navigation ul{
    margin:0;
    padding:0 .5em;
    list-style:none;
    display:inline;
    float:left;
}
.navigation li{
    display:inline;
    float:left;
    list-style:none;
    margin:0;
    padding:0;
    
    background-repeat:repeat-x;
    background-color:#ccc;
    background-position:0em -2em;
    background-image:url("../images/small-transparent-vertical-gradient-reversed.png");
}
.navigation li > div.inner{
    margin:0;
    padding:0;
    display:inline;
    float:left;
}

.navigation ul ul{
    display:none;
}
.navigation a{
    display:inline;
    float:left;
    padding:0.2em 0;
    margin:0em 0em;
}
.navigation li a span{
    display:inline;
    float:left;
    padding:0.3em 2em;
    margin:.2em 0em;
    color:#333;
}
.navigation a:hover{
    background-position:0em -6em;
}
.navigation .odd > div.inner{
}

.navigation .first > .inner > a span,
.navigation .first > .inner > a,
.navigation .first{
    -moz-border-radius:none;
    -webkit-border-radius:none;

    -moz-border-radius-bottomleft:.3em;
    -moz-border-radius-topleft:.3em;
    -webkit-border-top-left-radius:.3em;
    -webkit-border-bottom-left-radius:.3em;
}
.navigation .last a span,
.navigation .last a,
.navigation .last{
    -moz-border-radius:none;
    -webkit-border-radius:none;
    
    -moz-border-radius-bottomright:.3em;
    -moz-border-radius-topright:.3em;
    -webkit-border-top-right-radius:.3em;
    -webkit-border-bottom-right-radius:.3em;
}
.navigation .last > div.inner{
}
.navigation .current > a{
}
.navigation .current > a:hover{
}


.navigation li ul li{
    padding:.2em 0em;
}
.navigation li ul a{
    display:inline;
    float:left;
    padding:0;
    margin:0;
    
}
.navigation li ul a:hover{
}
.navigation li ul a{
    background-repeat:repeat-x;
    background-color:#ddd;
    background-position:0em -1em;
    background-image:url("../images/small-transparent-vertical-gradient-reversed.png");
}

$themedir$/js/navigation.js
Code:
(function($) {
    $.fn.handleSubMenu = function(settings) {
        var config = {
            childItems : 0
        }
        if (settings) $.extend(config, settings);
          /*
           *   _isActive
           *        Is the element marked as the active menu item ?
           *        or does it have any descendant items marked as the current menu item?
           */
        function isActive(elm,action){
            var name = elm.find("a:eq(0)").text()
            var activeParents = elm.parents(".current, .active")
            var activeChildren = elm.find(".current, .active")
            var thisIsActive = elm.hasClass("active") || elm.hasClass("current")
            var parentIsMaster = elm.parents().eq(1).filter(".inner").length>0
            
            if( activeChildren.length>0 ){
                output = true;
            }else if( activeParents.length>0 ){
                output = true;
            }else if(thisIsActive){
                output = true;
            }else{
                output = false;
            }
            if(parentIsMaster){}
            return output
        }
        var open = function(elm){
            /*
                if this item contains a submenu, show it.
            */
            $(elm).find("ul").css("display","inline")
        }
        var close = function(elm){
            if(!isActive($(elm),"close") ){
                /*
                if the current elem (an LI) has LI descendants
                and none of those are marked with the ".current" className,
                hide the UL containing them
                */
                $(elm).find("ul").css("display","none")
            }
        }
        
        /*
           *   Hover Logic
           *        Deal with it.
           */
        $(this).hover(function(){ open($(this))},function(){ close($(this))})

        /*
           *   Activated Menu Items
           *        Keep them open.
           */
         if( isActive($(this),"initialisation") ){
            $(this).parent().css("display","inline")
         }else{
             if(!$(this).parents().eq(1).filter(".inner").length > 0){
             //    not sure about this yet.
             //    $(this).css("display","none");
             }
         }
    }
})(jQuery);

$(function(){
    $(".primary-navigation li").each(function(){
        $(this).handleSubMenu()

    })
})

$themeDir$/template.php

Inside the <head> ;
Code:
<script type="text/javascript" src="<?php print get_theme_url();?>/js/jquery/jquery-1.3.2.min.js"></script>
<script type="text/javascript" src="<?php print get_theme_url();?>/js/navigation.js"></script>

Inside the <body> (somewhere);
Code:
<div class="row navigation">
    <div class="inner">
        <?php print template_tiered_menu(); ?>
    </div>
</div>
Fear is mindkiller, the little death that obliterates.
Reply
#2
Javascript coder? hmm interesting.
http://nijikokun.com
random stuff. idk.
Reply
#3
I seem to have neglected to include the actual php logic. fixing that now.

done.
Fear is mindkiller, the little death that obliterates.
Reply
#4
Do you have a demo setup? Javascript usually seems to fix all css dropdown menus.
Clients always want to be able to change the content of their pages, but they are unwilling to do so.

Have you ever coded in your underwear before?
Reply




Users browsing this thread: 1 Guest(s)