diff --git a/src/public/javascripts/services/bootstrap.js b/src/public/javascripts/services/bootstrap.js index a15072a17..2aaee1f1c 100644 --- a/src/public/javascripts/services/bootstrap.js +++ b/src/public/javascripts/services/bootstrap.js @@ -28,7 +28,7 @@ import treeUtils from './tree_utils.js'; import utils from './utils.js'; import server from './server.js'; import entrypoints from './entrypoints.js'; -import tooltip from './tooltip.js'; +import noteTooltipService from './note_tooltip.js'; import bundle from "./bundle.js"; import treeCache from "./tree_cache.js"; import libraryLoader from "./library_loader.js"; @@ -141,6 +141,6 @@ treeService.showTree(); entrypoints.registerEntrypoints(); -tooltip.setupTooltip(); +noteTooltipService.setupGlobalTooltip(); bundle.executeStartupBundles(); diff --git a/src/public/javascripts/services/frontend_script_api.js b/src/public/javascripts/services/frontend_script_api.js index 229afa98d..df7d33103 100644 --- a/src/public/javascripts/services/frontend_script_api.js +++ b/src/public/javascripts/services/frontend_script_api.js @@ -6,6 +6,7 @@ import linkService from './link.js'; import treeCache from './tree_cache.js'; import noteDetailService from './note_detail.js'; import noteTypeService from './note_type.js'; +import noteTooltipService from './note_tooltip.js'; /** * This is the main frontend API interface for scripts. It's published in the local "api" object. @@ -225,6 +226,12 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null) { * @param {array} types - list of mime types to be used */ this.setCodeMimeTypes = noteTypeService.setCodeMimeTypes; + + /** + * @method + * @param {object} $el - jquery object on which to setup the tooltip + */ + this.setupElementTooltip = noteTooltipService.setupElementTooltip } export default FrontendScriptApi; \ No newline at end of file diff --git a/src/public/javascripts/services/tooltip.js b/src/public/javascripts/services/note_tooltip.js similarity index 53% rename from src/public/javascripts/services/tooltip.js rename to src/public/javascripts/services/note_tooltip.js index 8f3ea5327..c3f6caccb 100644 --- a/src/public/javascripts/services/tooltip.js +++ b/src/public/javascripts/services/note_tooltip.js @@ -3,64 +3,72 @@ import treeUtils from "./tree_utils.js"; import linkService from "./link.js"; import server from "./server.js"; -function setupTooltip() { - $(document).on("mouseenter", "a", async function() { - const $link = $(this); - - if ($link.hasClass("no-tooltip-preview") || $link.hasClass("disabled")) { - return; - } - - // this is to avoid showing tooltip from inside CKEditor link editor dialog - if ($link.closest(".ck-link-actions").length) { - return; - } - - let notePath = linkService.getNotePathFromUrl($link.attr("href")); - - if (!notePath) { - notePath = $link.attr("data-note-path"); - } - - if (!notePath) { - return; - } - - const noteId = treeUtils.getNoteIdFromNotePath(notePath); - - const notePromise = noteDetailService.loadNote(noteId); - const attributePromise = server.get('notes/' + noteId + '/attributes'); - - const [note, attributes] = await Promise.all([notePromise, attributePromise]); - - const html = await renderTooltip(note, attributes); - - // we need to check if we're still hovering over the element - // since the operation to get tooltip content was async, it is possible that - // we now create tooltip which won't close because it won't receive mouseleave event - if ($(this).is(":hover")) { - $(this).tooltip({ - delay: {"show": 300, "hide": 100}, - container: 'body', - placement: 'auto', - trigger: 'manual', - boundary: 'window', - title: html, - html: true - }); - - $(this).tooltip('show'); - } - }); - - $(document).on("mouseleave", "a", function() { - $(this).tooltip('dispose'); - }); +function setupGlobalTooltip() { + $(document).on("mouseenter", "a", mouseEnterHandler); + $(document).on("mouseleave", "a", mouseLeaveHandler); // close any tooltip after click, this fixes the problem that sometimes tooltips remained on the screen $(document).on("click", () => $('.tooltip').remove()); } +function setupElementTooltip($el) { + $el.on('mouseenter', mouseEnterHandler); + $el.on('mouseleave', mouseLeaveHandler); +} + +async function mouseEnterHandler() { + const $link = $(this); + + if ($link.hasClass("no-tooltip-preview") || $link.hasClass("disabled")) { + return; + } + + // this is to avoid showing tooltip from inside CKEditor link editor dialog + if ($link.closest(".ck-link-actions").length) { + return; + } + + let notePath = linkService.getNotePathFromUrl($link.attr("href")); + + if (!notePath) { + notePath = $link.attr("data-note-path"); + } + + if (!notePath) { + return; + } + + const noteId = treeUtils.getNoteIdFromNotePath(notePath); + + const notePromise = noteDetailService.loadNote(noteId); + const attributePromise = server.get('notes/' + noteId + '/attributes'); + + const [note, attributes] = await Promise.all([notePromise, attributePromise]); + + const html = await renderTooltip(note, attributes); + + // we need to check if we're still hovering over the element + // since the operation to get tooltip content was async, it is possible that + // we now create tooltip which won't close because it won't receive mouseleave event + if ($(this).is(":hover")) { + $(this).tooltip({ + delay: {"show": 300, "hide": 100}, + container: 'body', + placement: 'auto', + trigger: 'manual', + boundary: 'window', + title: html, + html: true + }); + + $(this).tooltip('show'); + } +} + +function mouseLeaveHandler() { + $(this).tooltip('dispose'); +} + async function renderTooltip(note, attributes) { let content = ''; const promoted = attributes.filter(attr => @@ -103,7 +111,9 @@ async function renderTooltip(note, attributes) { } if (note.type === 'text') { - content += note.content; + // surround with
for a case when note.content is pure text (e.g. "[protected]") which + // then fails the jquery non-empty text test + content += '
' + note.content + '
'; } else if (note.type === 'code') { content += $("
")
@@ -125,5 +135,6 @@ async function renderTooltip(note, attributes) {
 }
 
 export default {
-    setupTooltip
+    setupGlobalTooltip,
+    setupElementTooltip
 }
\ No newline at end of file