diff --git a/addons/web/static/src/core/hotkeys/hotkey_service.js b/addons/web/static/src/core/hotkeys/hotkey_service.js index 185efa47315..77b13e41f63 100644 --- a/addons/web/static/src/core/hotkeys/hotkey_service.js +++ b/addons/web/static/src/core/hotkeys/hotkey_service.js @@ -70,14 +70,15 @@ export const hotkeyService = { return; } - // FIXME : this is a temporary hack. It replaces all [accesskey] attrs by [data-hotkey] on all elements. - const elementsWithoutDataHotkey = getVisibleElements( - activeElement, - "[accesskey]:not([data-hotkey])" - ); - for (const el of elementsWithoutDataHotkey) { - el.dataset.hotkey = el.accessKey; - el.removeAttribute("accesskey"); + // Replace all [accesskey] attrs by [data-hotkey] on all elements. + // This is needed to take over on the default accesskey behavior + // and also to avoid any conflict with it. + const elementsWithAccessKey = document.querySelectorAll("[accesskey]"); + for (const el of elementsWithAccessKey) { + if (el instanceof HTMLElement) { + el.dataset.hotkey = el.accessKey; + el.removeAttribute("accesskey"); + } } // Special case: open hotkey overlays 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 7562df48d8a..20a73185089 100644 --- a/addons/web/static/tests/core/hotkeys/hotkey_service_tests.js +++ b/addons/web/static/tests/core/hotkeys/hotkey_service_tests.js @@ -15,7 +15,7 @@ import { triggerHotkey, } from "../../helpers/utils"; -const { Component, xml } = owl; +const { Component, useState, xml } = owl; const serviceRegistry = registry.category("services"); let env; @@ -52,6 +52,104 @@ QUnit.test("register / unregister", async (assert) => { assert.verifySteps([key]); }); +QUnit.test("[accesskey] attrs replaced by [data-hotkey]", async (assert) => { + const div = document.createElement("div"); + div.className = "foo"; + div.accessKey = "a"; + div.onclick = () => assert.step("click"); + div.textContent = "foo"; + target.appendChild(div); + + // div must only have [accesskey] attribute + assert.containsOnce(target, ".foo"); + assert.containsOnce(target, ".foo[accesskey]"); + assert.containsNone(target, ".foo[data-hotkey]"); + + // press any hotkey, i.e. the left arrow + triggerHotkey("arrowleft"); + await nextTick(); + + // div should now only have [data-hotkey] attribute + assert.containsOnce(target, ".foo"); + assert.containsOnce(target, ".foo[data-hotkey]"); + assert.containsNone(target, ".foo[accesskey]"); + + // try to press the related hotkey, just to make sure it works + assert.verifySteps([]); + triggerHotkey("a", true); + await nextTick(); + assert.verifySteps(["click"]); +}); + +QUnit.test("[accesskey] attrs replaced by [data-hotkey], part 2", async (assert) => { + class UIOwnershipTakerComponent extends Component { + setup() { + useActiveElement("bouh"); + } + } + UIOwnershipTakerComponent.template = xml`
bouh
`; + class MyComponent extends Component { + setup() { + this.state = useState({ foo: true }); + this.step = assert.step.bind(assert); + } + } + MyComponent.components = { UIOwnershipTakerComponent }; + MyComponent.template = xml` +