[FIX] web: repair some keynav in dropdowns

ENCOUNTERED ISSUE:
Unable to close a dropdown with ESC when the focus has been given
to a select element inside the dropdown.

TO REPRODUCE:
i.e. in the searchpanel, go to "FilterMenu > Add Custom Filter" and
open the field select element.
Press ESC once: the field select element closes just fine.
Press ESC a 2nd time: we expect the dropdown to close but nothing occur.

REASON EXPLANATION:
Since 84715436d our Dropdown component uses the 'dropdown-menu'
bootstrap class.
But under some conditions bootstrap stops the keydown events propagation
when the event.target matches the query selector '.dropdown-menu'.

IMPLEMENTED FIX:
This commit refines this selector directly inside the bootstrap library.
This is admittedly a bad practice but:
- this modification is trivial and sensible
- the modified selector is only used locally
  in the bootstrap's 'dropdown.js' file
- the added test should prevent the lost of
  this customization in the future

task-2764821

Part-of: odoo/odoo#84969
This commit is contained in:
Bruno Boi
2022-02-21 20:11:54 +00:00
parent 22211ec6c2
commit 78f85f2725
2 changed files with 32 additions and 1 deletions
@@ -111,7 +111,7 @@
var Selector = {
DATA_TOGGLE: '[data-toggle="dropdown"]',
FORM_CHILD: '.dropdown form',
MENU: '.dropdown-menu',
MENU: '.dropdown-menu:not(.o-dropdown--menu)', // Odoo fix task-2764821
NAVBAR_NAV: '.navbar-nav',
VISIBLE_ITEMS: '.dropdown-menu .dropdown-item:not(.disabled):not(:disabled)'
};
@@ -665,6 +665,37 @@ QUnit.module("Components", ({ beforeEach }) => {
assert.verifySteps(["1", "2"], "items should have been selected in this order");
});
QUnit.test("dropdowns keynav is not impacted by bootstrap", async (assert) => {
class Parent extends Component {}
Parent.components = { Dropdown };
Parent.template = xml`
<Dropdown startOpen="true">
<select><option>foo</option></select>
</Dropdown>
`;
env = await makeTestEnv();
await mount(Parent, target, { env });
assert.containsOnce(target, ".dropdown-menu", "menu is opened at start");
const menu = target.querySelector(".dropdown-menu");
// This class presence makes bootstrap ignore the below event
assert.hasClass(menu, "o-dropdown--menu");
const select = menu.querySelector("select");
const ev = new KeyboardEvent("keydown", {
bubbles: true,
// Define the ESC key with standard API (for hotkey_service)
key: "Escape",
code: "Escape",
// Define the ESC key with deprecated API (for bootstrap)
keyCode: 27,
which: 27,
});
select.dispatchEvent(ev);
await nextTick();
assert.containsNone(target, ".dropdown-menu", "menu is now closed");
});
QUnit.test("props toggler='parent'", async (assert) => {
class Parent extends Component {}
Parent.template = xml`