diff --git a/bin/copy-dist.ts b/bin/copy-dist.ts index 3e138fed1..2c071142c 100644 --- a/bin/copy-dist.ts +++ b/bin/copy-dist.ts @@ -76,7 +76,6 @@ try { "node_modules/dayjs/", "node_modules/boxicons/css/", "node_modules/boxicons/fonts/", - "node_modules/mermaid/dist/", "node_modules/jquery/dist/", "node_modules/jquery-hotkeys/", "node_modules/split.js/dist/", diff --git a/src/public/app/layouts/mobile_layout.ts b/src/public/app/layouts/mobile_layout.ts index 51609ce32..f0f567041 100644 --- a/src/public/app/layouts/mobile_layout.ts +++ b/src/public/app/layouts/mobile_layout.ts @@ -16,7 +16,6 @@ import RelationMapButtons from "../widgets/floating_buttons/relation_map_buttons import SvgExportButton from "../widgets/floating_buttons/svg_export_button.js"; import BacklinksWidget from "../widgets/floating_buttons/zpetne_odkazy.js"; import HideFloatingButtonsButton from "../widgets/floating_buttons/hide_floating_buttons_button.js"; -import MermaidWidget from "../widgets/mermaid.js"; import NoteListWidget from "../widgets/note_list.js"; import GlobalMenuWidget from "../widgets/buttons/global_menu.js"; import LauncherContainer from "../widgets/containers/launcher_container.js"; @@ -165,7 +164,6 @@ export default class MobileLayout { .child(new BacklinksWidget()) .child(new HideFloatingButtonsButton()) ) - .child(new MermaidWidget()) .child(new PromotedAttributesWidget()) .child( new ScrollingContainer() diff --git a/src/public/app/services/content_renderer.ts b/src/public/app/services/content_renderer.ts index 720f4da25..a1999cffe 100644 --- a/src/public/app/services/content_renderer.ts +++ b/src/public/app/services/content_renderer.ts @@ -15,6 +15,7 @@ import { loadElkIfNeeded, postprocessMermaidSvg } from "./mermaid.js"; import { normalizeMimeTypeForCKEditor } from "./mime_type_definitions.js"; import renderDoc from "./doc_renderer.js"; import { t } from "i18next"; +import type { Mermaid } from "mermaid"; let idCounter = 1; @@ -226,7 +227,7 @@ function renderFile(entity: FNote | FAttachment, type: string, $renderedContent: } async function renderMermaid(note: FNote | FAttachment, $renderedContent: JQuery) { - await libraryLoader.requireLibrary(libraryLoader.MERMAID); + const mermaid = (await import("mermaid")).default; const blob = await note.getBlob(); const content = blob?.content || ""; @@ -236,10 +237,10 @@ async function renderMermaid(note: FNote | FAttachment, $renderedContent: JQuery const documentStyle = window.getComputedStyle(document.documentElement); const mermaidTheme = documentStyle.getPropertyValue("--mermaid-theme"); - mermaid.mermaidAPI.initialize({ startOnLoad: false, theme: mermaidTheme.trim(), securityLevel: "antiscript" }); + mermaid.mermaidAPI.initialize({ startOnLoad: false, theme: mermaidTheme.trim() as "default", securityLevel: "antiscript" }); try { - await loadElkIfNeeded(content); + await loadElkIfNeeded(mermaid, content); const { svg } = await mermaid.mermaidAPI.render("in-mermaid-graph-" + idCounter++, content); $renderedContent.append($(postprocessMermaidSvg(svg))); diff --git a/src/public/app/services/library_loader.ts b/src/public/app/services/library_loader.ts index 8dca65060..129dca688 100644 --- a/src/public/app/services/library_loader.ts +++ b/src/public/app/services/library_loader.ts @@ -55,10 +55,6 @@ const WHEEL_ZOOM: Library = { js: ["node_modules/vanilla-js-wheel-zoom/dist/wheel-zoom.min.js"] }; -const MERMAID: Library = { - js: ["node_modules/mermaid/dist/mermaid.min.js"] -}; - const MARKJS: Library = { js: ["node_modules/mark.js/dist/jquery.mark.es6.min.js"] }; @@ -181,7 +177,6 @@ export default { CALENDAR_WIDGET, KATEX, WHEEL_ZOOM, - MERMAID, MARKJS, HIGHLIGHT_JS, LEAFLET diff --git a/src/public/app/services/mermaid.ts b/src/public/app/services/mermaid.ts index 1100081c9..a42a3716e 100644 --- a/src/public/app/services/mermaid.ts +++ b/src/public/app/services/mermaid.ts @@ -1,3 +1,5 @@ +import type { Mermaid } from "mermaid"; + let elkLoaded = false; /** @@ -9,7 +11,7 @@ let elkLoaded = false; * * @param mermaidContent the plain text of the mermaid diagram, potentially including a frontmatter. */ -export async function loadElkIfNeeded(mermaidContent: string) { +export async function loadElkIfNeeded(mermaid: Mermaid, mermaidContent: string) { if (elkLoaded) { // Exit immediately since the ELK library is already loaded. return; @@ -18,7 +20,7 @@ export async function loadElkIfNeeded(mermaidContent: string) { const parsedContent = await mermaid.parse(mermaidContent, { suppressErrors: true }); - if (parsedContent?.config?.layout === "elk") { + if (parsedContent && parsedContent.config?.layout === "elk") { elkLoaded = true; mermaid.registerLayoutLoaders((await import("@mermaid-js/layout-elk")).default); } diff --git a/src/public/app/types.d.ts b/src/public/app/types.d.ts index 05b533f73..8a2ebe75b 100644 --- a/src/public/app/types.d.ts +++ b/src/public/app/types.d.ts @@ -8,6 +8,7 @@ import library_loader, { Library } from "./services/library_loader.ts"; import type { init } from "i18next"; import type { lint } from "./services/eslint.ts"; import type { RelationType } from "./widgets/type_widgets/relation_map.ts"; +import type { Mermaid } from "mermaid"; interface ElectronProcess { type: string; @@ -138,45 +139,6 @@ declare global { zoomOnClick: boolean }) }; - interface MermaidApi { - initialize(opts: { - startOnLoad: boolean, - theme: string, - securityLevel: "antiscript" - }): void; - render(selector: string, data: string); - } - interface MermaidLoader { - - } - interface MermaidChartConfig { - useMaxWidth: boolean; - } - interface MermaidConfig { - theme: string; - securityLevel: "antiscript", - flow: MermaidChartConfig; - sequence: MermaidChartConfig; - gantt: MermaidChartConfig; - class: MermaidChartConfig; - state: MermaidChartConfig; - pie: MermaidChartConfig; - journey: MermaidChartConfig; - git: MermaidChartConfig; - } - var mermaid: { - mermaidAPI: MermaidApi; - registerLayoutLoaders(loader: MermaidLoader); - init(config: MermaidConfig, el: HTMLElement | JQuery); - parse(content: string, opts: { - suppressErrors: true - }): Promise<{ - config: { - layout: string; - } - }> - }; - interface CKCodeBlockLanguage { language: string; label: string; @@ -207,7 +169,7 @@ declare global { enablePreview: boolean }, mermaid: { - lazyLoad: () => Promise, + lazyLoad: () => Promise, config: MermaidConfig } }); diff --git a/src/public/app/widgets/type_widgets/abstract_svg_split_type_widget.ts b/src/public/app/widgets/type_widgets/abstract_svg_split_type_widget.ts index ac2a276ff..2eddf56c8 100644 --- a/src/public/app/widgets/type_widgets/abstract_svg_split_type_widget.ts +++ b/src/public/app/widgets/type_widgets/abstract_svg_split_type_widget.ts @@ -7,6 +7,7 @@ import AbstractSplitTypeWidget from "./abstract_split_type_widget.js"; * This adds the following functionality: * * - Automatic handling of the preview when content or the note changes. + * - Built-in pan and zoom functionality with automatic re-centering. * */ export default abstract class AbstractSvgSplitTypeWidget extends AbstractSplitTypeWidget { diff --git a/src/public/app/widgets/type_widgets/editable_text.ts b/src/public/app/widgets/type_widgets/editable_text.ts index 28eccfdbf..dacc85edf 100644 --- a/src/public/app/widgets/type_widgets/editable_text.ts +++ b/src/public/app/widgets/type_widgets/editable_text.ts @@ -13,10 +13,10 @@ import dialogService from "../../services/dialog.js"; import { initSyntaxHighlighting } from "./ckeditor/syntax_highlight.js"; import options from "../../services/options.js"; import toast from "../../services/toast.js"; -import { getMermaidConfig } from "../mermaid.js"; import { normalizeMimeTypeForCKEditor } from "../../services/mime_type_definitions.js"; import { buildConfig, buildToolbarConfig } from "./ckeditor/config.js"; import type FNote from "../../entities/fnote.js"; +import { getMermaidConfig } from "./mermaid.js"; const ENABLE_INSPECTOR = false; @@ -279,7 +279,7 @@ export default class EditableTextTypeWidget extends AbstractTextTypeWidget { enablePreview: true // Enable preview view }, mermaid: { - lazyLoad: async () => await libraryLoader.requireLibrary(libraryLoader.MERMAID), + lazyLoad: async () => (await import("mermaid")).default, // FIXME config: getMermaidConfig() } }); diff --git a/src/public/app/widgets/type_widgets/mermaid.ts b/src/public/app/widgets/type_widgets/mermaid.ts index e9ac91d88..2e0da337d 100644 --- a/src/public/app/widgets/type_widgets/mermaid.ts +++ b/src/public/app/widgets/type_widgets/mermaid.ts @@ -1,3 +1,4 @@ +import type { MermaidConfig } from "mermaid"; import library_loader from "../../services/library_loader.js"; import { loadElkIfNeeded, postprocessMermaidSvg } from "../../services/mermaid.js"; import AbstractSvgSplitTypeWidget from "./abstract_svg_split_type_widget.js"; @@ -11,8 +12,8 @@ export class MermaidTypeWidget extends AbstractSvgSplitTypeWidget { } async renderSvg(content: string) { - await library_loader.requireLibrary(library_loader.MERMAID); - await loadElkIfNeeded(content); + const mermaid = (await import("mermaid")).default; + await loadElkIfNeeded(mermaid, content); mermaid.mermaidAPI.initialize({ startOnLoad: false, @@ -28,19 +29,18 @@ export class MermaidTypeWidget extends AbstractSvgSplitTypeWidget { export function getMermaidConfig(): MermaidConfig { const documentStyle = window.getComputedStyle(document.documentElement); - const mermaidTheme = documentStyle.getPropertyValue("--mermaid-theme"); + const mermaidTheme = documentStyle.getPropertyValue("--mermaid-theme") as "default"; return { - theme: mermaidTheme.trim(), + theme: mermaidTheme.trim() as "default", securityLevel: "antiscript", - // TODO: Are all these options correct? - flow: { useMaxWidth: false }, + flowchart: { useMaxWidth: false }, sequence: { useMaxWidth: false }, gantt: { useMaxWidth: false }, class: { useMaxWidth: false }, state: { useMaxWidth: false }, pie: { useMaxWidth: true }, journey: { useMaxWidth: false }, - git: { useMaxWidth: false } + gitGraph: { useMaxWidth: false } }; } diff --git a/src/public/app/widgets/type_widgets/read_only_text.ts b/src/public/app/widgets/type_widgets/read_only_text.ts index 8791f8f27..8575c47c9 100644 --- a/src/public/app/widgets/type_widgets/read_only_text.ts +++ b/src/public/app/widgets/type_widgets/read_only_text.ts @@ -1,10 +1,10 @@ import AbstractTextTypeWidget from "./abstract_text_type_widget.js"; import libraryLoader from "../../services/library_loader.js"; import { applySyntaxHighlight } from "../../services/syntax_highlight.js"; -import { getMermaidConfig } from "../mermaid.js"; import type FNote from "../../entities/fnote.js"; import type { EventData } from "../../components/app_context.js"; import { getLocaleById } from "../../services/i18n.js"; +import { getMermaidConfig } from "./mermaid.js"; const TPL = `
@@ -141,8 +141,8 @@ export default class ReadOnlyTextTypeWidget extends AbstractTextTypeWidget { }); // Initialize mermaid - await libraryLoader.requireLibrary(libraryLoader.MERMAID); - mermaid.init(getMermaidConfig(), this.$content.find(".mermaid-diagram")); + const mermaid = (await import("mermaid")).default; + mermaid.init(getMermaidConfig(), this.$content.find(".mermaid-diagram")[0]); } async refreshIncludedNoteEvent({ noteId }: EventData<"refreshIncludedNote">) { diff --git a/src/routes/assets.ts b/src/routes/assets.ts index 1fa52dff7..f5cf33612 100644 --- a/src/routes/assets.ts +++ b/src/routes/assets.ts @@ -64,8 +64,6 @@ async function register(app: express.Application) { app.use(`/${assetPath}/node_modules/boxicons/css/`, persistentCacheStatic(path.join(srcRoot, "..", "node_modules/boxicons/css/"))); app.use(`/${assetPath}/node_modules/boxicons/fonts/`, persistentCacheStatic(path.join(srcRoot, "..", "node_modules/boxicons/fonts/"))); - app.use(`/${assetPath}/node_modules/mermaid/dist/`, persistentCacheStatic(path.join(srcRoot, "..", "node_modules/mermaid/dist/"))); - app.use(`/${assetPath}/node_modules/jquery/dist/`, persistentCacheStatic(path.join(srcRoot, "..", "node_modules/jquery/dist/"))); app.use(`/${assetPath}/node_modules/jquery-hotkeys/`, persistentCacheStatic(path.join(srcRoot, "..", "node_modules/jquery-hotkeys/")));