Blame | Letzte Änderung | Log anzeigen | RSS feed
<?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 3361 2011-02-24 15:34:41Z tiefland $* @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 arrayforeach ($aNode as $key=>$val) {if (!is_array($val)) {// Dont get the recursive data in here! they are// always arraysif (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(newHTML_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 nodesforeach ($params['structure']->getChildren($parentID)as $nodeID) {$data = $params['structure']->getData($nodeID);$parentNode = &$treeMenu->addItem(newHTML_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 nodesforeach ($params['structure']->nodes->nodes as $node) {$tag = $node->getTag();$parentNode = &$treeMenu->addItem(newHTML_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* require_once )ed or require_once 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 stringinclude_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 " "* 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 = ' ';$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?>