diff --git a/addons/mail/static/src/core/common/navigable_list.js b/addons/mail/static/src/core/common/navigable_list.js index 3d2a9ad0080..099827ce930 100644 --- a/addons/mail/static/src/core/common/navigable_list.js +++ b/addons/mail/static/src/core/common/navigable_list.js @@ -28,9 +28,8 @@ export class NavigableList extends Component { setup() { this.rootRef = useRef("root"); this.state = useState({ - activeOption: null, + activeIndex: null, open: false, - options: [], }); this.hotkey = useService("hotkey"); this.hotkeysToRemove = []; @@ -58,33 +57,22 @@ export class NavigableList extends Component { } get show() { - return Boolean(this.state.open && (this.props.isLoading || this.state.options.length)); + return Boolean(this.state.open && (this.props.isLoading || this.props.options.length)); } open() { - this.load(); this.state.open = true; + this.state.activeIndex = null; this.navigate("first"); } close() { this.state.open = false; - this.state.activeOption = null; + this.state.activeIndex = null; } - load() { - this.state.options = []; - this.state.options = this.props.options.map((option, index) => ({ - ...option, - id: index, - })); - } - - isActiveOption(option) { - return this.state.activeOption?.id === option.id; - } - - selectOption(ev, option, params = {}) { + selectOption(ev, index, params = {}) { + const option = this.props.options[index]; if (option.unselectable) { this.close(); return; @@ -96,14 +84,14 @@ export class NavigableList extends Component { } navigate(direction) { - const activeOptionId = this.state.activeOption ? this.state.activeOption.id : -1; + const activeOptionId = this.state.activeIndex !== null ? this.state.activeIndex : 0; let targetId = undefined; switch (direction) { case "first": targetId = 0; break; case "last": - targetId = this.state.options.length - 1; + targetId = this.props.options.length - 1; break; case "previous": targetId = activeOptionId - 1; @@ -114,7 +102,7 @@ export class NavigableList extends Component { break; case "next": targetId = activeOptionId + 1; - if (targetId > this.state.options.length - 1) { + if (targetId > this.props.options.length - 1) { this.navigate("first"); return; } @@ -122,7 +110,7 @@ export class NavigableList extends Component { default: return; } - this.state.activeOption = this.state.options.find((o) => o.id === targetId); + this.state.activeIndex = targetId; } onKeydown(ev) { @@ -132,11 +120,11 @@ export class NavigableList extends Component { const hotkey = getActiveHotkey(ev); switch (hotkey) { case "enter": - if (!this.show || !this.state.activeOption) { + if (!this.show || this.state.activeIndex === null) { return; } markEventHandled(ev, "NavigableList.select"); - this.selectOption(ev, this.state.activeOption); + this.selectOption(ev, this.state.activeIndex); break; case "escape": markEventHandled(ev, "NavigableList.close"); @@ -157,7 +145,7 @@ export class NavigableList extends Component { ev.preventDefault(); } - onOptionMouseEnter(option) { - this.state.activeOption = option; + onOptionMouseEnter(index) { + this.state.activeIndex = index; } } diff --git a/addons/mail/static/src/core/common/navigable_list.xml b/addons/mail/static/src/core/common/navigable_list.xml index 45fe0f5895c..38170334a71 100644 --- a/addons/mail/static/src/core/common/navigable_list.xml +++ b/addons/mail/static/src/core/common/navigable_list.xml @@ -12,13 +12,13 @@
- + diff --git a/addons/mail/static/tests/composer/composer_tests.js b/addons/mail/static/tests/composer/composer_tests.js index 8a0fda96b53..91bb7e3fca6 100644 --- a/addons/mail/static/tests/composer/composer_tests.js +++ b/addons/mail/static/tests/composer/composer_tests.js @@ -388,6 +388,35 @@ QUnit.test("pending mentions are kept when toggling composer", async () => { await contains(".o-mail-Message-body a.o_mail_redirect", { text: "@Mitchell Admin" }); }); +QUnit.test("composer suggestion should match with input selection", async () => { + const pyEnv = await startServer(); + const partnerId = pyEnv["res.partner"].create({ + email: "testpartner@odoo.com", + name: "Luigi", + }); + const channelId = pyEnv["discuss.channel"].create({ + name: "Mario Party", + channel_member_ids: [ + Command.create({ partner_id: pyEnv.currentPartnerId }), + Command.create({ partner_id: partnerId }), + ], + }); + const { openDiscuss } = await start(); + openDiscuss(channelId); + await contains(".o-mail-Composer-input", { value: "" }); + await insertText(".o-mail-Composer-input", "#"); + await contains(".o-mail-Composer-suggestion", { text: "#Mario Party" }); + await click(".o-mail-Composer-suggestion"); + await contains(".o-mail-Composer-input", { value: "#Mario Party " }); + await insertText(".o-mail-Composer-input", "@"); + await contains(".o-mail-Composer-suggestion", { text: "Luigi" }); + $(".o-mail-Composer-input")[0].setSelectionRange(3, 3); + await contains(".o-mail-Composer-suggestion", { text: "#Mario Party" }); + const textarea = $(".o-mail-Composer-input")[0]; + textarea.setSelectionRange(textarea.value.length, textarea.value.length); + await contains(".o-mail-Composer-suggestion", { text: "Luigi" }); +}); + QUnit.test('do not post message on channel with "SHIFT-Enter" keyboard shortcut', async () => { const pyEnv = await startServer(); const channelId = pyEnv["discuss.channel"].create({ name: "general" });