307 lines
9.9 KiB
JavaScript
307 lines
9.9 KiB
JavaScript
|
'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);
|