From 90dbe637edc64aebdd6b96dceb0549b0d6b72edb Mon Sep 17 00:00:00 2001 From: azivner Date: Wed, 7 Nov 2018 17:16:33 +0100 Subject: [PATCH] autocomplete for add link dialog, #203 --- src/public/javascripts/dialogs/add_link.js | 61 ++++++------------- .../javascripts/dialogs/jump_to_note.js | 4 -- .../javascripts/services/note_autocomplete.js | 8 ++- src/routes/api/autocomplete.js | 5 +- src/services/note_cache.js | 9 ++- src/views/dialogs/add_link.ejs | 8 +-- 6 files changed, 39 insertions(+), 56 deletions(-) diff --git a/src/public/javascripts/dialogs/add_link.js b/src/public/javascripts/dialogs/add_link.js index c2ebd937f..d4fd54ada 100644 --- a/src/public/javascripts/dialogs/add_link.js +++ b/src/public/javascripts/dialogs/add_link.js @@ -15,7 +15,6 @@ const $prefixFormGroup = $("#add-link-prefix-form-group"); const $linkTypeDiv = $("#add-link-type-div"); const $linkTypes = $("input[name='add-link-type']"); const $linkTypeHtml = $linkTypes.filter('input[value="html"]'); -const $showRecentNotesButton = $dialog.find(".show-recent-notes-button"); function setLinkType(linkType) { $linkTypes.each(function () { @@ -51,50 +50,31 @@ async function showDialog() { $linkTitle.val(noteTitle); } - await $autoComplete.autocomplete({ - source: noteAutocompleteService.autocompleteSource, - minLength: 0, - change: async (event, ui) => { - if (!ui.item) { - return; - } + noteAutocompleteService.initNoteAutocomplete($autoComplete); - const notePath = linkService.getNotePathFromLabel(ui.item.value); + $autoComplete.on('autocomplete:selected', function(event, suggestion, dataset) { + if (!suggestion.path) { + return false; + } - if (!notePath) { - return; - } + const noteId = treeUtils.getNoteIdFromNotePath(suggestion.path); - const noteId = treeUtils.getNoteIdFromNotePath(notePath); - - if (noteId) { - await setDefaultLinkTitle(noteId); - } - }, - select: function (event, ui) { - if (ui.item.value === 'No results') { - return false; - } - }, - // this is called when user goes through autocomplete list with keyboard - // at this point the item isn't selected yet so we use supplied ui.item to see WHERE the cursor is - focus: async (event, ui) => { - const notePath = linkService.getNotePathFromLabel(ui.item.value); - const noteId = treeUtils.getNoteIdFromNotePath(notePath); - - await setDefaultLinkTitle(noteId); - - event.preventDefault(); + if (noteId) { + setDefaultLinkTitle(noteId); } }); - showRecentNotes(); + $autoComplete.on('autocomplete:cursorchanged', function(event, suggestion, dataset) { + const noteId = treeUtils.getNoteIdFromNotePath(suggestion.path); + + setDefaultLinkTitle(noteId); + }); + + noteAutocompleteService.showRecentNotes($autoComplete); } $form.submit(() => { - const value = $autoComplete.val(); - - const notePath = linkService.getNotePathFromLabel(value); + const notePath = $autoComplete.getSelectedPath(); const noteId = treeUtils.getNoteIdFromNotePath(notePath); if (notePath) { @@ -131,6 +111,9 @@ $form.submit(() => { $dialog.modal('hide'); } } + else { + console.error("No path to add link."); + } return false; }); @@ -152,14 +135,8 @@ function linkTypeChanged() { $linkTypeDiv.toggle(!hasSelection()); } -function showRecentNotes() { - $autoComplete.autocomplete("search", ""); -} - $linkTypes.change(linkTypeChanged); -$showRecentNotesButton.click(showRecentNotes); - export default { showDialog }; \ No newline at end of file diff --git a/src/public/javascripts/dialogs/jump_to_note.js b/src/public/javascripts/dialogs/jump_to_note.js index 68698163d..17ec5d29e 100644 --- a/src/public/javascripts/dialogs/jump_to_note.js +++ b/src/public/javascripts/dialogs/jump_to_note.js @@ -5,7 +5,6 @@ import noteAutocompleteService from '../services/note_autocomplete.js'; const $dialog = $("#jump-to-note-dialog"); const $autoComplete = $("#jump-to-note-autocomplete"); const $showInFullTextButton = $("#show-in-full-text-button"); -const $showRecentNotesButton = $dialog.find(".show-recent-notes-button"); $dialog.on("shown.bs.modal", e => $autoComplete.focus()); @@ -45,11 +44,8 @@ function showInFullText(e) { } - $showInFullTextButton.click(showInFullText); -$showRecentNotesButton.click(noteAutocompleteService.showRecentNotes); - $dialog.bind('keydown', 'ctrl+return', showInFullText); export default { diff --git a/src/public/javascripts/services/note_autocomplete.js b/src/public/javascripts/services/note_autocomplete.js index 9ec1a541f..d42a85c4c 100644 --- a/src/public/javascripts/services/note_autocomplete.js +++ b/src/public/javascripts/services/note_autocomplete.js @@ -44,11 +44,17 @@ function initNoteAutocomplete($el) { displayKey: 'title', templates: { suggestion: function(suggestion) { - return suggestion.title; + return suggestion.highlighted; } } } ]); + + $el.on('autocomplete:selected', function(event, suggestion, dataset) { + $el.prop("data-selected-path", suggestion.path); + }); + + $el.getSelectedPath = () => $el.prop("data-selected-path"); } return $el; diff --git a/src/routes/api/autocomplete.js b/src/routes/api/autocomplete.js index 3ccee1616..5cb7fdc6a 100644 --- a/src/routes/api/autocomplete.js +++ b/src/routes/api/autocomplete.js @@ -44,9 +44,12 @@ async function getRecentNotes(currentNoteId) { LIMIT 200`, [currentNoteId]); return recentNotes.map(rn => { + const title = noteCacheService.getNoteTitleForPath(rn.notePath.split('/')); + return { path: rn.notePath, - title: noteCacheService.getNoteTitleForPath(rn.notePath.split('/')) + title: title, + highlighted: title }; }); } diff --git a/src/services/note_cache.js b/src/services/note_cache.js index dec1aebf3..731663c62 100644 --- a/src/services/note_cache.js +++ b/src/services/note_cache.js @@ -43,11 +43,15 @@ function highlightResults(results, allTokens) { // sort by the longest so we first highlight longest matches allTokens.sort((a, b) => a.length > b.length ? -1 : 1); + for (const result of results) { + result.highlighted = result.title; + } + 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"); + result.highlighted = result.highlighted.replace(tokenRegex, "$1"); } } } @@ -58,7 +62,8 @@ function findNotes(query) { } // trim is necessary because even with .split() trailing spaces are tokens which causes havoc - const allTokens = query.trim().toLowerCase().split(" "); + // filtering '/' because it's used as separator + const allTokens = query.trim().toLowerCase().split(" ").filter(token => token !== '/'); const tokens = allTokens.slice(); const results = []; diff --git a/src/views/dialogs/add_link.ejs b/src/views/dialogs/add_link.ejs index e0ac06700..08902ee9d 100644 --- a/src/views/dialogs/add_link.ejs +++ b/src/views/dialogs/add_link.ejs @@ -1,4 +1,4 @@ -