One of the things that happened with Angry Donuts here is that while I was fiddling with the logo and stuff, someone popped into the IRC and started asking about how hard it would be to implement DHTML menus based on this script. The person went by Aw0L and I have no idea who that is, otherwise, but I did end up getting the script working, after giving it a pretty serious workover.
Since I’ve had a very bad week, and I needed something very interesting to distract myself, I grabbed it and started fiddling with it. The script, it turns out, implemented the one thing I truly wanted to see in this kind of thing: memory. These menus remember which menus were open and closed from page to page, by storing them in a cookie. Perfect, I thought.
Well, the script wasn’t exactly perfect, and hey, I know jack about javascript, but what the heck. Turns out that it had several problems. It only supported one layer of menus, and it automatically closed every other menu when you opened one. Right for the kind of menu it was doing, not quite right for the type of menu I wanted. Another was that the menus assume they’re pretty much static, in terms of how the memory works, and required that they be numbered sequentially. This is a problem if menus come and go. All of these problems were fixed.
Next, of course, was the issue of making Drupal menus work with this. These menus were set up in a div/span/div pattern, whereas Drupal’s menus are all ul tags. I figured I’d go the easy route first and themed Drupal’s menu functions to re-do the menus in the new format, fully intent to see if I could walk it backward once I was assured that I could have the menus the way I want. Well, that retrospect hasn’t happened yet, and it’s something that I started to do, but ran into a problem and didn’t have the drive to finish it.
There are two very interesting problems that came up. The first is that Drupal’s menu system does a bad thing, which is that parent menu items are also menu links in their own right. In a system where I’m overriding the click to open a collapsing menu, I no longer have that link. Now, some of the pages in the default Drupal system aren’t a big deal. create content, for example, just goes to a summary page. No big deal if it’s lost. administer just goes to the logs page, which isn’t even really a good page for it to go to. Good riddance to that. Sadly administer >> settings is a very important page, and is only minimally related to the pages beneath it. Likewise, if you turn on statistics, it puts all of its pages under administer >> log.
The solution there is that there is a hardcoded array of container links that it puts a fake menu entry in for, at the top of the container beneath it. This isn’t really ideal; and I didn’t turn on every module and see very option, so I actually only have it populated with the very minimal menu entries necessary for my setup. But it does the trick.
The other problem is that, because I’m overriding the menu themes, modules that imitate the menus don’t get the benefits unless they, too, get re-themed. The best example of this is book module. You may notice on Angry Donuts that the book navigation menu isn’t re-themed. I wasn’t sure if that was actually going to be the right choice for the book navigation, though I think it probably will be, and I will probably write the proper code to theme that block so that it duplicates my new menus. The question is whether or not I do it before I return it to the proper UL/LI setup. It’s vaguely possible that if I’m very clever, I won’t need to. If so, that’ll be another article.
Here is my template.php code:
/**
* DHTML menus
*/
// Manual process: Provide all menus that are both parent menus and have
// important content. This adds a pseudo menu item as the first item in
// the container, and lets you rename it too.
function _get_add_links() {
return array(
'admin/settings' => "system settings",
'admin/logs' => "watchdog",
);
}
function phptemplate_menu_item($mid, $children = '', $leaf = TRUE) {
if ($mid == menu_get_active_nontask_item()) {
$active = " active";
}
if ($leaf) {
return " <div class=\"leaf$active\">" . menu_item_link($mid) . "</div>\n";
}
else {
$menu = menu_get_menu();
$output = "<div class=\"menutitle collapsed\" id = \"menu-sub$mid\" " .
"onclick=\"SwitchMenu('sub$mid')\">" . $menu['items'][$mid]['title'] .
"</div>\n";
$output .= "<span class='submenu' id='sub$mid'>\n";
$add_links = _get_add_links();
if ($add_links[$menu['items'][$mid]['path']]) {
$output .= "<div class='leaf$active'>" . menu_item_link($mid) .
"</div>\n";
}
$output .= "$children\n</span>\n";
return $output;
}
}
function phptemplate_menu_item_link($item, $link_item) {
$add_links = _get_add_links();
$title = ($link_item['path'] && $add_links[$link_item['path']]
? $add_links[$link_item['path']] : $item['title']);
return l($title, $link_item['path'], isset($item['description'])
? array('title' => $item['description']) : array());
}
function phptemplate_menu_tree($pid = 1, $toplevel = true) {
$menu = menu_get_menu();
$output = '';
if (isset($menu['visible'][$pid]) && $menu['visible'][$pid]['children']) {
foreach ($menu['visible'][$pid]['children'] as $mid) {
$output .= theme('menu_item', $mid, theme('menu_tree', $mid, false),
count($menu['visible'][$mid]['children']) == 0);
}
}
if ($toplevel && $output) {
$output = "<div class='menu' id='masterdiv'>\n$output\n</div>";
drupal_add_js(drupal_get_path('theme', 'ad') . "/menus.js");
}
return $output;
}
And here is my style.css code:
/* For the DHTML menus */
.menutitle{
color: #600;
cursor:pointer;
font-weight: bold;
padding-left: 1em;
margin-top: 0.2em;
text-transform: capitalize;
}
.menu div.collapsed {
background: url(images/menu-collapsed.png) no-repeat center left;
}
.menu div.expanded {
background: url(images/menu-expanded.png) no-repeat center left;
}
.menu .submenu{
margin-left: .75em;
}
.menu div.leaf {
background: url(images/menu-leaf.png) no-repeat center left;
padding: 0.2em 0em 0 1em;
text-transform: capitalize;
}
.menu div.leaf a {
font-weight: normal;
}
.menu .active a.active {
color: #000;
font-weight: bold;
}
.menu .active a:after, .block a.active:after {
content: " >>";
}
.menu .active a:before, .block a.active:before {
content: "<< ";
}
/* end DHTML menus styles */
| Attachment | Size |
|---|---|
| menus.js.txt | 2.29 KB |


Errors in posting
Ok, there are three issues that need to be addressed. If you read this prior to the date on this comment, the PHP listed was wrong. The filter was eating all HTML tags out of it, so that had ugly ugly results. Thanks to killes for finding this!
Second, I didn't include the custom icons I use for arrows, which live in the theme. So copy menu-*.png from drupal/misc into your theme to get them to work (or figure out how to change the paths in the .CSS file. Your choice).
Finally, this was done before the base_url change in 4.7 HEAD, so the code will have to be modified to reflect that.
Post new comment