Projet

Général

Profil

Paste
Télécharger (12,3 ko) Statistiques
| Branche: | Révision:

root / drupal7 / sites / all / modules / dhtml_menu / dhtml_menu.js @ bad4e148

1

    
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
  attach: function(context, settings) {
19
    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
    $('li.dhtml-menu.collapsed.expanded', context).removeClass('expanded');
32

    
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
      $('li.dhtml-menu.expanded', context).addClass('dhtml-menu-open');
38
    }
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
      $('ul.menu').focus(function() {freeze = false});
58
      $('body').mouseleave(function() {freeze = true});
59
      $('body').blur(function() {freeze = true});
60
    }
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
      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
    }
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
    $('ul.menu li.dhtml-menu:not(.leaf,.dhtml-processed)', context).each(function() {
85
      $(this).addClass("dhtml-processed");
86
      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
        /**
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
        /* 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
          li.addClass('dhtml-folder dhtml-menu-processed');
130
          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
          link.focus(function(e) {
150
            Drupal.dhtmlMenu.switchMenu(li, link, ul, true);
151
          });
152
          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
          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
        }
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
    if (settings.nav == 'bullet' && $('.menu li').length && !rtl && $('.menu li.dhtml-folder').length) {
216
      // Shift overlay to the left by the width of the icon and the distance between icon and text.
217
      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
    }
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);
350