mirror of
https://github.com/zadam/trilium.git
synced 2025-06-06 18:08:33 +02:00
reverted incomplete work on export per-directory metadata
This commit is contained in:
parent
f8ade4d0c5
commit
a45b801a84
@ -16,7 +16,6 @@ const archiver = require('archiver');
|
|||||||
const log = require("../log");
|
const log = require("../log");
|
||||||
const TaskContext = require("../task_context");
|
const TaskContext = require("../task_context");
|
||||||
const ValidationError = require("../../errors/validation_error");
|
const ValidationError = require("../../errors/validation_error");
|
||||||
const MetaFile = require("../meta/meta_file");
|
|
||||||
const NoteMeta = require("../meta/note_meta");
|
const NoteMeta = require("../meta/note_meta");
|
||||||
const AttachmentMeta = require("../meta/attachment_meta");
|
const AttachmentMeta = require("../meta/attachment_meta");
|
||||||
const AttributeMeta = require("../meta/attribute_meta");
|
const AttributeMeta = require("../meta/attribute_meta");
|
||||||
@ -40,24 +39,6 @@ async function exportToZip(taskContext, branch, format, res, setHeaders = true)
|
|||||||
/** @type {Object.<string, NoteMeta>} */
|
/** @type {Object.<string, NoteMeta>} */
|
||||||
const noteIdToMeta = {};
|
const noteIdToMeta = {};
|
||||||
|
|
||||||
/** @type {Object.<string, NoteMeta>} */
|
|
||||||
const childNoteIdToParentMeta = {};
|
|
||||||
|
|
||||||
/** @type {Object.<string, NoteMeta[]>} */
|
|
||||||
const parentNoteIdToChildrenMeta = {};
|
|
||||||
|
|
||||||
function getNotePath(noteId) {
|
|
||||||
const notePath = [noteId];
|
|
||||||
|
|
||||||
let cur = noteIdToMeta[noteId];
|
|
||||||
while (cur = childNoteIdToParentMeta[cur.noteId]) {
|
|
||||||
notePath.push(cur.noteId);
|
|
||||||
}
|
|
||||||
|
|
||||||
notePath.reverse();
|
|
||||||
return notePath;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {Object.<string, int>} existingFileNames
|
* @param {Object.<string, int>} existingFileNames
|
||||||
* @param {string} fileName
|
* @param {string} fileName
|
||||||
@ -135,49 +116,13 @@ async function exportToZip(taskContext, branch, format, res, setHeaders = true)
|
|||||||
return getUniqueFilename(existingFileNames, fileName);
|
return getUniqueFilename(existingFileNames, fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {BBranch[]} branches
|
|
||||||
* @param {Object.<string, int>} existingFileNames
|
|
||||||
* @returns {MetaFile}
|
|
||||||
*/
|
|
||||||
function createMetaFileForDirectory(branches, existingFileNames = {}) {
|
|
||||||
// namespace is shared by children in the same note
|
|
||||||
const metas = [];
|
|
||||||
|
|
||||||
for (const branch of branches) {
|
|
||||||
const noteMeta = createNoteMeta(branch, existingFileNames);
|
|
||||||
|
|
||||||
// can be undefined if export is disabled for this note
|
|
||||||
if (noteMeta) {
|
|
||||||
metas.push(noteMeta);
|
|
||||||
|
|
||||||
const parentMeta = noteIdToMeta[branch.parentNoteId];
|
|
||||||
|
|
||||||
if (parentMeta) {
|
|
||||||
childNoteIdToParentMeta[noteMeta.noteId] = parentMeta;
|
|
||||||
parentNoteIdToChildrenMeta[parentMeta.noteId] = parentNoteIdToChildrenMeta[parentMeta.noteId] || [];
|
|
||||||
parentNoteIdToChildrenMeta[parentMeta.noteId].push(noteMeta);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!metas.length) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const metaFile = new MetaFile();
|
|
||||||
metaFile.formatVersion = 3;
|
|
||||||
metaFile.appVersion = packageInfo.version;
|
|
||||||
metaFile.files = metas;
|
|
||||||
return metaFile;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {BBranch} branch
|
* @param {BBranch} branch
|
||||||
|
* @param {NoteMeta} parentMeta
|
||||||
* @param {Object.<string, int>} existingFileNames
|
* @param {Object.<string, int>} existingFileNames
|
||||||
* @returns {NoteMeta|null}
|
* @returns {NoteMeta|null}
|
||||||
*/
|
*/
|
||||||
function createNoteMeta(branch, existingFileNames) {
|
function createNoteMeta(branch, parentMeta, existingFileNames) {
|
||||||
const note = branch.getNote();
|
const note = branch.getNote();
|
||||||
|
|
||||||
if (note.hasOwnedLabel('excludeFromExport')) {
|
if (note.hasOwnedLabel('excludeFromExport')) {
|
||||||
@ -192,13 +137,15 @@ async function exportToZip(taskContext, branch, format, res, setHeaders = true)
|
|||||||
baseFileName = baseFileName.substr(0, 200);
|
baseFileName = baseFileName.substr(0, 200);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const notePath = parentMeta.notePath.concat([note.noteId]);
|
||||||
|
|
||||||
if (note.noteId in noteIdToMeta) {
|
if (note.noteId in noteIdToMeta) {
|
||||||
const fileName = getUniqueFilename(existingFileNames,
|
const fileName = getUniqueFilename(existingFileNames, `${baseFileName}.clone.${format === 'html' ? 'html' : 'md'}`);
|
||||||
`${baseFileName}.clone.${format === 'html' ? 'html' : 'md'}`);
|
|
||||||
|
|
||||||
const meta = new NoteMeta();
|
const meta = new NoteMeta();
|
||||||
meta.isClone = true;
|
meta.isClone = true;
|
||||||
meta.noteId = note.noteId;
|
meta.noteId = note.noteId;
|
||||||
|
meta.notePath = notePath;
|
||||||
meta.title = note.getTitleOrProtected();
|
meta.title = note.getTitleOrProtected();
|
||||||
meta.prefix = branch.prefix;
|
meta.prefix = branch.prefix;
|
||||||
meta.dataFileName = fileName;
|
meta.dataFileName = fileName;
|
||||||
@ -210,6 +157,7 @@ async function exportToZip(taskContext, branch, format, res, setHeaders = true)
|
|||||||
const meta = new NoteMeta();
|
const meta = new NoteMeta();
|
||||||
meta.isClone = false;
|
meta.isClone = false;
|
||||||
meta.noteId = note.noteId;
|
meta.noteId = note.noteId;
|
||||||
|
meta.notePath = notePath;
|
||||||
meta.title = note.getTitleOrProtected();
|
meta.title = note.getTitleOrProtected();
|
||||||
meta.notePosition = branch.notePosition;
|
meta.notePosition = branch.notePosition;
|
||||||
meta.prefix = branch.prefix;
|
meta.prefix = branch.prefix;
|
||||||
@ -260,10 +208,23 @@ async function exportToZip(taskContext, branch, format, res, setHeaders = true)
|
|||||||
existingFileNames
|
existingFileNames
|
||||||
);
|
);
|
||||||
return attMeta;
|
return attMeta;
|
||||||
});
|
});
|
||||||
|
|
||||||
if (childBranches.length > 0) {
|
if (childBranches.length > 0) {
|
||||||
meta.dirFileName = getUniqueFilename(existingFileNames, baseFileName);
|
meta.dirFileName = getUniqueFilename(existingFileNames, baseFileName);
|
||||||
|
meta.children = [];
|
||||||
|
|
||||||
|
// namespace is shared by children in the same note
|
||||||
|
const childExistingNames = {};
|
||||||
|
|
||||||
|
for (const childBranch of childBranches) {
|
||||||
|
const note = createNoteMeta(childBranch, meta, childExistingNames);
|
||||||
|
|
||||||
|
// can be undefined if export is disabled for this note
|
||||||
|
if (note) {
|
||||||
|
meta.children.push(note);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return meta;
|
return meta;
|
||||||
@ -281,8 +242,8 @@ async function exportToZip(taskContext, branch, format, res, setHeaders = true)
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const targetPath = getNotePath(targetMeta.noteId);
|
const targetPath = targetMeta.notePath.slice();
|
||||||
const sourcePath = getNotePath(sourceMeta.noteId);
|
const sourcePath = sourceMeta.notePath.slice();
|
||||||
|
|
||||||
// > 1 for the edge case that targetPath and sourcePath are exact same (a link to itself)
|
// > 1 for the edge case that targetPath and sourcePath are exact same (a link to itself)
|
||||||
while (targetPath.length > 1 && sourcePath.length > 1 && targetPath[0] === sourcePath[0]) {
|
while (targetPath.length > 1 && sourcePath.length > 1 && targetPath[0] === sourcePath[0]) {
|
||||||
@ -367,7 +328,7 @@ async function exportToZip(taskContext, branch, format, res, setHeaders = true)
|
|||||||
|
|
||||||
if (noteMeta.format === 'html') {
|
if (noteMeta.format === 'html') {
|
||||||
if (!content.substr(0, 100).toLowerCase().includes("<html")) {
|
if (!content.substr(0, 100).toLowerCase().includes("<html")) {
|
||||||
const cssUrl = `${"../".repeat(getNotePath(noteMeta.noteId).length - 1)}style.css`;
|
const cssUrl = `${"../".repeat(noteMeta.notePath.length - 1)}style.css`;
|
||||||
const htmlTitle = utils.escapeHtml(title);
|
const htmlTitle = utils.escapeHtml(title);
|
||||||
|
|
||||||
// <base> element will make sure external links are openable - https://github.com/zadam/trilium/issues/1289#issuecomment-704066809
|
// <base> element will make sure external links are openable - https://github.com/zadam/trilium/issues/1289#issuecomment-704066809
|
||||||
@ -448,17 +409,14 @@ ${markdownContent}`;
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const metaFile = createMetaFileForDirectory(note.getChildBranches());
|
if (noteMeta.children?.length > 0) {
|
||||||
if (metaFile) {
|
const directoryPath = filePathPrefix + noteMeta.dirFileName;
|
||||||
const childFilePathPrefix = `${filePathPrefix}${noteMeta.dirFileName}/`;
|
|
||||||
|
|
||||||
// create directory
|
// create directory
|
||||||
archive.append('', { name: childFilePathPrefix, date: dateUtils.parseDateTime(note.utcDateModified) });
|
archive.append('', { name: `${directoryPath}/`, date: dateUtils.parseDateTime(note.utcDateModified) });
|
||||||
|
|
||||||
metaFile.save(archive, childFilePathPrefix);
|
for (const childMeta of noteMeta.children) {
|
||||||
|
saveNote(childMeta, `${directoryPath}/`);
|
||||||
for (const childMeta of metaFile.files) {
|
|
||||||
saveNote(childMeta, childFilePathPrefix);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -482,13 +440,11 @@ ${markdownContent}`;
|
|||||||
html += escapedTitle;
|
html += escapedTitle;
|
||||||
}
|
}
|
||||||
|
|
||||||
const childrenMeta = parentNoteIdToChildrenMeta[meta.noteId];
|
if (meta.children && meta.children.length > 0) {
|
||||||
|
|
||||||
if (childrenMeta?.length > 0) {
|
|
||||||
html += '<ul>';
|
html += '<ul>';
|
||||||
|
|
||||||
for (const childMeta of childrenMeta) {
|
for (const child of meta.children) {
|
||||||
html += saveNavigationInner(childMeta);
|
html += saveNavigationInner(child);
|
||||||
}
|
}
|
||||||
|
|
||||||
html += '</ul>'
|
html += '</ul>'
|
||||||
@ -526,10 +482,8 @@ ${markdownContent}`;
|
|||||||
firstNonEmptyNote = getNoteTargetUrl(curMeta.noteId, rootMeta);
|
firstNonEmptyNote = getNoteTargetUrl(curMeta.noteId, rootMeta);
|
||||||
}
|
}
|
||||||
|
|
||||||
const childrenMeta = parentNoteIdToChildrenMeta[curMeta.noteId];
|
if (curMeta.children && curMeta.children.length > 0) {
|
||||||
|
curMeta = curMeta.children[0];
|
||||||
if (childrenMeta?.length > 0) {
|
|
||||||
curMeta = childrenMeta[0];
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
break;
|
break;
|
||||||
@ -561,13 +515,14 @@ ${markdownContent}`;
|
|||||||
archive.append(cssContent, { name: cssMeta.dataFileName });
|
archive.append(cssContent, { name: cssMeta.dataFileName });
|
||||||
}
|
}
|
||||||
|
|
||||||
const existingFileNames = format === 'html' ? { 'navigation': 1, 'index': 1 } : {};
|
const existingFileNames = format === 'html' ? ['navigation', 'index'] : [];
|
||||||
const metaFile = createMetaFileForDirectory([branch], existingFileNames);
|
const rootMeta = createNoteMeta(branch, { notePath: [] }, existingFileNames);
|
||||||
|
|
||||||
if (!metaFile) { // corner case of disabled export for exported note
|
const metaFile = {
|
||||||
res.sendStatus(400);
|
formatVersion: 2,
|
||||||
return;
|
appVersion: packageInfo.version,
|
||||||
}
|
files: [ rootMeta ]
|
||||||
|
};
|
||||||
|
|
||||||
let navigationMeta, indexMeta, cssMeta;
|
let navigationMeta, indexMeta, cssMeta;
|
||||||
|
|
||||||
@ -610,9 +565,15 @@ ${markdownContent}`;
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
metaFile.save(archive);
|
if (!rootMeta) { // corner case of disabled export for exported note
|
||||||
|
res.sendStatus(400);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const metaFileJson = JSON.stringify(metaFile, null, '\t');
|
||||||
|
|
||||||
|
archive.append(metaFileJson, { name: "!!!meta.json" });
|
||||||
|
|
||||||
const rootMeta = metaFile.files[0];
|
|
||||||
saveNote(rootMeta, '');
|
saveNote(rootMeta, '');
|
||||||
|
|
||||||
if (format === 'html') {
|
if (format === 'html') {
|
||||||
|
@ -1,16 +0,0 @@
|
|||||||
class MetaFile {
|
|
||||||
/** @type {int} */
|
|
||||||
formatVersion;
|
|
||||||
/** @type {string} */
|
|
||||||
appVersion;
|
|
||||||
/** @type {NoteMeta[]} */
|
|
||||||
files;
|
|
||||||
|
|
||||||
save(archive, filePathPrefix = '') {
|
|
||||||
const metaFileJson = JSON.stringify(this, null, '\t');
|
|
||||||
|
|
||||||
archive.append(metaFileJson, { name: filePathPrefix + "!!!meta.json" });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = MetaFile;
|
|
@ -1,10 +1,7 @@
|
|||||||
class NoteMeta {
|
class NoteMeta {
|
||||||
/** @type {string} */
|
/** @type {string} */
|
||||||
noteId;
|
noteId;
|
||||||
/**
|
/** @type {string} */
|
||||||
* @type {string[]}
|
|
||||||
* @deprecated unused as of v3
|
|
||||||
*/
|
|
||||||
notePath;
|
notePath;
|
||||||
/** @type {boolean} */
|
/** @type {boolean} */
|
||||||
isClone;
|
isClone;
|
||||||
@ -32,10 +29,7 @@ class NoteMeta {
|
|||||||
attributes;
|
attributes;
|
||||||
/** @type {AttachmentMeta[]} */
|
/** @type {AttachmentMeta[]} */
|
||||||
attachments;
|
attachments;
|
||||||
/**
|
/** @type {NoteMeta[]|undefined} */
|
||||||
* @type {NoteMeta[]|undefined}
|
|
||||||
* @deprecated unused as of v3, there's meta file for each directory, avoiding the need to use this
|
|
||||||
*/
|
|
||||||
children;
|
children;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user