diff options
Diffstat (limited to 'includes/menu.inc')
-rw-r--r-- | includes/menu.inc | 154 |
1 files changed, 138 insertions, 16 deletions
diff --git a/includes/menu.inc b/includes/menu.inc index a8742f2ca..8371980aa 100644 --- a/includes/menu.inc +++ b/includes/menu.inc @@ -185,6 +185,26 @@ define('MENU_LOCAL_ACTION', MENU_IS_LOCAL_TASK | MENU_IS_LOCAL_ACTION); */ /** + * @name Menu context types + * @{ + * Flags for use in the "context" attribute of menu router items. + */ + +/** + * Internal menu flag: Local task should be displayed in page context. + */ +define('MENU_CONTEXT_PAGE', 0x0001); + +/** + * Internal menu flag: Local task should be displayed inline. + */ +define('MENU_CONTEXT_INLINE', 0x0002); + +/** + * @} End of "Menu context types". + */ + +/** * @name Menu status codes * @{ * Status codes for menu callbacks. @@ -663,14 +683,14 @@ function _menu_item_localize(&$item, $map, $link_translate = FALSE) { * a non existing node) then this function return FALSE. */ function _menu_translate(&$router_item, $map, $to_arg = FALSE) { - if ($to_arg) { + if ($to_arg && !empty($router_item['to_arg_functions'])) { // Fill in missing path elements, such as the current uid. _menu_link_map_translate($map, $router_item['to_arg_functions']); } // The $path_map saves the pieces of the path as strings, while elements in // $map may be replaced with loaded objects. $path_map = $map; - if (!_menu_load_objects($router_item, $map)) { + if (!empty($router_item['load_functions']) && !_menu_load_objects($router_item, $map)) { // An error occurred loading an object. $router_item['access'] = FALSE; return FALSE; @@ -706,17 +726,15 @@ function _menu_translate(&$router_item, $map, $to_arg = FALSE) { * An array of helper function (ex: array(2 => 'menu_tail_to_arg')) */ function _menu_link_map_translate(&$map, $to_arg_functions) { - if ($to_arg_functions) { - $to_arg_functions = unserialize($to_arg_functions); - foreach ($to_arg_functions as $index => $function) { - // Translate place-holders into real values. - $arg = $function(!empty($map[$index]) ? $map[$index] : '', $map, $index); - if (!empty($map[$index]) || isset($arg)) { - $map[$index] = $arg; - } - else { - unset($map[$index]); - } + $to_arg_functions = unserialize($to_arg_functions); + foreach ($to_arg_functions as $index => $function) { + // Translate place-holders into real values. + $arg = $function(!empty($map[$index]) ? $map[$index] : '', $map, $index); + if (!empty($map[$index]) || isset($arg)) { + $map[$index] = $arg; + } + else { + unset($map[$index]); } } } @@ -751,7 +769,9 @@ function _menu_link_translate(&$item) { } else { $map = explode('/', $item['link_path']); - _menu_link_map_translate($map, $item['to_arg_functions']); + if (!empty($item['to_arg_functions'])) { + _menu_link_map_translate($map, $item['to_arg_functions']); + } $item['href'] = implode('/', $map); // Note - skip callbacks without real values for their arguments. @@ -761,7 +781,7 @@ function _menu_link_translate(&$item) { } // menu_tree_check_access() may set this ahead of time for links to nodes. if (!isset($item['access'])) { - if (!_menu_load_objects($item, $map)) { + if (!empty($item['load_functions']) && !_menu_load_objects($item, $map)) { // An error occurred loading an object. $item['access'] = FALSE; return FALSE; @@ -1614,10 +1634,11 @@ function menu_local_tasks($level = 0) { $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 = arg(); + $map = $router_item['original_map']; $children = array(); $tasks = array(); $root_path = $router_item['path']; @@ -1758,6 +1779,100 @@ function menu_local_tasks($level = 0) { } /** + * Retrieve contextual links for a system object based on registered local tasks. + * + * This leverages the menu system to retrieve the first layer of registered + * local tasks for a given system path. All local tasks of the tab type 'task' + * or 'context' are taken into account. + * + * @see hook_menu() + * + * For example, when considering the following registered local tasks: + * - node/%node/view (default local task) with no 'context' defined + * - node/%node/edit with context: MENU_CONTEXT_PAGE | MENU_CONTEXT_INLINE + * - node/%node/revisions with context: MENU_CONTEXT_PAGE + * - node/%node/report-as-spam with context: MENU_CONTEXT_INLINE + * + * If the path "node/123" is passed to this function, then it will return the + * links for 'edit' and 'report-as-spam'. + * + * @param $path + * The menu router path of the object to retrieve local tasks for, for example + * "node/123" or "admin/structure/menu/manage/[menu_name]". + * + * @return + * A list of menu router items that are local tasks for the passed in path. + * + * @see system_preprocess() + */ +function menu_contextual_links($parent_path, $args) { + static $path_empty = array(); + + $links = array(); + // Performance: In case a previous invocation for the same parent path did not + // return any links, we immediately return here. + if (isset($path_empty[$parent_path])) { + return $links; + } + // Construct the item-specific parent path. + $path = $parent_path . '/' . implode('/', $args); + + // Get the router item for the given parent link path. + $router_item = menu_get_item($path); + if (!$router_item || !$router_item['access']) { + $path_empty[$parent_path] = TRUE; + return $links; + } + $data = &drupal_static(__FUNCTION__, array()); + $root_path = $router_item['path']; + + // Performance: For a single, normalized path (such as 'node/%') we only query + // available tasks once per request. + if (!isset($data[$root_path])) { + // Get all contextual links that are direct children of the router item and + // not of the tab type 'view'. + $data[$root_path] = db_select('menu_router', 'm') + ->fields('m') + ->condition('tab_parent', $router_item['tab_root']) + ->condition('context', MENU_CONTEXT_PAGE, '<>') + ->orderBy('weight') + ->orderBy('title') + ->execute() + ->fetchAllAssoc('path', PDO::FETCH_ASSOC); + } + $parent_length = drupal_strlen($root_path) + 1; + $map = $router_item['original_map']; + foreach ($data[$root_path] as $item) { + // Extract the actual "task" string from the path argument. + $key = drupal_substr($item['path'], $parent_length); + + // Denormalize and translate the contextual link. + _menu_translate($item, $map, TRUE); + if (!$item['access']) { + continue; + } + // All contextual links are keyed by the actual "task" path argument. The + // menu system does not allow for two local tasks with the same name, and + // since the key is also used as CSS class for the link item, which may be + // styled as icon, it wouldn't make sense to display the same icon for + // different tasks. + $links[$key] = $item; + } + + // Allow modules to alter contextual links. + drupal_alter('menu_contextual_links', $links, $router_item, $root_path); + + // Performance: If the current user does not have access to any links for this + // router path and no other module added further links, we assign FALSE here + // to skip the entire process the next time the same router path is requested. + if (empty($links)) { + $path_empty[$parent_path] = TRUE; + } + + return $links; +} + +/** * Returns the rendered local tasks at the top level. */ function menu_primary_local_tasks() { @@ -2898,6 +3013,10 @@ function _menu_router_build($callbacks) { $item['tab_parent'] = ''; $item['tab_root'] = $path; } + // If not specified, assign the default tab type for local tasks. + elseif (!isset($item['context'])) { + $item['context'] = MENU_CONTEXT_PAGE; + } for ($i = $item['_number_parts'] - 1; $i; $i--) { $parent_path = implode('/', array_slice($item['_parts'], 0, $i)); if (isset($menu[$parent_path])) { @@ -2970,6 +3089,7 @@ function _menu_router_build($callbacks) { 'theme callback' => '', 'description' => '', 'position' => '', + 'context' => 0, 'tab_parent' => '', 'tab_root' => $path, 'path' => $path, @@ -3013,6 +3133,7 @@ function _menu_router_save($menu, $masks) { 'delivery_callback', 'fit', 'number_parts', + 'context', 'tab_parent', 'tab_root', 'title', @@ -3041,6 +3162,7 @@ function _menu_router_save($menu, $masks) { 'delivery_callback' => $item['delivery callback'], 'fit' => $item['_fit'], 'number_parts' => $item['_number_parts'], + 'context' => $item['context'], 'tab_parent' => $item['tab_parent'], 'tab_root' => $item['tab_root'], 'title' => $item['title'], |