Projet

Général

Profil

Paste
Télécharger (13,7 ko) Statistiques
| Branche: | Révision:

root / drupal7 / sites / all / modules / adminimal_admin_menu / js / slicknav / jquery-no-conflict.slicknav.js @ c304a780

1
/*!
2
        SlickNav Responsive Mobile Menu
3
        (c) 2014 Josh Cope
4
        licensed under MIT
5
*/
6
;(function ($, document, window) {
7
  var
8
    // default settings object.
9
    defaults = {
10
      label: 'MENU',
11
      duplicate: true,
12
      duration: 200,
13
      easingOpen: 'swing',
14
      easingClose: 'swing',
15
      closedSymbol: '►',
16
      openedSymbol: '▼',
17
      prependTo: 'body',
18
      parentTag: 'a',
19
      closeOnClick: false,
20
      allowParentLinks: false,
21
      init: function () {
22
      },
23
      open: function () {
24
      },
25
      close: function () {
26
      }
27
    },
28
    mobileMenu = 'slicknav',
29
    prefix = 'slicknav';
30

    
31
  function Plugin(element, options) {
32
    this.element = element;
33

    
34
    // jQuery has an extend method which merges the contents of two or
35
    // more objects, storing the result in the first object. The first object
36
    // is generally empty as we don't want to alter the default options for
37
    // future instances of the plugin
38
    this.settings = $.extend({}, defaults, options);
39

    
40
    this._defaults = defaults;
41
    this._name = mobileMenu;
42

    
43
    this.init();
44
  }
45

    
46
  Plugin.prototype.init = function () {
47
    var $this = this;
48
    var menu = $(this.element);
49
    var settings = this.settings;
50

    
51
    // clone menu if needed
52
    if (settings.duplicate) {
53
      $this.mobileNav = menu.clone();
54
      //remove ids from clone to prevent css issues
55
      $this.mobileNav.removeAttr('id');
56
      $this.mobileNav.find('*').each(function (i, e) {
57
        $(e).removeAttr('id');
58
      });
59
    }
60
    else {
61
      $this.mobileNav = menu;
62
    }
63

    
64
    // styling class for the button
65
    var iconClass = prefix + '_icon';
66

    
67
    if (settings.label == '') {
68
      iconClass += ' ' + prefix + '_no-text';
69
    }
70

    
71
    if (settings.parentTag == 'a') {
72
      settings.parentTag = 'a href="#"';
73
    }
74

    
75
    // create menu bar
76
    $this.mobileNav.attr('class', prefix + '_nav');
77
    var menuBar = $('<div class="' + prefix + '_menu"></div>');
78
    $this.btn = $('<' + settings.parentTag + ' aria-haspopup="true" tabindex="0" class="' + prefix + '_btn ' + prefix + '_collapsed"><span class="' + prefix + '_menutxt">' + settings.label + '</span><span class="' + iconClass + '"><span class="' + prefix + '_icon-bar"></span><span class="' + prefix + '_icon-bar"></span><span class="' + prefix + '_icon-bar"></span></span></a>');
79
    $(menuBar).append($this.btn);
80
    $(settings.prependTo).prepend(menuBar);
81
    menuBar.append($this.mobileNav);
82

    
83
    // iterate over structure adding additional structure
84
    var items = $this.mobileNav.find('li');
85
    $(items).each(function () {
86
      var item = $(this);
87
      var data = {};
88
      data.children = item.children('ul').attr('role', 'menu');
89
      item.data("menu", data);
90

    
91
      // if a list item has a nested menu
92
      if (data.children.length > 0) {
93

    
94
        // select all text before the child menu
95
        var a = item.contents();
96
        var nodes = [];
97
        $(a).each(function () {
98
          if (!$(this).is("ul")) {
99
            nodes.push(this);
100
          }
101
          else {
102
            return false;
103
          }
104
        });
105

    
106
        // wrap item text with tag and add classes
107
        var wrap = $(nodes).wrapAll('<' + settings.parentTag + ' role="menuitem" aria-haspopup="true" tabindex="-1" class="' + prefix + '_item"/>').parent();
108

    
109
        item.addClass(prefix + '_collapsed');
110
        item.addClass(prefix + '_parent');
111

    
112
        // create parent arrow
113
        $(nodes).last().after('<span class="' + prefix + '_arrow">' + settings.closedSymbol + '</span>');
114

    
115

    
116
      }
117
      else {
118
        if (item.children().length == 0) {
119
          item.addClass(prefix + '_txtnode');
120
        }
121
      }
122

    
123
      // accessibility for links
124
      item.children('a').attr('role', 'menuitem').click(function () {
125
        //Emulate menu close if set
126
        if (settings.closeOnClick) {
127
          $($this.btn).click();
128
        }
129
      });
130
    });
131

    
132
    // structure is in place, now hide appropriate items
133
    $(items).each(function () {
134
      var data = $(this).data("menu");
135
      $this._visibilityToggle(data.children, false, null, true);
136
    });
137

    
138
    // finally toggle entire menu
139
    $this._visibilityToggle($this.mobileNav, false, 'init', true);
140

    
141
    // accessibility for menu button
142
    $this.mobileNav.attr('role', 'menu');
143

    
144
    // outline prevention when using mouse
145
    $(document).mousedown(function () {
146
      $this._outlines(false);
147
    });
148

    
149
    $(document).keyup(function () {
150
      $this._outlines(true);
151
    });
152

    
153
    // menu button click
154
    $($this.btn).click(function (e) {
155
      e.preventDefault();
156
      $this._menuToggle();
157
    });
158

    
159
    // click on menu parent
160
    $this.mobileNav.on('click', '.' + prefix + '_item', function (e) {
161
      e.preventDefault();
162
      $this._itemClick($(this));
163
    });
164

    
165
    // check for enter key on menu button and menu parents
166
    $($this.btn).keydown(function (e) {
167
      var ev = e || event;
168
      if (ev.keyCode == 13) {
169
        e.preventDefault();
170
        $this._menuToggle();
171
      }
172
    });
173

    
174
    $this.mobileNav.on('keydown', '.' + prefix + '_item', function (e) {
175
      var ev = e || event;
176
      if (ev.keyCode == 13) {
177
        e.preventDefault();
178
        $this._itemClick($(e.target));
179
      }
180
    });
181

    
182
    // allow links clickable within parent tags if set
183
    if (settings.allowParentLinks) {
184
      $('.' + prefix + '_item a').click(function (e) {
185
        e.stopImmediatePropagation();
186
      });
187
    }
188
  };
189

    
190
  //toggle menu
191
  Plugin.prototype._menuToggle = function (el) {
192
    var $this = this;
193
    var btn = $this.btn;
194
    var mobileNav = $this.mobileNav;
195

    
196
    if (btn.hasClass(prefix + '_collapsed')) {
197
      btn.removeClass(prefix + '_collapsed');
198
      btn.addClass(prefix + '_open');
199
    }
200
    else {
201
      btn.removeClass(prefix + '_open');
202
      btn.addClass(prefix + '_collapsed');
203
    }
204
    btn.addClass(prefix + '_animating');
205
    $this._visibilityToggle(mobileNav, true, btn);
206
  };
207

    
208
  // toggle clicked items
209
  Plugin.prototype._itemClick = function (el) {
210
    var $this = this;
211
    var settings = $this.settings;
212
    var data = el.data("menu");
213
    if (!data) {
214
      data = {};
215
      data.arrow = el.children('.' + prefix + '_arrow');
216
      data.ul = el.next('ul');
217
      data.parent = el.parent();
218
      el.data("menu", data);
219
    }
220
    if (data.parent.hasClass(prefix + '_collapsed')) {
221
      data.arrow.html(settings.openedSymbol);
222
      data.parent.removeClass(prefix + '_collapsed');
223
      data.parent.addClass(prefix + '_open');
224
      data.parent.addClass(prefix + '_animating');
225
      $this._visibilityToggle(data.ul, true, el);
226
    }
227
    else {
228
      data.arrow.html(settings.closedSymbol);
229
      data.parent.addClass(prefix + '_collapsed');
230
      data.parent.removeClass(prefix + '_open');
231
      data.parent.addClass(prefix + '_animating');
232
      $this._visibilityToggle(data.ul, true, el);
233
    }
234
  };
235

    
236
  // toggle actual visibility and accessibility tags
237
  Plugin.prototype._visibilityToggle = function (el, animate, trigger, init) {
238
    var $this = this;
239
    var settings = $this.settings;
240
    var items = $this._getActionItems(el);
241
    var duration = 0;
242
    if (animate) {
243
      duration = settings.duration;
244
    }
245

    
246
    if (el.hasClass(prefix + '_hidden')) {
247
      el.removeClass(prefix + '_hidden');
248
      el.slideDown(duration, settings.easingOpen, function () {
249

    
250
        $(trigger).removeClass(prefix + '_animating');
251
        $(trigger).parent().removeClass(prefix + '_animating');
252

    
253
        //Fire open callback
254
        if (!init) {
255
          settings.open(trigger);
256
        }
257
      });
258
      el.attr('aria-hidden', 'false');
259
      items.attr('tabindex', '0');
260
      $this._setVisAttr(el, false);
261
    }
262
    else {
263
      el.addClass(prefix + '_hidden');
264
      el.slideUp(duration, this.settings.easingClose, function () {
265
        el.attr('aria-hidden', 'true');
266
        items.attr('tabindex', '-1');
267
        $this._setVisAttr(el, true);
268
        el.hide(); //jQuery 1.7 bug fix
269

    
270
        $(trigger).removeClass(prefix + '_animating');
271
        $(trigger).parent().removeClass(prefix + '_animating');
272

    
273
        //Fire init or close callback
274
        if (!init) {
275
          settings.close(trigger);
276
        }
277
        else {
278
          if (trigger == 'init') {
279
            settings.init();
280
          }
281
        }
282
      });
283
    }
284
  };
285

    
286
  // set attributes of element and children based on visibility
287
  Plugin.prototype._setVisAttr = function (el, hidden) {
288
    var $this = this;
289

    
290
    // select all parents that aren't hidden
291
    var nonHidden = el.children('li').children('ul').not('.' + prefix + '_hidden');
292

    
293
    // iterate over all items setting appropriate tags
294
    if (!hidden) {
295
      nonHidden.each(function () {
296
        var ul = $(this);
297
        ul.attr('aria-hidden', 'false');
298
        var items = $this._getActionItems(ul);
299
        items.attr('tabindex', '0');
300
        $this._setVisAttr(ul, hidden);
301
      });
302
    }
303
    else {
304
      nonHidden.each(function () {
305
        var ul = $(this);
306
        ul.attr('aria-hidden', 'true');
307
        var items = $this._getActionItems(ul);
308
        items.attr('tabindex', '-1');
309
        $this._setVisAttr(ul, hidden);
310
      });
311
    }
312
  };
313

    
314
  // get all 1st level items that are clickable
315
  Plugin.prototype._getActionItems = function (el) {
316
    var data = el.data("menu");
317
    if (!data) {
318
      data = {};
319
      var items = el.children('li');
320
      var anchors = items.children('a');
321
      data.links = anchors.add(items.children('.' + prefix + '_item'));
322
      el.data("menu", data);
323
    }
324
    return data.links;
325
  };
326

    
327
  Plugin.prototype._outlines = function (state) {
328
    if (!state) {
329
      $('.' + prefix + '_item, .' + prefix + '_btn').css('outline', 'none');
330
    }
331
    else {
332
      $('.' + prefix + '_item, .' + prefix + '_btn').css('outline', '');
333
    }
334
  };
335

    
336
  Plugin.prototype.toggle = function () {
337
    $this._menuToggle();
338
  };
339

    
340
  Plugin.prototype.open = function () {
341
    $this = this;
342
    if ($this.btn.hasClass(prefix + '_collapsed')) {
343
      $this._menuToggle();
344
    }
345
  };
346

    
347
  Plugin.prototype.close = function () {
348
    $this = this;
349
    if ($this.btn.hasClass(prefix + '_open')) {
350
      $this._menuToggle();
351
    }
352
  };
353

    
354
  $.fn[mobileMenu] = function (options) {
355
    var args = arguments;
356

    
357
    // Is the first parameter an object (options), or was omitted, instantiate
358
    // a new instance
359
    if (options === undefined || typeof options === 'object') {
360
      return this.each(function () {
361

    
362
        // Only allow the plugin to be instantiated once due to methods
363
        if (!$.data(this, 'plugin_' + mobileMenu)) {
364

    
365
          // if it has no instance, create a new one, pass options to our
366
          // plugin constructor, and store the plugin instance in the elements
367
          // jQuery data object.
368
          $.data(this, 'plugin_' + mobileMenu, new Plugin(this, options));
369
        }
370
      });
371

    
372
      // If is a string and doesn't start with an underscore or 'init'
373
      // function, treat this as a call to a public method.
374
    }
375
    else {
376
      if (typeof options === 'string' && options[0] !== '_' && options !== 'init') {
377

    
378
        // Cache the method call to make it possible to return a value
379
        var returns;
380

    
381
        this.each(function () {
382
          var instance = $.data(this, 'plugin_' + mobileMenu);
383

    
384
          // Tests that there's already a plugin-instance and checks that the
385
          // requested public method exists
386
          if (instance instanceof Plugin && typeof instance[options] === 'function') {
387

    
388
            // Call the method of our plugin instance, and pass it the supplied
389
            // arguments.
390
            returns = instance[options].apply(instance, Array.prototype.slice.call(args, 1));
391
          }
392
        });
393

    
394
        // If the earlier cached method gives a value back return the value,
395
        // otherwise return this to preserve chainability.
396
        return returns !== undefined ? returns : this;
397
      }
398
    }
399
  };
400
}($jQueryAdminimal, document, window));
401

    
402
(function ($) {
403

    
404
  Drupal.admin = Drupal.admin || {};
405
  Drupal.admin.behaviors = Drupal.admin.behaviors || {};
406

    
407
// Create the responsive menu using SlickNav.
408
  Drupal.admin.behaviors.responsivemenu = function (context, settings, $adminMenu) {
409

    
410
    $('#admin-menu-menu-responsive').slicknav({
411
      label: Drupal.t('Menu'),
412
      prependTo: 'body',
413
      closedSymbol: '<i class="closed"></i>',
414
      openedSymbol: '<i class="open"></i>',
415
      allowParentLinks: true
416
    });
417

    
418
  };
419

    
420
// Create the responsive shortcuts dropdown.
421
  Drupal.admin.behaviors.responsiveshortcuts = function (context, settings, $adminMenu) {
422

    
423
    // Check if there are any shortucts to respondify.
424
    if (jQuery("div.toolbar-shortcuts ul.menu li").length) {
425

    
426
      // Create the dropdown base
427
      $('<select id="responsive-shortcuts-dropdown"/>').appendTo("#admin-menu-shortcuts-responsive div.toolbar-shortcuts");
428

    
429
      // Create default option "Select"
430
      $("<option />", {
431
        "selected": "selected",
432
        "class": "hide",
433
        "value": "",
434
        "text": Drupal.t('Shortcuts')
435
      }).appendTo("#admin-menu-shortcuts-responsive div.toolbar-shortcuts select");
436

    
437
      // Populate dropdown with menu items
438
      $("#admin-menu-shortcuts-responsive div.toolbar-shortcuts a").each(function () {
439
        var el = $(this);
440
        $("<option />", {
441
          "value": el.attr("href"),
442
          "text": el.text()
443
        }).appendTo("#admin-menu-shortcuts-responsive div.toolbar-shortcuts select");
444
      });
445

    
446
      // Redirect the user when selecting an option.
447
      $("#admin-menu-shortcuts-responsive div.toolbar-shortcuts select").change(function () {
448
        window.location = $(this).find("option:selected").val();
449
      });
450

    
451
      // Clean the mess.
452
      $('#admin-menu-shortcuts-responsive div.toolbar-shortcuts ul').remove();
453
      // Move the select box into the responsive menu.
454
      $("#admin-menu-shortcuts-responsive").prependTo(".slicknav_menu");
455

    
456
    }
457

    
458
    // Remove the edit shortcuts link from the DOM to avoid duble rendering.
459
    $('#admin-menu-shortcuts-responsive #edit-shortcuts').remove();
460

    
461
  };
462
})($jQueryAdminimal);