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 19:20:12 -0000 @@ -198,22 +198,63 @@ Drupal.admin.behaviors.hover = function ); } + var maxHeight = $(window).height() - $adminMenu.height(); + $('li.expandable > ul', $adminMenu).mousemove(function (e) { + // Don't move if the hovered link does not belong to this list. + // @todo Better way? Heavily hard-codes current theme markup. + if (e.target.parentNode.parentNode != this) { + return; + } + // Stop moving when hovering expandable parent items. + // @todo Adjust relativeY based on amount of (direct) preceding expandable items. + if ($(e.target.parentNode).is('.expandable')) { + return; + } + var $ul = $(this); + var $li = $ul.parent(); + var liOffset = $li.offset().top; + var liHeight = $li.height(); + // No animation if the tree fits into the visible viewport. + if (liOffset + $ul.height() > maxHeight) { + // @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', ''); + } + } + }); + // @todo Delayed mouseout needs to be put back in, resp. see hoverIntent issue. + 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); } ); Index: admin_menu.module =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/admin_menu/admin_menu.module,v retrieving revision 1.43.2.17.2.30 diff -u -p -r1.43.2.17.2.30 admin_menu.module --- admin_menu.module 20 Feb 2010 01:02:58 -0000 1.43.2.17.2.30 +++ admin_menu.module 12 Mar 2010 21:33:44 -0000 @@ -82,6 +82,51 @@ function admin_menu_menu() { 'type' => MENU_CALLBACK, 'file' => 'admin_menu.inc', ); + + $items['admin/test'] = array( + 'title' => 'Dropdown test', + 'access arguments' => array('administer site configuration'), + ); + $factor = 100; + foreach (range(1, 40) as $l1) { + $items["admin/test/$l1"] = array( + 'title' => "{$l1}th-level item", + 'access callback' => TRUE, + ); + if (rand(0, 200) >= $factor) { + foreach (range(1, 6) as $l2) { + $items["admin/test/$l1/$l2"] = array( + 'title' => "{$l2}th-level item", + 'access callback' => TRUE, + ); + if (rand(0, 150) >= $factor) { + foreach (range(1, 6) as $l3) { + $items["admin/test/$l1/$l2/$l3"] = array( + 'title' => "{$l3}th-level item", + 'access callback' => TRUE, + ); + if (rand(0, 130) >= $factor) { + foreach (range(1, 6) as $l4) { + $items["admin/test/$l1/$l2/$l3/$l4"] = array( + 'title' => "{$l4}th-level item", + 'access callback' => TRUE, + ); + if (rand(0, 110) >= $factor) { + foreach (range(1, 10) as $l5) { + $items["admin/test/$l1/$l2/$l3/$l4/$l5"] = array( + 'title' => "{$l5}th-level item", + 'access callback' => TRUE, + ); + } + } + } + } + } + } + } + } + } + return $items; }