From 38e7589042438bf1cb2b7891b76e17a8e204afdf Mon Sep 17 00:00:00 2001 From: Samuel Degueldre Date: Mon, 22 Aug 2022 06:49:15 +0000 Subject: [PATCH] [FIX] web: prevent crash when mixing hotkeys with and without area Previously, when registering a hotkey without an area then a hotkey with area, there would be a crash, as that latest hotkey is the candidate winner, and we then check that there is no other matching hotkey with an area that's more specific. In doing this, we assume all other candidates have an area and call it as a function, but since some hotkey registrations don't have one, we get a crash. This commit fixes that by filtering the candidates to only those which have an area before trying to narrow down to the most specific one. Part-of: odoo/odoo#98535 --- .../static/src/core/hotkeys/hotkey_service.js | 2 +- .../core/hotkeys/hotkey_service_tests.js | 19 ++++++++++++++++++- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/addons/web/static/src/core/hotkeys/hotkey_service.js b/addons/web/static/src/core/hotkeys/hotkey_service.js index c6301aead52..2de7568fdec 100644 --- a/addons/web/static/src/core/hotkeys/hotkey_service.js +++ b/addons/web/static/src/core/hotkeys/hotkey_service.js @@ -233,7 +233,7 @@ export const hotkeyService = { let winner = candidates.shift(); if (winner && winner.area) { // If there is an area, find the closest one - for (const candidate of candidates) { + for (const candidate of candidates.filter((c) => Boolean(c.area))) { if (candidate.area() && winner.area().contains(candidate.area())) { winner = candidate; } diff --git a/addons/web/static/tests/core/hotkeys/hotkey_service_tests.js b/addons/web/static/tests/core/hotkeys/hotkey_service_tests.js index 907320a678b..c48768ea9f5 100644 --- a/addons/web/static/tests/core/hotkeys/hotkey_service_tests.js +++ b/addons/web/static/tests/core/hotkeys/hotkey_service_tests.js @@ -40,7 +40,7 @@ QUnit.test("register / unregister", async (assert) => { triggerHotkey(key); await nextTick(); - let removeHotkey = hotkey.add(key, () => assert.step(key)); + const removeHotkey = hotkey.add(key, () => assert.step(key)); await nextTick(); triggerHotkey(key); @@ -1095,3 +1095,20 @@ QUnit.test("operation area with validating option", async (assert) => { await nextTick(); assert.verifySteps(["RGNTDJÛ!"]); }); + +QUnit.test("mixing hotkeys with and without operation area", async (assert) => { + class A extends Component { + setup() { + const areaRef = useRef("area"); + useHotkey("space", () => assert.step("withoutArea")); + useHotkey("space", () => assert.step("withArea"), { area: () => areaRef.el }); + } + } + A.template = xml`
`; + await mount(A, target, { env }); + + target.querySelector(".root").focus(); + triggerHotkey("Space"); + await nextTick(); + assert.verifySteps(["withArea"]); +});