751 lines
25 KiB
Plaintext
751 lines
25 KiB
Plaintext
<?php
|
|
/**
|
|
* @file
|
|
* Provides configurable blocks of menu items.
|
|
*/
|
|
|
|
/**
|
|
* Denotes that the tree should use the menu picked by the curent page.
|
|
*/
|
|
define('MENU_TREE__CURRENT_PAGE_MENU', '_active');
|
|
|
|
// Off-load the following infrequently called hooks to another file.
|
|
function menu_block_theme(&$existing, $type, $theme, $path) {
|
|
module_load_include('inc', 'menu_block', 'menu_block.admin');
|
|
return _menu_block_theme($existing, $type, $theme, $path);
|
|
}
|
|
function menu_block_block_info() {
|
|
module_load_include('inc', 'menu_block', 'menu_block.admin');
|
|
return _menu_block_block_info();
|
|
}
|
|
function menu_block_block_configure($delta = '') {
|
|
module_load_include('inc', 'menu_block', 'menu_block.admin');
|
|
return _menu_block_block_configure($delta);
|
|
}
|
|
function menu_block_block_save($delta = '', $edit = array()) {
|
|
module_load_include('inc', 'menu_block', 'menu_block.admin');
|
|
return _menu_block_block_save($delta, $edit);
|
|
}
|
|
function menu_block_form_block_admin_display_form_alter(&$form, $form_state) {
|
|
module_load_include('inc', 'menu_block', 'menu_block.admin');
|
|
return _menu_block_form_block_admin_display_form_alter($form, $form_state);
|
|
}
|
|
function menu_block_ctools_plugin_directory($module, $plugin) {
|
|
module_load_include('inc', 'menu_block', 'menu_block.admin');
|
|
return _menu_block_ctools_plugin_directory($module, $plugin);
|
|
}
|
|
|
|
/**
|
|
* Implements hook_menu().
|
|
*/
|
|
function menu_block_menu() {
|
|
// @todo Remove this check if block module is re-added as a dependency.
|
|
if (module_exists('block')) {
|
|
$items['admin/structure/block/add-menu-block'] = array(
|
|
'title' => 'Add menu block',
|
|
'description' => 'Add a new menu block.',
|
|
'page callback' => 'drupal_get_form',
|
|
'page arguments' => array('menu_block_add_block_form'),
|
|
'access arguments' => array('administer blocks'),
|
|
'type' => MENU_LOCAL_ACTION,
|
|
'file' => 'menu_block.admin.inc',
|
|
);
|
|
$default_theme = variable_get('theme_default', 'bartik');
|
|
foreach (list_themes() as $key => $theme) {
|
|
if ($key != $default_theme) {
|
|
$items['admin/structure/block/list/' . $key . '/add-menu-block'] = array(
|
|
'title' => 'Add menu block',
|
|
'description' => 'Add a new menu block.',
|
|
'page callback' => 'drupal_get_form',
|
|
'page arguments' => array('menu_block_add_block_form'),
|
|
'access arguments' => array('administer blocks'),
|
|
'type' => MENU_LOCAL_ACTION,
|
|
'file' => 'menu_block.admin.inc',
|
|
);
|
|
}
|
|
}
|
|
$items['admin/structure/block/delete-menu-block'] = array(
|
|
'title' => 'Delete menu block',
|
|
'page callback' => 'drupal_get_form',
|
|
'page arguments' => array('menu_block_delete'),
|
|
'access arguments' => array('administer blocks'),
|
|
'type' => MENU_CALLBACK,
|
|
'file' => 'menu_block.admin.inc',
|
|
);
|
|
}
|
|
|
|
$items['admin/config/user-interface/menu-block'] = array(
|
|
'title' => 'Menu block',
|
|
'description' => 'Configure menu block.',
|
|
'page callback' => 'drupal_get_form',
|
|
'page arguments' => array('menu_block_admin_settings_form'),
|
|
'access arguments' => array('administer blocks'),
|
|
'type' => MENU_NORMAL_ITEM,
|
|
'file' => 'menu_block.admin.inc',
|
|
);
|
|
return $items;
|
|
}
|
|
|
|
/**
|
|
* Implements hook_menu_alter().
|
|
*/
|
|
function menu_block_menu_alter(&$items) {
|
|
// Fake the necessary menu attributes necessary for a contextual link.
|
|
$items['admin/content/book/%node']['title'] = 'Edit book outline';
|
|
$items['admin/content/book/%node']['type'] = MENU_LOCAL_TASK;
|
|
$items['admin/content/book/%node']['context'] = (MENU_CONTEXT_PAGE | MENU_CONTEXT_INLINE);
|
|
$items['admin/content/book/%node']['tab_root'] = 'admin/content/book';
|
|
}
|
|
|
|
/**
|
|
* Implements hook_help().
|
|
*/
|
|
function menu_block_help($path, $arg) {
|
|
switch ($path) {
|
|
case 'admin/structure/block/manage/%/%':
|
|
if ($arg[4] != 'menu_block') {
|
|
break;
|
|
}
|
|
case 'admin/help#menu_block':
|
|
case 'admin/structure/block/add-menu-block':
|
|
module_load_include('inc', 'menu_block', 'menu_block.pages');
|
|
return _menu_block_help($path, $arg);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Implements hook_block_view().
|
|
*/
|
|
function menu_block_block_view($delta = '') {
|
|
$config = menu_block_get_config($delta);
|
|
$data = menu_tree_build($config);
|
|
// Add contextual links for this block.
|
|
if (!empty($data['content'])) {
|
|
if (in_array($config['menu_name'], array_keys(menu_get_menus()))) {
|
|
$data['content']['#contextual_links']['menu_block'] = array('admin/structure/menu/manage', array($config['menu_name']));
|
|
}
|
|
elseif (strpos($config['menu_name'], 'book-toc-') === 0) {
|
|
$node = str_replace('book-toc-', '', $config['menu_name']);
|
|
$data['content']['#contextual_links']['menu_block'] = array('admin/content/book', array($node));
|
|
}
|
|
}
|
|
return $data;
|
|
}
|
|
|
|
/**
|
|
* Process variables for menu-block-wrapper.tpl.php.
|
|
*
|
|
* @see menu-block-wrapper.tpl.php
|
|
*/
|
|
function template_preprocess_menu_block_wrapper(&$variables) {
|
|
$variables['classes_array'][] = 'menu-block-' . $variables['delta'];
|
|
$variables['classes_array'][] = 'menu-name-' . $variables['config']['menu_name'];
|
|
$variables['classes_array'][] = 'parent-mlid-' . $variables['config']['parent_mlid'];
|
|
$variables['classes_array'][] = 'menu-level-' . $variables['config']['level'];
|
|
}
|
|
|
|
/**
|
|
* Returns a list of menu names implemented by all modules.
|
|
*
|
|
* @return
|
|
* array A list of menu names and titles.
|
|
*/
|
|
function menu_block_get_all_menus() {
|
|
$all_menus = &drupal_static(__FUNCTION__);
|
|
|
|
if (!$all_menus) {
|
|
if ($cached = cache_get('menu_block_menus', 'cache_menu')) {
|
|
$all_menus = $cached->data;
|
|
}
|
|
else {
|
|
// Retrieve core's menus.
|
|
$all_menus = menu_get_menus();
|
|
// Retrieve all the menu names provided by hook_menu_block_get_menus().
|
|
$all_menus = array_merge($all_menus, module_invoke_all('menu_block_get_menus'));
|
|
// Add an option to use the menu for the active menu item.
|
|
$all_menus[MENU_TREE__CURRENT_PAGE_MENU] = '<' . t('the menu selected by the page') . '>';
|
|
asort($all_menus);
|
|
cache_set('menu_block_menus', $all_menus, 'cache_menu');
|
|
}
|
|
}
|
|
return $all_menus;
|
|
}
|
|
|
|
/**
|
|
* Returns the configuration for the requested block delta.
|
|
*
|
|
* @param $delta
|
|
* string The delta that uniquely identifies the block in the block system. If
|
|
* not specified, the default configuration will be returned.
|
|
* @return
|
|
* array An associated array of configuration options.
|
|
*/
|
|
function menu_block_get_config($delta = NULL) {
|
|
$config = array(
|
|
'delta' => $delta,
|
|
'menu_name' => 'main-menu',
|
|
'parent_mlid' => 0,
|
|
'title_link' => 0,
|
|
'admin_title' => '',
|
|
'level' => 1,
|
|
'follow' => 0,
|
|
'depth' => 0,
|
|
'expanded' => 0,
|
|
'sort' => 0,
|
|
);
|
|
|
|
// Get the block configuration options.
|
|
if ($delta) {
|
|
static $blocks;
|
|
if (!isset($blocks)) {
|
|
$blocks = module_invoke_all('menu_block_blocks');
|
|
}
|
|
if (!empty($blocks[$delta])) {
|
|
// Merge the default values.
|
|
$config = $blocks[$delta] + $config;
|
|
// Set the delta.
|
|
$config['delta'] = $delta;
|
|
// Flag the block as exported.
|
|
$config['exported_to_code'] = TRUE;
|
|
}
|
|
|
|
$config['title_link'] = variable_get("menu_block_{$delta}_title_link", $config['title_link']);
|
|
$config['admin_title'] = variable_get("menu_block_{$delta}_admin_title", $config['admin_title']);
|
|
$config['level'] = variable_get("menu_block_{$delta}_level", $config['level']);
|
|
$config['follow'] = variable_get("menu_block_{$delta}_follow", $config['follow']);
|
|
$config['depth'] = variable_get("menu_block_{$delta}_depth", $config['depth']);
|
|
$config['expanded'] = variable_get("menu_block_{$delta}_expanded", $config['expanded']);
|
|
$config['sort'] = variable_get("menu_block_{$delta}_sort", $config['sort']);
|
|
list($config['menu_name'], $config['parent_mlid']) = explode(':', variable_get("menu_block_{$delta}_parent", $config['menu_name'] . ':' . $config['parent_mlid']));
|
|
}
|
|
|
|
return $config;
|
|
}
|
|
|
|
/**
|
|
* Build a menu tree based on the provided configuration.
|
|
*
|
|
* @param $config
|
|
* array An array of configuration options that specifies how to build the
|
|
* menu tree and its title.
|
|
* - delta: (string) The menu_block's block delta.
|
|
* - menu_name: (string) The machine name of the requested menu. Can also be
|
|
* set to MENU_TREE__CURRENT_PAGE_MENU to use the menu selected by the page.
|
|
* - parent_mlid: (int) The mlid of the item that should root the tree. Use 0
|
|
* to use the menu's root.
|
|
* - title_link: (boolean) Specifies if the title should be rendered as a link
|
|
* or a simple string.
|
|
* - admin_title: (string) An optional title to uniquely identify the block on
|
|
* the administer blocks page.
|
|
* - level: (int) The starting level of the tree.
|
|
* - follow: (string) Specifies if the starting level should follow the
|
|
* active menu item. Should be set to 0, 'active' or 'child'.
|
|
* - depth: (int) The maximum depth the tree should contain, relative to the
|
|
* starting level.
|
|
* - expanded: (boolean) Specifies if the entire tree be expanded or not.
|
|
* - sort: (boolean) Specifies if the tree should be sorted with the active
|
|
* trail at the top of the tree.
|
|
* @return
|
|
* array An associative array containing several pieces of data.
|
|
* - content: The tree as a renderable array.
|
|
* - subject: The title rendered as HTML.
|
|
* - subject_array: The title as a renderable array.
|
|
*/
|
|
function menu_tree_build($config) {
|
|
// Retrieve the active menu item from the database.
|
|
if ($config['menu_name'] == MENU_TREE__CURRENT_PAGE_MENU) {
|
|
// Retrieve the list of available menus.
|
|
$menu_order = variable_get('menu_block_menu_order', array('main-menu' => '', 'user-menu' => ''));
|
|
|
|
// Check for regular expressions as menu keys.
|
|
$patterns = array();
|
|
foreach (array_keys($menu_order) as $pattern) {
|
|
if ($pattern[0] == '/') {
|
|
$patterns[$pattern] = NULL;
|
|
}
|
|
}
|
|
|
|
// Extract the "current" path from the request, or from the active menu
|
|
// trail if applicable.
|
|
$link_path = $_GET['q'] ? $_GET['q'] : '<front>';
|
|
$trail = menu_get_active_trail();
|
|
$last_item = end($trail);
|
|
if (!empty($last_item['link_path'])) {
|
|
$link_path = $last_item['link_path'];
|
|
}
|
|
|
|
// Retrieve all the menus containing a link to the current page.
|
|
$result = db_query("SELECT menu_name FROM {menu_links} WHERE link_path = :link_path", array(':link_path' => $link_path));
|
|
foreach ($result as $item) {
|
|
// Check if the menu is in the list of available menus.
|
|
if (isset($menu_order[$item->menu_name])) {
|
|
// Mark the menu.
|
|
$menu_order[$item->menu_name] = MENU_TREE__CURRENT_PAGE_MENU;
|
|
}
|
|
else {
|
|
// Check if the menu matches one of the available patterns.
|
|
foreach (array_keys($patterns) as $pattern) {
|
|
if (preg_match($pattern, $item->menu_name)) {
|
|
// Mark the menu.
|
|
$menu_order[$pattern] = MENU_TREE__CURRENT_PAGE_MENU;
|
|
// Store the actual menu name.
|
|
$patterns[$pattern] = $item->menu_name;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// Find the first marked menu.
|
|
$config['menu_name'] = array_search(MENU_TREE__CURRENT_PAGE_MENU, $menu_order);
|
|
// If a pattern was matched, use the actual menu name instead of the pattern.
|
|
if (!empty($patterns[$config['menu_name']])) {
|
|
$config['menu_name'] = $patterns[$config['menu_name']];
|
|
}
|
|
$config['parent_mlid'] = 0;
|
|
|
|
// If no menu link was found, don't display the block.
|
|
if (empty($config['menu_name'])) {
|
|
return array(
|
|
'subject' => t('The menu selected by the page'),
|
|
'subject_array' => array(),
|
|
'content' => array(),
|
|
);
|
|
}
|
|
}
|
|
|
|
// Get the default block name.
|
|
$menu_names = menu_block_get_all_menus();
|
|
menu_block_set_title(t($menu_names[$config['menu_name']]));
|
|
|
|
if ($config['expanded'] || $config['parent_mlid']) {
|
|
// Get the full, un-pruned tree.
|
|
$tree = menu_tree_all_data($config['menu_name']);
|
|
// And add the active trail data back to the full tree.
|
|
menu_tree_add_active_path($tree);
|
|
}
|
|
else {
|
|
// Get the tree pruned for just the active trail.
|
|
$tree = menu_tree_page_data($config['menu_name']);
|
|
}
|
|
|
|
// Allow alteration of the tree and config before we begin operations on it.
|
|
drupal_alter('menu_block_tree', $tree, $config);
|
|
|
|
// Localize the tree.
|
|
if (module_exists('i18n_menu')) {
|
|
$tree = i18n_menu_localize_tree($tree);
|
|
}
|
|
|
|
// Prune the tree along the active trail to the specified level.
|
|
if ($config['level'] > 1 || $config['parent_mlid']) {
|
|
if ($config['parent_mlid']) {
|
|
$parent_item = menu_link_load($config['parent_mlid']);
|
|
menu_tree_prune_tree($tree, $config['level'], $parent_item);
|
|
}
|
|
else {
|
|
menu_tree_prune_tree($tree, $config['level']);
|
|
}
|
|
}
|
|
|
|
// Prune the tree to the active menu item.
|
|
if ($config['follow']) {
|
|
menu_tree_prune_active_tree($tree, $config['follow']);
|
|
}
|
|
|
|
// If the menu-item-based tree is not "expanded", trim the tree to the active path.
|
|
if ($config['parent_mlid'] && !$config['expanded']) {
|
|
menu_tree_trim_active_path($tree);
|
|
}
|
|
|
|
// Trim the branches that extend beyond the specified depth.
|
|
if ($config['depth'] > 0) {
|
|
menu_tree_depth_trim($tree, $config['depth']);
|
|
}
|
|
|
|
// Sort the active path to the top of the tree.
|
|
if ($config['sort']) {
|
|
menu_tree_sort_active_path($tree);
|
|
}
|
|
|
|
// Render the tree.
|
|
$data = array();
|
|
$title = menu_block_get_title($config['title_link'], $config);
|
|
$data['subject_array'] = $title;
|
|
$data['subject'] = drupal_render($title);
|
|
$data['content']['#content'] = menu_block_tree_output($tree, $config);
|
|
if (!empty($data['content']['#content'])) {
|
|
$data['content']['#theme'] = array(
|
|
'menu_block_wrapper__' . str_replace('-', '_', $config['delta']),
|
|
'menu_block_wrapper__' . str_replace('-', '_', $config['menu_name']),
|
|
'menu_block_wrapper'
|
|
);
|
|
$data['content']['#config'] = $config;
|
|
$data['content']['#delta'] = $config['delta'];
|
|
}
|
|
else {
|
|
$data['content'] = '';
|
|
}
|
|
|
|
return $data;
|
|
}
|
|
|
|
/**
|
|
* Retrieves the menu item to use for the tree's title.
|
|
*
|
|
* @param $render_title_as_link
|
|
* boolean A boolean that says whether to render the title as a link or a
|
|
* simple string.
|
|
* @return
|
|
* array A renderable array containing the tree's title.
|
|
*/
|
|
function menu_block_get_title($render_title_as_link = TRUE) {
|
|
$menu_item = menu_block_set_title();
|
|
|
|
// The tree's title is a menu title, a normal string.
|
|
if (is_string($menu_item)) {
|
|
$title = array('#markup' => check_plain($menu_item));
|
|
}
|
|
// The tree's title is a menu item with a link.
|
|
elseif ($render_title_as_link) {
|
|
if (!empty($menu_item['in_active_trail'])) {
|
|
if (!empty($menu_item['localized_options']['attributes']['class'])) {
|
|
$menu_item['localized_options']['attributes']['class'][] = 'active-trail';
|
|
}
|
|
else {
|
|
$menu_item['localized_options']['attributes']['class'][] = 'active-trail';
|
|
}
|
|
}
|
|
$title = array(
|
|
'#type' => 'link',
|
|
'#title' => $menu_item['title'],
|
|
'#href' => $menu_item['href'],
|
|
'#options' => $menu_item['localized_options'],
|
|
);
|
|
}
|
|
// The tree's title is a menu item.
|
|
else {
|
|
$title = array('#markup' => check_plain($menu_item['title']));
|
|
}
|
|
return $title;
|
|
}
|
|
|
|
/**
|
|
* Sets the menu item to use for the tree's title.
|
|
*
|
|
* @param $item
|
|
* array The menu item (an array) or the menu item's title as a string.
|
|
*/
|
|
function menu_block_set_title($item = NULL) {
|
|
$menu_item = &drupal_static(__FUNCTION__);
|
|
|
|
// Save the menu item.
|
|
if (!is_null($item)) {
|
|
$menu_item = $item;
|
|
}
|
|
|
|
return $menu_item;
|
|
}
|
|
|
|
/**
|
|
* Add the active trail indicators into the tree.
|
|
*
|
|
* The data returned by menu_tree_page_data() has link['in_active_trail'] set to
|
|
* TRUE for each menu item in the active trail. The data returned from
|
|
* menu_tree_all_data() does not contain the active trail indicators. This is a
|
|
* helper function that adds it back in.
|
|
*
|
|
* @param $tree
|
|
* array The menu tree.
|
|
* @return
|
|
* void
|
|
*/
|
|
function menu_tree_add_active_path(&$tree) {
|
|
// Grab any menu item to find the menu_name for this tree.
|
|
$menu_item = current($tree);
|
|
$tree_with_trail = menu_tree_page_data($menu_item['link']['menu_name']);
|
|
|
|
// To traverse the original tree down the active trail, we use a pointer.
|
|
$subtree_pointer =& $tree;
|
|
|
|
// Find each key in the active trail.
|
|
while ($tree_with_trail) {
|
|
foreach ($tree_with_trail AS $key => &$value) {
|
|
if ($tree_with_trail[$key]['link']['in_active_trail']) {
|
|
// Set the active trail info in the original tree.
|
|
$subtree_pointer[$key]['link']['in_active_trail'] = TRUE;
|
|
// Continue in the subtree, if it exists.
|
|
$tree_with_trail =& $tree_with_trail[$key]['below'];
|
|
$subtree_pointer =& $subtree_pointer[$key]['below'];
|
|
break;
|
|
}
|
|
else {
|
|
unset($tree_with_trail[$key]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Trim everything but the active trail in the tree.
|
|
*
|
|
* @param $tree
|
|
* array The menu tree to trim.
|
|
* @return
|
|
* void
|
|
*/
|
|
function menu_tree_trim_active_path(&$tree) {
|
|
foreach ($tree AS $key => &$value) {
|
|
if (($tree[$key]['link']['in_active_trail'] || $tree[$key]['link']['expanded']) && $tree[$key]['below']) {
|
|
// Continue in the subtree, if it exists.
|
|
menu_tree_trim_active_path($tree[$key]['below']);
|
|
}
|
|
else {
|
|
// Trim anything not expanded or along the active trail.
|
|
$tree[$key]['below'] = FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Sort the active trail to the top of the tree.
|
|
*
|
|
* @param $tree
|
|
* array The menu tree to sort.
|
|
* @return
|
|
* void
|
|
*/
|
|
function menu_tree_sort_active_path(&$tree) {
|
|
module_load_include('inc', 'menu_block', 'menu_block.sort');
|
|
_menu_tree_sort_active_path($tree);
|
|
}
|
|
|
|
/**
|
|
* Prune a tree so that it begins at the specified level.
|
|
*
|
|
* This function will follow the active menu trail to the specified level.
|
|
*
|
|
* @param $tree
|
|
* array The menu tree to prune.
|
|
* @param $level
|
|
* int The level of the original tree that will start the pruned tree.
|
|
* @param $parent_item
|
|
* array The menu item that should be used as the root of the tree.
|
|
* @return
|
|
* void
|
|
*/
|
|
function menu_tree_prune_tree(&$tree, $level, $parent_item = FALSE) {
|
|
if (!empty($parent_item)) {
|
|
// Prune the tree along the path to the menu item.
|
|
for ($i = 1; $i <= MENU_MAX_DEPTH && $parent_item["p$i"] != '0'; $i++) {
|
|
$plid = $parent_item["p$i"];
|
|
$found_active_trail = FALSE;
|
|
// Examine each element at this level for the ancestor.
|
|
foreach ($tree AS $key => &$value) {
|
|
if ($tree[$key]['link']['mlid'] == $plid) {
|
|
menu_block_set_title($tree[$key]['link']);
|
|
// Prune the tree to the children of this ancestor.
|
|
$tree = $tree[$key]['below'] ? $tree[$key]['below'] : array();
|
|
$found_active_trail = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
// If we don't find the ancestor, bail out.
|
|
if (!$found_active_trail) {
|
|
$tree = array();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Trim the upper levels down to the one desired.
|
|
for ($i = 1; $i < $level; $i++) {
|
|
$found_active_trail = FALSE;
|
|
// Examine each element at this level for the active trail.
|
|
foreach ($tree AS $key => &$value) {
|
|
if ($tree[$key]['link']['in_active_trail']) {
|
|
// Get the title for the pruned tree.
|
|
menu_block_set_title($tree[$key]['link']);
|
|
// Prune the tree to the children of the item in the active trail.
|
|
$tree = $tree[$key]['below'] ? $tree[$key]['below'] : array();
|
|
$found_active_trail = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
// If we don't find the active trail, the active item isn't in the tree we want.
|
|
if (!$found_active_trail) {
|
|
$tree = array();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Prune a tree so that it begins at the active menu item.
|
|
*
|
|
* @param $tree
|
|
* array The menu tree to prune.
|
|
* @param $level
|
|
* string The level which the tree will be pruned to: 'active' or 'child'.
|
|
* @return
|
|
* void
|
|
*/
|
|
function menu_tree_prune_active_tree(&$tree, $level) {
|
|
module_load_include('inc', 'menu_block', 'menu_block.follow');
|
|
_menu_tree_prune_active_tree($tree, $level);
|
|
}
|
|
|
|
/**
|
|
* Prune a tree so it does not extend beyond the specified depth limit.
|
|
*
|
|
* @param $tree
|
|
* array The menu tree to prune.
|
|
* @param $depth_limit
|
|
* int The maximum depth of the returned tree; must be a positive integer.
|
|
* @return
|
|
* void
|
|
*/
|
|
function menu_tree_depth_trim(&$tree, $depth_limit) {
|
|
// Prevent invalid input from returning a trimmed tree.
|
|
if ($depth_limit < 1) {
|
|
return;
|
|
}
|
|
|
|
// Examine each element at this level to find any possible children.
|
|
foreach ($tree AS $key => &$value) {
|
|
if ($tree[$key]['below']) {
|
|
if ($depth_limit > 1) {
|
|
menu_tree_depth_trim($tree[$key]['below'], $depth_limit-1);
|
|
}
|
|
else {
|
|
// Remove the children items.
|
|
$tree[$key]['below'] = FALSE;
|
|
}
|
|
}
|
|
if ($depth_limit == 1 && $tree[$key]['link']['has_children']) {
|
|
// Turn off the menu styling that shows there were children.
|
|
$tree[$key]['link']['has_children'] = FALSE;
|
|
$tree[$key]['link']['leaf_has_children'] = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns a rendered menu tree.
|
|
*
|
|
* This is a copy of menu_tree_output() with additional classes added to the
|
|
* output.
|
|
*
|
|
* @param $tree
|
|
* array A data structure representing the tree as returned from menu_tree_data.
|
|
* @return
|
|
* string The rendered HTML of that data structure.
|
|
*/
|
|
function menu_block_tree_output(&$tree, $config = array()) {
|
|
$build = array();
|
|
$items = array();
|
|
|
|
// Create context if no config was provided.
|
|
if (empty($config)) {
|
|
$config['delta'] = 0;
|
|
// Grab any menu item to find the menu_name for this tree.
|
|
$menu_item = current($tree);
|
|
$config['menu_name'] = $menu_item['link']['menu_name'];
|
|
}
|
|
$hook_delta = str_replace('-', '_', $config['delta']);
|
|
$hook_menu_name = str_replace('-', '_', $config['menu_name']);
|
|
|
|
// Pull out just the menu items we are going to render so that we
|
|
// get an accurate count for the first/last classes.
|
|
foreach ($tree as $key => &$value) {
|
|
if (!$tree[$key]['link']['hidden']) {
|
|
$items[] = $tree[$key];
|
|
}
|
|
}
|
|
|
|
$num_items = count($items);
|
|
foreach ($items as $i => &$data) {
|
|
$class = array();
|
|
if ($i == 0) {
|
|
$class[] = 'first';
|
|
}
|
|
if ($i == $num_items - 1) {
|
|
$class[] = 'last';
|
|
}
|
|
// Set a class if the link has children.
|
|
if ($data['below']) {
|
|
$class[] = 'expanded';
|
|
}
|
|
elseif ($data['link']['has_children']) {
|
|
$class[] = 'collapsed';
|
|
}
|
|
else {
|
|
$class[] = 'leaf';
|
|
}
|
|
if (!empty($data['link']['leaf_has_children'])) {
|
|
$class[] = 'has-children';
|
|
}
|
|
// Set a class if the link is in the active trail.
|
|
if ($data['link']['in_active_trail']) {
|
|
$class[] = 'active-trail';
|
|
$data['link']['localized_options']['attributes']['class'][] = 'active-trail';
|
|
}
|
|
if ($data['link']['href'] == $_GET['q'] || ($data['link']['href'] == '<front>' && drupal_is_front_page())) {
|
|
$class[] = 'active';
|
|
}
|
|
// Set a menu link ID class.
|
|
$class[] = 'menu-mlid-' . $data['link']['mlid'];
|
|
|
|
// Allow menu-specific theme overrides.
|
|
$element['#theme'] = array(
|
|
'menu_link__menu_block__' . $hook_delta,
|
|
'menu_link__menu_block__' . $hook_menu_name,
|
|
'menu_link__menu_block',
|
|
'menu_link__' . $hook_menu_name,
|
|
'menu_link',
|
|
);
|
|
$element['#attributes']['class'] = $class;
|
|
$element['#title'] = $data['link']['title'];
|
|
$element['#href'] = $data['link']['href'];
|
|
$element['#localized_options'] = !empty($data['link']['localized_options']) ? $data['link']['localized_options'] : array();
|
|
$element['#below'] = $data['below'] ? menu_block_tree_output($data['below'], $config) : $data['below'];
|
|
$element['#original_link'] = $data['link'];
|
|
$element['#bid'] = array('module' => 'menu_block', 'delta' => $config['delta']);
|
|
// Index using the link's unique mlid.
|
|
$build[$data['link']['mlid']] = $element;
|
|
}
|
|
if ($build) {
|
|
// Make sure drupal_render() does not re-order the links.
|
|
$build['#sorted'] = TRUE;
|
|
// Add the theme wrapper for outer markup.
|
|
// Allow menu-specific theme overrides.
|
|
$build['#theme_wrappers'][] = array(
|
|
'menu_tree__menu_block__' . $hook_delta,
|
|
'menu_tree__menu_block__' . $hook_menu_name,
|
|
'menu_tree__menu_block',
|
|
'menu_tree__' . $hook_menu_name,
|
|
'menu_tree',
|
|
);
|
|
}
|
|
|
|
return $build;
|
|
}
|
|
|
|
/**
|
|
* Implements hook_menu_block_get_menus() on behalf of book.module.
|
|
*/
|
|
function book_menu_block_get_menus() {
|
|
$menus = array();
|
|
foreach (book_get_books() AS $book) {
|
|
$menus[$book['menu_name']] = $book['title'];
|
|
}
|
|
return $menus;
|
|
}
|
|
|
|
/**
|
|
* Implements hook_menu_block_get_sort_menus() on behalf of book.module.
|
|
*/
|
|
function book_menu_block_get_sort_menus() {
|
|
return array(
|
|
'/^book\-toc\-.+/' => t('Book navigation'),
|
|
);
|
|
}
|