diff --git a/addons/mass_mailing/static/src/js/mass_mailing_widget.js b/addons/mass_mailing/static/src/js/mass_mailing_widget.js index 053d1611619..5a03e1719f7 100644 --- a/addons/mass_mailing/static/src/js/mass_mailing_widget.js +++ b/addons/mass_mailing/static/src/js/mass_mailing_widget.js @@ -331,6 +331,9 @@ var MassMailingFieldHtml = FieldHtml.extend({ * @override */ _onLoadWysiwyg: function () { + // Let the global hotkey manager know about our iframe. + this.call('hotkey', 'registerIframe', this.wysiwyg.$iframe[0]); + if (this.snippetsLoaded) { this._onSnippetsLoaded(this.snippetsLoaded); } diff --git a/addons/web/static/src/core/hotkeys/hotkey_service.js b/addons/web/static/src/core/hotkeys/hotkey_service.js index 77b13e41f63..3ecf33357f1 100644 --- a/addons/web/static/src/core/hotkeys/hotkey_service.js +++ b/addons/web/static/src/core/hotkeys/hotkey_service.js @@ -33,10 +33,14 @@ export const hotkeyService = { let nextToken = 0; let overlaysVisible = false; - browser.addEventListener("keydown", onKeydown); - browser.addEventListener("keyup", removeHotkeyOverlays); - browser.addEventListener("blur", removeHotkeyOverlays); - browser.addEventListener("click", removeHotkeyOverlays); + addListeners(browser); + + function addListeners(target) { + target.addEventListener("keydown", onKeydown); + target.addEventListener("keyup", removeHotkeyOverlays); + target.addEventListener("blur", removeHotkeyOverlays); + target.addEventListener("click", removeHotkeyOverlays); + } /** * Handler for keydown events. @@ -376,6 +380,12 @@ export const hotkeyService = { unregisterHotkey(token); }; }, + /** + * @param {HTMLIFrameElement} iframe + */ + registerIframe(iframe) { + addListeners(iframe.contentWindow); + }, }; }, }; 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 20a73185089..78c425e9d31 100644 --- a/addons/web/static/tests/core/hotkeys/hotkey_service_tests.js +++ b/addons/web/static/tests/core/hotkeys/hotkey_service_tests.js @@ -9,6 +9,7 @@ import { makeTestEnv } from "../../helpers/mock_env"; import { destroy, getFixture, + makeDeferred, mount, nextTick, patchWithCleanup, @@ -842,3 +843,34 @@ QUnit.test("ignore numpad keys", async (assert) => { await nextTick(); assert.verifySteps(["1"]); }); + +QUnit.test("within iframes", async (assert) => { + assert.expect(5); + env.services.hotkey.add("enter", () => assert.step("called")); + await nextTick(); + + // Dispatch directly to target to show that the hotkey service works as expected + target.dispatchEvent(new KeyboardEvent("keydown", { key: "Enter", bubbles: true })); + await nextTick(); + assert.verifySteps(["called"]); + + // Append an iframe to target and wait until it is fully loaded. + const iframe = document.createElement("iframe"); + iframe.srcdoc = "

Hello world!

"; + const def = makeDeferred(); + iframe.onload = def.resolve; + target.appendChild(iframe); + await def; + + // Dispatch an hotkey from within the iframe + const h1 = iframe.contentDocument.querySelector("h1"); + h1.dispatchEvent(new KeyboardEvent("keydown", { key: "Enter", bubbles: true })); + await nextTick(); + assert.verifySteps([]); + + // Register the iframe to the hotkey service + env.services.hotkey.registerIframe(iframe); + h1.dispatchEvent(new KeyboardEvent("keydown", { key: "Enter", bubbles: true })); + await nextTick(); + assert.verifySteps(["called"]); +});