Index: includes/menu.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/menu.inc,v retrieving revision 1.362 diff -u -p -r1.362 menu.inc --- includes/menu.inc 11 Nov 2009 08:28:50 -0000 1.362 +++ includes/menu.inc 24 Nov 2009 21:02:16 -0000 @@ -162,7 +162,7 @@ define('MENU_SUGGESTED_ITEM', MENU_VISIB * parent item. An example is the path "node/52/edit", which performs the * "edit" task on "node/52". */ -define('MENU_LOCAL_TASK', MENU_IS_LOCAL_TASK); +define('MENU_LOCAL_TASK', MENU_IS_LOCAL_TASK | MENU_VISIBLE_IN_BREADCRUMB); /** * Menu type -- The "default" local task, which is initially active. @@ -170,7 +170,7 @@ define('MENU_LOCAL_TASK', MENU_IS_LOCAL_ * Every set of local tasks should provide one "default" task, that links to the * same path as its parent when clicked. */ -define('MENU_DEFAULT_LOCAL_TASK', MENU_IS_LOCAL_TASK | MENU_LINKS_TO_PARENT); +define('MENU_DEFAULT_LOCAL_TASK', MENU_IS_LOCAL_TASK | MENU_LINKS_TO_PARENT | MENU_VISIBLE_IN_BREADCRUMB); /** * Menu type -- An action specific to the parent, usually rendered as a link. @@ -178,7 +178,7 @@ define('MENU_DEFAULT_LOCAL_TASK', MENU_I * 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); +define('MENU_LOCAL_ACTION', MENU_IS_LOCAL_TASK | MENU_IS_LOCAL_ACTION | MENU_VISIBLE_IN_BREADCRUMB); /** * @} End of "Menu item types". @@ -2287,12 +2287,14 @@ function menu_get_router() { * Builds a link from a router item. */ function _menu_link_build($item) { - if ($item['type'] == MENU_CALLBACK) { - $item['hidden'] = -1; - } - elseif ($item['type'] == MENU_SUGGESTED_ITEM) { + // Suggested items are hidden in terms of disabled by default. + if ($item['type'] == MENU_SUGGESTED_ITEM) { $item['hidden'] = 1; } + // Hide any other items that are not visible in the tree (MENU_NORMAL_ITEM). + elseif (!($item['type'] & MENU_VISIBLE_IN_TREE)) { + $item['hidden'] = -1; + } // Note, we set this as 'system', so that we can be sure to distinguish all // the menu links generated automatically from entries in {menu_router}. $item['module'] = 'system'; @@ -2343,8 +2345,9 @@ function _menu_navigation_links_rebuild( $item['plid'] = $existing_item['plid']; } else { - // If it moved, put it at the top level in the new menu. - $item['plid'] = 0; + // It moved to a new menu, so let menu_link_save() try to find a + // valid parent based on path. + unset($item['plid']); } $item['has_children'] = $existing_item['has_children']; $item['updated'] = $existing_item['updated']; @@ -2543,7 +2546,6 @@ function _menu_delete_item($item, $force * saved. */ function menu_link_save(&$item) { - drupal_alter('menu_link', $item); // This is the easiest way to handle the unique internal path '', @@ -2569,14 +2571,12 @@ function menu_link_save(&$item) { } } + // The re-parenting process always needs to be invoked, since there is no + // guarantee that {menu_links} does not contain stale data caused by a + // re-parenting process that went wrong in a previous rebuild. + // 'plid' can be 0 (zero) for top-level links in a menu. if (isset($item['plid'])) { - if ($item['plid']) { - $parent = db_query("SELECT * FROM {menu_links} WHERE mlid = :mlid", array(':mlid' => $item['plid']))->fetchAssoc(); - } - else { - // Don't bother with the query - mlid can never equal zero.. - $parent = FALSE; - } + $parent = db_query("SELECT * FROM {menu_links} WHERE mlid = :mlid", array(':mlid' => $item['plid']))->fetchAssoc(); } else { $query = db_select('menu_links'); @@ -2585,10 +2585,9 @@ function menu_link_save(&$item) { if ($item['module'] == 'system') { $query->condition('module', 'system'); } - else { - // If not derived from a router item, we respect the specified menu name. - $query->condition('menu_name', $item['menu_name']); - } + // Always respect the link's menu name. Inheritance for router items is + // ensured in _menu_router_build(). + $query->condition('menu_name', $item['menu_name']); // Find the parent - it must be unique. $parent_path = $item['link_path']; @@ -2603,13 +2602,13 @@ function menu_link_save(&$item) { } } while ($parent === FALSE && $parent_path); } + // If a parent link was found, derive its menu. if ($parent !== FALSE) { $item['menu_name'] = $parent['menu_name']; } $menu_name = $item['menu_name']; - // Menu callbacks need to be in the links table for breadcrumbs, but can't - // be parents if they are generated directly from a router item. - if (empty($parent['mlid']) || $parent['hidden'] < 0) { + // If no corresponding parent link was found, move the link to the top-level. + if (empty($parent['mlid'])) { $item['plid'] = 0; } else { @@ -2636,7 +2635,7 @@ function menu_link_save(&$item) { ->execute(); } - if (!$item['plid']) { + if ($item['plid'] == 0) { $item['p1'] = $item['mlid']; for ($i = 2; $i <= MENU_MAX_DEPTH; $i++) { $item["p$i"] = 0; @@ -3054,6 +3053,15 @@ function _menu_router_build($callbacks) $parent = $menu[$parent_path]; + // Try to inherit the menu name from parent router items. + if (!isset($item['menu_name'])) { + if (!isset($parent['menu_name'])) { + $parent['menu_name'] = db_query("SELECT menu_name FROM {menu_links} WHERE router_path = :router_path", array(':router_path' => $parent_path))->fetchColumn(); + } + if (!empty($parent['menu_name'])) { + $item['menu_name'] = $parent['menu_name']; + } + } if (!isset($item['tab_parent'])) { // Parent stores the parent of the path. $item['tab_parent'] = $parent_path; Index: modules/menu/menu.module =================================================================== RCS file: /cvs/drupal/drupal/modules/menu/menu.module,v retrieving revision 1.217 diff -u -p -r1.217 menu.module --- modules/menu/menu.module 8 Nov 2009 10:02:41 -0000 1.217 +++ modules/menu/menu.module 24 Nov 2009 20:14:33 -0000 @@ -396,7 +396,12 @@ function _menu_parents_recurse($tree, $m * Reset a system-defined menu item. */ function menu_reset_item($item) { - $new_item = _menu_link_build(menu_get_item($item['router_path'])); + // To fully reset the link to its original/suggested values, we need the full + // information provided in hook_menu(); e.g. the original 'menu_name'. + $menu = menu_get_router(); + $router_item = $menu[$item['router_path']]; + $new_item = _menu_link_build($router_item); + // Merge certain properties from the current link into the reset link. foreach (array('mlid', 'has_children') as $key) { $new_item[$key] = $item[$key]; } Index: modules/menu/menu.test =================================================================== RCS file: /cvs/drupal/drupal/modules/menu/menu.test,v retrieving revision 1.26 diff -u -p -r1.26 menu.test --- modules/menu/menu.test 10 Nov 2009 17:27:53 -0000 1.26 +++ modules/menu/menu.test 24 Nov 2009 20:37:42 -0000 @@ -252,10 +252,9 @@ class MenuTestCase extends DrupalWebTest ); // Add menu link. - $this->drupalPost("admin/structure/menu/manage/$menu_name/add", $edit, t('Save')); + $this->drupalPost(NULL, $edit, t('Save')); $this->assertResponse(200); // Unlike most other modules, there is no confirmation message displayed. - $this->assertText($title, 'Menu link was added'); // Retrieve menu link. @@ -267,7 +266,10 @@ class MenuTestCase extends DrupalWebTest // We know link1 is at the top level, so $item1['deptj'] == 1 and $item1['plid'] == 0. // We know that the parent of link2 is link1, so $item2['plid'] == $item1['mlid']. // Both menu links were created in the navigation menu. - $this->assertTrue($item['menu_name'] == $menu_name && $item['plid'] == $plid && $item['link_path'] == $link && $item['link_title'] == $title, 'Menu link has correct data'); + $this->assertEqual($item['menu_name'], $menu_name); + $this->assertEqual($item['plid'], $plid); + $this->assertEqual($item['link_path'], $link); + $this->assertEqual($item['link_title'], $title); if ($plid == 0) { $this->assertTrue($item['depth'] == 1 && !$item['has_children'] && $item['p1'] == $item['mlid'] && $item['p2'] == 0, 'Menu link has correct data'); } @@ -370,9 +372,6 @@ class MenuTestCase extends DrupalWebTest // Verify menu link. $this->drupalGet(''); $this->assertNoText($title, 'Menu link was reset'); - - // Verify menu link. - $this->drupalGet(''); $this->assertText($old_title, 'Menu link was reset'); }