1// Code for Acessible Main menu 2 3jQuery(document).ready(function ($) { 4 5 //adding outline on menu if meniitems focused 6 $('.menuWrapper nav') 7 .on('focusin', function () { 8 $(this).addClass('menu-focused'); 9 }) 10 .on('focusout', function () { 11 let $this = $(this); 12 setTimeout(function () { 13 if (!$this.find(':focus').length) { 14 $this.removeClass('menu-focused'); 15 } 16 }, 10); 17 }); 18 19 20 $('.menuWrapper nav ul ul.sub-menu').each(function () { 21 const $submenu = $(this); 22 const $parentLi = $submenu.closest('li'); // parent <li> with sub-menu 23 const $parentLink = $parentLi.children('a').first(); 24 25 if ($parentLink.length) { 26 const linkText = $.trim($parentLink.clone().children().remove().end().text()); 27 if (linkText !== '') { 28 $submenu.attr('aria-label', linkText + ' submenu'); 29 } 30 } 31 }); 32 33 var top_level_links = jQuery(this).find('li a'); 34 jQuery(top_level_links).each(function () { 35 if (jQuery(this).next('ul').length > 0) { 36 jQuery(this).parent('li').attr('aria-haspopup', 'true'); 37 jQuery(this).parent('li').addClass('has-sub'); 38 jQuery(this).append('<span class="indicator1" aria-hidden="true"></span>') 39 40 } 41 }); 42 43 function updateAriaExpanded($li, expanded) { 44 const $link = $li.children("a"); 45 if ($li.children("ul.sub-menu").length) { 46 $link.attr("aria-expanded", expanded ? "true" : "false"); 47 } else { 48 $link.removeAttr("aria-expanded"); 49 } 50 } 51 52 function openMenu() { 53 if ($("body").hasClass("rtl")) { 54 $("#overflowMenu").animate({ 55 left: "0px" 56 }); 57 } else { 58 $("#overflowMenu").animate({ 59 right: "0px" 60 }); 61 } 62 $('#overflowMenu ul').find(' > li > a').attr('tabindex', 0); 63 $('#overflowMenu a.closeMenu').attr('tabindex', 0); 64 } 65 66 67 function applyAriaRoles() { 68 const $mainMenu = $(".menuWrapper nav > ul"); 69 70 $mainMenu.attr({ 71 "role": "menubar" 72 }); 73 74 const $topLevelLinks = $mainMenu.find("> li > a"); 75 76 $topLevelLinks.each(function (index) { 77 const $link = $(this); 78 $link.attr("role", "menuitem"); 79 $link.attr("tabindex", index === 0 ? "0" : "-1"); 80 81 const $parentLi = $link.closest("li"); 82 $parentLi.attr("role", "none"); 83 84 if ($parentLi.children("ul.sub-menu").length) { 85 $link.attr("aria-haspopup", "true"); 86 updateAriaExpanded($parentLi, false); 87 } else { 88 $link.removeAttr("aria-haspopup aria-expanded"); 89 } 90 }); 91 92 $(".menuWrapper nav ul ul.sub-menu").attr("role", "menu").attr("tabindex", "0"); 93 $(".menuWrapper nav ul ul.sub-menu > li").attr("role", "none"); 94 $(".menuWrapper nav ul ul.sub-menu > li > a").attr("role", "menuitem").attr("tabindex", "-1"); // set all submenu items to -1 initially 95 } 96 97 applyAriaRoles(); 98 99 function closeSubMenu($li) { 100 $li.find("> ul.sub-menu").slideUp().attr("aria-hidden", "true"); 101 updateAriaExpanded($li, false); 102 $li.find("> ul.sub-menu > li > a").attr("tabIndex", -1); 103 $li.find("> ul.sub-menu > li > ul.sub-menu").slideUp().attr("aria-hidden", "true"); 104 $li.find("> ul.sub-menu > li > a").each(function () { 105 updateAriaExpanded($(this).parent(), false); 106 }); 107 } 108 109 function openSubMenu($li, focusLast = false, focusFirst = false) { 110 $li.find("> ul.sub-menu").slideDown().attr("aria-hidden", "false"); 111 updateAriaExpanded($li, true); 112 $li.find("> ul.sub-menu > li > a").attr("tabIndex", 0); 113 if ($li.closest("ul.sub-menu").length > 0) { 114 $li.find("> ul.sub-menu").css({ 115 display: "block", 116 right: "-250px" 117 }); 118 } 119 if (focusLast) { 120 $li.find("> ul.sub-menu > li:last > a").focus(); 121 } else if (focusFirst) { 122 $li.find("> ul.sub-menu > li:first > a").focus(); 123 } 124 } 125 126 function onMenuItemClick(event) { 127 const $submenu = $(this).children("ul.sub-menu"); 128 const $link = $(this).children("a"); 129 if ($submenu.length) { 130 $(this).siblings("li").find("ul.sub-menu").slideUp().attr("aria-hidden", "true") 131 .siblings("a").each(function () { 132 updateAriaExpanded($(this).parent(), false); 133 }); 134 135 const isVisible = $submenu.is(":visible"); 136 // $submenu.slideToggle(); 137 $submenu.attr("aria-hidden", isVisible ? "true" : "false"); 138 updateAriaExpanded($(this), !isVisible); 139 $submenu.find("> li > a").attr("tabIndex", isVisible ? -1 : 0); 140 if ($(this).hasClass("has-sub-child")) { 141 $submenu.css('left', '100%'); 142 } 143 event.stopPropagation(); 144 } 145 } 146 147 $(".menuWrapper nav ul li").each(function () { 148 if ($(this).children("ul.sub-menu").length) { 149 $(this).on("click", onMenuItemClick); 150 } 151 }); 152 153 154 //Keyboard Navigation Handler for Main Menu, Overflow Menu and Submenus 155 156 $(document).on("keydown", function (event) { 157 const $currentElement = $(document.activeElement); 158 159 const $menuWrapper = $(".menuWrapper nav, .moreNav"); 160 if ($menuWrapper.has($currentElement).length === 0) { 161 return; 162 } 163 164 const isMainMenuItem = 165 $currentElement.closest(".menuWrapper nav > ul > li").length > 0 || 166 $currentElement.closest(".moreNav").length > 0; 167 168 const isInSubmenu = $currentElement.closest("ul.sub-menu").length > 0; 169 170 const $mainMenuItems = $(".menuWrapper nav > ul > li > a:visible, .moreNav > a:visible").filter(function () { 171 return $(this).closest("li").parents("ul").length === 1; 172 }); 173 174 const currentIndex = $mainMenuItems.get().indexOf($currentElement[0]); 175 176 const $parentLi = $currentElement.closest("li"); 177 const $submenuItems = isInSubmenu ? $currentElement.closest("ul.sub-menu").find("> li > a") : []; 178 const submenuIndex = isInSubmenu ? $submenuItems.index($currentElement) : -1; 179 180 // ENTER / SPACE 181 if (event.which === 13 || event.which === 32) { 182 event.preventDefault(); 183 if ($parentLi.children("ul.sub-menu").length) { 184 openSubMenu($parentLi, false, true); 185 // $parentLi.children("a").attr("aria-expanded", "true"); 186 } else { 187 window.location.href = $currentElement.attr("href"); 188 // $parentLi.children("a").attr("aria-expanded", "false"); 189 } 190 } 191 192 193 // LEFT / RIGHT / UP / DOWN / HOME / END / ALPHABETICAL KEYS 194 else if ([37, 38, 39, 40, 36, 35].includes(event.which) || (event.key.length === 1 && /[a-zA-Z0-9]/.test(event.key))) { 195 event.preventDefault(); 196 197 if (event.which === 37) { // LEFT 198 if (!isInSubmenu && isMainMenuItem) { 199 const prevIndex = currentIndex > 0 ? currentIndex - 1 : $mainMenuItems.length - 1; 200 $mainMenuItems.eq(prevIndex).focus(); 201 } else if (isInSubmenu) { 202 const $parentMenuItem = $currentElement.closest("ul.sub-menu").parent("li"); 203 closeSubMenu($parentMenuItem); 204 $parentMenuItem.find("> a").focus().attr("aria-expanded", "false"); 205 } 206 } else if (event.which === 39) { // RIGHT 207 let $currentLi = $currentElement.closest("li"); 208 209 // Case 1: On a submenu item that has its own nested submenu 210 if (isInSubmenu) { 211 let $nestedSubmenu = $currentLi.children("ul.sub-menu"); 212 if ($nestedSubmenu.length > 0) { 213 // Open nested submenu 214 $nestedSubmenu.attr("aria-hidden", "false").slideDown().css({ 215 display: "block", 216 right: "-250px" 217 }); 218 $currentLi.children("a").attr("aria-expanded", "true"); 219 220 // Focus first item in nested submenu 221 $nestedSubmenu.find('a[role="menuitem"]:visible').first().focus(); 222 } else { 223 // If no nested submenu, jump to next top-level menu item 224 let $topParentLi = $currentLi; 225 while ($topParentLi.closest("ul.sub-menu").length) { 226 $topParentLi = $topParentLi.closest("ul.sub-menu").parent("li"); 227 } 228 229 // Close all open submenus of this top-level item 230 $topParentLi.find("ul.sub-menu").slideUp().attr("aria-hidden", "true"); 231 $topParentLi.find("a[aria-expanded='true']").attr("aria-expanded", "false"); 232 233 const parentIndex = $mainMenuItems.index($topParentLi.find("> a")); 234 const nextIndex = parentIndex < $mainMenuItems.length - 1 ? parentIndex + 1 : 0; 235 $mainMenuItems.eq(nextIndex).focus(); 236 } 237 } 238 239 // Case 2: On a main menu item (not in submenu) 240 else if (!isInSubmenu && isMainMenuItem) { 241 const nextIndex = currentIndex < $mainMenuItems.length - 1 ? currentIndex + 1 : 0; 242 $mainMenuItems.eq(nextIndex).focus(); 243 } 244 } else if (event.which === 38) { // UP 245 246 if (isInSubmenu) { 247 const newIndex = submenuIndex > 0 ? submenuIndex - 1 : $submenuItems.length - 1; 248 $submenuItems.eq(newIndex).focus(); 249 if ($parentLi.children("ul.sub-menu").length) { 250 $parentLi.children("a").attr("aria-expanded", "true"); 251 } 252 } else if ($parentLi.children("ul.sub-menu").length) { 253 openSubMenu($parentLi, true); 254 } 255 256 } else if (event.which === 40) { // DOWN 257 258 if (isInSubmenu) { 259 const newIndex = submenuIndex < $submenuItems.length - 1 ? submenuIndex + 1 : 0; 260 $submenuItems.eq(newIndex).focus(); 261 if ($parentLi.children("ul.sub-menu").length) { 262 $parentLi.children("a").attr("aria-expanded", "true"); 263 } 264 } else if ($parentLi.children("ul.sub-menu").length) { 265 openSubMenu($parentLi, false, true); 266 } 267 268 } else if (event.which === 36) { // HOME 269 if (isInSubmenu) { 270 $submenuItems.eq(0).focus(); 271 } else { 272 $mainMenuItems.eq(0).focus(); 273 } 274 } else if (event.which === 35) { // END 275 if (isInSubmenu) { 276 $submenuItems.eq($submenuItems.length - 1).focus(); 277 } else { 278 $mainMenuItems.eq($mainMenuItems.length - 1).focus(); 279 } 280 } else if (event.key.length === 1 && /[a-zA-Z0-9]/.test(event.key)) { // First-char nav 281 const searchChar = event.key.toLowerCase(); 282 const items = isInSubmenu ? $submenuItems : $mainMenuItems; 283 let startIndex = isInSubmenu ? submenuIndex + 1 : currentIndex + 1; 284 if (startIndex >= items.length) startIndex = 0; 285 for (let i = 0; i < items.length; i++) {
286 const index = (startIndex + i) % items.length; 287 const itemText = items.eq(index).text().trim().toLowerCase(); 288 if (itemText.startsWith(searchChar)) { 289 items.eq(index).focus(); 290 break; 291 } 292 } 293 } 294 } 295 296 297 }); 298 299 300 $('html').on('click', function (event) { 301 // If clicked outside both main menu and overflow menu 302 if (!$(event.target).closest('.menuWrapper, #overflowMenu').length) { 303 $(".menuWrapper nav ul li ul.sub-menu").each(function () { 304 $(this) 305 .slideUp() 306 .attr("aria-hidden", "true") 307 .find("> li > a") 308 .attr("tabindex", -1); 309 }); 310 $(".menuWrapper nav ul li:has(ul.sub-menu) > a").attr("aria-expanded", "false"); 311 $("#overflowMenu .ofMenu ul li ul.sub-menu").each(function () { 312 $(this) 313 .slideUp() 314 .attr("aria-hidden", "true") 315 .find("> li > a") 316 .attr("tabindex", -1); 317 }); 318 $("#overflowMenu .ofMenu ul li:has(ul.sub-menu) > a").attr("aria-expanded", "false"); 319 } 320 }); 321 322 323 $('.menu').on('click', function (event) { 324 event.stopPropagation(); 325 }); 326 327 // $(".menuWrapper nav ul li").on("keyup", function(event) { 328 // if (event.which === 9) { 329 // $(this).siblings("li").find("ul.sub-menu").hide(); 330 // $(".menuWrapper nav ul li").each(menuEachLiKeyup); 331 // } 332 // }); 333 334 // $(".menuWrapper nav ul li").on("click", onMenuItemClick); 335 336 $(".menuWrapper nav ul li").each(function () { 337 if ($(this).children("ul.sub-menu").length) { 338 $(this).on("click", onMenuItemClick); 339 } 340 }); 341 342 $("nav li li").mouseover(function () { 343 if ($(this).children("ul.sub-menu").length == 1) { 344 let parent = $(this); 345 let child_menu = $(this).children("ul.sub-menu"); 346 if ( 347 $(parent).offset().left + $(parent).width() + $(child_menu).width() > 348 $(window).width() 349 ) { 350 $(child_menu).css("left", "-" + $(parent).width() + "px"); 351 } else { 352 $(child_menu).css("right", "-" + $(parent).width() + "px"); 353 } 354 } 355 }); 356 357 /***** Overflow Navigation Setup *****/ 358 359 if ($(window).innerWidth() >= 640) { 360 let menuContanerWidth = $(".menuWrapper .container").width(), 361 itemsTotalWith = 0; 362 $(".menu > ul > li").each(function (s, a) { 363 let itemClone = $(this).clone(); 364 itemClone.find('a').attr("tabindex", -1); 365 if ( 366 ((itemsTotalWith += $(this).width()), 367 itemsTotalWith > menuContanerWidth - 100 && 368 ($(this).hasClass("moreNav") || 369 ($(this).remove(), 370 $("#overflowMenu .ofMenu > ul").append(itemClone)), 371 !($(".menu ul .moreNav").length > 0))) 372 ) { 373 let n = $( 374 '<li class="moreNav" role="none">' + 375 '<a href="#" role="button" aria-label="More Menu" title="More Menu"><span class="icon-menu" aria-hidden="true"></span><span class="hide">' + 376 $(".menuMoreText").html() + 377 "</span></a></li>" 378 ); 379 $(".menuMoreText").html(""); 380 $(".menu>ul").append(n); 381 n.click(openMenu); 382 } 383 }); 384 } 385 386 // // More Button 387 $(".moreNav a").on("click", function (event) { 388 event.preventDefault(), event.stopPropagation(); 389 openMenu(); 390 }); 391 392 393 $('#overflowMenu').click(function (event) { 394 event.stopPropagation(); 395 }); 396 397 398 $(".ofMenu ul li").on("click", onMenuItemClick); 399 400 $('.ofMenu ul li').hover(function (e) { 401 $(this).siblings().children('ul.sub-menu').slideUp(); 402 $(this).children('ul.sub-menu').slideDown(); 403 }, function () { 404 $(this).parent().siblings().children('ul.sub-menu').slideUp(); 405 }); 406 407 /***** Responsive Navigation Setup *****/ 408
409 $(".menuToggle").click(function (event) { 410 event.preventDefault(); 411 $(".menuWrapper").stop().slideToggle(); 412 }); 413 414 if ($(window).width() <= 639) { 415 $(".menu ul li").each(function (index, element) { 416 $(this).off('click'); 417 if ($(this).children("ul").length) { 418 $(".indicator").hide(); 419 $("<a href='javascript:void(0)' aria-label='Click to expand submenu' class='menu-toggle'> </a>") 420 .insertAfter($(element).find(" > a ")); 421 } 422 }); 423 } 424 425 $(".menu-toggle").click(function (event) { 426 event.preventDefault(); 427 $(this).toggleClass("open").parents('li').siblings().children("ul.sub-menu").stop().slideUp('fast'); 428 $(this).next("ul.sub-menu").slideToggle('fast'); 429 430 $(this).parents('li').siblings().children("a").removeClass("open"); 431 $(this).parents('li').siblings().children("a.menu-select").removeClass("menu-select"); 432 $(this).prev().toggleClass("menu-select"); 433 434 var menuTitle = $(this).closest("li").find("> a").text().trim(); 435 var collapseText = S3WaaSAccessibilityParams.clickToCollapse; 436 var expandText = S3WaaSAccessibilityParams.clickToExpand; 437 var submenuWord = S3WaaSAccessibilityParams.submenu; 438 439 if ($(this).hasClass("open")) { 440 $(this).attr("aria-label", collapseText + " " + menuTitle + " " + submenuWord).removeAttr("aria-expanded").attr("aria-expanded", "true"); 441 } else { 442 $(this).attr("aria-label", expandText + " " + menuTitle + " " + submenuWord).removeAttr("aria-expanded").attr("aria-expanded", "false"); 443 } 444 }); 445 446 447 jQuery(".menuWrapper nav ul li ul.sub-menu > li > a, #overflowMenu .ofMenu ul li ul.submenu > li > a").on("keydown", function (event) { 448 const $submenu = $(this).closest("ul.sub-menu"); 449 const $submenuItems = $submenu.find("> li > a"); 450 const currentIndex = $submenuItems.index(this); 451 452 // Trap focus within submenu 453 if (event.which === 9) { // Tab key 454 if (!event.shiftKey && currentIndex === $submenuItems.length - 1) { 455 event.preventDefault(); 456 $submenuItems.eq(0).focus(); 457 } else if (event.shiftKey && currentIndex === 0) { 458 event.preventDefault(); 459 $submenuItems.eq($submenuItems.length - 1).focus(); 460 } 461 } 462 463 if (event.which === 27) { // Escape key 464 const $parentLi = $submenu.parent("li"); 465 closeSubMenu($parentLi); 466 $parentLi.find("> a").focus().attr('aria-expanded', 'false'); 467 event.preventDefault(); 468 469 } 470 471 472 }); 473 474 //if no submenu is open and esc key pressed move focus to first focusable element in main 475 jQuery(".menuWrapper nav > ul > li > a").on("keydown", function (event) { 476 if (event.which === 27) { 477 const $levelFirstMenu = jQuery(this).closest("ul.sub-menu"); 478 479 if ($levelFirstMenu.length === 0) { 480 const $firstMainLink = jQuery("main a:visible").first(); 481 if ($firstMainLink.length) { 482 $firstMainLink.focus(); 483 } 484 event.preventDefault(); 485 } 486 } 487 }); 488 489 490}); 491 492jQuery(document).ready(function ($) { 493 const $ov = $('#overflowMenu'); 494 const ovWidth = $ov.width(); 495 496 // Ensure menu is collapsed on load 497 $('.moreNav > a').attr('aria-expanded', 'false'); 498 $ov.hide().css('right', -ovWidth); 499 $ov.find('.sub-menu').hide().attr('aria-hidden', 'true'); 500 $ov.find('a').attr('tabindex', -1); 501 502 const $toggleButton = $('.moreNav > a'); 503 $toggleButton.attr({ 504 'aria-haspopup': 'true', 505 'aria-expanded': 'false', 506 'aria-controls': 'overflowMenu' // connects to the popup menu 507 }); 508 $ov.attr({ 509 'role': 'dialog',
510 'aria-modal': 'true' 511 }); 512 513 function applyAttributes() { 514 $ov.find('.ofMenu > ul').attr('role', 'menu'); 515 $ov.find('li').attr('role', 'none'); 516 $ov.find('a').attr('role', 'menuitem'); 517 $ov.find('li:has(ul.sub-menu) > a') 518 .attr('aria-haspopup', 'true') 519 .attr('aria-expanded', 'false') 520 .attr('tabindex', -1); 521 $ov.find('ul.sub-menu') 522 .attr('role', 'menu') 523 .attr('aria-hidden', 'true') 524 .hide(); 525 } 526 applyAttributes(); 527 528 function trapWithin($container) { 529 const $focusables = $container.find('a:visible, button:visible').filter('[tabindex!="-1"]'); 530 const first = $focusables.first(); 531 const last = $focusables.last(); 532 533 $focusables.off('keydown.trap').on('keydown.trap', function (e) { 534 const $items = $focusables; 535 const currentIndex = $items.index(this); 536 537 if (e.key === 'Tab') { 538 if (e.shiftKey && this === first[0]) { 539 e.preventDefault(); 540 last.focus(); 541 } else if (!e.shiftKey && this === last[0]) { 542 e.preventDefault(); 543 first.focus(); 544 } 545 } 546 547 if (e.key === 'ArrowDown') { 548 e.preventDefault(); 549 const nextIndex = (currentIndex + 1) % $items.length; 550 $items.eq(nextIndex).focus(); 551 } 552 553 if (e.key === 'ArrowUp') { 554 e.preventDefault(); 555 const prevIndex = (currentIndex - 1 + $items.length) % $items.length; 556 $items.eq(prevIndex).focus(); 557 } 558 }); 559 } 560 561 function openOverflow() { 562 if ($ov.is(':visible')) return; 563 564 $toggleButton.attr('aria-expanded', 'true'); 565 566 $ov.css({ 567 right: -ovWidth, 568 display: 'block' 569 }).animate({ 570 right: 0 571 }, 400, function () { 572 $ov.find('a').attr('tabindex', 0); 573 // const $firstItem = $ov.find('.ofMenu > ul > li > a:visible').first(); 574 // $firstItem.focus(); 575 $ov.focus().css('outline', '2px solid black') 576 trapWithin($ov); 577 578 announceMenuStatus('More menu expanded'); 579 }); 580 } 581 582 583 function closeOverflow() { 584 $ov.animate({ 585 right: -ovWidth 586 }, 400, function () { 587 $ov.css('display', 'none'); 588 $ov.find('a').attr('tabindex', -1); 589 $ov.find('[aria-expanded="true"]').each(function () { 590 $(this) 591 .attr('aria-expanded', 'false') 592 .next('ul.sub-menu') 593 .hide() 594 .attr('aria-hidden', 'true'); 595 }); 596 $ov.find('*').off('keydown.trap'); 597 $toggleButton.attr('aria-expanded', 'false').focus(); 598 599 announceMenuStatus('More menu collapsed'); 600 }); 601 } 602 603 function toggleSubmenu($link, open) { 604 const $sub = $link.next('.sub-menu'); 605 $link.attr('aria-expanded', open); 606 $sub.attr('aria-hidden', !open)[open ? 'slideDown' : 'slideUp'](); 607 if (open) { 608 const $first = $sub.find('a:visible').first().focus(); 609 trapWithin($sub); 610 } else { 611 $sub.find('*').off('keydown.trap'); 612 $link.focus(); 613 } 614 } 615 616 $('.moreNav > a').on('click keydown', function (e) { 617 if (e.type === 'click' || e.key === 'Enter' || e.key === ' ') { 618 e.preventDefault(); 619 openOverflow(); 620 } 621 }); 622 623 $ov.find('.closeMenu').on('click keydown', function (e) { 624 if (e.type === 'click' || e.key === 'Enter' || e.key === ' ') { 625 e.preventDefault(); 626 closeOverflow(); 627 } 628 }); 629 630 $ov.on('keydown', 'a', function (e) { 631 const key = e.which; 632 const $link = $(this); 633 const $li = $link.parent('li'); 634 const isParent = $li.children('ul.sub-menu').length > 0; 635 let $all = $ov.find('a:visible'); 636 let idx = $all.index(this); 637 638 if ([13, 32].includes(key)) { 639 e.preventDefault(); 640 if (isParent) { 641 toggleSubmenu($link, $link.attr('aria-expanded') == 'false'); 642 } else { 643 location.href = $link.attr('href'); 644 } 645 } else if (key === 27) { 646 const $visibleSubmenus = $ov.find('ul.sub-menu:visible').filter(function () { 647 return $(this).css('display') !== 'none'; 648 }); 649 650 if ($visibleSubmenus.length > 0) { 651 const $deepestSubmenu = $visibleSubmenus.sort((a, b) => { 652 return $(a).parents('ul.sub-menu').length - $(b).parents('ul.sub-menu').length; 653 }
653).last(); 654 655 const $parentLi = $deepestSubmenu.parent('li'); 656 const $parentLink = $parentLi.children('a'); 657 658 $deepestSubmenu.slideUp().attr('aria-hidden', 'true'); 659 $parentLink.attr('aria-expanded', 'false'); 660 $deepestSubmenu.find('*').off('keydown.trap'); 661 $parentLink.focus(); 662 } else { 663 closeOverflow(); 664 } 665 e.preventDefault(); 666 } else if (key === 37) { 667 e.preventDefault(); 668 const $submenu = $link.closest('ul.sub-menu'); 669 const $allMain = $ov.find('.ofMenu > ul > li > a:visible'); 670 671 if ($submenu.length > 0) { 672 const $parentLi = $submenu.parent('li'); 673 const $parentLink = $parentLi.children('a'); 674 $submenu.slideUp().attr('aria-hidden', 'true'); 675 $parentLink.attr('aria-expanded', 'false'); 676 $parentLink.focus(); 677 } else { 678 const prev = (idx - 1 + $all.length) % $all.length; 679 $all.eq(prev).focus(); 680 } 681 } else if (key === 39) { 682 e.preventDefault(); 683 const $submenu = $link.closest('ul.sub-menu'); 684 const $allMain = $ov.find('.ofMenu > ul > li > a:visible'); 685 686 if ($submenu.length > 0) { 687 const $parentLi = $submenu.parent('li'); 688 const $parentLink = $parentLi.children('a'); 689 $submenu.slideUp().attr('aria-hidden', 'true'); 690 $parentLink.attr('aria-expanded', 'false'); 691 const mainIdx = $allMain.index($parentLink); 692 const nextIdx = (mainIdx + 1) % $allMain.length; 693 $allMain.eq(nextIdx).focus(); 694 } else { 695 const next = (idx + 1) % $all.length; 696 $all.eq(next).focus(); 697 } 698 } else if (key === 36) { 699 e.preventDefault(); 700 $all.first().focus(); 701 } else if (key === 35) { 702 e.preventDefault(); 703 $all.last().focus(); 704 } 705 }); 706 707 $(document).on('click', function (e) { 708 if ($ov.is(':visible') && !$(e.target).closest('#overflowMenu, .moreNav').length) { 709 closeOverflow(); 710 } 711 }); 712 713 $(window).on('unload', function () { 714 $ov.hide().css('right', -ovWidth); 715 $ov.find('.sub-menu').hide().attr('aria-hidden', 'true'); 716 $ov.find('a').attr('tabindex', -1); 717 $ov.find('[aria-expanded="true"]').attr('aria-expanded', 'false'); 718 }); 719 720 // Append HTML in body for screen reader purpose only 721 if ($('#menu-status').length === 0) { 722 $('body').append('<div id="menu-status" role="status" aria-live="polite" style="position:absolute;left:-9999px;width:1px;height:1px;overflow:hidden;"></div>'); 723 } 724 725 // overflow menu expand/collapse message for screen reader 726 function announceMenuStatus(message) { 727 const $status = $('#menu-status'); 728 $status.text(''); // Clear first to force re-announcement 729 setTimeout(() => $status.text(message), 10); 730 } 731 732 733});
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.