diff options
| author | Priyanka Kakadiya <pka@odoo.com> | 2021-01-29 11:55:19 +0000 |
|---|---|---|
| committer | Priyanka Kakadiya <pka@odoo.com> | 2021-03-10 13:30:18 +0000 |
| commit | 2542f731c5b06c3b451ecde7992d3bb45adb2c60 (patch) | |
| tree | d590eab9af3504ca9c4932cca13d36070ac3489a /addons/mail/static/src | |
| parent | a8b43d02066b2299ac2f4b88056c37725e9ce6cd (diff) | |
[FIX] mail: fix keyboard shortcut issue for small screen
Current behavior before PR:
When having a small screen, the composer in a chat window has no actual
shortcut to send the message.
Desired behavior after PR is merged:
'CTRL-Enter' keyboard shortcut will work for small screen size.
LINKS:
PR https://github.com//pull/65241
Task-2446076
closes odoo/odoo#65241
Signed-off-by: Sébastien Theys (seb) <seb@odoo.com>
Diffstat (limited to 'addons/mail/static/src')
5 files changed, 115 insertions, 4 deletions
diff --git a/addons/mail/static/src/components/chat_window_manager/chat_window_manager_tests.js b/addons/mail/static/src/components/chat_window_manager/chat_window_manager_tests.js index 4e032e93dfb..979280465c3 100644 --- a/addons/mail/static/src/components/chat_window_manager/chat_window_manager_tests.js +++ b/addons/mail/static/src/components/chat_window_manager/chat_window_manager_tests.js @@ -1892,6 +1892,42 @@ QUnit.test('chat window should scroll to the newly posted message just after pos ); }); +QUnit.test('chat window: post message on non-mailing channel with "CTRL-Enter" keyboard shortcut for small screen size', async function (assert) { + assert.expect(1); + + this.data['mail.channel'].records.push({ + id: 20, + is_minimized: true, + mass_mailing: false, + }); + await this.start({ + env: { + device: { + isMobile: true, // here isMobile is used for the small screen size, not actually for the mobile devices + }, + }, + }); + + await afterNextRender(() => document.querySelector(`.o_MessagingMenu_toggler`).click()); + await afterNextRender(() => + document.querySelector(`.o_MessagingMenu_dropdownMenu .o_NotificationList_preview`).click() + ); + // 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 for small screen" + ); +}); + QUnit.test('[technical] chat window: composer state conservation on toggle home menu when folded', async function (assert) { // technical as show/hide home menu simulation are involved and home menu implementation // have side-effects on DOM that may make chat window components not work 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 25796afff9d..6c0705ee40a 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 @@ -278,8 +278,7 @@ class ComposerTextInput extends Component { !ev.altKey && !ev.ctrlKey && !ev.metaKey && - !ev.shiftKey && - !this.env.messaging.device.isMobile + !ev.shiftKey ) { this.trigger('o-composer-text-input-send-shortcut'); ev.preventDefault(); diff --git a/addons/mail/static/src/components/thread_view/thread_view.js b/addons/mail/static/src/components/thread_view/thread_view.js index 8a4898d6f3a..5b0f5f4a57a 100644 --- a/addons/mail/static/src/components/thread_view/thread_view.js +++ b/addons/mail/static/src/components/thread_view/thread_view.js @@ -20,7 +20,11 @@ class ThreadView extends Component { constructor(...args) { super(...args); useShouldUpdateBasedOnProps(); - useStore((...args) => this._useStoreSelector(...args)); + useStore((...args) => this._useStoreSelector(...args), { + compareDepth: { + threadTextInputSendShortcuts: 1, + }, + }); useUpdate({ func: () => this._update() }); /** * Reference of the composer. Useful to set focus on composer when @@ -133,6 +137,7 @@ class ThreadView extends Component { threadIsTemporary: thread && thread.isTemporary, threadMassMailing: thread && thread.mass_mailing, threadModel: thread && thread.model, + threadTextInputSendShortcuts: thread && thread.textInputSendShortcuts || [], threadView, threadViewIsLoading: threadView && threadView.isLoading, }; 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 99c78279adc..495408cc8f6 100644 --- a/addons/mail/static/src/components/thread_view/thread_view.xml +++ b/addons/mail/static/src/components/thread_view/thread_view.xml @@ -38,7 +38,7 @@ isDoFocus="props.isDoFocus" showAttachmentsExtensions="props.showComposerAttachmentsExtensions" showAttachmentsFilenames="props.showComposerAttachmentsFilenames" - textInputSendShortcuts="(threadView.thread.model === 'mail.channel' and threadView.thread.mass_mailing) ? ['ctrl-enter', 'meta-enter'] : ['enter']" + textInputSendShortcuts="threadView.textInputSendShortcuts" t-ref="composer" /> </t> diff --git a/addons/mail/static/src/models/thread_view/thread_view.js b/addons/mail/static/src/models/thread_view/thread_view.js index 534fd2769a9..a7ccf0c7d4d 100644 --- a/addons/mail/static/src/models/thread_view/thread_view.js +++ b/addons/mail/static/src/models/thread_view/thread_view.js @@ -69,6 +69,33 @@ function factory(dependencies) { /** * @private + * @returns {mail.messaging} + */ + _computeMessaging() { + return [['link', this.env.messaging]]; + } + + /** + * @private + * @returns {string[]} + */ + _computeTextInputSendShortcuts() { + if (!this.thread) { + return; + } + const isMailingList = this.thread.model === 'mail.channel' && this.thread.mass_mailing; + // Actually in mobile there is a send button, so we need there 'enter' to allow new line. + // Hence, we want to use a different shortcut 'ctrl/meta enter' to send for small screen + // size with a non-mailing channel. + // here send will be done on clicking the button or using the 'ctrl/meta enter' shortcut. + if (this.env.messaging.device.isMobile || isMailingList) { + return ['ctrl-enter', 'meta-enter']; + } + return ['enter']; + } + + /** + * @private * @returns {integer|undefined} */ _computeThreadCacheInitialScrollHeight() { @@ -199,6 +226,18 @@ function factory(dependencies) { composer: many2one('mail.composer', { related: 'thread.composer', }), + /** + * Serves as compute dependency. + */ + device: one2one('mail.device', { + related: 'messaging.device', + }), + /** + * Serves as compute dependency. + */ + deviceIsMobile: attr({ + related: 'device.isMobile', + }), hasComposerFocus: attr({ related: 'composer.hasFocus', }), @@ -255,6 +294,12 @@ function factory(dependencies) { messages: many2many('mail.message', { related: 'threadCache.messages', }), + /** + * Serves as compute dependency. + */ + messaging: many2one('mail.messaging', { + compute: '_computeMessaging', + }), nonEmptyMessages: many2many('mail.message', { related: 'threadCache.nonEmptyMessages', }), @@ -288,6 +333,20 @@ function factory(dependencies) { related: 'threadViewer.stringifiedDomain', }), /** + * Determines the keyboard shortcuts that are available to send a message + * from the composer of this thread viewer. + */ + textInputSendShortcuts: attr({ + compute: '_computeTextInputSendShortcuts', + dependencies: [ + 'device', + 'deviceIsMobile', + 'thread', + 'threadMassMailing', + 'threadModel', + ], + }), + /** * Determines the `mail.thread` currently displayed by `this`. */ thread: many2one('mail.thread', { @@ -336,6 +395,18 @@ function factory(dependencies) { related: 'threadViewer.threadCacheInitialScrollPositions', }), /** + * Serves as compute dependency. + */ + threadMassMailing: attr({ + related: 'thread.mass_mailing', + }), + /** + * Serves as compute dependency. + */ + threadModel: attr({ + related: 'thread.model', + }), + /** * Not a real field, used to trigger `thread.markAsSeen` when one of * the dependencies changes. */ |
