Merge pull request #13301 from edx/jareer/ECOM-4945
Fixed Shift-Tab on menu and ARIA roles, groups
This commit is contained in:
@@ -1,81 +1,87 @@
|
||||
$(document).ready(function() {
|
||||
(function(require) {
|
||||
'use strict';
|
||||
|
||||
// define variables for code legibility
|
||||
var dropdownMenuToggle = $('.dropdown');
|
||||
var dropdownMenu = $('.dropdown-menu');
|
||||
var menuItems = dropdownMenu.find('a');
|
||||
require([
|
||||
'jquery',
|
||||
'edx-ui-toolkit/js/utils/constants'
|
||||
], function($, constants) {
|
||||
// define variables for code legibility
|
||||
var $dropdownMenuToggle = $('.dropdown');
|
||||
var $dropdownMenu = $('.dropdown-menu');
|
||||
var menuItems = $dropdownMenu.find('.dropdown-menuitem');
|
||||
|
||||
// bind menu toggle click for later use
|
||||
dropdownMenuToggle.toggle(function() {
|
||||
dropdownMenu.addClass('expanded').find('a').first().focus();
|
||||
dropdownMenuToggle.addClass('active').attr('aria-expanded', 'true');
|
||||
}, function() {
|
||||
dropdownMenu.removeClass('expanded');
|
||||
dropdownMenuToggle.removeClass('active').attr('aria-expanded', 'false').focus();
|
||||
});
|
||||
// bind menu toggle click for later use
|
||||
$dropdownMenuToggle.toggle(function() {
|
||||
$dropdownMenu.addClass('expanded').find('.dropdown-menuitem').first()
|
||||
.focus();
|
||||
$dropdownMenuToggle.addClass('active').attr('aria-expanded', 'true');
|
||||
}, function() {
|
||||
$dropdownMenu.removeClass('expanded');
|
||||
$dropdownMenuToggle.removeClass('active').attr('aria-expanded', 'false').focus();
|
||||
});
|
||||
|
||||
// catch keypresses when focused on dropdownMenuToggle (we only care about spacebar keypresses here)
|
||||
dropdownMenuToggle.on('keydown', function(event) {
|
||||
// if space key pressed
|
||||
if (event.which == 32) {
|
||||
dropdownMenuToggle.click();
|
||||
event.preventDefault();
|
||||
}
|
||||
});
|
||||
|
||||
// catch keypresses when inside dropdownMenu (we want to catch spacebar; escape; up arrow or shift+tab; and down arrow or tab)
|
||||
dropdownMenu.on('keydown', function(event) {
|
||||
catchKeyPress($(this), event);
|
||||
});
|
||||
|
||||
function catchKeyPress(object, event) {
|
||||
// get currently focused item
|
||||
var focusedItem = jQuery(':focus');
|
||||
|
||||
// get the number of focusable items
|
||||
var numberOfMenuItems = menuItems.length;
|
||||
|
||||
// get the index of the currently focused item
|
||||
var focusedItemIndex = menuItems.index(focusedItem);
|
||||
|
||||
// var to store next focused item index
|
||||
var itemToFocusIndex;
|
||||
|
||||
// if space key pressed
|
||||
if (event.which == 32) {
|
||||
dropdownMenuToggle.click();
|
||||
event.preventDefault();
|
||||
}
|
||||
|
||||
// if escape key pressed
|
||||
if (event.which == 27) {
|
||||
dropdownMenuToggle.click();
|
||||
event.preventDefault();
|
||||
}
|
||||
|
||||
// if up arrow key pressed or shift+tab
|
||||
if (event.which == 38 || (event.which == 9 && event.shiftKey)) {
|
||||
// if first item go to last
|
||||
if (focusedItemIndex === 0) {
|
||||
menuItems.last().focus();
|
||||
} else {
|
||||
itemToFocusIndex = focusedItemIndex - 1;
|
||||
menuItems.get(itemToFocusIndex).focus();
|
||||
// catch keypresses when focused on dropdownMenuToggle (we only care about spacebar keypresses here)
|
||||
$dropdownMenuToggle.on('keydown', function(event) {
|
||||
// if space key pressed
|
||||
if (event.which === constants.keyCodes.space) {
|
||||
$dropdownMenuToggle.click();
|
||||
event.preventDefault();
|
||||
}
|
||||
});
|
||||
|
||||
function catchKeyPress(object, event) {
|
||||
// get currently focused item
|
||||
var focusedItem = jQuery(':focus');
|
||||
|
||||
// get the number of focusable items
|
||||
var numberOfMenuItems = menuItems.length;
|
||||
|
||||
// get the index of the currently focused item
|
||||
var focusedItemIndex = menuItems.index(focusedItem);
|
||||
|
||||
// var to store next focused item index
|
||||
var itemToFocusIndex;
|
||||
|
||||
// if space key pressed
|
||||
if (event.which === constants.keyCodes.space) {
|
||||
$dropdownMenuToggle.click();
|
||||
event.preventDefault();
|
||||
}
|
||||
|
||||
// if escape key pressed
|
||||
if (event.which === constants.keyCodes.esc) {
|
||||
$dropdownMenuToggle.click();
|
||||
event.preventDefault();
|
||||
}
|
||||
|
||||
// if up arrow key pressed or shift+tab else down key or tab is pressed
|
||||
if (event.which === constants.keyCodes.up || event.which === constants.keyCodes.left ||
|
||||
(event.which === constants.keyCodes.tab && event.shiftKey)) {
|
||||
// if first item go to last
|
||||
if (focusedItemIndex === 0) {
|
||||
menuItems.last().focus();
|
||||
} else {
|
||||
itemToFocusIndex = focusedItemIndex - 1;
|
||||
menuItems.get(itemToFocusIndex).focus();
|
||||
}
|
||||
event.preventDefault();
|
||||
} else if (event.which === constants.keyCodes.down || event.which === constants.keyCodes.right ||
|
||||
event.which === constants.keyCodes.tab) {
|
||||
// if last item go to first
|
||||
if (focusedItemIndex === numberOfMenuItems - 1) {
|
||||
menuItems.first().focus();
|
||||
} else {
|
||||
itemToFocusIndex = focusedItemIndex + 1;
|
||||
menuItems.get(itemToFocusIndex).focus();
|
||||
}
|
||||
event.preventDefault();
|
||||
}
|
||||
event.preventDefault();
|
||||
}
|
||||
|
||||
// if down arrow key pressed or tab key
|
||||
if (event.which == 40 || event.which == 9) {
|
||||
// if last item go to first
|
||||
if (focusedItemIndex == numberOfMenuItems - 1) {
|
||||
menuItems.first().focus();
|
||||
} else {
|
||||
itemToFocusIndex = focusedItemIndex + 1;
|
||||
menuItems.get(itemToFocusIndex).focus();
|
||||
}
|
||||
event.preventDefault();
|
||||
}
|
||||
}
|
||||
});
|
||||
// catch keypresses when inside dropdownMenu
|
||||
// (we want to catch spacebar; escape; up arrow or shift+tab; and down arrow or tab)
|
||||
$dropdownMenu.on('keydown', function(event) {
|
||||
catchKeyPress($(this), event);
|
||||
});
|
||||
});
|
||||
}).call(this, require || RequireJS.require);
|
||||
|
||||
@@ -20,18 +20,20 @@ from openedx.core.djangoapps.user_api.accounts.image_helpers import get_profile_
|
||||
<img class="menu-image" src="${profile_image_url}" alt="">
|
||||
${username}
|
||||
</a>
|
||||
<button type="button" class="menu-button button-more has-dropdown js-dropdown-button" aria-haspopup="true" aria-expanded="false" aria-controls="${_("Usermenu")}">
|
||||
<span class="icon fa fa-caret-down" aria-hidden="true"></span>
|
||||
<span class="sr-only">${_("Usermenu dropdown")}</span>
|
||||
</button>
|
||||
<ul class="dropdown-menu list-divided is-hidden" id="${_("Usermenu")}" tabindex="-1">
|
||||
<%block name="navigation_dropdown_menu_links" >
|
||||
<li class="dropdown-item item has-block-link"><a href="${reverse('dashboard')}" class="action">${_("Dashboard")}</a></li>
|
||||
<li class="dropdown-item item has-block-link"><a href="${reverse('learner_profile', kwargs={'username': user.username})}" class="action">${_("Profile")}</a></li>
|
||||
<li class="dropdown-item item has-block-link"><a href="${reverse('account_settings')}" class="action">${_("Account")}</a></li>
|
||||
</%block>
|
||||
<li class="dropdown-item item has-block-link"><a href="${reverse('logout')}" role="menuitem" class="action">${_("Sign Out")}</a></li>
|
||||
</ul>
|
||||
<div role="group" aria-label="User menu">
|
||||
<button type="button" class="menu-button button-more has-dropdown js-dropdown-button" aria-expanded="false" aria-controls="${_("Usermenu")}">
|
||||
<span class="icon fa fa-caret-down" aria-hidden="true"></span>
|
||||
<span class="sr-only">${_("Usermenu dropdown")}</span>
|
||||
</button>
|
||||
<ul class="dropdown-menu list-divided is-hidden" id="${_("Usermenu")}" tabindex="-1">
|
||||
<%block name="navigation_dropdown_menu_links" >
|
||||
<li class="dropdown-item item has-block-link"><a href="${reverse('dashboard')}" class="action dropdown-menuitem">${_("Dashboard")}</a></li>
|
||||
<li class="dropdown-item item has-block-link"><a href="${reverse('learner_profile', kwargs={'username': user.username})}" class="action dropdown-menuitem">${_("Profile")}</a></li>
|
||||
<li class="dropdown-item item has-block-link"><a href="${reverse('account_settings')}" class="action dropdown-menuitem">${_("Account")}</a></li>
|
||||
</%block>
|
||||
<li class="dropdown-item item has-block-link"><a href="${reverse('logout')}" role="menuitem" class="action dropdown-menuitem">${_("Sign Out")}</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
% else:
|
||||
<ol class="user">
|
||||
@@ -47,11 +49,13 @@ from openedx.core.djangoapps.user_api.accounts.image_helpers import get_profile_
|
||||
</a>
|
||||
</li>
|
||||
<li class="primary">
|
||||
<button class="dropdown" aria-haspopup="true" aria-expanded="false"><span class="sr">${_("More options dropdown")}</span><span class="fa fa-sort-desc" aria-hidden="true"></span></button>
|
||||
<ul class="dropdown-menu" aria-label="More Options" role="menu">
|
||||
${navigation_dropdown_menu_links()}
|
||||
<li class="item"><a href="${reverse('logout')}" role="menuitem">${_("Sign Out")}</a></li>
|
||||
</ul>
|
||||
<div role="group" aria-label="User menu">
|
||||
<button class="dropdown" aria-expanded="false"><span class="sr">${_("More options dropdown")}</span><span class="fa fa-sort-desc" aria-hidden="true"></span></button>
|
||||
<ul class="dropdown-menu" aria-label="More Options" role="menu">
|
||||
${navigation_dropdown_menu_links()}
|
||||
<li class="item"><a href="${reverse('logout')}" role="menuitem" class="dropdown-menuitem">${_("Sign Out")}</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</li>
|
||||
</ol>
|
||||
% endif
|
||||
|
||||
Reference in New Issue
Block a user