From cd653b9f0c1ac5402bddfe63c7282ee84cead96b Mon Sep 17 00:00:00 2001 From: zadam Date: Fri, 8 Jan 2021 21:44:43 +0100 Subject: [PATCH] add link dialog should recognize external links, closes #1521 --- package-lock.json | 6 +- package.json | 4 +- src/public/app/dialogs/add_link.js | 62 ++++++++++++++------ src/public/app/services/note_autocomplete.js | 47 ++++++++++++++- src/views/dialogs/add_link.ejs | 8 +-- 5 files changed, 99 insertions(+), 28 deletions(-) diff --git a/package-lock.json b/package-lock.json index ca0fc60f1..aa759f4a7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2361,9 +2361,9 @@ } }, "dayjs": { - "version": "1.10.1", - "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.10.1.tgz", - "integrity": "sha512-2xg7JrHQeLBQFkvTumLoy62x1siyeocc98QwjtURgvRqOPYmAkMUdmSjrOA+MlmL6QMQn5MUhDf6rNZNuPc1LQ==" + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.10.2.tgz", + "integrity": "sha512-h/YtykNNTR8Qgtd1Fxl5J1/SFP1b7SOk/M1P+Re+bCdFMV0IMkuKNgHPN7rlvvuhfw24w0LX78iYKt4YmePJNQ==" }, "debug": { "version": "4.1.1", diff --git a/package.json b/package.json index abc18103c..9e63a9f54 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,7 @@ "commonmark": "0.29.3", "cookie-parser": "1.4.5", "csurf": "1.11.0", - "dayjs": "1.10.1", + "dayjs": "1.10.2", "ejs": "3.1.5", "electron-debug": "3.2.0", "electron-dl": "3.0.2", @@ -54,7 +54,7 @@ "mime-types": "2.1.28", "multer": "1.4.2", "node-abi": "2.19.3", - "open": "7.3.0", + "open": "7.3.1", "portscanner": "2.2.0", "rand-token": "1.0.1", "request": "^2.88.2", diff --git a/src/public/app/dialogs/add_link.js b/src/public/app/dialogs/add_link.js index 5da0b6b44..3e5bc5d1b 100644 --- a/src/public/app/dialogs/add_link.js +++ b/src/public/app/dialogs/add_link.js @@ -7,6 +7,7 @@ const $form = $("#add-link-form"); const $autoComplete = $("#add-link-note-autocomplete"); const $linkTitle = $("#link-title"); const $addLinkTitleSettings = $("#add-link-title-settings"); +const $addLinkTitleRadios = $(".add-link-title-radios"); const $addLinkTitleFormGroup = $("#add-link-title-form-group"); /** @var TextTypeWidget */ @@ -17,7 +18,7 @@ export async function showDialog(widget, text = '') { $addLinkTitleSettings.toggle(!textTypeWidget.hasSelection()); - $addLinkTitleSettings.find('input[type=radio]').on('change', updateTitleFormGroupVisibility); + $addLinkTitleSettings.find('input[type=radio]').on('change', updateTitleSettingsVisibility); // with selection hyper link is implied if (textTypeWidget.hasSelection()) { @@ -27,7 +28,7 @@ export async function showDialog(widget, text = '') { $addLinkTitleSettings.find("input[value='reference-link']").prop("checked", true); } - updateTitleFormGroupVisibility(); + updateTitleSettingsVisibility(); utils.openDialog($dialog); @@ -40,13 +41,15 @@ export async function showDialog(widget, text = '') { $linkTitle.val(noteTitle); } - noteAutocompleteService.initNoteAutocomplete($autoComplete); + noteAutocompleteService.initNoteAutocomplete($autoComplete, { allowExternalLinks: true }); - $autoComplete.on('autocomplete:noteselected', function(event, suggestion, dataset) { + $autoComplete.on('autocomplete:noteselected', (event, suggestion, dataset) => { if (!suggestion.notePath) { return false; } + updateTitleSettingsVisibility(); + const noteId = treeService.getNoteIdFromNotePath(suggestion.notePath); if (noteId) { @@ -54,11 +57,26 @@ export async function showDialog(widget, text = '') { } }); - $autoComplete.on('autocomplete:cursorchanged', function(event, suggestion, dataset) { - const noteId = treeService.getNoteIdFromNotePath(suggestion.notePath); + $autoComplete.on('autocomplete:externallinkselected', (event, suggestion, dataset) => { + if (!suggestion.externalLink) { + return false; + } - if (noteId) { - setDefaultLinkTitle(noteId); + updateTitleSettingsVisibility(); + + $linkTitle.val(suggestion.externalLink); + }); + + $autoComplete.on('autocomplete:cursorchanged', function(event, suggestion, dataset) { + if (suggestion.externalLink) { + $linkTitle.val(suggestion.externalLink) + } + else { + const noteId = treeService.getNoteIdFromNotePath(suggestion.notePath); + + if (noteId) { + setDefaultLinkTitle(noteId); + } } }); @@ -69,31 +87,41 @@ export async function showDialog(widget, text = '') { noteAutocompleteService.showRecentNotes($autoComplete); } - $autoComplete.trigger('focus'); + $autoComplete + .trigger('focus') + .trigger('select'); // to be able to quickly remove entered text } function getLinkType() { + if ($autoComplete.getSelectedExternalLink()) { + return 'external-link'; + } + return $addLinkTitleSettings.find('input[type=radio]:checked').val(); } -function updateTitleFormGroupVisibility() { - const visible = getLinkType() === 'hyper-link'; +function updateTitleSettingsVisibility() { + const linkType = getLinkType(); - $addLinkTitleFormGroup.toggle(visible); + $addLinkTitleFormGroup.toggle(linkType !== 'reference-link'); + $addLinkTitleRadios.toggle(linkType !== 'external-link') } $form.on('submit', () => { - const notePath = $autoComplete.getSelectedNotePath(); - - if (notePath) { + if ($autoComplete.getSelectedNotePath()) { $dialog.modal('hide'); const linkTitle = getLinkType() === 'reference-link' ? null : $linkTitle.val(); - textTypeWidget.addLink(notePath, linkTitle); + textTypeWidget.addLink($autoComplete.getSelectedNotePath(), linkTitle); + } + else if ($autoComplete.getSelectedExternalLink()) { + $dialog.modal('hide'); + + textTypeWidget.addLink($autoComplete.getSelectedExternalLink(), $linkTitle.val()); } else { - logError("No path to add link."); + logError("No link to add."); } return false; diff --git a/src/public/app/services/note_autocomplete.js b/src/public/app/services/note_autocomplete.js index 7b7203cf6..6d847a1cd 100644 --- a/src/public/app/services/note_autocomplete.js +++ b/src/public/app/services/note_autocomplete.js @@ -7,6 +7,8 @@ import treeService from './tree.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"; + async function autocompleteSourceForCKEditor(queryText) { return await new Promise((res, rej) => { autocompleteSource(queryText, rows => { @@ -25,7 +27,7 @@ async function autocompleteSourceForCKEditor(queryText) { }); } -async function autocompleteSource(term, cb) { +async function autocompleteSource(term, cb, options = {}) { const activeNoteId = appContext.tabManager.getActiveTabNoteId(); let results = await server.get('autocomplete' @@ -43,6 +45,16 @@ async function autocompleteSource(term, cb) { ].concat(results); } + if (term.match(/^[a-z]+:\/\/.+/i) && options.allowExternalLinks) { + results = [ + { + action: 'external-link', + externalLink: term, + highlightedNotePathTitle: `Insert external link to "${term}"` + } + ].concat(results); + } + cb(results); } @@ -130,7 +142,7 @@ function initNoteAutocomplete($el, options) { tabAutocomplete: false }, [ { - source: autocompleteSource, + source: (term, cb) => autocompleteSource(term, cb, options), displayKey: 'notePathTitle', templates: { suggestion: suggestion => suggestion.highlightedNotePathTitle @@ -141,6 +153,19 @@ function initNoteAutocomplete($el, options) { ]); $el.on('autocomplete:selected', async (event, suggestion) => { + if (suggestion.action === 'external-link') { + $el.setSelectedNotePath(null); + $el.setSelectedExternalLink(suggestion.externalLink); + + $el.autocomplete("val", suggestion.externalLink); + + $el.autocomplete("close"); + + $el.trigger('autocomplete:externallinkselected', [suggestion]); + + return; + } + if (suggestion.action === 'create-note') { const {note} = await noteCreateService.createNote(suggestion.parentNoteId, { title: suggestion.noteTitle, @@ -151,6 +176,7 @@ function initNoteAutocomplete($el, options) { } $el.setSelectedNotePath(suggestion.notePath); + $el.setSelectedExternalLink(null); $el.autocomplete("val", suggestion.noteTitle); @@ -204,6 +230,23 @@ function init() { .toggleClass("disabled", !notePath.trim()) .attr(SELECTED_NOTE_PATH_KEY, notePath); // we also set attr here so tooltip can be displayed }; + + $.fn.getSelectedExternalLink = function () { + if (!$(this).val().trim()) { + return ""; + } else { + return $(this).attr(SELECTED_EXTERNAL_LINK_KEY); + } + }; + + $.fn.setSelectedExternalLink = function (externalLink) { + $(this).attr(SELECTED_EXTERNAL_LINK_KEY, externalLink); + + $(this) + .closest(".input-group") + .find(".go-to-selected-note-button") + .toggleClass("disabled", true); + } } export default { diff --git a/src/views/dialogs/add_link.ejs b/src/views/dialogs/add_link.ejs index c6c4e702f..0bbc1f3ff 100644 --- a/src/views/dialogs/add_link.ejs +++ b/src/views/dialogs/add_link.ejs @@ -2,7 +2,7 @@