summaryrefslogtreecommitdiff
path: root/includes/menu.inc
diff options
context:
space:
mode:
Diffstat (limited to 'includes/menu.inc')
-rw-r--r--includes/menu.inc132
1 files changed, 78 insertions, 54 deletions
diff --git a/includes/menu.inc b/includes/menu.inc
index ad6090b25..fe6d459d1 100644
--- a/includes/menu.inc
+++ b/includes/menu.inc
@@ -552,6 +552,14 @@ function _menu_check_access(&$item, $map) {
function _menu_item_localize(&$item, $map, $link_translate = FALSE) {
$callback = $item['title_callback'];
$item['localized_options'] = $item['options'];
+ // All 'class' attributes are assumed to be an array during rendering, but
+ // links stored in the database may use an old string value.
+ // @todo In order to remove this code we need to implement a database update
+ // including unserializing all existing link options and running this code
+ // on them, as well as adding validation to menu_link_save().
+ if (isset($item['options']['attributes']['class']) && is_string($item['options']['attributes']['class'])) {
+ $item['localized_options']['attributes']['class'] = explode(' ', $item['options']['attributes']['class']);
+ }
// If we are translating the title of a menu link, and its title is the same
// as the corresponding router item, then we can use the title information
// from the router. If it's customized, then we need to use the link title
@@ -805,16 +813,21 @@ function menu_tree($menu_name) {
/**
* Returns a rendered menu tree.
*
+ * The menu item's LI element is given one of the following classes:
+ * - expanded: The menu item is showing its submenu.
+ * - collapsed: The menu item has a submenu which is not shown.
+ * - leaf: The menu item has no submenu.
+ *
* @param $tree
* A data structure representing the tree as returned from menu_tree_data.
* @return
- * The rendered HTML of that data structure.
+ * A structured array to be rendered by drupal_render().
*/
function menu_tree_output($tree) {
- $output = '';
+ $build = array();
$items = array();
- // Pull out just the menu items we are going to render so that we
+ // Pull out just the menu links we are going to render so that we
// get an accurate count for the first/last classes.
foreach ($tree as $data) {
if (!$data['link']['hidden']) {
@@ -824,23 +837,47 @@ function menu_tree_output($tree) {
$num_items = count($items);
foreach ($items as $i => $data) {
- $extra_class = array();
+ $class = array();
if ($i == 0) {
- $extra_class[] = 'first';
+ $class[] = 'first';
}
if ($i == $num_items - 1) {
- $extra_class[] = 'last';
+ $class[] = 'last';
}
- $extra_class = implode(' ', $extra_class);
- $link = theme('menu_item_link', $data['link']);
+ // Set a class if the link has children.
if ($data['below']) {
- $output .= theme('menu_item', $link, $data['link']['has_children'], menu_tree_output($data['below']), $data['link']['in_active_trail'], $extra_class);
+ $class[] = 'expanded';
+ }
+ elseif ($data['link']['has_children']) {
+ $class[] = 'collapsed';
}
else {
- $output .= theme('menu_item', $link, $data['link']['has_children'], '', $data['link']['in_active_trail'], $extra_class);
+ $class[] = 'leaf';
+ }
+ // Set a class if the link is in the active trail.
+ if ($data['link']['in_active_trail']) {
+ $class[] = 'active-trail';
+ $data['localized_options']['attributes']['class'][] = 'active-trail';
}
+
+ $element['#theme'] = 'menu_link';
+ $element['#attributes']['class'] = $class;
+ $element['#title'] = $data['link']['title'];
+ $element['#href'] = $data['link']['href'];
+ $element['#localized_options'] = !empty($data['localized_options']) ? $data['localized_options'] : array();
+ $element['#below'] = $data['below'] ? menu_tree_output($data['below']) : $data['below'];
+ $element['#original_link'] = $data['link'];
+ // 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.
+ $build['#theme_wrappers'][] = 'menu_tree';
}
- return $output ? theme('menu_tree', $output) : '';
+
+ return $build;
}
/**
@@ -1254,20 +1291,16 @@ function _menu_tree_data(&$links, $parents, $depth) {
}
/**
- * Generate the HTML output for a single menu link.
+ * Preprocess the rendered tree for theme_menu_tree.
*
* @ingroup themeable
*/
-function theme_menu_item_link($link) {
- if (empty($link['localized_options'])) {
- $link['localized_options'] = array();
- }
-
- return l($link['title'], $link['href'], $link['localized_options']);
+function template_preprocess_menu_tree(&$variables) {
+ $variables['tree'] = $variables['tree']['#children'];
}
/**
- * Generate the HTML output for a menu tree
+ * Theme wrapper for the HTML output for a menu sub-tree.
*
* @ingroup themeable
*/
@@ -1276,56 +1309,47 @@ function theme_menu_tree($tree) {
}
/**
- * Generate the HTML output for a menu item and submenu.
+ * Generate the HTML output for a menu link and submenu.
*
- * The menu item's LI element is given one of the following classes:
- * - expanded: The menu item is showing its submenu.
- * - collapsed: The menu item has a submenu which is not shown.
- * - leaf: The menu item has no submenu.
+ * @param $element
+ * Structured array data for a menu link.
*
* @ingroup themeable
- *
- * @param $link
- * The fully-formatted link for this menu item.
- * @param $has_children
- * Boolean value indicating if this menu item has children.
- * @param $menu
- * Contains a fully-formatted submenu, if one exists for this menu item.
- * Defaults to NULL.
- * @param $in_active_trail
- * Boolean determining if the current page is below the menu item in the
- * menu system. Defaults to FALSE.
- * @param $extra_class
- * Extra classes that should be added to the class of the list item.
- * Defaults to NULL.
*/
-function theme_menu_item($link, $has_children, $menu = '', $in_active_trail = FALSE, $extra_class = NULL) {
- $class = ($menu ? 'expanded' : ($has_children ? 'collapsed' : 'leaf'));
- if (!empty($extra_class)) {
- $class .= ' ' . $extra_class;
- }
- if ($in_active_trail) {
- $class .= ' active-trail';
+function theme_menu_link(array $element) {
+ $sub_menu = '';
+
+ if ($element['#below']) {
+ $sub_menu = drupal_render($element['#below']);
}
- return '<li class="' . $class . '">' . $link . $menu . "</li>\n";
+ $output = l($element['#title'], $element['#href'], $element['#localized_options']);
+ return '<li' . drupal_attributes($element['#attributes']) . '>' . $output . $sub_menu . "</li>\n";
}
/**
* Generate the HTML output for a single local task link.
*
+ * @param $link
+ * A menu link array with 'title', 'href', and 'localized_options' keys.
+ * @param $active
+ * A boolean indicating whether the local task is active.
+ *
* @ingroup themeable
*/
function theme_menu_local_task($link, $active = FALSE) {
- return '<li ' . ($active ? 'class="active" ' : '') . '>' . $link . "</li>\n";
+ return '<li ' . ($active ? 'class="active" ' : '') . '>' . l($link['title'], $link['href'], $link['localized_options']) . "</li>\n";
}
/**
* Generate the HTML output for a single local action link.
*
+ * @param $link
+ * A menu link array with 'title', 'href', and 'localized_options' keys.
+ *
* @ingroup themeable
*/
function theme_menu_local_action($link) {
- return '<li>' . $link . "</li>\n";
+ return '<li>' . l($link['title'], $link['href'], $link['localized_options']) . "</li>\n";
}
/**
@@ -1528,17 +1552,18 @@ function menu_local_tasks($level = 0) {
$action_count = 0;
foreach ($children[$path] as $item) {
if ($item['access']) {
+ $link = $item;
// The default task is always active.
if ($item['type'] == MENU_DEFAULT_LOCAL_TASK) {
// Find the first parent which is not a default local task or action.
for ($p = $item['tab_parent']; $tasks[$p]['type'] == MENU_DEFAULT_LOCAL_TASK; $p = $tasks[$p]['tab_parent']);
- $link = theme('menu_item_link', array('href' => $tasks[$p]['href']) + $item);
+ // Use the path of the parent instead.
+ $link['href'] = $tasks[$p]['href'];
$tabs_current .= theme('menu_local_task', $link, TRUE);
$next_path = $item['path'];
$tab_count++;
}
else {
- $link = theme('menu_item_link', $item);
if ($item['type'] == MENU_LOCAL_TASK) {
$tabs_current .= theme('menu_local_task', $link);
$tab_count++;
@@ -1574,17 +1599,16 @@ function menu_local_tasks($level = 0) {
}
if ($item['access']) {
$count++;
+ $link = $item;
if ($item['type'] == MENU_DEFAULT_LOCAL_TASK) {
// Find the first parent which is not a default local task.
for ($p = $item['tab_parent']; $tasks[$p]['type'] == MENU_DEFAULT_LOCAL_TASK; $p = $tasks[$p]['tab_parent']);
- $link = theme('menu_item_link', array('href' => $tasks[$p]['href']) + $item);
+ // Use the path of the parent instead.
+ $link['href'] = $tasks[$p]['href'];
if ($item['path'] == $router_item['path']) {
$root_path = $tasks[$p]['path'];
}
}
- else {
- $link = theme('menu_item_link', $item);
- }
// We check for the active tab.
if ($item['path'] == $path) {
$tabs_current .= theme('menu_local_task', $link, TRUE);