| 1 |
// $Id: dhtml_menu.js,v 1.46 2009/10/25 14:32:36 arancaytar Exp $
|
| 2 |
|
| 3 |
/**
|
| 4 |
* @file dhtml_menu.js
|
| 5 |
* The Javascript code for DHTML Menu
|
| 6 |
*/
|
| 7 |
|
| 8 |
|
| 9 |
(function($) {
|
| 10 |
Drupal.dhtmlMenu = {};
|
| 11 |
Drupal.dhtmlMenu.animation = {show:{}, hide:{}, count:0};
|
| 12 |
|
| 13 |
/**
|
| 14 |
* Initialize the module's JS functions
|
| 15 |
*/
|
| 16 |
Drupal.behaviors.dhtmlMenu = {
|
| 17 |
attach: function() {
|
| 18 |
var settings = Drupal.settings.dhtmlMenu;
|
| 19 |
|
| 20 |
// Initialize the animation effects from the settings.
|
| 21 |
for (i in settings.animation.effects) {
|
| 22 |
if (settings.animation.effects[i]) {
|
| 23 |
Drupal.dhtmlMenu.animation.show[i] = 'show';
|
| 24 |
Drupal.dhtmlMenu.animation.hide[i] = 'hide';
|
| 25 |
Drupal.dhtmlMenu.animation.count++;
|
| 26 |
}
|
| 27 |
}
|
| 28 |
|
| 29 |
// Sanitize by removing "expanded" on menus already marked "collapsed".
|
| 30 |
$('li.dhtml-menu.collapsed.expanded').removeClass('expanded');
|
| 31 |
|
| 32 |
/* Relevant only on "open-only" menus:
|
| 33 |
* The links of expanded items should be marked for emphasis.
|
| 34 |
*/
|
| 35 |
if (settings.nav == 'open') {
|
| 36 |
$('li.dhtml-menu.expanded').addClass('dhtml-menu-open');
|
| 37 |
}
|
| 38 |
|
| 39 |
/* Relevant only when hovering:
|
| 40 |
*
|
| 41 |
* If a context menu is opened (as most users do when opening links in a
|
| 42 |
* new tab), the mouseleave event will be triggered. Although the context
|
| 43 |
* menu still works, having the menu close underneath it is confusing.
|
| 44 |
*
|
| 45 |
* This code will "freeze" the menu's collapse if the body is left
|
| 46 |
* (which happens when a context menu opens), and only release it when the cursor
|
| 47 |
* reenters the menu.
|
| 48 |
*
|
| 49 |
* Note that due to the order in which events are called,
|
| 50 |
* the hovering collapse must work asynchronously so
|
| 51 |
* this event is triggered before the collapse.
|
| 52 |
*/
|
| 53 |
else if (settings.nav == 'hover') {
|
| 54 |
var freeze = false;
|
| 55 |
$('ul.menu').mouseenter(function() {freeze = false});
|
| 56 |
$('body').mouseleave(function() {freeze = true});
|
| 57 |
}
|
| 58 |
|
| 59 |
/* Relevant only on bullet-icon expansion:
|
| 60 |
* Create the markup for the bullet overlay, and the amount to shift it to the right in RTL mode.
|
| 61 |
*/
|
| 62 |
else if (settings.nav == 'bullet') {
|
| 63 |
var bullet = $('<a href="#" class="dhtml-menu-icon"></a>');
|
| 64 |
var rtl = $('html').attr('dir') == 'rtl' ? Math.ceil($('.menu li').css('margin-right').replace('px', '')) + 1 : 0;
|
| 65 |
}
|
| 66 |
|
| 67 |
/* Relevant only when adding cloned links:
|
| 68 |
* Create the markup for the cloned list item container.
|
| 69 |
*/
|
| 70 |
else if (settings.nav == 'clone') {
|
| 71 |
// Note: a single long class is used here to avoid matching the .dhtml-menu.leaf selector later on.
|
| 72 |
var cloned = $('<li class="leaf dhtml-menu-cloned-leaf"></li>');
|
| 73 |
}
|
| 74 |
|
| 75 |
/* Add jQuery effects and listeners to all menu items. */
|
| 76 |
$('ul.menu li.dhtml-menu:not(.leaf)').each(function() {
|
| 77 |
var li = $(this);
|
| 78 |
var link = $(this).find('a:first');
|
| 79 |
var ul = $(this).find('ul:first');
|
| 80 |
|
| 81 |
// Only work on menus with an actual sub-menu.
|
| 82 |
if (link.length && ul.length) {
|
| 83 |
/* When using cloned items:
|
| 84 |
* - Clone the menu link and mark it as a clone.
|
| 85 |
*/
|
| 86 |
if (settings.nav == 'clone') {
|
| 87 |
link.clone().prependTo(ul).wrap(cloned);
|
| 88 |
}
|
| 89 |
|
| 90 |
/* When using double-click:
|
| 91 |
* - Add a dblclick event handler that allows the normal link action to complete.
|
| 92 |
*/
|
| 93 |
else if (settings.nav == 'doubleclick') {
|
| 94 |
link.dblclick(function(e) {
|
| 95 |
return true;
|
| 96 |
});
|
| 97 |
}
|
| 98 |
|
| 99 |
/* When using bullet expansion:
|
| 100 |
* - Change the icon to a folder image
|
| 101 |
* - Add the clickable overlay and its handler
|
| 102 |
* - In RTL mode, shift the overlay to the right of the text.
|
| 103 |
* - @TODO: Explore whether "float:right" in dhtml_menu-rtl.css could solve this.
|
| 104 |
*/
|
| 105 |
else if (settings.nav == 'bullet') {
|
| 106 |
li.addClass('dhtml-folder');
|
| 107 |
var b = bullet.clone().prependTo(link).click(function(e) {
|
| 108 |
Drupal.dhtmlMenu.toggleMenu(li, link, ul);
|
| 109 |
if (settings.effects.remember) {
|
| 110 |
Drupal.dhtmlMenu.cookieSet();
|
| 111 |
}
|
| 112 |
return false;
|
| 113 |
});
|
| 114 |
|
| 115 |
// When using RTL, each overlay must be shifted to the other side of the link text, individually.
|
| 116 |
if (rtl) {
|
| 117 |
// Shift the overlay right by the width of the text and the distance between text and icon.
|
| 118 |
b.css('right', '-' + (Math.ceil(link.css('width').replace('px', '')) + rtl) + 'px');
|
| 119 |
}
|
| 120 |
}
|
| 121 |
|
| 122 |
/* When using hover expansion:
|
| 123 |
* - Add mouse-hovering events.
|
| 124 |
*/
|
| 125 |
else if (settings.nav == 'hover') {
|
| 126 |
link.mouseenter(function(e) {
|
| 127 |
Drupal.dhtmlMenu.switchMenu(li, link, ul, true);
|
| 128 |
});
|
| 129 |
li.mouseleave(function(e) {
|
| 130 |
// Only collapse the menu if it was initially collapsed.
|
| 131 |
if (li.hasClass('start-collapsed')) {
|
| 132 |
/* As explained earlier, this event fires before the body event.
|
| 133 |
* We need to wait to make sure that the user isn't browsing a
|
| 134 |
* context menu right now, in which case the menu isn't collapsed.
|
| 135 |
*/
|
| 136 |
setTimeout(function() {
|
| 137 |
if (!freeze) {
|
| 138 |
Drupal.dhtmlMenu.switchMenu(li, link, ul, false);
|
| 139 |
}
|
| 140 |
}, 10);
|
| 141 |
}
|
| 142 |
});
|
| 143 |
}
|
| 144 |
|
| 145 |
/* When using menus that cannot collapse:
|
| 146 |
* Toggle the menu normally, but only if the menu is closed.
|
| 147 |
*/
|
| 148 |
else if (settings.nav == 'open') {
|
| 149 |
link.click(function(e) {
|
| 150 |
// Don't collapse expanded menus.
|
| 151 |
if (li.hasClass('expanded')) {
|
| 152 |
return true;
|
| 153 |
}
|
| 154 |
Drupal.dhtmlMenu.toggleMenu(li, link, ul);
|
| 155 |
$('.dhtml-menu-open').removeClass('dhtml-menu-open');
|
| 156 |
$('li.dhtml-menu.expanded').addClass('dhtml-menu-open');
|
| 157 |
return false;
|
| 158 |
});
|
| 159 |
}
|
| 160 |
|
| 161 |
// These three options make links simply toggle when clicked.
|
| 162 |
if (settings.nav == 'clone' || settings.nav == 'doubleclick' || settings.nav == 'none') {
|
| 163 |
link.click(function(e) {
|
| 164 |
Drupal.dhtmlMenu.toggleMenu(li, link, ul);
|
| 165 |
if (settings.effects.remember) {
|
| 166 |
Drupal.dhtmlMenu.cookieSet();
|
| 167 |
}
|
| 168 |
return false;
|
| 169 |
});
|
| 170 |
}
|
| 171 |
}
|
| 172 |
});
|
| 173 |
|
| 174 |
// When using LTR, all icons can be shifted as one, as the text width is not relevant.
|
| 175 |
if (settings.nav == 'bullet' && !rtl) {
|
| 176 |
// Shift overlay to the left by the width of the icon and the distance between icon and text.
|
| 177 |
var shift = '-' + (Math.ceil(($('.menu li').css('margin-left').replace('px', ''))) + 16) + 'px';
|
| 178 |
// Shift the overlay using a negative left-hand offset, and the text using a negative right-hand margin.
|
| 179 |
$('.dhtml-menu-icon').css('left', shift).css('margin-right', shift);
|
| 180 |
}
|
| 181 |
}
|
| 182 |
}
|
| 183 |
|
| 184 |
/**
|
| 185 |
* Toggles the menu's state between open and closed.
|
| 186 |
*
|
| 187 |
* @param li
|
| 188 |
* Object. The <li> element that will be expanded or collapsed.
|
| 189 |
* @param link
|
| 190 |
* Object. The <a> element representing the menu link anchor.
|
| 191 |
* @param ul
|
| 192 |
* Object. The <ul> element containing the sub-items.
|
| 193 |
*/
|
| 194 |
Drupal.dhtmlMenu.toggleMenu = function(li, link, ul) {
|
| 195 |
// Make it open if closed, close if open.
|
| 196 |
Drupal.dhtmlMenu.switchMenu(li, link, ul, !li.hasClass('expanded'));
|
| 197 |
}
|
| 198 |
|
| 199 |
/**
|
| 200 |
* Switches the menu's state to a defined value.
|
| 201 |
* This function does nothing if the menu is in the target state already.
|
| 202 |
*
|
| 203 |
* @param li
|
| 204 |
* Object. The <li> element that will be expanded or collapsed.
|
| 205 |
* @param link
|
| 206 |
* Object. The <a> element representing the menu link anchor.
|
| 207 |
* @param ul
|
| 208 |
* Object. The <ul> element containing the sub-items.
|
| 209 |
*/
|
| 210 |
Drupal.dhtmlMenu.switchMenu = function(li, link, ul, open) {
|
| 211 |
// No need for switching. Menu is already in desired state.
|
| 212 |
if (open == li.hasClass('expanded')) {
|
| 213 |
return;
|
| 214 |
}
|
| 215 |
|
| 216 |
var effects = Drupal.settings.dhtmlMenu.effects;
|
| 217 |
|
| 218 |
if (open) {
|
| 219 |
Drupal.dhtmlMenu.animate(ul, 'show');
|
| 220 |
li.removeClass('collapsed').addClass('expanded');
|
| 221 |
|
| 222 |
// If the siblings effect is on, close all sibling menus.
|
| 223 |
if (effects.siblings != 'none') {
|
| 224 |
var id = link.attr('id');
|
| 225 |
/* Siblings are all open menus that are neither parents nor children of this menu.
|
| 226 |
* First, mark this item's children for exclusion.
|
| 227 |
*/
|
| 228 |
li.find('li').addClass('own-children-temp');
|
| 229 |
|
| 230 |
// If the relativity option is on, select only the siblings that have the same root
|
| 231 |
if (effects.siblings == 'close-same-tree') {
|
| 232 |
var root = li.parent();
|
| 233 |
}
|
| 234 |
else {
|
| 235 |
var root = $('ul.menu');
|
| 236 |
}
|
| 237 |
var siblings = root.find('li.expanded').not('.own-children-temp').not(':has(#' + id + ')');
|
| 238 |
|
| 239 |
// If children should not get closed automatically...
|
| 240 |
if (effects.children == 'none') {
|
| 241 |
// Remove items that are currently hidden from view (do not close these).
|
| 242 |
$('li.collapsed li.expanded').addClass('sibling-children-temp');
|
| 243 |
// Only close the top-most open sibling, not its children.
|
| 244 |
siblings.find('li.expanded').addClass('sibling-children-temp');
|
| 245 |
siblings = $(siblings).not('.sibling-children-temp');
|
| 246 |
}
|
| 247 |
|
| 248 |
// The temp classes can now be removed.
|
| 249 |
$('.own-children-temp, .sibling-children-temp')
|
| 250 |
.removeClass('own-children-temp')
|
| 251 |
.removeClass('sibling-children-temp');
|
| 252 |
|
| 253 |
Drupal.dhtmlMenu.animate(siblings.find('ul:first'), 'hide');
|
| 254 |
siblings.removeClass('expanded').addClass('collapsed');
|
| 255 |
}
|
| 256 |
}
|
| 257 |
else {
|
| 258 |
Drupal.dhtmlMenu.animate(ul, 'hide');
|
| 259 |
li.removeClass('expanded').addClass('collapsed');
|
| 260 |
|
| 261 |
// If children are closed automatically, find and close them now.
|
| 262 |
if (effects.children == 'close-children') {
|
| 263 |
// If a sub-menu closes in the forest and nobody sees it, is animation a waste of performance? Yes.
|
| 264 |
li.find('li.expanded')
|
| 265 |
.removeClass('expanded').addClass('collapsed')
|
| 266 |
.find('ul:first').css('display', 'none');
|
| 267 |
}
|
| 268 |
}
|
| 269 |
}
|
| 270 |
|
| 271 |
/**
|
| 272 |
* Animate a specific block element using the configured DHTML effects.
|
| 273 |
*
|
| 274 |
* @param element
|
| 275 |
* The element to be animated. DHTML Menu only animates <ul> elements,
|
| 276 |
* but this could in theory be any block (not inline) element.
|
| 277 |
*
|
| 278 |
* @param action
|
| 279 |
* One of either 'show' or 'hide'.
|
| 280 |
*/
|
| 281 |
Drupal.dhtmlMenu.animate = function(element, action) {
|
| 282 |
var effects = Drupal.dhtmlMenu.animation;
|
| 283 |
var speed = Drupal.settings.dhtmlMenu.animation.speed;
|
| 284 |
|
| 285 |
if (effects.count) {
|
| 286 |
element.animate(effects[action], speed * 1);
|
| 287 |
}
|
| 288 |
else {
|
| 289 |
element.css('display', action == 'show' ? 'block' : 'none');
|
| 290 |
}
|
| 291 |
}
|
| 292 |
|
| 293 |
/**
|
| 294 |
* Saves the dhtml_menu cookie.
|
| 295 |
*/
|
| 296 |
Drupal.dhtmlMenu.cookieSet = function() {
|
| 297 |
var expanded = new Array();
|
| 298 |
$('li.expanded').each(function() {
|
| 299 |
expanded.push($(this).children('a:first').attr('id'));
|
| 300 |
});
|
| 301 |
document.cookie = 'dhtml_menu=' + expanded.join(',') + ';path=/';
|
| 302 |
}
|
| 303 |
|
| 304 |
})(jQuery);
|
| 305 |
|