PageSourceSearch

https://lkv.li/packages/sw_all/js/foundation/foundation.dropdownMe…=be477dd6d68c574d71a87bc268be737a97e4e81e

js lkv.li collected 2026-10-02 16:46:15 UTC 16,413 bytes, 486 lines download raw bytes

1'use strict';
2
3var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
4
5function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
6
7!function ($) {
8
9  /**
10   * DropdownMenu module.
11   * @module foundation.dropdown-menu
12   * @requires foundation.util.keyboard
13   * @requires foundation.util.box
14   * @requires foundation.util.nest
15   */
16
17  var DropdownMenu = function () {
18    /**
19     * Creates a new instance of DropdownMenu.
20     * @class
21     * @fires DropdownMenu#init
22     * @param {jQuery} element - jQuery object to make into a dropdown menu.
23     * @param {Object} options - Overrides to the default plugin settings.
24     */
25    function DropdownMenu(element, options) {
26      _classCallCheck(this, DropdownMenu);
27
28      this.$element = element;
29      this.options = $.extend({}, DropdownMenu.defaults, this.$element.data(), options);
30
31      Foundation.Nest.Feather(this.$element, 'dropdown');
32      this._init();
33
34      Foundation.registerPlugin(this, 'DropdownMenu');
35      Foundation.Keyboard.register('DropdownMenu', {
36        'ENTER': 'open',
37        'SPACE': 'open',
38        'ARROW_RIGHT': 'next',
39        'ARROW_UP': 'up',
40        'ARROW_DOWN': 'down',
41        'ARROW_LEFT': 'previous',
42        'ESCAPE': 'close'
43      });
44    }
45
46    /**
47     * Initializes the plugin, and calls _prepareMenu
48     * @private
49     * @function
50     */
51
52
53    _createClass(DropdownMenu, [{
54      key: '_init',
55      value: function _init() {
56        var subs = this.$element.find('li.is-dropdown-submenu-parent');
57        this.$element.children('.is-dropdown-submenu-parent').children('.is-dropdown-submenu').addClass('first-sub');
58
59        this.$menuItems = this.$element.find('[role="menuitem"]');
60        this.$tabs = this.$element.children('[role="menuitem"]');
61        this.$tabs.find('ul.is-dropdown-submenu').addClass(this.options.verticalClass);
62
63        if (this.$element.hasClass(this.options.rightClass) || this.options.alignment === 'right' || Foundation.rtl() || this.$element.parents('.top-bar-right').is('*')) {
64          this.options.alignment = 'right';
65          subs.addClass('opens-left');
66        } else {
67          subs.addClass('opens-right');
68        }
69        this.changed = false;
70        this._events();
71      }
72    }, {
73      key: '_isVertical',
74      value: function _isVertical() {
75        return this.$tabs.css('display') === 'block';
76      }
77
78      /**
79       * Adds event listeners to elements within the menu
80       * @private
81       * @function
82       */
83
84    }, {
85      key: '_events',
86      value: function _events() {
87        var _this = this,
88            hasTouch = 'ontouchstart' in window || typeof window.ontouchstart !== 'undefined',
89            parClass = 'is-dropdown-submenu-parent';
90
91        // used for onClick and in the keyboard handlers
92        var handleClickFn = function handleClickFn(e) {
93          var $elem = $(e.target).parentsUntil('ul', '.' + parClass),
94              hasSub = $elem.hasClass(parClass),
95              hasClicked = $elem.attr('data-is-click') === 'true',
96              $sub = $elem.children('.is-dropdown-submenu');
97
98          if (hasSub) {
99            if (hasClicked) {
100              if (!_this.options.closeOnClick || !_this.options.clickOpen && !hasTouch || _this.options.forceFollow && hasTouch) {
101                return;
102              } else {
103                e.stopImmediatePropagation();
104                e.preventDefault();
105                _this._hide($elem);
106              }
107            } else {
108              e.preventDefault();
109              e.stopImmediatePropagation();
110              _this._show($sub);
111              $elem.add($elem.parentsUntil(_this.$element, '.' + parClass)).attr('data-is-click', true);
112            }
113          }
114        };
115
116        if (this.options.clickOpen || hasTouch) {
117          this.$menuItems.on('click.zf.dropdownmenu touchstart.zf.dropdownmenu', handleClick
vendor: 5,487 bytes, lines 117-282
117Fn);
118        }
119
120        // Handle Leaf element Clicks
121        if (_this.options.closeOnClickInside) {
122          this.$menuItems.on('click.zf.dropdownmenu', function (e) {
123            var $elem = $(this),
124                hasSub = $elem.hasClass(parClass);
125            if (!hasSub) {
126              _this._hide();
127            }
128          });
129        }
130
131        if (!this.options.disableHover) {
132          this.$menuItems.on('mouseenter.zf.dropdownmenu', function (e) {
133            var $elem = $(this),
134                hasSub = $elem.hasClass(parClass);
135
136            if (hasSub) {
137              clearTimeout($elem.data('_delay'));
138              $elem.data('_delay', setTimeout(function () {
139                _this._show($elem.children('.is-dropdown-submenu'));
140              }, _this.options.hoverDelay));
141            }
142          }).on('mouseleave.zf.dropdownmenu', function (e) {
143            var $elem = $(this),
144                hasSub = $elem.hasClass(parClass);
145            if (hasSub && _this.options.autoclose) {
146              if ($elem.attr('data-is-click') === 'true' && _this.options.clickOpen) {
147                return false;
148              }
149
150              clearTimeout($elem.data('_delay'));
151              $elem.data('_delay', setTimeout(function () {
152                _this._hide($elem);
153              }, _this.options.closingTime));
154            }
155          });
156        }
157        this.$menuItems.on('keydown.zf.dropdownmenu', function (e) {
158          var $element = $(e.target).parentsUntil('ul', '[role="menuitem"]'),
159              isTab = _this.$tabs.index($element) > -1,
160              $elements = isTab ? _this.$tabs : $element.siblings('li').add($element),
161              $prevElement,
162              $nextElement;
163
164          $elements.each(function (i) {
165            if ($(this).is($element)) {
166              $prevElement = $elements.eq(i - 1);
167              $nextElement = $elements.eq(i + 1);
168              return;
169            }
170          });
171
172          var nextSibling = function nextSibling() {
173                if (!$element.is(':last-child')) {
174                  $nextElement.children('a:first').focus();
175                  e.preventDefault();
176                }
177              },
178              prevSibling = function prevSibling() {
179                $prevElement.children('a:first').focus();
180                e.preventDefault();
181              },
182              openSub = function openSub() {
183                var $sub = $element.children('ul.is-dropdown-submenu');
184                if ($sub.length) {
185                  _this._show($sub);
186                  $element.find('li > a:first').focus();
187                  e.preventDefault();
188                } else {
189                  return;
190                }
191              },
192              closeSub = function closeSub() {
193                //if ($element.is(':first-child')) {
194                var close = $element.parent('ul').parent('li');
195                close.children('a:first').focus();
196                _this._hide(close);
197                e.preventDefault();
198                //}
199              };
200          var functions = {
201            open: openSub,
202            close: function close() {
203              _this._hide(_this.$element);
204              _this.$menuItems.find('a:first').focus(); // focus to first element
205              e.preventDefault();
206            },
207            handled: function handled() {
208              e.stopImmediatePropagation();
209            }
210          };
211
212          if (isTab) {
213            if (_this._isVertical()) {
214              // vertical menu
215              if (Foundation.rtl()) {
216                // right aligned
217                $.extend(functions, {
218                  down: nextSibling,
219                  up: prevSibling,
220                  next: closeSub,
221                  previous: openSub
222                });
223              } else {
224                // left aligned
225                $.extend(functions, {
226                  down: nextSibling,
227                  up: prevSibling,
228                  next: openSub,
229                  previous: closeSub
230                });
231              }
232            } else {
233              // horizontal menu
234              if (Foundation.rtl()) {
235                // right aligned
236                $.extend(functions, {
237                  next: prevSibling,
238                  previous: nextSibling,
239                  down: openSub,
240                  up: closeSub
241                });
242              } else {
243                // left aligned
244                $.extend(functions, {
245                  next: nextSibling,
246                  previous: prevSibling,
247                  down: openSub,
248                  up: closeSub
249                });
250              }
251            }
252          } else {
253            // not tabs -> one sub
254            if (Foundation.rtl()) {
255              // right aligned
256              $.extend(functions, {
257                next: closeSub,
258                previous: openSub,
259                down: nextSibling,
260                up: prevSibling
261              });
262            } else {
263              // left aligned
264              $.extend(functions, {
265                next: openSub,
266                previous: closeSub,
267                down: nextSibling,
268                up: prevSibling
269              });
270            }
271          }
272          Foundation.Keyboard.handleKey(e, 'DropdownMenu', functions);
273        });
274      }
275
276      /**
277       * Adds an event handler to the body to close any dropdowns on a click.
278       * @function
279       * @private
280       */
281
282    }, {
283      key: '_addBodyHandler',
284      value: function _addBodyHandler() {
285        var $body = $(document.body),
286            _this = this;
287        $body.off('mouseup.zf.dropdownmenu touchend.zf.dropdownmenu').on('mouseup.zf.dropdownmenu touchend.zf.dropdownmenu', function (e) {
288          var $link = _this.$element.find(e.target);
289          if ($link.length) {
290            return;
291          }
292
293          _this._hide();
294          $body.off('mouseup.zf.dropdownmenu touchend.zf.dropdownmenu');
295        });
296      }
297
298      /**
299       * Opens a dropdown pane, and checks for collisions first.
300       * @param {jQuery} $sub - ul element that is a submenu to show
301       * @function
302       * @private
303       * @fires DropdownMenu#show
304       */
305
306    }, {
307      key: '_show',
308      value: function _show($sub) {
309        var idx = this.$tabs.index(this.$tabs.filter(function (i, el) {
310          return $(el).find($sub).length > 0;
311        }));
312        var $sibs = $sub.parent('li.is-dropdown-submenu-parent').siblings('li.is-dropdown-submenu-parent');
313        this._hide($sibs, idx);
314        $sub.css('visibility', 'hidden').addClass('js-dropdown-active').parent('li.is-dropdown-submenu-parent').addClass('is-active');
315        var clear = Foundation.Box.ImNotTouchingYou($sub, null, true);
316        if (!clear) {
317          var oldClass = this.options.alignment === 'left' ? '-right' : '-left',
318              $parentLi = $sub.parent('.is-dropdown-submenu-parent');
319          $parentLi.removeClass('opens' + oldClass).addClass('opens-' + this.options.alignment);
320          clear = Foundation.Box.ImNotTouchingYou($sub, null, true);
321          if (!clear) {
322            $parentLi.removeClass('opens-' + this.options.alignment).addClass('opens-inner');
323          }
324          this.changed = true;
325        }
326        $sub.css('visibility', '');
327        if (this.options.closeOnClick) {
328          this._addBodyHandler();
329        }
330        /**
331         * Fires when the new dropdown pane is visible.
332         * @event DropdownMenu#show
333         */
334        this.$element.trigger('show.zf.dropdownmenu', [$sub]);
335      }
336
337      /**
338       * Hides a single, currently open dropdown pane, if passed a parameter, otherwise, hides everything.
339       * @function
340       * @param {jQuery} $elem - element with a submenu to hide
341       * @param {Number} idx - index of the $tabs collection to hide
342       * @private
343       */
344
345    }, {
346      key: '_hide',
347      value: function _hide($elem, idx) {
348        var $toClose;
349        if ($elem && $elem.length) {
350          $toClose = $elem;
351        } else if (idx !== undefined) {
352          $toClose = this.$tabs.not(function (i, el) {
353            return i === idx;
354          });
355        } else {
356          $toClose = this.$element;
357        }
358        var somethingToClose = $toClose.hasClass('is-active') || $toClose.find('.is-active').length > 0;
359
360        if (somethingToClose) {
361          $toClose.find('li.is-active').add($toClose).attr({
362            'data-is-click': false
363          }).removeClass('is-active');
364
365          $toClose.find('ul.js-dropdown-active').removeClass('js-dropdown-active');
366
367          if (this.changed || $toClose.find('opens-inner').length) {
368            var oldClass = this.options.alignment === 'left' ? 'right' : 'left';
369            $toClose.find('li.is-dropdown-submenu-parent').add($toClose).removeClass('opens-inner opens-' + this.options.alignment).addClass('opens-' + oldClass);
370            this.changed = false;
371          }
372          /**
373           * Fires when the open menus are closed.
374           * @event DropdownMenu#hide
375           */
376          this.$element.trigger('hide.zf.dropdownmenu', [$toClose]);
377        }
378      }
379
380      /**
381       * Destroys the plugin.
382       * @function
383       */
384
385    }, {
386      key: 'destroy',
387      value: function destroy() {
388        this.$menuItems.off('.zf.dropdownmenu').removeAttr('data-is-click').removeClass('is-right-arrow is-left-arrow is-down-arrow opens-right opens-left opens-inner');
389        $(document.body).off('.zf.dropdownmenu');
390        Foundation.Nest.Burn(this.$element, 'dropdown');
391        Foundation.unregisterPlugin(this);
392      }
393    }]);
394
395    return DropdownMenu;
396  }();
397
398  /**
399   * Default settings for plugin
400   */
401
402
403  DropdownMenu.defaults = {
404    /**
405     * Disallows hover events from opening submenus
406     * @option
407     * @type {boolean}
408     * @default false
409     */
410    disableHover: false,
411    /**
412     * Allow a submenu to automatically close on a mouseleave event, if not clicked open.
413     * @option
414     * @type {boolean}
415     * @default true
416     */
417    autoclose: true,
418    /**
419     * Amount of time to delay opening a submenu on hover event.
420     * @option
421     * @type {number}
422     * @default 50
423     */
424    hoverDelay: 50,
425    /**
426     * Allow a submenu to open/remain open on parent click event. Allows cursor to move away from menu.
427     * @option
428     * @type {boolean}
429     * @default false
430     */
431    clickOpen: false,
432    /**
433     * Amount of time to delay closing a submenu on a mouseleave event.
434     * @option
435     * @type {number}
436     * @default 500
437     */
438
439    closingTime: 500,
440    /**
441     * Position of the menu relative to what direction the submenus should open. Handled by JS. Can be `'left'` or `'right'`.
442     * @option
443     * @type {string}
444     * @default 'left'
445     */
446    alignment: 'left',
447    /**
448     * Allow clicks on the body to close any open submenus.
449     * @option
450     * @type {boolean}
451     * @default true
452     */
453    closeOnClick: true,
454    /**
455     * Allow clicks on leaf anchor links to close any open submenus.
456     * @option
457     * @type {boolean}
458     * @default true
459     */
460    closeOnClickInside: true,
461    /**
462     * Class applied to vertical oriented menus, Foundation default is `vertical`. Update this if using your own class.
463     * @option
464     * @type {string}
465     * @default 'vertical'
466     */
467    verticalClass: 'vertical',
468    /**
469     * Class applied to right-side oriented menus, Foundation default is `align-right`. Update this if using your own class.
470     * @option
471     * @type {string}
472     * @default 'align-right'
473     */
474    rightClass: 'align-right',
475    /**
476     * Boolean to force overide the clicking of links to perform default action, on second touch event for mobile.
477     * @option
478     * @type {boolean}
479     * @default true
480     */
481    forceFollow: true
482  };
483
484  // Window exports
485  Foundation.plugin(DropdownMenu, 'DropdownMenu');
486}(jQuery);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.