mirror of
https://github.com/zadam/trilium.git
synced 2025-03-01 14:22:32 +01:00
Merge remote-tracking branch 'origin/beta' into beta
This commit is contained in:
commit
055bb39e4d
@ -1613,16 +1613,12 @@ class BNote extends AbstractBeccaEntity {
|
|||||||
|
|
||||||
revision.save(); // to generate revisionId, which is then used to save attachments
|
revision.save(); // to generate revisionId, which is then used to save attachments
|
||||||
|
|
||||||
if (this.type === 'text') {
|
|
||||||
for (const noteAttachment of this.getAttachments()) {
|
for (const noteAttachment of this.getAttachments()) {
|
||||||
if (noteAttachment.utcDateScheduledForErasureSince) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const revisionAttachment = noteAttachment.copy();
|
const revisionAttachment = noteAttachment.copy();
|
||||||
revisionAttachment.ownerId = revision.revisionId;
|
revisionAttachment.ownerId = revision.revisionId;
|
||||||
revisionAttachment.setContent(noteAttachment.getContent(), {forceSave: true});
|
revisionAttachment.setContent(noteAttachment.getContent(), {forceSave: true});
|
||||||
|
|
||||||
|
if (this.type === 'text') {
|
||||||
// content is rewritten to point to the revision attachments
|
// content is rewritten to point to the revision attachments
|
||||||
noteContent = noteContent.replaceAll(`attachments/${noteAttachment.attachmentId}`,
|
noteContent = noteContent.replaceAll(`attachments/${noteAttachment.attachmentId}`,
|
||||||
`attachments/${revisionAttachment.attachmentId}`);
|
`attachments/${revisionAttachment.attachmentId}`);
|
||||||
|
@ -86,6 +86,29 @@ class BRevision extends AbstractBeccaEntity {
|
|||||||
return this._getContent();
|
return this._getContent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {*}
|
||||||
|
* @throws Error in case of invalid JSON */
|
||||||
|
getJsonContent() {
|
||||||
|
const content = this.getContent();
|
||||||
|
|
||||||
|
if (!content || !content.trim()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return JSON.parse(content);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @returns {*|null} valid object or null if the content cannot be parsed as JSON */
|
||||||
|
getJsonContentSafely() {
|
||||||
|
try {
|
||||||
|
return this.getJsonContent();
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param content
|
* @param content
|
||||||
* @param {object} [opts]
|
* @param {object} [opts]
|
||||||
@ -105,6 +128,45 @@ class BRevision extends AbstractBeccaEntity {
|
|||||||
.map(row => new BAttachment(row));
|
.map(row => new BAttachment(row));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @returns {BAttachment|null} */
|
||||||
|
getAttachmentById(attachmentId, opts = {}) {
|
||||||
|
opts.includeContentLength = !!opts.includeContentLength;
|
||||||
|
|
||||||
|
const query = opts.includeContentLength
|
||||||
|
? `SELECT attachments.*, LENGTH(blobs.content) AS contentLength
|
||||||
|
FROM attachments
|
||||||
|
JOIN blobs USING (blobId)
|
||||||
|
WHERE ownerId = ? AND attachmentId = ? AND isDeleted = 0`
|
||||||
|
: `SELECT * FROM attachments WHERE ownerId = ? AND attachmentId = ? AND isDeleted = 0`;
|
||||||
|
|
||||||
|
return sql.getRows(query, [this.revisionId, attachmentId])
|
||||||
|
.map(row => new BAttachment(row))[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @returns {BAttachment[]} */
|
||||||
|
getAttachmentsByRole(role) {
|
||||||
|
return sql.getRows(`
|
||||||
|
SELECT attachments.*
|
||||||
|
FROM attachments
|
||||||
|
WHERE ownerId = ?
|
||||||
|
AND role = ?
|
||||||
|
AND isDeleted = 0
|
||||||
|
ORDER BY position`, [this.revisionId, role])
|
||||||
|
.map(row => new BAttachment(row));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @returns {BAttachment} */
|
||||||
|
getAttachmentByTitle(title) {
|
||||||
|
return sql.getRows(`
|
||||||
|
SELECT attachments.*
|
||||||
|
FROM attachments
|
||||||
|
WHERE ownerId = ?
|
||||||
|
AND title = ?
|
||||||
|
AND isDeleted = 0
|
||||||
|
ORDER BY position`, [this.revisionId, title])
|
||||||
|
.map(row => new BAttachment(row))[0];
|
||||||
|
}
|
||||||
|
|
||||||
beforeSaving() {
|
beforeSaving() {
|
||||||
super.beforeSaving();
|
super.beforeSaving();
|
||||||
|
|
||||||
|
@ -45,6 +45,7 @@ const TPL = `
|
|||||||
<a class="dropdown-item export-note-button">Export note</a>
|
<a class="dropdown-item export-note-button">Export note</a>
|
||||||
<a class="dropdown-item delete-note-button">Delete note</a>
|
<a class="dropdown-item delete-note-button">Delete note</a>
|
||||||
<a data-trigger-command="printActiveNote" class="dropdown-item print-active-note-button"><kbd data-command="printActiveNote"></kbd> Print note</a>
|
<a data-trigger-command="printActiveNote" class="dropdown-item print-active-note-button"><kbd data-command="printActiveNote"></kbd> Print note</a>
|
||||||
|
<a data-trigger-command="forceSaveRevision" class="dropdown-item save-revision-button"><kbd data-command="forceSaveRevision"></kbd> Save revision</a>
|
||||||
</div>
|
</div>
|
||||||
</div>`;
|
</div>`;
|
||||||
|
|
||||||
|
@ -274,26 +274,11 @@ export default class RevisionsDialog extends BasicWidget {
|
|||||||
|
|
||||||
this.$content.html($table);
|
this.$content.html($table);
|
||||||
} else if (revisionItem.type === 'canvas') {
|
} else if (revisionItem.type === 'canvas') {
|
||||||
/**
|
const sanitizedTitle = revisionItem.title.replace(/[^a-z0-9-.]/gi, "");
|
||||||
* FIXME: We load a font called Virgil.wof2, which originates from excalidraw.com
|
|
||||||
* REMOVE external dependency!!!! This is defined in the svg in defs.style
|
|
||||||
*/
|
|
||||||
const content = fullRevision.content;
|
|
||||||
|
|
||||||
try {
|
this.$content.html($("<img>")
|
||||||
const data = JSON.parse(content)
|
.attr("src", `api/revisions/${revisionItem.revisionId}/image/${sanitizedTitle}?${Math.random()}`)
|
||||||
const svg = data.svg || "no svg present."
|
.css("max-width", "100%"));
|
||||||
|
|
||||||
/**
|
|
||||||
* maxWidth: 100% use full width of container but do not enlarge!
|
|
||||||
* height:auto to ensure that height scales with width
|
|
||||||
*/
|
|
||||||
const $svgHtml = $(svg).css({maxWidth: "100%", height: "auto"});
|
|
||||||
this.$content.html($('<div>').append($svgHtml));
|
|
||||||
} catch (err) {
|
|
||||||
console.error("error parsing fullRevision.content as JSON", fullRevision.content, err);
|
|
||||||
this.$content.html($("<div>").text("Error parsing content. Please check console.error() for more details."));
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
this.$content.text("Preview isn't available for this note type.");
|
this.$content.text("Preview isn't available for this note type.");
|
||||||
}
|
}
|
||||||
|
@ -5,14 +5,27 @@ const becca = require('../../becca/becca');
|
|||||||
const RESOURCE_DIR = require('../../services/resource_dir').RESOURCE_DIR;
|
const RESOURCE_DIR = require('../../services/resource_dir').RESOURCE_DIR;
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
|
|
||||||
function returnImage(req, res) {
|
function returnImageFromNote(req, res) {
|
||||||
const image = becca.getNote(req.params.noteId);
|
const image = becca.getNote(req.params.noteId);
|
||||||
|
|
||||||
|
return returnImageInt(image, res);
|
||||||
|
}
|
||||||
|
|
||||||
|
function returnImageFromRevision(req, res) {
|
||||||
|
const image = becca.getRevision(req.params.revisionId);
|
||||||
|
|
||||||
|
return returnImageInt(image, res);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {BNote|BRevision} image
|
||||||
|
* @param res
|
||||||
|
*/
|
||||||
|
function returnImageInt(image, res) {
|
||||||
if (!image) {
|
if (!image) {
|
||||||
res.set('Content-Type', 'image/png');
|
res.set('Content-Type', 'image/png');
|
||||||
return res.send(fs.readFileSync(`${RESOURCE_DIR}/db/image-deleted.png`));
|
return res.send(fs.readFileSync(`${RESOURCE_DIR}/db/image-deleted.png`));
|
||||||
}
|
} else if (!["image", "canvas"].includes(image.type)) {
|
||||||
else if (!["image", "canvas"].includes(image.type)){
|
|
||||||
return res.sendStatus(400);
|
return res.sendStatus(400);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -84,7 +97,8 @@ function updateImage(req) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
returnImage,
|
returnImageFromNote,
|
||||||
|
returnImageFromRevision,
|
||||||
returnAttachedImage,
|
returnAttachedImage,
|
||||||
updateImage
|
updateImage
|
||||||
};
|
};
|
||||||
|
@ -181,6 +181,8 @@ function register(app) {
|
|||||||
apiRoute(GET, '/api/revisions/:revisionId/blob', revisionsApiRoute.getRevisionBlob);
|
apiRoute(GET, '/api/revisions/:revisionId/blob', revisionsApiRoute.getRevisionBlob);
|
||||||
apiRoute(DEL, '/api/revisions/:revisionId', revisionsApiRoute.eraseRevision);
|
apiRoute(DEL, '/api/revisions/:revisionId', revisionsApiRoute.eraseRevision);
|
||||||
apiRoute(PST, '/api/revisions/:revisionId/restore', revisionsApiRoute.restoreRevision);
|
apiRoute(PST, '/api/revisions/:revisionId/restore', revisionsApiRoute.restoreRevision);
|
||||||
|
route(GET, '/api/revisions/:revisionId/image/:filename', [auth.checkApiAuthOrElectron], imageRoute.returnImageFromRevision);
|
||||||
|
|
||||||
route(GET, '/api/revisions/:revisionId/download', [auth.checkApiAuthOrElectron], revisionsApiRoute.downloadRevision);
|
route(GET, '/api/revisions/:revisionId/download', [auth.checkApiAuthOrElectron], revisionsApiRoute.downloadRevision);
|
||||||
|
|
||||||
|
|
||||||
@ -200,7 +202,7 @@ function register(app) {
|
|||||||
apiRoute(GET, '/api/attribute-values/:attributeName', attributesRoute.getValuesForAttribute);
|
apiRoute(GET, '/api/attribute-values/:attributeName', attributesRoute.getValuesForAttribute);
|
||||||
|
|
||||||
// :filename is not used by trilium, but instead used for "save as" to assign a human-readable filename
|
// :filename is not used by trilium, but instead used for "save as" to assign a human-readable filename
|
||||||
route(GET, '/api/images/:noteId/:filename', [auth.checkApiAuthOrElectron], imageRoute.returnImage);
|
route(GET, '/api/images/:noteId/:filename', [auth.checkApiAuthOrElectron], imageRoute.returnImageFromNote);
|
||||||
route(PUT, '/api/images/:noteId', [auth.checkApiAuthOrElectron, uploadMiddlewareWithErrorHandling, csrfMiddleware], imageRoute.updateImage, apiResultHandler);
|
route(PUT, '/api/images/:noteId', [auth.checkApiAuthOrElectron, uploadMiddlewareWithErrorHandling, csrfMiddleware], imageRoute.updateImage, apiResultHandler);
|
||||||
|
|
||||||
apiRoute(GET, '/api/options', optionsApiRoute.getOptions);
|
apiRoute(GET, '/api/options', optionsApiRoute.getOptions);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user