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