'use strict'; var _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; }; }(); function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } !function ($) { /** * AccordionMenu module. * @module foundation.accordionMenu * @requires foundation.util.keyboard * @requires foundation.util.motion * @requires foundation.util.nest */ var AccordionMenu = function () { /** * Creates a new instance of an accordion menu. * @class * @fires AccordionMenu#init * @param {jQuery} element - jQuery object to make into an accordion menu. * @param {Object} options - Overrides to the default plugin settings. */ function AccordionMenu(element, options) { _classCallCheck(this, AccordionMenu); this.$element = element; this.options = $.extend({}, AccordionMenu.defaults, this.$element.data(), options); Foundation.Nest.Feather(this.$element, 'accordion'); this._init(); Foundation.registerPlugin(this, 'AccordionMenu'); Foundation.Keyboard.register('AccordionMenu', { 'ENTER': 'toggle', 'SPACE': 'toggle', 'ARROW_RIGHT': 'open', 'ARROW_UP': 'up', 'ARROW_DOWN': 'down', 'ARROW_LEFT': 'close', 'ESCAPE': 'closeAll', 'TAB': 'down', 'SHIFT_TAB': 'up' }); } /** * Initializes the accordion menu by hiding all nested menus. * @private */ _createClass(AccordionMenu, [{ key: '_init', value: function _init() { this.$element.find('[data-submenu]').not('.is-active').slideUp(0); //.find('a').css('padding-left', '1rem'); this.$element.attr({ 'role': 'tablist', 'aria-multiselectable': this.options.multiOpen }); this.$menuLinks = this.$element.find('.is-accordion-submenu-parent'); this.$menuLinks.each(function () { var linkId = this.id || Foundation.GetYoDigits(6, 'acc-menu-link'), $elem = $(this), $sub = $elem.children('[data-submenu]'), subId = $sub[0].id || Foundation.GetYoDigits(6, 'acc-menu'), isActive = $sub.hasClass('is-active'); $elem.attr({ 'aria-controls': subId, 'aria-expanded': isActive, 'role': 'tab', 'id': linkId }); $sub.attr({ 'aria-labelledby': linkId, 'aria-hidden': !isActive, 'role': 'tabpanel', 'id': subId }); }); var initPanes = this.$element.find('.is-active'); if (initPanes.length) { var _this = this; initPanes.each(function () { _this.down($(this)); }); } this._events(); } /** * Adds event handlers for items within the menu. * @private */ }, { key: '_events', value: function _events() { var _this = this; this.$element.find('li').each(function () { var $submenu = $(this).children('[data-submenu]'); if ($submenu.length) { $(this).children('a').off('click.zf.accordionMenu').on('click.zf.accordionMenu', function (e) { e.preventDefault(); _this.toggle($submenu); }); } }).on('keydown.zf.accordionmenu', function (e) { var $element = $(this), $elements = $element.parent('ul').children('li'), $prevElement, $nextElement, $target = $element.children('[data-submenu]'); $elements.each(function (i) { if ($(this).is($element)) { $prevElement = $elements.eq(Math.max(0, i - 1)).find('a').first(); $nextElement = $elements.eq(Math.min(i + 1, $elements.length - 1)).find('a').first(); if ($(this).children('[data-submenu]:visible').length) { // has open sub menu $nextElement = $element.find('li:first-child').find('a').first(); } if ($(this).is(':first-child')) { // is first element of sub menu $prevElement = $element.parents('li').first().find('a').first(); } else if ($prevElement.children('[data-submenu]:visible').length) { // if previous element has open sub menu $prevElement = $prevElement.find('li:last-child').find('a').first(); } if ($(this).is(':last-child')) { // is last element of sub menu $nextElement = $element.parents('li').first().next('li').find('a').first(); } return; } }); Foundation.Keyboard.handleKey(e, 'AccordionMenu', { open: function () { if ($target.is(':hidden')) { _this.down($target); $target.find('li').first().find('a').first().focus(); } }, close: function () { if ($target.length && !$target.is(':hidden')) { // close active sub of this item _this.up($target); } else if ($element.parent('[data-submenu]').length) { // close currently open sub _this.up($element.parent('[data-submenu]')); $element.parents('li').first().find('a').first().focus(); } }, up: function () { $prevElement.attr('tabindex', -1).focus(); return true; }, down: function () { $nextElement.attr('tabindex', -1).focus(); return true; }, toggle: function () { if ($element.children('[data-submenu]').length) { _this.toggle($element.children('[data-submenu]')); } }, closeAll: function () { _this.hideAll(); }, handled: function (preventDefault) { if (preventDefault) { e.preventDefault(); } e.stopImmediatePropagation(); } }); }); //.attr('tabindex', 0); } /** * Closes all panes of the menu. * @function */ }, { key: 'hideAll', value: function hideAll() { this.$element.find('[data-submenu]').slideUp(this.options.slideSpeed); } /** * Toggles the open/close state of a submenu. * @function * @param {jQuery} $target - the submenu to toggle */ }, { key: 'toggle', value: function toggle($target) { if (!$target.is(':animated')) { if (!$target.is(':hidden')) { this.up($target); } else { this.down($target); } } } /** * Opens the sub-menu defined by `$target`. * @param {jQuery} $target - Sub-menu to open. * @fires AccordionMenu#down */ }, { key: 'down', value: function down($target) { var _this = this; if (!this.options.multiOpen) { this.up(this.$element.find('.is-active').not($target.parentsUntil(this.$element).add($target))); } $target.addClass('is-active').attr({ 'aria-hidden': false }).parent('.is-accordion-submenu-parent').attr({ 'aria-expanded': true }); //Foundation.Move(this.options.slideSpeed, $target, function() { $target.slideDown(_this.options.slideSpeed, function () { /** * Fires when the menu is done opening. * @event AccordionMenu#down */ _this.$element.trigger('down.zf.accordionMenu', [$target]); }); //}); } /** * Closes the sub-menu defined by `$target`. All sub-menus inside the target will be closed as well. * @param {jQuery} $target - Sub-menu to close. * @fires AccordionMenu#up */ }, { key: 'up', value: function up($target) { var _this = this; //Foundation.Move(this.options.slideSpeed, $target, function(){ $target.slideUp(_this.options.slideSpeed, function () { /** * Fires when the menu is done collapsing up. * @event AccordionMenu#up */ _this.$element.trigger('up.zf.accordionMenu', [$target]); }); //}); var $menus = $target.find('[data-submenu]').slideUp(0).addBack().attr('aria-hidden', true); $menus.parent('.is-accordion-submenu-parent').attr('aria-expanded', false); } /** * Destroys an instance of accordion menu. * @fires AccordionMenu#destroyed */ }, { key: 'destroy', value: function destroy() { this.$element.find('[data-submenu]').slideDown(0).css('display', ''); this.$element.find('a').off('click.zf.accordionMenu'); Foundation.Nest.Burn(this.$element, 'accordion'); Foundation.unregisterPlugin(this); } }]); return AccordionMenu; }(); AccordionMenu.defaults = { /** * Amount of time to animate the opening of a submenu in ms. * @option * @example 250 */ slideSpeed: 250, /** * Allow the menu to have multiple open panes. * @option * @example true */ multiOpen: true }; // Window exports Foundation.plugin(AccordionMenu, 'AccordionMenu'); }(jQuery);