diff --git a/modules/comment/comment.module b/modules/comment/comment.module index 5e4c34a99dea8c40687b51f9bd3325c7efc17044..76ccbd431ffa9226b87b51286e2e723b959c9d68 100644 --- a/modules/comment/comment.module +++ b/modules/comment/comment.module @@ -220,7 +220,7 @@ function comment_menu() { 'description' => 'List and edit site comments and the comment approval queue.', 'page callback' => 'comment_admin', 'access arguments' => array('administer comments'), - 'type' => MENU_LOCAL_TASK, + 'type' => MENU_LOCAL_TASK | MENU_NORMAL_ITEM, 'file' => 'comment.admin.inc', ); // Tabs begin here. diff --git a/modules/dashboard/dashboard.module b/modules/dashboard/dashboard.module index 13fb5575af8db7f2865fd2d001742deb6908b39b..62d3722195e4e1d5e48a71261c936c27e67afdf3 100644 --- a/modules/dashboard/dashboard.module +++ b/modules/dashboard/dashboard.module @@ -33,26 +33,26 @@ function dashboard_help($path, $arg) { function dashboard_menu() { $items['admin/structure/dashboard'] = array( 'title' => 'Dashboard', - 'description' => "Configure which blocks can be shown on the dashboard.", + 'description' => 'Configure which blocks can be shown on the dashboard.', 'page callback' => 'dashboard_admin_blocks', 'access arguments' => array('administer blocks'), ); $items['admin/dashboard'] = array( 'title' => 'Dashboard', - 'description' => 'View and customize your dashboard', + 'description' => 'View and customize your dashboard.', 'page callback' => 'dashboard_admin', 'access arguments' => array('access dashboard'), - 'type' => MENU_LOCAL_TASK | MENU_NORMAL_ITEM, // Make this appear first, so for example, in admin menus, it shows up on - // the top corner of the window as a convinient "home link". + // the top corner of the window as a convenient "home link". 'weight' => -15, ); $items['admin/dashboard/customize'] = array( - 'title' => 'Dashboard', - 'description' => 'View and customize your dashboard', + 'title' => 'Customize dashboard', + 'description' => 'Customize your dashboard.', 'page callback' => 'dashboard_admin', 'page arguments' => array(TRUE), 'access arguments' => array('access dashboard'), + 'type' => MENU_VISIBLE_IN_BREADCRUMB, ); $items['admin/dashboard/drawer'] = array( 'page callback' => 'dashboard_show_disabled', @@ -235,14 +235,6 @@ function dashboard_forms() { * Whether to launch in customization mode right away. TRUE or FALSE. */ function dashboard_admin($launch_customize = FALSE) { - // Only continue if provided arguments are expected. This function serves - // as the callback for the top-level admin/ page, so any unexpected arguments - // are likely the result of someone typing in the URL of an administrative - // page that doesn't actually exist; for example, admin/some/random/page. - if (!is_bool($launch_customize)) { - return MENU_NOT_FOUND; - } - $js_settings = array( 'dashboard' => array( 'drawer' => url('admin/dashboard/drawer'), diff --git a/modules/help/help.admin.inc b/modules/help/help.admin.inc index 568a5ad2f532d79b26a837ff6df9008d1b7fb121..1dec032f411af5ba3bc96108b24a7d932672c9f1 100644 --- a/modules/help/help.admin.inc +++ b/modules/help/help.admin.inc @@ -22,12 +22,12 @@ function help_main() { function help_page($name) { $output = ''; if (module_hook($name, 'help')) { - $module = drupal_parse_info_file(drupal_get_path('module', $name) . '/' . $name . '.info'); - drupal_set_title($module['name']); + $info = system_get_info('module'); + drupal_set_title($info[$name]['name']); $temp = module_invoke($name, 'help', "admin/help#$name", drupal_help_arg()); if (empty($temp)) { - $output .= t("No help is available for module %module.", array('%module' => $module['name'])); + $output .= t("No help is available for module %module.", array('%module' => $info[$name]['name'])); } else { $output .= $temp; @@ -35,12 +35,14 @@ function help_page($name) { // Only print list of administration pages if the module in question has // any such pages associated to it. - $admin_tasks = system_get_module_admin_tasks($name); + $admin_tasks = system_get_module_admin_tasks($name, $info[$name]); if (!empty($admin_tasks)) { - ksort($admin_tasks); - $output .= theme('item_list', array('items' => $admin_tasks, 'title' => t('@module administration pages', array('@module' => $module['name'])))); + $links = array(); + foreach ($admin_tasks as $task) { + $links[] = l($task['title'], $task['link_path'], $task['localized_options']); + } + $output .= theme('item_list', array('items' => $links, 'title' => t('@module administration pages', array('@module' => $info[$name]['name'])))); } - } return $output; } diff --git a/modules/help/help.module b/modules/help/help.module index 2c964d7bfb5afaed05f122705aa3dd850c62b878..d6b06e888bc5efd814fb61444c260ddaf2b0d1a9 100644 --- a/modules/help/help.module +++ b/modules/help/help.module @@ -25,6 +25,7 @@ function help_menu() { 'page callback' => 'help_page', 'page arguments' => array(2), 'access arguments' => array('access administration pages'), + 'type' => MENU_VISIBLE_IN_BREADCRUMB, 'file' => 'help.admin.inc', ); } diff --git a/modules/locale/locale.module b/modules/locale/locale.module index 41752862854477509b064eaa3105427c7df8ff48..1e29966d28bcc9dae96b42107d7e780724bbb0f9 100644 --- a/modules/locale/locale.module +++ b/modules/locale/locale.module @@ -136,6 +136,7 @@ function locale_menu() { 'page arguments' => array('locale_language_providers_url_form'), 'access arguments' => array('administer languages'), 'file' => 'locale.admin.inc', + 'type' => MENU_VISIBLE_IN_BREADCRUMB, ); $items['admin/config/regional/language/configure/session'] = array( 'title' => 'Session language detection configuration', @@ -143,6 +144,7 @@ function locale_menu() { 'page arguments' => array('locale_language_providers_session_form'), 'access arguments' => array('administer languages'), 'file' => 'locale.admin.inc', + 'type' => MENU_VISIBLE_IN_BREADCRUMB, ); $items['admin/config/regional/language/edit/%'] = array( 'title' => 'Edit language', diff --git a/modules/profile/profile.module b/modules/profile/profile.module index a94c3c033066cd78a12034f89ed2c5c0257aa568..dab0f68f02fc214e0d4c844f3ffaa3d34f5554b9 100644 --- a/modules/profile/profile.module +++ b/modules/profile/profile.module @@ -98,6 +98,7 @@ function profile_menu() { 'page callback' => 'drupal_get_form', 'page arguments' => array('profile_field_form'), 'access arguments' => array('administer users'), + 'type' => MENU_VISIBLE_IN_BREADCRUMB, 'file' => 'profile.admin.inc', ); $items['admin/config/people/profile/autocomplete'] = array( @@ -112,6 +113,7 @@ function profile_menu() { 'page callback' => 'drupal_get_form', 'page arguments' => array('profile_field_form'), 'access arguments' => array('administer users'), + 'type' => MENU_VISIBLE_IN_BREADCRUMB, 'file' => 'profile.admin.inc', ); $items['admin/config/people/profile/delete'] = array( @@ -119,6 +121,7 @@ function profile_menu() { 'page callback' => 'drupal_get_form', 'page arguments' => array('profile_field_delete'), 'access arguments' => array('administer users'), + 'type' => MENU_VISIBLE_IN_BREADCRUMB, 'file' => 'profile.admin.inc', ); $items['profile/autocomplete'] = array( diff --git a/modules/search/search.module b/modules/search/search.module index 80cdfbbbc3510d85c438e4db31a0ef6dcdeaf5d5..9ef6e6cc3d383cfcd6b375455dc393d0f3415e99 100644 --- a/modules/search/search.module +++ b/modules/search/search.module @@ -173,7 +173,6 @@ function search_menu() { 'page callback' => 'drupal_get_form', 'page arguments' => array('search_admin_settings'), 'access arguments' => array('administer search'), - 'type' => MENU_NORMAL_ITEM, 'weight' => -10, 'file' => 'search.admin.inc', ); @@ -182,6 +181,7 @@ function search_menu() { 'page callback' => 'drupal_get_form', 'page arguments' => array('search_reindex_confirm'), 'access arguments' => array('administer search'), + 'type' => MENU_VISIBLE_IN_BREADCRUMB, 'file' => 'search.admin.inc', ); diff --git a/modules/simpletest/tests/menu.test b/modules/simpletest/tests/menu.test index 5857247ff9f4bffc51aac9ff6093c1b2a547657b..f95634807cb442575bdfd98d4350985abfb9a503 100644 --- a/modules/simpletest/tests/menu.test +++ b/modules/simpletest/tests/menu.test @@ -551,7 +551,7 @@ class MenuBreadcrumbTestCase extends DrupalWebTestCase { function testBreadCrumbs() { // Prepare common base breadcrumb elements. $home = array('<front>' => 'Home'); - $admin = $home + array('admin' => t('Administer')); + $admin = $home + array('admin' => t('Administration')); $config = $admin + array('admin/config' => t('Configuration')); $type = 'article'; $langcode = LANGUAGE_NONE; diff --git a/modules/simpletest/tests/menu_test.module b/modules/simpletest/tests/menu_test.module index 340b8067af7fc30e0c4581f2853bcb5e3cfac2c5..344bdb027ede7d9d07e9ce49258b9527bc3b1a1f 100644 --- a/modules/simpletest/tests/menu_test.module +++ b/modules/simpletest/tests/menu_test.module @@ -219,7 +219,6 @@ function menu_test_menu() { 'description' => 'File inheritance test description', 'page callback' => 'menu_test_callback', 'access arguments' => array('access content'), - 'type' => MENU_LOCAL_TASK, ); $items['menu_login_callback'] = array( diff --git a/modules/system/system.admin.inc b/modules/system/system.admin.inc index 63612fe12f8683e33139107afb22545638c2e62b..cafe079bd4c6b7676419459266303428fef7a10c 100644 --- a/modules/system/system.admin.inc +++ b/modules/system/system.admin.inc @@ -6,70 +6,6 @@ * Admin page callbacks for the system module. */ -/** - * Menu callback; Provide the administration overview page. - */ -function system_main_admin_page($arg = NULL) { - // Only continue if provided arguments are expected. This function serves - // as the callback for the top-level admin/ page, so any unexpected arguments - // are likely the result of someone typing in the URL of an administrative - // page that doesn't actually exist; for example, admin/some/random/page. - if (isset($arg) && substr($arg, 0, 3) != 'by-') { - return MENU_NOT_FOUND; - } - - // Check for status report errors. - if (system_status(TRUE) && user_access('administer site configuration')) { - drupal_set_message(t('One or more problems were detected with your Drupal installation. Check the <a href="@status">status report</a> for more information.', array('@status' => url('admin/reports/status'))), 'error'); - } - $blocks = array(); - if ($admin = db_query("SELECT menu_name, mlid FROM {menu_links} WHERE link_path = 'admin' AND module = 'system'")->fetchAssoc()) { - $result = db_query(" - SELECT m.*, ml.* - FROM {menu_links} ml - INNER JOIN {menu_router} m ON ml.router_path = m.path - WHERE ml.link_path != 'admin/help' AND menu_name = :menu_name AND ml.plid = :mlid AND hidden = 0", $admin, array('fetch' => PDO::FETCH_ASSOC)); - foreach ($result as $item) { - _menu_link_translate($item); - if (!$item['access']) { - continue; - } - // The link 'description' either derived from the hook_menu 'description' - // or entered by the user via menu module is saved as the title attribute. - if (!empty($item['localized_options']['attributes']['title'])) { - $item['description'] = $item['localized_options']['attributes']['title']; - } - $block = $item; - $block['content'] = ''; - $block['show'] = FALSE; - if ($item['block_callback'] && function_exists($item['block_callback'])) { - $function = $item['block_callback']; - $block['content'] .= $function(); - } - $content = system_admin_menu_block($item); - if ((isset($item['page_callback']) && !in_array($item['page_callback'], array('system_admin_menu_block_page', 'system_admin_config_page', 'system_settings_overview'))) || count($content)) { - // Only show blocks for items which are not containers, or those which - // are containers and do have items we can show. - $block['show'] = TRUE; - $block['title'] = l($item['title'], $item['href'], $item['localized_options']); - if (!empty($content)) { - $block['content'] .= theme('admin_block_content', array('content' => $content)); - } - } - // Prepare for sorting as in function _menu_tree_check_access(). - // The weight is offset so it is always positive, with a uniform 5-digits. - $blocks[(50000 + $item['weight']) . ' ' . $item['title'] . ' ' . $item['mlid']] = $block; - } - } - if ($blocks) { - ksort($blocks); - return theme('admin_page', array('blocks' => $blocks)); - } - else { - return t('You do not have any administrative items.'); - } -} - /** * Menu callback; Provide the administration overview page. */ @@ -90,10 +26,11 @@ function system_admin_config_page() { if (!$item['access']) { continue; } - // The link 'description' either derived from the hook_menu 'description' - // or entered by the user via menu module is saved as the title attribute. + // The link description, either derived from 'description' in hook_menu() + // or customized via menu module is used as title attribute. if (!empty($item['localized_options']['attributes']['title'])) { $item['description'] = $item['localized_options']['attributes']['title']; + unset($item['localized_options']['attributes']['title']); } $block = $item; $block['content'] = ''; @@ -142,9 +79,9 @@ function system_admin_menu_block_page() { } /** - * Menu callback; prints a listing of admin tasks for each installed module. + * Menu callback; prints a listing of admin tasks, organized by module. */ -function system_admin_by_module() { +function system_admin_index() { $module_info = system_get_info('module'); foreach ($module_info as $module => $info) { $module_info[$module] = new stdClass(); @@ -152,30 +89,24 @@ function system_admin_by_module() { } uasort($module_info, 'system_sort_modules_by_info_name'); $menu_items = array(); - $help_arg = module_exists('help') ? drupal_help_arg() : FALSE; foreach ($module_info as $module => $info) { - if ($module == 'help') { - continue; - } - - $admin_tasks = system_get_module_admin_tasks($module); - // Only display a section if there are any available tasks. - if (count($admin_tasks)) { - - // Check for help links. - if ($help_arg && module_invoke($module, 'help', "admin/help#$module", $help_arg)) { - $admin_tasks[100] = l(t('Get help'), "admin/help/$module"); + if ($admin_tasks = system_get_module_admin_tasks($module, $info->info)) { + // Sort links by title. + uasort($admin_tasks, 'system_sort_by_title'); + // Move 'Configure permissions' links to the bottom of each section. + $permission_key = "admin/people/permissions#module-$module"; + if (isset($admin_tasks[$permission_key])) { + $permission_task = $admin_tasks[$permission_key]; + unset($admin_tasks[$permission_key]); + $admin_tasks[$permission_key] = $permission_task; } - // Sort. - ksort($admin_tasks); - $menu_items[$info->info['name']] = array($info->info['description'], $admin_tasks); } } - return theme('system_admin_by_module', array('menu_items' => $menu_items)); + return theme('system_admin_index', array('menu_items' => $menu_items)); } /** @@ -977,6 +908,19 @@ function system_modules($form, $form_state = array()) { return $form; } +/** + * Array sorting callback; sorts elements by 'title' key. + */ +function system_sort_by_title($a, $b) { + if (!isset($b['title'])) { + return -1; + } + if (!isset($a['title'])) { + return 1; + } + return strcasecmp($a['title'], $b['title']); +} + /** * Array sorting callback; sorts modules or themes by their name. */ @@ -2387,43 +2331,36 @@ function system_batch_page() { * * @param $variables * An associative array containing: - * - block: An array containing information about the block. It should include - * a 'title', a 'description' and a formatted 'content'. + * - block: An array containing information about the block: + * - show: A Boolean whether to output the block. Defaults to FALSE. + * - title: The block's title. + * - content: (optional) Formatted content for the block. + * - description: (optional) Description of the block. Only output if + * 'content' is not set. * * @ingroup themeable */ function theme_admin_block($variables) { $block = $variables['block']; + $output = ''; // Don't display the block if it has no content to display. if (empty($block['show'])) { - return ''; + return $output; } - if (empty($block['content'])) { - $output = <<< EOT - <div class="admin-panel"> - <h3> - $block[title] - </h3> - <div class="description"> - $block[description] - </div> - </div> -EOT; + $output .= '<div class="admin-panel">'; + if (!empty($block['title'])) { + $output .= '<h3>' . $block['title'] . '</h3>'; + } + if (!empty($block['content'])) { + $output .= '<div class="body">' . $block['content'] . '</div>'; } else { - $output = <<< EOT - <div class="admin-panel"> - <h3> - $block[title] - </h3> - <div class="body"> - $block[content] - </div> - </div> -EOT; + $output .= '<div class="description">' . $block['description'] . '</div>'; } + $output .= '</div>'; + return $output; } @@ -2432,30 +2369,28 @@ function theme_admin_block($variables) { * * @param $variables * An associative array containing: - * - content: An array containing information about the block. It should - * include a 'title', a 'description' and a formatted 'content'. + * - content: An array containing information about the block. Each element + * of the array represents an administrative menu item, and must at least + * contain the keys 'title', 'href', and 'localized_options', which are + * passed to l(). A 'description' key may also be provided. * * @ingroup themeable */ function theme_admin_block_content($variables) { $content = $variables['content']; + $output = ''; - if (!$content) { - return ''; - } - - if (system_admin_compact_mode()) { - $output = '<ul class="menu">'; - foreach ($content as $item) { - $output .= '<li class="leaf">' . l($item['title'], $item['href'], $item['localized_options']) . '</li>'; + if (!empty($content)) { + $class = 'admin-list'; + if ($compact = system_admin_compact_mode()) { + $class .= ' compact'; } - $output .= '</ul>'; - } - else { - $output = '<dl class="admin-list">'; + $output .= '<dl class="' . $class . '">'; foreach ($content as $item) { $output .= '<dt>' . l($item['title'], $item['href'], $item['localized_options']) . '</dt>'; - $output .= '<dd>' . filter_xss_admin($item['description']) . '</dd>'; + if (!$compact && isset($item['description'])) { + $output .= '<dd>' . filter_xss_admin($item['description']) . '</dd>'; + } } $output .= '</dl>'; } @@ -2514,11 +2449,10 @@ function theme_admin_page($variables) { * * @ingroup themeable */ -function theme_system_admin_by_module($variables) { +function theme_system_admin_index($variables) { $menu_items = $variables['menu_items']; $stripe = 0; - $output = ''; $container = array('left' => '', 'right' => ''); $flip = array('left' => 'right', 'right' => 'left'); $position = 'left'; @@ -2531,7 +2465,7 @@ function theme_system_admin_by_module($variables) { if (count($items)) { $block = array(); $block['title'] = $module; - $block['content'] = theme('item_list', array('items' => $items)); + $block['content'] = theme('admin_block_content', array('content' => $items)); $block['description'] = t($description); $block['show'] = TRUE; @@ -2547,6 +2481,7 @@ function theme_system_admin_by_module($variables) { } $output = '<div class="admin clearfix">'; + $output .= theme('system_compact_link'); foreach ($container as $id => $data) { $output .= '<div class="' . $id . ' clearfix">'; $output .= $data; diff --git a/modules/system/system.module b/modules/system/system.module index 73b7c67a72039f67be1cb25d99c13d1259b9381d..ce555c927705b47ae9dae9efdb2ed40cafdb26ed 100644 --- a/modules/system/system.module +++ b/modules/system/system.module @@ -87,7 +87,7 @@ function system_help($path, $arg) { $output .= '<dd>' . t('Actions are individual tasks that the system can do, such as unpublishing a piece of content or banning a user. Modules, such as the <a href="@trigger-help">Trigger module</a>, can fire these actions when certain system events happen; for example, when a new post is added or when a user logs in. Modules may also provide additional actions. Visit the <a href="@actions">Actions page</a> to configure actions.', array('@trigger-help' => url('admin/help/trigger'), '@actions' => url('admin/config/system/actions'))) . '</dd>'; $output .= '</dl>'; return $output; - case 'admin/by-module': + case 'admin/index': return '<p>' . t('This page shows you all available administration tasks for each module.') . '</p>'; case 'admin/appearance': $output = '<p>' . t('Set and configure the default theme for your website. Alternative <a href="@themes">themes</a> are available.', array('@themes' => 'http://drupal.org/project/themes')) . '</p>'; @@ -184,7 +184,7 @@ function system_theme() { 'variables' => array('content' => NULL), 'file' => 'system.admin.inc', ), - 'system_admin_by_module' => array( + 'system_admin_index' => array( 'variables' => array('menu_items' => NULL), 'file' => 'system.admin.inc', ), @@ -526,9 +526,9 @@ function system_menu() { 'file' => 'system.admin.inc', ); $items['admin'] = array( - 'title' => 'Administer', + 'title' => 'Administration', 'access arguments' => array('access administration pages'), - 'page callback' => 'system_main_admin_page', + 'page callback' => 'system_admin_menu_block_page', 'weight' => 9, 'menu_name' => 'management', 'theme callback' => 'variable_get', @@ -542,17 +542,14 @@ function system_menu() { 'type' => MENU_CALLBACK, 'file' => 'system.admin.inc', ); - $items['admin/by-task'] = array( - 'title' => 'By task', - 'page callback' => 'system_main_admin_page', - 'access arguments' => array('access administration pages'), + $items['admin/tasks'] = array( + 'title' => 'Tasks', 'type' => MENU_DEFAULT_LOCAL_TASK, - 'file' => 'system.admin.inc', 'weight' => -20, ); - $items['admin/by-module'] = array( - 'title' => 'By module', - 'page callback' => 'system_admin_by_module', + $items['admin/index'] = array( + 'title' => 'Index', + 'page callback' => 'system_admin_index', 'access arguments' => array('access administration pages'), 'type' => MENU_LOCAL_TASK, 'weight' => -18, @@ -652,6 +649,7 @@ function system_menu() { $items['admin/modules/list/confirm'] = array( 'title' => 'List', 'access arguments' => array('administer modules'), + 'type' => MENU_VISIBLE_IN_BREADCRUMB, ); $items['admin/modules/uninstall'] = array( 'title' => 'Uninstall', @@ -664,6 +662,7 @@ function system_menu() { $items['admin/modules/uninstall/confirm'] = array( 'title' => 'Uninstall', 'access arguments' => array('administer modules'), + 'type' => MENU_VISIBLE_IN_BREADCRUMB, 'file' => 'system.admin.inc', ); @@ -874,6 +873,7 @@ function system_menu() { 'title' => 'Date and time lookup', 'page callback' => 'system_date_time_lookup', 'access arguments' => array('administer site configuration'), + 'type' => MENU_CALLBACK, 'file' => 'system.admin.inc', ); @@ -935,6 +935,7 @@ function system_menu() { 'page callback' => 'drupal_get_form', 'page arguments' => array('system_actions_configure'), 'access arguments' => array('administer actions'), + 'type' => MENU_VISIBLE_IN_BREADCRUMB, 'file' => 'system.admin.inc', ); $items['admin/config/system/actions/delete/%actions'] = array( @@ -2024,6 +2025,14 @@ function system_preprocess_block(&$variables) { */ function system_admin_menu_block($item) { $cache = &drupal_static(__FUNCTION__, array()); + // If we are calling this function for a menu item that corresponds to a + // local task (for example, admin/tasks), then we want to retrieve the + // parent item's child links, not this item's (since this item won't have + // any). + if ($item['tab_root'] != $item['path']) { + $item = menu_get_item($item['tab_root_href']); + } + if (!isset($item['mlid'])) { $item += db_query("SELECT mlid, menu_name FROM {menu_links} ml WHERE ml.router_path = :path AND module = 'system'", array(':path' => $item['path']))->fetchAssoc(); } @@ -2033,53 +2042,31 @@ function system_admin_menu_block($item) { } $content = array(); - $default_task = NULL; - $has_subitems = FALSE; - $result = db_query(" - SELECT m.load_functions, m.to_arg_functions, m.access_callback, m.access_arguments, m.page_callback, m.page_arguments, m.delivery_callback, m.title, m.title_callback, m.title_arguments, m.theme_callback, m.theme_arguments, m.type, m.description, m.path, m.weight as router_weight, ml.* - FROM {menu_router} m - LEFT JOIN {menu_links} ml ON m.path = ml.router_path - WHERE (ml.plid = :plid AND ml.menu_name = :name AND hidden = 0) OR (m.tab_parent = :path AND m.type IN (:local_task, :default_task))", array(':plid' => $item['mlid'], ':name' => $item['menu_name'], ':path' => $item['path'], ':local_task' => MENU_LOCAL_TASK, ':default_task' => MENU_DEFAULT_LOCAL_TASK), array('fetch' => PDO::FETCH_ASSOC)); - foreach ($result as $link) { - if (!isset($link['link_path'])) { - // If this was not an actual link, fake the tab as a menu link, so we - // don't need to special case it beyond this point. - $link['link_title'] = $link['title']; - $link['link_path'] = $link['path']; - $link['options'] = 'a:0:{}'; - $link['weight'] = $link['router_weight']; - } - else { - // We found a non-tab subitem, remember that. - $has_subitems = TRUE; - } + $query = db_select('menu_links', 'ml', array('fetch' => PDO::FETCH_ASSOC)); + $query->join('menu_router', 'm', 'm.path = ml.router_path'); + $query + ->fields('ml') + // Weight should be taken from {menu_links}, not {menu_router}. + ->fields('m', array_diff(drupal_schema_fields_sql('menu_router'), array('weight'))) + ->condition('ml.plid', $item['mlid']) + ->condition('ml.menu_name', $item['menu_name']) + ->condition('ml.hidden', 0); + + foreach ($query->execute() as $link) { _menu_link_translate($link); - if (!$link['access']) { - continue; - } - - // The link 'description' — either derived from the hook_menu 'description' or - // entered by the user via menu module — is saved as the title attribute. - // The title attribute is then unset to reduce redundancy in admin pages - // for screen readers. - if (!empty($link['localized_options']['attributes']['title'])) { - $link['description'] = $link['localized_options']['attributes']['title']; - unset($link['localized_options']['attributes']['title']); - } - - // Prepare for sorting as in function _menu_tree_check_access(). - // The weight is offset so it is always positive, with a uniform 5-digits. - $key = (50000 + $link['weight']) . ' ' . drupal_strtolower($link['title']) . ' ' . $link['mlid']; - $content[$key] = $link; - if ($link['type'] == MENU_DEFAULT_LOCAL_TASK) { - $default_task = $key; + if ($link['access']) { + // The link description, either derived from 'description' in + // hook_menu() or customized via menu module is used as title attribute. + if (!empty($link['localized_options']['attributes']['title'])) { + $link['description'] = $link['localized_options']['attributes']['title']; + unset($link['localized_options']['attributes']['title']); + } + // Prepare for sorting as in function _menu_tree_check_access(). + // The weight is offset so it is always positive, with a uniform 5-digits. + $key = (50000 + $link['weight']) . ' ' . drupal_strtolower($link['title']) . ' ' . $link['mlid']; + $content[$key] = $link; } } - if ($has_subitems) { - // If we've had at least one non-tab subitem, remove the link for the - // default task, since that is already broken down to subitems. - unset($content[$default_task]); - } ksort($content); $cache[$item['mlid']] = $content; return $content; @@ -2828,38 +2815,61 @@ function system_admin_compact_page($mode = 'off') { * * @param $module * Module name. + * @param $info + * The module's information, as provided by system_get_info(). + * * @return * An array of task links. */ -function system_get_module_admin_tasks($module) { - $items = &drupal_static(__FUNCTION__, array()); - - if (empty($items)) { - $result = db_query(" - SELECT m.load_functions, m.to_arg_functions, m.access_callback, m.access_arguments, m.page_callback, m.page_arguments, m.delivery_callback, m.title, m.title_callback, m.title_arguments, m.theme_callback, m.theme_arguments, m.type, ml.* - FROM {menu_links} ml INNER JOIN {menu_router} m ON ml.router_path = m.path WHERE ml.link_path LIKE 'admin/%' AND hidden >= 0 AND module = 'system' AND m.number_parts > 2", array(), array('fetch' => PDO::FETCH_ASSOC)); - foreach ($result as $item) { - _menu_link_translate($item); - if ($item['access']) { - $items[$item['router_path']] = $item; +function system_get_module_admin_tasks($module, $info) { + $links = &drupal_static(__FUNCTION__); + + if (!isset($links)) { + $links = array(); + $query = db_select('menu_links', 'ml', array('fetch' => PDO::FETCH_ASSOC)); + $query->join('menu_router', 'm', 'm.path = ml.router_path'); + $query + ->fields('ml') + // Weight should be taken from {menu_links}, not {menu_router}. + ->fields('m', array_diff(drupal_schema_fields_sql('menu_router'), array('weight'))) + ->condition('ml.link_path', 'admin/%', 'LIKE') + ->condition('ml.hidden', 0, '>=') + ->condition('ml.module', 'system') + ->condition('m.number_parts', 1, '>') + ->condition('m.page_callback', 'system_admin_menu_block_page', '!='); + foreach ($query->execute() as $link) { + _menu_link_translate($link); + if ($link['access']) { + $links[$link['router_path']] = $link; } } } - $admin_access = user_access('administer permissions'); $admin_tasks = array(); - $admin_task_count = 0; - // Check for permissions. - if (in_array($module, module_implements('permission')) && $admin_access) { - $admin_tasks[-1] = l(t('Configure permissions'), 'admin/people/permissions', array('fragment' => 'module-' . $module)); + if ($menu = module_invoke($module, 'menu')) { + foreach ($menu as $path => $item) { + if (isset($links[$path])) { + $task = $links[$path]; + // The link description, either derived from 'description' in + // hook_menu() or customized via menu module is used as title attribute. + if (!empty($task['localized_options']['attributes']['title'])) { + $task['description'] = $task['localized_options']['attributes']['title']; + unset($task['localized_options']['attributes']['title']); + } + $admin_tasks[$path] = $task; + } + } } - // Check for menu items that are admin links. - if (in_array($module, module_implements('menu')) && $menu = module_invoke($module, 'menu')) { - foreach (array_keys($menu) as $path) { - if (isset($items[$path])) { - $admin_tasks[$items[$path]['title'] . $admin_task_count ++] = l($items[$path]['title'], $path); - } + // Append link for permissions. + if (module_hook($module, 'permission')) { + $item = menu_get_item('admin/people/permissions'); + if (!empty($item['access'])) { + $item['link_path'] = $item['href']; + $item['title'] = t('Configure @module permissions', array('@module' => $info['name'])); + unset($item['description']); + $item['localized_options']['fragment'] = 'module-' . $module; + $admin_tasks["admin/people/permissions#module-$module"] = $item; } } diff --git a/modules/system/system.test b/modules/system/system.test index 3fe9ac11d831ceafb4d1e3b742d3df8a60400fcb..3946199ec77f382aa6af082bcff48bce505f6fe6 100644 --- a/modules/system/system.test +++ b/modules/system/system.test @@ -1848,21 +1848,96 @@ class ShutdownFunctionsTest extends DrupalWebTestCase { } /** - * Functional tests compact mode. + * Tests administrative overview pages. */ -class CompactModeTest extends DrupalWebTestCase { +class SystemAdminTestCase extends DrupalWebTestCase { public static function getInfo() { return array( - 'name' => 'Compact mode', - 'description' => 'Tests compact mode functionality.', + 'name' => 'Administrative pages', + 'description' => 'Tests output on administrative pages and compact mode functionality.', 'group' => 'System', ); } function setUp() { - parent::setUp(); - $admin_user = $this->drupalCreateUser(array('access administration pages')); - $this->drupalLogin($admin_user); + // testAdminPages() requires Locale module. + parent::setUp(array('locale')); + + // Create an administrator with all permissions, as well as a regular user + // who can only access administration pages and perform some Locale module + // administrative tasks, but not all of them. + $this->admin_user = $this->drupalCreateUser(array_keys(module_invoke_all('permission'))); + $this->web_user = $this->drupalCreateUser(array( + 'access administration pages', + 'translate interface', + )); + $this->drupalLogin($this->admin_user); + } + + /** + * Tests output on administrative listing pages. + */ + function testAdminPages() { + // Go to Administration. + $this->drupalGet('admin'); + + // Verify that all visible, top-level administration links are listed on + // the main administration page. + foreach (menu_get_router() as $path => $item) { + if (strpos($path, 'admin/') === 0 && ($item['type'] & MENU_VISIBLE_IN_TREE) && $item['_number_parts'] == 2) { + $this->assertLink($item['title']); + $this->assertLinkByHref($path); + $this->assertText($item['description']); + } + } + + // For each administrative listing page on which the Locale module appears, + // verify that there are links to the module's primary configuration pages, + // but no links to its individual sub-configuration pages. Also verify that + // a user with access to only some Locale module administration pages only + // sees links to the pages they have access to. + $admin_list_pages = array( + 'admin/index', + 'admin/config', + 'admin/config/regional', + ); + + foreach ($admin_list_pages as $page) { + // For the administrator, verify that there are links to Locale's primary + // configuration pages, but no links to individual sub-configuration + // pages. + $this->drupalLogin($this->admin_user); + $this->drupalGet($page); + $this->assertLinkByHref('admin/config'); + $this->assertLinkByHref('admin/config/regional/settings'); + $this->assertLinkByHref('admin/config/regional/date-time'); + $this->assertLinkByHref('admin/config/regional/language'); + $this->assertNoLinkByHref('admin/config/regional/language/configure/session'); + $this->assertNoLinkByHref('admin/config/regional/language/configure/url'); + $this->assertLinkByHref('admin/config/regional/translate'); + // On admin/index only, the administrator should also see a "Configure + // permissions" link for the Locale module. + if ($page == 'admin/index') { + $this->assertLinkByHref("admin/people/permissions#module-locale"); + } + + // For a less privileged user, verify that there are no links to Locale's + // primary configuration pages, but a link to the translate page exists. + $this->drupalLogin($this->web_user); + $this->drupalGet($page); + $this->assertLinkByHref('admin/config'); + $this->assertNoLinkByHref('admin/config/regional/settings'); + $this->assertNoLinkByHref('admin/config/regional/date-time'); + $this->assertNoLinkByHref('admin/config/regional/language'); + $this->assertNoLinkByHref('admin/config/regional/language/configure/session'); + $this->assertNoLinkByHref('admin/config/regional/language/configure/url'); + $this->assertLinkByHref('admin/config/regional/translate'); + // This user cannot configure permissions, so even on admin/index should + // not see a "Configure permissions" link for the Locale module. + if ($page == 'admin/index') { + $this->assertNoLinkByHref("admin/people/permissions#module-locale"); + } + } } /** diff --git a/themes/seven/template.php b/themes/seven/template.php index 27a0a40cc80925c68369d4108b7310a037143436..46e853e87418804dbf95bb61b2cc8a011902c37c 100644 --- a/themes/seven/template.php +++ b/themes/seven/template.php @@ -51,7 +51,7 @@ function seven_node_add_list($variables) { } /** - * Override of theme_admin_block_content(). + * Overrides theme_admin_block_content(). * * Use unordered list markup in both compact and extended mode. */ @@ -63,7 +63,7 @@ function seven_admin_block_content($variables) { foreach ($content as $item) { $output .= '<li class="leaf">'; $output .= l($item['title'], $item['href'], $item['localized_options']); - if (!system_admin_compact_mode()) { + if (isset($item['description']) && !system_admin_compact_mode()) { $output .= '<div class="description">' . filter_xss_admin($item['description']) . '</div>'; } $output .= '</li>';