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 .= " "; } // 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]