From 9be524ef8913f98fd1c6ac172a8c31393429db2d Mon Sep 17 00:00:00 2001 From: zadam Date: Fri, 24 Mar 2023 10:57:32 +0100 Subject: [PATCH] attachment improvements --- src/public/app/services/utils.js | 12 +++ .../widgets/buttons/attachments_actions.js | 95 +++++++++++++++++++ .../widgets/floating_buttons/zpetne_odkazy.js | 5 + src/public/app/widgets/note_title.js | 12 ++- .../ribbon_widgets/note_info_widget.js | 16 +--- .../app/widgets/type_widgets/attachments.js | 75 +++++++++------ src/public/stylesheets/style.css | 4 + src/routes/api/notes.js | 17 ++-- 8 files changed, 187 insertions(+), 49 deletions(-) create mode 100644 src/public/app/widgets/buttons/attachments_actions.js diff --git a/src/public/app/services/utils.js b/src/public/app/services/utils.js index 49edcf5ec..2041551f1 100644 --- a/src/public/app/services/utils.js +++ b/src/public/app/services/utils.js @@ -114,6 +114,17 @@ function formatLabel(label) { return str; } +function formatSize(size) { + size = Math.max(Math.round(size / 1024), 1); + + if (size < 1024) { + return `${size} KiB`; + } + else { + return `${Math.round(size / 102.4) / 10} MiB`; + } +} + function toObject(array, fn) { const obj = {}; @@ -363,6 +374,7 @@ export default { formatDate, formatDateISO, formatDateTime, + formatSize, localNowDateTime, now, isElectron, diff --git a/src/public/app/widgets/buttons/attachments_actions.js b/src/public/app/widgets/buttons/attachments_actions.js new file mode 100644 index 000000000..1fc1983b5 --- /dev/null +++ b/src/public/app/widgets/buttons/attachments_actions.js @@ -0,0 +1,95 @@ +import BasicWidget from "../basic_widget.js"; + +const TPL = ` +`; + +export default class AttachmentActionsWidget extends BasicWidget { + constructor(attachment) { + super(); + + this.attachment = attachment; + } + + doRender() { + this.$widget = $(TPL); + + // this.$findInTextButton = this.$widget.find('.find-in-text-button'); + // this.$printActiveNoteButton = this.$widget.find('.print-active-note-button'); + // this.$showSourceButton = this.$widget.find('.show-source-button'); + // this.$renderNoteButton = this.$widget.find('.render-note-button'); + // + // this.$exportNoteButton = this.$widget.find('.export-note-button'); + // this.$exportNoteButton.on("click", () => { + // if (this.$exportNoteButton.hasClass("disabled")) { + // return; + // } + // + // this.triggerCommand("showExportDialog", { + // notePath: this.noteContext.notePath, + // defaultType: "single" + // }); + // }); + // + // this.$importNoteButton = this.$widget.find('.import-files-button'); + // this.$importNoteButton.on("click", () => this.triggerCommand("showImportDialog", {noteId: this.noteId})); + // + // this.$widget.on('click', '.dropdown-item', () => this.$widget.find("[data-toggle='dropdown']").dropdown('toggle')); + // + // this.$openNoteExternallyButton = this.$widget.find(".open-note-externally-button"); + // + // this.$deleteNoteButton = this.$widget.find(".delete-note-button"); + // this.$deleteNoteButton.on("click", () => { + // if (this.note.noteId === 'root') { + // return; + // } + // + // branchService.deleteNotes([this.note.getParentBranches()[0].branchId], true); + // }); + } + + refreshWithNote(note) { + // this.toggleDisabled(this.$findInTextButton, ['text', 'code', 'book', 'search'].includes(note.type)); + // + // this.toggleDisabled(this.$showSourceButton, ['text', 'relationMap', 'mermaid'].includes(note.type)); + // + // this.toggleDisabled(this.$printActiveNoteButton, ['text', 'code'].includes(note.type)); + // + // this.$renderNoteButton.toggle(note.type === 'render'); + // + // this.$openNoteExternallyButton.toggle(utils.isElectron()); + } + + toggleDisabled($el, enable) { + if (enable) { + $el.removeAttr('disabled'); + } else { + $el.attr('disabled', 'disabled'); + } + } +} diff --git a/src/public/app/widgets/floating_buttons/zpetne_odkazy.js b/src/public/app/widgets/floating_buttons/zpetne_odkazy.js index ec896cca5..7d3c76ca3 100644 --- a/src/public/app/widgets/floating_buttons/zpetne_odkazy.js +++ b/src/public/app/widgets/floating_buttons/zpetne_odkazy.js @@ -85,6 +85,11 @@ export default class BacklinksWidget extends NoteContextAwareWidget { async refreshWithNote(note) { this.clearItems(); + if (this.noteContext?.viewScope?.viewMode !== 'default') { + this.toggle(false); + return; + } + // can't use froca since that would count only relations from loaded notes const resp = await server.get(`note-map/${this.noteId}/backlink-count`); diff --git a/src/public/app/widgets/note_title.js b/src/public/app/widgets/note_title.js index 29ebd1f35..83a5e8a15 100644 --- a/src/public/app/widgets/note_title.js +++ b/src/public/app/widgets/note_title.js @@ -70,10 +70,16 @@ export default class NoteTitleWidget extends NoteContextAwareWidget { } async refreshWithNote(note) { - this.$noteTitle.val(note.title); + const viewMode = this.noteContext.viewScope.viewMode; + this.$noteTitle.val(viewMode === 'default' + ? note.title + : `${viewMode}: ${note.title}`); - this.$noteTitle.prop("readonly", (note.isProtected && !protectedSessionHolder.isProtectedSessionAvailable()) - || ['_lbRoot', '_lbAvailableLaunchers', '_lbVisibleLaunchers'].includes(note.noteId)); + this.$noteTitle.prop("readonly", + (note.isProtected && !protectedSessionHolder.isProtectedSessionAvailable()) + || ['_lbRoot', '_lbAvailableLaunchers', '_lbVisibleLaunchers'].includes(note.noteId) + || viewMode !== 'default' + ); this.setProtectedStatus(note); } diff --git a/src/public/app/widgets/ribbon_widgets/note_info_widget.js b/src/public/app/widgets/ribbon_widgets/note_info_widget.js index 28459da5d..c463c9c0d 100644 --- a/src/public/app/widgets/ribbon_widgets/note_info_widget.js +++ b/src/public/app/widgets/ribbon_widgets/note_info_widget.js @@ -1,5 +1,6 @@ import NoteContextAwareWidget from "../note_context_aware_widget.js"; import server from "../../services/server.js"; +import utils from "../../services/utils.js"; const TPL = `
@@ -105,12 +106,12 @@ export default class NoteInfoWidget extends NoteContextAwareWidget { this.$subTreeSize.empty().append($('')); const noteSizeResp = await server.get(`stats/note-size/${this.noteId}`); - this.$noteSize.text(this.formatSize(noteSizeResp.noteSize)); + this.$noteSize.text(utils.formatSize(noteSizeResp.noteSize)); const subTreeResp = await server.get(`stats/subtree-size/${this.noteId}`); if (subTreeResp.subTreeNoteCount > 1) { - this.$subTreeSize.text(`(subtree size: ${this.formatSize(subTreeResp.subTreeSize)} in ${subTreeResp.subTreeNoteCount} notes)`); + this.$subTreeSize.text(`(subtree size: ${utils.formatSize(subTreeResp.subTreeSize)} in ${subTreeResp.subTreeNoteCount} notes)`); } else { this.$subTreeSize.text(""); @@ -143,17 +144,6 @@ export default class NoteInfoWidget extends NoteContextAwareWidget { this.$noteSizesWrapper.hide(); } - formatSize(size) { - size = Math.max(Math.round(size / 1024), 1); - - if (size < 1024) { - return `${size} KiB`; - } - else { - return `${Math.round(size / 102.4) / 10} MiB`; - } - } - entitiesReloadedEvent({loadResults}) { if (loadResults.isNoteReloaded(this.noteId) || loadResults.isNoteContentReloaded(this.noteId)) { this.refresh(); diff --git a/src/public/app/widgets/type_widgets/attachments.js b/src/public/app/widgets/type_widgets/attachments.js index 041104e9d..566550ee9 100644 --- a/src/public/app/widgets/type_widgets/attachments.js +++ b/src/public/app/widgets/type_widgets/attachments.js @@ -1,14 +1,29 @@ import TypeWidget from "./type_widget.js"; import server from "../../services/server.js"; +import utils from "../../services/utils.js"; +import AttachmentActionsWidget from "../buttons/attachments_actions.js"; const TPL = ` -
+
-
- Note attachments are pieces of data attached to a given note, providing attachment support. - This view is useful for diagnostics. -
- -
+
`; export default class AttachmentsTypeWidget extends TypeWidget { @@ -35,13 +47,14 @@ export default class AttachmentsTypeWidget extends TypeWidget { doRender() { this.$widget = $(TPL); - this.$list = this.$widget.find('.note-attachment-list'); + this.$list = this.$widget.find('.attachment-list'); super.doRender(); } async doRefresh(note) { this.$list.empty(); + this.children = []; const attachments = await server.get(`notes/${this.noteId}/attachments?includeContent=true`); @@ -52,28 +65,36 @@ export default class AttachmentsTypeWidget extends TypeWidget { } for (const attachment of attachments) { + const attachmentActionsWidget = new AttachmentActionsWidget(); + this.child(attachmentActionsWidget); + this.$list.append( - $('
') + $('
') .append( - $('

').append($('').text(attachment.name)) - ) - .append( - $('') + $('
') + .append($('

').append($('').text(attachment.title))) .append( - $('

') - .append($('
').text('Length:')) - .append($('').text(attachment.contentLength)) - .append($('').text('MIME:')) - .append($('').text(attachment.mime)) - .append($('').text('Date modified:')) - .append($('').text(attachment.utcDateModified)) + $('
') + .text(`Role: ${attachment.role}, Size: ${utils.formatSize(attachment.contentLength)}`) ) + .append($('
')) // spacer + .append(attachmentActionsWidget.render()) ) .append( - $('
')
-                            .text(attachment.content)
+                        $('
') + .append(this.renderContent(attachment)) ) ); } } + + renderContent(attachment) { + if (attachment.content) { + return $("
").text(attachment.content);
+        } else if (attachment.role === 'image') {
+            return ``;
+        } else {
+            return '';
+        }
+    }
 }
\ No newline at end of file
diff --git a/src/public/stylesheets/style.css b/src/public/stylesheets/style.css
index d7f382993..528ec8edc 100644
--- a/src/public/stylesheets/style.css
+++ b/src/public/stylesheets/style.css
@@ -119,6 +119,10 @@ button.close:hover {
     border-radius: var(--button-border-radius);
 }
 
+.icon-action-always-border {
+    border-color: var(--button-border-color);
+}
+
 .icon-action:hover:not(.disabled) {
     text-decoration: none;
     border-color: var(--button-border-color);
diff --git a/src/routes/api/notes.js b/src/routes/api/notes.js
index d52897950..8fe38b86e 100644
--- a/src/routes/api/notes.js
+++ b/src/routes/api/notes.js
@@ -142,14 +142,19 @@ function getAttachments(req) {
     return attachments.map(attachment => {
        const pojo = attachment.getPojo();
 
-       if (includeContent && utils.isStringNote(null, attachment.mime)) {
-           pojo.content = attachment.getContent()?.toString();
-           pojo.contentLength = pojo.content.length;
+       if (includeContent) {
+           if (utils.isStringNote(null, attachment.mime)) {
+               pojo.content = attachment.getContent()?.toString();
+               pojo.contentLength = pojo.content.length;
 
-           const MAX_ATTACHMENT_LENGTH = 1_000_000;
+               const MAX_ATTACHMENT_LENGTH = 1_000_000;
 
-           if (pojo.content.length > MAX_ATTACHMENT_LENGTH) {
-               pojo.content = pojo.content.substring(0, MAX_ATTACHMENT_LENGTH);
+               if (pojo.content.length > MAX_ATTACHMENT_LENGTH) {
+                   pojo.content = pojo.content.substring(0, MAX_ATTACHMENT_LENGTH);
+               }
+           } else {
+               const content = attachment.getContent();
+               pojo.contentLength = content?.length;
            }
        }