diff --git a/packages/web/src/commands/CommandListener.svelte b/packages/web/src/commands/CommandListener.svelte index 8b311ef99..8b75bec91 100644 --- a/packages/web/src/commands/CommandListener.svelte +++ b/packages/web/src/commands/CommandListener.svelte @@ -1,8 +1,8 @@ - - + diff --git a/packages/web/src/commands/CommandPalette.svelte b/packages/web/src/commands/CommandPalette.svelte index 8589ba08a..e0ee22d85 100644 --- a/packages/web/src/commands/CommandPalette.svelte +++ b/packages/web/src/commands/CommandPalette.svelte @@ -31,7 +31,13 @@ $: selectedIndex = true ? 0 : filter; - onMount(() => domInput.focus()); + onMount(() => { + const oldFocus = document.activeElement; + domInput.focus(); + return () => { + if (oldFocus) oldFocus.focus(); + }; + }); $: sortedComands = _.sortBy( Object.values($commands).filter(x => x.enabled), diff --git a/packages/web/src/commands/registerCommand.ts b/packages/web/src/commands/registerCommand.ts index 7d3c99909..26547034c 100644 --- a/packages/web/src/commands/registerCommand.ts +++ b/packages/web/src/commands/registerCommand.ts @@ -20,6 +20,7 @@ export interface GlobalCommand { showDisabled?: boolean; toolbarName?: string; toolbarOrder?: number; + disableHandleKeyText?: string; } export default function registerCommand(command: GlobalCommand) { diff --git a/packages/web/src/query/AceEditor.svelte b/packages/web/src/query/AceEditor.svelte index 4b37d3c59..e02757136 100644 --- a/packages/web/src/query/AceEditor.svelte +++ b/packages/web/src/query/AceEditor.svelte @@ -15,6 +15,9 @@ import 'ace-builds/src-noconflict/theme-twilight'; import 'ace-builds/src-noconflict/ext-searchbox'; import 'ace-builds/src-noconflict/ext-language_tools'; + import { currentDropDownMenu } from '../stores'; + import _ from 'lodash'; + import { handleCommandKeyDown } from '../commands/CommandListener.svelte'; const EDITOR_ID = `svelte-ace-editor-div:${Math.floor(Math.random() * 10000000000)}`; const dispatch = createEventDispatcher<{ @@ -40,6 +43,7 @@ export let mode: string = 'text'; // String export let theme: string = 'github'; // String export let options: any = {}; // Object + export let menu; let editor: ace.Editor; let contentBackup: string = ''; @@ -54,13 +58,6 @@ const requireEditorPlugins = () => {}; requireEditorPlugins(); - onDestroy(() => { - if (editor) { - editor.destroy(); - editor.container.remove(); - } - }); - $: watchValue(value); function watchValue(val: string) { if (contentBackup !== val && editor && typeof val === 'string') { @@ -101,6 +98,17 @@ resizeOnNextTick(); } + const handleContextMenu = e => { + e.preventDefault(); + const left = e.pageX; + const top = e.pageY; + currentDropDownMenu.set({ left, top, items: _.isFunction(menu) ? menu() : menu }); + }; + + const handleKeyDown = (data, hash, keyString, keyCode, event) => { + handleCommandKeyDown(event); + }; + onMount(() => { editor = ace.edit(EDITOR_ID); @@ -115,6 +123,18 @@ if (options) { editor.setOptions(options); } + + editor.container.addEventListener('contextmenu', handleContextMenu); + editor.keyBinding.addKeyboardHandler(handleKeyDown); + }); + + onDestroy(() => { + if (editor) { + editor.container.removeEventListener('contextmenu', handleContextMenu); + editor.keyBinding.removeKeyboardHandler(handleKeyDown); + editor.destroy(); + editor.container.remove(); + } }); function setEventCallBacks() { diff --git a/packages/web/src/tabs/QueryTab.svelte b/packages/web/src/tabs/QueryTab.svelte index a4c53912a..a0fd3aa2e 100644 --- a/packages/web/src/tabs/QueryTab.svelte +++ b/packages/web/src/tabs/QueryTab.svelte @@ -30,11 +30,28 @@ ), onClick: () => get(currentQuery).kill(), }); + registerCommand({ + id: 'query.toggleComment', + category: 'Query', + name: 'Toggle comment', + keyText: 'Ctrl+/', + disableHandleKeyText: 'Ctrl+/', + enabledStore: derived(currentQuery, query => query != null), + onClick: () => get(currentQuery).toggleComment(), + }); + registerCommand({ + id: 'query.formatCode', + category: 'Query', + name: 'Format code', + enabledStore: derived(currentQuery, query => query != null), + onClick: () => get(currentQuery).formatCode(), + }); @@ -170,6 +201,7 @@ setEditorData(e.detail)} on:focus={() => lastFocusedQuery.set(instance)} bind:this={domEditor} diff --git a/packages/web/src/widgets/TabsPanel.svelte b/packages/web/src/widgets/TabsPanel.svelte index 705b02bd2..d43e40cf0 100644 --- a/packages/web/src/widgets/TabsPanel.svelte +++ b/packages/web/src/widgets/TabsPanel.svelte @@ -17,10 +17,24 @@ if (key.startsWith('archive://')) return 'icon archive'; return 'icon file'; } + + registerCommand({ + id: 'tabs.nextTab', + category: 'Tabs', + name: 'Next tab', + keyText: 'Ctrl+Tab', + enabledStore: derived(openedTabs, tabs => tabs.filter(x => !x.closedTime).length >= 2), + onClick: () => { + const tabs = get(openedTabs).filter(x => x.closedTime == null); + if (tabs.length >= 2) setSelectedTab(tabs[tabs.length - 2].tabid); + }, + });