summaryrefslogtreecommitdiff
path: root/includes/menu.inc
diff options
context:
space:
mode:
Diffstat (limited to 'includes/menu.inc')
-rw-r--r--includes/menu.inc154
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'],