diff --git a/core/includes/menu.inc b/core/includes/menu.inc index 27196d1..5eac915 100644 --- a/core/includes/menu.inc +++ b/core/includes/menu.inc @@ -1942,10 +1942,10 @@ function menu_navigation_links($menu_name, $level = 0) { /** * Collects the local tasks (tabs), action links, and the root path. * - * @param $level + * @param int $level * The level of tasks you ask for. Primary tasks are 0, secondary are 1. * - * @return + * @return array * An array containing * - tabs: Local tasks for the requested level. * - actions: Action links for the requested level. @@ -1965,11 +1965,6 @@ function menu_local_tasks($level = 0) { ); if (!isset($data)) { - $data = array(); - // Set defaults in case there are no actions or tabs. - $actions = $empty['actions']; - $tabs = array(); - // Look for route-based tabs. $data['tabs'] = array(); $data['actions'] = array(); @@ -1983,194 +1978,20 @@ function menu_local_tasks($level = 0) { } } - // @todo Remove the code below once the old menu router system got removed. + // @todo Remove when all local tasks/actions are converted to plugins. $router_item = menu_get_item(); - // If this router item points to its parent, start from the parents to // compute tabs and actions. if ($router_item && ($router_item['type'] & MENU_LINKS_TO_PARENT)) { $router_item = menu_get_item($router_item['tab_parent_href']); } - // If we failed to fetch a router item or the current user doesn't have // access to it, don't bother computing the tabs. if ((!$route_name && !$router_item) || ($router_item && !$router_item['access'])) { return $empty; } - - // @todo remove all code using {menu_router} and anything using MENU_* - // constants when all local actions and local tasks are converted to - // plugins. The remaining code should just invoke those managers plus do the - // invocations of hook_menu_local_tasks() and hook_menu_local_tasks_alter(). if ($router_item) { - // Get all tabs (also known as local tasks) and the root page. - $result = db_select('menu_router', NULL, array('fetch' => PDO::FETCH_ASSOC)) - ->fields('menu_router') - ->condition('tab_root', $router_item['tab_root']) - ->condition('context', MENU_CONTEXT_INLINE, '<>') - ->orderBy('weight') - ->orderBy('title') - ->execute(); - $map = $router_item['original_map']; - $children = array(); - $tasks = array(); - $root_path = $router_item['path']; - - foreach ($result as $item) { - _menu_translate($item, $map, TRUE); - if ($item['tab_parent']) { - // All tabs, but not the root page. - $children[$item['tab_parent']][$item['path']] = $item; - } - // Store the translated item for later use. - $tasks[$item['path']] = $item; - } - - // Find all tabs below the current path. - $path = $router_item['path']; - // Tab parenting may skip levels, so the number of parts in the path may not - // equal the depth. Thus we use the $depth counter (offset by 1000 for ksort). - $depth = 1001; - $actions = array(); - while (isset($children[$path])) { - $tabs_current = array(); - $actions_current = array(); - $next_path = ''; - $tab_count = 0; - $action_count = 0; - foreach ($children[$path] as $item) { - // Local tasks can be normal items too, so bitmask with - // MENU_IS_LOCAL_TASK before checking. - if (!($item['type'] & MENU_IS_LOCAL_TASK)) { - // This item is not a tab, skip it. - continue; - } - if ($item['access']) { - $link = $item; - // The default task is always active. As tabs can be normal items - // too, so bitmask with MENU_LINKS_TO_PARENT before checking. - if (($item['type'] & MENU_LINKS_TO_PARENT) == MENU_LINKS_TO_PARENT) { - // Find the first parent which is not a default local task or action. - for ($p = $item['tab_parent']; ($tasks[$p]['type'] & MENU_LINKS_TO_PARENT) == MENU_LINKS_TO_PARENT; $p = $tasks[$p]['tab_parent']); - // Use the path of the parent instead. - $link['href'] = $tasks[$p]['href']; - // Mark the link as active, if the current path happens to be the - // path of the default local task itself (i.e., instead of its - // tab_parent_href or tab_root_href). Normally, links for default - // local tasks link to their parent, but the path of default local - // tasks can still be accessed directly, in which case this link - // would not be marked as active, since l() only compares the href - // with current_path(). - if ($link['href'] != current_path()) { - $link['localized_options']['attributes']['class'][] = 'active'; - } - $tabs_current[$link['href']] = array( - '#theme' => 'menu_local_task', - '#link' => $link, - '#active' => TRUE, - '#weight' => isset($link['weight']) ? $link['weight'] : NULL, - ); - $next_path = $item['path']; - $tab_count++; - } - else { - // Actions can be normal items too, so bitmask with - // MENU_IS_LOCAL_ACTION before checking. - if (($item['type'] & MENU_IS_LOCAL_ACTION) == MENU_IS_LOCAL_ACTION) { - // The item is an action, display it as such. - $actions_current[$link['href']] = array( - '#theme' => 'menu_local_action', - '#link' => $link, - '#weight' => isset($link['weight']) ? $link['weight'] : NULL, - ); - $action_count++; - } - else { - // Otherwise, it's a normal tab. - $tabs_current[$link['href']] = array( - '#theme' => 'menu_local_task', - '#link' => $link, - '#weight' => isset($link['weight']) ? $link['weight'] : NULL, - ); - $tab_count++; - } - } - } - } - $path = $next_path; - $tabs[$depth] = $tabs_current; - $actions = array_merge($actions, $actions_current); - $depth++; - } - $data['actions'] = $actions; - // Find all tabs at the same level or above the current one. - $parent = $router_item['tab_parent']; - $path = $router_item['path']; - $current = $router_item; - $depth = 1000; - while (isset($children[$parent])) { - $tabs_current = array(); - $next_path = ''; - $next_parent = ''; - $count = 0; - foreach ($children[$parent] as $item) { - // Skip local actions. - if ($item['type'] & MENU_IS_LOCAL_ACTION) { - continue; - } - if ($item['access']) { - $count++; - $link = $item; - // Local tasks can be normal items too, so bitmask with - // MENU_LINKS_TO_PARENT before checking. - if (($item['type'] & MENU_LINKS_TO_PARENT) == MENU_LINKS_TO_PARENT) { - // Find the first parent which is not a default local task. - for ($p = $item['tab_parent']; ($tasks[$p]['type'] & MENU_LINKS_TO_PARENT) == MENU_LINKS_TO_PARENT; $p = $tasks[$p]['tab_parent']); - // Use the path of the parent instead. - $link['href'] = $tasks[$p]['href']; - if ($item['path'] == $router_item['path']) { - $root_path = $tasks[$p]['path']; - } - } - // We check for the active tab. - if ($item['path'] == $path) { - // Mark the link as active, if the current path is a (second-level) - // local task of a default local task. Since this default local task - // links to its parent, l() will not mark it as active, as it only - // compares the link's href to current_path(). - if ($link['href'] != current_path()) { - $link['localized_options']['attributes']['class'][] = 'active'; - } - $tabs_current[$link['href']] = array( - '#theme' => 'menu_local_task', - '#link' => $link, - '#active' => TRUE, - '#weight' => isset($link['weight']) ? $link['weight'] : NULL, - ); - $next_path = $item['tab_parent']; - if (isset($tasks[$next_path])) { - $next_parent = $tasks[$next_path]['tab_parent']; - } - } - else { - $tabs_current[$link['href']] = array( - '#theme' => 'menu_local_task', - '#link' => $link, - '#weight' => isset($link['weight']) ? $link['weight'] : NULL, - ); - } - } - } - $path = $next_path; - $parent = $next_parent; - $tabs[$depth] = $tabs_current; - $depth--; - } - // Sort by depth. - ksort($tabs); - // Remove the depth, we are interested only in their relative placement. - $tabs = array_values($tabs); - $data['tabs'] += $tabs; + _menu_get_legacy_tasks($router_item, $data, $root_path); } // Allow modules to dynamically add further tasks. @@ -2197,6 +2018,189 @@ function menu_local_tasks($level = 0) { } /** + * Finds legacy local tasks/actions. + * + * @param array $router_item + * The current router item. + * @param array $data + * An associative array of local tasks/actions. + * @param string $root_path + * + * @deprecated Remove once all local tasks/actions are converted to plugins. + */ +function _menu_get_legacy_tasks($router_item, &$data, &$root_path) { + // Get all tabs (also known as local tasks) and the root page. + $result = db_select('menu_router', NULL, array('fetch' => PDO::FETCH_ASSOC)) + ->fields('menu_router') + ->condition('tab_root', $router_item['tab_root']) + ->condition('context', MENU_CONTEXT_INLINE, '<>') + ->orderBy('weight') + ->orderBy('title') + ->execute(); + $map = $router_item['original_map']; + $children = array(); + $tasks = array(); + $root_path = $router_item['path']; + + foreach ($result as $item) { + _menu_translate($item, $map, TRUE); + if ($item['tab_parent']) { + // All tabs, but not the root page. + $children[$item['tab_parent']][$item['path']] = $item; + } + // Store the translated item for later use. + $tasks[$item['path']] = $item; + } + + // Find all tabs below the current path. + $path = $router_item['path']; + // Tab parenting may skip levels, so the number of parts in the path may not + // equal the depth. Thus we use the $depth counter (offset by 1000 for ksort). + $depth = 1001; + $tabs = array(); + $actions = array(); + while (isset($children[$path])) { + $tabs_current = array(); + $actions_current = array(); + $next_path = ''; + $tab_count = 0; + $action_count = 0; + foreach ($children[$path] as $item) { + // Local tasks can be normal items too, so bitmask with + // MENU_IS_LOCAL_TASK before checking. + if (!($item['type'] & MENU_IS_LOCAL_TASK)) { + // This item is not a tab, skip it. + continue; + } + if ($item['access']) { + $link = $item; + // The default task is always active. As tabs can be normal items + // too, so bitmask with MENU_LINKS_TO_PARENT before checking. + if (($item['type'] & MENU_LINKS_TO_PARENT) == MENU_LINKS_TO_PARENT) { + // Find the first parent which is not a default local task or action. + for ($p = $item['tab_parent']; ($tasks[$p]['type'] & MENU_LINKS_TO_PARENT) == MENU_LINKS_TO_PARENT; $p = $tasks[$p]['tab_parent']); + // Use the path of the parent instead. + $link['href'] = $tasks[$p]['href']; + // Mark the link as active, if the current path happens to be the + // path of the default local task itself (i.e., instead of its + // tab_parent_href or tab_root_href). Normally, links for default + // local tasks link to their parent, but the path of default local + // tasks can still be accessed directly, in which case this link + // would not be marked as active, since l() only compares the href + // with current_path(). + if ($link['href'] != current_path()) { + $link['localized_options']['attributes']['class'][] = 'active'; + } + $tabs_current[$link['href']] = array( + '#theme' => 'menu_local_task', + '#link' => $link, + '#active' => TRUE, + '#weight' => isset($link['weight']) ? $link['weight'] : NULL, + ); + $next_path = $item['path']; + $tab_count++; + } + else { + // Actions can be normal items too, so bitmask with + // MENU_IS_LOCAL_ACTION before checking. + if (($item['type'] & MENU_IS_LOCAL_ACTION) == MENU_IS_LOCAL_ACTION) { + // The item is an action, display it as such. + $actions_current[$link['href']] = array( + '#theme' => 'menu_local_action', + '#link' => $link, + '#weight' => isset($link['weight']) ? $link['weight'] : NULL, + ); + $action_count++; + } + else { + // Otherwise, it's a normal tab. + $tabs_current[$link['href']] = array( + '#theme' => 'menu_local_task', + '#link' => $link, + '#weight' => isset($link['weight']) ? $link['weight'] : NULL, + ); + $tab_count++; + } + } + } + } + $path = $next_path; + $tabs[$depth] = $tabs_current; + $actions = array_merge($actions, $actions_current); + $depth++; + } + $data['actions'] = $actions; + // Find all tabs at the same level or above the current one. + $parent = $router_item['tab_parent']; + $path = $router_item['path']; + $current = $router_item; + $depth = 1000; + while (isset($children[$parent])) { + $tabs_current = array(); + $next_path = ''; + $next_parent = ''; + $count = 0; + foreach ($children[$parent] as $item) { + // Skip local actions. + if ($item['type'] & MENU_IS_LOCAL_ACTION) { + continue; + } + if ($item['access']) { + $count++; + $link = $item; + // Local tasks can be normal items too, so bitmask with + // MENU_LINKS_TO_PARENT before checking. + if (($item['type'] & MENU_LINKS_TO_PARENT) == MENU_LINKS_TO_PARENT) { + // Find the first parent which is not a default local task. + for ($p = $item['tab_parent']; ($tasks[$p]['type'] & MENU_LINKS_TO_PARENT) == MENU_LINKS_TO_PARENT; $p = $tasks[$p]['tab_parent']); + // Use the path of the parent instead. + $link['href'] = $tasks[$p]['href']; + if ($item['path'] == $router_item['path']) { + $root_path = $tasks[$p]['path']; + } + } + // We check for the active tab. + if ($item['path'] == $path) { + // Mark the link as active, if the current path is a (second-level) + // local task of a default local task. Since this default local task + // links to its parent, l() will not mark it as active, as it only + // compares the link's href to current_path(). + if ($link['href'] != current_path()) { + $link['localized_options']['attributes']['class'][] = 'active'; + } + $tabs_current[$link['href']] = array( + '#theme' => 'menu_local_task', + '#link' => $link, + '#active' => TRUE, + '#weight' => isset($link['weight']) ? $link['weight'] : NULL, + ); + $next_path = $item['tab_parent']; + if (isset($tasks[$next_path])) { + $next_parent = $tasks[$next_path]['tab_parent']; + } + } + else { + $tabs_current[$link['href']] = array( + '#theme' => 'menu_local_task', + '#link' => $link, + '#weight' => isset($link['weight']) ? $link['weight'] : NULL, + ); + } + } + } + $path = $next_path; + $parent = $next_parent; + $tabs[$depth] = $tabs_current; + $depth--; + } + // Sort by depth. + ksort($tabs); + // Remove the depth, we are interested only in their relative placement. + $tabs = array_values($tabs); + $data['tabs'] += $tabs; +} + +/** * Retrieves contextual links for a path based on registered local tasks. * * This leverages the menu system to retrieve the first layer of registered