Projet

Général

Profil

Paste
Télécharger (10,6 ko) Statistiques
| Branche: | Révision:

root / drupal7 / sites / all / modules / dhtml_menu / dhtml_menu.js @ 87dbc3bf

1
// $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);
307