mirror of
https://github.com/frappe/books.git
synced 2024-12-22 19:09:01 +00:00
refactor: use App level shortcut
This commit is contained in:
parent
0bc22d847b
commit
a140e82321
@ -52,20 +52,27 @@ import { checkForUpdates } from './utils/ipcCalls';
|
||||
import { updateConfigFiles } from './utils/misc';
|
||||
import { Search } from './utils/search';
|
||||
import { routeTo } from './utils/ui';
|
||||
import { Shortcuts, useKeys } from './utils/vueUtils';
|
||||
|
||||
export default {
|
||||
name: 'App',
|
||||
setup() {
|
||||
return { keys: useKeys() };
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
activeScreen: null,
|
||||
dbPath: '',
|
||||
companyName: '',
|
||||
searcher: null,
|
||||
shortcuts: null,
|
||||
};
|
||||
},
|
||||
provide() {
|
||||
return {
|
||||
searcher: computed(() => this.searcher),
|
||||
shortcuts: computed(() => this.shortcuts),
|
||||
keys: computed(() => this.keys),
|
||||
};
|
||||
},
|
||||
components: {
|
||||
@ -75,6 +82,7 @@ export default {
|
||||
WindowsTitleBar,
|
||||
},
|
||||
async mounted() {
|
||||
this.shortcuts = new Shortcuts(this.keys);
|
||||
const lastSelectedFilePath = fyo.config.get(
|
||||
ConfigKeys.LastSelectedFilePath,
|
||||
null
|
||||
|
@ -11,7 +11,11 @@
|
||||
</div>
|
||||
|
||||
<!-- Search Modal -->
|
||||
<Modal :open-modal="openModal" @closemodal="close" :set-close-listener="false">
|
||||
<Modal
|
||||
:open-modal="openModal"
|
||||
@closemodal="close"
|
||||
:set-close-listener="false"
|
||||
>
|
||||
<!-- Search Input -->
|
||||
<div class="p-1">
|
||||
<input
|
||||
@ -191,18 +195,13 @@ import { getBgTextColorClass } from 'src/utils/colors';
|
||||
import { openLink } from 'src/utils/ipcCalls';
|
||||
import { docsPathMap } from 'src/utils/misc';
|
||||
import { getGroupLabelMap, searchGroups } from 'src/utils/search';
|
||||
import { useKeys } from 'src/utils/vueUtils';
|
||||
import { getIsNullOrUndef } from 'utils/';
|
||||
import { getModKeyCode } from 'src/utils/vueUtils';
|
||||
import { safeParseInt } from 'utils/index';
|
||||
import { nextTick, watch } from 'vue';
|
||||
import Button from './Button.vue';
|
||||
import Modal from './Modal.vue';
|
||||
|
||||
export default {
|
||||
setup() {
|
||||
const keys = useKeys();
|
||||
return { keys };
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
idx: 0,
|
||||
@ -214,69 +213,62 @@ export default {
|
||||
allowedLimits: [50, 100, 500, -1],
|
||||
};
|
||||
},
|
||||
inject: ['searcher'],
|
||||
inject: ['searcher', 'shortcuts'],
|
||||
components: { Modal, Button },
|
||||
async mounted() {
|
||||
if (fyo.store.isDevelopment) {
|
||||
window.search = this;
|
||||
}
|
||||
|
||||
watch(this.keys, (keys) => {
|
||||
if (
|
||||
keys.size === 2 &&
|
||||
keys.has('KeyK') &&
|
||||
(keys.has('MetaLeft') || keys.has('ControlLeft'))
|
||||
) {
|
||||
this.open();
|
||||
}
|
||||
|
||||
if (!this.openModal) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (keys.size === 1 && keys.has('Escape')) {
|
||||
this.close();
|
||||
}
|
||||
|
||||
const input = this.$refs.input;
|
||||
if (!getIsNullOrUndef(input) && document.activeElement !== input) {
|
||||
input.focus();
|
||||
}
|
||||
|
||||
this.setFilter(keys);
|
||||
});
|
||||
this.openModal = false;
|
||||
},
|
||||
activated() {
|
||||
this.setShortcuts();
|
||||
this.openModal = false;
|
||||
},
|
||||
deactivated() {
|
||||
this.deleteShortcuts();
|
||||
},
|
||||
methods: {
|
||||
openDocs() {
|
||||
openLink('https://docs.frappebooks.com/' + docsPathMap.Search);
|
||||
},
|
||||
setFilter(keys) {
|
||||
if (!keys.has('MetaLeft') && !keys.has('ControlLeft')) {
|
||||
return;
|
||||
getShortcuts() {
|
||||
const modKey = getModKeyCode(this.platform);
|
||||
const ifOpen = (cb) => () => this.openModal && cb();
|
||||
const ifClose = (cb) => () => !this.openModal && cb();
|
||||
|
||||
const shortcuts = [
|
||||
{ shortcut: ['KeyK', modKey], callback: ifClose(() => this.open()) },
|
||||
{ shortcut: ['Escape'], callback: ifOpen(() => this.close()) },
|
||||
];
|
||||
|
||||
for (const i in searchGroups) {
|
||||
shortcuts.push({
|
||||
shortcut: [modKey, `Digit${Number(i) + 1}`],
|
||||
callback: ifOpen(() => {
|
||||
const group = searchGroups[i];
|
||||
const value = this.searcher.filters.groupFilters[group];
|
||||
if (typeof value !== 'boolean') {
|
||||
return;
|
||||
}
|
||||
|
||||
this.searcher.set(group, !value);
|
||||
}),
|
||||
});
|
||||
}
|
||||
|
||||
if (!keys.size === 2) {
|
||||
return;
|
||||
return shortcuts;
|
||||
},
|
||||
setShortcuts() {
|
||||
for (const { shortcut, callback } of this.getShortcuts()) {
|
||||
this.shortcuts.set(shortcut, callback);
|
||||
}
|
||||
|
||||
const matches = [...keys].join(',').match(/Digit(\d+)/);
|
||||
if (!matches) {
|
||||
return;
|
||||
},
|
||||
deleteShortcuts() {
|
||||
for (const { shortcut } of this.getShortcuts()) {
|
||||
this.shortcuts.delete(shortcut);
|
||||
}
|
||||
|
||||
const digit = matches[1];
|
||||
const index = safeParseInt(digit) - 1;
|
||||
const group = searchGroups[index];
|
||||
const value = this.searcher.filters.groupFilters[group];
|
||||
if (!group || typeof value !== 'boolean') {
|
||||
return;
|
||||
}
|
||||
|
||||
this.searcher.set(group, !value);
|
||||
},
|
||||
modKey(key) {
|
||||
key = key.toUpperCase();
|
||||
|
2
src/shims-vue-custom.d.ts
vendored
2
src/shims-vue-custom.d.ts
vendored
@ -5,6 +5,6 @@ declare module 'vue' {
|
||||
interface ComponentCustomProperties {
|
||||
t: (...args: TranslationLiteral[]) => string;
|
||||
fyo: Fyo;
|
||||
platform: string;
|
||||
platform: 'Windows' | 'Linux' | 'Mac';
|
||||
}
|
||||
}
|
||||
|
@ -1,19 +1,81 @@
|
||||
import { onMounted, onUnmounted, Ref, ref } from 'vue';
|
||||
import { onMounted, onUnmounted, Ref, ref, watch } from 'vue';
|
||||
|
||||
export function useKeys(callback?: (keys: Set<string>) => void) {
|
||||
const keys: Ref<Set<string>> = ref(new Set());
|
||||
interface Keys {
|
||||
pressed: Set<string>;
|
||||
alt: boolean;
|
||||
ctrl: boolean;
|
||||
meta: boolean;
|
||||
shift: boolean;
|
||||
repeat: boolean;
|
||||
}
|
||||
|
||||
export class Shortcuts {
|
||||
keys: Ref<Keys>;
|
||||
shortcuts: Map<string, Function>;
|
||||
|
||||
constructor(keys?: Ref<Keys>) {
|
||||
this.keys = keys ?? useKeys();
|
||||
this.shortcuts = new Map();
|
||||
|
||||
watch(this.keys, (keys) => {
|
||||
this.#trigger(keys);
|
||||
});
|
||||
}
|
||||
|
||||
#trigger(keys: Keys) {
|
||||
const key = Array.from(keys.pressed).sort().join('+');
|
||||
this.shortcuts.get(key)?.();
|
||||
}
|
||||
|
||||
has(shortcut: string[]) {
|
||||
const key = shortcut.sort().join('+');
|
||||
return this.shortcuts.has(key);
|
||||
}
|
||||
|
||||
set(shortcut: string[], callback: Function, removeIfSet: boolean = true) {
|
||||
const key = shortcut.sort().join('+');
|
||||
if (removeIfSet) {
|
||||
this.shortcuts.delete(key);
|
||||
}
|
||||
|
||||
if (this.shortcuts.has(key)) {
|
||||
throw new Error(`Shortcut ${key} already exists.`);
|
||||
}
|
||||
|
||||
this.shortcuts.set(key, callback);
|
||||
}
|
||||
|
||||
delete(shortcut: string[]) {
|
||||
const key = shortcut.sort().join('+');
|
||||
this.shortcuts.delete(key);
|
||||
}
|
||||
}
|
||||
|
||||
export function useKeys() {
|
||||
const keys: Ref<Keys> = ref({
|
||||
pressed: new Set<string>(),
|
||||
alt: false,
|
||||
ctrl: false,
|
||||
meta: false,
|
||||
shift: false,
|
||||
repeat: false,
|
||||
});
|
||||
|
||||
const keydownListener = (e: KeyboardEvent) => {
|
||||
keys.value.add(e.code);
|
||||
callback?.(keys.value);
|
||||
keys.value.pressed.add(e.code);
|
||||
keys.value.alt = e.altKey;
|
||||
keys.value.ctrl = e.ctrlKey;
|
||||
keys.value.meta = e.metaKey;
|
||||
keys.value.shift = e.shiftKey;
|
||||
keys.value.repeat = e.repeat;
|
||||
};
|
||||
|
||||
const keyupListener = (e: KeyboardEvent) => {
|
||||
keys.value.delete(e.code);
|
||||
keys.value.pressed.delete(e.code);
|
||||
|
||||
// Key up won't trigger on macOS for other keys.
|
||||
if (e.code === 'MetaLeft') {
|
||||
keys.value.clear();
|
||||
keys.value.pressed.clear();
|
||||
}
|
||||
};
|
||||
|
||||
@ -47,3 +109,11 @@ export function useMouseLocation() {
|
||||
|
||||
return loc;
|
||||
}
|
||||
|
||||
export function getModKeyCode(platform: 'Windows' | 'Linux' | 'Mac') {
|
||||
if (platform === 'Mac') {
|
||||
return 'MetaLeft';
|
||||
}
|
||||
|
||||
return 'CtrlLeft';
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user