<?php
/**
 * HTML_TreeMenu
 *
 * PHP Versions 4 and 5
 *
 *   Copyright (c) 2002-2005, Richard Heyes, Harald Radi
 *   All rights reserved.
 *
 *   Redistribution and use in source and binary forms, with or without
 *   modification, are permitted provided that the following conditions
 *   are met:
 *
 *   o Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   o Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *   o The names of the authors may not be used to endorse or promote
 *     products derived from this software without specific prior written
 *     permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * @category HTML
 * @package  HTML_TreeMenu
 * @author   Richard Heyes <richard@php.net>
 * @author   Harald Radi <harald.radi@nme.at>
 * @license  http://www.opensource.org/licenses/bsd-license.php  BSD License
 * @version  CVS: $Id: TreeMenu.php 304737 2010-10-25 09:08:58Z clockwerx $
 * @link     http://pear.php.net/package/HTML_TreeMenu
 * @todo     PEAR CS - split classes into individual files
 */

/**
 * HTML_TreeMenu Class
 *
 * A simple couple of PHP classes and some not so simple
 * Jabbascript which produces a tree menu. In IE this menu
 * is dynamic, with branches being collapsable. In IE5+ the
 * status of the collapsed/open branches persists across page
 * refreshes.In any other browser the tree is static. Code is
 * based on work of Harald Radi.
 *
 * Usage.
 *
 * After installing the package, copy the example php script to
 * your servers document root. Also place the TreeMenu.js and the
 * images folder in the same place. Running the script should
 * then produce the tree.
 *
 * Thanks go to Chip Chapin (http://www.chipchapin.com) for many
 * excellent ideas and improvements.
 *
 * @category HTML
 * @package  HTML_TreeMenu
 * @author   Richard Heyes <richard@php.net>
 * @author   Harald Radi <harald.radi@nme.at>
 * @license  http://www.opensource.org/licenses/bsd-license.php  BSD License
 * @link     http://pear.php.net/package/HTML_TreeMenu
 */
class HTML_TreeMenu
{
    /**
     * Indexed array of subnodes
     * @var array
     * @access public
     */
    var $items;

    /**
     * Constructor
     *
     * @access public
     */
    function HTML_TreeMenu()
    {
        // Not much to do here :(
    }

    /**
     * This function adds an item to the the tree.
     *
     * @param HTML_TreeNode &$node The node to add.
     *                             This object should be a HTML_TreeNode object.
     *
     * @return int Returns a reference to the new node inside the tree.
     * @access public
     */
    function &addItem(&$node)
    {
        $this->items[] = &$node;
        return $this->items[count($this->items) - 1];
    }

    /**
     * Import method for creating {@link HTML_TreeMenu} objects/structures
     * out of existing tree objects/structures.
     *
     * Currently supported are Wolfram Kriesings' PEAR Tree class, and
     * Richard Heyes' Tree class ({@link http://www.phpguru.org/}). This
     * method is intended to be used statically, eg:
     * <code>
     * $treeMenu = &HTML_TreeMenu::createFromStructure($myTreeStructureObj);
     * </code>
     *
     * @param array $params An array of parameters that determine
     *                      how the import happens. This can consist of:
     *                      <pre>
     *                          structure   => The tree structure
     *                          type        => The type of the structure, currently
     *                                         can be either 'heyes' or 'kriesing'
     *                          nodeOptions => Default options for each node
     *                      </pre>
     *
     * @return HTML_TreeMenu The resulting {@link HTML_TreeMenu} object
     * @access public
     * @static
     */
    function createFromStructure($params)
    {
        if (!isset($params['nodeOptions'])) {
            $params['nodeOptions'] = array();
        }

        switch (@$params['type']) {

        /*
         * Wolfram Kriesings' PEAR Tree class
         */
        case 'kriesing':
            $className   = get_class($params['structure']->dataSourceClass);
            $className   = strtolower($className);
            $isXMLStruct = strpos($className, '_xml') !== false ? true : false;

            // Get the entire tree, the $nodes are sorted like in the tree view
            // from top to bottom, so we can easily put them in the nodes
            $nodes = $params['structure']->getNode();

            // Make a new menu and fill it with the values from the tree
            $treeMenu = new HTML_TreeMenu();
            // we need the current node as the reference
            $curNode[0] = &$treeMenu;

            foreach ($nodes as $aNode) {
                $events = array();
                $data   = array();

                /* In an XML, all the attributes are saved in an array, but
                 * since they might be  used as the parameters, we simply
                 * extract them here if we handle an XML-structure
                 */
                if ( $isXMLStruct && sizeof($aNode['attributes'])) {
                    foreach ($aNode['attributes'] as $key=>$val) {
                        if ( !$aNode[$key] ) {
                            // dont overwrite existing values
                            $aNode[$key] = $val;
                        }
                    }
                }

                // Process all the data that are saved in $aNode and put them
                // in the data and/or events array
                foreach ($aNode as $key=>$val) {
                    if (!is_array($val)) {
                        // Dont get the recursive data in here! they are
                        // always arrays
                        if (substr($key, 0, 2) == 'on') {
                            // get the events
                            $events[$key] = $val;
                        }

                        // I put it in data too, so in case an options starts
                        // with 'on' its also passed to the node ... not too
                        // cool i know
                        $data[$key] = $val;
                    }
                }

                // Normally the text is in 'name' in the Tree class, so we
                // check both but 'text' is used if found
                $data['text'] = $aNode['text'] ?
                    $aNode['text'] : $aNode['name'];

                // Add the item to the proper node
                $thisNode = &$curNode[$aNode['level']]->addItem(new
                            HTML_TreeNode($data, $events));

                $curNode[$aNode['level']+1] = &$thisNode;
            }
            break;

        /*
         * Richard Heyes' (me!) second (array based) Tree class
         */
        case 'heyes_array':
            // Need to create a HTML_TreeMenu object ?
            if (!isset($params['treeMenu'])) {
                $treeMenu = &new HTML_TreeMenu();
                $parentID = 0;
            } else {
                $treeMenu = &$params['treeMenu'];
                $parentID = $params['parentID'];
            }

            // Loop thru the trees nodes
            foreach ($params['structure']->getChildren($parentID)
                    as $nodeID) {
                $data       = $params['structure']->getData($nodeID);
                $parentNode = &$treeMenu->addItem(new
                    HTML_TreeNode(array_merge($params['nodeOptions'], $data)));

                // Recurse ?
                if ($params['structure']->hasChildren($nodeID)) {
                    $recurseParams['type']        = 'heyes_array';
                    $recurseParams['parentID']    = $nodeID;
                    $recurseParams['nodeOptions'] = $params['nodeOptions'];
                    $recurseParams['structure']   = &$params['structure'];
                    $recurseParams['treeMenu']    = &$parentNode;
                    HTML_TreeMenu::createFromStructure($recurseParams);
                }
            }

            break;

        /*
         * Richard Heyes' (me!) original OO based Tree class
         */
        case 'heyes':
        default:
            // Need to create a HTML_TreeMenu object ?
            if (!isset($params['treeMenu'])) {
                $treeMenu = &new HTML_TreeMenu();
            } else {
                $treeMenu = &$params['treeMenu'];
            }

            // Loop thru the trees nodes
            foreach ($params['structure']->nodes->nodes as $node) {
                $tag        = $node->getTag();
                $parentNode = &$treeMenu->addItem(new
                 HTML_TreeNode(array_merge($params['nodeOptions'], $tag)));

                // Recurse ?
                if (!empty($node->nodes->nodes)) {
                    $recurseParams['structure']   = $node;
                    $recurseParams['nodeOptions'] = $params['nodeOptions'];
                    $recurseParams['treeMenu']    = &$parentNode;
                    HTML_TreeMenu::createFromStructure($recurseParams);
                }
            }
            break;

        }
        return $treeMenu;
    }

    /**
     * Creates a treeMenu from XML.
     *
     * The structure of your XML should be like so:
     * <code>
     * <treemenu>
     *     <node text="First node" icon="folder.gif"
     *           expandedIcon="folder-expanded.gif" />
     *     <node text="Second node" icon="folder.gif"
     *           expandedIcon="folder-expanded.gif">
     *         <node text="Sub node" icon="folder.gif"
     *               expandedIcon="folder-expanded.gif" />
     *     </node>
     *     <node text="Third node" icon="folder.gif"
     *           expandedIcon="folder-expanded.gif">
     * </treemenu>
     * </code>
     *
     * Any of the options you can supply to the HTML_TreeNode constructor can
     * be supplied as attributes to the <node> tag. If there are no
     * subnodes for a particular node, you can use the XML shortcut
     * <node ... /> instead of <node ... ></node>. The $xml argument
     * can be either the XML as a string, or an pre-created XML_Tree
     * object. Also, this method REQUIRES my own Tree class to work
     * ({@link http://www.phpguru.org/static/tree.html}). If this has not been
     * include()ed or require()ed this method will die().
     *
     * @param string|XML_Tree $xml This can be either a string containing the XML,
     *                             or an
     *                             {@link http://pear.php.net/package/XML_Tree
     *                             XML_Tree} object
     *
     * @return HTML_TreeMenu The {@link HTML_TreeMenu} object
     * @access public
     * @static
     * @todo update {@link http://pear.php.net/package/XML_Tree XML_Tree} usage
     *       to {@link http://pear.php.net/package/XML_Serializer XML_Serializer}
     */
    function createFromXML($xml)
    {
        if (!class_exists('Tree')) {
            die('Could not find Tree class');
        }

        if (is_string($xml)) {
            // Supplied $xml is a string
            include_once 'XML/Tree.php';
            $xmlTree = &new XML_Tree();
            $xmlTree->getTreeFromString($xml);
        } else {
            // Supplied $xml is an XML_Tree object
            $xmlTree = $xml;
        }

        // Now process the XML_Tree object, setting the XML attributes
        // to be the tag data (with out the XML tag name or contents).
        $treeStructure = Tree::createFromXMLTree($xmlTree, true);
        $treeStructure->nodes->traverse(create_function('&$node', '
         $tagData = $node->getTag(); $node->setTag($tagData["attributes"]);'));

        return HTML_TreeMenu::createFromStructure(array(
                                               'structure' => $treeStructure));
    }
} // HTML_TreeMenu


/**
 * HTML_TreeNode class
 *
 * This class is supplementary to the above and provides a way to
 * add nodes to the tree. A node can have other nodes added to it.
 *
 * @category HTML
 * @package  HTML_TreeMenu
 * @author   Richard Heyes <richard@php.net>
 * @author   Harald Radi <harald.radi@nme.at>
 * @license  http://www.opensource.org/licenses/bsd-license.php  BSD License
 * @link     http://pear.php.net/package/HTML_TreeMenu
 * @todo     PEAR CS - rename to HTML_TreeMenu_Node
 */
class HTML_TreeNode
{
    /**#@+
     * @var string
     * @access public
     */

    /**
     * The text for this node.
     */
    var $text;

    /**
     * The link for this node.
     */
    var $link;

    /**
     * The icon for this node.
     */
    var $icon;

    /**
     * The icon to show when expanded for this node.
     */
    var $expandedIcon;

    /**
     * The css class for this node
     */
    var $cssClass;

    /**
     * The link target for this node
     */
    var $linkTarget;

    /**#@-*/

    /**#@+
     * @access public
     */

    /**
     * Indexed array of subnodes
     * @var array
     */
    var $items;

    /**
     * Whether this node is expanded or not
     * @var bool
     */
    var $expanded;

    /**
     * Whether this node is dynamic or not
     * @var bool
     */
    var $isDynamic;

    /**
     * Should this node be made visible?
     * @var bool
     */
    var $ensureVisible;

    /**
     * The parent node. Null if top level
     * @var HTML_TreeNode
     */
    var $parent;

    /**
     * Javascript event handlers;
     * @var array
     */
    var $events;

    /**#@-*/

    /**
     * Constructor
     *
     * @param array $options An array of options which you can pass to change
     *                       the way this node looks/acts. This can consist of:
     *                       <pre>
     *                         o text          The title of the node,
     *                                         defaults to blank
     *                         o link          The link for the node,
     *                                         defaults to blank
     *                         o icon          The icon for the node,
     *                                         defaults to blank
     *                         o expandedIcon  The icon to show when the node
     *                                         is expanded
     *                         o cssClass      The CSS class for this node,
     *                                         defaults to blank
     *                         o expanded      The default expanded status of
     *                                         this node, defaults to false
     *                                         This doesn't affect non dynamic
     *                                         presentation types
     *                         o linkTarget    Target for the links.
     *                                         Defaults to linkTarget of the
     *                                         HTML_TreeMenu_Presentation.
     *                         o isDynamic     If this node is dynamic or not.
     *                                         Only affects certain
     *                                         presentation types.
     *                         o ensureVisible If true this node will be made
     *                                         visible despite the expanded
     *                                         settings, and client side
     *                                         persistence. Will not affect
     *                                         some presentation styles, such as
     *                                         Listbox.
     *                                         Default is false
     *                        </pre>
     * @param array $events  An array of javascript events and the
     *                       corresponding event handlers.
     *                       Additionally to the standard javascript events you
     *                       can specify handlers for the 'onexpand',
     *                       'oncollapse' and 'ontoggle' events which will be
     *                       fired whenever a node is collapsed and/or expanded.
     *
     * @access public
     */
    function HTML_TreeNode($options = array(), $events = array())
    {
        $this->text          = '';
        $this->link          = '';
        $this->icon          = '';
        $this->expandedIcon  = '';
        $this->cssClass      = '';
        $this->expanded      = false;
        $this->isDynamic     = true;
        $this->ensureVisible = false;
        $this->linkTarget    = null;

        $this->parent = null;
        $this->events = $events;

        foreach ($options as $option => $value) {
            $this->$option = $value;
        }
    }

    /**
     * Allows setting of various parameters after the initial constructor call
     *
     * Possible options you can set are:
     * <pre>
     *  o text
     *  o link
     *  o icon
     *  o cssClass
     *  o expanded
     *  o isDynamic
     *  o ensureVisible
     * </pre>
     *
     * NOTE:  The same options as in {@link HTML_TreeNode()}
     *
     * @param string $option Option to set
     * @param string $value  Value to set the option to
     *
     * @return void
     * @access public
     */
    function setOption($option, $value)
    {
        $this->$option = $value;
    }

    /**
     * Adds a new subnode to this node.
     *
     * @param HTML_TreeNode &$node The new node
     *
     * @return int
     * @access public
     */
    function &addItem(&$node)
    {
        $node->parent  = &$this;
        $this->items[] = &$node;

        /*
         * If the subnode has ensureVisible set it needs
         * to be handled, and all parents set accordingly.
         */
        if ($node->ensureVisible) {
            $this->_ensureVisible();
        }

        return $this->items[count($this->items) - 1];
    }

    /**
     * Private function to handle ensureVisible stuff
     *
     * @return void
     * @access private
     */
    function _ensureVisible()
    {
        $this->ensureVisible = true;
        $this->expanded      = true;

        if (!is_null($this->parent)) {
            $this->parent->_ensureVisible();
        }
    }
} // HTML_TreeNode


/**
 * HTML_TreeMenu_Presentation class
 *
 * Base class for other presentation classes to
 * inherit from.
 *
 * @category HTML
 * @package  HTML_TreeMenu
 * @author   Richard Heyes <richard@php.net>
 * @author   Harald Radi <harald.radi@nme.at>
 * @license  http://www.opensource.org/licenses/bsd-license.php  BSD License
 * @link     http://pear.php.net/package/HTML_TreeMenu
 */
class HTML_TreeMenu_Presentation
{
    /**
     * The TreeMenu structure
     * @var HTML_TreeMenu
     * @access public
     */
    var $menu;

    /**
     * Base constructor simply sets the menu object
     *
     * @param HTML_TreeMenu &$structure The menu structure
     */
    function HTML_TreeMenu_Presentation(&$structure)
    {
        $this->menu = &$structure;
    }

    /**
     * Prints the HTML generated by the toHTML() method.
     * toHTML() must therefore be defined by the derived
     * class.
     *
     * @param array $options Options to set. Any options taken by the
     *                       presentation class can be specified here.
     *
     * @return void
     * @access public
     */
    function printMenu($options = array())
    {
        foreach ($options as $option => $value) {
            $this->$option = $value;
        }

        echo $this->toHTML();
    }
}


/**
 * HTML_TreeMenu_DHTML class
 *
 * This class is a presentation class for the tree structure
 * created using the TreeMenu/TreeNode. It presents the
 * traditional tree, static for browsers that can't handle
 * the DHTML.
 *
 * @category HTML
 * @package  HTML_TreeMenu
 * @author   Richard Heyes <richard@php.net>
 * @author   Harald Radi <harald.radi@nme.at>
 * @license  http://www.opensource.org/licenses/bsd-license.php  BSD License
 * @link     http://pear.php.net/package/HTML_TreeMenu
 */
class HTML_TreeMenu_DHTML extends HTML_TreeMenu_Presentation
{
    /**#@+
     * @access public
     */

    /**
     * Dynamic status of the treemenu.
     * If true (default) this has no effect. If
     * false it will override all dynamic status vars and set the menu to be
     * fully expanded an non-dynamic.
     * @var bool
     */
    var $isDynamic;

    /**
     * Path to the images
     * @var string
     */
    var $images;

    /**
     * Target for the links generated
     * @var string
     */
    var $linkTarget;

    /**
     * Whether to use clientside persistence or not
     * @var bool
     */
    var $usePersistence;

    /**
     * The default CSS class for the nodes
     * @var string
     */
    var $defaultClass;

    /**
     * Whether to skip first level branch images
     * @var bool
     */
    var $noTopLevelImages;

    /**
     * Name of Jabbascript object to use
     * @var string
     */
    var $jsObjectName;

    /**#@-*/

    /**
     * Constructor
     *
     * Takes the tree structure as an argument and an array of options
     * which can consist of:
     * <pre>
     *  o images            -  The path to the images folder.
     *                         Defaults to "images"
     *  o linkTarget        -  The target for the link.
     *                         Defaults to "_self"
     *  o defaultClass      -  The default CSS class to apply to a node.
     *                         Default is none.
     *  o usePersistence    -  Whether to use clientside persistence. This
     *                         persistence is achieved using cookies.
     *                         Default is true.
     *  o noTopLevelImages  -  Whether to skip displaying the first level of
     *                         images if there is multiple top level branches.
     *  o maxDepth          -  The maximum depth of indentation. Useful for
     *                         ensuring deeply nested trees don't go way off to
     *                         the right of your page etc.
     *                         Defaults to no limit.
     *  o jsObjectName      -  Name to use for jabbascript object. Set this if
     *                         you have different menus that should maintain
     *                         their persistence information separately.
     * </pre>
     *
     * And also a boolean for whether the entire tree is dynamic or not.
     * This overrides any perNode dynamic settings.
     *
     * @param HTML_TreeMenu &$structure The menu structure
     * @param array         $options    Array of options
     * @param bool          $isDynamic  Whether the tree is dynamic or not
     *
     * @access public
     */
    function HTML_TreeMenu_DHTML(&$structure, $options = array(), $isDynamic = true)
    {
        $this->HTML_TreeMenu_Presentation($structure);
        $this->isDynamic = $isDynamic;

        // Defaults
        $this->images           = 'images';
        $this->maxDepth         = 0;        // No limit
        $this->linkTarget       = '_self';
        $this->jsObjectName     = 'objTreeMenu';
        $this->defaultClass     = '';
        $this->usePersistence   = true;
        $this->noTopLevelImages = false;

        foreach ($options as $option => $value) {
            $this->$option = $value;
        }
    }

    /**
     * Returns the HTML for the menu.
     *
     * This method can be used instead of
     * {@link HTML_TreeMenu_Presentation::printMenu()}
     * to use the menu system with a template system.
     *
     * @return string The HTML for the menu
     * @access public
     */
    function toHTML()
    {
        static $count = 0;

        $menuObj = $this->jsObjectName . '_' . ++$count;

        $html  = "\n";
        $html .= '<script type="text/javascript">' . "\n//<![CDATA[\n\t";
        $html .= sprintf('%s = new TreeMenu("%s", "%s", "%s", "%s", %s, %s);',
                         $menuObj,
                         $this->images,
                         $menuObj,
                         $this->linkTarget,
                         $this->defaultClass,
                         $this->usePersistence ? 'true' : 'false',
                         $this->noTopLevelImages ? 'true' : 'false');

        $html .= "\n";

        /*
         * Loop through subnodes
         */
        if (isset($this->menu->items)) {
            for ($i=0; $i<count($this->menu->items); $i++) {
                $html .= $this->_nodeToHTML($this->menu->items[$i], $menuObj);
            }
        }

        $html .= sprintf("\n\t%s.drawMenu();", $menuObj);
        $html .= sprintf("\n\t%s.writeOutput();", $menuObj);

        if ($this->usePersistence && $this->isDynamic) {
            $html .= sprintf("\n\t%s.resetBranches();", $menuObj);
        }
        $html .= "\n// ]]>\n</script>";

        return $html;
    }

    /**
     * Prints a node of the menu
     *
     * @param HTML_TreeNode $nodeObj        node object
     * @param mixed         $prefix         prefix
     * @param string        $return         default to 'newNode'
     * @param int           $currentDepth   default to 0
     * @param mixed         $maxDepthPrefix default to null
     *
     * @return string
     * @access private
     */
    function _nodeToHTML($nodeObj,
                         $prefix,
                         $return         = 'newNode',
                         $currentDepth   = 0,
                         $maxDepthPrefix = null)
    {
        $prefix = empty($maxDepthPrefix) ? $prefix : $maxDepthPrefix;

        $expanded  = $this->isDynamic ?
                        ($nodeObj->expanded  ? 'true' : 'false') : 'true';
        $isDynamic = $this->isDynamic ?
                        ($nodeObj->isDynamic ? 'true' : 'false') : 'false';
        $html      = sprintf("\t %s = %s.addItem(new TreeNode" .
                        "('%s', %s, %s, %s, %s, '%s', '%s', %s));\n",
                        $return,
                        $prefix,
                        str_replace("'", "\\'", $nodeObj->text),
                        !empty($nodeObj->icon) ? "'" . $nodeObj->icon . "'" : 'null',
                        !empty($nodeObj->link) ? "'" . $nodeObj->link . "'" : 'null',
                        $expanded,
                        $isDynamic,
                        $nodeObj->cssClass,
                        $nodeObj->linkTarget,
                        !empty($nodeObj->expandedIcon) ?
                            "'" . $nodeObj->expandedIcon . "'" : 'null');

        foreach ($nodeObj->events as $event => $handler) {
            $html .= sprintf("\t %s.setEvent('%s', '%s');\n",
                             $return,
                             $event,
                             str_replace(array("\r", "\n", "'"),
                                array('\r', '\n', "\'"),
                             $handler));
        }

        if ($this->maxDepth > 0 AND $currentDepth == $this->maxDepth) {
            $maxDepthPrefix = $prefix;
        }

        /*
         * Loop through subnodes
         */
        if (!empty($nodeObj->items)) {
            for ($i=0; $i<count($nodeObj->items); $i++) {
                $html .= $this->_nodeToHTML($nodeObj->items[$i],
                                            $return,
                                            $return . '_' . ($i + 1),
                                            $currentDepth + 1,
                                            $maxDepthPrefix);
            }
        }

        return $html;
    }
} // End class HTML_TreeMenu_DHTML


/**
 * HTML_TreeMenu_Listbox class
 *
 * This class presents the menu as a listbox
 *
 * @category HTML
 * @package  HTML_TreeMenu
 * @author   Richard Heyes <richard@php.net>
 * @author   Harald Radi <harald.radi@nme.at>
 * @license  http://www.opensource.org/licenses/bsd-license.php  BSD License
 * @link     http://pear.php.net/package/HTML_TreeMenu
 */
class HTML_TreeMenu_Listbox extends HTML_TreeMenu_Presentation
{
    /**#@+
     * @access public
     */

    /**
     * The text that is displayed in the first option
     * @var string
     */
    var $promoText;

    /**
     * The character used for indentation
     * @var string
     */
    var $indentChar;

    /**
     * How many of the indent chars to use per indentation level
     * @var int
     */
    var $indentNum;

    /**
     * Target for the links generated
     * @var string
     */
    var $linkTarget;

    /**#@-*/

    /**
     * Constructor
     *
     * @param object $structure The menu structure
     * @param array  $options   Options which affect the display of the listbox.
     *                          These can consist of:
     *                          <pre>
     *                           o promoText  The text that appears at the the
     *                                        top of the listbox
     *                                        Defaults to "Select..."
     *                           o indentChar The character to use for indenting
     *                                        the nodes
     *                                        Defaults to "&nbsp;"
     *                           o indentNum  How many of the indentChars to use
     *                                        per indentation level
     *                                        Defaults to 2
     *                           o linkTarget Target for the links.
     *                                        Defaults to "_self"
     *                           o submitText Text for the submit button.
     *                                        Defaults to "Go"
     *                           </pre>
     *
     * @access public
     */
    function HTML_TreeMenu_Listbox($structure, $options = array())
    {
        $this->HTML_TreeMenu_Presentation($structure);

        $this->promoText  = 'Select...';
        $this->indentChar = '&nbsp;';
        $this->indentNum  = 2;
        $this->linkTarget = '_self';
        $this->submitText = 'Go';

        foreach ($options as $option => $value) {
            $this->$option = $value;
        }
    }

    /**
     * Returns the HTML generated
     *
     * @return string
     * @access public
     */
    function toHTML()
    {
        static $count = 0;

        $nodeHTML = '';

        /*
         * Loop through subnodes
         */
        if (isset($this->menu->items)) {
            for ($i=0; $i<count($this->menu->items); $i++) {
                $nodeHTML .= $this->_nodeToHTML($this->menu->items[$i]);
            }
        }

        return sprintf('<form target="%s" action="" onsubmit="var link = ' .
                       'this.%s.options[this.%s.selectedIndex].value; ' .
                       'if (link) {this.action = link; return true} else ' .
                       'return false"><select name="%s">' .
                       '<option value="">%s</option>%s</select> ' .
                       '<input type="submit" value="%s" /></form>',
                       $this->linkTarget,
                       'HTML_TreeMenu_Listbox_' . ++$count,
                       'HTML_TreeMenu_Listbox_' . $count,
                       'HTML_TreeMenu_Listbox_' . $count,
                       $this->promoText,
                       $nodeHTML,
                       $this->submitText);
    }

    /**
     * Returns HTML for a single node
     *
     * @param HTML_TreeNode $node   node
     * @param string        $prefix defaults to empty string
     *
     * @return string
     * @access private
     */
    function _nodeToHTML($node, $prefix = '')
    {
        $html = sprintf('<option value="%s">%s%s</option>',
                        $node->link,
                        $prefix,
                        $node->text);

        /*
         * Loop through subnodes
         */
        if (isset($node->items)) {
            for ($i=0; $i<count($node->items); $i++) {
                $html .= $this->_nodeToHTML($node->items[$i],
                    $prefix . str_repeat($this->indentChar,
                    $this->indentNum));
            }
        }

        return $html;
    }
} // End class HTML_TreeMenu_Listbox
?>
