mirror of
				https://github.com/zadam/trilium.git
				synced 2025-10-31 10:26:08 +01:00 
			
		
		
		
	ancillary type widget
This commit is contained in:
		| @@ -146,8 +146,7 @@ class BNoteAncillary extends AbstractBeccaEntity { | |||||||
|             isProtected: !!this.isProtected, |             isProtected: !!this.isProtected, | ||||||
|             contentCheckSum: this.contentCheckSum, |             contentCheckSum: this.contentCheckSum, | ||||||
|             isDeleted: false, |             isDeleted: false, | ||||||
|             utcDateModified: this.utcDateModified, |             utcDateModified: this.utcDateModified | ||||||
|             content: this.content, |  | ||||||
|         }; |         }; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -166,14 +166,12 @@ class BNoteRevision extends AbstractBeccaEntity { | |||||||
|             utcDateLastEdited: this.utcDateLastEdited, |             utcDateLastEdited: this.utcDateLastEdited, | ||||||
|             utcDateCreated: this.utcDateCreated, |             utcDateCreated: this.utcDateCreated, | ||||||
|             utcDateModified: this.utcDateModified, |             utcDateModified: this.utcDateModified, | ||||||
|             content: this.content, |  | ||||||
|             contentLength: this.contentLength |             contentLength: this.contentLength | ||||||
|         }; |         }; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     getPojoToSave() { |     getPojoToSave() { | ||||||
|         const pojo = this.getPojo(); |         const pojo = this.getPojo(); | ||||||
|         delete pojo.content; // not getting persisted |  | ||||||
|         delete pojo.contentLength; // not getting persisted |         delete pojo.contentLength; // not getting persisted | ||||||
|  |  | ||||||
|         if (pojo.isProtected) { |         if (pojo.isProtected) { | ||||||
|   | |||||||
| @@ -117,11 +117,19 @@ export default class RootCommandExecutor extends Component { | |||||||
|         }); |         }); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     async showNoteSourceEvent() { |     async showNoteSourceCommand() { | ||||||
|         const notePath = appContext.tabManager.getActiveContextNotePath(); |         const notePath = appContext.tabManager.getActiveContextNotePath(); | ||||||
|  |  | ||||||
|         if (notePath) { |         if (notePath) { | ||||||
|             await appContext.tabManager.openContextWithNote(notePath, { activate: true, viewMode: 'source' }); |             await appContext.tabManager.openContextWithNote(notePath, { activate: true, viewMode: 'source' }); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     async showNoteAncillariesCommand() { | ||||||
|  |         const notePath = appContext.tabManager.getActiveContextNotePath(); | ||||||
|  |  | ||||||
|  |         if (notePath) { | ||||||
|  |             await appContext.tabManager.openContextWithNote(notePath, { activate: true, viewMode: 'ancillaries' }); | ||||||
|  |         } | ||||||
|  |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -28,6 +28,7 @@ const TPL = ` | |||||||
|         <a data-trigger-command="renderActiveNote" class="dropdown-item render-note-button"><kbd data-command="renderActiveNote"></kbd> Re-render note</a> |         <a data-trigger-command="renderActiveNote" class="dropdown-item render-note-button"><kbd data-command="renderActiveNote"></kbd> Re-render note</a> | ||||||
|         <a data-trigger-command="findInText" class="dropdown-item find-in-text-button">Search in note <kbd data-command="findInText"></a> |         <a data-trigger-command="findInText" class="dropdown-item find-in-text-button">Search in note <kbd data-command="findInText"></a> | ||||||
|         <a data-trigger-command="showNoteSource" class="dropdown-item show-source-button"><kbd data-command="showNoteSource"></kbd> Note source</a> |         <a data-trigger-command="showNoteSource" class="dropdown-item show-source-button"><kbd data-command="showNoteSource"></kbd> Note source</a> | ||||||
|  |         <a data-trigger-command="showNoteAncillaries" class="dropdown-item show-source-button"><kbd data-command="showNoteAncillaries"></kbd> Note ancillaries</a> | ||||||
|         <a data-trigger-command="openNoteExternally" class="dropdown-item open-note-externally-button"><kbd data-command="openNoteExternally"></kbd> Open note externally</a> |         <a data-trigger-command="openNoteExternally" class="dropdown-item open-note-externally-button"><kbd data-command="openNoteExternally"></kbd> Open note externally</a> | ||||||
|         <a class="dropdown-item import-files-button">Import files</a> |         <a class="dropdown-item import-files-button">Import files</a> | ||||||
|         <a class="dropdown-item export-note-button">Export note</a> |         <a class="dropdown-item export-note-button">Export note</a> | ||||||
|   | |||||||
| @@ -12,7 +12,8 @@ export default class MermaidExportButton extends NoteContextAwareWidget { | |||||||
|     isEnabled() { |     isEnabled() { | ||||||
|         return super.isEnabled() |         return super.isEnabled() | ||||||
|             && this.note?.type === 'mermaid' |             && this.note?.type === 'mermaid' | ||||||
|             && this.note.isContentAvailable(); |             && this.note.isContentAvailable() | ||||||
|  |             && this.noteContext?.viewScope.viewMode === 'default'; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     doRender() { |     doRender() { | ||||||
|   | |||||||
| @@ -36,7 +36,8 @@ export default class MermaidWidget extends NoteContextAwareWidget { | |||||||
|     isEnabled() { |     isEnabled() { | ||||||
|         return super.isEnabled() |         return super.isEnabled() | ||||||
|             && this.note?.type === 'mermaid' |             && this.note?.type === 'mermaid' | ||||||
|             && this.note.isContentAvailable(); |             && this.note.isContentAvailable() | ||||||
|  |             && this.noteContext?.viewScope.viewMode === 'default'; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     doRender() { |     doRender() { | ||||||
|   | |||||||
| @@ -27,6 +27,7 @@ import NoteMapTypeWidget from "./type_widgets/note_map.js"; | |||||||
| import WebViewTypeWidget from "./type_widgets/web_view.js"; | import WebViewTypeWidget from "./type_widgets/web_view.js"; | ||||||
| import DocTypeWidget from "./type_widgets/doc.js"; | import DocTypeWidget from "./type_widgets/doc.js"; | ||||||
| import ContentWidgetTypeWidget from "./type_widgets/content_widget.js"; | import ContentWidgetTypeWidget from "./type_widgets/content_widget.js"; | ||||||
|  | import AncillariesTypeWidget from "./type_widgets/ancillaries.js"; | ||||||
|  |  | ||||||
| const TPL = ` | const TPL = ` | ||||||
| <div class="note-detail"> | <div class="note-detail"> | ||||||
| @@ -61,7 +62,8 @@ const typeWidgetClasses = { | |||||||
|     'noteMap': NoteMapTypeWidget, |     'noteMap': NoteMapTypeWidget, | ||||||
|     'webView': WebViewTypeWidget, |     'webView': WebViewTypeWidget, | ||||||
|     'doc': DocTypeWidget, |     'doc': DocTypeWidget, | ||||||
|     'contentWidget': ContentWidgetTypeWidget |     'contentWidget': ContentWidgetTypeWidget, | ||||||
|  |     'ancillaries': AncillariesTypeWidget | ||||||
| }; | }; | ||||||
|  |  | ||||||
| export default class NoteDetailWidget extends NoteContextAwareWidget { | export default class NoteDetailWidget extends NoteContextAwareWidget { | ||||||
| @@ -189,6 +191,8 @@ export default class NoteDetailWidget extends NoteContextAwareWidget { | |||||||
|  |  | ||||||
|         if (type === 'text' && this.noteContext.viewScope.viewMode === 'source') { |         if (type === 'text' && this.noteContext.viewScope.viewMode === 'source') { | ||||||
|             type = 'readOnlyCode'; |             type = 'readOnlyCode'; | ||||||
|  |         } else if (this.noteContext.viewScope.viewMode === 'ancillaries') { | ||||||
|  |             type = 'ancillaries'; | ||||||
|         } else if (type === 'text' && await this.noteContext.isReadOnly()) { |         } else if (type === 'text' && await this.noteContext.isReadOnly()) { | ||||||
|             type = 'readOnlyText'; |             type = 'readOnlyText'; | ||||||
|         } else if ((type === 'code' || type === 'mermaid') && await this.noteContext.isReadOnly()) { |         } else if ((type === 'code' || type === 'mermaid') && await this.noteContext.isReadOnly()) { | ||||||
|   | |||||||
| @@ -460,7 +460,9 @@ export default class TabRowWidget extends BasicWidget { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     updateTitle($tab, title) { |     updateTitle($tab, title) { | ||||||
|         $tab.find('.note-tab-title').text(title); |         $tab.attr("title", title) | ||||||
|  |         $tab.find('.note-tab-title') | ||||||
|  |             .text(title); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     getTabById(ntxId) { |     getTabById(ntxId) { | ||||||
|   | |||||||
							
								
								
									
										79
									
								
								src/public/app/widgets/type_widgets/ancillaries.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										79
									
								
								src/public/app/widgets/type_widgets/ancillaries.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,79 @@ | |||||||
|  | import TypeWidget from "./type_widget.js"; | ||||||
|  | import server from "../../services/server.js"; | ||||||
|  |  | ||||||
|  | const TPL = ` | ||||||
|  | <div class="note-ancillaries note-detail-printable"> | ||||||
|  |     <style> | ||||||
|  |         .note-ancillaries { | ||||||
|  |             padding: 15px; | ||||||
|  |         } | ||||||
|  |          | ||||||
|  |         .ancillary-content { | ||||||
|  |             max-height: 400px; | ||||||
|  |             background: var(--accented-background-color); | ||||||
|  |             padding: 10px; | ||||||
|  |             margin-top: 10px; | ||||||
|  |             margin-bottom: 10px; | ||||||
|  |         } | ||||||
|  |          | ||||||
|  |         .ancillary-details th { | ||||||
|  |             padding-left: 10px; | ||||||
|  |             padding-right: 10px; | ||||||
|  |         } | ||||||
|  |     </style> | ||||||
|  |  | ||||||
|  |     <div class="alert alert-info" style="margin: 10px 0 10px 0; padding: 20px;"> | ||||||
|  |         Note ancillaries are pieces of data attached to a given note, providing ancillary support.  | ||||||
|  |         This view is useful for diagnostics. | ||||||
|  |     </div> | ||||||
|  |      | ||||||
|  |     <div class="note-ancillary-list"></div> | ||||||
|  | </div>`; | ||||||
|  |  | ||||||
|  | export default class AncillariesTypeWidget extends TypeWidget { | ||||||
|  |     static getType() { return "ancillaries"; } | ||||||
|  |  | ||||||
|  |     doRender() { | ||||||
|  |         this.$widget = $(TPL); | ||||||
|  |         this.$list = this.$widget.find('.note-ancillary-list'); | ||||||
|  |  | ||||||
|  |         super.doRender(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     async doRefresh(note) { | ||||||
|  |         this.$list.empty(); | ||||||
|  |  | ||||||
|  |         const ancillaries = await server.get(`notes/${this.noteId}/ancillaries?includeContent=true`); | ||||||
|  |  | ||||||
|  |         if (ancillaries.length === 0) { | ||||||
|  |             this.$list.html("<strong>This note has no ancillaries.</strong>"); | ||||||
|  |  | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         for (const ancillary of ancillaries) { | ||||||
|  |             this.$list.append( | ||||||
|  |                 $('<div class="note-ancillary-wrapper">') | ||||||
|  |                     .append( | ||||||
|  |                         $('<h4>').append($('<span class="ancillary-name">').text(ancillary.name)) | ||||||
|  |                     ) | ||||||
|  |                     .append( | ||||||
|  |                         $('<table class="ancillary-details">') | ||||||
|  |                             .append( | ||||||
|  |                                 $('<tr>') | ||||||
|  |                                     .append($('<th>').text('Length:')) | ||||||
|  |                                     .append($('<td>').text(ancillary.contentLength)) | ||||||
|  |                                     .append($('<th>').text('MIME:')) | ||||||
|  |                                     .append($('<td>').text(ancillary.mime)) | ||||||
|  |                                     .append($('<th>').text('Date modified:')) | ||||||
|  |                                     .append($('<td>').text(ancillary.utcDateModified)) | ||||||
|  |                             ) | ||||||
|  |                     ) | ||||||
|  |                     .append( | ||||||
|  |                         $('<pre class="ancillary-content">') | ||||||
|  |                             .text(ancillary.content) | ||||||
|  |                     ) | ||||||
|  |             ); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -127,6 +127,36 @@ function setNoteTypeMime(req) { | |||||||
|     note.save(); |     note.save(); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | function getNoteAncillaries(req) { | ||||||
|  |     const includeContent = req.query.includeContent === 'true'; | ||||||
|  |     const {noteId} = req.params; | ||||||
|  |  | ||||||
|  |     const note = becca.getNote(noteId); | ||||||
|  |  | ||||||
|  |     if (!note) { | ||||||
|  |         throw new NotFoundError(`Note '${noteId}' doesn't exist.`); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     const noteAncillaries = note.getNoteAncillaries(); | ||||||
|  |  | ||||||
|  |     return noteAncillaries.map(ancillary => { | ||||||
|  |        const pojo = ancillary.getPojo(); | ||||||
|  |  | ||||||
|  |        if (includeContent && utils.isStringNote(null, ancillary.mime)) { | ||||||
|  |            pojo.content = ancillary.getContent()?.toString(); | ||||||
|  |            pojo.contentLength = pojo.content.length; | ||||||
|  |  | ||||||
|  |            const MAX_ANCILLARY_LENGTH = 1_000_000; | ||||||
|  |  | ||||||
|  |            if (pojo.content.length > MAX_ANCILLARY_LENGTH) { | ||||||
|  |                pojo.content = pojo.content.substring(0, MAX_ANCILLARY_LENGTH); | ||||||
|  |            } | ||||||
|  |        } | ||||||
|  |  | ||||||
|  |        return pojo; | ||||||
|  |     }); | ||||||
|  | } | ||||||
|  |  | ||||||
| function saveNoteAncillary(req) { | function saveNoteAncillary(req) { | ||||||
|     const {noteId, name} = req.params; |     const {noteId, name} = req.params; | ||||||
|     const {mime, content} = req.body; |     const {mime, content} = req.body; | ||||||
| @@ -354,5 +384,6 @@ module.exports = { | |||||||
|     getDeleteNotesPreview, |     getDeleteNotesPreview, | ||||||
|     uploadModifiedFile, |     uploadModifiedFile, | ||||||
|     forceSaveNoteRevision, |     forceSaveNoteRevision, | ||||||
|  |     getNoteAncillaries, | ||||||
|     saveNoteAncillary |     saveNoteAncillary | ||||||
| }; | }; | ||||||
|   | |||||||
| @@ -126,6 +126,7 @@ function register(app) { | |||||||
|     apiRoute(PUT, '/api/notes/:noteId/sort-children', notesApiRoute.sortChildNotes); |     apiRoute(PUT, '/api/notes/:noteId/sort-children', notesApiRoute.sortChildNotes); | ||||||
|     apiRoute(PUT, '/api/notes/:noteId/protect/:isProtected', notesApiRoute.protectNote); |     apiRoute(PUT, '/api/notes/:noteId/protect/:isProtected', notesApiRoute.protectNote); | ||||||
|     apiRoute(PUT, '/api/notes/:noteId/type', notesApiRoute.setNoteTypeMime); |     apiRoute(PUT, '/api/notes/:noteId/type', notesApiRoute.setNoteTypeMime); | ||||||
|  |     apiRoute(GET, '/api/notes/:noteId/ancillaries', notesApiRoute.getNoteAncillaries); | ||||||
|     apiRoute(PUT, '/api/notes/:noteId/ancillaries/:name', notesApiRoute.saveNoteAncillary); |     apiRoute(PUT, '/api/notes/:noteId/ancillaries/:name', notesApiRoute.saveNoteAncillary); | ||||||
|     apiRoute(GET, '/api/notes/:noteId/revisions', noteRevisionsApiRoute.getNoteRevisions); |     apiRoute(GET, '/api/notes/:noteId/revisions', noteRevisionsApiRoute.getNoteRevisions); | ||||||
|     apiRoute(DELETE, '/api/notes/:noteId/revisions', noteRevisionsApiRoute.eraseAllNoteRevisions); |     apiRoute(DELETE, '/api/notes/:noteId/revisions', noteRevisionsApiRoute.eraseAllNoteRevisions); | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user