[FIX] web,mass_mailing: bind the wysiwyg iframe document to hotkey service

Before this commit
When the user hit ctrl+k on a mass mailing, no command palette nor link
dialog was opening.
This was due to the fact that the hotkey service would not react
to hotkeys being pressed from inside of an iframe element.

After this commit
One can now register an iframe to the hotkey service to let it react
to hotkeys being pressed from within the registered iframes.

task-2738457

closes odoo/odoo#91102

Forward-port-of: #89940
Forward-port-of: #82994
Signed-off-by: David Monjoie (dmo) <dmo@odoo.com>
This commit is contained in:
Nicolas Bayet
2022-06-29 17:11:27 +02:00
parent 023153896d
commit 59ef804bba
3 changed files with 49 additions and 4 deletions
@@ -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);
}
@@ -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);
},
};
},
};
@@ -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 = "<h1>Hello world!</h1>";
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"]);
});