diff --git a/src/public/app/services/load_results.js b/src/public/app/services/load_results.js index fe71831aa..faf985bc8 100644 --- a/src/public/app/services/load_results.js +++ b/src/public/app/services/load_results.js @@ -97,7 +97,7 @@ export default class LoadResults { } addNoteContent(noteIds, componentId) { - for (const noteId of noteIds) { + for (const noteId of noteIds || []) { this.contentNoteIdToComponentId.push({noteId, componentId}); } } diff --git a/src/services/export/single.js b/src/services/export/single.js index 6158731cf..24b18bf75 100644 --- a/src/services/export/single.js +++ b/src/services/export/single.js @@ -4,16 +4,17 @@ const mimeTypes = require('mime-types'); const html = require('html'); const utils = require('../utils'); const mdService = require('./md'); +const becca = require("../../becca/becca"); function exportSingleNote(taskContext, branch, format, res) { const note = branch.getNote(); if (note.type === 'image' || note.type === 'file') { - return [400, `Note type ${note.type} cannot be exported as single file.`]; + return [400, `Note type '${note.type}' cannot be exported as single file.`]; } if (format !== 'html' && format !== 'markdown') { - return [400, `Unrecognized format ${format}`]; + return [400, `Unrecognized format '${format}'`]; } let payload, extension, mime; @@ -22,6 +23,8 @@ function exportSingleNote(taskContext, branch, format, res) { if (note.type === 'text') { if (format === 'html') { + content = inlineAttachmentImages(content); + if (!content.toLowerCase().includes("${content}`; } @@ -47,9 +50,9 @@ function exportSingleNote(taskContext, branch, format, res) { mime = 'application/json'; } - const filename = `${note.title}.${extension}`; + const fileName = `${note.title}.${extension}`; - res.setHeader('Content-Disposition', utils.getContentDisposition(filename)); + res.setHeader('Content-Disposition', utils.getContentDisposition(fileName)); res.setHeader('Content-Type', `${mime}; charset=UTF-8`); res.send(payload); @@ -58,6 +61,34 @@ function exportSingleNote(taskContext, branch, format, res) { taskContext.taskSucceeded(); } +function inlineAttachmentImages(content) { + const re = /src="[^"]*api\/attachments\/([a-zA-Z0-9_]+)\/image\/?[^"]+"/g; + let match; + + while (match = re.exec(content)) { + const attachment = becca.getAttachment(match[1]); + if (!attachment) { + continue; + } + + if (!attachment.mime.startsWith('image/')) { + continue; + } + + const attachmentContent = attachment.getContent(); + if (!Buffer.isBuffer(attachmentContent)) { + continue; + } + + const base64Content = attachmentContent.toString('base64'); + const srcValue = `data:${attachment.mime};base64,${base64Content}`; + + content = content.replaceAll(match[0], `src="${srcValue}"`); + } + + return content; +} + module.exports = { exportSingleNote }; diff --git a/src/services/export/zip.js b/src/services/export/zip.js index a40bca8bd..7acacb864 100644 --- a/src/services/export/zip.js +++ b/src/services/export/zip.js @@ -174,15 +174,14 @@ async function exportToZip(taskContext, branch, format, res, setHeaders = true) if (attachments.length > 0) { meta.attachments = attachments - .filter(attachment => ["canvasSvg", "mermaidSvg"].includes(attachment.name)) .map(attachment => ({ - - name: attachment.name, + title: attachment.title, + role: attachment.role, mime: attachment.mime, dataFileName: getDataFileName( null, attachment.mime, - baseFileName + "_" + attachment.name, + baseFileName + "_" + attachment.title, existingFileNames ) }));