mirror of
https://github.com/zadam/trilium.git
synced 2025-11-02 11:26:15 +01:00
feat(command_palette): basic implementation
This commit is contained in:
337
apps/client/src/services/command_registry.ts
Normal file
337
apps/client/src/services/command_registry.ts
Normal file
@@ -0,0 +1,337 @@
|
|||||||
|
import appContext, { type CommandNames } from "../components/app_context.js";
|
||||||
|
|
||||||
|
export interface CommandDefinition {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
description?: string;
|
||||||
|
icon?: string;
|
||||||
|
shortcut?: string;
|
||||||
|
commandName?: CommandNames;
|
||||||
|
handler?: () => void | Promise<void>;
|
||||||
|
aliases?: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
class CommandRegistry {
|
||||||
|
private commands: Map<string, CommandDefinition> = new Map();
|
||||||
|
private aliases: Map<string, string> = new Map();
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.registerDefaultCommands();
|
||||||
|
}
|
||||||
|
|
||||||
|
private registerDefaultCommands() {
|
||||||
|
// Navigation & UI Commands
|
||||||
|
this.register({
|
||||||
|
id: "toggle-zen-mode",
|
||||||
|
name: "Toggle Zen Mode",
|
||||||
|
description: "Enter/exit distraction-free mode",
|
||||||
|
icon: "bx bx-fullscreen",
|
||||||
|
shortcut: "F9",
|
||||||
|
commandName: "toggleZenMode"
|
||||||
|
});
|
||||||
|
|
||||||
|
this.register({
|
||||||
|
id: "toggle-left-pane",
|
||||||
|
name: "Toggle Left Pane",
|
||||||
|
description: "Show/hide the note tree sidebar",
|
||||||
|
icon: "bx bx-sidebar",
|
||||||
|
handler: () => appContext.triggerCommand("toggleLeftPane")
|
||||||
|
});
|
||||||
|
|
||||||
|
this.register({
|
||||||
|
id: "show-options",
|
||||||
|
name: "Show Options",
|
||||||
|
description: "Open settings/preferences",
|
||||||
|
icon: "bx bx-cog",
|
||||||
|
commandName: "showOptions",
|
||||||
|
aliases: ["settings", "preferences"]
|
||||||
|
});
|
||||||
|
|
||||||
|
this.register({
|
||||||
|
id: "show-help",
|
||||||
|
name: "Show Help",
|
||||||
|
description: "Open help documentation",
|
||||||
|
icon: "bx bx-help-circle",
|
||||||
|
handler: () => appContext.triggerCommand("showHelp")
|
||||||
|
});
|
||||||
|
|
||||||
|
this.register({
|
||||||
|
id: "collapse-tree",
|
||||||
|
name: "Collapse Tree",
|
||||||
|
description: "Collapse all tree nodes",
|
||||||
|
icon: "bx bx-collapse",
|
||||||
|
shortcut: "Alt+C",
|
||||||
|
handler: () => appContext.triggerCommand("collapseTree")
|
||||||
|
});
|
||||||
|
|
||||||
|
// Note Operations
|
||||||
|
this.register({
|
||||||
|
id: "create-note-into",
|
||||||
|
name: "Create New Note",
|
||||||
|
description: "Create a new child note",
|
||||||
|
icon: "bx bx-plus",
|
||||||
|
shortcut: "CommandOrControl+P",
|
||||||
|
commandName: "createNoteInto",
|
||||||
|
aliases: ["new note", "add note"]
|
||||||
|
});
|
||||||
|
|
||||||
|
this.register({
|
||||||
|
id: "create-sql-console",
|
||||||
|
name: "Create SQL Console",
|
||||||
|
description: "Create a new SQL console note",
|
||||||
|
icon: "bx bx-data",
|
||||||
|
handler: () => appContext.triggerCommand("showSQLConsole")
|
||||||
|
});
|
||||||
|
|
||||||
|
this.register({
|
||||||
|
id: "create-ai-chat",
|
||||||
|
name: "Create AI Chat",
|
||||||
|
description: "Create a new AI chat note",
|
||||||
|
icon: "bx bx-bot",
|
||||||
|
commandName: "createAiChat"
|
||||||
|
});
|
||||||
|
|
||||||
|
this.register({
|
||||||
|
id: "clone-notes-to",
|
||||||
|
name: "Clone Note",
|
||||||
|
description: "Clone current note to another location",
|
||||||
|
icon: "bx bx-copy",
|
||||||
|
shortcut: "CommandOrControl+Shift+C",
|
||||||
|
commandName: "cloneNotesTo"
|
||||||
|
});
|
||||||
|
|
||||||
|
this.register({
|
||||||
|
id: "delete-notes",
|
||||||
|
name: "Delete Note",
|
||||||
|
description: "Delete current note",
|
||||||
|
icon: "bx bx-trash",
|
||||||
|
shortcut: "Delete",
|
||||||
|
commandName: "deleteNotes"
|
||||||
|
});
|
||||||
|
|
||||||
|
this.register({
|
||||||
|
id: "export-note",
|
||||||
|
name: "Export Note",
|
||||||
|
description: "Export current note",
|
||||||
|
icon: "bx bx-export",
|
||||||
|
handler: () => {
|
||||||
|
const notePath = appContext.tabManager.getActiveContextNotePath();
|
||||||
|
if (notePath) {
|
||||||
|
appContext.triggerCommand("showExportDialog", {
|
||||||
|
notePath,
|
||||||
|
defaultType: "single"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.register({
|
||||||
|
id: "show-note-source",
|
||||||
|
name: "Show Note Source",
|
||||||
|
description: "View note in source mode",
|
||||||
|
icon: "bx bx-code",
|
||||||
|
handler: () => appContext.triggerCommand("showNoteSource")
|
||||||
|
});
|
||||||
|
|
||||||
|
this.register({
|
||||||
|
id: "show-attachments",
|
||||||
|
name: "Show Attachments",
|
||||||
|
description: "View note attachments",
|
||||||
|
icon: "bx bx-paperclip",
|
||||||
|
handler: () => appContext.triggerCommand("showAttachments")
|
||||||
|
});
|
||||||
|
|
||||||
|
// Session & Security
|
||||||
|
this.register({
|
||||||
|
id: "enter-protected-session",
|
||||||
|
name: "Enter Protected Session",
|
||||||
|
description: "Enter password-protected mode",
|
||||||
|
icon: "bx bx-lock",
|
||||||
|
commandName: "enterProtectedSession"
|
||||||
|
});
|
||||||
|
|
||||||
|
this.register({
|
||||||
|
id: "leave-protected-session",
|
||||||
|
name: "Leave Protected Session",
|
||||||
|
description: "Exit protected mode",
|
||||||
|
icon: "bx bx-lock-open",
|
||||||
|
commandName: "leaveProtectedSession"
|
||||||
|
});
|
||||||
|
|
||||||
|
// Search & Organization
|
||||||
|
this.register({
|
||||||
|
id: "search-notes",
|
||||||
|
name: "Search Notes",
|
||||||
|
description: "Open advanced search",
|
||||||
|
icon: "bx bx-search",
|
||||||
|
shortcut: "CommandOrControl+Shift+F",
|
||||||
|
handler: () => appContext.triggerCommand("searchNotes", {})
|
||||||
|
});
|
||||||
|
|
||||||
|
this.register({
|
||||||
|
id: "search-in-subtree",
|
||||||
|
name: "Search in Subtree",
|
||||||
|
description: "Search within current subtree",
|
||||||
|
icon: "bx bx-search-alt",
|
||||||
|
shortcut: "CommandOrControl+Shift+S",
|
||||||
|
handler: () => {
|
||||||
|
const notePath = appContext.tabManager.getActiveContextNotePath();
|
||||||
|
if (notePath) {
|
||||||
|
appContext.triggerCommand("searchInSubtree", { notePath });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.register({
|
||||||
|
id: "show-search-history",
|
||||||
|
name: "Show Search History",
|
||||||
|
description: "View previous searches",
|
||||||
|
icon: "bx bx-history",
|
||||||
|
handler: () => appContext.triggerCommand("showSearchHistory")
|
||||||
|
});
|
||||||
|
|
||||||
|
this.register({
|
||||||
|
id: "sort-child-notes",
|
||||||
|
name: "Sort Child Notes",
|
||||||
|
description: "Sort notes alphabetically",
|
||||||
|
icon: "bx bx-sort",
|
||||||
|
shortcut: "Alt+S",
|
||||||
|
commandName: "sortChildNotes"
|
||||||
|
});
|
||||||
|
|
||||||
|
// Developer Tools
|
||||||
|
this.register({
|
||||||
|
id: "show-backend-log",
|
||||||
|
name: "Show Backend Log",
|
||||||
|
description: "View server logs",
|
||||||
|
icon: "bx bx-terminal",
|
||||||
|
handler: () => appContext.triggerCommand("showBackendLog")
|
||||||
|
});
|
||||||
|
|
||||||
|
this.register({
|
||||||
|
id: "run-active-note",
|
||||||
|
name: "Run Active Note",
|
||||||
|
description: "Execute current note as script",
|
||||||
|
icon: "bx bx-play",
|
||||||
|
commandName: "runActiveNote"
|
||||||
|
});
|
||||||
|
|
||||||
|
// Recent Changes
|
||||||
|
this.register({
|
||||||
|
id: "show-recent-changes",
|
||||||
|
name: "Show Recent Changes",
|
||||||
|
description: "View recently modified notes",
|
||||||
|
icon: "bx bx-time",
|
||||||
|
handler: () => appContext.triggerCommand("showRecentChanges", { ancestorNoteId: "root" })
|
||||||
|
});
|
||||||
|
|
||||||
|
// Additional useful commands
|
||||||
|
this.register({
|
||||||
|
id: "open-new-tab",
|
||||||
|
name: "Open New Tab",
|
||||||
|
description: "Open a new tab",
|
||||||
|
icon: "bx bx-tab",
|
||||||
|
shortcut: "CommandOrControl+T",
|
||||||
|
commandName: "openNewTab"
|
||||||
|
});
|
||||||
|
|
||||||
|
this.register({
|
||||||
|
id: "close-active-tab",
|
||||||
|
name: "Close Active Tab",
|
||||||
|
description: "Close the current tab",
|
||||||
|
icon: "bx bx-x",
|
||||||
|
shortcut: "CommandOrControl+W",
|
||||||
|
commandName: "closeActiveTab"
|
||||||
|
});
|
||||||
|
|
||||||
|
this.register({
|
||||||
|
id: "show-launch-bar",
|
||||||
|
name: "Show Launch Bar",
|
||||||
|
description: "Open the launch bar subtree",
|
||||||
|
icon: "bx bx-grid-alt",
|
||||||
|
handler: () => appContext.triggerCommand("showLaunchBarSubtree")
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
register(command: CommandDefinition) {
|
||||||
|
this.commands.set(command.id, command);
|
||||||
|
|
||||||
|
// Register aliases
|
||||||
|
if (command.aliases) {
|
||||||
|
for (const alias of command.aliases) {
|
||||||
|
this.aliases.set(alias.toLowerCase(), command.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getCommand(id: string): CommandDefinition | undefined {
|
||||||
|
return this.commands.get(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
getAllCommands(): CommandDefinition[] {
|
||||||
|
return Array.from(this.commands.values());
|
||||||
|
}
|
||||||
|
|
||||||
|
searchCommands(query: string): CommandDefinition[] {
|
||||||
|
const normalizedQuery = query.toLowerCase();
|
||||||
|
const results: { command: CommandDefinition; score: number }[] = [];
|
||||||
|
|
||||||
|
for (const command of this.commands.values()) {
|
||||||
|
let score = 0;
|
||||||
|
|
||||||
|
// Exact match on name
|
||||||
|
if (command.name.toLowerCase() === normalizedQuery) {
|
||||||
|
score = 100;
|
||||||
|
}
|
||||||
|
// Name starts with query
|
||||||
|
else if (command.name.toLowerCase().startsWith(normalizedQuery)) {
|
||||||
|
score = 80;
|
||||||
|
}
|
||||||
|
// Name contains query
|
||||||
|
else if (command.name.toLowerCase().includes(normalizedQuery)) {
|
||||||
|
score = 60;
|
||||||
|
}
|
||||||
|
// Description contains query
|
||||||
|
else if (command.description?.toLowerCase().includes(normalizedQuery)) {
|
||||||
|
score = 40;
|
||||||
|
}
|
||||||
|
// Check aliases
|
||||||
|
else if (command.aliases?.some(alias => alias.toLowerCase().includes(normalizedQuery))) {
|
||||||
|
score = 50;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (score > 0) {
|
||||||
|
results.push({ command, score });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sort by score (highest first) and then by name
|
||||||
|
results.sort((a, b) => {
|
||||||
|
if (a.score !== b.score) {
|
||||||
|
return b.score - a.score;
|
||||||
|
}
|
||||||
|
return a.command.name.localeCompare(b.command.name);
|
||||||
|
});
|
||||||
|
|
||||||
|
return results.map(r => r.command);
|
||||||
|
}
|
||||||
|
|
||||||
|
async executeCommand(commandId: string) {
|
||||||
|
const command = this.getCommand(commandId);
|
||||||
|
if (!command) {
|
||||||
|
console.error(`Command not found: ${commandId}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (command.handler) {
|
||||||
|
await command.handler();
|
||||||
|
} else if (command.commandName) {
|
||||||
|
appContext.triggerCommand(command.commandName);
|
||||||
|
} else {
|
||||||
|
console.error(`Command ${commandId} has no handler or commandName`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const commandRegistry = new CommandRegistry();
|
||||||
|
export default commandRegistry;
|
||||||
@@ -3,6 +3,7 @@ import appContext from "../components/app_context.js";
|
|||||||
import noteCreateService from "./note_create.js";
|
import noteCreateService from "./note_create.js";
|
||||||
import froca from "./froca.js";
|
import froca from "./froca.js";
|
||||||
import { t } from "./i18n.js";
|
import { t } from "./i18n.js";
|
||||||
|
import commandRegistry from "./command_registry.js";
|
||||||
import type { MentionFeedObjectItem } from "@triliumnext/ckeditor5";
|
import type { MentionFeedObjectItem } from "@triliumnext/ckeditor5";
|
||||||
|
|
||||||
// this key needs to have this value, so it's hit by the tooltip
|
// this key needs to have this value, so it's hit by the tooltip
|
||||||
@@ -29,9 +30,12 @@ export interface Suggestion {
|
|||||||
notePathTitle?: string;
|
notePathTitle?: string;
|
||||||
notePath?: string;
|
notePath?: string;
|
||||||
highlightedNotePathTitle?: string;
|
highlightedNotePathTitle?: string;
|
||||||
action?: string | "create-note" | "search-notes" | "external-link";
|
action?: string | "create-note" | "search-notes" | "external-link" | "command";
|
||||||
parentNoteId?: string;
|
parentNoteId?: string;
|
||||||
icon?: string;
|
icon?: string;
|
||||||
|
commandId?: string;
|
||||||
|
commandDescription?: string;
|
||||||
|
commandShortcut?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Options {
|
interface Options {
|
||||||
@@ -44,6 +48,8 @@ interface Options {
|
|||||||
hideGoToSelectedNoteButton?: boolean;
|
hideGoToSelectedNoteButton?: boolean;
|
||||||
/** If set, hides all right-side buttons in the autocomplete dropdown */
|
/** If set, hides all right-side buttons in the autocomplete dropdown */
|
||||||
hideAllButtons?: boolean;
|
hideAllButtons?: boolean;
|
||||||
|
/** If set, enables command palette mode */
|
||||||
|
isCommandPalette?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function autocompleteSourceForCKEditor(queryText: string) {
|
async function autocompleteSourceForCKEditor(queryText: string) {
|
||||||
@@ -73,6 +79,41 @@ async function autocompleteSourceForCKEditor(queryText: string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function autocompleteSource(term: string, cb: (rows: Suggestion[]) => void, options: Options = {}) {
|
async function autocompleteSource(term: string, cb: (rows: Suggestion[]) => void, options: Options = {}) {
|
||||||
|
// Check if we're in command mode
|
||||||
|
if (options.isCommandPalette && term.startsWith(">")) {
|
||||||
|
const commandQuery = term.substring(1).trim();
|
||||||
|
|
||||||
|
if (commandQuery.length === 0) {
|
||||||
|
// Show all commands if no query
|
||||||
|
const allCommands = commandRegistry.getAllCommands();
|
||||||
|
const commandSuggestions: Suggestion[] = allCommands.map(cmd => ({
|
||||||
|
action: "command",
|
||||||
|
commandId: cmd.id,
|
||||||
|
noteTitle: cmd.name,
|
||||||
|
highlightedNotePathTitle: cmd.name,
|
||||||
|
commandDescription: cmd.description,
|
||||||
|
commandShortcut: cmd.shortcut,
|
||||||
|
icon: cmd.icon
|
||||||
|
}));
|
||||||
|
cb(commandSuggestions);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Search commands
|
||||||
|
const matchedCommands = commandRegistry.searchCommands(commandQuery);
|
||||||
|
const commandSuggestions: Suggestion[] = matchedCommands.map(cmd => ({
|
||||||
|
action: "command",
|
||||||
|
commandId: cmd.id,
|
||||||
|
noteTitle: cmd.name,
|
||||||
|
highlightedNotePathTitle: cmd.name,
|
||||||
|
commandDescription: cmd.description,
|
||||||
|
commandShortcut: cmd.shortcut,
|
||||||
|
icon: cmd.icon
|
||||||
|
}));
|
||||||
|
cb(commandSuggestions);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const fastSearch = options.fastSearch === false ? false : true;
|
const fastSearch = options.fastSearch === false ? false : true;
|
||||||
if (fastSearch === false) {
|
if (fastSearch === false) {
|
||||||
if (term.trim().length === 0) {
|
if (term.trim().length === 0) {
|
||||||
@@ -270,7 +311,23 @@ function initNoteAutocomplete($el: JQuery<HTMLElement>, options?: Options) {
|
|||||||
},
|
},
|
||||||
displayKey: "notePathTitle",
|
displayKey: "notePathTitle",
|
||||||
templates: {
|
templates: {
|
||||||
suggestion: (suggestion) => `<span class="${suggestion.icon ?? "bx bx-note"}"></span> ${suggestion.highlightedNotePathTitle}`
|
suggestion: (suggestion) => {
|
||||||
|
if (suggestion.action === "command") {
|
||||||
|
let html = `<div class="command-suggestion">`;
|
||||||
|
html += `<div style="position: relative;">`;
|
||||||
|
html += `<span class="${suggestion.icon || "bx bx-terminal"}"></span> <strong>${suggestion.highlightedNotePathTitle}</strong>`;
|
||||||
|
if (suggestion.commandShortcut) {
|
||||||
|
html += ` <kbd>${suggestion.commandShortcut}</kbd>`;
|
||||||
|
}
|
||||||
|
html += `</div>`;
|
||||||
|
if (suggestion.commandDescription) {
|
||||||
|
html += `<small style="color: var(--muted-text-color);">${suggestion.commandDescription}</small>`;
|
||||||
|
}
|
||||||
|
html += '</div>';
|
||||||
|
return html;
|
||||||
|
}
|
||||||
|
return `<span class="${suggestion.icon ?? "bx bx-note"}"></span> ${suggestion.highlightedNotePathTitle}`;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
// we can't cache identical searches because notes can be created / renamed, new recent notes can be added
|
// we can't cache identical searches because notes can be created / renamed, new recent notes can be added
|
||||||
cache: false
|
cache: false
|
||||||
@@ -280,6 +337,12 @@ function initNoteAutocomplete($el: JQuery<HTMLElement>, options?: Options) {
|
|||||||
|
|
||||||
// TODO: Types fail due to "autocomplete:selected" not being registered in type definitions.
|
// TODO: Types fail due to "autocomplete:selected" not being registered in type definitions.
|
||||||
($el as any).on("autocomplete:selected", async (event: Event, suggestion: Suggestion) => {
|
($el as any).on("autocomplete:selected", async (event: Event, suggestion: Suggestion) => {
|
||||||
|
if (suggestion.action === "command") {
|
||||||
|
$el.autocomplete("close");
|
||||||
|
$el.trigger("autocomplete:commandselected", [suggestion]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (suggestion.action === "external-link") {
|
if (suggestion.action === "external-link") {
|
||||||
$el.setSelectedNotePath(null);
|
$el.setSelectedNotePath(null);
|
||||||
$el.setSelectedExternalLink(suggestion.externalLink);
|
$el.setSelectedExternalLink(suggestion.externalLink);
|
||||||
|
|||||||
@@ -1780,6 +1780,37 @@ textarea {
|
|||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Command palette styling */
|
||||||
|
.jump-to-note-dialog .aa-suggestion .command-suggestion {
|
||||||
|
margin: -0.5rem -1rem;
|
||||||
|
padding: 0.75rem 1rem;
|
||||||
|
border-left: 3px solid var(--main-border-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.jump-to-note-dialog .aa-cursor .command-suggestion,
|
||||||
|
.jump-to-note-dialog .aa-suggestion:hover .command-suggestion {
|
||||||
|
border-left-color: var(--link-color);
|
||||||
|
background-color: var(--hover-background-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.jump-to-note-dialog .command-suggestion kbd {
|
||||||
|
padding: 0.2rem 0.4rem;
|
||||||
|
font-size: 0.8em;
|
||||||
|
background-color: var(--button-background-color);
|
||||||
|
border: 1px solid var(--main-border-color);
|
||||||
|
border-radius: 3px;
|
||||||
|
margin-left: 0.5rem;
|
||||||
|
position: absolute;
|
||||||
|
right: 1rem;
|
||||||
|
top: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.jump-to-note-dialog .command-suggestion small {
|
||||||
|
display: block;
|
||||||
|
margin-top: 0.25rem;
|
||||||
|
line-height: 1.3;
|
||||||
|
}
|
||||||
|
|
||||||
.empty-table-placeholder {
|
.empty-table-placeholder {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
color: var(--muted-text-color);
|
color: var(--muted-text-color);
|
||||||
|
|||||||
@@ -6,13 +6,14 @@ import BasicWidget from "../basic_widget.js";
|
|||||||
import shortcutService from "../../services/shortcuts.js";
|
import shortcutService from "../../services/shortcuts.js";
|
||||||
import { Modal } from "bootstrap";
|
import { Modal } from "bootstrap";
|
||||||
import { openDialog } from "../../services/dialog.js";
|
import { openDialog } from "../../services/dialog.js";
|
||||||
|
import commandRegistry from "../../services/command_registry.js";
|
||||||
|
|
||||||
const TPL = /*html*/`<div class="jump-to-note-dialog modal mx-auto" tabindex="-1" role="dialog">
|
const TPL = /*html*/`<div class="jump-to-note-dialog modal mx-auto" tabindex="-1" role="dialog">
|
||||||
<div class="modal-dialog modal-lg" role="document">
|
<div class="modal-dialog modal-lg" role="document">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<input class="jump-to-note-autocomplete form-control" placeholder="${t("jump_to_note.search_placeholder")}">
|
<input class="jump-to-note-autocomplete form-control" placeholder="${t("jump_to_note.search_placeholder", { defaultValue: "Search notes or type > for commands..." })}">
|
||||||
</div>
|
</div>
|
||||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="${t("jump_to_note.close")}"></button>
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="${t("jump_to_note.close")}"></button>
|
||||||
</div>
|
</div>
|
||||||
@@ -92,16 +93,25 @@ export default class JumpToNoteDialog extends BasicWidget {
|
|||||||
allowCreatingNotes: true,
|
allowCreatingNotes: true,
|
||||||
hideGoToSelectedNoteButton: true,
|
hideGoToSelectedNoteButton: true,
|
||||||
allowJumpToSearchNotes: true,
|
allowJumpToSearchNotes: true,
|
||||||
container: this.$results[0]
|
container: this.$results[0],
|
||||||
|
isCommandPalette: true
|
||||||
})
|
})
|
||||||
// clear any event listener added in previous invocation of this function
|
// clear any event listener added in previous invocation of this function
|
||||||
.off("autocomplete:noteselected")
|
.off("autocomplete:noteselected")
|
||||||
|
.off("autocomplete:commandselected")
|
||||||
.on("autocomplete:noteselected", function (event, suggestion, dataset) {
|
.on("autocomplete:noteselected", function (event, suggestion, dataset) {
|
||||||
if (!suggestion.notePath) {
|
if (!suggestion.notePath) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
appContext.tabManager.getActiveContext()?.setNote(suggestion.notePath);
|
appContext.tabManager.getActiveContext()?.setNote(suggestion.notePath);
|
||||||
|
})
|
||||||
|
.on("autocomplete:commandselected", async function (event, suggestion, dataset) {
|
||||||
|
if (!suggestion.commandId) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
await commandRegistry.executeCommand(suggestion.commandId);
|
||||||
});
|
});
|
||||||
|
|
||||||
// if you open the Jump To dialog soon after using it previously, it can often mean that you
|
// if you open the Jump To dialog soon after using it previously, it can often mean that you
|
||||||
|
|||||||
Reference in New Issue
Block a user