Index: includes/menu.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/menu.inc,v
retrieving revision 1.407
diff -u -9 -p -r1.407 menu.inc
--- includes/menu.inc	23 Aug 2010 23:38:06 -0000	1.407
+++ includes/menu.inc	25 Aug 2010 21:59:08 -0000
@@ -1036,53 +1036,57 @@ function menu_tree_all_data($menu_name, 
 }
 
 /**
  * Get the data structure representing a named menu tree, based on the current page.
  *
  * The tree order is maintained by storing each parent in an individual
  * field, see http://drupal.org/node/141866 for more.
  *
  * @param $menu_name
- *   The named menu links to return
+ *   The named menu links to return.
  * @param $max_depth
  *   Optional maximum depth of links to retrieve.
+ * @param $only_active_trail
+ *   Only return the items in the active trail instead of all items on every
+ *   level of the trail.
  *
  * @return
  *   An array of menu links, in the order they should be rendered. The array
  *   is a list of associative arrays -- these have two keys, link and below.
  *   link is a menu item, ready for theming as a link. Below represents the
  *   submenu below the link if there is one, and it is a subtree that has the
  *   same structure described for the top-level array.
  */
-function menu_tree_page_data($menu_name, $max_depth = NULL) {
+function menu_tree_page_data($menu_name, $max_depth = NULL, $only_active_trail = FALSE) {
   $tree = &drupal_static(__FUNCTION__, array());
 
   // Load the menu item corresponding to the current page.
   if ($item = menu_get_item()) {
     if (isset($max_depth)) {
       $max_depth = min($max_depth, MENU_MAX_DEPTH);
     }
     // Generate a cache ID (cid) specific for this page.
-    $cid = 'links:' . $menu_name . ':page-cid:' . $item['href'] . ':' . $GLOBALS['language']->language . ':' . (int) $item['access'] . ':' . (int) $max_depth;
+    $cid = 'links:' . $menu_name . ':page-cid:' . $item['href'] . ':' . $GLOBALS['language']->language . ':' . (int) $item['access'] . ':' . (int) $max_depth . ':' . (int) $only_active_trail;
 
     if (!isset($tree[$cid])) {
       // If the static variable doesn't have the data, check {cache_menu}.
       $cache = cache_get($cid, 'cache_menu');
       if ($cache && isset($cache->data)) {
         // If the cache entry exists, it contains the parameters for
         // menu_build_tree().
         $tree_parameters = $cache->data;
       }
       // If the tree data was not in the cache, build $tree_parameters.
       if (!isset($tree_parameters)) {
         $tree_parameters = array(
           'min_depth' => 1,
           'max_depth' => $max_depth,
+          'only_active_trail' => $only_active_trail,
         );
         // If the item for the current page is accessible, build the tree
         // parameters accordingly.
         if ($item['access']) {
           // Check whether a menu link exists that corresponds to the current path.
           $args[] = $item['href'];
           if (drupal_is_front_page()) {
             $args[] = '<front>';
           }
@@ -1122,45 +1126,48 @@ function menu_tree_page_data($menu_name,
 
           // We always want all the top-level links with plid == 0.
           $active_link[] = '0';
 
           // Use array_values() so that the indices are numeric.
           $parents = $active_link = array_unique(array_values($active_link));
 
           $expanded = variable_get('menu_expanded', array());
           // Check whether the current menu has any links set to be expanded.
-          if (in_array($menu_name, $expanded)) {
+          if (in_array($menu_name, $expanded) && !$only_active_trail) {
             // Collect all the links set to be expanded, and then add all of
             // their children to the list as well.
             do {
               $result = db_select('menu_links', NULL, array('fetch' => PDO::FETCH_ASSOC))
                 ->fields('menu_links', array('mlid'))
                 ->condition('menu_name', $menu_name)
                 ->condition('expanded', 1)
                 ->condition('has_children', 1)
                 ->condition('plid', $parents, 'IN')
                 ->condition('mlid', $parents, 'NOT IN')
                 ->execute();
               $num_rows = FALSE;
               foreach ($result as $item) {
                 $parents[] = $item['mlid'];
                 $num_rows = TRUE;
               }
             } while ($num_rows);
           }
-          $tree_parameters['expanded'] = $parents;
-          $tree_parameters['active_trail'] = $active_link;
         }
         // Otherwise, only show the top-level menu items when access is denied.
         else {
-          $tree_parameters['expanded'] = array(0);
+          $parents = $active_link = array(0);
         }
 
+        if (!$only_active_trail) {
+          $tree_parameters['expanded'] = $parents;
+        }
+        $tree_parameters['active_trail'] = $active_link;
+
         // Cache the tree building parameters using the page-specific cid.
         cache_set($cid, $tree_parameters, 'cache_menu');
       }
 
       // Build the tree using the parameters; the resulting tree will be cached
       // by _menu_build_tree().
       $tree[$cid] = menu_build_tree($menu_name, $tree_parameters);
     }
     return $tree[$cid];
@@ -1172,21 +1179,23 @@ function menu_tree_page_data($menu_name,
 /**
  * Build a menu tree, translate links, and check access.
  *
  * @param $menu_name
  *   The name of the menu.
  * @param $parameters
  *   (optional) An associative array of build parameters. Possible keys:
  *   - expanded: An array of parent link ids to return only menu links that are
  *     children of one of the plids in this list. If empty, the whole menu tree
- *     is built.
+ *     is built, unless 'only_active_trail' is TRUE.
  *   - active_trail: An array of mlids, representing the coordinates of the
  *     currently active menu link.
+ *   - only_active_trail: Whether to return only menu links that are in the
+ *     active trail. This option is ignored, if 'expanded' is non-empty.
  *   - min_depth: The minimum depth of menu links in the resulting tree.
  *     Defaults to 1, which is the default to build a whole tree for a menu, i.e.
  *     excluding menu container itself.
  *   - max_depth: The maximum depth of menu links in the resulting tree.
  *
  * @return
  *   A fully built menu tree.
  */
 function menu_build_tree($menu_name, array $parameters = array()) {
@@ -1250,18 +1259,21 @@ function _menu_build_tree($menu_name, ar
       'description',
     ));
     for ($i = 1; $i <= MENU_MAX_DEPTH; $i++) {
       $query->orderBy('p' . $i, 'ASC');
     }
     $query->condition('ml.menu_name', $menu_name);
     if (!empty($parameters['expanded'])) {
       $query->condition('ml.plid', $parameters['expanded'], 'IN');
     }
+    elseif (!empty($parameters['only_active_trail'])) {
+      $query->condition('ml.mlid', $parameters['active_trail'], 'IN');
+    }
     $min_depth = (isset($parameters['min_depth']) ? $parameters['min_depth'] : 1);
     if ($min_depth != 1) {
       $query->condition('ml.depth', $min_depth, '>=');
     }
     if (isset($parameters['max_depth'])) {
       $query->condition('ml.depth', $parameters['max_depth'], '<=');
     }
 
     // Build an ordered array of links using the query result object.
@@ -2166,19 +2178,19 @@ function menu_set_active_trail($new_trai
       $result = $query->execute();
       $found = array();
       foreach ($result as $menu) {
         $found[] = $menu->menu_name;
       }
       // The $menu_names array is ordered, so take the first one that matches.
       $found_menu_names = array_intersect($menu_names, $found);
       $name = current($found_menu_names);
       if ($name !== FALSE) {
-        $tree = menu_tree_page_data($name);
+        $tree = menu_tree_page_data($name, NULL, TRUE);
         list($key, $curr) = each($tree);
       }
     }
 
     while ($curr) {
       // Terminate the loop when we find the current path in the active trail.
       if ($curr['link']['href'] == $item['href']) {
         $trail[] = $curr['link'];
         $curr = FALSE;
