diff --git a/apps/server/src/becca/entities/bbranch.ts b/apps/server/src/becca/entities/bbranch.ts index 00e3ec4b7..b31cadd71 100644 --- a/apps/server/src/becca/entities/bbranch.ts +++ b/apps/server/src/becca/entities/bbranch.ts @@ -278,6 +278,11 @@ class BBranch extends AbstractBeccaEntity { }); } } + + getParentNote() { + return this.parentNote; + } + } export default BBranch; diff --git a/apps/server/src/becca/entities/bnote.ts b/apps/server/src/becca/entities/bnote.ts index 419c9bdfe..650316777 100644 --- a/apps/server/src/becca/entities/bnote.ts +++ b/apps/server/src/becca/entities/bnote.ts @@ -1758,6 +1758,22 @@ class BNote extends AbstractBeccaEntity { return childBranches; } + get encodedTitle() { + return encodeURIComponent(this.title); + } + + getVisibleChildBranches() { + return this.getChildBranches().filter((branch) => !branch.getNote().isLabelTruthy("shareHiddenFromTree")); + } + + getVisibleChildNotes() { + return this.getVisibleChildBranches().map((branch) => branch.getNote()); + } + + hasVisibleChildren() { + return this.getVisibleChildNotes().length > 0; + } + } export default BNote; diff --git a/apps/server/src/services/export/zip.ts b/apps/server/src/services/export/zip.ts index 81c67a21b..f544f2a73 100644 --- a/apps/server/src/services/export/zip.ts +++ b/apps/server/src/services/export/zip.ts @@ -19,9 +19,11 @@ import type NoteMeta from "../meta/note_meta.js"; import type AttachmentMeta from "../meta/attachment_meta.js"; import type AttributeMeta from "../meta/attribute_meta.js"; import type BBranch from "../../becca/entities/bbranch.js"; +import type BNote from "../../becca/entities/bnote.js"; import type { Response } from "express"; import type { NoteMetaFile } from "../meta/note_meta.js"; import cssContent from "@triliumnext/ckeditor5/content.css"; +import { renderNoteContent } from "../../share/content_renderer.js"; type RewriteLinksFn = (content: string, noteMeta: NoteMeta) => string; @@ -314,7 +316,7 @@ async function exportToZip(taskContext: TaskContext, branch: BBranch, format: "h } } - function prepareContent(title: string, content: string | Buffer, noteMeta: NoteMeta): string | Buffer { + function prepareContent(note: BNote | undefined, title: string, content: string | Buffer, noteMeta: NoteMeta): string | Buffer { if (["html", "markdown"].includes(noteMeta?.format || "")) { content = content.toString(); content = rewriteFn(content, noteMeta); @@ -329,8 +331,11 @@ async function exportToZip(taskContext: TaskContext, branch: BBranch, format: "h const cssUrl = `${"../".repeat(noteMeta.notePath.length - 1)}style.css`; const htmlTitle = escapeHtml(title); - // element will make sure external links are openable - https://github.com/zadam/trilium/issues/1289#issuecomment-704066809 - content = ` + if (note) { + content = renderNoteContent(note); + } else { + // element will make sure external links are openable - https://github.com/zadam/trilium/issues/1289#issuecomment-704066809 + content = ` @@ -346,6 +351,7 @@ async function exportToZip(taskContext: TaskContext, branch: BBranch, format: "h `; + } } return content.length < 100_000 ? html.prettyPrint(content, { indent_size: 2 }) : content; @@ -375,7 +381,7 @@ ${markdownContent}`; let content: string | Buffer = `

This is a clone of a note. Go to its primary location.

`; - content = prepareContent(noteMeta.title, content, noteMeta); + content = prepareContent(undefined, noteMeta.title, content, noteMeta); archive.append(content, { name: filePathPrefix + noteMeta.dataFileName }); @@ -391,7 +397,7 @@ ${markdownContent}`; } if (noteMeta.dataFileName) { - const content = prepareContent(noteMeta.title, note.getContent(), noteMeta); + const content = prepareContent(note, noteMeta.title, note.getContent(), noteMeta); archive.append(content, { name: filePathPrefix + noteMeta.dataFileName, diff --git a/apps/server/src/share/content_renderer.ts b/apps/server/src/share/content_renderer.ts index e94eb4297..aad3ab9d2 100644 --- a/apps/server/src/share/content_renderer.ts +++ b/apps/server/src/share/content_renderer.ts @@ -4,6 +4,8 @@ import assetPath, { assetUrlFragment } from "../services/asset_path.js"; import shareRoot from "./share_root.js"; import escapeHtml from "escape-html"; import type SNote from "./shaca/entities/snote.js"; +import BNote from "../becca/entities/bnote.js"; +import type BBranch from "../becca/entities/bbranch.js"; import { t } from "i18next"; import SBranch from "./shaca/entities/sbranch.js"; import options from "../services/options.js"; @@ -24,8 +26,8 @@ export interface Result { isEmpty?: boolean; } -function getSharedSubTreeRoot(note: SNote): { note?: SNote; branch?: SBranch } { - if (note.noteId === shareRoot.SHARE_ROOT_NOTE_ID) { +function getSharedSubTreeRoot(note: SNote | BNote | undefined): { note?: SNote | BNote; branch?: SBranch | BBranch } { + if (!note || note.noteId === shareRoot.SHARE_ROOT_NOTE_ID) { // share root itself is not shared return {}; } @@ -34,6 +36,13 @@ function getSharedSubTreeRoot(note: SNote): { note?: SNote; branch?: SBranch } { // for the sake of simplicity, URLs are not note paths const parentBranch = note.getParentBranches()[0]; + if (note instanceof BNote) { + return { + note, + branch: parentBranch + } + } + if (parentBranch.parentNoteId === shareRoot.SHARE_ROOT_NOTE_ID) { return { note, @@ -44,7 +53,7 @@ function getSharedSubTreeRoot(note: SNote): { note?: SNote; branch?: SBranch } { return getSharedSubTreeRoot(parentBranch.getParentNote()); } -export function renderNoteContent(note: SNote) { +export function renderNoteContent(note: SNote | BNote) { const { header, content, isEmpty } = getContent(note); const subRoot = getSharedSubTreeRoot(note); const showLoginInShareTheme = options.getOption("showLoginInShareTheme"); @@ -105,7 +114,7 @@ export function renderNoteContent(note: SNote) { }); } -function getContent(note: SNote) { +function getContent(note: SNote | BNote) { if (note.isProtected) { return { header: "", @@ -154,7 +163,7 @@ function renderIndex(result: Result) { result.content += ""; } -function renderText(result: Result, note: SNote) { +function renderText(result: Result, note: SNote | BNote) { const document = new JSDOM(result.content || "").window.document; result.isEmpty = document.body.textContent?.trim().length === 0 && document.querySelectorAll("img").length === 0; @@ -247,7 +256,7 @@ export function renderCode(result: Result) { } } -function renderMermaid(result: Result, note: SNote) { +function renderMermaid(result: Result, note: SNote | BNote) { if (typeof result.content !== "string") { return; } @@ -261,11 +270,11 @@ function renderMermaid(result: Result, note: SNote) { `; } -function renderImage(result: Result, note: SNote) { +function renderImage(result: Result, note: SNote | BNote) { result.content = ``; } -function renderFile(note: SNote, result: Result) { +function renderFile(note: SNote | BNote, result: Result) { if (note.mime === "application/pdf") { result.content = ``; } else {