1(function($) { 2 3 /* globals jQuery */ 4 5 "use strict"; 6 7 /** 8 * Accesibility | Keyboard Support 9 PBL 10 */ 11 12 // FIX: prevent site scroll when Toggle or Accordion open by SPACE key 13 14 document.addEventListener('keydown', function(e) { 15 if ((e.code === 'Space' || e.keyCode === 32)) { 16 const el = e.target; 17 if (el.classList.contains('mfn-toggle-item') || el.classList.contains('question')) { 18 e.preventDefault(); // prevent default site scroll 19 } 20 } 21 }, { capture: true }); 22 23 // keyboard events 24 25 var keyboard = { 26 27 keysTriggered: { // multitasking alike 28 Tab: false, Enter: false, ShiftLeft: false, ShiftRight: false, Escape: false, 29 ArrowLeft: false, ArrowRight: false, ArrowUp: false, ArrowDown: false, Space: false 30 }, 31 32 utils: { 33 isSimpleHamburgerStack: !($('body').hasClass('header-simple') && !$('body').hasClass('mobile-side-slide')), 34 switchExpanded: (el, state) => $(el).attr('aria-expanded', state).parent('li').attr('aria-expanded', state), // FIX: .parent('li') - add aria-expanded to megamenu parent li 35 isHeaderBuilderEnabled: $('body').hasClass('mfn-header-template'), 36 }, 37 38 menuLinks: [...$('#menu .menu-item a').not('.menu-toggle').toArray(), $('a.mfn-menu-link').toArray()], 39 subheaderLinks: $('#Subheader a').toArray(), 40 wooPopup: $('.mfn-header-login').find('a, input').toArray(), 41 contentLinks: [...$('#Content a').toArray(), ...$('#Footer a').toArray()], 42 43 clickListener() { 44 45 jQuery(document).on('keydown', 'a, *[role="link"], *[role="button"], input, button', ( e ) => { 46 47 let { originalEvent } = e; 48 let { code : keyClicked } = originalEvent; 49 50 if ( keyClicked in this.keysTriggered ) { 51 this.keysTriggered[keyClicked] = true; 52 } 53 54 // event BEFORE default browser behavior 55 56 let { Tab, ShiftLeft, ShiftRight } = this.keysTriggered; 57 58 if( Tab && ! (ShiftLeft || ShiftRight)){ 59 60 const focusedElement = $(':focus'); 61 62 // prevent tab outside search window 63 64 if( focusedElement.hasClass('icon_close') ){ 65 if( focusedElement.closest('.search_wrapper').find('.mfn-live-search-box').is(':hidden') ){ 66 return false; 67 } 68 } 69 } 70 71 if( Tab && (ShiftLeft || ShiftRight)){ 72 73 const focusedElement = $(':focus'); 74 75 // prevent tab * shift outside search window 76 77 if( focusedElement.is('[name="s"]') ){ 78 return false; 79 } 80 } 81 82 // event AFTER default browser behavior 83 84 setTimeout( _ => this.recognizeGesture(e), 1); 85 }); 86 87 jQuery(document).on('keyup', 'a, *[role="link"], *[role="button"], input, button', ( e ) => { 88 let { originalEvent } = e; 89 let { code : keyClicked } = originalEvent; 90 91 if ( keyClicked in this.keysTriggered ) { 92 this.keysTriggered[keyClicked] = false; 93 } 94 95 setTimeout( _ => this.recognizeGesture(e), 1); 96 }); 97 98 jQuery('#skip-links-menu').one('focus', 'a', function(){ 99 $('#skip-links-menu').css('top', '0px'); 100 }); 101 }, 102 103 skipLinks() { 104 if( $(':focus').closest('nav').is('#skip-links-menu') ) { 105 $('#skip-links-menu').css('top', '0px'); 106 } else { 107 $('#skip-links-menu').css('top', '-200px'); 108 } 109 }, 110 111 recognizeGesture(e) { 112 let { Tab, ShiftLeft, ShiftRight, ArrowDown, ArrowUp, ArrowLeft, ArrowRight, Enter, Escape, Space } = this.keysTriggered; 113 const focusedElement = $(':focus'); 114 let modalOpened = $('*[aria-expanded=true]:not(#menu):not(.sub-menu)'); 115 const menuOpened = $('nav#menu').find('*[aria-expanded=true]'); 116 const domPrefix = $('body').hasClass('side-slide-is-open') ? '.extras-wrapper ' : '.top_bar_right '; 117 const isHeaderBuilderEnabled = $('body').hasClass('mfn-header-template'); 118 const shouldChangeDirection = () => { 119 let shouldChange = false; 120 121 if ($('body').hasClass('rtl')) shouldChange = true; // RTL 122 if ($('body').hasClass('header-rtl')) shouldChange = true; // Header Right | Ex. Creative Right 123 124 return shouldChange; 125 } 126 127 /* CLOSE MODALS WHEN CURSOR IS OUTSIDE OF IT --- FORCE !!! */ 128 if( $(modalOpened).length && !focusedElement.closest(modalOpened).length) { 129 // If Side_slide is opened, then modals should be closed first ALWAYS 130 // classList object| it will recog if item is from DOM, not just a trash code from jquery 131 const elementToClose = Object.values(modalOpened).filter( 132 (modal) => (modal.classList && $(modal).attr('id') !== 'Side_slide') 133 ) 134 modalOpened = !elementToClose.length ? modalOpened : $(elementToClose[0]); 135 136 // WooModal - when outside of login modal, go to first link 137 if ( $(modalOpened).hasClass('mfn-header-login') || $(modalOpened).hasClass('woocommerce-MyAccount-navigation') ) { 138 $(modalOpened).closest('.mfn-header-login[aria-disabled=false]').find('a').first().focus(); 139 return; 140 } 141 142 // All other modals are using mfn-close-icon class, Side_slide is exception 143 if( modalOpened.attr('id') !== 'Side_slide' && modalOpened.attr('aria-expanded') == 'true') { 144 145 if( $(modalOpened).siblings('.mfn-close-icon').length ){ 146 $(modalOpened).siblings('.mfn-close-icon').trigger('click'); 147 } else { 148 $(modalOpened).find('.mfn-close-icon').trigger('click'); 149 } 150 } 151 152 // HB 2.0 --- do not close if modal of megamenu/sideslide is opened 153 if ( !$(modalOpened).is(focusedElement.siblings('.mfn-menu-item-megamenu')) && !$(modalOpened).hasClass('mfn-header-tmpl-menu-sidebar') && isHeaderBuilderEnabled) { 154 this.utils.switchExpanded(modalOpened, false); 155 } 156 157 switch(true){ 158 case modalOpened.hasClass('mfn-cart-holder'): 159 $(`${domPrefix} #header_cart`).trigger('focus'); 160 break; 161 case modalOpened.attr('id') === 'Side_slide': 162 modalOpened.find('.close').trigger('click'); 163 $(`.responsive-menu-toggle`).trigger('focus'); 164 break; 165 } 166 } 167 168 /* CLOSE MENU DROPDOWNS WHEN OUTSIDE OF IT --- AVOID HAMBURGER MENU WITH SIMPLE STYLE OF HEADER !!! */ 169 if( $(menuOpened).length && this.utils.isSimpleHamburgerStack ) { 170 if ( !focusedElement.closest(menuOpened).length && !menuOpened.siblings().is(focusedElement) ) { 171 $(menuOpened).attr('aria-expanded','false').slideUp(); 172 } 173 } 174 175 /* DOUBLE CHECK OF SUBMENUS ARIA-EXPANDED! */ 176 $('.sub-menu[aria-expanded=true]').each( (index, item) => { 177 if ( $(item).css('display') == 'none') { 178 this.utils.switchExpanded(item, false); 179 } 180 181 //HB 2.0 - get into deeper submenus 182 if ( !$(document.activeElement).closest('ul').is($(item)) && !$(document.activeElement).siblings('ul').length && !$(document.activeElement).closest('ul[aria-expanded="true"]').length && isHeaderBuilderEnabled) { 183 this.utils.switchExpanded(item, false); 184 }; 185 }) 186 187 // --- SPACE --- 188 189 if( Space ){ 190 switch( true ){ 191 192 // Elements which imitate links 193 case focusedElement.attr('role') === 'button': 194 case focusedElement.attr('role') === 'link': 195 if( focusedElement.find('.title').length ) { //accordion 196 focusedElement.find('.title').trigger('click'); 197 } 198 break; 199 200 } 201 } 202 203 // --- ENTER --- 204 205 if( Enter ){ 206 switch( true ){ 207 208 // WooCommerce login - X close 209 210 case focusedElement.hasClass('close-login-modal'): 211 $('#Wrapper a.toggle-login-modal').trigger('focus').trigger('click'); 212 this.utils.switchExpanded( $('.mfn-header-login[aria-disabled=false]'), false); 213 break; 214 215 // HB 2.0 - dropdown aria switch 216 217 case focusedElement.hasClass('mfn-header-menu-burger') && isHeaderBuilderEnabled: 218 $(focusedElement).trigger('click'); 219 $(focusedElement).siblings('div').find('ul a').first().focus(); 220 break; 221 222 case focusedElement.hasClass('mfn-header-menu-toggle') && isHeaderBuilderEnabled: 223 const hamburgerMenuDOM = $(focusedElement).closest('.mcb-item-header_burger-inner').find('a.mfn-header-menu-burger'); 224 hamburgerMenuDOM.trigger('click').focus(); 225 break; 226 227 // Searchform - X close 228 229 case focusedElement.hasClass('mfn-close-icon'): 230 $(focusedElement).trigger('click'); 231 break; 232 233 // Side Slide - X close 234 235 case focusedElement.hasClass('close'): 236 this.utils.switchExpanded(modalOpened, false); 237 $('.responsive-menu-toggle').trigger('focus'); 238 break; 239 240 //Submenu side-slide 241 case focusedElement.hasClass('menu-toggle') && $('body').hasClass('side-slide-is-open'): 242 const submenuSide = focusedElement.siblings('.sub-menu'); 243 244 // Arias 245 if (submenuSide.attr('aria-expanded') === 'false') { 246 submenuSide.attr('aria-expanded', true); 247 } else { 248 submenuSide.attr('aria-expanded', false); 249 250 // If children has dropdowns, close them 251 submenuSide.find('.sub-menu').each((index, item) => { 252 $(item).closest('li').removeClass('hover'); 253 $(item).attr('aria-expanded', false).css('display', 'none'); 254 }) 255 } 256 257 // Prevention of opening by TAB 258 if (submenuSide.css('display') == 'block') { 259 submenuSide.find('a').first().trigger('focus'); 260 } 261 262 break; 263 264 //Submenu dropdown 265 case focusedElement.hasClass('menu-toggle') && !$('body').hasClass('side-slide-is-open'): 266 const submenu = focusedElement.siblings('.sub-menu'); 267 268 //When hamburger menu with header simple, then break the loop 269 if ( !this.utils.isSimpleHamburgerStack ){ 270 271 if ( submenu.attr('aria-expanded') == 'true' ) { 272 this.utils.switchExpanded(submenu, false); 273 } else { 274 this.utils.switchExpanded(submenu, true); 275 276 let submenuItem = submenu.find('a').first(); 277 setTimeout(_ => submenuItem.trigger('focus'), 100); 278 } 279 280 break; 281 } 282 283 if (submenu.css('display') != 'none') { 284 this.utils.switchExpanded(submenu, false); 285 submenu.slideUp(0); 286 287 //close deeper arias expanded 288 const subarias = submenu.find('*[aria-expanded=true]'); 289 if (subarias.length) { 290 this.utils.switchExpanded(subarias, false);
291 subarias.slideUp(); 292 } 293 294 } else { 295 this.utils.switchExpanded(submenu, true); 296 297 let submenuItem = submenu.slideDown(0).find('a').first(); 298 setTimeout(_ => submenuItem.trigger('focus'), 100); 299 } 300 301 break; 302 // WooCommerce Header Login 303 case focusedElement.hasClass('toggle-login-modal'): 304 $('.mfn-header-login[aria-disabled=false]').find('input, a').first().trigger('focus'); 305 $('.mfn-header-login[aria-disabled=false]').attr('aria-expanded', 'true'); 306 break; 307 308 // Elements which imitate links 309 case focusedElement.attr('role') === 'button': 310 case focusedElement.attr('role') === 'link': 311 if( focusedElement.find('.image_links').length ){ //image 312 window.location = focusedElement.find('a').attr('href'); 313 } else if( focusedElement.find('.title').length ) { //accordion 314 focusedElement.find('.title').trigger('click'); 315 } else if( focusedElement.closest('.mfn-woo-list').length ) { 316 focusedElement.trigger('click'); 317 } 318 break; 319 320 //WPML dropdown 321 case focusedElement.attr('data-title') === 'wpml': 322 const langDropdown = focusedElement.siblings('.wpml-lang-dropdown'); 323 324 if ( langDropdown.attr('aria-expanded') == 'false' ) { 325 langDropdown.attr('aria-expanded', 'true'); 326 langDropdown.find('a').first().trigger('focus'); 327 } else { 328 langDropdown.attr('aria-expanded', 'false'); 329 } 330 break; 331 332 //WooCommerce Cart Sidebar 333 case focusedElement.hasClass('single_add_to_cart_button'): 334 $('.mfn-cart-holder').find('a').first().trigger('focus'); 335 break; 336 337 //Turn on dropdown or sidecart 338 case focusedElement.hasClass('responsive-menu-toggle'): 339 //Sideslide --- socials && extras, order of array is important! 340 if ( $('body').hasClass('mobile-side-slide') ) { 341 this.menuLinks = [ 342 ...$('#Side_slide').find('a.close').toArray(), 343 ...$('.extras-wrapper').find('a').toArray(), 344 ...this.menuLinks, 345 ...$('#Side_slide .social').find('a').toArray() 346 ]; 347 348 $(this.menuLinks[0]).trigger('focus'); 349 focusedElement.trigger('click'); 350 this.utils.switchExpanded( $('#Side_slide'), true ); 351 } 352 353 break; 354 355 case focusedElement.hasClass('overlay-menu-toggle'): 356 if( $('#overlay-menu ul').attr('aria-expanded') == 'false' || $('#overlay-menu ul').attr('aria-expanded') === undefined ){ 357 this.utils.switchExpanded( $('#overlay-menu ul'), true ); 358 359 $('#overlay-menu').find('.menu-item a').first().trigger('focus'); 360 }else{ 361 this.utils.switchExpanded($('#overlay-menu ul'), false); 362 363 if( focusedElement.hasClass('close') ) { 364 $('.overlay-menu-toggle').trigger('focus'); 365 } 366 } 367 break; 368 369 } 370 371 // end: ENTER 372 373 // --- TAB + SHIFT --- 374 375 } else if(Tab && (ShiftLeft || ShiftRight) ) { 376 377 //Tabs fix, make noticable for tab, overwrite tabindex from -1 to 0 378 $('a.ui-tabs-anchor').attr('tabindex', 0); 379 380 //Skip links, are they triggered? 381 this.skipLinks(); 382 383 //Sideslide, if get out of the submenu by TAB, remove the hover effect too 384 if(!focusedElement.is('.submenu') && !isHeaderBuilderEnabled && $('body').hasClass('side-slide-is-open')){ 385 const rootElement = focusedElement.closest('li').siblings('.hover'); 386 rootElement.removeClass('hover'); 387 388 rootElement.find('.sub-menu').each((index, item) => { 389 $(item).closest('li').removeClass('hover'); 390 }) 391 } 392 393 // HB 2.0 - regular dropdown 394 if( focusedElement.is('.mfn-menu-link') && $('body').hasClass('mfn-header-template') && isHeaderBuilderEnabled){ 395 const subContainer = focusedElement.siblings('.mfn-submenu').length ? 'mfn-submenu' : 'mfn-menu-item-megamenu'; 396 const dropdownButton = focusedElement.siblings(`.${subContainer}`); 397 398 // The mega menu is manged by function to force close modals, regular dropdown (nomegamenu) bypass 399 if ( subContainer === 'mfn-submenu' && focusedElement.closest('ul').attr('aria-expanded')) { 400 this.utils.switchExpanded($(focusedElement).siblings('.mfn-submenu'), false); 401 } 402 403 if (dropdownButton.length) { 404 const elChild = $(focusedElement).siblings(`.${subContainer}`); 405 this.utils.switchExpanded(elChild, true); 406 } 407 } 408 409 // HB 2.0 - mega menu inner dropdown 410 if(focusedElement.closest('ul').hasClass('mfn-megamenu-menu') && focusedElement.closest('li').hasClass('menu-item-has-children') && isHeaderBuilderEnabled){ 411 this.utils.switchExpanded($(focusedElement).siblings('.sub-menu'), true); 412 } 413 if(focusedElement.closest('ul').hasClass('sub-menu') && focusedElement.closest('li').hasClass('menu-item-has-children') && isHeaderBuilderEnabled){ 414 this.utils.switchExpanded($(focusedElement).siblings('.sub-menu'), true); 415 } 416 417 // end: TAB + SHIFT 418 419 // --- TAB --- 420 421 }else if(Tab) { 422 423 // Tabs fix, make noticable for tab, overwrite tabindex from -1 to 0 424 $('a.ui-tabs-anchor').attr('tabindex', 0); 425 426 // Skip links, are they triggered? 427 this.skipLinks(); 428 429 switch( true ) { 430 431 case focusedElement.closest('li').hasClass('wc-block-product-categories-list-item'): // woocommerce widget -- product category dropdowns 432 if( !focusedElement.closest('.li-expanded').length ){ 433 focusedElement.siblings('.cat-expander').trigger('click'); 434 focusedElement.siblings('ul').find('a').first().trigger('focus'); 435 } 436 437 focusedElement.closest('li').siblings('.li-expanded').each((index, object) => $(object).find('.cat-expander').trigger('click') ); 438 break; 439
440 case focusedElement.is('.overlay-menu-toggle', '.focus') && $('#Overlay').css('display') === 'block': //Overlay 441 $('.overlay-menu-toggle').trigger('focus'); 442 break; 443 444 case focusedElement.is( $(this.contentLinks[this.contentLinks.length-1]) ) && !$('body').hasClass('footer-menu-sticky'): //when reached end of page 445 //if fixed nav, then first, reach that 446 if( $('.fixed-nav').length ) { 447 $('.fixed-nav').first().trigger('focus'); 448 } else { 449 $('body a').first().trigger('focus'); 450 } 451 break; 452 453 //Sideslide, if get out of the submenu by TAB, remove the hover effect too 454 case !focusedElement.is('.submenu') && !isHeaderBuilderEnabled && $('body').hasClass('side-slide-is-open'): 455 const rootElement = focusedElement.closest('li').siblings('.hover'); 456 rootElement.removeClass('hover'); 457 458 rootElement.find('.sub-menu').each((index, item) => { 459 $(item).closest('li').removeClass('hover'); 460 }) 461 break; 462 463 // Header Builder - dropdowns (including mega menu dropdowns), trigger focus 464 465 case focusedElement.is('.mfn-menu-link') && isHeaderBuilderEnabled: 466 467 const subContainer = focusedElement.siblings('.mfn-submenu').length ? 'mfn-submenu' : 'mfn-menu-item-megamenu'; 468 const dropdownButton = focusedElement.siblings(`.${subContainer}`); 469 470 // Calculate the width + position (left,right etc...) 471 const rootMenuItem = $(focusedElement).closest('.mfn-menu-item-has-megamenu').find('a.mfn-menu-link')[0]; 472 $(rootMenuItem).trigger('mouseenter').trigger('hover').trigger('mouseover'); 473 474 // The mega menu is manged by function to force close modals, regular dropdown (nomegamenu) bypass 475 if ( subContainer === 'mfn-submenu' && focusedElement.closest('ul').attr('aria-expanded') === 'true') { 476 this.utils.switchExpanded($(focusedElement).siblings('.mfn-submenu'), false); 477 } 478 479 if (dropdownButton.length) { 480 const elChild = $(focusedElement).siblings(`.${subContainer}`); 481 this.utils.switchExpanded(elChild, true); 482 } 483 484 break; 485 486 // Header Builder - mega menu, set active arias only. 487 case focusedElement.closest('ul').hasClass('mfn-megamenu-menu') && focusedElement.closest('li').hasClass('menu-item-has-children') && isHeaderBuilderEnabled: 488 this.utils.switchExpanded($(focusedElement).siblings('.sub-menu'), true); 489 break; 490 case focusedElement.closest('ul').hasClass('sub-menu') && focusedElement.closest('li').hasClass('menu-item-has-children') && isHeaderBuilderEnabled: 491 this.utils.switchExpanded($(focusedElement).siblings('.sub-menu'), true); 492 break; 493 } 494 495 // --- ESCAPE --- 496 497 } else if ( Escape ) { 498 var openedSubmenus = Array.from( $('.sub-menu[aria-expanded=true]') ); 499 var modals = $('.woocommerce').find('nav[aria-expanded=true]'); 500 501 // Mega menu, only for builder items. 502 if(focusedElement.closest('div.mfn-menu-item-megamenu') && isHeaderBuilderEnabled){ 503 let newFocusedEl = focusedElement.closest('div.mfn-menu-item-megamenu'); 504 505 this.utils.switchExpanded($(newFocusedEl), false); 506 $(newFocusedEl).siblings('a').trigger('focus'); 507 }else if(focusedElement.closest('.mfn-header-login').length){ 508 // HB 2.0 - close the woomodal 509 $('#Wrapper a.toggle-login-modal').trigger('focus') 510 $('body').removeClass('mfn-show-login-modal'); 511 this.utils.switchExpanded( $('.mfn-header-login[aria-disabled=false]'), false); 512 }else if ( $('body').hasClass('side-slide-is-open') && focusedElement.closest('#Side_slide').length) { 513 //side slide 514 modalOpened.find('.close').trigger('click'); 515 516 $('.responsive-menu-toggle').trigger('focus'); 517 }else if( openedSubmenus.length && isHeaderBuilderEnabled ) { 518 // HB 2.0 - menus, dropdown 519 if($(focusedElement).closest('.mfn-header-tmpl-menu-sidebar').length){ //sideslide 520 $(focusedElement).closest('.mfn-header-tmpl-menu-sidebar').attr('aria-expanded', false); 521 $('.mfn-header-menu-toggle').trigger('focus'); 522 } else { //dropdown 523 const mainMenuItem = $(focusedElement).closest('.mfn-header-mainmenu').find('[aria-expanded=true]').first(); 524 $(mainMenuItem).siblings('a').trigger('focus'); 525 this.utils.switchExpanded(mainMenuItem, false); 526 } 527 528 } else if( openedSubmenus.length && !isHeaderBuilderEnabled ) { 529 //menus, dropdown 530 var menuItemOpened = $('nav').find('.sub-menu[aria-expanded=true]').siblings('a.menu-toggle'); 531
532 openedSubmenus.forEach(submenu => { 533 this.utils.switchExpanded(submenu, false); 534 $(submenu).slideUp(); 535 }) 536 537 menuItemOpened.trigger('focus'); 538 539 } else if( !isHeaderBuilderEnabled && $('.mfn-header-login').find('nav[aria-expanded=true]').length ) { 540 //side login 541 $('.close-login-modal').trigger('click'); 542 this.utils.switchExpanded(modals, false); 543 544 $('.myaccount_button').trigger('focus'); 545 546 } else if( $('.mfn-cart-holder').attr('aria-expanded') == 'true' ) { 547 //side cart 548 $('.mfn-cart-holder').find('.close-mfn-cart').trigger('click'); 549 this.utils.switchExpanded($('.mfn-cart-holder'), false); 550 551 $('#header_cart').trigger('focus'); 552 return; 553 554 } else if ( $('.responsive-menu-toggle').hasClass('active') ) { 555 // responsive menu toggle 556 $('.responsive-menu-toggle').trigger('click'); 557 $('.responsive-menu-toggle').trigger('focus'); 558 559 } else if ( $(focusedElement).closest('ul').hasClass('mfn-megamenu-menu') && isHeaderBuilderEnabled ) { 560 $(focusedElement).closest('.mfn-menu-item-megamenu').attr('aria-expanded', false); 561 $(focusedElement).closest('.mfn-menu-item-megamenu').closest('li').find('a').focus(); 562 563 } else if( $(focusedElement).closest('.mfn-header-tmpl-menu-sidebar') && isHeaderBuilderEnabled ) { 564 $(focusedElement).closest('.mfn-header-tmpl-menu-sidebar').attr('aria-expanded', false); 565 $('.mfn-header-menu-toggle').trigger('focus'); 566 567 // Searchform - X close 568 } else if( $(focusedElement).parent('.form-searchform') ) { 569 $(focusedElement).trigger('click'); 570 $(focusedElement).siblings('.mfn-close-icon').trigger('click'); 571 } 572 573 } else if ( !shouldChangeDirection() ? ArrowRight : ArrowLeft ) { 574 575 if(focusedElement.closest('li').find('.menu-toggle').length) { 576 const submenu = focusedElement.siblings('.sub-menu'); 577 578 if (submenu.css('display') == 'none') { 579 this.utils.switchExpanded(submenu, true); 580 581 //open and focus next submenu 582 let submenuItem = submenu.slideDown(0).find('a').first(); 583 setTimeout(_ => submenuItem.trigger('focus'), 100); 584 } 585 } 586 587 } else if ( !shouldChangeDirection() ? ArrowLeft : ArrowRight ) { 588 589 if(focusedElement.closest('ul[aria-expanded=true]').length) { 590 const submenu = focusedElement.closest('.sub-menu'); 591 592 //close deeper arias expanded 593 const subarias = submenu.find('*[aria-expanded=true]'); 594 if (subarias.length) { 595 this.utils.switchExpanded(subarias, false); 596 subarias.slideUp(); 597 } 598 } 599 600 } 601 602 }, 603 604 init() { 605 606 if( $('body').hasClass('keyboard-support') ) { 607 608 this.clickListener(); 609 const submenu = $('.sub-menu'); 610 611 /* Instead of using WP Walkers, we can do that using JS, quicker, simpler (KISS PRINCIPLE) */ 612 submenu.attr('aria-expanded', 'false'); 613 $('.menu-toggle, .menu-item a').attr('tabindex', '0'); 614 615 /* Attach aria-label with menu item name, DRY */ 616 if (submenu.siblings('a')) { 617 if( this.utils.isHeaderBuilderEnabled ) { 618 submenu.siblings('a').each( (index, item) => { 619 $(item).attr('aria-label', `${mfn.accessibility.translation.toggleSubmenu} ${$(item).find('.menu-label').text()}`); 620 }) 621 } else { 622 submenu.siblings('a.menu-toggle').each( (index, item) => { 623 $(item).attr('aria-label', `${mfn.accessibility.translation.toggleSubmenu} ${$(item).siblings('a').text()}`); 624 }) 625 } 626 } 627 628 629 /* These containers are changing for multiple templates, change it by JS (DRY PRINCIPLE) */ 630 $('#Content').attr('role', 'main'); 631 $('#Header_wrapper').attr('role', 'banner').attr('aria-label', mfn.accessibility.translation.headerContainer); 632 633 // HB 2.0 Woo Menu 634 $('.woocommerce-MyAccount-navigation').attr('role', 'navigation').attr('aria-expanded', 'false'); 635 $('.mfn-header-login[aria-disabled="true"]').find('a, input, button').each((index, item) => $(item).attr('tabindex', '-1')); 636 637 /* Remove aria-expanded for headers which does not open on menu click (responsive-menu-button) */ 638 if ( !$('body').is('.header-creative, .header-simple, .header-overlay') ) { 639 $('#menu').removeAttr('aria-expanded'); 640 } 641 } 642 643 } 644 645 } 646 647 /** 648 * Accesibility | New tab or _blank target links | PBL 649 */ 650 651 var warningLinks = { 652 653 onLinkAlert(){ 654 $('a').click(function( e ) { 655 656 const target = $(e.currentTarget); 657 if( (target.attr('target') === '_blank' || target.attr('target') === '0' ) ) { 658 //stop action 659 var answer = confirm ("The link will open in a new tab. Do you want to continue? "); 660 if (!answer) { 661 e.preventDefault(); 662 } 663 664 } 665 666 }) 667 }, 668 669 init(){ 670 if ( $('body').hasClass('warning-links') ) { 671 this.onLinkAlert(); 672 } 673 } 674 675 } 676 677 /** 678 * $(window).on('load') 679 * window.load 680 */ 681 682 $(window).on('load', function() { 683 684 keyboard.init(); 685 686 warningLinks.init(); 687 688 }); 689 690})(jQuery);
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.