mirror of
https://github.com/TriliumNext/Notes.git
synced 2025-07-29 11:02:28 +08:00
feat(edit-docs): rewrite links to allow navigation in help
This commit is contained in:
parent
652fc48a86
commit
a88a92d490
@ -9,6 +9,7 @@ import type { WriteStream } from "fs";
|
||||
import debounce from "./src/public/app/services/debounce.js";
|
||||
import { extractZip, initializeDatabase, startElectron } from "./electron-utils.js";
|
||||
import cls from "./src/services/cls.js";
|
||||
import type { AdvancedExportOptions } from "./src/services/export/zip.js";
|
||||
|
||||
const NOTE_ID_USER_GUIDE = "pOsGYCXsbNQG";
|
||||
const markdownPath = path.join("docs", "User Guide");
|
||||
@ -69,7 +70,54 @@ async function exportData(format: "html" | "markdown", outputPath: string) {
|
||||
|
||||
// First export as zip.
|
||||
const { exportToZipFile } = (await import("./src/services/export/zip.js")).default;
|
||||
await exportToZipFile(NOTE_ID_USER_GUIDE, format, zipFilePath);
|
||||
|
||||
const exportOpts: AdvancedExportOptions = {};
|
||||
if (format === "html") {
|
||||
exportOpts.customRewriteLinks = (originalRewriteLinks, getNoteTargetUrl) => {
|
||||
return (content: string, noteMeta: NoteMeta) => {
|
||||
content = content.replace(/src="[^"]*api\/images\/([a-zA-Z0-9_]+)\/[^"]*"/g, (match, targetNoteId) => {
|
||||
const url = getNoteTargetUrl(targetNoteId, noteMeta);
|
||||
|
||||
return url ? `src="${url}"` : match;
|
||||
});
|
||||
|
||||
content = content.replace(/src="[^"]*api\/attachments\/([a-zA-Z0-9_]+)\/image\/[^"]*"/g, (match, targetAttachmentId) => {
|
||||
const url = findAttachment(targetAttachmentId);
|
||||
|
||||
return url ? `src="${url}"` : match;
|
||||
});
|
||||
|
||||
content = content.replace(/href="[^"]*#root[^"]*attachmentId=([a-zA-Z0-9_]+)\/?"/g, (match, targetAttachmentId) => {
|
||||
const url = findAttachment(targetAttachmentId);
|
||||
|
||||
return url ? `href="${url}"` : match;
|
||||
});
|
||||
|
||||
content = content.replace(/href="[^"]*#root[a-zA-Z0-9_\/]*\/([a-zA-Z0-9_]+)[^"]*"/g, (match, targetNoteId) => {
|
||||
const components = match.split("/");
|
||||
components[components.length - 1] = `_help_${components[components.length - 1]}`;
|
||||
return components.join("/");
|
||||
});
|
||||
|
||||
return content;
|
||||
|
||||
function findAttachment(targetAttachmentId: string) {
|
||||
let url;
|
||||
|
||||
const attachmentMeta = (noteMeta.attachments || []).find((attMeta) => attMeta.attachmentId === targetAttachmentId);
|
||||
if (attachmentMeta) {
|
||||
// easy job here, because attachment will be in the same directory as the note's data file.
|
||||
url = attachmentMeta.dataFileName;
|
||||
} else {
|
||||
console.info(`Could not find attachment meta object for attachmentId '${targetAttachmentId}'`);
|
||||
}
|
||||
return url;
|
||||
}
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
await exportToZipFile(NOTE_ID_USER_GUIDE, format, zipFilePath, exportOpts);
|
||||
await extractZip(zipFilePath, outputPath);
|
||||
} finally {
|
||||
if (await fsExtra.exists(zipFilePath)) {
|
||||
|
@ -23,7 +23,20 @@ import type { Response } from "express";
|
||||
import { RESOURCE_DIR } from "../resource_dir.js";
|
||||
import type { NoteMetaFile } from "../meta/note_meta.js";
|
||||
|
||||
async function exportToZip(taskContext: TaskContext, branch: BBranch, format: "html" | "markdown", res: Response | fs.WriteStream, setHeaders = true) {
|
||||
type RewriteLinksFn = (content: string, noteMeta: NoteMeta) => string;
|
||||
|
||||
export interface AdvancedExportOptions {
|
||||
/**
|
||||
* 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) {
|
||||
if (!["html", "markdown"].includes(format)) {
|
||||
throw new ValidationError(`Only 'html' and 'markdown' allowed as export format, '${format}' given`);
|
||||
}
|
||||
@ -253,6 +266,8 @@ async function exportToZip(taskContext: TaskContext, branch: BBranch, format: "h
|
||||
return url;
|
||||
}
|
||||
|
||||
const rewriteFn = (zipExportOptions?.customRewriteLinks ? zipExportOptions?.customRewriteLinks(rewriteLinks, getNoteTargetUrl) : rewriteLinks);
|
||||
|
||||
function rewriteLinks(content: string, noteMeta: NoteMeta): string {
|
||||
content = content.replace(/src="[^"]*api\/images\/([a-zA-Z0-9_]+)\/[^"]*"/g, (match, targetNoteId) => {
|
||||
const url = getNoteTargetUrl(targetNoteId, noteMeta);
|
||||
@ -297,8 +312,7 @@ async function exportToZip(taskContext: TaskContext, branch: BBranch, format: "h
|
||||
function prepareContent(title: string, content: string | Buffer, noteMeta: NoteMeta): string | Buffer {
|
||||
if (["html", "markdown"].includes(noteMeta?.format || "")) {
|
||||
content = content.toString();
|
||||
|
||||
content = rewriteLinks(content, noteMeta);
|
||||
content = rewriteFn(content, noteMeta);
|
||||
}
|
||||
|
||||
if (noteMeta.format === "html" && typeof content === "string") {
|
||||
@ -591,7 +605,7 @@ ${markdownContent}`;
|
||||
taskContext.taskSucceeded();
|
||||
}
|
||||
|
||||
async function exportToZipFile(noteId: string, format: "markdown" | "html", zipFilePath: string) {
|
||||
async function exportToZipFile(noteId: string, format: "markdown" | "html", zipFilePath: string, zipExportOptions?: AdvancedExportOptions) {
|
||||
const fileOutputStream = fs.createWriteStream(zipFilePath);
|
||||
const taskContext = new TaskContext("no-progress-reporting");
|
||||
|
||||
@ -601,7 +615,7 @@ async function exportToZipFile(noteId: string, format: "markdown" | "html", zipF
|
||||
throw new ValidationError(`Note ${noteId} not found.`);
|
||||
}
|
||||
|
||||
await exportToZip(taskContext, note.getParentBranches()[0], format, fileOutputStream, false);
|
||||
await exportToZip(taskContext, note.getParentBranches()[0], format, fileOutputStream, false, zipExportOptions);
|
||||
|
||||
log.info(`Exported '${noteId}' with format '${format}' to '${zipFilePath}'`);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user