diff --git a/includes/common.inc b/includes/common.inc index 767d0c40059e0449f100725f647ecd8fd1fa6cff..caaa3f5a4fd70405c7357e6a25ac4aa67b1f1300 100644 --- a/includes/common.inc +++ b/includes/common.inc @@ -4343,6 +4343,9 @@ function drupal_common_theme() { 'menu_local_task' => array( 'arguments' => array('link' => NULL, 'active' => FALSE), ), + 'menu_local_action' => array( + 'arguments' => array('link' => NULL), + ), 'menu_local_tasks' => array( 'arguments' => array(), ), diff --git a/includes/menu.inc b/includes/menu.inc index e3e5e724f23a869ff2c19f777abe9dc5046f356c..f80836cc7093899de8bcd98a831e5688b448e93e 100644 --- a/includes/menu.inc +++ b/includes/menu.inc @@ -112,6 +112,11 @@ */ define('MENU_IS_LOCAL_TASK', 0x0080); +/** + * Internal menu flag -- menu item is a local action. + */ +define('MENU_IS_LOCAL_ACTION', 0x0100); + /** * @} End of "Menu flags". */ @@ -167,6 +172,14 @@ */ define('MENU_DEFAULT_LOCAL_TASK', MENU_IS_LOCAL_TASK | MENU_LINKS_TO_PARENT); +/** + * Menu type -- An action specific to the parent, usually rendered as a link. + * + * Local actions are menu items that describe actions on the parent item such + * as adding a new user, taxonomy term, etc. + */ +define('MENU_LOCAL_ACTION', MENU_IS_LOCAL_TASK | MENU_IS_LOCAL_ACTION); + /** * @} End of "Menu item types". */ @@ -1305,6 +1318,15 @@ function theme_menu_local_task($link, $active = FALSE) { return '<li ' . ($active ? 'class="active" ' : '') . '>' . $link . "</li>\n"; } +/** + * Generate the HTML output for a single local action link. + * + * @ingroup themeable + */ +function theme_menu_local_action($link) { + return '<li>' . $link . "</li>\n"; +} + /** * Generates elements for the $arg array in the help hook. */ @@ -1437,27 +1459,39 @@ function menu_navigation_links($menu_name, $level = 0) { } /** - * Collects the local tasks (tabs) for a given level. + * Collects the local tasks (tabs), action links, and the root path. * * @param $level * The level of tasks you ask for. Primary tasks are 0, secondary are 1. - * @param $return_root - * Whether to return the root path for the current page. * @return - * Themed output corresponding to the tabs of the requested level, or - * router path if $return_root == TRUE. This router path corresponds to - * a parent tab, if the current page is a default local task. - */ -function menu_local_tasks($level = 0, $return_root = FALSE) { - $tabs = &drupal_static(__FUNCTION__); - $root_path = &drupal_static(__FUNCTION__ . ':root_path'); + * An array containing + * - tabs: Local tasks for the requested level: + * - count: The number of local tasks. + * - output: The themed output of local tasks. + * - actions: Action links for the requested level: + * - count: The number of action links. + * - output: The themed output of action links. + * - root_path: The router path for the current page. If the current page is + * a default local task, then this corresponds to the parent tab. + */ +function menu_local_tasks($level = 0) { + $data = &drupal_static(__FUNCTION__); + $root_path = &drupal_static(__FUNCTION__ . ':root_path', ''); + $empty = array( + 'tabs' => array('count' => 0, 'output' => ''), + 'actions' => array('count' => 0, 'output' => ''), + 'root_path' => &$root_path, + ); - if (!isset($tabs)) { + if (!isset($data)) { + $data = array(); + // Set defaults in case there are no actions or tabs. + $actions = $empty['actions']; $tabs = array(); $router_item = menu_get_item(); if (!$router_item || !$router_item['access']) { - return ''; + return $empty; } // Get all tabs and the root page. $result = db_select('menu_router', NULL, array('fetch' => PDO::FETCH_ASSOC)) @@ -1480,7 +1514,6 @@ function menu_local_tasks($level = 0, $return_root = FALSE) { // 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 @@ -1488,31 +1521,42 @@ function menu_local_tasks($level = 0, $return_root = FALSE) { $depth = 1001; while (isset($children[$path])) { $tabs_current = ''; + $actions_current = ''; $next_path = ''; - $count = 0; + $tab_count = 0; + $action_count = 0; foreach ($children[$path] as $item) { if ($item['access']) { - $count++; // The default task is always active. if ($item['type'] == MENU_DEFAULT_LOCAL_TASK) { - // Find the first parent which is not a 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); $tabs_current .= theme('menu_local_task', $link, TRUE); $next_path = $item['path']; + $tab_count++; } else { $link = theme('menu_item_link', $item); - $tabs_current .= theme('menu_local_task', $link); + if ($item['type'] == MENU_LOCAL_TASK) { + $tabs_current .= theme('menu_local_task', $link); + $tab_count++; + } + else { + $actions_current .= theme('menu_local_action', $link); + $action_count++; + } } } } $path = $next_path; - $tabs[$depth]['count'] = $count; + $tabs[$depth]['count'] = $tab_count; $tabs[$depth]['output'] = $tabs_current; + $actions['count'] = $action_count; + $actions['output'] = $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']; @@ -1524,6 +1568,9 @@ function menu_local_tasks($level = 0, $return_root = FALSE) { $next_parent = ''; $count = 0; foreach ($children[$parent] as $item) { + if ($item['type'] == MENU_LOCAL_ACTION) { + continue; + } if ($item['access']) { $count++; if ($item['type'] == MENU_DEFAULT_LOCAL_TASK) { @@ -1560,36 +1607,51 @@ function menu_local_tasks($level = 0, $return_root = FALSE) { ksort($tabs); // Remove the depth, we are interested only in their relative placement. $tabs = array_values($tabs); + $data['tabs'] = $tabs; } - if ($return_root) { - return $root_path; - } - else { - // We do not display single tabs. - return (isset($tabs[$level]) && $tabs[$level]['count'] > 1) ? $tabs[$level]['output'] : ''; + if (isset($data['tabs'][$level])) { + return array( + 'tabs' => $data['tabs'][$level], + 'actions' => $data['actions'], + 'root_path' => $root_path, + ); } + return $empty; } /** * Returns the rendered local tasks at the top level. */ function menu_primary_local_tasks() { - return menu_local_tasks(0); + $links = menu_local_tasks(0); + // Do not display single tabs. + return ($links['tabs']['count'] > 1 ? $links['tabs']['output'] : ''); } /** * Returns the rendered local tasks at the second level. */ function menu_secondary_local_tasks() { - return menu_local_tasks(1); + $links = menu_local_tasks(1); + // Do not display single tabs. + return ($links['tabs']['count'] > 1 ? $links['tabs']['output'] : ''); +} + +/** + * Returns the rendered local actions at the current level. + */ +function menu_local_actions() { + $links = menu_local_tasks(); + return $links['actions']['output']; } /** * Returns the router path, or the path of the parent tab of a default local task. */ function menu_tab_root_path() { - return menu_local_tasks(0, TRUE); + $links = menu_local_tasks(); + return $links['root_path']; } /** diff --git a/includes/theme.inc b/includes/theme.inc index 73af67648286e126c647d989400f41579154e1a4..32feb595aa36c779555c27cb2e56b34086df2378 100644 --- a/includes/theme.inc +++ b/includes/theme.inc @@ -2039,6 +2039,7 @@ function template_preprocess_page(&$variables) { $variables['messages'] = $variables['show_messages'] ? theme('status_messages') : ''; $variables['main_menu'] = theme_get_setting('toggle_main_menu') ? menu_main_menu() : array(); $variables['secondary_menu'] = theme_get_setting('toggle_secondary_menu') ? menu_secondary_menu() : array(); + $variables['action_links'] = menu_local_actions(); $variables['search_box'] = (theme_get_setting('toggle_search') ? drupal_render(drupal_get_form('search_theme_form')) : ''); $variables['site_name'] = (theme_get_setting('toggle_name') ? filter_xss_admin(variable_get('site_name', 'Drupal')) : ''); $variables['site_slogan'] = (theme_get_setting('toggle_slogan') ? filter_xss_admin(variable_get('site_slogan', '')) : ''); diff --git a/modules/menu/menu.module b/modules/menu/menu.module index 3bab4280c10fcb139018c4b9d0e5c08e4a96ec8d..beb29590bf74104dff8cd50624e34862588d519f 100644 --- a/modules/menu/menu.module +++ b/modules/menu/menu.module @@ -65,7 +65,7 @@ function menu_menu() { 'page callback' => 'drupal_get_form', 'page arguments' => array('menu_edit_menu', 'add'), 'access arguments' => array('administer menu'), - 'type' => MENU_LOCAL_TASK, + 'type' => MENU_LOCAL_ACTION, ); $items['admin/structure/menu/settings'] = array( 'title' => 'Settings', @@ -94,7 +94,7 @@ function menu_menu() { 'page callback' => 'drupal_get_form', 'page arguments' => array('menu_edit_item', 'add', NULL, 3), 'access arguments' => array('administer menu'), - 'type' => MENU_LOCAL_TASK, + 'type' => MENU_LOCAL_ACTION, ); $items['admin/structure/menu-customize/%menu/edit'] = array( 'title' => 'Edit menu', diff --git a/modules/system/page.tpl.php b/modules/system/page.tpl.php index 39127200ef6e06ed97fd800fac9fe232f1024139..eb449a619f2ef8ac64d9703c7ef4138166a2c125 100644 --- a/modules/system/page.tpl.php +++ b/modules/system/page.tpl.php @@ -68,6 +68,8 @@ * - $secondary_menu (array): An array containing the Secondary menu links for * the site, if they have been configured. * - $breadcrumb: The breadcrumb trail for the current page. + * - $action_links: Actions local to the page, such as 'Add menu' on the menu + * administration interface. * * Page content (in order of occurrence in the default page.tpl.php): * - $title: The page title, for use in the actual HTML content. @@ -171,6 +173,7 @@ <?php if ($title): ?><h1 class="title" id="page-title"><?php print $title; ?></h1><?php endif; ?> <?php if ($tabs): ?><div class="tabs"><?php print $tabs; ?></div><?php endif; ?> <?php print $help; ?> + <?php if ($action_links): ?><ul class="action-links"><?php print $action_links; ?></ul><?php endif; ?> <div id="content-area" class="region"> <?php print $content; ?> </div> <!-- /#content-area --> diff --git a/themes/garland/page.tpl.php b/themes/garland/page.tpl.php index 0bf43da70b9ab736573f1689e0c4107e41ae4f68..acca29d9ba911ba779e5cc0bea6d783649d58d55 100644 --- a/themes/garland/page.tpl.php +++ b/themes/garland/page.tpl.php @@ -54,6 +54,7 @@ <?php if ($tabs2): ?><ul class="tabs secondary"><?php print $tabs2 ?></ul><?php endif; ?> <?php if ($show_messages && $messages): print $messages; endif; ?> <?php print $help; ?> + <?php if ($action_links): ?><ul class="action-links"><?php print $action_links; ?></ul><?php endif; ?> <div class="clearfix"> <?php print $content ?> </div> diff --git a/themes/seven/page.tpl.php b/themes/seven/page.tpl.php index cdef2212088f8ab0565959fbfdcfdcd39055b936..e47ccc33413d5e546a46485c43b883d142b4689c 100644 --- a/themes/seven/page.tpl.php +++ b/themes/seven/page.tpl.php @@ -33,6 +33,7 @@ <?php print $help; ?> </div> <?php endif; ?> + <?php if ($action_links): ?><ul class="action-links"><?php print $action_links; ?></ul><?php endif; ?> <?php print $content; ?> </div> diff --git a/themes/seven/style.css b/themes/seven/style.css index 36005a7d09ceccf9e5d693585ce11a432084ad94..314064231ea908ea5facd3e7be2fd5b613fd1c36 100644 --- a/themes/seven/style.css +++ b/themes/seven/style.css @@ -608,6 +608,16 @@ html.js input.throbbing { background-position: 100% -16px; } +ul.action-links { + margin: 1em 0; + overflow: hidden; +} + +ul.action-links li { + float: left; + margin: 0 1em 0 0; +} + /* Exceptions */ #diff-inline-form select, #block-system-main div.filter-options select {