mirror of
				https://github.com/zadam/trilium.git
				synced 2025-10-31 11:39:01 +01:00 
			
		
		
		
	note tooltip displays the whole note with scrollbar, other behavior changes. closes #4120
This commit is contained in:
		
							parent
							
								
									d0e5ad5b7e
								
							
						
					
					
						commit
						ddf75cd5e5
					
				| @ -182,8 +182,6 @@ export default class Entrypoints extends Component { | ||||
|     } | ||||
| 
 | ||||
|     hideAllPopups() { | ||||
|         $(".tooltip").removeClass("show"); | ||||
| 
 | ||||
|         if (utils.isDesktop()) { | ||||
|             $(".aa-input").autocomplete("close"); | ||||
|         } | ||||
|  | ||||
| @ -1,5 +1,6 @@ | ||||
| class FAttachment { | ||||
|     constructor(froca, row) { | ||||
|         /** @type {Froca} */ | ||||
|         this.froca = froca; | ||||
| 
 | ||||
|         this.update(row); | ||||
| @ -34,12 +35,9 @@ class FAttachment { | ||||
|         return this.froca.notes[this.ownerId]; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * @param [opts.preview=false] - retrieve only first 10 000 characters for a preview | ||||
|      * @return {FBlob} | ||||
|      */ | ||||
|     async getBlob(opts = {}) { | ||||
|         return await this.froca.getBlob('attachments', this.attachmentId, opts); | ||||
|     /** @return {FBlob} */ | ||||
|     async getBlob() { | ||||
|         return await this.froca.getBlob('attachments', this.attachmentId); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -6,6 +6,7 @@ import promotedAttributeDefinitionParser from '../services/promoted_attribute_de | ||||
|  */ | ||||
| class FAttribute { | ||||
|     constructor(froca, row) { | ||||
|         /** @type {Froca} */ | ||||
|         this.froca = froca; | ||||
| 
 | ||||
|         this.update(row); | ||||
|  | ||||
| @ -4,6 +4,7 @@ | ||||
|  */ | ||||
| class FBranch { | ||||
|     constructor(froca, row) { | ||||
|         /** @type {Froca} */ | ||||
|         this.froca = froca; | ||||
| 
 | ||||
|         this.update(row); | ||||
|  | ||||
| @ -31,6 +31,7 @@ class FNote { | ||||
|      * @param {Object.<string, Object>} row | ||||
|      */ | ||||
|     constructor(froca, row) { | ||||
|         /** @type {Froca} */ | ||||
|         this.froca = froca; | ||||
| 
 | ||||
|         /** @type {string[]} */ | ||||
| @ -859,12 +860,9 @@ class FNote { | ||||
|         return this.getBlob(); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * @param [opts.preview=false] - retrieve only first 10 000 characters for a preview | ||||
|      * @return {Promise<FBlob>} | ||||
|      */ | ||||
|     async getBlob(opts = {}) { | ||||
|         return await this.froca.getBlob('notes', this.noteId, opts); | ||||
|     /** @return {Promise<FBlob>} */ | ||||
|     async getBlob() { | ||||
|         return await this.froca.getBlob('notes', this.noteId); | ||||
|     } | ||||
| 
 | ||||
|     toString() { | ||||
|  | ||||
| @ -19,7 +19,6 @@ let idCounter = 1; | ||||
|  */ | ||||
| async function getRenderedContent(entity, options = {}) { | ||||
|     options = Object.assign({ | ||||
|         trim: false, | ||||
|         tooltip: false | ||||
|     }, options); | ||||
| 
 | ||||
| @ -29,7 +28,7 @@ async function getRenderedContent(entity, options = {}) { | ||||
|     const $renderedContent = $('<div class="rendered-content">'); | ||||
| 
 | ||||
|     if (type === 'text') { | ||||
|         await renderText(entity, options, $renderedContent); | ||||
|         await renderText(entity, $renderedContent); | ||||
|     } | ||||
|     else if (type === 'code') { | ||||
|         await renderCode(entity, options, $renderedContent); | ||||
| @ -86,12 +85,13 @@ async function getRenderedContent(entity, options = {}) { | ||||
|     }; | ||||
| } | ||||
| 
 | ||||
| async function renderText(note, options, $renderedContent) { | ||||
| /** @param {FNote} note */ | ||||
| async function renderText(note, $renderedContent) { | ||||
|     // entity must be FNote
 | ||||
|     const blob = await note.getBlob({preview: options.trim}); | ||||
|     const blob = await note.getBlob(); | ||||
| 
 | ||||
|     if (!utils.isHtmlEmpty(blob.content)) { | ||||
|         $renderedContent.append($('<div class="ck-content">').html(trim(blob.content, options.trim))); | ||||
|         $renderedContent.append($('<div class="ck-content">').html(blob.content)); | ||||
| 
 | ||||
|         if ($renderedContent.find('span.math-tex').length > 0) { | ||||
|             await libraryLoader.requireLibrary(libraryLoader.KATEX); | ||||
| @ -112,10 +112,11 @@ async function renderText(note, options, $renderedContent) { | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| async function renderCode(note, options, $renderedContent) { | ||||
|     const blob = await note.getBlob({preview: options.trim}); | ||||
| /** @param {FNote} note */ | ||||
| async function renderCode(note, $renderedContent) { | ||||
|     const blob = await note.getBlob(); | ||||
| 
 | ||||
|     $renderedContent.append($("<pre>").text(trim(blob.content, options.trim))); | ||||
|     $renderedContent.append($("<pre>").text(blob.content)); | ||||
| } | ||||
| 
 | ||||
| function renderImage(entity, $renderedContent, options = {}) { | ||||
| @ -285,15 +286,6 @@ async function renderChildrenList($renderedContent, note) { | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| function trim(text, doTrim) { | ||||
|     if (!doTrim) { | ||||
|         return text; | ||||
|     } | ||||
|     else { | ||||
|         return text.substr(0, Math.min(text.length, 2000)); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| function getRenderingType(entity) { | ||||
|     let type = entity.type || entity.role; | ||||
|     const mime = entity.mime; | ||||
|  | ||||
| @ -368,12 +368,11 @@ class Froca { | ||||
|     } | ||||
| 
 | ||||
|     /** @returns {Promise<FBlob>} */ | ||||
|     async getBlob(entityType, entityId, opts = {}) { | ||||
|         opts.preview = !!opts.preview; | ||||
|         const key = `${entityType}-${entityId}-${opts.preview}`; | ||||
|     async getBlob(entityType, entityId) { | ||||
|         const key = `${entityType}-${entityId}`; | ||||
| 
 | ||||
|         if (!this.blobPromises[key]) { | ||||
|             this.blobPromises[key] = server.get(`${entityType}/${entityId}/blob?preview=${opts.preview}`) | ||||
|             this.blobPromises[key] = server.get(`${entityType}/${entityId}/blob`) | ||||
|                 .then(row => new FBlob(row)) | ||||
|                 .catch(e => console.error(`Cannot get blob for ${entityType} '${entityId}'`)); | ||||
| 
 | ||||
|  | ||||
| @ -8,27 +8,32 @@ import appContext from "../components/app_context.js"; | ||||
| 
 | ||||
| function setupGlobalTooltip() { | ||||
|     $(document).on("mouseenter", "a", mouseEnterHandler); | ||||
|     $(document).on("mouseleave", "a", mouseLeaveHandler); | ||||
| 
 | ||||
|     // close any note tooltip after click, this fixes the problem that sometimes tooltips remained on the screen
 | ||||
|     $(document).on("click", () => $('.note-tooltip').remove()); | ||||
|     $(document).on("click", e => { | ||||
|         if ($(e.target).closest(".note-tooltip").length) { | ||||
|             // click within the tooltip shouldn't close it
 | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         $('.note-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")) { | ||||
|     if ($link.hasClass("no-tooltip-preview") || $link.hasClass("disabled")) { | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     // this is to avoid showing tooltip from inside the CKEditor link editor dialog
 | ||||
|     if ($link.closest(".ck-link-actions").length) { | ||||
|     } else if ($link.closest(".ck-link-actions").length) { | ||||
|         // this is to avoid showing tooltip from inside the CKEditor link editor dialog
 | ||||
|         return; | ||||
|     } else if ($link.closest(".note-tooltip").length) { | ||||
|         // don't show tooltip for links within tooltip
 | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
| @ -39,8 +44,21 @@ async function mouseEnterHandler() { | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     const linkId = $link.attr("data-link-id") || `link-${Math.floor(Math.random() * 1000000)}`; | ||||
|     $link.attr("data-link-id", linkId); | ||||
| 
 | ||||
|     if ($(`.${linkId}`).is(":visible")) { | ||||
|         // tooltip is already open for this link
 | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     const note = await froca.getNote(noteId); | ||||
|     const content = await renderTooltip(note); | ||||
| 
 | ||||
|     const [content] = await Promise.all([ | ||||
|         renderTooltip(note), | ||||
|         // to reduce flicker due to accidental mouseover, cursor must stay for a bit over the link for tooltip to appear
 | ||||
|         new Promise(res => setTimeout(res, 500)) | ||||
|     ]); | ||||
| 
 | ||||
|     if (utils.isHtmlEmpty(content)) { | ||||
|         return; | ||||
| @ -53,7 +71,6 @@ async function mouseEnterHandler() { | ||||
|     // 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', | ||||
|             // https://github.com/zadam/trilium/issues/2794 https://github.com/zadam/trilium/issues/2988
 | ||||
|             // with bottom this flickering happens a bit less
 | ||||
| @ -63,15 +80,19 @@ async function mouseEnterHandler() { | ||||
|             title: html, | ||||
|             html: true, | ||||
|             template: '<div class="tooltip note-tooltip" role="tooltip"><div class="arrow"></div><div class="tooltip-inner"></div></div>', | ||||
|             sanitize: false | ||||
|             sanitize: false, | ||||
|             customClass: linkId | ||||
|         }); | ||||
| 
 | ||||
|         $(this).tooltip('show'); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| function mouseLeaveHandler() { | ||||
|     $(this).tooltip('dispose'); | ||||
|         setTimeout(() => { | ||||
|             if (!$(this).is(":hover") && !$(`.${linkId}`).is(":hover")) { | ||||
|                 // cursor is neither over the link nor over the tooltip, user likely is not interested
 | ||||
|                 $(this).tooltip('dispose'); | ||||
|             } | ||||
|         }, 1000); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| async function renderTooltip(note) { | ||||
|  | ||||
| @ -471,7 +471,7 @@ table.promoted-attributes-in-tooltip td, table.promoted-attributes-in-tooltip th | ||||
| .note-tooltip-content { | ||||
|     /* height needs to stay small because tooltip has problem when it can't fit to either top or bottom of the cursor */ | ||||
|     max-height: 300px; | ||||
|     overflow: hidden; | ||||
|     overflow: auto; | ||||
| } | ||||
| 
 | ||||
| .note-tooltip-content .note-title-with-path .note-path { | ||||
|  | ||||
| @ -15,9 +15,7 @@ function getNote(req) { | ||||
| } | ||||
| 
 | ||||
| function getNoteBlob(req) { | ||||
|     const preview = req.query.preview === 'true'; | ||||
| 
 | ||||
|     return blobService.getBlobPojo('notes', req.params.noteId, { preview }); | ||||
|     return blobService.getBlobPojo('notes', req.params.noteId); | ||||
| } | ||||
| 
 | ||||
| function getNoteMetadata(req) { | ||||
|  | ||||
| @ -2,9 +2,7 @@ const becca = require('../becca/becca'); | ||||
| const NotFoundError = require("../errors/not_found_error"); | ||||
| const protectedSessionService = require("./protected_session"); | ||||
| 
 | ||||
| function getBlobPojo(entityName, entityId, opts = {}) { | ||||
|     opts.preview = !!opts.preview; | ||||
| 
 | ||||
| function getBlobPojo(entityName, entityId) { | ||||
|     const entity = becca.getEntity(entityName, entityId); | ||||
| 
 | ||||
|     if (!entity) { | ||||
| @ -19,10 +17,6 @@ function getBlobPojo(entityName, entityId, opts = {}) { | ||||
|         pojo.content = null; | ||||
|     } else { | ||||
|         pojo.content = processContent(pojo.content, entity.isProtected, true); | ||||
| 
 | ||||
|         if (opts.preview && pojo.content.length > 10000) { | ||||
|             pojo.content = `${pojo.content.substr(0, 10000)}\r\n\r\n... and ${pojo.content.length - 10000} more characters.`; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     return pojo; | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 zadam
						zadam