Projet

Général

Profil

Paste
Télécharger (11,8 ko) Statistiques
| Branche: | Révision:

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

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
        /* 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
          li.addClass('dhtml-folder dhtml-menu-processed');
116
          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
          link.focus(function(e) {
136
            Drupal.dhtmlMenu.switchMenu(li, link, ul, true);
137
          });
138
          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
          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
        }
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
    if (settings.nav == 'bullet' && !rtl && $('.menu li.dhtml-folder').length) {
202
      // Shift overlay to the left by the width of the icon and the distance between icon and text.
203
      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
    }
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);
336