mirror of
https://github.com/zadam/trilium.git
synced 2025-11-09 06:45:49 +01:00
refactor(export/zip): extract prepare content into providers
This commit is contained in:
@@ -1,10 +1,8 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
import html from "html";
|
|
||||||
import dateUtils from "../date_utils.js";
|
import dateUtils from "../date_utils.js";
|
||||||
import path from "path";
|
import path from "path";
|
||||||
import mimeTypes from "mime-types";
|
import mimeTypes from "mime-types";
|
||||||
import mdService from "./markdown.js";
|
|
||||||
import packageInfo from "../../../package.json" with { type: "json" };
|
import packageInfo from "../../../package.json" with { type: "json" };
|
||||||
import { getContentDisposition, escapeHtml } from "../utils.js";
|
import { getContentDisposition, escapeHtml } from "../utils.js";
|
||||||
import protectedSessionService from "../protected_session.js";
|
import protectedSessionService from "../protected_session.js";
|
||||||
@@ -22,27 +20,9 @@ import type BBranch from "../../becca/entities/bbranch.js";
|
|||||||
import type { Response } from "express";
|
import type { Response } from "express";
|
||||||
import type { NoteMetaFile } from "../meta/note_meta.js";
|
import type { NoteMetaFile } from "../meta/note_meta.js";
|
||||||
import HtmlExportProvider from "./zip/html.js";
|
import HtmlExportProvider from "./zip/html.js";
|
||||||
import { ZipExportProvider, ZipExportProviderData } from "./zip/abstract_provider.js";
|
import { AdvancedExportOptions, ZipExportProvider, ZipExportProviderData } from "./zip/abstract_provider.js";
|
||||||
import MarkdownExportProvider from "./zip/markdown.js";
|
import MarkdownExportProvider from "./zip/markdown.js";
|
||||||
|
|
||||||
type RewriteLinksFn = (content: string, noteMeta: NoteMeta) => string;
|
|
||||||
|
|
||||||
export interface AdvancedExportOptions {
|
|
||||||
/**
|
|
||||||
* If `true`, then only the note's content will be kept. If `false` (default), then each page will have its own <html> template.
|
|
||||||
*/
|
|
||||||
skipHtmlTemplate?: boolean;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Provides a custom function to rewrite the links found in HTML or Markdown notes. This method is called for every note imported, if it's of the right type.
|
|
||||||
*
|
|
||||||
* @param originalRewriteLinks the original rewrite links function. Can be used to access the default behaviour without having to reimplement it.
|
|
||||||
* @param getNoteTargetUrl the method to obtain a note's target URL, used internally by `originalRewriteLinks` but can be used here as well.
|
|
||||||
* @returns a function to rewrite the links in HTML or Markdown notes.
|
|
||||||
*/
|
|
||||||
customRewriteLinks?: (originalRewriteLinks: RewriteLinksFn, getNoteTargetUrl: (targetNoteId: string, sourceMeta: NoteMeta) => string | null) => RewriteLinksFn;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function exportToZip(taskContext: TaskContext, branch: BBranch, format: "html" | "markdown", res: Response | fs.WriteStream, setHeaders = true, zipExportOptions?: AdvancedExportOptions) {
|
async function exportToZip(taskContext: TaskContext, branch: BBranch, format: "html" | "markdown", res: Response | fs.WriteStream, setHeaders = true, zipExportOptions?: AdvancedExportOptions) {
|
||||||
if (!["html", "markdown"].includes(format)) {
|
if (!["html", "markdown"].includes(format)) {
|
||||||
throw new ValidationError(`Only 'html' and 'markdown' allowed as export format, '${format}' given`);
|
throw new ValidationError(`Only 'html' and 'markdown' allowed as export format, '${format}' given`);
|
||||||
@@ -322,47 +302,7 @@ async function exportToZip(taskContext: TaskContext, branch: BBranch, format: "h
|
|||||||
content = rewriteFn(content, noteMeta);
|
content = rewriteFn(content, noteMeta);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (noteMeta.format === "html" && typeof content === "string") {
|
return provider.prepareContent(title, content, noteMeta);
|
||||||
if (!content.substr(0, 100).toLowerCase().includes("<html") && !zipExportOptions?.skipHtmlTemplate) {
|
|
||||||
if (!noteMeta?.notePath?.length) {
|
|
||||||
throw new Error("Missing note path.");
|
|
||||||
}
|
|
||||||
|
|
||||||
const cssUrl = `${"../".repeat(noteMeta.notePath.length - 1)}style.css`;
|
|
||||||
const htmlTitle = escapeHtml(title);
|
|
||||||
|
|
||||||
// <base> element will make sure external links are openable - https://github.com/zadam/trilium/issues/1289#issuecomment-704066809
|
|
||||||
content = `<html>
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
||||||
<link rel="stylesheet" href="${cssUrl}">
|
|
||||||
<base target="_parent">
|
|
||||||
<title data-trilium-title>${htmlTitle}</title>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div class="content">
|
|
||||||
<h1 data-trilium-h1>${htmlTitle}</h1>
|
|
||||||
|
|
||||||
<div class="ck-content">${content}</div>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>`;
|
|
||||||
}
|
|
||||||
|
|
||||||
return content.length < 100_000 ? html.prettyPrint(content, { indent_size: 2 }) : content;
|
|
||||||
} else if (noteMeta.format === "markdown" && typeof content === "string") {
|
|
||||||
let markdownContent = mdService.toMarkdown(content);
|
|
||||||
|
|
||||||
if (markdownContent.trim().length > 0 && !markdownContent.startsWith("# ")) {
|
|
||||||
markdownContent = `# ${title}\r
|
|
||||||
${markdownContent}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
return markdownContent;
|
|
||||||
} else {
|
|
||||||
return content;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function saveNote(noteMeta: NoteMeta, filePathPrefix: string) {
|
function saveNote(noteMeta: NoteMeta, filePathPrefix: string) {
|
||||||
|
|||||||
@@ -1,11 +1,30 @@
|
|||||||
import { Archiver } from "archiver";
|
import { Archiver } from "archiver";
|
||||||
import type { default as NoteMeta, NoteMetaFile } from "../../meta/note_meta.js";
|
import type { default as NoteMeta, NoteMetaFile } from "../../meta/note_meta.js";
|
||||||
|
|
||||||
|
type RewriteLinksFn = (content: string, noteMeta: NoteMeta) => string;
|
||||||
|
|
||||||
|
export interface AdvancedExportOptions {
|
||||||
|
/**
|
||||||
|
* If `true`, then only the note's content will be kept. If `false` (default), then each page will have its own <html> template.
|
||||||
|
*/
|
||||||
|
skipHtmlTemplate?: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides a custom function to rewrite the links found in HTML or Markdown notes. This method is called for every note imported, if it's of the right type.
|
||||||
|
*
|
||||||
|
* @param originalRewriteLinks the original rewrite links function. Can be used to access the default behaviour without having to reimplement it.
|
||||||
|
* @param getNoteTargetUrl the method to obtain a note's target URL, used internally by `originalRewriteLinks` but can be used here as well.
|
||||||
|
* @returns a function to rewrite the links in HTML or Markdown notes.
|
||||||
|
*/
|
||||||
|
customRewriteLinks?: (originalRewriteLinks: RewriteLinksFn, getNoteTargetUrl: (targetNoteId: string, sourceMeta: NoteMeta) => string | null) => RewriteLinksFn;
|
||||||
|
}
|
||||||
|
|
||||||
export interface ZipExportProviderData {
|
export interface ZipExportProviderData {
|
||||||
getNoteTargetUrl: (targetNoteId: string, sourceMeta: NoteMeta) => string | null;
|
getNoteTargetUrl: (targetNoteId: string, sourceMeta: NoteMeta) => string | null;
|
||||||
metaFile: NoteMetaFile;
|
metaFile: NoteMetaFile;
|
||||||
rootMeta: NoteMeta;
|
rootMeta: NoteMeta;
|
||||||
archive: Archiver;
|
archive: Archiver;
|
||||||
|
zipExportOptions?: AdvancedExportOptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
export abstract class ZipExportProvider {
|
export abstract class ZipExportProvider {
|
||||||
@@ -14,14 +33,17 @@ export abstract class ZipExportProvider {
|
|||||||
getNoteTargetUrl: (targetNoteId: string, sourceMeta: NoteMeta) => string | null;
|
getNoteTargetUrl: (targetNoteId: string, sourceMeta: NoteMeta) => string | null;
|
||||||
rootMeta: NoteMeta;
|
rootMeta: NoteMeta;
|
||||||
archive: Archiver;
|
archive: Archiver;
|
||||||
|
zipExportOptions?: AdvancedExportOptions;
|
||||||
|
|
||||||
constructor(data: ZipExportProviderData) {
|
constructor(data: ZipExportProviderData) {
|
||||||
this.metaFile = data.metaFile;
|
this.metaFile = data.metaFile;
|
||||||
this.getNoteTargetUrl = data.getNoteTargetUrl;
|
this.getNoteTargetUrl = data.getNoteTargetUrl;
|
||||||
this.rootMeta = data.rootMeta;
|
this.rootMeta = data.rootMeta;
|
||||||
this.archive = data.archive;
|
this.archive = data.archive;
|
||||||
|
this.zipExportOptions = data.zipExportOptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract prepareMeta(): void;
|
abstract prepareMeta(): void;
|
||||||
|
abstract prepareContent(title: string, content: string | Buffer, noteMeta: NoteMeta): string | Buffer;
|
||||||
abstract afterDone(): void;
|
abstract afterDone(): void;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,6 +33,41 @@ export default class HtmlExportProvider extends ZipExportProvider {
|
|||||||
this.metaFile.files.push(this.cssMeta);
|
this.metaFile.files.push(this.cssMeta);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
prepareContent(title: string, content: string | Buffer, noteMeta: NoteMeta): string | Buffer {
|
||||||
|
if (noteMeta.format === "html" && typeof content === "string") {
|
||||||
|
if (!content.substr(0, 100).toLowerCase().includes("<html") && !this.zipExportOptions?.skipHtmlTemplate) {
|
||||||
|
if (!noteMeta?.notePath?.length) {
|
||||||
|
throw new Error("Missing note path.");
|
||||||
|
}
|
||||||
|
|
||||||
|
const cssUrl = `${"../".repeat(noteMeta.notePath.length - 1)}style.css`;
|
||||||
|
const htmlTitle = escapeHtml(title);
|
||||||
|
|
||||||
|
// <base> element will make sure external links are openable - https://github.com/zadam/trilium/issues/1289#issuecomment-704066809
|
||||||
|
content = `<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<link rel="stylesheet" href="${cssUrl}">
|
||||||
|
<base target="_parent">
|
||||||
|
<title data-trilium-title>${htmlTitle}</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="content">
|
||||||
|
<h1 data-trilium-h1>${htmlTitle}</h1>
|
||||||
|
|
||||||
|
<div class="ck-content">${content}</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return content.length < 100_000 ? html.prettyPrint(content, { indent_size: 2 }) : content;
|
||||||
|
} else {
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
afterDone() {
|
afterDone() {
|
||||||
if (!this.navigationMeta || !this.indexMeta || !this.cssMeta) {
|
if (!this.navigationMeta || !this.indexMeta || !this.cssMeta) {
|
||||||
throw new Error("Missing meta.");
|
throw new Error("Missing meta.");
|
||||||
|
|||||||
@@ -1,8 +1,26 @@
|
|||||||
|
import NoteMeta from "../../meta/note_meta"
|
||||||
import { ZipExportProvider } from "./abstract_provider"
|
import { ZipExportProvider } from "./abstract_provider"
|
||||||
|
import mdService from "../markdown.js";
|
||||||
|
|
||||||
export default class MarkdownExportProvider extends ZipExportProvider {
|
export default class MarkdownExportProvider extends ZipExportProvider {
|
||||||
|
|
||||||
prepareMeta() { }
|
prepareMeta() { }
|
||||||
|
|
||||||
|
prepareContent(title: string, content: string | Buffer, noteMeta: NoteMeta): string | Buffer {
|
||||||
|
if (noteMeta.format === "markdown" && typeof content === "string") {
|
||||||
|
let markdownContent = mdService.toMarkdown(content);
|
||||||
|
|
||||||
|
if (markdownContent.trim().length > 0 && !markdownContent.startsWith("# ")) {
|
||||||
|
markdownContent = `# ${title}\r
|
||||||
|
${markdownContent}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return markdownContent;
|
||||||
|
} else {
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
afterDone() { }
|
afterDone() { }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user