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:
parent
384bc28ccd
commit
67f8879551
@ -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,
|
||||||
|
@ -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}`;
|
||||||
|
@ -131,6 +131,7 @@ export default {
|
|||||||
DropdownWithActions,
|
DropdownWithActions,
|
||||||
},
|
},
|
||||||
emits: ['close'],
|
emits: ['close'],
|
||||||
|
inject: ['shortcuts'],
|
||||||
provide() {
|
provide() {
|
||||||
return {
|
return {
|
||||||
schemaName: this.schemaName,
|
schemaName: this.schemaName,
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user