import server from "./server.js"; import appContext from "../components/app_context.js"; import utils from './utils.js'; import noteCreateService from './note_create.js'; import froca from "./froca.js"; import { t } from "./i18n.js"; // this key needs to have this value, so it's hit by the tooltip const SELECTED_NOTE_PATH_KEY = "data-note-path"; const SELECTED_EXTERNAL_LINK_KEY = "data-external-link"; export interface Suggestion { noteTitle?: string; externalLink?: string; notePathTitle?: string; notePath?: string; highlightedNotePathTitle?: string; action?: string | "create-note" | "search-notes" | "external-link"; parentNoteId?: string; } interface Options { container?: HTMLElement; fastSearch?: boolean; allowCreatingNotes?: boolean; allowJumpToSearchNotes?: boolean; allowExternalLinks?: boolean; hideGoToSelectedNoteButton?: boolean; } async function autocompleteSourceForCKEditor(queryText: string) { return await new Promise((res, rej) => { autocompleteSource(queryText, rows => { res(rows.map(row => { return { action: row.action, noteTitle: row.noteTitle, id: `@${row.notePathTitle}`, name: row.notePathTitle, link: `#${row.notePath}`, notePath: row.notePath, highlightedNotePathTitle: row.highlightedNotePathTitle } })); }, { allowCreatingNotes: true }); }); } async function autocompleteSource(term: string, cb: (rows: Suggestion[]) => void, options: Options = {}) { const fastSearch = options.fastSearch === false ? false : true; if (fastSearch === false) { if (term.trim().length === 0){ return; } cb( [{ noteTitle: term, highlightedNotePathTitle: t("quick-search.searching") }] ); } const activeNoteId = appContext.tabManager.getActiveContextNoteId(); let results: Suggestion[] = await server.get(`autocomplete?query=${encodeURIComponent(term)}&activeNoteId=${activeNoteId}&fastSearch=${fastSearch}`); if (term.trim().length >= 1 && options.allowCreatingNotes) { results = [ { action: 'create-note', noteTitle: term, parentNoteId: activeNoteId || 'root', highlightedNotePathTitle: t("note_autocomplete.create-note", { term }) } as Suggestion ].concat(results); } if (term.trim().length >= 1 && options.allowJumpToSearchNotes) { results = results.concat([ { action: 'search-notes', noteTitle: term, highlightedNotePathTitle: `${t("note_autocomplete.search-for", { term })} Ctrl+Enter` } ]); } if (term.match(/^[a-z]+:\/\/.+/i) && options.allowExternalLinks) { results = [ { action: 'external-link', externalLink: term, highlightedNotePathTitle: t("note_autocomplete.insert-external-link", { term }) } as Suggestion ].concat(results); } cb(results); } function clearText($el: JQuery) { if (utils.isMobile()) { return; } $el.setSelectedNotePath(""); $el.autocomplete("val", "").trigger('change'); } function setText($el: JQuery, text: string) { if (utils.isMobile()) { return; } $el.setSelectedNotePath(""); $el .autocomplete("val", text.trim()) .autocomplete("open"); } function showRecentNotes($el:JQuery) { if (utils.isMobile()) { return; } $el.setSelectedNotePath(""); $el.autocomplete("val", ""); $el.autocomplete('open'); $el.trigger('focus'); } function fullTextSearch($el: JQuery, options: Options){ const searchString = $el.autocomplete('val') as unknown as string; if (options.fastSearch === false || searchString?.trim().length === 0) { return; } $el.trigger('focus'); options.fastSearch = false; $el.autocomplete('val', ''); $el.autocomplete() $el.setSelectedNotePath(""); $el.autocomplete('val', searchString); // Set a delay to avoid resetting to true before full text search (await server.get) is called. setTimeout(() => { options.fastSearch = true; }, 100); } function initNoteAutocomplete($el: JQuery, options: Options) { if ($el.hasClass("note-autocomplete-input") || utils.isMobile()) { // clear any event listener added in previous invocation of this function $el.off('autocomplete:noteselected'); return $el; } options = options || {}; $el.addClass("note-autocomplete-input"); const $clearTextButton = $("