feat: Adds keyboard shortcuts for conversation actions (#2672)
* feat: Adds keyboard shortcuts for conversation actions * Minor fixes * Minor fixes * Minor fixes and add new shortcut * MInor fixes * Review fixes * Minor fixes * Code cleanup * Minor fixes * Uses Alt or Option key instead of shift-key * Review fixes * Review fixes Co-authored-by: Pranav Raj S <pranav@chatwoot.com> Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
This commit is contained in:
parent
c7482696d4
commit
c523a953f7
15 changed files with 311 additions and 51 deletions
|
@ -19,7 +19,7 @@
|
|||
{{ $t('CHAT_LIST.LIST.404') }}
|
||||
</p>
|
||||
|
||||
<div class="conversations-list">
|
||||
<div ref="activeConversation" class="conversations-list">
|
||||
<conversation-card
|
||||
v-for="chat in conversationList"
|
||||
:key="chat.id"
|
||||
|
@ -62,8 +62,13 @@ import ChatFilter from './widgets/conversation/ChatFilter';
|
|||
import ChatTypeTabs from './widgets/ChatTypeTabs';
|
||||
import ConversationCard from './widgets/conversation/ConversationCard';
|
||||
import timeMixin from '../mixins/time';
|
||||
import eventListenerMixins from 'shared/mixins/eventListenerMixins';
|
||||
import conversationMixin from '../mixins/conversations';
|
||||
import wootConstants from '../constants';
|
||||
import {
|
||||
hasPressedAltAndJKey,
|
||||
hasPressedAltAndKKey,
|
||||
} from 'shared/helpers/KeyboardHelpers';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
|
@ -71,7 +76,7 @@ export default {
|
|||
ConversationCard,
|
||||
ChatFilter,
|
||||
},
|
||||
mixins: [timeMixin, conversationMixin],
|
||||
mixins: [timeMixin, conversationMixin, eventListenerMixins],
|
||||
props: {
|
||||
conversationInbox: {
|
||||
type: [String, Number],
|
||||
|
@ -94,6 +99,7 @@ export default {
|
|||
},
|
||||
computed: {
|
||||
...mapGetters({
|
||||
currentChat: 'getSelectedChat',
|
||||
chatLists: 'getAllConversations',
|
||||
mineChatsList: 'getMineChats',
|
||||
allChatList: 'getAllStatusChats',
|
||||
|
@ -188,6 +194,33 @@ export default {
|
|||
});
|
||||
},
|
||||
methods: {
|
||||
handleKeyEvents(e) {
|
||||
const allConversations = this.$refs.activeConversation.querySelectorAll(
|
||||
'div.conversations-list div.conversation'
|
||||
);
|
||||
const activeConversation = this.$refs.activeConversation.querySelector(
|
||||
'div.conversations-list div.conversation.active'
|
||||
);
|
||||
const activeConversationIndex = [...allConversations].indexOf(
|
||||
activeConversation
|
||||
);
|
||||
const lastConversationIndex = allConversations.length - 1;
|
||||
if (hasPressedAltAndJKey(e)) {
|
||||
if (activeConversationIndex === -1) {
|
||||
allConversations[0].click();
|
||||
}
|
||||
if (activeConversationIndex >= 1) {
|
||||
allConversations[activeConversationIndex - 1].click();
|
||||
}
|
||||
}
|
||||
if (hasPressedAltAndKKey(e)) {
|
||||
if (activeConversationIndex === -1) {
|
||||
allConversations[lastConversationIndex].click();
|
||||
} else if (activeConversationIndex < lastConversationIndex) {
|
||||
allConversations[activeConversationIndex + 1].click();
|
||||
}
|
||||
}
|
||||
},
|
||||
resetAndFetchData() {
|
||||
this.$store.dispatch('conversationPage/reset');
|
||||
this.$store.dispatch('emptyAllConversations');
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
</woot-button>
|
||||
<woot-button
|
||||
v-if="showAdditionalActions"
|
||||
ref="arrowDownButton"
|
||||
:color-scheme="buttonClass"
|
||||
:disabled="isLoading"
|
||||
icon="ion-arrow-down-b"
|
||||
|
@ -99,6 +100,12 @@
|
|||
import { mapGetters } from 'vuex';
|
||||
import { mixin as clickaway } from 'vue-clickaway';
|
||||
import alertMixin from 'shared/mixins/alertMixin';
|
||||
import eventListenerMixins from 'shared/mixins/eventListenerMixins';
|
||||
import {
|
||||
hasPressedAltAndEKey,
|
||||
hasPressedCommandPlusAltAndEKey,
|
||||
hasPressedAltAndMKey,
|
||||
} from 'shared/helpers/KeyboardHelpers';
|
||||
|
||||
import WootDropdownItem from 'shared/components/ui/dropdown/DropdownItem.vue';
|
||||
import WootDropdownSubMenu from 'shared/components/ui/dropdown/DropdownSubMenu.vue';
|
||||
|
@ -118,7 +125,7 @@ export default {
|
|||
WootDropdownMenu,
|
||||
WootDropdownSubMenu,
|
||||
},
|
||||
mixins: [clickaway, alertMixin],
|
||||
mixins: [clickaway, alertMixin, eventListenerMixins],
|
||||
props: { conversationId: { type: [String, Number], required: true } },
|
||||
data() {
|
||||
return {
|
||||
|
@ -164,6 +171,33 @@ export default {
|
|||
},
|
||||
},
|
||||
methods: {
|
||||
async handleKeyEvents(e) {
|
||||
const allConversations = document.querySelectorAll(
|
||||
'.conversations-list .conversation'
|
||||
);
|
||||
if (hasPressedAltAndEKey(e)) {
|
||||
const activeConversation = document.querySelector(
|
||||
'div.conversations-list div.conversation.active'
|
||||
);
|
||||
const activeConversationIndex = [...allConversations].indexOf(
|
||||
activeConversation
|
||||
);
|
||||
const lastConversationIndex = allConversations.length - 1;
|
||||
try {
|
||||
await this.toggleStatus(wootConstants.STATUS_TYPE.RESOLVED);
|
||||
} catch (error) {
|
||||
// error
|
||||
}
|
||||
if (hasPressedCommandPlusAltAndEKey(e)) {
|
||||
if (activeConversationIndex < lastConversationIndex) {
|
||||
allConversations[activeConversationIndex + 1].click();
|
||||
} else if (allConversations.length > 1) {
|
||||
allConversations[0].click();
|
||||
document.querySelector('.conversations-list').scrollTop = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
showOpenButton() {
|
||||
return this.isResolved || this.isSnoozed;
|
||||
},
|
||||
|
|
|
@ -59,10 +59,17 @@
|
|||
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],
|
||||
mixins: [adminMixin, eventListenerMixins],
|
||||
props: {
|
||||
menuItem: {
|
||||
type: Object,
|
||||
|
@ -117,6 +124,20 @@ 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;
|
||||
},
|
||||
|
|
|
@ -10,8 +10,11 @@
|
|||
</template>
|
||||
<script>
|
||||
import wootConstants from '../../constants';
|
||||
import eventListenerMixins from 'shared/mixins/eventListenerMixins';
|
||||
import { hasPressedAltAndNKey } from 'shared/helpers/KeyboardHelpers';
|
||||
|
||||
export default {
|
||||
mixins: [eventListenerMixins],
|
||||
props: {
|
||||
items: {
|
||||
type: Array,
|
||||
|
@ -28,6 +31,15 @@ export default {
|
|||
},
|
||||
},
|
||||
methods: {
|
||||
handleKeyEvents(e) {
|
||||
if (hasPressedAltAndNKey(e)) {
|
||||
if (this.activeTab === wootConstants.ASSIGNEE_TYPE.ALL) {
|
||||
this.onTabChange(0);
|
||||
} else {
|
||||
this.onTabChange(this.activeTabIndex + 1);
|
||||
}
|
||||
}
|
||||
},
|
||||
onTabChange(selectedTabIndex) {
|
||||
if (this.items[selectedTabIndex].key !== this.activeTab) {
|
||||
this.$emit('chatTabChange', this.items[selectedTabIndex].key);
|
||||
|
|
|
@ -78,11 +78,17 @@
|
|||
|
||||
<script>
|
||||
import FileUpload from 'vue-upload-component';
|
||||
import {
|
||||
hasPressedAltAndWKey,
|
||||
hasPressedAltAndAKey,
|
||||
} from 'shared/helpers/KeyboardHelpers';
|
||||
import eventListenerMixins from 'shared/mixins/eventListenerMixins';
|
||||
|
||||
import { REPLY_EDITOR_MODES } from './constants';
|
||||
export default {
|
||||
name: 'ReplyTopPanel',
|
||||
components: { FileUpload },
|
||||
mixins: [eventListenerMixins],
|
||||
props: {
|
||||
mode: {
|
||||
type: String,
|
||||
|
@ -156,6 +162,14 @@ export default {
|
|||
},
|
||||
},
|
||||
methods: {
|
||||
handleKeyEvents(e) {
|
||||
if (hasPressedAltAndWKey(e)) {
|
||||
this.toggleFormatMode();
|
||||
}
|
||||
if (hasPressedAltAndAKey(e)) {
|
||||
this.$refs.upload.$children[1].$el.click();
|
||||
}
|
||||
},
|
||||
toggleFormatMode() {
|
||||
this.setFormatMode(!this.isFormatMode);
|
||||
},
|
||||
|
|
|
@ -32,11 +32,17 @@
|
|||
<script>
|
||||
import { REPLY_EDITOR_MODES, CHAR_LENGTH_WARNING } from './constants';
|
||||
import EmojiOrIcon from 'shared/components/EmojiOrIcon';
|
||||
import {
|
||||
hasPressedAltAndPKey,
|
||||
hasPressedAltAndLKey,
|
||||
} from 'shared/helpers/KeyboardHelpers';
|
||||
import eventListenerMixins from 'shared/mixins/eventListenerMixins';
|
||||
export default {
|
||||
name: 'ReplyTopPanel',
|
||||
components: {
|
||||
EmojiOrIcon,
|
||||
},
|
||||
mixins: [eventListenerMixins],
|
||||
props: {
|
||||
mode: {
|
||||
type: String,
|
||||
|
@ -76,6 +82,14 @@ export default {
|
|||
},
|
||||
},
|
||||
methods: {
|
||||
handleKeyEvents(e) {
|
||||
if (hasPressedAltAndPKey(e)) {
|
||||
this.handleNoteClick();
|
||||
}
|
||||
if (hasPressedAltAndLKey(e)) {
|
||||
this.handleReplyClick();
|
||||
}
|
||||
},
|
||||
handleReplyClick() {
|
||||
this.setReplyMode(REPLY_EDITOR_MODES.REPLY);
|
||||
},
|
||||
|
|
|
@ -12,12 +12,29 @@
|
|||
|
||||
<script>
|
||||
import wootConstants from '../../../constants';
|
||||
import eventListenerMixins from 'shared/mixins/eventListenerMixins';
|
||||
import { hasPressedAltAndBKey } from 'shared/helpers/KeyboardHelpers';
|
||||
|
||||
export default {
|
||||
mixins: [eventListenerMixins],
|
||||
data: () => ({
|
||||
activeStatus: wootConstants.STATUS_TYPE.OPEN,
|
||||
}),
|
||||
methods: {
|
||||
handleKeyEvents(e) {
|
||||
if (hasPressedAltAndBKey(e)) {
|
||||
if (this.activeStatus === wootConstants.STATUS_TYPE.OPEN) {
|
||||
this.activeStatus = wootConstants.STATUS_TYPE.RESOLVED;
|
||||
} else if (this.activeStatus === wootConstants.STATUS_TYPE.RESOLVED) {
|
||||
this.activeStatus = wootConstants.STATUS_TYPE.PENDING;
|
||||
} else if (this.activeStatus === wootConstants.STATUS_TYPE.PENDING) {
|
||||
this.activeStatus = wootConstants.STATUS_TYPE.SNOOZED;
|
||||
} else if (this.activeStatus === wootConstants.STATUS_TYPE.SNOOZED) {
|
||||
this.activeStatus = wootConstants.STATUS_TYPE.OPEN;
|
||||
}
|
||||
}
|
||||
this.onTabChange();
|
||||
},
|
||||
onTabChange() {
|
||||
this.$store.dispatch('setChatFilter', this.activeStatus);
|
||||
this.$emit('statusFilterChange', this.activeStatus);
|
||||
|
|
|
@ -68,7 +68,9 @@ import { mapGetters } from 'vuex';
|
|||
import MoreActions from './MoreActions';
|
||||
import Thumbnail from '../Thumbnail';
|
||||
import agentMixin from '../../../mixins/agentMixin.js';
|
||||
import eventListenerMixins from 'shared/mixins/eventListenerMixins';
|
||||
import AvailabilityStatusBadge from '../conversation/AvailabilityStatusBadge';
|
||||
import { hasPressedAltAndOKey } from 'shared/helpers/KeyboardHelpers';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
|
@ -76,7 +78,7 @@ export default {
|
|||
Thumbnail,
|
||||
AvailabilityStatusBadge,
|
||||
},
|
||||
mixins: [agentMixin],
|
||||
mixins: [agentMixin, eventListenerMixins],
|
||||
props: {
|
||||
chat: {
|
||||
type: Object,
|
||||
|
@ -117,6 +119,11 @@ export default {
|
|||
},
|
||||
|
||||
methods: {
|
||||
handleKeyEvents(e) {
|
||||
if (hasPressedAltAndOKey(e)) {
|
||||
this.$emit('contact-panel-toggle');
|
||||
}
|
||||
},
|
||||
assignAgent(agent) {
|
||||
this.$store
|
||||
.dispatch('assignAgent', {
|
||||
|
|
|
@ -74,6 +74,7 @@
|
|||
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';
|
||||
|
@ -105,7 +106,13 @@ export default {
|
|||
ReplyBottomPanel,
|
||||
WootMessageEditor,
|
||||
},
|
||||
mixins: [clickaway, inboxMixin, uiSettingsMixin, alertMixin],
|
||||
mixins: [
|
||||
clickaway,
|
||||
inboxMixin,
|
||||
uiSettingsMixin,
|
||||
alertMixin,
|
||||
eventListenerMixins,
|
||||
],
|
||||
props: {
|
||||
selectedTweet: {
|
||||
type: [Object, String],
|
||||
|
@ -289,12 +296,6 @@ export default {
|
|||
}
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
document.addEventListener('keydown', this.handleKeyEvents);
|
||||
},
|
||||
destroyed() {
|
||||
document.removeEventListener('keydown', this.handleKeyEvents);
|
||||
},
|
||||
methods: {
|
||||
toggleUserMention(currentMentionState) {
|
||||
this.hasUserMention = currentMentionState;
|
||||
|
@ -353,6 +354,9 @@ export default {
|
|||
if (this.showRichContentEditor) {
|
||||
return;
|
||||
}
|
||||
if (this.$refs.messageInput === undefined) {
|
||||
return;
|
||||
}
|
||||
this.$nextTick(() => this.$refs.messageInput.focus());
|
||||
},
|
||||
emojiOnClick(emoji) {
|
||||
|
|
|
@ -9,7 +9,11 @@
|
|||
icon="ion-pricetags"
|
||||
emoji="🏷️"
|
||||
/>
|
||||
<div v-on-clickaway="closeDropdownLabel" class="label-wrap">
|
||||
<div
|
||||
v-on-clickaway="closeDropdownLabel"
|
||||
class="label-wrap"
|
||||
@keyup.esc="closeDropdownLabel"
|
||||
>
|
||||
<add-label @add="toggleLabels" />
|
||||
<woot-label
|
||||
v-for="label in activeLabels"
|
||||
|
|
|
@ -11,12 +11,7 @@
|
|||
/>
|
||||
</div>
|
||||
<div class="list-scroll-container">
|
||||
<div
|
||||
ref="multiselectDropdown"
|
||||
class="multiselect-dropdown--list"
|
||||
@keyup.up="onArrowUp"
|
||||
@keyup.down="onArrowDown"
|
||||
>
|
||||
<div class="multiselect-dropdown--list">
|
||||
<woot-dropdown-menu>
|
||||
<woot-dropdown-item
|
||||
v-for="option in filteredOptions"
|
||||
|
@ -119,38 +114,6 @@ export default {
|
|||
focusInput() {
|
||||
this.$refs.searchbar.focus();
|
||||
},
|
||||
onArrowUp() {
|
||||
const allDropdownItems = this.$refs.multiselectDropdown.querySelectorAll(
|
||||
'.dropdown .multiselect-dropdown--item'
|
||||
);
|
||||
const focusedElement = this.$refs.multiselectDropdown.querySelector(
|
||||
'.dropdown .multiselect-dropdown--item:focus'
|
||||
);
|
||||
const activeElementIndex = [...allDropdownItems].indexOf(focusedElement);
|
||||
const lastElementIndex = allDropdownItems.length - 1;
|
||||
|
||||
if (activeElementIndex >= 1) {
|
||||
allDropdownItems[activeElementIndex - 1].focus();
|
||||
} else {
|
||||
allDropdownItems[lastElementIndex].focus();
|
||||
}
|
||||
},
|
||||
onArrowDown() {
|
||||
const allDropdownItems = this.$refs.multiselectDropdown.querySelectorAll(
|
||||
'.dropdown .multiselect-dropdown--item'
|
||||
);
|
||||
const focusedElement = this.$refs.multiselectDropdown.querySelector(
|
||||
'.dropdown .multiselect-dropdown--item:focus'
|
||||
);
|
||||
const activeElementIndex = [...allDropdownItems].indexOf(focusedElement);
|
||||
const lastElementIndex = allDropdownItems.length - 1;
|
||||
|
||||
if (activeElementIndex === lastElementIndex) {
|
||||
allDropdownItems[0].focus();
|
||||
} else {
|
||||
allDropdownItems[activeElementIndex + 1].focus();
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
|
|
@ -42,6 +42,10 @@ export default {
|
|||
&:hover {
|
||||
background: var(--color-background);
|
||||
}
|
||||
|
||||
&:focus {
|
||||
background: var(--color-background);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
<template>
|
||||
<ul
|
||||
ref="dropdownMenu"
|
||||
class="dropdown menu vertical"
|
||||
:class="[placement && `dropdown--${placement}`]"
|
||||
>
|
||||
|
@ -7,15 +8,67 @@
|
|||
</ul>
|
||||
</template>
|
||||
<script>
|
||||
import eventListenerMixins from 'shared/mixins/eventListenerMixins';
|
||||
import {
|
||||
hasPressedArrowUpKey,
|
||||
hasPressedArrowDownKey,
|
||||
} from 'shared/helpers/KeyboardHelpers';
|
||||
export default {
|
||||
name: 'WootDropdownMenu',
|
||||
componentName: 'WootDropdownMenu',
|
||||
|
||||
mixins: [eventListenerMixins],
|
||||
|
||||
props: {
|
||||
placement: {
|
||||
type: String,
|
||||
default: 'top',
|
||||
},
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.focusItem();
|
||||
},
|
||||
methods: {
|
||||
focusItem() {
|
||||
this.$refs.dropdownMenu
|
||||
.querySelector('ul.dropdown li.dropdown-menu__item .button')
|
||||
.focus();
|
||||
},
|
||||
handleKeyEvents(e) {
|
||||
if (hasPressedArrowUpKey(e)) {
|
||||
const items = this.$refs.dropdownMenu.querySelectorAll(
|
||||
'ul.dropdown li.dropdown-menu__item .button'
|
||||
);
|
||||
const focusItems = this.$refs.dropdownMenu.querySelector(
|
||||
'ul.dropdown li.dropdown-menu__item .button:focus'
|
||||
);
|
||||
const activeElementIndex = [...items].indexOf(focusItems);
|
||||
const lastElementIndex = items.length - 1;
|
||||
|
||||
if (activeElementIndex >= 1) {
|
||||
items[activeElementIndex - 1].focus();
|
||||
} else {
|
||||
items[lastElementIndex].focus();
|
||||
}
|
||||
}
|
||||
if (hasPressedArrowDownKey(e)) {
|
||||
const items = this.$refs.dropdownMenu.querySelectorAll(
|
||||
'li.dropdown-menu__item .button'
|
||||
);
|
||||
const focusItems = this.$refs.dropdownMenu.querySelector(
|
||||
'li.dropdown-menu__item .button:focus'
|
||||
);
|
||||
const activeElementIndex = [...items].indexOf(focusItems);
|
||||
const lastElementIndex = items.length - 1;
|
||||
|
||||
if (activeElementIndex === lastElementIndex) {
|
||||
items[0].focus();
|
||||
} else {
|
||||
items[activeElementIndex + 1].focus();
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
|
|
@ -9,3 +9,75 @@ export const isEscape = e => {
|
|||
export const hasPressedShift = e => {
|
||||
return e.shiftKey;
|
||||
};
|
||||
|
||||
export const hasPressedAltAndCKey = e => {
|
||||
return e.altKey && e.keyCode === 67;
|
||||
};
|
||||
|
||||
export const hasPressedAltAndVKey = e => {
|
||||
return e.altKey && e.keyCode === 86;
|
||||
};
|
||||
|
||||
export const hasPressedAltAndRKey = e => {
|
||||
return e.altKey && e.keyCode === 82;
|
||||
};
|
||||
|
||||
export const hasPressedAltAndSKey = e => {
|
||||
return e.altKey && e.keyCode === 83;
|
||||
};
|
||||
|
||||
export const hasPressedAltAndBKey = e => {
|
||||
return e.altKey && e.keyCode === 66;
|
||||
};
|
||||
|
||||
export const hasPressedAltAndNKey = e => {
|
||||
return e.altKey && e.keyCode === 78;
|
||||
};
|
||||
|
||||
export const hasPressedAltAndWKey = e => {
|
||||
return e.altKey && e.keyCode === 87;
|
||||
};
|
||||
|
||||
export const hasPressedAltAndAKey = e => {
|
||||
return e.altKey && e.keyCode === 65;
|
||||
};
|
||||
|
||||
export const hasPressedAltAndPKey = e => {
|
||||
return e.altKey && e.keyCode === 80;
|
||||
};
|
||||
|
||||
export const hasPressedAltAndLKey = e => {
|
||||
return e.altKey && e.keyCode === 76;
|
||||
};
|
||||
|
||||
export const hasPressedAltAndEKey = e => {
|
||||
return e.altKey && e.keyCode === 69;
|
||||
};
|
||||
|
||||
export const hasPressedCommandPlusAltAndEKey = e => {
|
||||
return e.metaKey && e.altKey && e.keyCode === 69;
|
||||
};
|
||||
|
||||
export const hasPressedAltAndOKey = e => {
|
||||
return e.altKey && e.keyCode === 79;
|
||||
};
|
||||
|
||||
export const hasPressedAltAndJKey = e => {
|
||||
return e.altKey && e.keyCode === 74;
|
||||
};
|
||||
|
||||
export const hasPressedAltAndKKey = e => {
|
||||
return e.altKey && e.keyCode === 75;
|
||||
};
|
||||
|
||||
export const hasPressedAltAndMKey = e => {
|
||||
return e.altKey && e.keyCode === 77;
|
||||
};
|
||||
|
||||
export const hasPressedArrowUpKey = e => {
|
||||
return e.keyCode === 38;
|
||||
};
|
||||
|
||||
export const hasPressedArrowDownKey = e => {
|
||||
return e.keyCode === 40;
|
||||
};
|
||||
|
|
8
app/javascript/shared/mixins/eventListenerMixins.js
Normal file
8
app/javascript/shared/mixins/eventListenerMixins.js
Normal file
|
@ -0,0 +1,8 @@
|
|||
export default {
|
||||
mounted() {
|
||||
document.addEventListener('keydown', this.handleKeyEvents);
|
||||
},
|
||||
destroyed() {
|
||||
document.removeEventListener('keydown', this.handleKeyEvents);
|
||||
},
|
||||
};
|
Loading…
Add table
Add a link
Reference in a new issue