From 3abcadb5cb16b99ef6d1ed092521422fd168a313 Mon Sep 17 00:00:00 2001 From: Pranav Raj S Date: Wed, 15 Sep 2021 20:15:06 +0530 Subject: [PATCH] fix: Reject keyboard shortcut listeners if input box is active (#3019) Reject keyboard shortcut listeners if input box is active --- .../dashboard/components/ChatList.vue | 19 +++++++++++++- .../components/buttons/ResolveAction.vue | 4 ++- .../dashboard/components/layout/Sidebar.vue | 26 +++++++++++++++++++ .../components/layout/SidebarItem.vue | 23 +--------------- .../widgets/conversation/ReplyBox.vue | 18 +++++++------ app/javascript/sdk/sdk.js | 5 ++-- .../shared/mixins/eventListenerMixins.js | 26 ++++++++++++++++--- 7 files changed, 84 insertions(+), 37 deletions(-) diff --git a/app/javascript/dashboard/components/ChatList.vue b/app/javascript/dashboard/components/ChatList.vue index 6d65ba2dd..5ca64d215 100644 --- a/app/javascript/dashboard/components/ChatList.vue +++ b/app/javascript/dashboard/components/ChatList.vue @@ -194,7 +194,7 @@ export default { }); }, methods: { - handleKeyEvents(e) { + getKeyboardListenerParams() { const allConversations = this.$refs.activeConversation.querySelectorAll( 'div.conversations-list div.conversation' ); @@ -205,7 +205,19 @@ export default { activeConversation ); const lastConversationIndex = allConversations.length - 1; + return { + allConversations, + activeConversation, + activeConversationIndex, + lastConversationIndex, + }; + }, + handleKeyEvents(e) { if (hasPressedAltAndJKey(e)) { + const { + allConversations, + activeConversationIndex, + } = this.getKeyboardListenerParams(); if (activeConversationIndex === -1) { allConversations[0].click(); } @@ -214,6 +226,11 @@ export default { } } if (hasPressedAltAndKKey(e)) { + const { + allConversations, + activeConversationIndex, + lastConversationIndex, + } = this.getKeyboardListenerParams(); if (activeConversationIndex === -1) { allConversations[lastConversationIndex].click(); } else if (activeConversationIndex < lastConversationIndex) { diff --git a/app/javascript/dashboard/components/buttons/ResolveAction.vue b/app/javascript/dashboard/components/buttons/ResolveAction.vue index 76090b89f..637424815 100644 --- a/app/javascript/dashboard/components/buttons/ResolveAction.vue +++ b/app/javascript/dashboard/components/buttons/ResolveAction.vue @@ -176,7 +176,9 @@ export default { '.conversations-list .conversation' ); if (hasPressedAltAndMKey(e)) { - this.$refs.arrowDownButton.$el.click(); + if (this.$refs.arrowDownButton) { + this.$refs.arrowDownButton.$el.click(); + } } if (hasPressedAltAndEKey(e)) { const activeConversation = document.querySelector( diff --git a/app/javascript/dashboard/components/layout/Sidebar.vue b/app/javascript/dashboard/components/layout/Sidebar.vue index e8c0e21f8..07314e9c0 100644 --- a/app/javascript/dashboard/components/layout/Sidebar.vue +++ b/app/javascript/dashboard/components/layout/Sidebar.vue @@ -95,10 +95,15 @@ import AddAccountModal from './sidebarComponents/AddAccountModal.vue'; import AddLabelModal from '../../routes/dashboard/settings/labels/AddLabel'; import WootKeyShortcutModal from 'components/widgets/modal/WootKeyShortcutModal'; import { + hasPressedAltAndCKey, + hasPressedAltAndRKey, + hasPressedAltAndSKey, + hasPressedAltAndVKey, hasPressedCommandAndForwardSlash, isEscape, } from 'shared/helpers/KeyboardHelpers'; import eventListenerMixins from 'shared/mixins/eventListenerMixins'; +import router from '../../routes'; export default { components: { @@ -276,6 +281,27 @@ export default { if (isEscape(e)) { this.closeKeyShortcutModal(); } + + if (hasPressedAltAndCKey(e)) { + if (!this.isCurrentRouteSameAsNavigation('home')) { + router.push({ name: 'home' }); + } + } else if (hasPressedAltAndVKey(e)) { + if (!this.isCurrentRouteSameAsNavigation('contacts_dashboard')) { + router.push({ name: 'contacts_dashboard' }); + } + } else if (hasPressedAltAndRKey(e)) { + if (!this.isCurrentRouteSameAsNavigation('settings_account_reports')) { + router.push({ name: 'settings_account_reports' }); + } + } else if (hasPressedAltAndSKey(e)) { + if (!this.isCurrentRouteSameAsNavigation('agent_list')) { + router.push({ name: 'agent_list' }); + } + } + }, + isCurrentRouteSameAsNavigation(routeName) { + return router.currentRoute && router.currentRoute.name === routeName; }, toggleSupportChatWindow() { window.$chatwoot.toggle(); diff --git a/app/javascript/dashboard/components/layout/SidebarItem.vue b/app/javascript/dashboard/components/layout/SidebarItem.vue index 4576045fc..462853e6a 100644 --- a/app/javascript/dashboard/components/layout/SidebarItem.vue +++ b/app/javascript/dashboard/components/layout/SidebarItem.vue @@ -59,17 +59,10 @@ import { mapGetters } from 'vuex'; import router from '../../routes'; -import { - hasPressedAltAndCKey, - hasPressedAltAndVKey, - hasPressedAltAndRKey, - hasPressedAltAndSKey, -} from 'shared/helpers/KeyboardHelpers'; import adminMixin from '../../mixins/isAdmin'; -import eventListenerMixins from 'shared/mixins/eventListenerMixins'; import { getInboxClassByType } from 'dashboard/helper/inbox'; export default { - mixins: [adminMixin, eventListenerMixins], + mixins: [adminMixin], props: { menuItem: { type: Object, @@ -124,20 +117,6 @@ export default { } } }, - handleKeyEvents(e) { - if (hasPressedAltAndCKey(e)) { - router.push({ name: 'home' }); - } - if (hasPressedAltAndVKey(e)) { - router.push({ name: 'contacts_dashboard' }); - } - if (hasPressedAltAndRKey(e)) { - router.push({ name: 'settings_account_reports' }); - } - if (hasPressedAltAndSKey(e)) { - router.push({ name: 'settings_home' }); - } - }, showItem(item) { return this.isAdmin && item.newLink !== undefined; }, diff --git a/app/javascript/dashboard/components/widgets/conversation/ReplyBox.vue b/app/javascript/dashboard/components/widgets/conversation/ReplyBox.vue index b9c9688fd..e06cdb239 100644 --- a/app/javascript/dashboard/components/widgets/conversation/ReplyBox.vue +++ b/app/javascript/dashboard/components/widgets/conversation/ReplyBox.vue @@ -76,7 +76,6 @@ import { mapGetters } from 'vuex'; import { mixin as clickaway } from 'vue-clickaway'; import alertMixin from 'shared/mixins/alertMixin'; -import eventListenerMixins from 'shared/mixins/eventListenerMixins'; import EmojiInput from 'shared/components/emoji/EmojiInput'; import CannedResponse from './CannedResponse'; @@ -108,13 +107,7 @@ export default { ReplyBottomPanel, WootMessageEditor, }, - mixins: [ - clickaway, - inboxMixin, - uiSettingsMixin, - alertMixin, - eventListenerMixins, - ], + mixins: [clickaway, inboxMixin, uiSettingsMixin, alertMixin], props: { selectedTweet: { type: [Object, String], @@ -304,6 +297,15 @@ export default { } }, }, + + mounted() { + // Donot use the keyboard listener mixin here as the events here are supposed to be + // working even if input/textarea is focussed. + document.addEventListener('keydown', this.handleKeyEvents); + }, + destroyed() { + document.removeEventListener('keydown', this.handleKeyEvents); + }, methods: { toggleUserMention(currentMentionState) { this.hasUserMention = currentMentionState; diff --git a/app/javascript/sdk/sdk.js b/app/javascript/sdk/sdk.js index 324b5a835..ebdbdf1ca 100644 --- a/app/javascript/sdk/sdk.js +++ b/app/javascript/sdk/sdk.js @@ -99,6 +99,7 @@ export const SDK_CSS = `.woot-widget-holder { .woot--close::before, .woot--close::after { background-color: #fff; content: ' '; + display: inline; height: 24px; left: 32px; position: absolute; @@ -149,7 +150,7 @@ export const SDK_CSS = `.woot-widget-holder { max-height: 100vh; padding: 0 8px; } - + .woot-widget-holder.has-unread-view iframe { min-height: unset !important; } @@ -157,7 +158,7 @@ export const SDK_CSS = `.woot-widget-holder { .woot-widget-holder.has-unread-view.woot-elements--left { left: 0; } - + .woot-widget-bubble.woot--close { bottom: 60px; opacity: 0; diff --git a/app/javascript/shared/mixins/eventListenerMixins.js b/app/javascript/shared/mixins/eventListenerMixins.js index aad6952b3..0a426c2aa 100644 --- a/app/javascript/shared/mixins/eventListenerMixins.js +++ b/app/javascript/shared/mixins/eventListenerMixins.js @@ -1,8 +1,28 @@ +import { isEscape } from '../helpers/KeyboardHelpers'; + export default { mounted() { - document.addEventListener('keydown', this.handleKeyEvents); + document.addEventListener('keydown', this.onKeyDownHandler); }, - destroyed() { - document.removeEventListener('keydown', this.handleKeyEvents); + beforeDestroy() { + document.removeEventListener('keydown', this.onKeyDownHandler); + }, + methods: { + onKeyDownHandler(e) { + const isEventFromAnInputBox = + e.target?.tagName === 'INPUT' || e.target?.tagName === 'TEXTAREA'; + const isEventFromProseMirror = e.target?.className?.includes( + 'ProseMirror' + ); + + if (isEventFromAnInputBox || isEventFromProseMirror) { + if (isEscape(e)) { + e.target.blur(); + } + return; + } + + this.handleKeyEvents(e); + }, }, };