import type { Modifier } from 'obsidian' import { MarkdownView, Modal } from 'obsidian' import { mount, unmount } from 'svelte' import { Action, eventBus, EventNames, isInputComposition } from '../globals' import type LocatorPlugin from '../main' import ModalVault from './ModalVault.svelte' abstract class LocatorModal extends Modal { protected constructor(plugin: LocatorPlugin) { super(plugin.app) const settings = plugin.settings // Remove all the default modal's children // so that we can more easily customize it // const closeEl = this.containerEl.find('.modal-close-button') this.modalEl.replaceChildren() // this.modalEl.append(closeEl) this.modalEl.addClass('locator-modal', 'prompt') this.modalEl.removeClass('modal') this.modalEl.tabIndex = -1 // Setup events that can be listened through the event bus // #region Up/Down navigation this.scope.register([], 'ArrowDown', e => { e.preventDefault() eventBus.emit(Action.ArrowDown) }) this.scope.register([], 'ArrowUp', e => { e.preventDefault() eventBus.emit(Action.ArrowUp) }) // Ctrl+j/k for (const key of [ { k: 'J', dir: 'down' }, { k: 'K', dir: 'up' }, ] as const) { for (const modifier of ['Ctrl', 'Mod'] as const) { this.scope.register([modifier], key.k, _e => { if (settings.vimLikeNavigationShortcut) { // e.preventDefault() eventBus.emit('arrow-' + key.dir) } }) } } // Ctrl+n/p for (const key of [ { k: 'N', dir: 'down' }, { k: 'P', dir: 'up' }, ] as const) { for (const modifier of ['Ctrl', 'Mod'] as const) { this.scope.register([modifier], key.k, _e => { if (settings.vimLikeNavigationShortcut) { // e.preventDefault() eventBus.emit('arrow-' + key.dir) } }) } } // #endregion Up/Down navigation let openInCurrentPaneKey: Modifier[] let openInNewPaneKey: Modifier[] let createInCurrentPaneKey: Modifier[] let createInNewPaneKey: Modifier[] let openInNewLeafKey: Modifier[] = ['Mod', 'Alt'] if (settings.openInNewPane) { openInCurrentPaneKey = ['Mod'] openInNewPaneKey = [] createInCurrentPaneKey = ['Mod', 'Shift'] createInNewPaneKey = ['Shift'] } else { openInCurrentPaneKey = [] openInNewPaneKey = ['Mod'] createInCurrentPaneKey = ['Shift'] createInNewPaneKey = ['Mod', 'Shift'] } // Open in new pane this.scope.register(openInNewPaneKey, 'Enter', e => { e.preventDefault() eventBus.emit(Action.OpenInNewPane) }) // Open in a new leaf this.scope.register(openInNewLeafKey, 'Enter', e => { e.preventDefault() eventBus.emit(Action.OpenInNewLeaf) }) // Insert link this.scope.register(['Alt'], 'Enter', e => { e.preventDefault() eventBus.emit(Action.InsertLink) }) // Create a new note this.scope.register(createInCurrentPaneKey, 'Enter', e => { e.preventDefault() eventBus.emit(Action.CreateNote) }) this.scope.register(createInNewPaneKey, 'Enter', e => { e.preventDefault() eventBus.emit(Action.CreateNote, { newLeaf: true }) }) // Open in current pane this.scope.register(openInCurrentPaneKey, 'Enter', e => { if (!isInputComposition()) { // Check if the user is still typing e.preventDefault() eventBus.emit(Action.Enter) } }) // Open in background this.scope.register(['Mod'], 'O', e => { if (!isInputComposition()) { // Check if the user is still typing e.preventDefault() eventBus.emit(Action.OpenInBackground) } }) this.scope.register([], 'Tab', e => { e.preventDefault() eventBus.emit(Action.Tab) // Switch context }) // Search history this.scope.register(['Alt'], 'ArrowDown', e => { e.preventDefault() eventBus.emit(Action.NextSearchHistory) }) this.scope.register(['Alt'], 'ArrowUp', e => { e.preventDefault() eventBus.emit(Action.PrevSearchHistory) }) // Context this.scope.register(['Mod'], 'G', _e => { eventBus.emit(EventNames.ToggleExcerpts) }) } } export class LocatorVaultModal extends LocatorModal { /** * Instanciate the Locator vault modal * @param plugin * @param query The query to pre-fill the search field with */ constructor(plugin: LocatorPlugin, query?: string) { super(plugin) // Selected text in the editor const selectedText = plugin.app.workspace .getActiveViewOfType(MarkdownView) ?.editor.getSelection() plugin.searchHistory.getHistory().then(history => { // Previously searched query const previous = history[0] // Instantiate and display the Svelte component const cmp = mount(ModalVault, { target: this.modalEl, props: { plugin, modal: this, previousQuery: query || selectedText || previous || '', }, }) this.onClose = () => { // Since the component is manually created, // we also need to manually destroy it unmount(cmp) } }) } }