| 1 |
<?php
|
| 2 |
// $Id: dhtml_menu.theme.inc,v 1.11 2009/10/25 14:27:48 arancaytar Exp $
|
| 3 |
|
| 4 |
|
| 5 |
/**
|
| 6 |
* @file dhtml_menu.theme.inc
|
| 7 |
* All functions related to generating the menu markup.
|
| 8 |
*/
|
| 9 |
|
| 10 |
/**
|
| 11 |
* Preprocessor for menu_item_link.
|
| 12 |
* Adds an ID attribute to menu links and helps the module
|
| 13 |
* follow the recursion of menu_tree_output().
|
| 14 |
*/
|
| 15 |
function dhtml_menu_theme_menu_item_link($link) {
|
| 16 |
global $theme;
|
| 17 |
$function = &drupal_static(__FUNCTION__);
|
| 18 |
$settings = variable_get('dhtml_menu_settings');
|
| 19 |
if (!isset($function)) {
|
| 20 |
$registry = variable_get('dhtml_menu_theme', array());
|
| 21 |
if (isset($registry[$theme]) && function_exists($registry[$theme]['menu_item_link'])) {
|
| 22 |
$function = $registry[$theme]['menu_item_link'];
|
| 23 |
}
|
| 24 |
else {
|
| 25 |
$function = 'theme_menu_item_link';
|
| 26 |
}
|
| 27 |
}
|
| 28 |
|
| 29 |
// Do not stack items that have no menu or mlid.
|
| 30 |
if (empty($link['menu_name']) || empty($link['mlid'])) {
|
| 31 |
return $function($link);
|
| 32 |
}
|
| 33 |
|
| 34 |
$extended_link = $link;
|
| 35 |
|
| 36 |
// If the menu is blacklisted or not whitelisted, mark the link as disabled for DHTML.
|
| 37 |
$extended_link['dhtml_disabled'] = ($settings['filter']['type'] == 'blacklist') == !empty($settings['filter']['list'][$link['menu_name']]);
|
| 38 |
|
| 39 |
// Add the ID attribute.
|
| 40 |
$extended_link = array_merge_recursive($extended_link, array('localized_options' => array('attributes' => array())));
|
| 41 |
$extended_link['localized_options']['attributes']['id'] = 'dhtml_menu-' . _dhtml_menu_unique_id($link['mlid']);
|
| 42 |
|
| 43 |
// Each link in series is another level of recursion. Add it to the stack, even if it is disabled.
|
| 44 |
_dhtml_menu_stack($extended_link);
|
| 45 |
|
| 46 |
// Pass the altered variables to the normal menu themer, but only if DHTML should be used.
|
| 47 |
return $function(!$extended_link['dhtml_disabled'] ? $extended_link : $link);
|
| 48 |
}
|
| 49 |
|
| 50 |
/**
|
| 51 |
* Preprocessor for menu_item.
|
| 52 |
* Checks whether the current item has children that
|
| 53 |
* were not rendered, and loads and renders them.
|
| 54 |
*/
|
| 55 |
function dhtml_menu_theme_menu_item($link, $has_children, $menu = '', $in_active_trail = FALSE, $extra_class = NULL) {
|
| 56 |
global $theme;
|
| 57 |
$cookie = &drupal_static(__FUNCTION__ . ':cookie', array());
|
| 58 |
$function = &drupal_static(__FUNCTION__ . ':function');
|
| 59 |
|
| 60 |
if (empty($function)) {
|
| 61 |
$settings = variable_get('dhtml_menu_settings');
|
| 62 |
if ($settings['effects']['remember'] && $settings['nav'] != 'open' && $settings['effects']['siblings'] != 'close-all') {
|
| 63 |
$cookie = explode(',', @$_COOKIE['dhtml_menu']);
|
| 64 |
}
|
| 65 |
$registry = variable_get('dhtml_menu_theme', array());
|
| 66 |
if (isset($registry[$theme]) && function_exists($registry[$theme]['menu_item'])) {
|
| 67 |
$function = $registry[$theme]['menu_item'];
|
| 68 |
}
|
| 69 |
else {
|
| 70 |
$function = 'theme_menu_item';
|
| 71 |
}
|
| 72 |
}
|
| 73 |
|
| 74 |
/* When theme('menu_item') is called, the menu tree below it has been
|
| 75 |
* rendered already. Since we are done on this recursion level,
|
| 76 |
* one element must be popped off the stack.
|
| 77 |
*/
|
| 78 |
$item = _dhtml_menu_stack();
|
| 79 |
|
| 80 |
// If this item should not have DHTML, then return to the "parent" function.
|
| 81 |
if (!$item || !empty($item['dhtml_disabled'])) {
|
| 82 |
return $function($link, $has_children, $menu, $in_active_trail, $extra_class);
|
| 83 |
}
|
| 84 |
|
| 85 |
$extra_class .= ' dhtml-menu ';
|
| 86 |
|
| 87 |
// If there are children, but they were not loaded...
|
| 88 |
if ($has_children && !$menu) {
|
| 89 |
// Load the tree below the current position.
|
| 90 |
$tree = _dhtml_menu_subtree($item);
|
| 91 |
|
| 92 |
// Render it...
|
| 93 |
$menu = menu_tree_output($tree);
|
| 94 |
|
| 95 |
// Sanitize the tree - uncheck has_children if no children were loaded.
|
| 96 |
if (!$menu) {
|
| 97 |
$has_children = FALSE;
|
| 98 |
}
|
| 99 |
}
|
| 100 |
|
| 101 |
// If the current item can expand, and is neither saved as open nor in the active trail, close it.
|
| 102 |
if ($menu && !($in_active_trail || in_array($item['localized_options']['attributes']['id'], $cookie))) {
|
| 103 |
$extra_class .= ' collapsed start-collapsed ';
|
| 104 |
}
|
| 105 |
|
| 106 |
// Cascade up to the original theming function.
|
| 107 |
return $function($link, $has_children, $menu, $in_active_trail, $extra_class);
|
| 108 |
}
|
| 109 |
|
| 110 |
/**
|
| 111 |
* Helper function for storing recursion levels.
|
| 112 |
*
|
| 113 |
* @param $link
|
| 114 |
* If a menu item link is passed, it will be pushed onto the stack.
|
| 115 |
* Otherwise, one element will be popped off the stack.
|
| 116 |
*
|
| 117 |
* @return
|
| 118 |
* The last element of the stack, if no argument is passed.
|
| 119 |
*/
|
| 120 |
function _dhtml_menu_stack($link = FALSE) {
|
| 121 |
static $stack = array();
|
| 122 |
if ($link) {
|
| 123 |
$stack[] = $link;
|
| 124 |
}
|
| 125 |
else {
|
| 126 |
return array_pop($stack);
|
| 127 |
}
|
| 128 |
}
|
| 129 |
|
| 130 |
/**
|
| 131 |
* Traverses the menu tree and returns the sub-tree of the item
|
| 132 |
* indicated by the parameter.
|
| 133 |
*
|
| 134 |
* @param $item
|
| 135 |
* A menu item link that must contain the keys "mlid" and "menu_name".
|
| 136 |
*
|
| 137 |
* @return
|
| 138 |
* The tree below the menu item, or an empty array.
|
| 139 |
*/
|
| 140 |
function _dhtml_menu_subtree($item) {
|
| 141 |
static $index = array();
|
| 142 |
static $indexed = array();
|
| 143 |
|
| 144 |
// This looks expensive, but menu_tree_all_data uses static caching.
|
| 145 |
$tree = menu_tree_all_data($item['menu_name']);
|
| 146 |
|
| 147 |
// Index the menu tree to find ancestor paths for each item.
|
| 148 |
if (!isset($indexed[$item['menu_name']])) {
|
| 149 |
$index += _dhtml_menu_index($tree);
|
| 150 |
$indexed[$item['menu_name']] = TRUE;
|
| 151 |
}
|
| 152 |
|
| 153 |
// If the menu tree does not contain this item, stop.
|
| 154 |
if (!isset($index[$item['mlid']])) {
|
| 155 |
return array();
|
| 156 |
}
|
| 157 |
|
| 158 |
// Traverse the tree using the ancestor path.
|
| 159 |
foreach ($index[$item['mlid']]['parents'] as $mlid) {
|
| 160 |
$key = $index[$mlid]['key'];
|
| 161 |
if (isset($tree[$key])) {
|
| 162 |
$tree = $tree[$key]['below'];
|
| 163 |
}
|
| 164 |
else {
|
| 165 |
return array();
|
| 166 |
}
|
| 167 |
}
|
| 168 |
|
| 169 |
// Go one level further to go below the current item.
|
| 170 |
$key = $index[$item['mlid']]['key'];
|
| 171 |
return isset($tree[$key]) ? $tree[$key]['below'] : array();
|
| 172 |
}
|
| 173 |
|
| 174 |
/**
|
| 175 |
* Indexes the menu tree by mlid. This is needed to identify the items
|
| 176 |
* without relying on titles or stacks. This function is recursive.
|
| 177 |
*
|
| 178 |
* @param $tree
|
| 179 |
* A tree of menu items such as the return value of menu_tree_all_data().
|
| 180 |
* @param $ancestors
|
| 181 |
* Optional, used only by internal recursion.
|
| 182 |
* @param $parent
|
| 183 |
* Optional, used only by internal recursion.
|
| 184 |
*
|
| 185 |
* @return
|
| 186 |
* An array associating mlid values with the internal keys of the menu tree,
|
| 187 |
* and all the mlids of the item's ancestors.
|
| 188 |
*/
|
| 189 |
function _dhtml_menu_index($tree, $ancestors = array(), $parent = NULL) {
|
| 190 |
$index = array();
|
| 191 |
if ($parent) {
|
| 192 |
$ancestors[] = $parent;
|
| 193 |
}
|
| 194 |
|
| 195 |
foreach ($tree as $key => $item) {
|
| 196 |
$index[$item['link']['mlid']] = array(
|
| 197 |
'key' => $key,
|
| 198 |
'parents' => $ancestors,
|
| 199 |
);
|
| 200 |
if (!empty($item['below'])) {
|
| 201 |
$index += _dhtml_menu_index($item['below'], $ancestors, $item['link']['mlid']);
|
| 202 |
}
|
| 203 |
}
|
| 204 |
return $index;
|
| 205 |
}
|
| 206 |
|
| 207 |
/**
|
| 208 |
* Keeps track of ID attributes and adds a suffix to make it unique-when necessary.
|
| 209 |
*/
|
| 210 |
function _dhtml_menu_unique_id($id) {
|
| 211 |
static $ids = array();
|
| 212 |
if (!isset($ids[$id])) {
|
| 213 |
$ids[$id] = 1;
|
| 214 |
return $id;
|
| 215 |
}
|
| 216 |
else {
|
| 217 |
return $id . '-' . $ids[$id]++;
|
| 218 |
}
|
| 219 |
}
|
| 220 |
|