[FIX] web: Make company switcher widget usable with the keyboard

Background
==========

After the refactor on the multi-company behavior performed for v13, now
there are two possible actions per company, depending on where they're
clicked: switch to the company or toggle it. Such actions were handled
by `<div>` elements, which aren't keyboard-reachable by default.

The Issue
=========

Because of the above, the company switcher was neither reachable nor
usable when using the keyboard.

Solution
========

To solve this, the following is performed:
- Add HTML attributes required to make elements reachable, along with
  their corresponding aria attributes
- Actions that are currently triggered when clicking on an element, now
  are also triggered when the keyboard focus is on the element and `ENTER`
  or `SPACE` are hit

Closes #47650

closes odoo/odoo#48627

X-original-commit: 33a7238d0b03ccb89e4c4d2f0d7380b5649dc4d4
Signed-off-by: Nicolas Lempereur (nle) <nle@odoo.com>
Signed-off-by: Luis González [Vauxoo] <luisg123v@users.noreply.github.com>
This commit is contained in:
Luis González
2020-03-30 16:31:37 +00:00
parent e4be7ad7a6
commit 8ccdbea9a7
2 changed files with 24 additions and 9 deletions
@@ -19,7 +19,9 @@ var SwitchCompanyMenu = Widget.extend({
template: 'SwitchCompanyMenu',
events: {
'click .dropdown-item[data-menu] div.log_into': '_onSwitchCompanyClick',
'keydown .dropdown-item[data-menu] div.log_into': '_onSwitchCompanyClick',
'click .dropdown-item[data-menu] div.toggle_company': '_onToggleCompanyClick',
'keydown .dropdown-item[data-menu] div.toggle_company': '_onToggleCompanyClick',
},
// force this item to be the first one to the left of the UserMenu in the systray
sequence: 1,
@@ -54,9 +56,13 @@ var SwitchCompanyMenu = Widget.extend({
/**
* @private
* @param {MouseEvent} ev
* @param {MouseEvent|KeyEvent} ev
*/
_onSwitchCompanyClick: function (ev) {
if (ev.type == 'keydown' && ev.which != $.ui.keyCode.ENTER && ev.which != $.ui.keyCode.SPACE) {
return;
}
ev.preventDefault();
ev.stopPropagation();
var dropdownItem = $(ev.currentTarget).parent();
var dropdownMenu = dropdownItem.parent();
@@ -76,6 +82,7 @@ var SwitchCompanyMenu = Widget.extend({
dropdownItem.find('.fa-square-o').removeClass('fa-square-o').addClass('fa-check-square');
}
}
$(ev.currentTarget).attr('aria-pressed', 'true');
session.setCompanies(companyID, allowed_company_ids);
},
@@ -85,9 +92,13 @@ var SwitchCompanyMenu = Widget.extend({
/**
* @private
* @param {MouseEvent} ev
* @param {MouseEvent|KeyEvent} ev
*/
_onToggleCompanyClick: function (ev) {
if (ev.type == 'keydown' && ev.which != $.ui.keyCode.ENTER && ev.which != $.ui.keyCode.SPACE) {
return;
}
ev.preventDefault();
ev.stopPropagation();
var dropdownItem = $(ev.currentTarget).parent();
var companyID = dropdownItem.data('company-id');
@@ -96,9 +107,11 @@ var SwitchCompanyMenu = Widget.extend({
if (dropdownItem.find('.fa-square-o').length) {
allowed_company_ids.push(companyID);
dropdownItem.find('.fa-square-o').removeClass('fa-square-o').addClass('fa-check-square');
$(ev.currentTarget).attr('aria-checked', 'true');
} else {
allowed_company_ids.splice(allowed_company_ids.indexOf(companyID), 1);
dropdownItem.find('.fa-check-square').addClass('fa-square-o').removeClass('fa-check-square');
$(ev.currentTarget).attr('aria-checked', 'false');
}
session.setCompanies(current_company_id, allowed_company_ids);
},
+9 -7
View File
@@ -1755,24 +1755,26 @@
</a>
<div class="dropdown-menu dropdown-menu-right" role="menu">
<t t-foreach="widget.user_companies" t-as="company">
<div role="menuitem" class="dropdown-item d-flex py-0 px-0" data-menu="company" t-att-data-company-id="company[0]">
<div class="ml-auto pl-3 pr-3 border border-top-0 border-left-0 border-bottom-0 toggle_company o_py">
<div class="dropdown-item d-flex py-0 px-0" data-menu="company" t-att-data-company-id="company[0]">
<t t-set="is_allowed" t-value="widget.allowed_company_ids.includes(company[0])"/>
<t t-set="is_current" t-value="company[0] === widget.current_company"/>
<div role="menuitemcheckbox" t-att-aria-checked="is_allowed" t-att-aria-label="company[1]" tabindex="0" class="ml-auto pl-3 pr-3 border border-top-0 border-left-0 border-bottom-0 toggle_company o_py">
<span style="height: 2rem;">
<t t-if="widget.allowed_company_ids.includes(company[0])">
<t t-if="is_allowed">
<i class="fa fa-fw fa-check-square pt-2"></i>
</t>
<t t-if="!widget.allowed_company_ids.includes(company[0])">
<t t-if="!is_allowed">
<i class="fa fa-fw fa-square-o pt-2"></i>
</t>
</span>
</div>
<div class="d-flex flex-grow-1 align-items-center py-0 log_into pl-3 o_py" t-att-style="company[0] === widget.current_company ? 'background-color: lightgrey;' : ''">
<t t-if="widget.allowed_company_ids.includes(company[0])">
<div role="button" t-att-aria-pressed="is_current" aria-label="Switch to this company" tabindex="0" class="d-flex flex-grow-1 align-items-center py-0 log_into pl-3 o_py" t-att-style="is_current ? 'background-color: lightgrey;' : ''">
<t t-if="is_allowed">
<span class='mr-3 company_label'>
<t t-esc="company[1]"/>
</span>
</t>
<t t-if="!widget.allowed_company_ids.includes(company[0])">
<t t-if="!is_allowed">
<span class='mr-3 company_label text-muted'>
<t t-esc="company[1]"/>
</span>