Refactored events to use a small global event bus

This commit is contained in:
Simon Cambier
2022-04-22 22:29:52 +02:00
parent acece86ee3
commit 330df899a0
11 changed files with 104 additions and 58 deletions

View File

@@ -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"

View File

@@ -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">

View File

@@ -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
View 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)
}
}
}
}

View File

@@ -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

View File

@@ -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: {

View File

@@ -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>

View File

@@ -1,2 +0,0 @@
import { writable } from 'svelte/store'
import type OmnisearchPlugin from './main'

View File

@@ -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)
})
}