Merge pull request #659 from TriliumNext/quick_search_in_autocomplete

Add full text search in autocomplete
This commit is contained in:
Elian Doran 2024-11-28 19:17:03 +02:00 committed by GitHub
commit 29b062660d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 57 additions and 16 deletions

View File

@ -30,10 +30,22 @@ async function autocompleteSourceForCKEditor(queryText) {
} }
async function autocompleteSource(term, cb, options = {}) { async function autocompleteSource(term, cb, options = {}) {
const fastSearch = options.fastSearch === false ? false : true;
if (fastSearch === false) {
if (term.trim().length === 0){
return;
}
cb(
[{
noteTitle: term,
highlightedNotePathTitle: `Searching...`
}]
);
}
const activeNoteId = appContext.tabManager.getActiveContextNoteId(); const activeNoteId = appContext.tabManager.getActiveContextNoteId();
let results = await server.get(`autocomplete?query=${encodeURIComponent(term)}&activeNoteId=${activeNoteId}`); let results = await server.get(`autocomplete?query=${encodeURIComponent(term)}&activeNoteId=${activeNoteId}&fastSearch=${fastSearch}`);
if (term.trim().length >= 1 && options.allowCreatingNotes) { if (term.trim().length >= 1 && options.allowCreatingNotes) {
results = [ results = [
{ {
@ -45,7 +57,7 @@ async function autocompleteSource(term, cb, options = {}) {
].concat(results); ].concat(results);
} }
if (term.trim().length >= 1 && options.allowSearchNotes) { if (term.trim().length >= 1 && options.allowJumpToSearchNotes) {
results = results.concat([ results = results.concat([
{ {
action: 'search-notes', action: 'search-notes',
@ -95,12 +107,22 @@ function showRecentNotes($el) {
$el.setSelectedNotePath(""); $el.setSelectedNotePath("");
$el.autocomplete("val", ""); $el.autocomplete("val", "");
$el.autocomplete('open');
$el.trigger('focus'); $el.trigger('focus');
}
// simulate pressing down arrow to trigger autocomplete function fullTextSearch($el, options){
const e = $.Event('keydown'); const searchString = $el.autocomplete('val');
e.which = 40; // arrow down if (options.fastSearch === false || searchString.trim().length === 0) {
$el.trigger(e); return;
}
$el.trigger('focus');
options.fastSearch = false;
$el.autocomplete('val', '');
$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, options) { function initNoteAutocomplete($el, options) {
@ -123,10 +145,14 @@ function initNoteAutocomplete($el, options) {
.addClass("input-group-text show-recent-notes-button bx bx-time") .addClass("input-group-text show-recent-notes-button bx bx-time")
.prop("title", "Show recent notes"); .prop("title", "Show recent notes");
const $fullTextSearchButton = $("<button>")
.addClass("input-group-text full-text-search-button bx bx-search")
.prop("title", "Full text search (Shift+Enter)");
const $goToSelectedNoteButton = $("<button>") const $goToSelectedNoteButton = $("<button>")
.addClass("input-group-text go-to-selected-note-button bx bx-arrow-to-right"); .addClass("input-group-text go-to-selected-note-button bx bx-arrow-to-right");
$el.after($clearTextButton).after($showRecentNotesButton); $el.after($clearTextButton).after($showRecentNotesButton).after($fullTextSearchButton);
if (!options.hideGoToSelectedNoteButton) { if (!options.hideGoToSelectedNoteButton) {
$el.after($goToSelectedNoteButton); $el.after($goToSelectedNoteButton);
@ -142,13 +168,18 @@ function initNoteAutocomplete($el, options) {
return false; return false;
}); });
$fullTextSearchButton.on('click', e => {
fullTextSearch($el, options);
return false;
});
let autocompleteOptions = {}; let autocompleteOptions = {};
if (options.container) { if (options.container) {
autocompleteOptions.dropdownMenuContainer = options.container; autocompleteOptions.dropdownMenuContainer = options.container;
autocompleteOptions.debug = true; // don't close on blur autocompleteOptions.debug = true; // don't close on blur
} }
if (options.allowSearchNotes) { if (options.allowJumpToSearchNotes) {
$el.on('keydown', (event) => { $el.on('keydown', (event) => {
if (event.ctrlKey && event.key === 'Enter') { if (event.ctrlKey && event.key === 'Enter') {
// Prevent Ctrl + Enter from triggering autoComplete. // Prevent Ctrl + Enter from triggering autoComplete.
@ -158,6 +189,14 @@ function initNoteAutocomplete($el, options) {
} }
}); });
} }
$el.on('keydown', async (event) => {
if (event.shiftKey && event.key === 'Enter') {
// Prevent Enter from triggering autoComplete.
event.stopImmediatePropagation();
event.preventDefault();
fullTextSearch($el,options)
}
});
$el.autocomplete({ $el.autocomplete({
...autocompleteOptions, ...autocompleteOptions,

View File

@ -58,7 +58,7 @@ export default class JumpToNoteDialog extends BasicWidget {
noteAutocompleteService.initNoteAutocomplete(this.$autoComplete, { noteAutocompleteService.initNoteAutocomplete(this.$autoComplete, {
allowCreatingNotes: true, allowCreatingNotes: true,
hideGoToSelectedNoteButton: true, hideGoToSelectedNoteButton: true,
allowSearchNotes: true, allowJumpToSearchNotes: true,
container: this.$results container: this.$results
}) })
// clear any event listener added in previous invocation of this function // clear any event listener added in previous invocation of this function

View File

@ -70,7 +70,7 @@ export default class EmptyTypeWidget extends TypeWidget {
noteAutocompleteService.initNoteAutocomplete(this.$autoComplete, { noteAutocompleteService.initNoteAutocomplete(this.$autoComplete, {
hideGoToSelectedNoteButton: true, hideGoToSelectedNoteButton: true,
allowCreatingNotes: true, allowCreatingNotes: true,
allowSearchNotes: true, allowJumpToSearchNotes: true,
container: this.$results container: this.$results
}) })
.on('autocomplete:noteselected', function(event, suggestion, dataset) { .on('autocomplete:noteselected', function(event, suggestion, dataset) {

View File

@ -448,7 +448,7 @@ pre:not(.CodeMirror-line):not(.hljs) {
padding-top: 8px; padding-top: 8px;
} }
.show-recent-notes-button { .show-recent-notes-button, .full-text-search-button {
cursor: pointer; cursor: pointer;
font-size: 1.3em; font-size: 1.3em;
padding-left: 5px; padding-left: 5px;

View File

@ -14,6 +14,8 @@ function getAutocomplete(req: Request) {
throw new ValidationError("Invalid query data type."); throw new ValidationError("Invalid query data type.");
} }
const query = (req.query.query || "").trim(); const query = (req.query.query || "").trim();
const fastSearch = String(req.query.fastSearch).toLowerCase() === "false" ? false : true;
const activeNoteId = req.query.activeNoteId || 'none'; const activeNoteId = req.query.activeNoteId || 'none';
let results; let results;
@ -24,7 +26,7 @@ function getAutocomplete(req: Request) {
results = getRecentNotes(activeNoteId); results = getRecentNotes(activeNoteId);
} }
else { else {
results = searchService.searchNotesForAutocomplete(query); results = searchService.searchNotesForAutocomplete(query, fastSearch);
} }
const msTaken = Date.now() - timestampStarted; const msTaken = Date.now() - timestampStarted;

View File

@ -340,9 +340,9 @@ function findFirstNoteWithQuery(query: string, searchContext: SearchContext): BN
return searchResults.length > 0 ? becca.notes[searchResults[0].noteId] : null; return searchResults.length > 0 ? becca.notes[searchResults[0].noteId] : null;
} }
function searchNotesForAutocomplete(query: string) { function searchNotesForAutocomplete(query: string, fastSearch: boolean = true) {
const searchContext = new SearchContext({ const searchContext = new SearchContext({
fastSearch: true, fastSearch: fastSearch,
includeArchivedNotes: false, includeArchivedNotes: false,
includeHiddenNotes: true, includeHiddenNotes: true,
fuzzyAttributeSearch: true, fuzzyAttributeSearch: true,