diff --git a/includes/menu.inc b/includes/menu.inc index 4f610f39dba5b9097376a04a56902cc0051aa0f0..6df95f11c0446d0b91bcf2136c539dcee9b14548 100644 --- a/includes/menu.inc +++ b/includes/menu.inc @@ -315,12 +315,16 @@ function menu_get_ancestors($parts) { } $current = ''; for ($j = $length; $j >= 0; $j--) { + // Check the bit on the $j offset. if ($i & (1 << $j)) { + // Bit one means the original value. $current .= $parts[$length - $j]; } else { + // Bit zero means means wildcard. $current .= '%'; } + // Unless we are at offset 0, add a slash. if ($j) { $current .= '/'; } @@ -1735,7 +1739,7 @@ function menu_local_tasks($level = 0) { return $empty; } - // Get all tabs and the root page. + // Get all tabs (also known as local tasks) and the root page. $result = db_select('menu_router', NULL, array('fetch' => PDO::FETCH_ASSOC)) ->fields('menu_router') ->condition('tab_root', $router_item['tab_root']) @@ -1772,12 +1776,19 @@ function menu_local_tasks($level = 0) { $tab_count = 0; $action_count = 0; foreach ($children[$path] as $item) { + // Local tasks can be normal items too, so bitmask with + // MENU_IS_LOCAL_TASK before checking. + if (!($item['type'] & MENU_IS_LOCAL_TASK)) { + // This item is not a tab, skip it. + continue; + } if ($item['access']) { $link = $item; - // The default task is always active. - if ($item['type'] == MENU_DEFAULT_LOCAL_TASK) { + // The default task is always active. As tabs can be normal items + // too, so bitmask with MENU_LINKS_TO_PARENT before checking. + if (($item['type'] & MENU_LINKS_TO_PARENT) == MENU_LINKS_TO_PARENT) { // 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']); + for ($p = $item['tab_parent']; ($tasks[$p]['type'] & MENU_LINKS_TO_PARENT) == MENU_LINKS_TO_PARENT; $p = $tasks[$p]['tab_parent']); // Use the path of the parent instead. $link['href'] = $tasks[$p]['href']; $tabs_current[] = array( @@ -1789,19 +1800,23 @@ function menu_local_tasks($level = 0) { $tab_count++; } else { - if ($item['type'] == MENU_LOCAL_TASK) { - $tabs_current[] = array( - '#theme' => 'menu_local_task', + // Actions can be normal items too, so bitmask with + // MENU_IS_LOCAL_ACTION before checking. + if (($item['type'] & MENU_IS_LOCAL_ACTION) == MENU_IS_LOCAL_ACTION) { + // The item is an action, display it as such. + $actions_current[] = array( + '#theme' => 'menu_local_action', '#link' => $link, ); - $tab_count++; + $action_count++; } else { - $actions_current[] = array( - '#theme' => 'menu_local_action', + // Otherwise, it's a normal tab. + $tabs_current[] = array( + '#theme' => 'menu_local_task', '#link' => $link, ); - $action_count++; + $tab_count++; } } } @@ -1825,15 +1840,18 @@ function menu_local_tasks($level = 0) { $next_parent = ''; $count = 0; foreach ($children[$parent] as $item) { + // Skip local actions. if ($item['type'] & MENU_IS_LOCAL_ACTION) { continue; } if ($item['access']) { $count++; $link = $item; - if ($item['type'] == MENU_DEFAULT_LOCAL_TASK) { + // Local tasks can be normal items too, so bitmask with + // MENU_LINKS_TO_PARENT before checking. + if (($item['type'] & MENU_LINKS_TO_PARENT) == MENU_LINKS_TO_PARENT) { // Find the first parent which is not a default local task. - for ($p = $item['tab_parent']; $tasks[$p]['type'] == MENU_DEFAULT_LOCAL_TASK; $p = $tasks[$p]['tab_parent']); + for ($p = $item['tab_parent']; ($tasks[$p]['type'] & MENU_LINKS_TO_PARENT) == MENU_LINKS_TO_PARENT; $p = $tasks[$p]['tab_parent']); // Use the path of the parent instead. $link['href'] = $tasks[$p]['href']; if ($item['path'] == $router_item['path']) { @@ -2215,7 +2233,7 @@ function menu_get_active_breadcrumb() { $end = end($active_trail); // Don't show a link to the current page in the breadcrumb trail. - if ($item['href'] == $end['href'] || ($item['type'] == MENU_DEFAULT_LOCAL_TASK && $end['href'] != '<front>')) { + if ($item['href'] == $end['href'] || (($item['type'] & MENU_LINKS_TO_PARENT) == MENU_LINKS_TO_PARENT && $end['href'] != '<front>')) { array_pop($breadcrumb); } } diff --git a/modules/dashboard/dashboard.module b/modules/dashboard/dashboard.module index 0ac52f2b623698c7f75c72fd4daa0e878c376b7c..02f4177070990c4c10f5cd7bc58ffee9c03a3d88 100644 --- a/modules/dashboard/dashboard.module +++ b/modules/dashboard/dashboard.module @@ -29,17 +29,18 @@ function dashboard_menu() { 'title' => 'Dashboard', 'description' => 'View and customize your dashboard', 'page callback' => 'dashboard_admin', - 'access arguments' => array('access administration pages'), + '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". - 'weight' => -100, + 'weight' => -15, ); $items['admin/dashboard/customize'] = array( 'title' => 'Dashboard', 'description' => 'View and customize your dashboard', 'page callback' => 'dashboard_admin', 'page arguments' => array(TRUE), - 'access arguments' => array('access administration pages'), + 'access arguments' => array('access dashboard'), 'type' => MENU_CALLBACK, ); $items['admin/dashboard/drawer'] = array( @@ -62,14 +63,17 @@ function dashboard_menu() { } /** - * Implements hook_menu_alter(). + * Implements hook_permission(). */ -function dashboard_menu_alter(&$items) { - // Make the dashboard the default local task on /admin. - $items['admin']['title'] = 'Dashboard'; - $items['admin']['page callback'] = 'dashboard_admin'; - $items['admin/dashboard']['type'] = MENU_DEFAULT_LOCAL_TASK; - $items['admin/by-task']['type'] = MENU_LOCAL_TASK; +function dashboard_permission() { + return array( + 'access dashboard' => array( + 'title' => t('View the administrative dashboard'), + 'description' => t('Customizing the dashboard requires the !permission-name permission.', array( + '!permission-name' => l(t('Administer blocks'), 'admin/people/permissions', array('fragment' => 'module-block')), + )), + ), + ); } /** diff --git a/modules/dashboard/dashboard.test b/modules/dashboard/dashboard.test index 6d9a21e4f2f7dced79664f3f41be21b101c67740..8d7f222960338fea313eb1e867dacbd53a9c53aa 100644 --- a/modules/dashboard/dashboard.test +++ b/modules/dashboard/dashboard.test @@ -19,7 +19,7 @@ class DashboardAccessTestCase extends DrupalWebTestCase { parent::setUp(); // Create and log in an administrative user having access to the dashboard. - $admin_user = $this->drupalCreateUser(array('access administration pages', 'administer blocks')); + $admin_user = $this->drupalCreateUser(array('access dashboard', 'administer blocks')); $this->drupalLogin($admin_user); // Make sure that the dashboard is using the same theme as the rest of the @@ -46,14 +46,14 @@ class DashboardAccessTestCase extends DrupalWebTestCase { $this->drupalPost('admin/structure/block/add', $custom_block, t('Save block')); // Ensure admin access. - $this->drupalGet('admin'); + $this->drupalGet('admin/dashboard'); $this->assertResponse(200, t('Admin has access to the dashboard.')); $this->assertRaw($custom_block['title'], t('Admin has access to a dashboard block.')); // Ensure non-admin access is denied. $normal_user = $this->drupalCreateUser(); $this->drupalLogin($normal_user); - $this->drupalGet('admin'); + $this->drupalGet('admin/dashboard'); $this->assertResponse(403, t('Non-admin has no access to the dashboard.')); $this->assertNoText($custom_block['title'], t('Non-admin has no access to a dashboard block.')); } diff --git a/modules/system/system.module b/modules/system/system.module index 364feb0e0493e09f22c90429ecd06355f69053c7..d19c02912f2a531cff271c735ba3b9aad82e604d 100644 --- a/modules/system/system.module +++ b/modules/system/system.module @@ -543,13 +543,14 @@ function system_menu() { 'access arguments' => array('access administration pages'), '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', 'access arguments' => array('access administration pages'), 'type' => MENU_LOCAL_TASK, - 'weight' => 2, + 'weight' => -18, 'file' => 'system.admin.inc', );