* fix: eslint operator-linebreak issue * fix: eslint quotes issue * fix: react jsx indent and props issues * fix: eslint trailing spaces issues * fix: eslint line around directives issue * fix: eslint semi rule * fix: eslint newline per chain rule * fix: eslint space infix ops rule * fix: eslint space-in-parens issue * fix: eslint space before function paren issue * fix: eslint space before blocks issue * fix: eslint arrow body style issue * fix: eslint dot-location issue * fix: eslint quotes issue * fix: eslint quote props issue * fix: eslint operator assignment issue * fix: eslint new line after import issue * fix: indent issues * fix: operator assignment issue * fix: all autofixable eslint issues * fix: all react related fixable issues * fix: autofixable eslint issues * chore: remove all template literals * fix: remaining autofixable issues * fix: failing js test
185 lines
7.7 KiB
JavaScript
185 lines
7.7 KiB
JavaScript
/**
|
|
* Ensuring collapsible and accessible components on multiple
|
|
* screen sizes for the responsive lms header.
|
|
*/
|
|
|
|
function createMobileMenu() {
|
|
/**
|
|
* Dynamically create a mobile menu from all specified mobile links
|
|
* on the page.
|
|
*/
|
|
|
|
'use strict';
|
|
|
|
$('.mobile-nav-item').each(function() {
|
|
var mobileNavItem = $(this).clone().addClass('mobile-nav-link');
|
|
mobileNavItem.removeAttr('role');
|
|
mobileNavItem.find('a').attr('role', 'menuitem');
|
|
// xss-lint: disable=javascript-jquery-append
|
|
$('.mobile-menu').append(mobileNavItem);
|
|
});
|
|
}
|
|
|
|
$(document).ready(function() {
|
|
'use strict';
|
|
|
|
var $hamburgerMenu;
|
|
var $mobileMenu;
|
|
// Toggling visibility for the user dropdown
|
|
$('.global-header .toggle-user-dropdown, .global-header .toggle-user-dropdown span').click(function(e) {
|
|
var $dropdownMenu = $('.global-header .nav-item .dropdown-user-menu');
|
|
var $userDropdown = $('.global-header .toggle-user-dropdown');
|
|
if ($dropdownMenu.is(':visible')) {
|
|
$dropdownMenu.addClass('hidden');
|
|
$userDropdown.attr('aria-expanded', 'false');
|
|
} else {
|
|
$dropdownMenu.removeClass('hidden');
|
|
$dropdownMenu.find('.dropdown-item')[0].focus();
|
|
$userDropdown.attr('aria-expanded', 'true');
|
|
}
|
|
$('.global-header .toggle-user-dropdown').toggleClass('open');
|
|
e.stopPropagation();
|
|
});
|
|
|
|
// Hide user dropdown on click away
|
|
if ($('.global-header .nav-item .dropdown-user-menu').length) {
|
|
$(window).click(function(e) {
|
|
var $dropdownMenu = $('.global-header .nav-item .dropdown-user-menu');
|
|
var $userDropdown = $('.global-header .toggle-user-dropdown');
|
|
if ($userDropdown.is(':visible') && !$(e.target).is('.dropdown-item, .toggle-user-dropdown')) {
|
|
$dropdownMenu.addClass('hidden');
|
|
$userDropdown.attr('aria-expanded', 'false');
|
|
}
|
|
});
|
|
}
|
|
|
|
// Toggling menu visibility with the hamburger menu
|
|
$('.global-header .hamburger-menu').click(function() {
|
|
$hamburgerMenu = $('.global-header .hamburger-menu');
|
|
$mobileMenu = $('.mobile-menu');
|
|
if ($mobileMenu.is(':visible')) {
|
|
$mobileMenu.addClass('hidden');
|
|
$hamburgerMenu.attr('aria-expanded', 'false');
|
|
} else {
|
|
$mobileMenu.removeClass('hidden');
|
|
$hamburgerMenu.attr('aria-expanded', 'true');
|
|
}
|
|
$hamburgerMenu.toggleClass('open');
|
|
});
|
|
|
|
// Hide hamburger menu if no nav items (sign in and register pages)
|
|
if ($('.mobile-nav-item').size() === 0) {
|
|
$('.global-header .hamburger-menu').addClass('hidden');
|
|
}
|
|
|
|
createMobileMenu();
|
|
});
|
|
|
|
// Accessibility keyboard controls for user dropdown and mobile menu
|
|
$('.mobile-menu, .global-header').on('keydown', function(e) {
|
|
'use strict';
|
|
|
|
var isNext,
|
|
nextLink,
|
|
loopFirst,
|
|
loopLast,
|
|
$curTarget = $(e.target),
|
|
isLastItem = $curTarget.parent().is(':last-child'),
|
|
isToggle = $curTarget.hasClass('toggle-user-dropdown'),
|
|
isHamburgerMenu = $curTarget.hasClass('hamburger-menu'),
|
|
isMobileOption = $curTarget.parent().hasClass('mobile-nav-link'),
|
|
isDropdownOption = !isMobileOption && $curTarget.parent().hasClass('dropdown-item'),
|
|
$userDropdown = $('.global-header .user-dropdown'),
|
|
$hamburgerMenu = $('.global-header .hamburger-menu'),
|
|
$toggleUserDropdown = $('.global-header .toggle-user-dropdown');
|
|
|
|
// Open or close relevant menu on enter or space click and focus on first element.
|
|
if ((e.key === 'Enter' || e.key === 'Space') && (isToggle || isHamburgerMenu)) {
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
|
|
$curTarget.click();
|
|
if (isHamburgerMenu) {
|
|
if ($('.mobile-menu').is(':visible')) {
|
|
$hamburgerMenu.attr('aria-expanded', true);
|
|
$('.mobile-menu .mobile-nav-link a').first().focus();
|
|
} else {
|
|
$hamburgerMenu.attr('aria-expanded', false);
|
|
}
|
|
} else if (isToggle) {
|
|
if ($('.global-header .nav-item .dropdown-user-menu').is(':visible')) {
|
|
$userDropdown.attr('aria-expanded', 'true');
|
|
$('.global-header .dropdown-item a:first').focus();
|
|
} else {
|
|
$userDropdown.attr('aria-expanded', false);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Enable arrow functionality within the menu.
|
|
if ((e.key === 'ArrowUp' || e.key === 'ArrowDown') && (isDropdownOption || isMobileOption
|
|
|| (isHamburgerMenu && $hamburgerMenu.hasClass('open')) || isToggle && $toggleUserDropdown.hasClass('open'))) {
|
|
isNext = e.key === 'ArrowDown';
|
|
if (isNext && !isHamburgerMenu && !isToggle && isLastItem) {
|
|
// Loop to the start from the final element
|
|
nextLink = isDropdownOption ? $toggleUserDropdown : $hamburgerMenu;
|
|
} else if (!isNext && (isHamburgerMenu || isToggle)) {
|
|
// Loop to the end when up arrow pressed from menu icon
|
|
nextLink = isHamburgerMenu ? $('.mobile-menu .mobile-nav-link a').last()
|
|
: $('.global-header .dropdown-user-menu .dropdown-nav-item').last().find('a');
|
|
} else if (isNext && (isHamburgerMenu || isToggle)) {
|
|
// Loop to the first element from the menu icon
|
|
nextLink = isHamburgerMenu ? $('.mobile-menu .mobile-nav-link a').first()
|
|
: $('.global-header .dropdown-user-menu .dropdown-nav-item').first().find('a');
|
|
} else {
|
|
// Loop up to the menu icon if first element in menu
|
|
if (!isNext && $curTarget.parent().is(':first-child') && !isHamburgerMenu && !isToggle) {
|
|
nextLink = isDropdownOption ? $toggleUserDropdown : $hamburgerMenu;
|
|
} else {
|
|
nextLink = isNext
|
|
? $curTarget.parent().next().find('a') // eslint-disable-line newline-per-chained-call
|
|
: $curTarget.parent().prev().find('a'); // eslint-disable-line newline-per-chained-call
|
|
}
|
|
}
|
|
nextLink.focus();
|
|
|
|
// Don't let the screen scroll on navigation
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
}
|
|
|
|
// Escape clears out of the menu
|
|
if (e.key === 'Escape' && (isDropdownOption || isHamburgerMenu || isMobileOption || isToggle)) {
|
|
if (isDropdownOption || isToggle) {
|
|
$('.global-header .nav-item .dropdown-user-menu').addClass('hidden');
|
|
$toggleUserDropdown.focus()
|
|
.attr('aria-expanded', 'false');
|
|
$('.global-header .toggle-user-dropdown').removeClass('open');
|
|
} else {
|
|
$('.mobile-menu').addClass('hidden');
|
|
$hamburgerMenu.focus()
|
|
.attr('aria-expanded', 'false')
|
|
.removeClass('open');
|
|
}
|
|
}
|
|
|
|
// Loop when tabbing and using arrows
|
|
if ((e.key === 'Tab') && ((isDropdownOption && isLastItem) || (isMobileOption && isLastItem) || (isHamburgerMenu
|
|
&& $hamburgerMenu.hasClass('open')) || (isToggle && $toggleUserDropdown.hasClass('open')))) {
|
|
nextLink = null;
|
|
loopFirst = isLastItem && !e.shiftKey && !isHamburgerMenu && !isToggle;
|
|
loopLast = (isHamburgerMenu || isToggle) && e.shiftKey;
|
|
if (!(loopFirst || loopLast)) {
|
|
return;
|
|
}
|
|
e.preventDefault();
|
|
if (isDropdownOption || isToggle) {
|
|
nextLink = loopFirst ? $toggleUserDropdown
|
|
: $('.global-header .dropdown-user-menu .dropdown-nav-item a').last();
|
|
} else {
|
|
nextLink = loopFirst ? $hamburgerMenu : $('.mobile-menu .mobile-nav-link a').last();
|
|
}
|
|
nextLink.focus();
|
|
}
|
|
});
|