Skip to content

Instantly share code, notes, and snippets.

@yankiara
Last active February 16, 2022 01:54
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save yankiara/e1a27e78061101df0fdb35e11172c2ec to your computer and use it in GitHub Desktop.
Save yankiara/e1a27e78061101df0fdb35e11172c2ec to your computer and use it in GitHub Desktop.
Oxygen ProMenu mobile accessibility
jQuery(document).ready(function($) {
// Initialize roles and aria attributes
$('.oxy-pro-menu-list .menu-item-has-children > a').attr('aria-haspopup','true').attr('aria-expanded','false');
$('.oxy-pro-menu-list .sub-menu').each(function(){
$(this).attr('aria-label', $(this).prev('a').text());
});
if ( $('.oxy-pro-menu-mobile-open-icon').css('display') == 'none' ) {
// Desktop dropdowns
// - Set aria-expanded
// - Open with ENTER or SPACE and close previsouly opened dropdown
// - Close with ENTER or SPACE or ESCAPE
// - Close with ESCAPE on child link or with TAB from last child link
// - Use of LEFT/RIGHT/UP/DOWN to navigate
$('.oxy-pro-menu-list .menu-item-has-children > a').on('keydown', function(e) {
if ( e.which == 13 || e.which == 32 ) {
e.preventDefault();
if ( $(this).attr('aria-expanded') == 'false' ) {
$('.oxy-pro-menu-list > .menu-item-has-children > a').mouseleave().attr('aria-expanded','false');
$(this).mouseenter().attr('aria-expanded','true');
} else {
$(this).mouseleave().attr('aria-expanded','false');
}
}
if ( e.which == 27 ) {
if ( $(this).attr('aria-expanded') == 'true' ) {
$(this).mouseleave().attr('aria-expanded','false');
}
}
});
$('.oxy-pro-menu-list > li > a').on('keydown', function(e) {
if ( e.which == 37 || e.which == 39 ) { // LEFT or RIGHT
var $next;
if ( e.which == 39 )
$next = $(this).parent().next('li');
else
$next = $(this).parent().prev('li');
if ( $next.length == 0 ) {
if ( e.which == 39 )
$next = $(this).parent().siblings().first();
else
$next = $(this).parent().siblings().last();
}
$next = $next.find('a').first();
$next.focus();
if ( $(this).attr('aria-expanded') == 'true' ) {
$(this).mouseleave().attr('aria-expanded','false');
if ( $next.attr('aria-haspopup') == 'true' )
$next.mouseenter().attr('aria-expanded','true');
}
}
if ( e.which == 40 ) { // DOWN
e.preventDefault();
var expanded = $(this).attr('aria-expanded');
if ( expanded && expanded == 'true' ) {
var $next = $(this).next('ul').find('li').first().find('a').first();
$next.focus();
} else if ( expanded && expanded == 'false' ) {
$(this).mouseenter().attr('aria-expanded','true');
}
}
if ( e.which == 38 ) { // UP
e.preventDefault();
}
});
$('.oxy-pro-menu-list > .menu-item-has-children > ul > li:last-child > a').on('keydown', function(e) {
if ( e.which == 9 ) {
$(this).closest(".menu-item-has-children").find("a").first().mouseleave().attr('aria-expanded','false');
}
});
$('.oxy-pro-menu-list .sub-menu > li > a').on('keydown', function(e) {
if ( e.which == 37 || e.which == 39 ) { // LEFT or RIGHT
var $next;
var $parent = $(this).closest('.menu-item-has-children');
if ( e.which == 39 )
$next = $parent.next('li');
else
$next = $parent.prev('li');
if ( $next.length == 0 ) {
if ( e.which == 39 )
$next = $parent.siblings().first();
else
$next = $parfent.siblings().last();
}
$next = $next.find('a').first();
$next.focus();
$parent.find('a').first().mouseleave().attr('aria-expanded','false');
if ( $next.attr('aria-haspopup') == 'true' )
$next.mouseenter().attr('aria-expanded','true');
}
if ( e.which == 38 || e.which == 40 ) { // UP and DOWN
e.preventDefault();
var $next;
if ( e.which == 38 )
$next = $(this).parent().prev('li');
else
$next = $(this).parent().next('li');
if ( $next.length == 0 ) {
if ( e.which == 38 )
$next = $(this).parent().siblings().last();
else
$next = $(this).parent().siblings().first();
}
$next.find("a").focus();
}
if ( e.which == 27 ) {
$(this).closest(".menu-item-has-children").find("a").first().mouseleave().attr('aria-expanded','false').focus();
}
});
} else {
// Mobile
// Close icon: Set focus on first menu item with <TAB>
// First menu item: Set focus on close icon with <SHIFT>+<TAB>
// Dropdowns: Set aria-expanded and close previously opened dropdown when opening new one
$('.oxy-pro-menu-mobile-close-icon').on('keydown',function(e) { // TAB
if ( e.which == 9 && !e.shiftKey ) {
e.preventDefault();
$('.oxy-pro-menu-list > li:first-child > a').focus();
}
});
$('.oxy-pro-menu-list > li:first-child > a').on('keydown',function(e) {
if( e.shiftKey && e.which == 9 ) { // SHIFT TAB
e.preventDefault();
$('.oxy-pro-menu-mobile-close-icon').focus();
}
});
$('.oxy-pro-menu-list > .menu-item-has-children > a').on('click', function(e) {
if ( $(this).attr('aria-expanded') == 'false' ) {
oxygen_pro_menu_toggle_dropdown( $('.oxy-pro-menu-list > .menu-item-has-children > a[aria-expanded="true"]') );
$('.oxy-pro-menu-list > .menu-item-has-children > a[aria-expanded="true"]').attr('aria-expanded','false');
$(this).attr('aria-expanded','true');
} else {
$(this).attr('aria-expanded','false');
}
});
}
});
<?php
/**
* Replace 'div' menu tag by 'nav'
* Adds aria-labels
* Activate SPACE and ENTER on open/close icons
**/
add_filter( 'do_shortcode_tag', function( $output, $tag, $attr ) {
if( 'oxy-pro-menu' != $tag ) return $output;
$output = preg_replace( '#^(\s*)<div(.*)</div>(?=.*<script)(.+)$#s', '$1<nav aria-label="Main"$2</nav>$3', $output );
$output = preg_replace( '#(class="[^"]*oxy-pro-menu-mobile-open-icon)#', 'aria-label="Open menu" role="button" tabindex="0" onkeydown="if(13===event.which||32===event.which){this.click();return false;}" $1', $output );
$output = preg_replace( '#(class="[^"]*oxy-pro-menu-mobile-close-icon)#', 'aria-label="Close menu" role="button" tabindex="0" onkeydown="if(13===event.which||32===event.which){this.click();return false;}" $1', $output );
return $output;
}, 10, 3 );
@mo-mono
Copy link

mo-mono commented Jan 8, 2022

Thank you so much for this snippet, helped me out a lot!

@yankiara
Copy link
Author

yankiara commented Jan 8, 2022

Updated!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment