Index: includes/menu.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/menu.inc,v
retrieving revision 1.357
diff -u -p -r1.357 menu.inc
--- includes/menu.inc 17 Oct 2009 11:39:15 -0000 1.357
+++ includes/menu.inc 30 Oct 2009 06:46:16 -0000
@@ -118,6 +118,11 @@ define('MENU_IS_LOCAL_TASK', 0x0080);
define('MENU_IS_LOCAL_ACTION', 0x0100);
/**
+ * Internal menu flag -- menu item is visible depending child items.
+ */
+define('MENU_DEPENDS_ON_CHILDREN', 0x0200);
+
+/**
* @} End of "Menu flags".
*/
@@ -156,6 +161,15 @@ define('MENU_CALLBACK', MENU_VISIBLE_IN_
define('MENU_SUGGESTED_ITEM', MENU_VISIBLE_IN_BREADCRUMB | 0x0010);
/**
+ * Menu type -- A container menu item, hidden when no children are accessible.
+ *
+ * Modules may use "container" menu items that are only displayed in case the
+ * current user is able to access any child item below it. They act like normal
+ * items when visible.
+ */
+define('MENU_CONTAINER_ITEM', MENU_VISIBLE_IN_TREE | MENU_VISIBLE_IN_BREADCRUMB | MENU_DEPENDS_ON_CHILDREN);
+
+/**
* Menu type -- A task specific to the parent item, usually rendered as a tab.
*
* Local tasks are menu items that describe actions to be performed on their
@@ -1267,7 +1281,6 @@ function menu_tree_check_access(&$tree,
}
}
_menu_tree_check_access($tree);
- return;
}
/**
@@ -1275,12 +1288,33 @@ function menu_tree_check_access(&$tree,
*/
function _menu_tree_check_access(&$tree) {
$new_tree = array();
+ $tree_level_access = FALSE;
foreach ($tree as $key => $v) {
$item = &$tree[$key]['link'];
_menu_link_translate($item);
if ($item['access']) {
+ // Return that this level is accessible when at least one link below this
+ // tree level is accessible.
+ $tree_level_access = TRUE;
+
+ $child_access = TRUE;
if ($tree[$key]['below']) {
- _menu_tree_check_access($tree[$key]['below']);
+ $child_access = _menu_tree_check_access($tree[$key]['below']);
+ }
+ // If this link is a MENU_CONTAINER_ITEM and there are no accessible
+ // children, then we mark it as inaccessible and skip it. $child_access
+ // will only ever be set if there was some recursion, and this check needs
+ // to live outside of the conditional recursion to also catch
+ // MENU_CONTAINER_ITEMs that do not have any children (because the menu
+ // tree was limited to a certain depth).
+ if ($item['type'] & MENU_DEPENDS_ON_CHILDREN) {
+// if ($item['link_path'] == 'admin/structure') {
+// dsm($tree[$key]);
+// }
+ if ($item['has_children'] && !$child_access) {
+ $item['access'] = FALSE;
+ continue;
+ }
}
// The weights are made a uniform 5 digits by adding 50000 as an offset.
// After _menu_link_translate(), $item['title'] has the localized link title.
@@ -1291,6 +1325,8 @@ function _menu_tree_check_access(&$tree)
// Sort siblings in the tree based on the weights and localized titles.
ksort($new_tree);
$tree = $new_tree;
+
+ return $tree_level_access;
}
/**
@@ -1339,6 +1375,13 @@ function _menu_tree_data(&$links, $paren
// Fetch next link after filling the sub-tree.
$next = end($links);
}
+ // Otherwise, reset the 'has_children' property, so implementations can
+ // properly build logic depending on it. This is especially required when a
+ // depth-limited menu tree is retrieved, so a link that could have children
+ // does not contain any.
+// else {
+// $tree[$item['mlid']]['link']['has_children'] = 0;
+// }
// Determine if we should exit the loop and return.
if (!$next || $next['depth'] < $depth) {
break;
Index: modules/simpletest/tests/menu.test
===================================================================
RCS file: /cvs/drupal/drupal/modules/simpletest/tests/menu.test,v
retrieving revision 1.20
diff -u -p -r1.20 menu.test
--- modules/simpletest/tests/menu.test 17 Oct 2009 02:58:04 -0000 1.20
+++ modules/simpletest/tests/menu.test 30 Oct 2009 04:19:18 -0000
@@ -242,7 +242,6 @@ class MenuIncTestCase extends DrupalWebT
menu_link_maintain('menu_test', 'delete', 'menu_test_maintain/4', '');
$this->assertEqual(menu_test_static_variable(), 'delete', t('hook_menu_link_delete() fired correctly'));
}
-
}
/**
@@ -280,7 +279,6 @@ class MenuRebuildTestCase extends Drupal
$admin_exists = db_query('SELECT path from {menu_router} WHERE path = :path', array(':path' => 'admin'))->fetchField();
$this->assertEqual($admin_exists, 'admin', t("The menu has been rebuilt, the path 'admin' now exists again."));
}
-
}
/**
@@ -338,3 +336,53 @@ class MenuTreeDataTestCase extends Drupa
}
}
+/**
+ * Tests menu item types.
+ */
+class MenuItemTypeTestCase extends DrupalWebTestCase {
+ public static function getInfo() {
+ return array(
+ 'name' => 'Menu item type test',
+ 'description' => 'Tests behavior of menu item types.',
+ 'group' => 'Menu',
+ );
+ }
+
+ function setUp() {
+ parent::setUp();
+
+ $permissions = module_invoke_all('permission');
+ $this->admin_user = $this->drupalCreateUser(array_keys($permissions));
+ $this->drupalLogin($this->admin_user);
+
+ // Disable the administration theme, so we see the "Management" menu block
+ // in Garland.
+ $edit = array(
+ 'admin_theme' => 0,
+ );
+ $this->drupalPost('admin/appearance', $edit, t('Save configuration'));
+ }
+
+ /**
+ * Test MENU_CONTAINER_ITEM.
+ */
+ function testMenuContainerItem() {
+ // Verify that both "Structure" and "Reports" links are displayed in the
+ // "Management" menu block for the admin user.
+ $this->drupalGet('admin');
+ $this->assertLink('Structure');
+ $this->assertLink('Reports');
+
+ // Create a user that is able change user permissions, but nothing else.
+ $web_user = $this->drupalCreateUser(array('access administration pages', 'administer users', 'administer permissions'));
+ $this->drupalLogin($web_user);
+
+ // Verify that neither "Structure" nor "Reports" is displayed in the
+ // "Management" menu block.
+ // @todo Enhance these assertions after http://drupal.org/node/618530
+ $this->drupalGet('admin');
+ $this->assertNoLink('Structure');
+ $this->assertNoLink('Reports');
+ }
+}
+
Index: modules/system/system.admin.inc
===================================================================
RCS file: /cvs/drupal/drupal/modules/system/system.admin.inc,v
retrieving revision 1.216
diff -u -p -r1.216 system.admin.inc
--- modules/system/system.admin.inc 19 Oct 2009 23:28:40 -0000 1.216
+++ modules/system/system.admin.inc 29 Oct 2009 23:02:59 -0000
@@ -18,7 +18,7 @@ function system_main_admin_page($arg = N
}
// Check for status report errors.
- if (system_status(TRUE) && user_access('administer site configuration')) {
+ if (user_access('administer site configuration') && system_status(TRUE)) {
drupal_set_message(t('One or more problems were detected with your Drupal installation. Check the status report for more information.', array('@status' => url('admin/reports/status'))), 'error');
}
$blocks = array();
@@ -46,7 +46,7 @@ function system_main_admin_page($arg = N
$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)) {
+ if ((isset($item['page_callback']) && !in_array($item['page_callback'], array('system_admin_menu_block_page', 'system_admin_config_page'))) || 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;
@@ -78,7 +78,7 @@ function system_main_admin_page($arg = N
*/
function system_admin_config_page() {
// Check for status report errors.
- if (system_status(TRUE) && user_access('administer site configuration')) {
+ if (user_access('administer site configuration') && system_status(TRUE)) {
drupal_set_message(t('One or more problems were detected with your Drupal installation. Check the status report for more information.', array('@status' => url('admin/reports/status'))), 'error');
}
$blocks = array();
@@ -175,23 +175,6 @@ function system_admin_by_module() {
}
/**
- * Menu callback; displays a module's settings page.
- */
-function system_settings_overview() {
- // Check database setup if necessary
- if (function_exists('db_check_setup') && empty($_POST)) {
- db_check_setup();
- }
-
- $item = menu_get_item('admin/config');
- $content = system_admin_menu_block($item);
-
- $output = theme('admin_block_content', array('content' => $content));
-
- return $output;
-}
-
-/**
* Menu callback; displays a listing of all themes.
*
* @ingroup forms
Index: modules/system/system.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/system/system.module,v
retrieving revision 1.828
diff -u -p -r1.828 system.module
--- modules/system/system.module 29 Oct 2009 06:58:56 -0000 1.828
+++ modules/system/system.module 30 Oct 2009 02:49:00 -0000
@@ -560,6 +560,7 @@ function system_menu() {
'type' => MENU_CALLBACK,
'file' => 'system.admin.inc',
);
+
$items['admin'] = array(
'title' => 'Administer',
'access arguments' => array('access administration pages'),
@@ -593,16 +594,18 @@ function system_menu() {
'file' => 'system.admin.inc',
);
- // Menu items that are basically just menu blocks.
+ // Structure.
$items['admin/structure'] = array(
'title' => 'Structure',
'description' => 'Control how your site looks and feels.',
+ 'type' => MENU_CONTAINER_ITEM,
'position' => 'right',
'weight' => -8,
'page callback' => 'system_admin_menu_block_page',
'access arguments' => array('access administration pages'),
'file' => 'system.admin.inc',
);
+
// Appearance.
$items['admin/appearance'] = array(
'title' => 'Appearance',
@@ -647,9 +650,10 @@ function system_menu() {
);
}
- // Configuration and modules.
+ // Configuration.
$items['admin/config'] = array(
'title' => 'Configuration and modules',
+ 'type' => MENU_CONTAINER_ITEM,
'page callback' => 'system_admin_config_page',
'access arguments' => array('access administration pages'),
'file' => 'system.admin.inc',
@@ -661,6 +665,8 @@ function system_menu() {
'weight' => -10,
'file' => 'system.admin.inc',
);
+
+ // Modules.
$items['admin/config/modules'] = array(
'title' => 'Modules',
'description' => 'Enable or disable add-on modules for your site.',
@@ -694,7 +700,26 @@ function system_menu() {
'file' => 'system.admin.inc',
);
- // Actions.
+ // System.
+ $items['admin/config/system'] = array(
+ 'title' => 'System',
+ 'description' => 'General system related configuration.',
+ 'type' => MENU_CONTAINER_ITEM,
+ 'position' => 'right',
+ 'weight' => -5,
+ 'page callback' => 'system_admin_menu_block_page',
+ 'access arguments' => array('access administration pages'),
+ 'file' => 'system.admin.inc',
+ );
+ $items['admin/config/system/site-information'] = array(
+ 'title' => 'Site information',
+ 'description' => 'Change basic site name, e-mail address, slogan, default front page, number of posts per page, error pages and cron.',
+ 'page callback' => 'drupal_get_form',
+ 'page arguments' => array('system_site_information_settings'),
+ 'access arguments' => array('administer site configuration'),
+ 'file' => 'system.admin.inc',
+ 'weight' => -10,
+ );
$items['admin/config/system/actions'] = array(
'title' => 'Actions',
'description' => 'Manage the actions defined for your site.',
@@ -735,7 +760,7 @@ function system_menu() {
'file' => 'system.admin.inc',
);
- // IP address blocking.
+ // People: IP address blocking.
$items['admin/config/people/ip-blocking'] = array(
'title' => 'IP address blocking',
'description' => 'Manage blocked IP addresses.',
@@ -760,10 +785,11 @@ function system_menu() {
'file' => 'system.admin.inc',
);
- // Configuration.
+ // Development.
$items['admin/config/development'] = array(
'title' => 'Development',
'description' => 'Development tools.',
+ 'type' => MENU_CONTAINER_ITEM,
'position' => 'left',
'weight' => 10,
'page callback' => 'system_admin_menu_block_page',
@@ -786,9 +812,20 @@ function system_menu() {
'access arguments' => array('administer site configuration'),
'file' => 'system.admin.inc',
);
+ $items['admin/config/development/logging'] = array(
+ 'title' => 'Logging and errors',
+ 'description' => "Settings for logging and alerts modules. Various modules can route Drupal's system events to different destinations, such as syslog, database, email, etc.",
+ 'page callback' => 'drupal_get_form',
+ 'page arguments' => array('system_logging_settings'),
+ 'access arguments' => array('administer site configuration'),
+ 'file' => 'system.admin.inc',
+ );
+
+ // Media.
$items['admin/config/media'] = array(
'title' => 'Media',
'description' => 'Media tools.',
+ 'type' => MENU_CONTAINER_ITEM,
'position' => 'left',
'weight' => 10,
'page callback' => 'system_admin_menu_block_page',
@@ -814,6 +851,7 @@ function system_menu() {
$items['admin/config/services'] = array(
'title' => 'Web services',
'description' => 'Tools related to web services.',
+ 'type' => MENU_CONTAINER_ITEM,
'page callback' => 'system_admin_menu_block_page',
'access arguments' => array('access administration pages'),
'file' => 'system.admin.inc',
@@ -826,19 +864,12 @@ function system_menu() {
'access arguments' => array('administer site configuration'),
'file' => 'system.admin.inc',
);
- $items['admin/config/development/logging'] = array(
- 'title' => 'Logging and errors',
- 'description' => "Settings for logging and alerts modules. Various modules can route Drupal's system events to different destinations, such as syslog, database, email, etc.",
- 'page callback' => 'drupal_get_form',
- 'page arguments' => array('system_logging_settings'),
- 'access arguments' => array('administer site configuration'),
- 'file' => 'system.admin.inc',
- );
// Regional and date settings.
$items['admin/config/regional'] = array(
'title' => 'Regional and language',
'description' => 'Regional settings, localization and translation.',
+ 'type' => MENU_CONTAINER_ITEM,
'position' => 'left',
'weight' => -7,
'page callback' => 'system_admin_menu_block_page',
@@ -937,9 +968,11 @@ function system_menu() {
'file' => 'system.admin.inc',
);
+ // Search and metadata.
$items['admin/config/search'] = array(
'title' => 'Search and metadata',
'description' => 'Local site search, metadata and SEO.',
+ 'type' => MENU_CONTAINER_ITEM,
'page callback' => 'system_admin_menu_block_page',
'access arguments' => array('access administration pages'),
'file' => 'system.admin.inc',
@@ -960,40 +993,26 @@ function system_menu() {
'type' => MENU_CALLBACK,
'file' => 'system.admin.inc',
);
+
+ // Content authoring.
$items['admin/config/content'] = array(
'title' => 'Content authoring',
'description' => 'Settings related to formatting and authoring content.',
+ 'type' => MENU_CONTAINER_ITEM,
'position' => 'right',
'weight' => 5,
'page callback' => 'system_admin_menu_block_page',
'access arguments' => array('access administration pages'),
'file' => 'system.admin.inc',
);
- $items['admin/config/system'] = array(
- 'title' => 'System',
- 'description' => 'General system related configuration.',
- 'position' => 'right',
- 'weight' => -5,
- 'page callback' => 'system_admin_menu_block_page',
- 'access arguments' => array('access administration pages'),
- 'file' => 'system.admin.inc',
- );
- $items['admin/config/system/site-information'] = array(
- 'title' => 'Site information',
- 'description' => 'Change basic site name, e-mail address, slogan, default front page, number of posts per page, error pages and cron.',
- 'page callback' => 'drupal_get_form',
- 'page arguments' => array('system_site_information_settings'),
- 'access arguments' => array('administer site configuration'),
- 'file' => 'system.admin.inc',
- 'weight' => -10,
- );
// Reports.
$items['admin/reports'] = array(
'title' => 'Reports',
'description' => 'View reports from system logs and other status information.',
+ 'type' => MENU_CONTAINER_ITEM,
'page callback' => 'system_admin_menu_block_page',
- 'access arguments' => array('access site reports'),
+ 'access arguments' => array('access administration pages'),
'weight' => 5,
'position' => 'left',
'file' => 'system.admin.inc',
@@ -1020,6 +1039,7 @@ function system_menu() {
'type' => MENU_CALLBACK,
'file' => 'system.admin.inc',
);
+
// Default page for batch operations.
$items['batch'] = array(
'page callback' => 'system_batch_page',