Index: dhtml_menu.module =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/dhtml_menu/dhtml_menu.module,v retrieving revision 1.40 diff -u -p -r1.40 dhtml_menu.module --- dhtml_menu.module 4 Apr 2009 07:31:30 -0000 1.40 +++ dhtml_menu.module 24 May 2009 19:39:40 -0000 @@ -57,7 +57,7 @@ function dhtml_menu_theme_menu_item_link } if (!isset($link['menu_name']) || !isset($link['mlid']) || !empty($disabled[$link['menu_name']])) { - $link['dhtml_disabled'] = TRUE; + $link['dhtml_disabled'] = TRUE; return $function($link); } @@ -77,9 +77,10 @@ function dhtml_menu_theme_menu_item_link */ function dhtml_menu_theme_menu_item($link, $has_children, $menu = '', $in_active_trail = FALSE, $extra_class = NULL) { global $theme; - static $cookie, $function; - if (!isset($cookie)) { - $cookie = explode(',', @$_COOKIE['dhtml_menu']); + static $cookie, $function, $nav; + if (!isset($nav)) { + $nav = variable_get('dhtml_menu_nav'); + $cookie = $nav != 'hover' ? explode(',', @$_COOKIE['dhtml_menu']) : array(); $registry = variable_get('dhtml_menu_theme', array()); $function = isset($registry[$theme]) && drupal_function_exists($registry[$theme]['menu_item']) ? $registry[$theme]['menu_item'] : 'theme_menu_item'; } @@ -92,15 +93,15 @@ function dhtml_menu_theme_menu_item($lin // Move to the last element in the stack (the current item). end($stack); - + // If this item should not have DHTML, then return to the "parent" function. $current = current($stack); if (!empty($current['dhtml_disabled'])) { $extra_class .= ' no-dhtml '; - + return $function($link, $has_children, $menu, $in_active_trail, $extra_class); } - + // If there are children, but they were not loaded... if ($has_children && !$menu) { // Load the tree below the current position. Index: dhtml_menu.admin.inc =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/dhtml_menu/dhtml_menu.admin.inc,v retrieving revision 1.9 diff -u -p -r1.9 dhtml_menu.admin.inc --- dhtml_menu.admin.inc 9 Nov 2008 22:32:49 -0000 1.9 +++ dhtml_menu.admin.inc 24 May 2009 19:39:40 -0000 @@ -17,6 +17,7 @@ function dhtml_menu_settings(&$form_stat '#title' => t('Static navigation'), '#options' => array( 'pseudo-child' => t('Fake child item: At the top of each submenu, an extra link will be generated that leads to the page of the parent item.'), + 'hover' => t(Hover: To expand a menu, hover your cursor over it. To visit the page, click it.'), 'bullet' => t('Link remains static: All menu links will continue to function as static links. To expand a menu, click the bullet icon next to the link.'), 'double-click' => t('Doubleclick: To expand a menu, click the link once. To navigate to the page, click it twice. This may be difficult to find for your users!'), 'none' => t('None: Clicking the link will expand the menu. Navigating to the page is not possible. This will make pages with sub-items very difficult to reach!'), @@ -24,14 +25,14 @@ function dhtml_menu_settings(&$form_stat '#default_value' => variable_get('dhtml_menu_nav', $settings['nav']), '#description' => t('Dynamic expansion of menus competes with the static navigation of content. Choose how to resolve this conflict.'), ); - + $form['animation'] = array( '#type' => 'fieldset', '#title' => t('Animation'), '#collapsible' => TRUE, '#collapsed' => TRUE, ); - + $form['animation']['dhtml_menu_animations'] = array( '#type' => 'checkboxes', '#title' => t('Effects'), @@ -43,7 +44,7 @@ function dhtml_menu_settings(&$form_stat '#description' => t('You may pick any number of animation effects that will accompany the opening and closing of a menu.'), '#default_value' => variable_get('dhtml_menu_animations', $settings['animations']), ); - + $form['animation']['dhtml_menu_speed'] = array( '#type' => 'select', '#title' => t('Speed'), @@ -51,14 +52,14 @@ function dhtml_menu_settings(&$form_stat '#default_value' => variable_get('dhtml_menu_speed', $settings['speed']), '#description' => t('Choose how quickly the menus should expand and collapse.'), ); - + $form['effects'] = array( '#type' => 'fieldset', '#title' => t('Other effects'), '#collapsible' => TRUE, '#collapsed' => TRUE, ); - + $form['effects']['dhtml_menu_siblings'] = array( '#type' => 'radios', '#title' => t('When a menu opens'), @@ -69,7 +70,7 @@ function dhtml_menu_settings(&$form_stat ), '#default_value' => variable_get('dhtml_menu_siblings', $settings['siblings']), ); - + $form['effects']['dhtml_menu_children'] = array( '#type' => 'radios', '#title' => t('When a menu closes'), Index: dhtml_menu.js =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/dhtml_menu/dhtml_menu.js,v retrieving revision 1.26 diff -u -p -r1.26 dhtml_menu.js --- dhtml_menu.js 10 Apr 2009 17:26:18 -0000 1.26 +++ dhtml_menu.js 24 May 2009 19:39:40 -0000 @@ -5,7 +5,7 @@ * @file dhtml_menu.js * The Javascript code for DHTML Menu */ - + Drupal.dhtmlMenu = {}; /** @@ -21,9 +21,10 @@ Drupal.behaviors.dhtmlMenu = { else { Drupal.dhtmlMenu.init = true; }*/ - + var nav = Drupal.settings.dhtmlMenu.nav; $('.collapsed').removeClass('expanded'); - var cookie = Drupal.dhtmlMenu.cookieGet(); + + if (nav != 'hover') var cookie = Drupal.dhtmlMenu.cookieGet(); for (var i in cookie) { // If the cookie was not applied to the HTML code yet, do so now. var li = $('#dhtml_menu-' + cookie[i]).parents('li:first'); @@ -31,14 +32,32 @@ Drupal.behaviors.dhtmlMenu = { Drupal.dhtmlMenu.toggleMenu(li); } } - - var nav = Drupal.settings.dhtmlMenu.nav; - + + /* Relevant only when hovering: + * + * If a context menu is opened (as most users do when opening links in a + * new tab), the mouseleave event will be triggered. Although the context + * menu would still work, having the menu close underneath it is confusing. + * + * This code will "freeze" the menu's collapse if the body is left + * (which a context menu causes), and only release it when the cursor + * reenters the menu. + * + * Note that due to event bubbling, the collapse must work asynchronously + * to make sure this event is triggered before the collapse. + */ + var freeze = false; + if (nav == 'hover') { + $('ul.menu').mouseenter(function() {freeze = false}); + $('body').mouseleave(function() {freeze = true}); + } + /* Add jQuery effects and listeners to all menu items. - * The ~ (sibling) selector is unidirectional and selects - * only the latter element, so we must use siblings() to get - * back to the link element. + * The ~ (sibling) selector is unidirectional and selects + * only the latter element, so we must use siblings() to get + * back to the link element. */ + $('ul.menu li:not(.leaf,.no-dhtml)').each(function() { if (nav == 'pseudo-child') { var ul = $(this).find('ul:first'); @@ -46,22 +65,42 @@ Drupal.behaviors.dhtmlMenu = { $(this).find('a:first').clone().prependTo(ul).wrap('
  • '); } } - - if (nav == 'doubleclick') { + else if (nav == 'doubleclick') { $(this).dblclick(function(e) { window.location = $(this).find('a:first').attr('href'); e.stopPropagation(); }); } - - $(this).click(function(e) { - Drupal.dhtmlMenu.toggleMenu(this); - e.stopPropagation(); - return false; - }); + + if (nav == 'hover') { + var li = this; + $(this).find('a:first').mouseenter(function(e) { + Drupal.dhtmlMenu.switchMenu(li, true); + }); + $(this).mouseleave(function(e) { + if ($(this).hasClass('start-collapsed')) { + var li = this; + /* As explained earlier, this event fires before the body event. + * We need to wait to make sure that the user isn't browsing a + * context menu right now, in which case the menu isn't collapsed. + */ + setTimeout(function() { + if (!freeze) Drupal.dhtmlMenu.switchMenu(li, false); + }, 10); + } + }); + } + else { + $(this).click(function(e) { + Drupal.dhtmlMenu.toggleMenu(this); + e.stopPropagation(); + return false; + }); + } + }); - - if (nav == 'bullet') { + + if (nav == 'bullet' || nav == 'hover') { $('ul.menu a').click(function(e) { e.stopPropagation(); return true; @@ -82,23 +121,18 @@ Drupal.behaviors.dhtmlMenu = { * Object. The
  • element that will be expanded or collapsed. */ Drupal.dhtmlMenu.toggleMenu = function(li) { - var effects = Drupal.settings.dhtmlMenu; + // make it open if closed, close if open. + Drupal.dhtmlMenu.switchMenu(li, !$(li).hasClass('expanded')); +} - // If the menu is expanded, collapse it. - if($(li).hasClass('expanded')) { - Drupal.dhtmlMenu.animate($(li).find('ul:first'), 'hide'); - - // If children are closed automatically, find and close them now. - if (effects.children == 'close-children') { - Drupal.dhtmlMenu.animate($(li).find('li.expanded').find('ul:first'), 'hide'); - $(li).find('li.expanded').removeClass('expanded').addClass('collapsed') - } +Drupal.dhtmlMenu.switchMenu = function(li, toggle) { + if (toggle == $(li).hasClass('expanded')) return; // No need for switching. - $(li).removeClass('expanded').addClass('collapsed'); - } + var effects = Drupal.settings.dhtmlMenu; - // Otherwise, expand it. - else { + // Expand it + if (toggle) + { Drupal.dhtmlMenu.animate($(li).find('ul:first'), 'show'); $(li).removeClass('collapsed').addClass('expanded'); @@ -134,6 +168,20 @@ Drupal.dhtmlMenu.toggleMenu = function(l } } + // Otherwise, collapse it. + else + { + Drupal.dhtmlMenu.animate($(li).find('ul:first'), 'hide'); + + // If children are closed automatically, find and close them now. + if (effects.children == 'close-children') { + Drupal.dhtmlMenu.animate($(li).find('li.expanded').find('ul:first'), 'hide'); + $(li).find('li.expanded').removeClass('expanded').addClass('collapsed') + } + + $(li).removeClass('expanded').addClass('collapsed'); + } + // Save the current state of the menus in the cookie. Drupal.dhtmlMenu.cookieSet(); } @@ -141,18 +189,18 @@ Drupal.dhtmlMenu.toggleMenu = function(l Drupal.dhtmlMenu.animate = function(ul, open) { var settings = Drupal.settings.dhtmlMenu; var effects = {}; - + for (effect in settings.animations) { if (eval("settings.animations." + effect)) { eval("effects." + effect + " = open"); } } - + //alert(effects); if (effects) { $(ul).animate(effects, settings.speed * 1); } - else $(ul).css('display', open == 'show' ? 'block' : 'none'); + else $(ul).css('display', open == 'show' ? 'block' : 'none'); } /**