[FIX] mail: keyboard navigation in chat window dropdown

Before this commit, dropdowns in chat window (chat window more menu,
message actions more menu) had no keyboard navigation support.

This happens because dropdown item navigation makes use of hotkey
service, and hotkey service intercepts keyboard in bubble phase on
window object. `ChatWindow` component had a `t-on-keydown.stop` on its
root node, which prevented the hotkey service to receive keyboard
navigation for the good working of dropdown keyboard navigation.

This commit removes the `.stop` modifier on this `t-on-keydown` root
node of `ChatWindow` template. `onKeydown` in dropdown inside chat
window have precedence over `onKeydown` on chat window: For example,
when dropdown is open, hotkey "Escape" closes the dropdown menu but
does not close the chat window.

closes odoo/odoo#127318

X-original-commit: 4b36b28bd9e426b115ffefbbc174fe2efa3dfbf3
Signed-off-by: Sébastien Theys (seb) <seb@odoo.com>
Signed-off-by: Alexandre Kühn (aku) <aku@odoo.com>
This commit is contained in:
Alexandre Kühn
2023-07-04 20:33:48 +02:00
parent 4376cf80b9
commit 2ac5ceb7ff
3 changed files with 57 additions and 1 deletions
@@ -78,6 +78,9 @@ export class ChatWindow extends Component {
}
onKeydown(ev) {
if (ev.target.closest(".o-dropdown")) {
return;
}
switch (ev.key) {
case "Escape":
if (
@@ -10,7 +10,7 @@
'position-absolute bottom-0 overflow-hidden d-flex flex-column': !props.chatWindow.hidden,
'rounded-top-3': !props.chatWindow.hidden and !ui.isSmall,
}"
t-on-keydown.stop="onKeydown"
t-on-keydown="onKeydown"
tabindex="1"
>
<div class="o-mail-ChatWindow-header d-flex align-items-center flex-shrink-0 bg-100" t-on-click="onClickHeader" t-att-class="{ 'cursor-pointer': !ui.isSmall, 'border-bottom': !props.chatWindow.folded }">
@@ -1023,3 +1023,56 @@ QUnit.test("Open chat window of new inviter", async (assert) => {
".o_notification:contains(Newbie connected. This is their first connection. Wish them luck.)"
);
});
QUnit.test(
"keyboard navigation ArrowUp/ArrowDown on message action dropdown in chat window",
async (assert) => {
const pyEnv = await startServer();
const channelId = pyEnv["discuss.channel"].create({ name: "General" });
pyEnv["mail.message"].create({
author_id: pyEnv.currentPartnerId,
body: "not empty",
model: "discuss.channel",
res_id: channelId,
});
await start();
await click(".o_menu_systray i[aria-label='Messages']");
await click(".o-mail-NotificationItem");
await afterNextRender(() => {
$(".o-mail-Message")[0].dispatchEvent(new window.MouseEvent("mouseenter"));
});
await click(".o-mail-Message [title='Expand']");
$(".o-mail-Message [title='Expand']")[0].focus(); // necessary otherwise focus is in composer input
assert.containsOnce($, ".o-mail-Message-moreMenu.dropdown-menu");
await triggerHotkey("ArrowDown");
assert.containsOnce($, ".o-mail-Message-moreMenu .dropdown-item:eq(0).focus");
await triggerHotkey("ArrowDown");
assert.containsOnce($, ".o-mail-Message-moreMenu .dropdown-item:eq(1).focus");
}
);
QUnit.test(
"Close dropdown in chat window with ESCAPE does not also close the chat window",
async (assert) => {
const pyEnv = await startServer();
const channelId = pyEnv["discuss.channel"].create({ name: "General" });
pyEnv["mail.message"].create({
author_id: pyEnv.currentPartnerId,
body: "not empty",
model: "discuss.channel",
res_id: channelId,
});
await start();
await click(".o_menu_systray i[aria-label='Messages']");
await click(".o-mail-NotificationItem");
await afterNextRender(() => {
$(".o-mail-Message")[0].dispatchEvent(new window.MouseEvent("mouseenter"));
});
await click(".o-mail-Message [title='Expand']");
$(".o-mail-Message [title='Expand']")[0].focus(); // necessary otherwise focus is in composer input
assert.containsOnce($, ".o-mail-Message-moreMenu.dropdown-menu");
await triggerHotkey("Escape");
assert.containsNone($, ".o-mail-Message-moreMenu.dropdown-menu");
assert.containsOnce($, ".o-mail-ChatWindow");
}
);