root / drupal7 / sites / all / modules / dhtml_menu / dhtml_menu.js @ a8cee257
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 | /* When using bullet expansion:
|
||
109 | * - Change the icon to a folder image
|
||
110 | * - Add the clickable overlay and its handler
|
||
111 | * - In RTL mode, shift the overlay to the right of the text.
|
||
112 | * - @TODO: Explore whether "float:right" in dhtml_menu-rtl.css could solve this.
|
||
113 | */
|
||
114 | else if (settings.nav == 'bullet') { |
||
115 | a8cee257 | Assos Assos | li.addClass('dhtml-folder dhtml-menu-processed');
|
116 | 85ad3d82 | Assos Assos | var b = bullet.clone().prependTo(link).click(function(e) { |
117 | Drupal.dhtmlMenu.toggleMenu(li, link, ul); |
||
118 | if (settings.effects.remember) {
|
||
119 | Drupal.dhtmlMenu.cookieSet(); |
||
120 | } |
||
121 | return false; |
||
122 | }); |
||
123 | |||
124 | // When using RTL, each overlay must be shifted to the other side of the link text, individually.
|
||
125 | if (rtl) {
|
||
126 | // Shift the overlay right by the width of the text and the distance between text and icon.
|
||
127 | b.css('right', '-' + (Math.ceil(link.css('width').replace('px', '')) + rtl) + 'px'); |
||
128 | } |
||
129 | } |
||
130 | |||
131 | /* When using hover expansion:
|
||
132 | * - Add mouse-hovering events.
|
||
133 | */
|
||
134 | else if (settings.nav == 'hover') { |
||
135 | a8cee257 | Assos Assos | link.focus(function(e) {
|
136 | Drupal.dhtmlMenu.switchMenu(li, link, ul, true);
|
||
137 | }); |
||
138 | 85ad3d82 | Assos Assos | link.mouseenter(function(e) {
|
139 | Drupal.dhtmlMenu.switchMenu(li, link, ul, true);
|
||
140 | }); |
||
141 | li.mouseleave(function(e) {
|
||
142 | // Only collapse the menu if it was initially collapsed.
|
||
143 | if (li.hasClass('start-collapsed')) { |
||
144 | /* As explained earlier, this event fires before the body event.
|
||
145 | * We need to wait to make sure that the user isn't browsing a
|
||
146 | * context menu right now, in which case the menu isn't collapsed.
|
||
147 | */
|
||
148 | setTimeout(function() {
|
||
149 | if (!freeze) {
|
||
150 | Drupal.dhtmlMenu.switchMenu(li, link, ul, false);
|
||
151 | } |
||
152 | }, 10);
|
||
153 | } |
||
154 | }); |
||
155 | a8cee257 | Assos Assos | li.blur(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 | 85ad3d82 | Assos Assos | } |
170 | |||
171 | /* When using menus that cannot collapse:
|
||
172 | * Toggle the menu normally, but only if the menu is closed.
|
||
173 | */
|
||
174 | else if (settings.nav == 'open') { |
||
175 | link.click(function(e) {
|
||
176 | // Don't collapse expanded menus.
|
||
177 | if (li.hasClass('expanded')) { |
||
178 | return true; |
||
179 | } |
||
180 | Drupal.dhtmlMenu.toggleMenu(li, link, ul); |
||
181 | $('.dhtml-menu-open').removeClass('dhtml-menu-open'); |
||
182 | $('li.dhtml-menu.expanded').addClass('dhtml-menu-open'); |
||
183 | return false; |
||
184 | }); |
||
185 | } |
||
186 | |||
187 | // These three options make links simply toggle when clicked.
|
||
188 | if (settings.nav == 'clone' || settings.nav == 'doubleclick' || settings.nav == 'none') { |
||
189 | link.click(function(e) {
|
||
190 | Drupal.dhtmlMenu.toggleMenu(li, link, ul); |
||
191 | if (settings.effects.remember) {
|
||
192 | Drupal.dhtmlMenu.cookieSet(); |
||
193 | } |
||
194 | return false; |
||
195 | }); |
||
196 | } |
||
197 | } |
||
198 | }); |
||
199 | |||
200 | // When using LTR, all icons can be shifted as one, as the text width is not relevant.
|
||
201 | a8cee257 | Assos Assos | if (settings.nav == 'bullet' && !rtl && $('.menu li.dhtml-folder').length) { |
202 | 85ad3d82 | Assos Assos | // Shift overlay to the left by the width of the icon and the distance between icon and text.
|
203 | a8cee257 | Assos Assos | if ($('.menu li').hasClass('margin-left')) { |
204 | // Saved for a later backport if needs.
|
||
205 | if (typeof($('.menu li').css('margin-right')) !== 'undefined') { |
||
206 | var shift = '-' + (Math.ceil(($('.menu li').css('margin-left').replace('px', ''))) + 16) + 'px'; |
||
207 | // Shift the overlay using a negative left-hand offset, and the text using a negative right-hand margin.
|
||
208 | $('.dhtml-menu-icon').css('left', shift).css('margin-right', shift); |
||
209 | } |
||
210 | } |
||
211 | 85ad3d82 | Assos Assos | } |
212 | } |
||
213 | } |
||
214 | |||
215 | /**
|
||
216 | * Toggles the menu's state between open and closed.
|
||
217 | *
|
||
218 | * @param li
|
||
219 | * Object. The <li> element that will be expanded or collapsed.
|
||
220 | * @param link
|
||
221 | * Object. The <a> element representing the menu link anchor.
|
||
222 | * @param ul
|
||
223 | * Object. The <ul> element containing the sub-items.
|
||
224 | */
|
||
225 | Drupal.dhtmlMenu.toggleMenu = function(li, link, ul) { |
||
226 | // Make it open if closed, close if open.
|
||
227 | Drupal.dhtmlMenu.switchMenu(li, link, ul, !li.hasClass('expanded'));
|
||
228 | } |
||
229 | |||
230 | /**
|
||
231 | * Switches the menu's state to a defined value.
|
||
232 | * This function does nothing if the menu is in the target state already.
|
||
233 | *
|
||
234 | * @param li
|
||
235 | * Object. The <li> element that will be expanded or collapsed.
|
||
236 | * @param link
|
||
237 | * Object. The <a> element representing the menu link anchor.
|
||
238 | * @param ul
|
||
239 | * Object. The <ul> element containing the sub-items.
|
||
240 | */
|
||
241 | Drupal.dhtmlMenu.switchMenu = function(li, link, ul, open) { |
||
242 | // No need for switching. Menu is already in desired state.
|
||
243 | if (open == li.hasClass('expanded')) { |
||
244 | return;
|
||
245 | } |
||
246 | |||
247 | var effects = Drupal.settings.dhtmlMenu.effects;
|
||
248 | |||
249 | if (open) {
|
||
250 | Drupal.dhtmlMenu.animate(ul, 'show');
|
||
251 | li.removeClass('collapsed').addClass('expanded'); |
||
252 | |||
253 | // If the siblings effect is on, close all sibling menus.
|
||
254 | if (effects.siblings != 'none') { |
||
255 | var id = li.attr('id'); |
||
256 | /* Siblings are all open menus that are neither parents nor children of this menu.
|
||
257 | * First, mark this item's children for exclusion.
|
||
258 | */
|
||
259 | li.find('li').addClass('own-children-temp'); |
||
260 | |||
261 | // If the relativity option is on, select only the siblings that have the same root
|
||
262 | if (effects.siblings == 'close-same-tree') { |
||
263 | var root = li.parent();
|
||
264 | } |
||
265 | else {
|
||
266 | var root = $('ul.menu'); |
||
267 | } |
||
268 | var siblings = root.find('li.expanded').not('.own-children-temp').not('#' + id); |
||
269 | |||
270 | // If children should not get closed automatically...
|
||
271 | if (effects.children == 'none') { |
||
272 | // Remove items that are currently hidden from view (do not close these).
|
||
273 | $('li.collapsed li.expanded').addClass('sibling-children-temp'); |
||
274 | // Only close the top-most open sibling, not its children.
|
||
275 | siblings.find('li.expanded').addClass('sibling-children-temp'); |
||
276 | siblings = $(siblings).not('.sibling-children-temp'); |
||
277 | } |
||
278 | |||
279 | // The temp classes can now be removed.
|
||
280 | $('.own-children-temp, .sibling-children-temp') |
||
281 | .removeClass('own-children-temp')
|
||
282 | .removeClass('sibling-children-temp');
|
||
283 | |||
284 | Drupal.dhtmlMenu.animate(siblings.find('ul:first'), 'hide'); |
||
285 | siblings.removeClass('expanded').addClass('collapsed'); |
||
286 | } |
||
287 | } |
||
288 | else {
|
||
289 | Drupal.dhtmlMenu.animate(ul, 'hide');
|
||
290 | li.removeClass('expanded').addClass('collapsed'); |
||
291 | |||
292 | // If children are closed automatically, find and close them now.
|
||
293 | if (effects.children == 'close-children') { |
||
294 | // If a sub-menu closes in the forest and nobody sees it, is animation a waste of performance? Yes.
|
||
295 | li.find('li.expanded')
|
||
296 | .removeClass('expanded').addClass('collapsed') |
||
297 | .find('ul:first').css('display', 'none'); |
||
298 | } |
||
299 | } |
||
300 | } |
||
301 | |||
302 | /**
|
||
303 | * Animate a specific block element using the configured DHTML effects.
|
||
304 | *
|
||
305 | * @param element
|
||
306 | * The element to be animated. DHTML Menu only animates <ul> elements,
|
||
307 | * but this could in theory be any block (not inline) element.
|
||
308 | *
|
||
309 | * @param action
|
||
310 | * One of either 'show' or 'hide'.
|
||
311 | */
|
||
312 | Drupal.dhtmlMenu.animate = function(element, action) { |
||
313 | var effects = Drupal.dhtmlMenu.animation;
|
||
314 | var speed = Drupal.settings.dhtmlMenu.animation.speed;
|
||
315 | |||
316 | if (effects.count) {
|
||
317 | element.animate(effects[action], speed * 1);
|
||
318 | } |
||
319 | else {
|
||
320 | element.css('display', action == 'show' ? 'block' : 'none'); |
||
321 | } |
||
322 | } |
||
323 | |||
324 | /**
|
||
325 | * Saves the dhtml_menu cookie.
|
||
326 | */
|
||
327 | Drupal.dhtmlMenu.cookieSet = function() { |
||
328 | var expanded = new Array(); |
||
329 | $('li.expanded').each(function() { |
||
330 | expanded.push(this.id);
|
||
331 | }); |
||
332 | document.cookie = 'dhtml_menu=' + expanded.join(',') + ';path=/'; |
||
333 | } |
||
334 | |||
335 | })(jQuery); |