2
0
mirror of https://github.com/frappe/books.git synced 2024-11-13 00:46:28 +00:00

incr: add mods to shortcut class

This commit is contained in:
18alantom 2023-01-20 16:31:09 +05:30
parent 384bc28ccd
commit 67f8879551
4 changed files with 98 additions and 31 deletions

View File

@ -55,7 +55,7 @@ import { checkForUpdates } from './utils/ipcCalls';
import { updateConfigFiles } from './utils/misc'; import { updateConfigFiles } from './utils/misc';
import { Search } from './utils/search'; import { Search } from './utils/search';
import { routeTo, systemLanguage } from './utils/ui'; import { routeTo, systemLanguage } from './utils/ui';
import { Shortcuts, useKeys } from './utils/vueUtils'; import { getModKeyCode, Shortcuts, useKeys } from './utils/vueUtils';
export default { export default {
name: 'App', name: 'App',
@ -69,6 +69,7 @@ export default {
companyName: '', companyName: '',
searcher: null, searcher: null,
shortcuts: null, shortcuts: null,
modKey: '',
}; };
}, },
provide() { provide() {
@ -76,6 +77,7 @@ export default {
languageDirection: computed(() => this.languageDirection), languageDirection: computed(() => this.languageDirection),
searcher: computed(() => this.searcher), searcher: computed(() => this.searcher),
shortcuts: computed(() => this.shortcuts), shortcuts: computed(() => this.shortcuts),
modKey: computed(() => this.modKey),
keys: computed(() => this.keys), keys: computed(() => this.keys),
}; };
}, },
@ -86,6 +88,7 @@ export default {
WindowsTitleBar, WindowsTitleBar,
}, },
async mounted() { async mounted() {
this.modKey = getModKeyCode(this.platform);
this.shortcuts = new Shortcuts(this.keys); this.shortcuts = new Shortcuts(this.keys);
const lastSelectedFilePath = fyo.config.get( const lastSelectedFilePath = fyo.config.get(
ConfigKeys.LastSelectedFilePath, ConfigKeys.LastSelectedFilePath,

View File

@ -5,7 +5,7 @@
<feather-icon name="search" class="w-4 h-4 me-1 text-gray-800" /> <feather-icon name="search" class="w-4 h-4 me-1 text-gray-800" />
<p>{{ t`Search` }}</p> <p>{{ t`Search` }}</p>
<div class="text-gray-500 px-1 ms-4 text-sm"> <div class="text-gray-500 px-1 ms-4 text-sm">
{{ modKey('k') }} {{ modKeyText('k') }}
</div> </div>
</Button> </Button>
</div> </div>
@ -195,7 +195,6 @@ import { getBgTextColorClass } from 'src/utils/colors';
import { openLink } from 'src/utils/ipcCalls'; import { openLink } from 'src/utils/ipcCalls';
import { docsPathMap } from 'src/utils/misc'; import { docsPathMap } from 'src/utils/misc';
import { getGroupLabelMap, searchGroups } from 'src/utils/search'; import { getGroupLabelMap, searchGroups } from 'src/utils/search';
import { getModKeyCode } from 'src/utils/vueUtils';
import { nextTick } from 'vue'; import { nextTick } from 'vue';
import Button from './Button.vue'; import Button from './Button.vue';
import Modal from './Modal.vue'; import Modal from './Modal.vue';
@ -212,7 +211,7 @@ export default {
allowedLimits: [50, 100, 500, -1], allowedLimits: [50, 100, 500, -1],
}; };
}, },
inject: ['searcher', 'shortcuts'], inject: ['searcher', 'shortcuts', 'modKey'],
components: { Modal, Button }, components: { Modal, Button },
async mounted() { async mounted() {
if (fyo.store.isDevelopment) { if (fyo.store.isDevelopment) {
@ -233,18 +232,20 @@ export default {
openLink('https://docs.frappebooks.com/' + docsPathMap.Search); openLink('https://docs.frappebooks.com/' + docsPathMap.Search);
}, },
getShortcuts() { getShortcuts() {
const modKey = getModKeyCode(this.platform);
const ifOpen = (cb) => () => this.openModal && cb(); const ifOpen = (cb) => () => this.openModal && cb();
const ifClose = (cb) => () => !this.openModal && cb(); const ifClose = (cb) => () => !this.openModal && cb();
const shortcuts = [ const shortcuts = [
{ shortcut: ['KeyK', modKey], callback: ifClose(() => this.open()) }, {
shortcut: ['KeyK', this.modKey],
callback: ifClose(() => this.open()),
},
{ shortcut: ['Escape'], callback: ifOpen(() => this.close()) }, { shortcut: ['Escape'], callback: ifOpen(() => this.close()) },
]; ];
for (const i in searchGroups) { for (const i in searchGroups) {
shortcuts.push({ shortcuts.push({
shortcut: [modKey, `Digit${Number(i) + 1}`], shortcut: [this.modKey, `Digit${Number(i) + 1}`],
callback: ifOpen(() => { callback: ifOpen(() => {
const group = searchGroups[i]; const group = searchGroups[i];
const value = this.searcher.filters.groupFilters[group]; const value = this.searcher.filters.groupFilters[group];
@ -261,15 +262,15 @@ export default {
}, },
setShortcuts() { setShortcuts() {
for (const { shortcut, callback } of this.getShortcuts()) { for (const { shortcut, callback } of this.getShortcuts()) {
this.shortcuts.set(shortcut, callback); this.shortcuts.meta.set(shortcut, callback);
} }
}, },
deleteShortcuts() { deleteShortcuts() {
for (const { shortcut } of this.getShortcuts()) { for (const { shortcut } of this.getShortcuts()) {
this.shortcuts.delete(shortcut); this.shortcuts.meta.delete(shortcut);
} }
}, },
modKey(key) { modKeyText(key) {
key = key.toUpperCase(); key = key.toUpperCase();
if (this.platform === 'Mac') { if (this.platform === 'Mac') {
return `${key}`; return `${key}`;

View File

@ -131,6 +131,7 @@ export default {
DropdownWithActions, DropdownWithActions,
}, },
emits: ['close'], emits: ['close'],
inject: ['shortcuts'],
provide() { provide() {
return { return {
schemaName: this.schemaName, schemaName: this.schemaName,

View File

@ -1,7 +1,6 @@
import { onMounted, onUnmounted, Ref, ref, watch } from 'vue'; import { onMounted, onUnmounted, reactive, ref, unref, watch } from 'vue';
interface Keys { interface ModMap {
pressed: Set<string>;
alt: boolean; alt: boolean;
ctrl: boolean; ctrl: boolean;
meta: boolean; meta: boolean;
@ -9,11 +8,23 @@ interface Keys {
repeat: boolean; repeat: boolean;
} }
export class Shortcuts { type Mod = keyof ModMap;
keys: Ref<Keys>;
shortcuts: Map<string, Function>;
constructor(keys?: Ref<Keys>) { interface Keys extends ModMap {
pressed: Set<string>;
}
type ShortcutFunction = () => void;
const mods: Readonly<Mod[]> = ['alt', 'ctrl', 'meta', 'repeat', 'shift'];
export class Shortcuts {
keys: Keys;
shortcuts: Map<string, ShortcutFunction>;
modMap: Partial<Record<Mod, boolean>>;
constructor(keys?: Keys) {
this.modMap = {};
this.keys = keys ?? useKeys(); this.keys = keys ?? useKeys();
this.shortcuts = new Map(); this.shortcuts = new Map();
@ -23,17 +34,22 @@ export class Shortcuts {
} }
#trigger(keys: Keys) { #trigger(keys: Keys) {
const key = Array.from(keys.pressed).sort().join('+'); const key = this.getKey(Array.from(keys.pressed), keys);
this.shortcuts.get(key)?.(); this.shortcuts.get(key)?.();
} }
has(shortcut: string[]) { has(shortcut: string[]) {
const key = shortcut.sort().join('+'); const key = this.getKey(shortcut);
return this.shortcuts.has(key); return this.shortcuts.has(key);
} }
set(shortcut: string[], callback: Function, removeIfSet: boolean = true) { set(
const key = shortcut.sort().join('+'); shortcut: string[],
callback: ShortcutFunction,
removeIfSet: boolean = true
) {
const key = this.getKey(shortcut);
if (removeIfSet) { if (removeIfSet) {
this.shortcuts.delete(key); this.shortcuts.delete(key);
} }
@ -46,13 +62,59 @@ export class Shortcuts {
} }
delete(shortcut: string[]) { delete(shortcut: string[]) {
const key = shortcut.sort().join('+'); const key = this.getKey(shortcut);
this.shortcuts.delete(key); this.shortcuts.delete(key);
} }
getKey(shortcut: string[], modMap?: Partial<ModMap>): string {
const _modMap = modMap || this.modMap;
this.modMap = {};
const shortcutString = shortcut.sort().join('+');
const modString = mods.filter((k) => _modMap[k]).join('+');
if (shortcutString && modString) {
return modString + '+' + shortcutString;
}
if (!modString) {
return shortcutString;
}
if (!shortcutString) {
return modString;
}
return '';
}
get alt() {
this.modMap['alt'] = true;
return this;
}
get ctrl() {
this.modMap['ctrl'] = true;
return this;
}
get meta() {
this.modMap['meta'] = true;
return this;
}
get shift() {
this.modMap['shift'] = true;
return this;
}
get repeat() {
this.modMap['repeat'] = true;
return this;
}
} }
export function useKeys() { export function useKeys() {
const keys: Ref<Keys> = ref({ const keys: Keys = reactive({
pressed: new Set<string>(), pressed: new Set<string>(),
alt: false, alt: false,
ctrl: false, ctrl: false,
@ -62,20 +124,20 @@ export function useKeys() {
}); });
const keydownListener = (e: KeyboardEvent) => { const keydownListener = (e: KeyboardEvent) => {
keys.value.pressed.add(e.code); keys.pressed.add(e.code);
keys.value.alt = e.altKey; keys.alt = e.altKey;
keys.value.ctrl = e.ctrlKey; keys.ctrl = e.ctrlKey;
keys.value.meta = e.metaKey; keys.meta = e.metaKey;
keys.value.shift = e.shiftKey; keys.shift = e.shiftKey;
keys.value.repeat = e.repeat; keys.repeat = e.repeat;
}; };
const keyupListener = (e: KeyboardEvent) => { const keyupListener = (e: KeyboardEvent) => {
keys.value.pressed.delete(e.code); keys.pressed.delete(e.code);
// Key up won't trigger on macOS for other keys. // Key up won't trigger on macOS for other keys.
if (e.code === 'MetaLeft') { if (e.code === 'MetaLeft') {
keys.value.pressed.clear(); keys.pressed.clear();
} }
}; };