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