Index: admin_menu.js
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/admin_menu/admin_menu.js,v
retrieving revision 1.7.2.7.2.18
diff -u -p -r1.7.2.7.2.18 admin_menu.js
--- admin_menu.js	20 Feb 2010 23:44:04 -0000	1.7.2.7.2.18
+++ admin_menu.js	12 Mar 2010 05:05:34 -0000
@@ -198,22 +198,59 @@ Drupal.admin.behaviors.hover = function 
     );
   }
 
+  var maxHeight = $(window).height() - $adminMenu.height();
+  $('li.expandable > ul', $adminMenu).mousemove(function (e) {
+    // Bail out if the hovered link does not belong to this list.
+    // @todo Better way?
+    if (e.target.parentNode.parentNode != this) {
+      return;
+    }
+    var $ul = $(this);
+    var $li = $ul.parent();
+    var liOffset = $li.offset().top;
+    var liHeight = $li.height();
+    // @todo This doesn't handle child-child-child-trees.
+    var multiplier = $ul.height() / maxHeight;
+    // No animation if the tree fits into the visible viewport.
+    if (multiplier > 1) {
+      // @todo Child trees overlay parent trees.
+      // $ul.css('zIndex', -10);
+      // Based on the current cursor position, subtract vertical offset of the
+      // list item, and subtract...
+      var relativeY = e.pageY - liOffset - liHeight;
+      // Child trees below a top-level item are positioned below the item, not
+      // next to it. We therefore have to subtract the list item height.
+      if (!$li.parents('li.expandable').length) {
+        relativeY -= liHeight;
+      }
+      if (e.pageY > liOffset + liHeight) {
+        $ul.css('top', liOffset - relativeY);
+      }
+      // When reaching the bottom offset of the list item, unset the custom
+      // positioning.
+      else {
+        $ul.css('top', '');
+      }
+    }
+  });
+  return;
+
   // Delayed mouseout.
   $('li.expandable', $adminMenu).hover(
     function () {
       // Stop the timer.
       clearTimeout(this.sfTimer);
       // Display child lists.
-      $('> ul', this)
-        .css({left: 'auto', display: 'block'})
+      $ul = $('> ul', this);
+      $ul.css({left: 'auto', display: 'block'})
         // Immediately hide nephew lists.
         .parent().siblings('li').children('ul').css({left: '-999em', display: 'none'});
     },
     function () {
       // Start the timer.
-      var uls = $('> ul', this);
+      var $ul = $('> ul', this);
       this.sfTimer = setTimeout(function () {
-        uls.css({left: '-999em', display: 'none'});
+        $ul.css({left: '-999em', display: 'none'});
       }, 400);
     }
   );
