| // +----------------------------------------------------------------------+ // // $Id$ // // {{{ DB_NestedSet_CoolMenu:: class /** * This class can be used to generate the data to build javascript popup menu * from a DB_NestedSet node array. * The Javascript part is done using the freely available CoolMenus * available at http://www.dhtmlcentral.com/projects/coolmenus/. * Currently version 4.0 is supported. * Adapted largely from the DB_NestedSet_TigraMenu class by Daniel Khan. * * @author Andy Crain * @package DB_NestedSet * @access public */ // }}} class DB_NestedSet_CoolMenu extends DB_NestedSet_Output { // {{{{ properties /** * @var string The default/root name of the current menu. * @access private */ var $_menuName = 'CMenu'; /** * @var integer The depth of the current menu. * @access private */ var $_levels = 1; /** * @var integer The level we started at * @access private */ var $_levelOffset = false; /** * @var array The current menu structure * @access private */ var $_structCoolMenu = false; /** * @var array The longest text for each level * @access private */ var $_strlenByLevel = array(); // }}} // {{{ DB_NestedSet_CoolMenu /** * Constructor * * @param array $params A hash with parameters needed by the class * @see _createFromStructure() * @return bool **/ function &DB_NestedSet_CoolMenu($params) { if(isset($params['menu_id'])) $this->_menuName .= $params['menu_id']; $this->_structCoolMenu = $this->_createFromStructure($params); return true; } // }}} // {{{ _createFromStructure() /** * Creates the JavaScript array for CoolMenu * Initially this method was introduced for the TreeMenu driver by Jason Rust * * o 'structure' => the result from $nestedSet->getAllNodes(true) * o 'textField' => the field in the table that has the text for node * o 'linkField' => the field in the table that has the link for the node * * @access private * @return string The CoolMenu makeMenu() JS methods code. */ function &_createFromStructure($params,$parent=null) { // Basically we go through the array of nodes checking to see // if each node has children and if so recursing. The reason this // works is because the data from getAllNodes() is ordered by level // so a root node will always be first, and sub children will always // be after them. static $rootlevel; // always start at level 1 if (!isset($params['currentLevel'])) { $params['currentLevel'] = 1; } if (!isset($rootlevel)) { $rootlevel = $params['currentLevel']; } if (isset($params['coolMenu'])) { $coolMenu = $coolMenu.$params['coolMenu']; } if(!$this->_levelOffset) { $this->_levelOffset = $params['currentLevel']; } if($this->_levels < ($params['currentLevel']- $this->_levelOffset)) { $this->_levels = $params['currentLevel'] - $this->_levelOffset; } // have to use a while loop here because foreach works on a copy of the array and // the child nodes are passed by reference during the recursion so that the parent // will know when they have been hit. reset($params['structure']); while(list($key, $node) = each($params['structure'])) { // see if we've already been here before if (isset($node['hit']) || $node['level'] < $params['currentLevel']) { continue; } // mark that we've hit this node $params['structure'][$key]['hit'] = $node['hit'] = true; // figure out max length for textfields, increase if necessary--NEEDED? if (!$this->_strlenByLevel[$params['currentLevel'] - $this->_levelOffset] || strlen($node[$params['textField']]) > $this->_strlenByLevel[$params['currentLevel'] - $this->_levelOffset]) { $this->_strlenByLevel[$params['currentLevel'] - $this->_levelOffset] = strlen($node[$params['textField']]); }; if($node['rootid'] == $node['id']){ if ($node[$params['linkField']] == basename($_SERVER['PHP_SELF'])) { $coolMenu = $coolMenu . $this->_menuName . ".makeMenu('item" . $node['id'] . "','','" . $node[$params['textField']] ."','" . $node[$params['linkField']] . "','','','','','','level0highlight_mouseout_style','level0highlight_mouseover_style')\n"; } else { $coolMenu = $coolMenu . $this->_menuName . ".makeMenu('item" . $node['id'] . "','','" . $node[$params['textField']] ."','" . $node[$params['linkField']] . "')\n"; } } else { $coolMenu = $coolMenu . $this->_menuName . ".makeMenu('item" . $node['id'] . "','item" . $parent . "','" . $node[$params['textField']] . "','" . $node[$params['linkField']] . "')\n"; } // see if it has children if (($node['r'] - 1) != $node['l']) { $children = array(); // harvest all the children $tempStructure = $params['structure']; foreach ($tempStructure as $childKey => $childNode) { if (!isset($childNode['hit']) && $node['rootid'] == $childNode['rootid'] && $node['l'] < $childNode['l'] && $node['r'] > $childNode['r'] && $childNode['level'] > $params['currentLevel']) { // important that we assign it by reference here, so that when the child // marks itself 'hit' the parent loops will know $children[] =& $params['structure'][$childKey]; } } $recurseParams = $params; $recurseParams['structure'] = $children; $recurseParams['currentLevel']++; $coolMenu = $coolMenu.$this->_createFromStructure($recurseParams,$node['id']); } } return $coolMenu; } // }}} // {{{ _buildStyles() /** * Creates the JavaScript code which sets the styles for each level * * @access private * @param array $options Array of menu style and structure parameters. * @return string The CSS styles for the menu. */ function _buildStyles($options) { $styles = false; //loop once for each level defined foreach ($options['levels'] as $level_id => $level_array) { $styles .= '/*Styles for level ' . $level_id . "*/\n"; foreach($level_array as $array_type => $values){ if($array_type == 'properties' && count($values)){ continue; } $styles .= '.level' . $level_id . $array_type . '{'; foreach($values as $att_key => $att_value){ $styles .= $att_key . ':' . $att_value . '; '; } $styles .= "}\n"; } } //this is required by CoolMenu--don't change! $styles = "'; return $styles; } /** * Creates the JavaScript code which sets the background style for the entire menu * * @access private * @param array $options Array of menu style parameters, i.e. $options['menu']['background_style']. * @return string The CSS style for the menu background. */ function _buildBackgroundStyle($properties) { $background_style = "/*Background style*/\n.backgroundStyle{"; foreach($properties as $prop_key => $prop_val){ $background_style .= $prop_key . ':' . $prop_val . '; '; } $background_style .= "}\n"; return $background_style; } /** * Creates the JavaScript code which sets properties for each level defined. * * @access private * @param array $options Array of menu style and structure parameters. * @return string The JS defining each menu level, e.g. CMenu3.level[0].height=25... */ function _buildLevelProperties($options) { $level_properties = false; //loop once for each level defined foreach ($options['levels'] as $level_id => $level_array) { $level_properties .= "\n/*Level " . $level_id . " properties*/\n" . $this->_menuName . ".level[$level_id]=new cm_makeLevel()\n"; if(count($level_array['mouseout_style'])){ $level_properties .= $this->_menuName . '.level[' . $level_id . '].regClass="level' . $level_id . 'mouseout_style"' . "\n"; } if(count($level_array['mouseover_style'])){ $level_properties .= $this->_menuName . '.level[' . $level_id . '].overClass="level' . $level_id . 'mouseover_style"' . "\n"; } if(count($level_array['border_style'])){ $level_properties .= $this->_menuName . '.level[' . $level_id . '].borderClass="level' . $level_id . 'border_style"' . "\n"; } if(count($level_array['properties'])){ foreach($level_array['properties'] as $prop_key => $prop_val){ $level_properties .= $this->_menuName . ".level[$level_id].$prop_key=$prop_val\n"; } } } return $level_properties; } /** * Creates the JavaScript code which sets properties for each level defined. * * @access private * @param array $options Array of menu structure parameters ($options['menu']['properties']). * @return string The JS defining menu structure, e.g. CMenu3.zIndex=100... */ function _buildMenuProperties($properties) { foreach($properties as $prop_key => $prop_val){ $menu_properties .= $this->_menuName . ".$prop_key=$prop_val\n"; } $menu_properties .= $this->_menuName . ".barClass=\"backgroundStyle\"\n"; return "\n/*Menu properties*/\n$menu_properties\n"; } // }}} // {{{ printTree() /** * Print's the current tree using the output driver * * @access public * @param void * @return string The complete JS for the menu. */ function printTree() { if (!$options = $this->_getOptions('printTree')) { return PEAR::raiseError("CoolMenu::printTree() needs options. See CoolMenu::setOptions()", NESEO_ERROR_NO_OPTIONS, PEAR_ERROR_TRIGGER, E_USER_ERROR); } echo $this->_buildStyles($options); echo "\n\n"; } // }}} } ?>