uw              Fri Mar  9 00:54:01 2001 EDT

  Added files:                 
    /php4/pear/Experimental     README 
    /php4/pear/Experimental/HTML        Menu.php 
  Log:
  Added a directory Experimental/ as no one said "no" on the PEAR list...
   - added a PHPlib menu2.inc rewrite 
   - added a README for the directory with a policy for Experimental/
  
  
  

Index: php4/pear/Experimental/HTML/Menu.php
+++ php4/pear/Experimental/HTML/Menu.php
<?php
/**
* Generates a HTML menu from a multidimensional hash.
* 
* Special thanks to the original author: Alex Vorobiev  <[EMAIL PROTECTED]>
*
* @version  $id: $
* @author   Ulf Wendel <[EMAIL PROTECTED]>
* @access   public
* @package  HTML
*/
class menu {


    /**
    * Menu structure as a multidimensional hash.
    * 
    * @var  array
    * @see  setMenu(), Menu()
    */    
    var $menu = array();
    
    
    /**
    * Mapping from URL to menu path.
    *
    * @var  array
    * @see  getPath()
    */
    var $urlmap = array();
    
    
    /**
    * Menu type: tree, rows, you-are-here.
    * 
    * @var  array
    * @see  setMenuType()
    */
    var $menu_type = "";
    
    
    /**
    * Path to a certain menu item.
    * 
    * Internal class variable introduced to save some recursion overhead. 
    *
    * @var  array
    * @see  get(), getPath()
    */
    var $path = array();
    
    
    /**
    * Generated HTML menu.
    * 
    * @var  string
    * @see  get()
    */
    var $html = "";

    
    /**
    * Initializes the menu, sets the type and menu structure.
    * 
    * @param    array
    * @param    string
    * @see      setMenuType(), setMenu()
    */
    function menu($menu = "", $type = "tree") { 
        
        if (is_array($menu))
            $this->setMenu($menu);

        $this->setMenuType($type);
        
    } // end constructor   
    
    
    /**
    * Sets the menu structure.
    *
    * The menu structure is defined by a multidimensional hash. This is 
    * quite "dirty" but simple and easy to traverse. An example 
    * show the structure. To get the following menu:
    * 
    * 1  - Projects
    * 11 - Projects => PHPDoc
    * 12 - Projects => Forms
    * 2  - Stuff
    *
    * you need the array:
    * 
    * $menu = array( 
    *           1 => array( 
    *                  "title" => "Projects", 
    *                  "url" => "/projects/index.php",
    *                  "sub" => array(
    *                           11 => array(
    *                                       "title" => "PHPDoc",
    *                                       ...
    *                                     ),
    *                           12 => array( ... ),
    *                 )
    *             ),
    *           2 => array( "title" => "Stuff", "url" => "/stuff/index.php" )
    *        )
    *
    * Note the index "sub" and the nesting. Note also that 1, 11, 12, 2 
    * must be unique. The class uses them as ID's. 
    * 
    * @param    array
    * @access   public
    * @see      append(), update(), delete()
    */
    function setMenu($menu) {
        
        $this->menu = $menu;
        $this->urlmap = array();
        
    } // end func setMenu
    
    
    /**
    * Sets the type / format of the menu: tree, rows or urhere.
    *
    * @param    string  "tree", "rows", "urhere"
    * @access   public
    */
    function setMenuType($menu_type) {
    
        $this->menu_type = strtolower($menu_type);
        
    } // end func setMenuType

    /**
    * Returns the HTML menu.
    * 
    * @param    string  Menu type: tree, urhere, rows, prevnext
    * @return   string  HTML of the menu
    * @access   public
    */
    function get($menu_type = "") {
        if ("" != $menu_type)
            $this->setMenuType($menu_type);

        $this->html = ""; 
                   
        // buildMenu for rows cares on this itself            
        if ("rows" != $this->menu_type)             
            $this->html  .= $this->getStart();
        
        // storing to a class variable saves some recursion overhead
        $this->path = $this->getPath();
        $this->buildMenu($this->menu);
    
        if ("rows" != $this->menu_typ)
            $this->html .= $this->getEnd();
        
        return $this->html . $this->getEnd();
    } // end func get
    
    
    /**
    * Prints the HTML menu.
    * 
    * @brother  get()
    * @return   void
    */
    function show($menu_type = "") {
        print $this->get($menu_type);
    } // end func show
    
    /**
    * Returns a sitemap.
    * 
    * @return string  HTML code
    * @access public
    */
    function getSitemap() {
      
      $oldtype = $this->menu_type;
      $this->setMenuType("tree");
      
      $this->html = $this->getStart();
    
      $this->path = $this->getPath();
      $this->buildSitemap($this->menu);

      $this->setMenuType($oldtype);
      
      return $this->html . $this->getEnd();
    } // end func getSitemap

    
    /**
    * Returns the prefix of the HTML menu items.
    * 
    * @return   string  HTML menu prefix
    * @see      getEnd(), get()
    */
    function getStart() {
    
        $html = "";
        switch ($this->menu_type) {
            case "rows":
            case "prevnext":
                $html .= "<table border><tr>";
                break;
                
            case "tree":
            case "urhere":
                $html .= "<table border>";
                break;
        }
        
        return $html;
    } // end func getStart

    
    /**
    * Returns the postfix of the HTML menu items.
    *
    * @return   string  HTML menu postfix
    * @see      getStart(), get()
    */
    function getEnd() {

        $html = "";
        switch ($this->menu_type) {
            case "rows":
            case "prevnext":
                $html .="</tr></table>";
                break;
            
            case "tree":
            case "urhere":
                $html = "</table>";
                break;
        }
        
        return $html;
    } // end func getEnd
    
    
    /**
    * Build the menu recursively.
    *
    * @param    array   first call: $this->menu, recursion: submenu
    * @param    integer level of recursion, current depth in the tree structure
    * @param    integer prevnext flag
    */
    function buildMenu($menu, $level = 0, $flag_stop_level = -1) {
        static $last_node = array();
        global $PHP_SELF;
     
        // WARNING: dirty redsys.de Hack
        if ("" != HOME && "/" . HOME == substr($PHP_SELF, 0, strlen(HOME) + 1))
            $PHP_SELF = substr($PHP_SELF, strlen(HOME) + 1);
            
            
        // the recursion goes slightly different for every menu type
        switch ($this->menu_type) {
            
            case "tree":
            
                // loop through the (sub)menu
                foreach ($menu as $node_id => $node) {

                    if ($PHP_SELF == $node["url"]) {
                        // menu item that fits to this url - "active" menu item
                        $type = 1;
                    } else if (isset($this->path[$level]) && $this->path[$level] == 
$node_id) {
                        // processed menu item is part of the path to the active menu 
item
                        $type = 2;
                    } else {
                        // not selected, not a part of the path to the active menu item
                        $type = 0;
                    }
        
                    $this->html .= $this->getEntry($node, $level, $type);
                    
                    // follow the subtree if the active menu item is in it
                    if ($type && isset($node["sub"]))
                        $this->buildMenu($node["sub"], $level + 1);
                }
                break;
                
            case "rows":
                
                // every (sub)menu has it's own table
                $this->html .= $this->getStart();
                $submenu = false;
                
                // loop through the (sub)menu
                foreach ($menu as $node_id => $node) {
                
                    if ($PHP_SELF == $node["url"]) {
                        // menu item that fits to this url - "active" menu item
                        $type = 1;
                    } else if (isset($this->path[$level]) && $this->path[$level] == 
$node_id) {
                        // processed menu item is part of the path to the active menu 
item
                        $type = 2;
                    } else {
                        // not selected, not a part of the path to the active menu item
                        $type = 0;
                    }

                    $this->html .= $this->getEntry($node, $level, $type);
                    
                    // remember the subtree
                    if ($type && isset($node["sub"]))
                        $submenu = $node["sub"];
                        
                }
                
                // close the table for this level
                $this->html .= $this->getEnd();
                
                // go deeper if neccessary
                if ($submenu)
                    $this->buildMenu($submenu, $level + 1);

                break;

            case "urhere":

                // loop through the (sub)menu
                foreach ($menu as $node_id => $node) {
                        
                    if ($PHP_SELF == $node["url"]) {
                        // menu item that fits to this url - "active" menu item
                        $type = 1;
                    } else if (isset($this->path[$level]) && $this->path[$level] == 
$node_id) {
                        // processed menu item is part of the path to the active menu 
item
                        $type = 2;
                    } else {
                        // not selected, not a part of the path to the active menu item
                        $type = 0;
                    }
        
                    // follow the subtree if the active menu item is in it
                    if ($type) {
                        $this->html .= $this->getEntry($node, $level, $type);
                        if (isset($node["sub"])) {
                            $this->buildMenu($node["sub"], $level + 1);
                            continue;
                        }
                    }
                    
                }
                break;
                
          case "prevnext":
                
                // loop through the (sub)menu
                foreach ($menu as $node_id => $node) {
                    
                    if (-1 != $flag_stop_level) {
                    
                        // add this item to the menu and stop recursion - (next >>) 
node
                        if ($flag_stop_level == $level) {
                            $this->html .= $this->getEntry($node, $level, 4);
                            $flag_stop_level = -1;
                        }

                        break;
                        
                    
                    } else if ($PHP_SELF == $node["url"]) {
                        // menu item that fits to this url - "active" menu item
                        $type = 1;
                        
                        if (0 != count($last_node)) {
                        
                            $this->html .= $this->getEntry($last_node, $level, 3);
                          
                        } else {
                        
                            // WARNING: if there's no previous take the first menu 
entry - you might not like this rule!
                            reset($this->menu);
                            list($node_id, $first_node) = each($this->menu);
                            $this->html .= $this->getEntry($first_node, $level, 3);
                            
                        
                        }
                        
                        $flag_stop_level = $level;
                        
                    } else if (isset($this->path[$level]) && $this->path[$level] == 
$node_id) {
                        // processed menu item is part of the path to the active menu 
item
                        $type = 2;
                     
                    } else {
                    
                        $type = 0;
                    
                    }
                    
                    // remember the last (<< prev) node
                    $last_node = $node;
                    
                    // follow the subtree if the active menu item is in it
                    if ($type && isset($node["sub"]))
                        $flag_stop_level = $this->buildMenu($node["sub"], $level + 1, 
(-1 != $flag_stop_level) ? $flag_stop_level + 1 : -1); 
                }
                break;
                
            
        } // end switch menu_type
        
        return ($flag_stop_level) ? $flag_stop_level - 1 : -1;
    } // end func buildMenu
    
    
    /**
    * Build the menu recursively.
    *
    * @param    array   first call: $this->menu, recursion: submenu
    * @param    int     level of recursion, current depth in the tree structure
    */
    function buildSitemap($menu, $level = 0) {
        global $PHP_SELF;
        
        // loop through the (sub)menu
        foreach ($menu as $node_id => $node) {
        
            if ($PHP_SELF == $node["url"]) {
                // menu item that fits to this url - "active" menu item
                $type = 1;
            } else if (isset($this->path[$level]) && $this->path[$level] == $node_id) {
                // processed menu item is part of the path to the active menu item
                $type = 2;
            } else {
                // not selected, not a part of the path to the active menu item
                $type = 0;
            }

            $this->html .= $this->getEntry($node, $level, $type);
            
            // follow the subtree if the active menu item is in it
            if (isset($node["sub"]))
                $this->buildSitemap($node["sub"], $level + 1);
        }

    } // end func buildSitemap
    
    
    /**
    * Returns the HTML of one menu item.
    * 
    * @param    array   menu item data (node data)
    * @param    integer level in the menu tree
    * @param    string  menu item type: 0, 1, 2. 0 => plain menu item,
    *                   1 => selected (active) menu item, 2 => item 
    *                   is a member of the path to the selected (active) menu item
    *                   3 => previous entry, 4 => next entry
    * @return   string  HTML
    * @see      buildMenu()
    */
    function getEntry(&$node, $level, $item_type) {

        $html = "";
        
        if ("tree" == $this->menu_type) {
            // tree menu
            $html .= "<tr>";
            $indent = "";
            if ($level) 
                for ($i = 0; $i < $level; $i++)
                    $indent .= "&nbsp;&nbsp;&nbsp;";
        }
        
        // draw the <td></td> cell depending on the type of the menu item
        switch ($item_type) {
            case 0:
                // plain menu item
                $html .= sprintf('<td>%s<a href="%s">%s</a></td>',
                                    $indent,
                                    $node["url"],
                                    $node["title"]
                                 );
                break;
                
            case 1:
                // selected (active) menu item
                $html .= sprintf('<td>%s<b>%s</b></td>', 
                                   $indent,
                                   $node["title"]
                                );
                break;
                
            case 2:
                // part of the path to the selected (active) menu item
                $html .= sprintf('<td>%s<a href="%s">%s</a>%s</td>',
                                    $indent,
                                    $node["url"],
                                    $node["title"],
                                    ("urhere" == $this->menu_type) ? " >> " : ""
                                );
                break;
                
            case 3: 
                // << previous url
                $html .= sprintf('<td>%s<a href="%s"><< %s</a></td>',
                                    $indent,
                                    $node["url"],
                                    $node["title"]
                                );
                break;

            case 4:
                // next url >>
                $html .= sprintf('<td>%s<a href="%s">%s >></a></td>',
                                    $indent,
                                    $node["url"],
                                    $node["title"]
                                );
                break;
                
        }
            
        if ("tree" == $this->menu_type)
            $html .= "</tr>\n";

        return $html;
    } // end func getEnty

    
    /*
    * Returns the path of the current page in the menu "tree".
    *
    * @return   array    path to the selected menu item
    * @global   $PHP_SELF
    * @see      buildPath(), $urlmap
    */
    function getPath() {
        global $PHP_SELF;
        
        $this->buildPath($this->menu, array());  
        
        return $this->urlmap[$PHP_SELF];          
    } // end func getPath
    
    
    /**
    * Computes the path of the current page in the menu "tree".
    * 
    * @param    array       first call: menu hash / recursion: submenu hash
    * @param    array       first call: array() / recursion: path
    * @return   boolean     true if the path to the current page was found, 
    *                       otherwise false. Only meaningful for the recursion.
    * @global   $PHP_SELF   
    * @see      getPath(), $urlmap
    */
    function buildPath($menu, $path) {
        global $PHP_SELF;
        
        // loop through the (sub)menu
        foreach ($menu as $node_id => $node) {
        
            // save the path of the current node in the urlmap
            $this->urlmap[$node["url"]] = $path;
            
            // we got'em - stop the search by returning true
            if ($node["url"] == $PHP_SELF)
               return true;
               
            // current node has a submenu               
            if ($node["sub"]) {
                
                // submenu path = current path + current node
                $subpath = $path;
                $subpath[] = $node_id;
                
                // continue search recursivly - return is the inner loop finds the 
                // node that belongs to $PHP_SELF
                if ($this->buildPath($node["sub"], $subpath))
                    return true;
            }

        } 

        // not found
        return false;        
    } // end func buildPath
    
} // end class menu
?>
-- 
PHP CVS Mailing List (http://www.php.net/)
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]
To contact the list administrators, e-mail: [EMAIL PROTECTED]

Reply via email to