Notes/src/public/app/widgets/mermaid.js

152 lines
4.4 KiB
JavaScript
Raw Normal View History

2024-09-13 11:24:42 +08:00
import { t } from "../services/i18n.js";
2021-09-29 22:10:15 +02:00
import libraryLoader from "../services/library_loader.js";
import NoteContextAwareWidget from "./note_context_aware_widget.js";
import server from "../services/server.js";
2024-09-01 23:20:41 +03:00
import utils from "../services/utils.js";
import { loadElkIfNeeded } from "../services/mermaid.js";
2021-09-29 22:10:15 +02:00
const TPL = `<div class="mermaid-widget">
2021-09-30 09:48:03 +02:00
<style>
.mermaid-widget {
flex-grow: 2;
overflow: auto;
min-height: 200px;
border-bottom: 1px solid var(--main-border-color);
padding: 20px;
margin-bottom: 10px;
2021-09-30 09:48:03 +02:00
flex-basis: 0;
}
2021-09-30 13:48:01 +02:00
.mermaid-render {
overflow: auto;
height: 100%;
text-align: center;
2021-09-30 13:48:01 +02:00
}
2023-10-21 23:24:43 +02:00
.mermaid-render svg {
width: 95%; /* https://github.com/zadam/trilium/issues/4340 */
}
2021-09-30 09:48:03 +02:00
</style>
2021-09-29 22:10:15 +02:00
<div class="mermaid-error alert alert-warning">
2025-01-09 18:07:02 +02:00
<p><strong>${t("mermaid.diagram_error")}</strong></p>
2021-09-30 13:02:07 +02:00
<p class="error-content"></p>
2021-09-29 22:10:15 +02:00
</div>
<div class="mermaid-render"></div>
</div>`;
2021-09-30 13:02:07 +02:00
let idCounter = 1;
2021-09-30 09:48:03 +02:00
2021-09-30 13:02:07 +02:00
export default class MermaidWidget extends NoteContextAwareWidget {
2021-09-29 22:10:15 +02:00
isEnabled() {
2025-01-09 18:07:02 +02:00
return super.isEnabled() && this.note?.type === "mermaid" && this.note.isContentAvailable() && this.noteContext?.viewScope.viewMode === "default";
2021-09-29 22:10:15 +02:00
}
doRender() {
this.$widget = $(TPL);
this.contentSized();
2025-01-09 18:07:02 +02:00
this.$display = this.$widget.find(".mermaid-render");
2021-09-29 22:10:15 +02:00
this.$errorContainer = this.$widget.find(".mermaid-error");
this.$errorMessage = this.$errorContainer.find(".error-content");
}
async refreshWithNote(note) {
2021-09-30 13:02:07 +02:00
this.$errorContainer.hide();
2021-09-29 22:10:15 +02:00
await libraryLoader.requireLibrary(libraryLoader.MERMAID);
2021-09-30 13:48:01 +02:00
mermaid.mermaidAPI.initialize({
startOnLoad: false,
...getMermaidConfig()
2021-09-30 13:48:01 +02:00
});
2021-09-29 22:10:15 +02:00
this.$display.empty();
2022-07-29 00:32:28 +02:00
const wheelZoomLoaded = libraryLoader.requireLibrary(libraryLoader.WHEEL_ZOOM);
this.$errorContainer.hide();
2021-09-29 22:10:15 +02:00
try {
2023-07-14 19:56:37 +02:00
const svg = await this.renderSvg();
2023-01-24 23:09:00 +01:00
if (this.dirtyAttachment) {
const payload = {
2025-01-09 18:07:02 +02:00
role: "image",
title: "mermaid-export.svg",
mime: "image/svg+xml",
content: svg,
position: 0
};
server.post(`notes/${this.noteId}/attachments?matchBy=title`, payload).then(() => {
this.dirtyAttachment = false;
});
}
2023-07-14 19:56:37 +02:00
this.$display.html(svg);
2023-07-14 19:56:37 +02:00
await wheelZoomLoaded;
2021-09-29 22:10:15 +02:00
2023-07-14 19:56:37 +02:00
this.$display.attr("id", `mermaid-render-${idCounter}`);
WZoom.create(`#mermaid-render-${idCounter}`, {
2025-01-09 18:07:02 +02:00
type: "html",
2023-10-20 23:44:30 +02:00
maxScale: 50,
speed: 1.3,
2023-07-14 19:56:37 +02:00
zoomOnClick: false
2023-02-13 23:46:04 +01:00
});
2021-09-29 22:10:15 +02:00
} catch (e) {
console.warn(e);
2021-09-30 13:02:07 +02:00
this.$errorMessage.text(e.message);
2021-09-29 22:10:15 +02:00
this.$errorContainer.show();
}
}
2023-07-14 19:56:37 +02:00
async renderSvg() {
2023-02-13 23:46:04 +01:00
idCounter++;
2022-07-29 00:32:28 +02:00
2023-05-05 22:21:51 +02:00
const blob = await this.note.getBlob();
const content = blob.content || "";
2022-07-29 00:32:28 +02:00
await loadElkIfNeeded(content);
2025-01-09 18:07:02 +02:00
const { svg } = await mermaid.mermaidAPI.render(`mermaid-graph-${idCounter}`, content);
2023-07-14 19:56:37 +02:00
return svg;
2022-07-29 00:32:28 +02:00
}
2025-01-09 18:07:02 +02:00
async entitiesReloadedEvent({ loadResults }) {
2021-09-29 22:10:15 +02:00
if (loadResults.isNoteContentReloaded(this.noteId)) {
this.dirtyAttachment = true;
2021-09-29 22:10:15 +02:00
await this.refresh();
}
}
2022-07-29 00:32:28 +02:00
2025-01-09 18:07:02 +02:00
async exportSvgEvent({ ntxId }) {
if (!this.isNoteContext(ntxId) || this.note.type !== "mermaid") {
2022-07-29 00:32:28 +02:00
return;
}
2023-07-14 19:56:37 +02:00
const svg = await this.renderSvg();
2024-09-01 23:20:41 +03:00
utils.downloadSvg(this.note.title, svg);
2022-07-29 00:32:28 +02:00
}
2021-09-29 22:10:15 +02:00
}
export function getMermaidConfig() {
const documentStyle = window.getComputedStyle(document.documentElement);
2025-01-09 18:07:02 +02:00
const mermaidTheme = documentStyle.getPropertyValue("--mermaid-theme");
return {
theme: mermaidTheme.trim(),
2025-01-09 18:07:02 +02:00
securityLevel: "antiscript",
flow: { useMaxWidth: false },
sequence: { useMaxWidth: false },
gantt: { useMaxWidth: false },
2025-01-09 18:07:02 +02:00
class: { useMaxWidth: false },
state: { useMaxWidth: false },
pie: { useMaxWidth: true },
journey: { useMaxWidth: false },
2025-01-09 18:07:02 +02:00
git: { useMaxWidth: false }
};
}