diff --git a/src/public/javascripts/dialogs/jump_to_note.js b/src/public/javascripts/dialogs/jump_to_note.js index bd6e4cd1f..6dca4d272 100644 --- a/src/public/javascripts/dialogs/jump_to_note.js +++ b/src/public/javascripts/dialogs/jump_to_note.js @@ -21,51 +21,29 @@ async function showDialog() { appendTo: document.querySelector('body'), hint: false, autoselect: true, - openOnFocus: true + openOnFocus: true, + minLength: 0 }, [ { source: noteautocompleteService.autocompleteSource, - displayKey: 'label', + displayKey: 'title', templates: { suggestion: function(suggestion) { - return suggestion.label; + return suggestion.title; } } } ]).on('autocomplete:selected', function(event, suggestion, dataset) { - console.log("selected: ", event, suggestion, dataset); - return; - - if (ui.item.value === 'No results') { + if (!suggestion.path) { return false; } - const notePath = linkService.getNotePathFromLabel(ui.item.value); - - treeService.activateNote(notePath); + treeService.activateNote(suggestion.path); $dialog.modal('hide'); }); - // await $autoComplete.autocomplete({ - // source: noteautocompleteService.autocompleteSource, - // focus: event => event.preventDefault(), - // minLength: 0, - // autoFocus: true, - // select: function (event, ui) { - // if (ui.item.value === 'No results') { - // return false; - // } - // - // const notePath = linkService.getNotePathFromLabel(ui.item.value); - // - // treeService.activateNote(notePath); - // - // $dialog.modal('hide'); - // } - // }); - - //showRecentNotes(); + showRecentNotes(); } function showInFullText(e) { @@ -83,7 +61,8 @@ function showInFullText(e) { } function showRecentNotes() { - $autoComplete.autocomplete("search", ""); + $autoComplete.autocomplete("val", ""); + $autoComplete.autocomplete("open"); } $showInFullTextButton.click(showInFullText); diff --git a/src/public/javascripts/services/note_autocomplete.js b/src/public/javascripts/services/note_autocomplete.js index 097148ac7..c9d9b6188 100644 --- a/src/public/javascripts/services/note_autocomplete.js +++ b/src/public/javascripts/services/note_autocomplete.js @@ -6,20 +6,14 @@ async function autocompleteSource(term, cb) { + '?query=' + encodeURIComponent(term) + '¤tNoteId=' + noteDetailService.getCurrentNoteId()); - if (result.length > 0) { - cb(result.map(row => { - return { - label: row.label, - value: row.label + ' (' + row.value + ')' - } - })); - } - else { - cb([{ - label: "No results", - value: "No results" - }]); + if (result.length === 0) { + result.push({ + title: "No results", + path: "" + }); } + + cb(result); } async function initNoteAutocomplete($el) { diff --git a/src/routes/api/autocomplete.js b/src/routes/api/autocomplete.js index 637feef1b..3ccee1616 100644 --- a/src/routes/api/autocomplete.js +++ b/src/routes/api/autocomplete.js @@ -25,12 +25,7 @@ async function getAutocomplete(req) { log.info(`Slow autocomplete took ${msTaken}ms`); } - return results.map(res => { - return { - value: res.path, - label: res.title - } - }); + return results; } async function getRecentNotes(currentNoteId) { diff --git a/src/services/note_cache.js b/src/services/note_cache.js index c785ec175..dec1aebf3 100644 --- a/src/services/note_cache.js +++ b/src/services/note_cache.js @@ -35,12 +35,31 @@ async function load() { loaded = true; } +function highlightResults(results, allTokens) { + // we remove < signs because they can cause trouble in matching and overwriting existing highlighted chunks + // which would make the resulting HTML string invalid. + allTokens = allTokens.map(token => token.replace('/ a.length > b.length ? -1 : 1); + + for (const token of allTokens) { + const tokenRegex = new RegExp("(" + utils.escapeRegExp(token) + ")", "gi"); + + for (const result of results) { + result.title = result.title.replace(tokenRegex, "$1"); + } + } +} + function findNotes(query) { if (!noteTitles || !query.length) { return []; } - const tokens = query.toLowerCase().split(" "); + // trim is necessary because even with .split() trailing spaces are tokens which causes havoc + const allTokens = query.trim().toLowerCase().split(" "); + const tokens = allTokens.slice(); const results = []; let noteIds = Object.keys(noteTitles); @@ -91,6 +110,8 @@ function findNotes(query) { results.sort((a, b) => a.title < b.title ? -1 : 1); + highlightResults(results, allTokens); + return results; } diff --git a/src/services/utils.js b/src/services/utils.js index 9e79bb14e..e88f2cf60 100644 --- a/src/services/utils.js +++ b/src/services/utils.js @@ -114,6 +114,10 @@ function union(a, b) { return res; } +function escapeRegExp(str) { + return str.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, "\\$1"); +} + module.exports = { randomSecureToken, randomString, @@ -132,5 +136,6 @@ module.exports = { toObject, stripTags, intersection, - union + union, + escapeRegExp }; \ No newline at end of file diff --git a/src/views/dialogs/jump_to_note.ejs b/src/views/dialogs/jump_to_note.ejs index 491539e49..378ea0125 100644 --- a/src/views/dialogs/jump_to_note.ejs +++ b/src/views/dialogs/jump_to_note.ejs @@ -1,4 +1,4 @@ -