diff --git a/apps/client/src/services/attribute_autocomplete.ts b/apps/client/src/services/attribute_autocomplete.ts index a39f6b5cfe..37fad01b51 100644 --- a/apps/client/src/services/attribute_autocomplete.ts +++ b/apps/client/src/services/attribute_autocomplete.ts @@ -302,6 +302,9 @@ function initLabelValueAutocomplete({ $el, open, nameCallback, onValueChange }: isSelecting = false; setTimeout(() => { + // Preserve the legacy contract: several consumers still commit the + // selected value from their existing Enter key handlers instead of + // listening to the autocomplete selection event directly. inputEl.dispatchEvent(new KeyboardEvent("keydown", { key: "Enter", code: "Enter", diff --git a/apps/client/src/services/note_autocomplete.ts b/apps/client/src/services/note_autocomplete.ts index 5f25bd99c8..e487b2226d 100644 --- a/apps/client/src/services/note_autocomplete.ts +++ b/apps/client/src/services/note_autocomplete.ts @@ -111,8 +111,20 @@ function escapeHtml(text: string): string { .replaceAll("'", "'"); } +function sanitizeHighlightedHtml(text: string, { allowBreaks = false }: { allowBreaks?: boolean } = {}): string { + const sanitizedBreaks = allowBreaks + ? text.replace(/]*\/?>/gi, "
") + : text.replace(/]*\/?>/gi, ""); + + return sanitizedBreaks + .replace(/]*>/gi, "") + .replace(/<\/b\s*>/gi, "") + .replace(/<\/?[^>]+>/g, ""); +} + function normalizeAttributeSnippet(snippet: string): string { - return snippet.replace(//gi, " · "); + return sanitizeHighlightedHtml(snippet, { allowBreaks: true }) + .replace(//gi, " · "); } function getSuggestionIconClass(item: Suggestion): string { @@ -135,7 +147,9 @@ function getSuggestionInputValue(item: Suggestion): string { function renderCommandSuggestion(item: Suggestion): string { const iconClass = escapeHtml(item.icon || "bx bx-terminal"); - const titleHtml = item.highlightedNotePathTitle || escapeHtml(item.noteTitle || ""); + const titleHtml = item.highlightedNotePathTitle + ? sanitizeHighlightedHtml(item.highlightedNotePathTitle) + : escapeHtml(item.noteTitle || ""); const descriptionHtml = item.commandDescription ? `
${escapeHtml(item.commandDescription)}
` : ""; const shortcutHtml = item.commandShortcut ? `${escapeHtml(item.commandShortcut)}` : ""; @@ -153,7 +167,9 @@ function renderCommandSuggestion(item: Suggestion): string { function renderNoteSuggestion(item: Suggestion): string { const iconClass = escapeHtml(getSuggestionIconClass(item)); - const titleHtml = item.highlightedNotePathTitle || escapeHtml(item.noteTitle || item.notePathTitle || item.externalLink || ""); + const titleHtml = item.highlightedNotePathTitle + ? sanitizeHighlightedHtml(item.highlightedNotePathTitle) + : escapeHtml(item.noteTitle || item.notePathTitle || item.externalLink || ""); const shortcutHtml = item.action === "search-notes" ? `Ctrl+Enter` : "";