JSCookMenu module. Nice alternative to PHPLayers.
Posted: Thu Jul 14, 2005 1:56 pm
I want to give my accolades to a great CMS
I have looked at many other CMSs, and have found they require studying endless documentation and/or code before I have any hope of making extensions. Although I am an official N00b, I was easily able to make my own module for a menu system with CMSMS.
I origianally developed this module because I thought I was having problems with PHPLayers. It turns out PHPLayers was working fine, but it is still nice to have a good alternative to PHPLayers.
I have structured the module directory as follows
Here is the code. (Note the TODO items. Hopefully someone with more time can work on these)
If you want to get this working, don't forget to change the base path in theme.js to
Enjoy 

I origianally developed this module because I thought I was having problems with PHPLayers. It turns out PHPLayers was working fine, but it is still nice to have a good alternative to PHPLayers.
I have structured the module directory as follows
Code: Select all
/modules/JSCookMenu/JSCookMenu.module.php
/modules/JSCookMenu/JSCookMenu/JSCookMenu.js
/modules/JSCookMenu/JSCookMenu/themes (Place themes here)
/modules/JSCookMenu/JSCookMenu/themes/ThemeIE (A example theme director)
Code: Select all
<?php
#########################################################
#
# Module for JSCookMenu (www.cs.ucla.edu/~heng/JSCookMenu/)
#
# Author: Benjamin Carnes (bjcarnes at gmail dot com)
#
# License: Do whatever you want with this. Just don't violate
# the CMS Made Simple licences and leave my name in the credits.
#
# See http://forum.cmsmadesimple.org/index.php?topic=51
# for some good intro info on module development
#
# TODO: Implement theme parameter
# TODO: Support admin link in menu
#
#########################################################
class JSCookMenu extends CMSModule
{
function GetName()
{
return 'JSCookMenu';
}
function GetVersion()
{
return '.02';
}
function GetHelp($lang = 'en_US')
{
return "
<h3>What does this do?</h3>
<p>Prints a dhtml vertical or horizontal menu using the <a href=\"http://www.cs.ucla.edu/~heng/JSCookMenu/\">JSCookMenu (v1.31)</a>.</p>
<h3>How do I use it?</h3>
<p>Just insert the module into your template/page like: <code>{cms_module module='JSCookMenu'}</code></p>
<h3>What parameters does it take?</h3>
<p>
<ul>
<li><em>(optional)</em> <tt>theme</tt> - (ThemeIE, ThemeMiniBlack, ThemeOffice, ThemePanel), Theme for menu. Additional themes
may be added simply by creating a new one and placing it in the modules/JSCookMenu/JSCookMenu/themes/ directory. Default is ThemeIE.
THIS PARAMETER DOESN'T WORK YET.</li>
<li><em>(optional)</em> <tt>showadmin</tt> - 1/0, whether you want to show or not the admin link. Default is 0.</li>
<li><em>(optional)</em> <tt>start_element</tt> - the hierarchy of your element (ie : 1.2 or 3.5.1 for example). This parameter sets the root of the menu.</li>
<li><em>(optional)</em> <tt>number_of_levels</tt> - an integer, the number of levels you want to show in your menu.</li>
<li><em>(optional)</em> <tt>horizontal</tt> - 1/0, whether you want to have a horizontal menu instead of vertical. Default is 1 (horizontal).</li>
</ul>
</p>
";
}
function GetAuthor()
{
return 'Benjamin Carnes';
}
function GetAuthorEmail()
{
return 'bjcarnes at gmail dot com';
}
function GetChangeLog()
{
return "Introducing beta<br /><b>TODO:</b> Implement theme parameter<br /><b>TODO:</b> Support admin link in menu";
}
function IsPluginModule()
{
return true;
}
function ContentPreRender(&$content)
{
$config = $this->cms->config;
$text .= '<__script__ language="JavaScript" SRC="'.$config['root_url'].'/modules/JSCookMenu/JSCookMenu/JSCookMenu.js"></__script>
<__script__ language="JavaScript" SRC="'.$config['root_url'].'/modules/JSCookMenu/JSCookMenu/themes/ThemeIE/theme.js"></__script>';
$content = ereg_replace("<\/head>", $text."</head>", $content);
}
function ContentStylesheet(&$stylesheet)
{
$config = $this->cms->config;
@ob_start();
@readfile(dirname(__FILE__).'/JSCookMenu/themes/ThemeIE/theme.css');
$stylesheet = @ob_get_contents() . $stylesheet;
@ob_end_clean();
}
function DoAction($name, $id, $params)
{
$config = $this->cms->config;
if ($name == 'default')
{
$basedepth = 1;
$allcontent = ContentManager::GetAllContent(false);
# getting menu parameters
$showadmin = isset($params['showadmin']) ? $params['showadmin'] : 0 ;
$horizontal = isset($params['horizontal']) ? $params['horizontal'] : 0 ;
$menu = '';
#Reset the base depth if necessary...
if (isset($params['start_element']))
{
$basedepth = count(split('\.', (string)$params['start_element']));
}
$disabled = array();
$filteredcontent = array();
#Filter out content elements that are disabled or at the wrong level
foreach ($allcontent as $onecontent)
{
#Handy little trick to figure out how deep in the tree we are
#Remember, content comes to use in order of how it should be displayed in the tree already
$depth = count(split('\.', $onecontent->Hierarchy()));
#If hierarchy starts with the start_element (if it's set), then continue on
if (isset($params['start_element']))
{
if ((strpos($onecontent->Hierarchy(), (string)$params['start_element']) === FALSE) || (strpos($onecontent->Hierarchy(), (string)$params['start_element']) != 0))
{
continue;
}
}
#Now check to make sure we're not too many levels deep if number_of_levels is set
if (isset($params['number_of_levels']))
{
$number_of_levels = $params['number_of_levels'] - 1;
$base_level = 1;
#Is start_element set? If so, reset the base_level to it's level
if (isset($params['start_element']))
{
$base_level = count(split('\.', (string)$params['start_element']));
}
#If this element's level is more than base_level + number_of_levels, then scratch it
if ($base_level + $number_of_levels < $depth)
{
continue;
}
}
# Check for inactive items or items set not to show in the menu
if (!$onecontent->Active() || !$onecontent->ShowInMenu())
{
# Stuff the hierarchy position into that array, so we can test for
# children that shouldn't be showing. Put the dot on the end
# since it will only affect children anyway... saves from a
# .1 matching .11
array_push($disabled, $onecontent->Hierarchy() . ".");
continue;
}
$disableme = false;
# Loop through disabled array to see if this is a child that
# shouldn't be showing -- we check this by seeing if the current
# hierarhcy postition starts with one of the disabled positions
foreach ($disabled as $onepos)
{
# Why php doesn't have a starts_with function is beyond me...
if (strstr($onecontent->Hierarchy(), $onepos) == $onecontent->Hierarchy())
{
$disableme = true;
continue; # Break from THIS foreach
}
}
if ($disableme)
{
continue; # Break from main foreach
}
array_push($filteredcontent, $onecontent);
}
/*reset($filteredcontent);
foreach ($filteredcontent as $onecontent)
{
$menu .= $onecontent->Hierarchy()."\n";
}*/
# foreach ($filteredcontent as $onecontent)
# {
# $menu .= $onecontent->MenuText()."<br />";
# }
if (isset($params['horizontal']))
{
$this->WriteMenuJS($menu, $filteredcontent, $params['horizontal']);
}
else
{
$this->WriteMenuJS($menu, $filteredcontent, 1);
}
# if ($showadmin == 1)
# {
# $menu .= ".|---\n";
# $menu .= ".|Admin|".$config['admin_dir']."/\n";
# }
return $menu;
}
//Catch-all
return '';
}
function WriteMenuJS(&$menu, &$filteredcontent, $horizontal)
{
$config = $this->cms->config;
$menu .= "\n<div id=\"jscookmenuid\"></div>\n";
$menu .= "\n<script language=\"JavaScript\"><!--\n";
$menu .= "\nvar jscMenuArr = [";
reset($filteredcontent);
$this->WriteMenuJSRec($menu, $filteredcontent, 0);
$menu .= "];\n";
$menu .= "\ncmThemeIE.folderLeft = '';\n";
$menu .= "\ncmThemeIE.folderRight = '<img alt=\"\" src=\"".$config['root_url']."/modules/JSCookMenu/JSCookMenu/themes/ThemeIE/arrow.gif\" />';\n";
$menu .= "\ncmThemeIE.itemLeft = '';\n";
if ($horizontal)
{
$menu .= "\ncmDraw ('jscookmenuid', jscMenuArr, 'hbr', cmThemeIE, 'ThemeIE');\n";
}
else
{
$menu .= "\ncmDraw ('jscookmenuid', jscMenuArr, 'vbr', cmThemeIE, 'ThemeIE');\n";
}
$menu .= "--></__script>";
}
function WriteMenuJSRec(&$menu, &$filteredcontent, $recdepth)
{
#Safety check
$recdepth++;
if ($recdepth > 100)
{
#Uh-oh. There must be a bug. Stop to avoid exhausting the stack memory.
return;
}
while ($onecontent = current($filteredcontent))
{
if ($onecontent->Type() == 'separator')
{
$menu .= "_cmSplit";
}
else
{
$menu .= "[";
// if this is a section header, the URL is simple '#'
$menu .= "'', '".$onecontent->MenuText()."', '".$onecontent->GetURL()."', '_top', '".$onecontent->MenuText()."'";
}
$nextcontent = next($filteredcontent);
if ($nextcontent)
{
$currmenudepth = count(split('\.', $onecontent->Hierarchy()));
$nextmenudepth = count(split('\.', $nextcontent->Hierarchy()));
#if next content is deeper
if ($nextmenudepth > $currmenudepth)
{
$menu .= ", ";
//next($filteredcontent);
$result = $this->WriteMenuJSRec($menu, $filteredcontent, $recdepth);
$menu .= "]";
$onecontent = current($filteredcontent);
$nextcontent = next($filteredcontent);
if ($nextcontent)
{
$currmenudepth = count(split('\.', $onecontent->Hierarchy()));
$nextmenudepth = count(split('\.', $nextcontent->Hierarchy()));
#content is at same depth
if ($nextmenudepth == $currmenudepth)
{
$menu .= "], ";
}
else #next content is shallower
{
if ($result == 0)
{
$menu .= ", ";
}
else
{
prev($filteredcontent);
return $result - 1;
}
}
}
}
#else if next content is at same depth
elseif ($nextmenudepth == $currmenudepth)
{
if ($onecontent->Type() == 'separator')
{
$menu .= ", ";
}
else
{
$menu .= "], ";
}
}
else #next content is shallower
{
if ($onecontent->Type() != 'separator')
{
$menu .= "]";
}
prev($filteredcontent);
return $currmenudepth - $nextmenudepth - 1;
}
}
}
$menu .= "]";
return 0;
}
}
?>
Code: Select all
var cmThemeIEBase = '/modules/JSCookMenu/JSCookMenu/themes/ThemeIE/';
