Index: admin_menu.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/admin_menu/admin_menu.inc,v
retrieving revision 1.47
diff -u -p -r1.47 admin_menu.inc
--- admin_menu.inc	9 Jun 2009 18:21:03 -0000	1.47
+++ admin_menu.inc	11 Jun 2009 18:10:35 -0000
@@ -302,76 +302,48 @@ function admin_menu_admin_menu(&$deleted
  * @param $menu_links
  *   An array containing the complete administration menu structure, passed by
  *   reference.
- * @param $sort
- *   An array containing the # parts of each link - must be updated if a link
- *   is added.
  *
  * @return
  *   An array of links that were removed from $menu_links.
  */
-function admin_menu_adjust_items(&$menu_links, &$sort) {
-  global $user;
-  $links = array();
-  $deleted = array();
-
-  // Change or remove items, or add new top-level items.
-  $deleted['admin/by-module'] = $menu_links['admin/by-module'];
-  unset($menu_links['admin/by-module'], $sort['admin/by-module']);
-  $deleted['admin/by-task'] = $menu_links['admin/by-task'];
-  unset($menu_links['admin/by-task'], $sort['admin/by-task']);
-
-  // Remove certain links to re-position them in admin_menu_admin_menu().
-  foreach ($menu_links as $path => $link) {
-    // Remove links below
-    // - admin/build/node-type/*
-    // - node/add*
-    if (strpos($path, 'admin/build/node-type/') !== FALSE || strpos($path, 'node/add') !== FALSE) {
-      $deleted[$path] = $link;
-      unset($menu_links[$path], $sort[$path]);
-    }
-  }
+function admin_menu_adjust_items() {
   // Add the icon containing special links.
-  $links[] = array(
-    'title' => theme('admin_menu_icon'),
-    'path' => '<front>',
-    'weight' => -100,
-    'parent_path' => '<root>',
-    'options' => array('extra class' => 'admin-menu-icon', 'html' => TRUE),
+  $links['<front>'] = array(
+    '#title' => theme('admin_menu_icon'),
+    #'#weight' => 0,
+    '#attributes' => array('class' => 'admin-menu-icon'),
+    '#options' => array(
+      'html' => TRUE,
+    ),
   );
   // Add link to show current authenticated/anonymous users - we will add the
   // data dynamically in the _alter hook.
-  $links[] = array(
-    'title' => admin_menu_get_user_count(),
-    'description' => t('Current anonymous / authenticated users'),
-    'path' => 'user',
-    'weight' => -90,
-    'parent_path' => '<root>',
-    'options' => array('extra class' => 'admin-menu-action admin-menu-users'),
-  );
-  $links[] = array(
-    'title' => '@username',
-    'path' => 'user/%',
-    'weight' => -99,
-    'parent_path' => '<root>',
+  $links['user'] = array(
+    '#title' => admin_menu_get_user_count(),
+    '#description' => t('Current anonymous / authenticated users'),
+    '#weight' => -90,
+    '#attributes' => array('class' => 'admin-menu-action admin-menu-users'),
+    '#options' => array(
+    ),
+  );
+  $links['user/%'] = array(
+    '#title' => '@username',
+    '#weight' => -99,
+    '#attributes' => array('class' => 'admin-menu-action'),
     // Note: @username is dynamically replaced by default, we just invoke
     // replacement by setting the 't' key here.
-    'options' => array('extra class' => 'admin-menu-action', 't' => array()),
+    '#options' => array(
+      't' => array(),
+    ),
+  );
+  $links['user/logout'] = array(
+    '#title' => 'Log out',
+    '#weight' => -100,
+    '#attributes' => array('class' => 'admin-menu-action'),
+    '#options' => array(
+    ),
   );
-  $links[] = array(
-    'title' => 'Log out',
-    'path' => 'user/logout',
-    'weight' => -100,
-    'parent_path' => '<root>',
-    'options' => array('extra class' => 'admin-menu-action'),
-  );
-  foreach ($links as $item) {
-    $path = $item['path'];
-    $item = admin_menu_link_build($item);
-    $menu_links[$path] = $item;
-    $sort[$path] = 1;
-  }
-
-  return $deleted;
+  return $links;
 }
 
 /**
@@ -418,10 +390,6 @@ function admin_menu_theme_settings() {
  * Wipe the menu so it can be rebuilt from scratch.
  */
 function admin_menu_flush_caches() {
-  // Flush cached menu tree.
-  db_delete('menu_links')->condition('menu_name', 'admin_menu')->execute();
-  menu_cache_clear('admin_menu');
-  variable_set('admin_menu_rebuild_links', TRUE);
   // Flush cached output of admin_menu.
   cache_clear_all('admin_menu:', 'cache_menu', TRUE);
   // Flush client-side cache hashes.
@@ -533,7 +501,13 @@ function admin_menu_toggle_modules() {
 function admin_menu_flush_cache($name = NULL) {
   switch ($name) {
     case 'admin_menu':
-      admin_menu_flush_caches();
+      // Flush cached menu tree.
+      db_delete('menu_links')
+        ->condition('menu_name', 'admin_menu')
+        ->condition('customized', 0)
+        ->execute();
+      menu_cache_clear('admin_menu');
+      menu_rebuild();
       break;
 
     case 'cache':
@@ -547,7 +521,7 @@ function admin_menu_flush_cache($name = 
       break;
 
     case 'menu':
-      module_invoke('menu', 'rebuild');
+      menu_rebuild();
       break;
 
     case 'registry':
Index: admin_menu.install
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/admin_menu/admin_menu.install,v
retrieving revision 1.15
diff -u -p -r1.15 admin_menu.install
--- admin_menu.install	18 Apr 2009 17:24:56 -0000	1.15
+++ admin_menu.install	11 Jun 2009 00:56:12 -0000
@@ -16,6 +16,7 @@ function admin_menu_schema() {
 function admin_menu_install() {
   // Create cache table.
   drupal_install_schema('admin_menu');
+  db_query("INSERT INTO {menu_custom} (menu_name, title, description) VALUES ('admin_menu', 'Administration menu', '')");
 }
 
 /**
@@ -83,3 +84,16 @@ function admin_menu_update_7300() {
   db_create_table($ret, 'cache_admin_menu', $schema);
   return $ret;
 }
+
+/**
+ * Add "admin_menu" menu.
+ */
+function admin_menu_update_7301() {
+  $ret = array();
+  if (db_query("SELECT menu_name FROM {menu_custom} WHERE menu_name = 'admin_menu'")->fetchField()) {
+    return $ret;
+  }
+  $ret[] = update_sql("INSERT INTO {menu_custom} (menu_name, title, description) VALUES ('admin_menu', 'Administration menu', '')");
+  return $ret;
+}
+
Index: admin_menu.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/admin_menu/admin_menu.module,v
retrieving revision 1.73
diff -u -p -r1.73 admin_menu.module
--- admin_menu.module	11 Jun 2009 01:39:20 -0000	1.73
+++ admin_menu.module	11 Jun 2009 18:09:44 -0000
@@ -48,6 +48,9 @@ function admin_menu_perm() {
  */
 function admin_menu_theme() {
   return array(
+    'admin_menu_links' => array(
+      'arguments' => array('elements' => array()),
+    ),
     'admin_menu_icon' => array(
       'arguments' => array(),
     ),
@@ -59,6 +62,7 @@ function admin_menu_theme() {
  */
 function admin_menu_menu() {
   // AJAX callback.
+  // @see http://drupal.org/project/js
   $items['js/admin_menu/cache'] = array(
     'page callback' => 'admin_menu_js_cache',
     'access arguments' => array('access administration menu'),
@@ -87,6 +91,44 @@ function admin_menu_menu() {
 }
 
 /**
+ * Implementation of hook_menu_alter().
+ */
+function admin_menu_menu_alter(&$items) {
+  // Move all items below admin/* into administration menu.
+  foreach ($items as $path => $item) {
+    if (strpos($path, 'admin') === 0) {
+      if (!isset($item['type'])) {
+        $items[$path]['menu_name'] = 'admin_menu';
+      }
+      else {
+        if ($item['type'] & MENU_IS_LOCAL_TASK) {
+          // Work around a core bug, which defines local tasks below menu
+          // callbacks (e.g. for admin/build/node-type/article/edit).
+          $parent = explode('/', $path);
+          array_pop($parent);
+          $parent = implode('/', $parent);
+          if (isset($items[$parent]['type']) && $items[$parent]['type'] & MENU_CALLBACK) {
+            continue;
+          }
+          // Trick this item into the visible menu tree.
+          $items[$path]['_visible'] = TRUE;
+        }
+        if ($item['type'] & MENU_CALLBACK) {
+          continue;
+        }
+        $items[$path]['menu_name'] = 'admin_menu';
+      }
+    }
+  }
+
+  // Remove 'admin', so children appear on the top-level.
+  $items['admin']['_visible'] = FALSE;
+  // Remove local tasks on 'admin'.
+  $items['admin/by-task']['_visible'] = FALSE;
+  $items['admin/by-module']['_visible'] = FALSE;
+}
+
+/**
  * Implementation of hook_init().
  *
  * We can't move this into admin_menu_footer(), because PHP-only based themes
@@ -174,67 +216,9 @@ function admin_menu_suppress($set = TRUE
 
 /**
  * Implementation of hook_footer().
- *
- * @todo Since admin_menu is rebuilt in the same request, we should be able
- *   to use a helper function instead of a variable to remind us to rebuild
- *   (variable_set() is slow).
  */
 function admin_menu_footer($main = 0) {
-  if (!user_access('access administration menu') || admin_menu_suppress(FALSE)) {
-    return;
-  }
-  global $user, $language;
-
-  $cache_server_enabled = variable_get('admin_menu_cache_server', TRUE);
-
-  // Determine whether we need to rebuild.
-  $rebuild = variable_get('admin_menu_rebuild_links', FALSE);
-  $cid = 'admin_menu:' . $user->uid . ':' . $language->language;
-
-  // Do nothing at all here if the client supports client-side caching, no
-  // rebuild is needed, the user has a hash, and is NOT requesting the cache
-  // update path. Consult the hash cache last, since it requires a DB request.
-  // @todo Implement a sanity-check to prevent permanent double requests; i.e.
-  //   what if the client-side cache fails for any reason and performs a second
-  //   request on every page?
-  if (!empty($_COOKIE['has_js']) && !$rebuild && strpos($_GET['q'], 'js/admin_menu/cache') !== 0) {
-    if (admin_menu_cache_get($cid)) {
-      return;
-    }
-  }
-
-  // Check for the flag indicating that we need to rebuild the menu.
-  if ($rebuild) {
-    module_load_include('inc', 'admin_menu');
-    _admin_menu_rebuild_links();
-    variable_del('admin_menu_rebuild_links');
-  }
-  // Try to load and output administration menu from server-side cache.
-  elseif ($cache_server_enabled) {
-    $cache = cache_get($cid, 'cache_menu');
-    if ($cache && isset($cache->data)) {
-      $content = $cache->data;
-    }
-  }
-
-  // Rebuild the output.
-  if (!isset($content)) {
-    $content  = '<div id="admin-menu">';
-    $content .= admin_menu_tree_output(menu_tree_all_data('admin_menu'));
-    $content .= '</div>';
-
-    // Cache the menu for this user.
-    if ($cache_server_enabled) {
-      cache_set($cid, $content, 'cache_menu');
-    }
-  }
-
-  // Store the new hash for this user.
-  if (!empty($_COOKIE['has_js'])) {
-    admin_menu_cache_set($cid, md5($content));
-  }
-
-  return $content;
+  return admin_menu_output();
 }
 
 /**
@@ -284,7 +268,7 @@ function admin_menu_cache_set($cid, $dat
  * Menu callback; Output administration menu for HTTP caching via AJAX request.
  */
 function admin_menu_js_cache($hash = NULL) {
-  // Fetch the menu.
+  // Get the rendered menu.
   $content = admin_menu_footer();
 
   // @todo According to http://www.mnot.net/blog/2006/05/11/browser_caching,
@@ -341,6 +325,96 @@ function admin_menu_get_user_count() {
 }
 
 /**
+ * Build the administration menu output.
+ *
+ * @todo Since admin_menu is rebuilt in the same request, we should be able
+ *   to use a helper function instead of a variable to remind us to rebuild
+ *   (variable_set() is slow).
+ */
+function admin_menu_output() {
+  if (!user_access('access administration menu') || admin_menu_suppress(FALSE)) {
+    return;
+  }
+  global $user, $language;
+
+  $cache_server_enabled = variable_get('admin_menu_cache_server', TRUE);
+
+  // Determine whether we need to rebuild.
+  $rebuild = variable_get('admin_menu_rebuild_links', FALSE);
+  $cid = 'admin_menu:' . $user->uid . ':' . $language->language;
+
+  // Do nothing at all here if the client supports client-side caching, no
+  // rebuild is needed, the user has a hash, and is NOT requesting the cache
+  // update path. Consult the hash cache last, since it requires a DB request.
+  // @todo Implement a sanity-check to prevent permanent double requests; i.e.
+  //   what if the client-side cache fails for any reason and performs a second
+  //   request on every page?
+  if (!empty($_COOKIE['has_js']) && !$rebuild && strpos($_GET['q'], 'js/admin_menu/cache') !== 0) {
+    if (admin_menu_cache_get($cid)) {
+      return;
+    }
+  }
+
+  // Check for the flag indicating that we need to rebuild the menu.
+  if (0 && $rebuild) {
+    module_load_include('inc', 'admin_menu');
+    _admin_menu_rebuild_links();
+    variable_del('admin_menu_rebuild_links');
+  }
+  // Try to load and output administration menu from server-side cache.
+  elseif ($cache_server_enabled) {
+    $cache = cache_get($cid, 'cache_menu');
+    if ($cache && isset($cache->data)) {
+      $content = $cache->data;
+    }
+  }
+
+  // Rebuild the output.
+  if (!isset($content)) {
+    // @todo Always output container to harden JS-less support.
+    $content['#prefix'] = '<div id="admin-menu">';
+    $content['#suffix'] = '</div>';
+
+    module_load_include('inc', 'admin_menu');
+    $content['links'] = array(
+      '#theme' => 'admin_menu_links',
+    );
+    $content['links'] += admin_menu_adjust_items();
+
+    // @todo How can we use #theme here?
+    $content['menu'] = array(
+      '#markup' => admin_menu_tree_output(menu_tree_all_data('admin_menu')),
+    );
+
+    drupal_alter('admin_menu_output', $content);
+    $content = drupal_render($content);
+
+    // Cache the menu for this user.
+    if ($cache_server_enabled) {
+      cache_set($cid, $content, 'cache_menu');
+    }
+  }
+
+  // Store the new hash for this user.
+  if (!empty($_COOKIE['has_js'])) {
+    admin_menu_cache_set($cid, md5($content));
+  }
+
+  return $content;
+}
+
+function theme_admin_menu_links(&$elements) {
+  $output = '';
+  foreach (element_children($elements, TRUE) as $path) {
+    $output .= '<li' . drupal_attributes($elements[$path]['#attributes']) . '>';
+    $output .= l($elements[$path]['#title'], $path, $elements[$path]['#options']);
+    $output .= theme('admin_menu_links', $elements[$path]);
+    $output .= '</li>';
+  }
+  return '<ul' . drupal_attributes($elements['#attributes']) . '>' . $output . '</ul>';
+}
+
+/**
  * Return a rendered menu tree.
  *
  * @param $tree
@@ -354,6 +428,11 @@ function admin_menu_tree_output($tree) {
   $output = '';
 
   foreach ($tree as $data) {
+    // Skip dynamic items.
+    if (isset($data['link']['type']) && $data['link']['type'] == MENU_CALLBACK) {
+      continue;
+    }
+    // @todo Obsolete.
     $extra_class = isset($data['link']['localized_options']['extra class']) ? $data['link']['localized_options']['extra class'] : NULL;
     $link = admin_menu_item_link($data['link']);
 
@@ -434,13 +513,6 @@ function theme_admin_menu_item($link, $h
 }
 
 /**
- * Implementation of hook_menu_alter().
- */
-function admin_menu_menu_alter() {
-  variable_set('admin_menu_rebuild_links', TRUE);
-}
-
-/**
  * Implementation of hook_translated_menu_link_alter().
  *
  * Here is where we make changes to links that need dynamic information such
