From 09c77f6c896201d6421daa78c730ec16ba901452 Mon Sep 17 00:00:00 2001 From: Xavier Dubuc Date: Thu, 20 Aug 2020 13:31:23 +0000 Subject: [PATCH] [FIX] mail: allow composer text input to send message with ctrl+enter MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Also allow meta+enter task-2296863 closes odoo/odoo#57050 X-original-commit: 6bad3666be3d3631eaadae409d0cabcdd02661a8 Signed-off-by: Sébastien Theys (seb) --- .../static/src/components/chatter/chatter.xml | 2 +- .../src/components/chatter/chatter_tests.js | 105 +++++++++ .../src/components/composer/composer.js | 25 ++- .../src/components/composer/composer.xml | 4 +- .../src/components/composer/composer_tests.js | 128 ++++++++++- .../composer_text_input.js | 63 ++++-- .../static/src/components/discuss/discuss.xml | 1 + .../discuss/tests/discuss_inbox_tests.js | 22 +- .../components/discuss/tests/discuss_tests.js | 201 +++++++++++++++++- .../components/thread_view/thread_view.xml | 2 +- 10 files changed, 500 insertions(+), 53 deletions(-) diff --git a/addons/mail/static/src/components/chatter/chatter.xml b/addons/mail/static/src/components/chatter/chatter.xml index a48396f813c..e5601dd7974 100644 --- a/addons/mail/static/src/components/chatter/chatter.xml +++ b/addons/mail/static/src/components/chatter/chatter.xml @@ -14,9 +14,9 @@ t-att-class="{ 'o-bordered': chatter.hasExternalBorder }" composerLocalId="chatter.thread.composer.localId" hasMentionSuggestionsBelowPosition="true" - hasTextInputSendOnEnterEnabled="false" isCompact="false" isExpandable="true" + textInputSendShortcuts="['ctrl-enter', 'meta-enter']" t-on-o-message-posted="_onComposerMessagePosted" t-ref="composer" /> diff --git a/addons/mail/static/src/components/chatter/chatter_tests.js b/addons/mail/static/src/components/chatter/chatter_tests.js index 73ff0eb2c38..d5c2932a6d7 100644 --- a/addons/mail/static/src/components/chatter/chatter_tests.js +++ b/addons/mail/static/src/components/chatter/chatter_tests.js @@ -342,6 +342,111 @@ QUnit.test('should not display user notification messages in chatter', async fun ); }); +QUnit.test('post message with "CTRL-Enter" keyboard shortcut', async function (assert) { + assert.expect(2); + + this.data['res.partner'].records.push({ id: 100 }); + await this.start(); + const chatter = this.env.models['mail.chatter'].create({ + threadId: 100, + threadModel: 'res.partner', + }); + await this.createChatterComponent({ chatter }); + assert.containsNone( + document.body, + '.o_Message', + "should not have any message initially in chatter" + ); + + await afterNextRender(() => + document.querySelector('.o_ChatterTopbar_buttonSendMessage').click() + ); + await afterNextRender(() => { + document.querySelector(`.o_ComposerTextInput_textarea`).focus(); + document.execCommand('insertText', false, "Test"); + }); + await afterNextRender(() => { + const kevt = new window.KeyboardEvent('keydown', { ctrlKey: true, key: "Enter" }); + document.querySelector('.o_ComposerTextInput_textarea').dispatchEvent(kevt); + }); + assert.containsOnce( + document.body, + '.o_Message', + "should now have single message in chatter after posting message from pressing 'CTRL-Enter' in text input of composer" + ); +}); + +QUnit.test('post message with "META-Enter" keyboard shortcut', async function (assert) { + assert.expect(2); + + this.data['res.partner'].records.push({ id: 100 }); + await this.start(); + const chatter = this.env.models['mail.chatter'].create({ + threadId: 100, + threadModel: 'res.partner', + }); + await this.createChatterComponent({ chatter }); + assert.containsNone( + document.body, + '.o_Message', + "should not have any message initially in chatter" + ); + + await afterNextRender(() => + document.querySelector('.o_ChatterTopbar_buttonSendMessage').click() + ); + await afterNextRender(() => { + document.querySelector(`.o_ComposerTextInput_textarea`).focus(); + document.execCommand('insertText', false, "Test"); + }); + await afterNextRender(() => { + const kevt = new window.KeyboardEvent('keydown', { key: "Enter", metaKey: true }); + document.querySelector('.o_ComposerTextInput_textarea').dispatchEvent(kevt); + }); + assert.containsOnce( + document.body, + '.o_Message', + "should now have single message in channel after posting message from pressing 'META-Enter' in text input of composer" + ); +}); + +QUnit.test('do not post message with "Enter" keyboard shortcut', async function (assert) { + // Note that test doesn't assert Enter makes a newline, because this + // default browser cannot be simulated with just dispatching + // programmatically crafted events... + assert.expect(2); + + this.data['res.partner'].records.push({ id: 100 }); + await this.start(); + const chatter = this.env.models['mail.chatter'].create({ + threadId: 100, + threadModel: 'res.partner', + }); + await this.createChatterComponent({ chatter }); + assert.containsNone( + document.body, + '.o_Message', + "should not have any message initially in chatter" + ); + + await afterNextRender(() => + document.querySelector('.o_ChatterTopbar_buttonSendMessage').click() + ); + await afterNextRender(() => { + document.querySelector(`.o_ComposerTextInput_textarea`).focus(); + document.execCommand('insertText', false, "Test"); + }); + await afterNextRender(() => { + const kevt = new window.KeyboardEvent('keydown', { key: "Enter" }); + document.querySelector('.o_ComposerTextInput_textarea').dispatchEvent(kevt); + }); + assert.containsNone( + document.body, + '.o_Message', + "should still not have any message in mailing channel after pressing 'Enter' in text input of composer" + ); +}); + }); }); }); diff --git a/addons/mail/static/src/components/composer/composer.js b/addons/mail/static/src/components/composer/composer.js index 0b23ee4ec22..510a5ac6038 100644 --- a/addons/mail/static/src/components/composer/composer.js +++ b/addons/mail/static/src/components/composer/composer.js @@ -261,6 +261,13 @@ class Composer extends Component { this._postMessage(); } + /** + * @private + */ + _onComposerTextInputSendShortcut() { + this._postMessage(); + } + /** * Called when some files have been dropped in the dropzone. * @@ -340,13 +347,6 @@ class Composer extends Component { await this._fileUploaderRef.comp.uploadFiles(ev.clipboardData.files); } - /** - * @private - */ - _onTextInputKeydownEnter() { - this._postMessage(); - } - } Object.assign(Composer, { @@ -357,7 +357,6 @@ Object.assign(Composer, { hasDiscardButton: false, hasFollowers: false, hasSendButton: true, - hasTextInputSendOnEnterEnabled: true, hasThreadName: false, hasThreadTyping: false, isCompact: true, @@ -381,7 +380,6 @@ Object.assign(Composer, { optional: true, }, hasSendButton: Boolean, - hasTextInputSendOnEnterEnabled: Boolean, hasThreadName: Boolean, hasThreadTyping: Boolean, showAttachmentsExtensions: { @@ -403,6 +401,15 @@ Object.assign(Composer, { }, isCompact: Boolean, isExpandable: Boolean, + /** + * If set, keyboard shortcuts from text input to send message. + * If not set, will use default values from `ComposerTextInput`. + */ + textInputSendShortcuts: { + type: Array, + element: String, + optional: true, + }, }, template: 'mail.Composer', }); diff --git a/addons/mail/static/src/components/composer/composer.xml b/addons/mail/static/src/components/composer/composer.xml index 30053cdd0f8..61694e5aaf1 100644 --- a/addons/mail/static/src/components/composer/composer.xml +++ b/addons/mail/static/src/components/composer/composer.xml @@ -75,9 +75,9 @@ }" composerLocalId="composer.localId" hasMentionSuggestionsBelowPosition="props.hasMentionSuggestionsBelowPosition" - hasSendOnEnterEnabled="props.hasTextInputSendOnEnterEnabled" isCompact="props.isCompact" - t-on-o-keydown-enter="_onTextInputKeydownEnter" + sendShortcuts="props.textInputSendShortcuts" + t-on-o-composer-text-input-send-shortcut="_onComposerTextInputSendShortcut" t-on-paste="_onPasteTextInput" t-ref="textInput" /> diff --git a/addons/mail/static/src/components/composer/composer_tests.js b/addons/mail/static/src/components/composer/composer_tests.js index 8e07affcccb..5d337e0ed0c 100644 --- a/addons/mail/static/src/components/composer/composer_tests.js +++ b/addons/mail/static/src/components/composer/composer_tests.js @@ -590,6 +590,116 @@ QUnit.test('composer: paste attachments', async function (assert) { ); }); +QUnit.test('send message when enter is pressed while holding ctrl key (this shortcut is available)', async function (assert) { + // Note that test doesn't assert ENTER makes no newline, because this + // default browser cannot be simulated with just dispatching + // programmatically crafted events... + assert.expect(5); + + this.data['mail.channel'].records.push({ id: 20 }); + await this.start({ + async mockRPC(route, args) { + if (args.method === 'message_post') { + assert.step('message_post'); + } + return this._super(...arguments); + }, + }); + const thread = this.env.models['mail.thread'].find(thread => + thread.id === 20 && + thread.model === 'mail.channel' + ); + await this.createComposerComponent(thread.composer, { + textInputSendShortcuts: ['ctrl-enter'], + }); + // Type message + document.querySelector(`.o_ComposerTextInput_textarea`).focus(); + document.execCommand('insertText', false, "test message"); + assert.strictEqual( + document.querySelector(`.o_ComposerTextInput_textarea`).value, + "test message", + "should have inserted text content in editable" + ); + + await afterNextRender(() => { + const enterEvent = new window.KeyboardEvent('keydown', { key: 'Enter' }); + document.querySelector(`.o_ComposerTextInput_textarea`) + .dispatchEvent(enterEvent); + }); + assert.strictEqual( + document.querySelector(`.o_ComposerTextInput_textarea`).value, + "test message", + "should have inserted text content in editable as message has not been posted" + ); + + // Send message with ctrl+enter + await afterNextRender(() => + document.querySelector(`.o_ComposerTextInput_textarea`) + .dispatchEvent(new window.KeyboardEvent('keydown', { ctrlKey: true, key: 'Enter' })) + ); + assert.verifySteps(['message_post']); + assert.strictEqual( + document.querySelector(`.o_ComposerTextInput_textarea`).value, + "", + "should have no content in composer input as message has been posted" + ); +}); + +QUnit.test('send message when enter is pressed while holding meta key (this shortcut is available)', async function (assert) { + // Note that test doesn't assert ENTER makes no newline, because this + // default browser cannot be simulated with just dispatching + // programmatically crafted events... + assert.expect(5); + + this.data['mail.channel'].records.push({ id: 20 }); + await this.start({ + async mockRPC(route, args) { + if (args.method === 'message_post') { + assert.step('message_post'); + } + return this._super(...arguments); + }, + }); + const thread = this.env.models['mail.thread'].find(thread => + thread.id === 20 && + thread.model === 'mail.channel' + ); + await this.createComposerComponent(thread.composer, { + textInputSendShortcuts: ['meta-enter'], + }); + // Type message + document.querySelector(`.o_ComposerTextInput_textarea`).focus(); + document.execCommand('insertText', false, "test message"); + assert.strictEqual( + document.querySelector(`.o_ComposerTextInput_textarea`).value, + "test message", + "should have inserted text content in editable" + ); + + await afterNextRender(() => { + const enterEvent = new window.KeyboardEvent('keydown', { key: 'Enter' }); + document.querySelector(`.o_ComposerTextInput_textarea`) + .dispatchEvent(enterEvent); + }); + assert.strictEqual( + document.querySelector(`.o_ComposerTextInput_textarea`).value, + "test message", + "should have inserted text content in editable as message has not been posted" + ); + + // Send message with meta+enter + await afterNextRender(() => + document.querySelector(`.o_ComposerTextInput_textarea`) + .dispatchEvent(new window.KeyboardEvent('keydown', { key: 'Enter', metaKey: true })) + ); + assert.verifySteps(['message_post']); + assert.strictEqual( + document.querySelector(`.o_ComposerTextInput_textarea`).value, + "", + "should have no content in composer input as message has been posted" + ); +}); + QUnit.test('composer text input cleared on message post', async function (assert) { assert.expect(4); @@ -610,8 +720,10 @@ QUnit.test('composer text input cleared on message post', async function (assert ); await this.createComposerComponent(thread.composer); // Type message - document.querySelector(`.o_ComposerTextInput_textarea`).focus(); - document.execCommand('insertText', false, "test message"); + await afterNextRender(() => { + document.querySelector(`.o_ComposerTextInput_textarea`).focus(); + document.execCommand('insertText', false, "test message"); + }); assert.strictEqual( document.querySelector(`.o_ComposerTextInput_textarea`).value, "test message", @@ -620,8 +732,7 @@ QUnit.test('composer text input cleared on message post', async function (assert // Send message await afterNextRender(() => - document.querySelector(`.o_ComposerTextInput_textarea`) - .dispatchEvent(new window.KeyboardEvent('keydown', { key: 'Enter' })) + document.querySelector('.o_Composer_buttonSend').click() ); assert.verifySteps(['message_post']); assert.strictEqual( @@ -691,8 +802,7 @@ QUnit.test('composer inputs cleared on message post in composer of a mailing cha // Send message await afterNextRender(() => - document.querySelector(`.o_ComposerTextInput_textarea`) - .dispatchEvent(new window.KeyboardEvent('keydown', { key: 'Enter' })) + document.querySelector('.o_Composer_buttonSend').click() ); assert.verifySteps(['message_post']); assert.strictEqual( @@ -956,7 +1066,7 @@ QUnit.test('composer: send button is disabled if attachment upload is not finish ); }); -QUnit.test('warning when attempting to post message when attachments are still uploading', async function (assert) { +QUnit.test('warning on send with shortcut when attempting to post message with still-uploading attachments', async function (assert) { assert.expect(7); await this.start({ @@ -991,7 +1101,9 @@ QUnit.test('warning when attempting to post message when attachments are still u id: 20, model: 'res.partner', }); - await this.createComposerComponent(thread.composer); + await this.createComposerComponent(thread.composer, { + textInputSendShortcuts: ['enter'], + }); const file = await createFile({ content: 'hello, world', contentType: 'text/plain', diff --git a/addons/mail/static/src/components/composer_text_input/composer_text_input.js b/addons/mail/static/src/components/composer_text_input/composer_text_input.js index 6a0943f9ca8..ef21d023cb5 100644 --- a/addons/mail/static/src/components/composer_text_input/composer_text_input.js +++ b/addons/mail/static/src/components/composer_text_input/composer_text_input.js @@ -241,18 +241,41 @@ class ComposerTextInput extends Component { _onKeydownTextareaEnter(ev) { if (this.composer.hasSuggestedPartners) { ev.preventDefault(); - } else { - if (!this.props.hasSendOnEnterEnabled) { - return; - } - if (ev.shiftKey) { - return; - } - if (this.env.messaging.device.isMobile) { - return; - } - this.trigger('o-keydown-enter'); + return; + } + if ( + this.props.sendShortcuts.includes('ctrl-enter') && + !ev.altKey && + ev.ctrlKey && + !ev.metaKey && + !ev.shiftKey + ) { + this.trigger('o-composer-text-input-send-shortcut'); ev.preventDefault(); + return; + } + if ( + this.props.sendShortcuts.includes('enter') && + !ev.altKey && + !ev.ctrlKey && + !ev.metaKey && + !ev.shiftKey && + !this.env.messaging.device.isMobile + ) { + this.trigger('o-composer-text-input-send-shortcut'); + ev.preventDefault(); + return; + } + if ( + this.props.sendShortcuts.includes('meta-enter') && + !ev.altKey && + !ev.ctrlKey && + ev.metaKey && + !ev.shiftKey + ) { + this.trigger('o-composer-text-input-send-shortcut'); + ev.preventDefault(); + return; } } @@ -341,13 +364,27 @@ Object.assign(ComposerTextInput, { components, defaultProps: { hasMentionSuggestionsBelowPosition: false, - hasSendOnEnterEnabled: true, + sendShortcuts: [], }, props: { composerLocalId: String, hasMentionSuggestionsBelowPosition: Boolean, - hasSendOnEnterEnabled: Boolean, isCompact: Boolean, + /** + * Keyboard shortcuts from text input to send message. + */ + sendShortcuts: { + type: Array, + element: String, + validate: prop => { + for (const shortcut of prop) { + if (!['ctrl-enter', 'enter', 'meta-enter'].includes(shortcut)) { + return false; + } + } + return true; + }, + }, }, template: 'mail.ComposerTextInput', }); diff --git a/addons/mail/static/src/components/discuss/discuss.xml b/addons/mail/static/src/components/discuss/discuss.xml index d88b4796d9c..79838422f81 100644 --- a/addons/mail/static/src/components/discuss/discuss.xml +++ b/addons/mail/static/src/components/discuss/discuss.xml @@ -94,6 +94,7 @@ hasCurrentPartnerAvatar="!env.messaging.device.isMobile" hasDiscardButton="true" hasThreadName="true" + textInputSendShortcuts="['ctrl-enter', 'meta-enter']" t-on-o-message-posted="_onReplyingToMessageMessagePosted" t-ref="composer" /> diff --git a/addons/mail/static/src/components/discuss/tests/discuss_inbox_tests.js b/addons/mail/static/src/components/discuss/tests/discuss_inbox_tests.js index 8ecc62e81b2..5f24acec192 100644 --- a/addons/mail/static/src/components/discuss/tests/discuss_inbox_tests.js +++ b/addons/mail/static/src/components/discuss/tests/discuss_inbox_tests.js @@ -312,11 +312,12 @@ QUnit.test('"reply to" composer should log note if message replied to is a note' "Send button text should be 'Log'" ); - await afterNextRender(() => { - document.execCommand('insertText', false, "Test"); - document.querySelector(`.o_ComposerTextInput_textarea`) - .dispatchEvent(new window.KeyboardEvent('keydown', { key: 'Enter' })); - }); + await afterNextRender(() => + document.execCommand('insertText', false, "Test") + ); + await afterNextRender(() => + document.querySelector('.o_Composer_buttonSend').click() + ); assert.verifySteps(['message_post']); }); @@ -363,11 +364,12 @@ QUnit.test('"reply to" composer should send message if message replied to is not "Send button text should be 'Send'" ); - await afterNextRender(() => { - document.execCommand('insertText', false, "Test"); - document.querySelector(`.o_ComposerTextInput_textarea`) - .dispatchEvent(new window.KeyboardEvent('keydown', { key: 'Enter' })); - }); + await afterNextRender(() => + document.execCommand('insertText', false, "Test") + ); + await afterNextRender(() => + document.querySelector('.o_Composer_buttonSend').click() + ); assert.verifySteps(['message_post']); }); diff --git a/addons/mail/static/src/components/discuss/tests/discuss_tests.js b/addons/mail/static/src/components/discuss/tests/discuss_tests.js index 3f9e93d1de8..2983fcc11b2 100644 --- a/addons/mail/static/src/components/discuss/tests/discuss_tests.js +++ b/addons/mail/static/src/components/discuss/tests/discuss_tests.js @@ -2846,8 +2846,10 @@ QUnit.test('post a simple message', async function (assert) { ); // insert some HTML in editable - document.querySelector(`.o_ComposerTextInput_textarea`).focus(); - document.execCommand('insertText', false, "Test"); + await afterNextRender(() => { + document.querySelector(`.o_ComposerTextInput_textarea`).focus(); + document.execCommand('insertText', false, "Test"); + }); assert.strictEqual( document.querySelector(`.o_ComposerTextInput_textarea`).value, "Test", @@ -2855,8 +2857,7 @@ QUnit.test('post a simple message', async function (assert) { ); await afterNextRender(() => - document.querySelector(`.o_ComposerTextInput_textarea`) - .dispatchEvent(new window.KeyboardEvent('keydown', { key: 'Enter' })) + document.querySelector('.o_Composer_buttonSend').click() ); assert.verifySteps(['message_post']); assert.strictEqual( @@ -2887,6 +2888,187 @@ QUnit.test('post a simple message', async function (assert) { ); }); +QUnit.test('post message on non-mailing channel with "Enter" keyboard shortcut', async function (assert) { + assert.expect(2); + + // channel expected to be found in the sidebar + // with a random unique id that will be referenced in the test + this.data['mail.channel'].records.push({ id: 20, mass_mailing: false }); + await this.start({ + discuss: { + params: { + default_active_id: 'mail.channel_20', + }, + }, + }); + assert.containsNone( + document.body, + '.o_Message', + "should not have any message initially in channel" + ); + + // insert some HTML in editable + await afterNextRender(() => { + document.querySelector(`.o_ComposerTextInput_textarea`).focus(); + document.execCommand('insertText', false, "Test"); + }); + await afterNextRender(() => { + const kevt = new window.KeyboardEvent('keydown', { key: "Enter" }); + document.querySelector('.o_ComposerTextInput_textarea').dispatchEvent(kevt); + }); + assert.containsOnce( + document.body, + '.o_Message', + "should now have single message in channel after posting message from pressing 'Enter' in text input of composer" + ); +}); + +QUnit.test('do not post message on non-mailing channel with "SHIFT-Enter" keyboard shortcut', async function (assert) { + // Note that test doesn't assert SHIFT-Enter makes a newline, because this + // default browser cannot be simulated with just dispatching + // programmatically crafted events... + assert.expect(2); + + // channel expected to be found in the sidebar + // with a random unique id that will be referenced in the test + this.data['mail.channel'].records.push({ id: 20, mass_mailing: true }); + await this.start({ + discuss: { + params: { + default_active_id: 'mail.channel_20', + }, + }, + }); + assert.containsNone( + document.body, + '.o_Message', + "should not have any message initially in channel" + ); + + // insert some HTML in editable + await afterNextRender(() => { + document.querySelector(`.o_ComposerTextInput_textarea`).focus(); + document.execCommand('insertText', false, "Test"); + }); + await afterNextRender(() => { + const kevt = new window.KeyboardEvent('keydown', { key: "Enter", shiftKey: true }); + document.querySelector('.o_ComposerTextInput_textarea').dispatchEvent(kevt); + }); + assert.containsNone( + document.body, + '.o_Message', + "should still not have any message in channel after pressing 'Shift-Enter' in text input of composer" + ); +}); + +QUnit.test('post message on mailing channel with "CTRL-Enter" keyboard shortcut', async function (assert) { + assert.expect(2); + + // channel expected to be found in the sidebar + // with a random unique id that will be referenced in the test + this.data['mail.channel'].records.push({ id: 20, mass_mailing: true }); + await this.start({ + discuss: { + params: { + default_active_id: 'mail.channel_20', + }, + }, + }); + assert.containsNone( + document.body, + '.o_Message', + "should not have any message initially in channel" + ); + + // insert some HTML in editable + await afterNextRender(() => { + document.querySelector(`.o_ComposerTextInput_textarea`).focus(); + document.execCommand('insertText', false, "Test"); + }); + await afterNextRender(() => { + const kevt = new window.KeyboardEvent('keydown', { ctrlKey: true, key: "Enter" }); + document.querySelector('.o_ComposerTextInput_textarea').dispatchEvent(kevt); + }); + assert.containsOnce( + document.body, + '.o_Message', + "should now have single message in channel after posting message from pressing 'CTRL-Enter' in text input of composer" + ); +}); + +QUnit.test('post message on mailing channel with "META-Enter" keyboard shortcut', async function (assert) { + assert.expect(2); + + // channel expected to be found in the sidebar + // with a random unique id that will be referenced in the test + this.data['mail.channel'].records.push({ id: 20, mass_mailing: true }); + await this.start({ + discuss: { + params: { + default_active_id: 'mail.channel_20', + }, + }, + }); + assert.containsNone( + document.body, + '.o_Message', + "should not have any message initially in channel" + ); + + // insert some HTML in editable + await afterNextRender(() => { + document.querySelector(`.o_ComposerTextInput_textarea`).focus(); + document.execCommand('insertText', false, "Test"); + }); + await afterNextRender(() => { + const kevt = new window.KeyboardEvent('keydown', { key: "Enter", metaKey: true }); + document.querySelector('.o_ComposerTextInput_textarea').dispatchEvent(kevt); + }); + assert.containsOnce( + document.body, + '.o_Message', + "should now have single message in channel after posting message from pressing 'META-Enter' in text input of composer" + ); +}); + +QUnit.test('do not post message on mailing channel with "Enter" keyboard shortcut', async function (assert) { + // Note that test doesn't assert Enter makes a newline, because this + // default browser cannot be simulated with just dispatching + // programmatically crafted events... + assert.expect(2); + + // channel expected to be found in the sidebar + // with a random unique id that will be referenced in the test + this.data['mail.channel'].records.push({ id: 20, mass_mailing: true }); + await this.start({ + discuss: { + params: { + default_active_id: 'mail.channel_20', + }, + }, + }); + assert.containsNone( + document.body, + '.o_Message', + "should not have any message initially in mailing channel" + ); + + // insert some HTML in editable + await afterNextRender(() => { + document.querySelector(`.o_ComposerTextInput_textarea`).focus(); + document.execCommand('insertText', false, "Test"); + }); + await afterNextRender(() => { + const kevt = new window.KeyboardEvent('keydown', { key: "Enter" }); + document.querySelector('.o_ComposerTextInput_textarea').dispatchEvent(kevt); + }); + assert.containsNone( + document.body, + '.o_Message', + "should still not have any message in mailing channel after pressing 'Enter' in text input of composer" + ); +}); + QUnit.test('rendering of inbox message', async function (assert) { // AKU TODO: kinda message specific test assert.expect(7); @@ -3205,11 +3387,12 @@ QUnit.test('reply to message from inbox (message linked to document)', async fun "composer text input should be auto-focus" ); - await afterNextRender(() => { - document.execCommand('insertText', false, "Test"); - document.querySelector(`.o_ComposerTextInput_textarea`) - .dispatchEvent(new window.KeyboardEvent('keydown', { key: 'Enter' })); - }); + await afterNextRender(() => + document.execCommand('insertText', false, "Test") + ); + await afterNextRender(() => + document.querySelector('.o_Composer_buttonSend').click() + ); assert.verifySteps(['message_post']); assert.notOk( document.querySelector('.o_Composer'), diff --git a/addons/mail/static/src/components/thread_view/thread_view.xml b/addons/mail/static/src/components/thread_view/thread_view.xml index 12352f67fe5..e7dd82ccf43 100644 --- a/addons/mail/static/src/components/thread_view/thread_view.xml +++ b/addons/mail/static/src/components/thread_view/thread_view.xml @@ -30,11 +30,11 @@ composerLocalId="threadView.thread.composer.localId" hasCurrentPartnerAvatar="props.hasComposerCurrentPartnerAvatar" hasSendButton="props.hasComposerSendButton" - hasTextInputSendOnEnterEnabled="(threadView.thread.model === 'mail.channel' and threadView.thread.mass_mailing) ? false : undefined" hasThreadTyping="props.hasComposerThreadTyping" isCompact="(threadView.thread.model === 'mail.channel' and threadView.thread.mass_mailing) ? false : undefined" showAttachmentsExtensions="props.showComposerAttachmentsExtensions" showAttachmentsFilenames="props.showComposerAttachmentsFilenames" + textInputSendShortcuts="(threadView.thread.model === 'mail.channel' and threadView.thread.mass_mailing) ? ['ctrl-enter', 'meta-enter'] : ['enter']" t-ref="composer" />