this.$menuLinks = this.$element.find('.is-accordion-submenu-parent');
this.$menuLinks.each(function(){
- var linkId = this.id || Foundation.GetYoDigits(6, 'acc-menu-link'),
+ var linkId = this.id || GetYoDigits(6, 'acc-menu-link'),
$elem = $(this),
$sub = $elem.children('[data-submenu]'),
- subId = $sub[0].id || Foundation.GetYoDigits(6, 'acc-menu'),
+ subId = $sub[0].id || GetYoDigits(6, 'acc-menu'),
isActive = $sub.hasClass('is-active');
- $elem.attr({
- 'aria-controls': subId,
- 'aria-expanded': isActive,
- 'role': 'menuitem',
- 'id': linkId
- });
+
+
+ if(_this.options.submenuToggle) {
+ $elem.addClass('has-submenu-toggle');
+ $elem.children('a').after('<button id="' + linkId + '" class="submenu-toggle" aria-controls="' + subId + '" aria-expanded="' + isActive + '" title="' + _this.options.submenuToggleText + '"><span class="submenu-toggle-text">' + _this.options.submenuToggleText + '</span></button>');
+ } else {
+ $elem.attr({
+ 'aria-controls': subId,
+ 'aria-expanded': isActive,
+ 'role': 'menuitem',
+ 'id': linkId
+ });
+ }
$sub.attr({
'aria-labelledby': linkId,
'aria-hidden': !isActive,
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});
+ $target.addClass('is-active').attr({'aria-hidden': false});
+
+ if(this.options.submenuToggle) {
+ $target.prev('.submenu-toggle').attr({'aria-expanded': true});
+ }
+ else {
+ $target.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]);
- });
- //});
+ $target.slideDown(_this.options.slideSpeed, function () {
+ /**
+ * Fires when the menu is done opening.
+ * @event AccordionMenu#down
+ */
+ _this.$element.trigger('down.zf.accordionMenu', [$target]);
+ });
}
/**
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);
+ if(this.options.submenuToggle) {
+ this.$element.find('.has-submenu-toggle').removeClass('has-submenu-toggle');
+ this.$element.find('.submenu-toggle').remove();
+ }
+
+ Nest.Burn(this.$element, 'accordion');
}
}
/**
* Amount of time to animate the opening of a submenu in ms.
* @option
- * @example 250
+ * @type {number}
+ * @default 250
*/
slideSpeed: 250,
+ /**
+ * Adds a separate submenu toggle button. This allows the parent item to have a link.
+ * @option
+ * @example true
+ */
+ submenuToggle: false,
+ /**
+ * The text used for the submenu toggle if enabled. This is used for screen readers only.
+ * @option
+ * @example true
+ */
+ submenuToggleText: 'Toggle menu',
/**
* Allow the menu to have multiple open panes.
* @option
var items = menu.find('li').attr({'role': 'menuitem'}),
subMenuClass = `is-${type}-submenu`,
subItemClass = `${subMenuClass}-item`,
- hasSubClass = `is-${type}-submenu-parent`;
+ hasSubClass = `is-${type}-submenu-parent`,
+ applyAria = (type !== 'accordion'); // Accordions handle their own ARIA attriutes.
- menu.find('a:first').attr('tabindex', 0);
-
items.each(function() {
var $item = $(this),
$sub = $item.children('ul');
if ($sub.length) {
- $item
- .addClass(hasSubClass)
- .attr({
+ $item.addClass(hasSubClass);
+ $sub.addClass(`submenu ${subMenuClass}`).attr({'data-submenu': ''});
+ if(applyAria) {
+ $item.attr({
'aria-haspopup': true,
- 'aria-expanded': false,
'aria-label': $item.children('a:first').text()
});
-
- $sub.attr({
- 'aria-hidden': true,
+ // Note: Drilldowns behave differently in how they hide, and so need
+ // additional attributes. We should look if this possibly over-generalized
+ // utility (Nest) is appropriate when we rework menus in 6.4
+ if(type === 'drilldown') {
+ $item.attr({'aria-expanded': false});
+ }
-
++ }
+ $sub
+ .addClass(`submenu ${subMenuClass}`)
+ .attr({
+ 'data-submenu': '',
'role': 'menu'
});
+ if(type === 'drilldown') {
+ $sub.attr({'aria-hidden': true});
}
}
/// @type Color
$accordionmenu-arrow-color: $primary-color !default;
+/// Sets accordion menu item padding.
+/// @type Color
+$accordionmenu-item-background: null !default;
+
+/// Sets accordion menu item border.
+/// @type Color
+$accordionmenu-border: 1px solid $light-gray !default;
+
+/// Sets accordion menu item padding.
+/// @type Color
+$accordionmenu-submenu-toggle-background: null !default;
+
+/// Sets accordion menu item padding.
+/// @type List
+$accordion-submenu-toggle-border: $accordionmenu-border !default;
+
+/// Sets accordion menu submenu toggle background width.
+/// @type Number
+$accordionmenu-submenu-toggle-width: 40px !default;
+
+/// Sets accordion menu submenu toggle background height.
+/// @type Number
+$accordionmenu-submenu-toggle-height: $accordionmenu-submenu-toggle-width !default;
+
+ /// Sets accordion menu arrow size if arrow is used.
+ /// @type Length
+ $accordionmenu-arrow-size: 6px !default;
+
@mixin foundation-accordion-menu {
+ .accordion-menu {
+ @if $accordionmenu-border {
+ border-bottom: $accordionmenu-border;
+ }
+
+ li {
+ @if $accordionmenu-border {
+ border-top: $accordionmenu-border;
+ border-right: $accordionmenu-border;
+ border-left: $accordionmenu-border;
+ }
+ }
+
+ .is-accordion-submenu li {
+ @if $accordionmenu-border {
+ border-right: 0;
+ border-left: 0;
+ }
+ }
+
+ a {
+ @if $accordionmenu-item-background {
+ background: $accordionmenu-item-background;
+ }
+ }
+
+ // Submenu li styling
+ .is-accordion-submenu-parent {
+ position: relative;
+
+ & > a {
+ margin-#{$global-right}: $accordionmenu-submenu-toggle-width;
+ }
+ }
+
+ // Submenu toggle
+ .submenu-toggle {
+ position: absolute;
+ top: 0;
+ #{$global-right}: 0;
+
+ width: $accordionmenu-submenu-toggle-width;
+ height: $accordionmenu-submenu-toggle-height;
+
+ border-#{$global-left}: $accordion-submenu-toggle-border;
+
+ @if $accordionmenu-submenu-toggle-background {
+ background: $accordionmenu-submenu-toggle-background;
+ }
+
+ // Add the arrow to the toggle
+ &::after {
+ @include css-triangle(6px, $accordionmenu-arrow-color, down);
+
+ top: 0;
+ bottom: 0;
+ margin: auto;
+ }
+ }
+
+ // Rotate the arrow when menu is open
+ .submenu-toggle[aria-expanded='true']::after {
+ transform: scaleY(-1);
+ transform-origin: 50% 50%;
+ }
+
+ .submenu-toggle-text {
+ @include element-invisible;
+ }
+ }
+
+ // If arrows are enabled, display them
@if $accordionmenu-arrows {
- .is-accordion-submenu-parent > a {
+ .is-accordion-submenu-parent:not(.has-submenu-toggle) > a {
position: relative;
&::after {
- @include css-triangle(6px, $accordionmenu-arrow-color, down);
+ @include css-triangle($accordionmenu-arrow-size, $accordionmenu-arrow-color, down);
+
position: absolute;
- top: 0;
+ top: 50%;
+ margin-top: -1 * ($accordionmenu-arrow-size / 2);
#{$global-right}: 1rem;
- bottom: 0;
-
- margin: auto 0;
}
}