Refactored events to use a small global event bus
This commit is contained in:
@@ -17,43 +17,12 @@ onMount(async () => {
|
||||
const debouncedOnInput = debounce(() => {
|
||||
dispatch("input", value)
|
||||
}, 100)
|
||||
|
||||
function moveNoteSelection(ev: KeyboardEvent): void {
|
||||
switch (ev.key) {
|
||||
case "ArrowDown":
|
||||
ev.preventDefault()
|
||||
dispatch("arrow-down")
|
||||
break
|
||||
case "ArrowUp":
|
||||
ev.preventDefault()
|
||||
dispatch("arrow-up")
|
||||
break
|
||||
|
||||
case "Enter":
|
||||
ev.preventDefault()
|
||||
if (ev.ctrlKey || ev.metaKey) {
|
||||
// Open in a new pane
|
||||
dispatch("ctrl-enter")
|
||||
} else if (ev.shiftKey) {
|
||||
// Create a new note
|
||||
dispatch("shift-enter")
|
||||
} else if (ev.altKey) {
|
||||
// Expand in-note results
|
||||
dispatch("alt-enter")
|
||||
} else {
|
||||
// Open in current pane
|
||||
dispatch("enter")
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<input
|
||||
bind:value
|
||||
bind:this={elInput}
|
||||
on:input={debouncedOnInput}
|
||||
on:keydown={moveNoteSelection}
|
||||
type="text"
|
||||
class="prompt-input"
|
||||
placeholder="Type to search through your notes"
|
||||
|
||||
@@ -5,9 +5,14 @@ let lastSearch = ""
|
||||
<script lang="ts">
|
||||
import CmpInput from "./CmpInput.svelte"
|
||||
import CmpResultInFile from "./CmpResultInFile.svelte"
|
||||
import { excerptAfter, type ResultNote, type SearchMatch } from "./globals"
|
||||
import {
|
||||
eventBus,
|
||||
excerptAfter,
|
||||
type ResultNote,
|
||||
type SearchMatch,
|
||||
} from "./globals"
|
||||
import { loopIndex } from "./utils"
|
||||
import { onMount, tick } from "svelte"
|
||||
import { onDestroy, onMount, tick } from "svelte"
|
||||
import { MarkdownView } from "obsidian"
|
||||
import { getSuggestions } from "./search"
|
||||
import type { ModalInFile, ModalVault } from "./modal"
|
||||
@@ -23,6 +28,14 @@ let note: ResultNote | null = null
|
||||
|
||||
onMount(() => {
|
||||
searchQuery = lastSearch
|
||||
eventBus.disable("vault")
|
||||
eventBus.on("infile", "enter", openSelection)
|
||||
eventBus.on("infile", "arrow-up", () => moveIndex(-1))
|
||||
eventBus.on("infile", "arrow-down", () => moveIndex(1))
|
||||
})
|
||||
|
||||
onDestroy(() => {
|
||||
eventBus.enable("vaut")
|
||||
})
|
||||
|
||||
$: {
|
||||
@@ -109,13 +122,7 @@ async function openSelection(): Promise<void> {
|
||||
</script>
|
||||
|
||||
<div class="modal-title">Omnisearch - File</div>
|
||||
<CmpInput
|
||||
value={searchQuery}
|
||||
on:input={(e) => (searchQuery = e.detail)}
|
||||
on:enter={openSelection}
|
||||
on:arrow-up={() => moveIndex(-1)}
|
||||
on:arrow-down={() => moveIndex(1)}
|
||||
/>
|
||||
<CmpInput value={searchQuery} on:input={(e) => (searchQuery = e.detail)} />
|
||||
|
||||
<div class="modal-content">
|
||||
<div class="prompt-results">
|
||||
|
||||
@@ -7,7 +7,7 @@ import { TFile } from "obsidian"
|
||||
import { onMount, tick } from "svelte"
|
||||
import CmpInput from "./CmpInput.svelte"
|
||||
import CmpResultNote from "./CmpResultNote.svelte"
|
||||
import type { ResultNote } from "./globals"
|
||||
import { eventBus, type ResultNote } from "./globals"
|
||||
import { ModalInFile, type ModalVault } from "./modal"
|
||||
import { createNote, openNote } from "./notes"
|
||||
import { getSuggestions } from "./search"
|
||||
@@ -30,6 +30,12 @@ $: {
|
||||
|
||||
onMount(() => {
|
||||
searchQuery = lastSearch
|
||||
eventBus.on("vault", "enter", onInputEnter)
|
||||
eventBus.on("vault", "shift-enter", onInputShiftEnter)
|
||||
eventBus.on("vault", "ctrl-enter", onInputCtrlEnter)
|
||||
eventBus.on("vault", "alt-enter", onInputAltEnter)
|
||||
eventBus.on("vault", "arrow-up", () => moveIndex(-1))
|
||||
eventBus.on("vault", "arrow-down", () => moveIndex(1))
|
||||
})
|
||||
|
||||
function onClick() {
|
||||
@@ -84,16 +90,7 @@ function scrollIntoView(): void {
|
||||
</script>
|
||||
|
||||
<div class="modal-title">Omnisearch - Vault</div>
|
||||
<CmpInput
|
||||
value={lastSearch}
|
||||
on:input={(e) => (searchQuery = e.detail)}
|
||||
on:enter={onInputEnter}
|
||||
on:shift-enter={onInputShiftEnter}
|
||||
on:ctrl-enter={onInputCtrlEnter}
|
||||
on:alt-enter={onInputAltEnter}
|
||||
on:arrow-up={() => moveIndex(-1)}
|
||||
on:arrow-down={() => moveIndex(1)}
|
||||
/>
|
||||
<CmpInput value={lastSearch} on:input={(e) => (searchQuery = e.detail)} />
|
||||
|
||||
<div class="modal-content">
|
||||
<div class="prompt-results">
|
||||
|
||||
36
src/event-bus.ts
Normal file
36
src/event-bus.ts
Normal file
@@ -0,0 +1,36 @@
|
||||
export type EventBusCallback = (...args: any[]) => any
|
||||
|
||||
export class EventBus {
|
||||
private handlers: Map<string, EventBusCallback> = new Map()
|
||||
private disabled: string[] = []
|
||||
|
||||
public on(ctx: string, event: string, callback: EventBusCallback): void {
|
||||
if (ctx.includes('@') || event.includes('@')) {
|
||||
throw new Error('Invalid ctx/event name - Cannot contain @')
|
||||
}
|
||||
this.handlers.set(`${ctx}@${event}`, callback)
|
||||
}
|
||||
|
||||
public off(ctx: string, event: string): void {
|
||||
this.handlers.delete(`${ctx}@${event}`)
|
||||
}
|
||||
|
||||
public disable(ctx: string): void {
|
||||
this.enable(ctx)
|
||||
this.disabled.push(ctx)
|
||||
}
|
||||
|
||||
public enable(ctx: string): void {
|
||||
this.disabled = this.disabled.filter(v => v !== ctx)
|
||||
}
|
||||
|
||||
public emit(event: string, ...args: any[]): void {
|
||||
for (const [key, handler] of this.handlers.entries()) {
|
||||
const ctx = key.split('@')[0]
|
||||
if (this.disabled.includes(ctx)) continue
|
||||
if (key.endsWith(`@${event}`)) {
|
||||
handler(...args)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,5 @@
|
||||
import { EventBus } from './event-bus'
|
||||
|
||||
// Matches a wikiling that begins a string
|
||||
export const regexWikilink = /^!?\[\[(?<name>.+?)(\|(?<alias>.+?))?\]\]/
|
||||
export const regexLineSplit = /\r?\n|\r|((\.|\?|!)( |\r?\n|\r))/g
|
||||
@@ -8,6 +10,10 @@ export const excerptAfter = 180
|
||||
|
||||
export const highlightClass = 'suggestion-highlight omnisearch-highlight'
|
||||
|
||||
export const eventBus = new EventBus()
|
||||
|
||||
// export const eventBus = new EventBus()
|
||||
|
||||
export type SearchNote = {
|
||||
path: string
|
||||
basename: string
|
||||
|
||||
35
src/modal.ts
35
src/modal.ts
@@ -1,6 +1,7 @@
|
||||
import { App, Modal, TFile } from 'obsidian'
|
||||
import CmpModalVault from './CmpModalVault.svelte'
|
||||
import CmpModalInFile from './CmpModalInFile.svelte'
|
||||
import { eventBus } from './globals'
|
||||
|
||||
abstract class ModalOmnisearch extends Modal {
|
||||
constructor(app: App) {
|
||||
@@ -12,13 +13,45 @@ abstract class ModalOmnisearch extends Modal {
|
||||
this.modalEl.replaceChildren()
|
||||
this.modalEl.append(closeEl)
|
||||
this.modalEl.addClass('omnisearch-modal', 'prompt')
|
||||
|
||||
this.modalEl.tabIndex = -1
|
||||
this.modalEl.onkeydown = ev => {
|
||||
switch (ev.key) {
|
||||
case 'ArrowDown':
|
||||
ev.preventDefault()
|
||||
eventBus.emit('arrow-down')
|
||||
break
|
||||
case 'ArrowUp':
|
||||
ev.preventDefault()
|
||||
eventBus.emit('arrow-up')
|
||||
break
|
||||
case 'Enter':
|
||||
ev.preventDefault()
|
||||
if (ev.ctrlKey || ev.metaKey) {
|
||||
// Open in a new pane
|
||||
eventBus.emit('ctrl-enter')
|
||||
}
|
||||
else if (ev.shiftKey) {
|
||||
// Create a new note
|
||||
eventBus.emit('shift-enter')
|
||||
}
|
||||
else if (ev.altKey) {
|
||||
// Expand in-note results
|
||||
eventBus.emit('alt-enter')
|
||||
}
|
||||
else {
|
||||
// Open in current pane
|
||||
eventBus.emit('enter')
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class ModalVault extends ModalOmnisearch {
|
||||
constructor(app: App) {
|
||||
super(app)
|
||||
|
||||
new CmpModalVault({
|
||||
target: this.modalEl,
|
||||
props: {
|
||||
|
||||
@@ -6,7 +6,6 @@ import {
|
||||
type ResultNote,
|
||||
type SearchMatch,
|
||||
} from './globals'
|
||||
import { get } from 'svelte/store'
|
||||
import { extractHeadingsFromCache, stringsToRegex, wait } from './utils'
|
||||
|
||||
let minisearchInstance: MiniSearch<IndexedNote>
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
import { writable } from 'svelte/store'
|
||||
import type OmnisearchPlugin from './main'
|
||||
@@ -32,7 +32,7 @@ export function removeFrontMatter(text: string): string {
|
||||
}
|
||||
|
||||
export function wait(ms: number): Promise<void> {
|
||||
return new Promise((resolve, reject) => {
|
||||
return new Promise(resolve => {
|
||||
setTimeout(resolve, ms)
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user