chore(react/type_widget): render included notes in read-only text

This commit is contained in:
Elian Doran 2025-09-21 20:27:58 +03:00
parent 2f3c2bbac8
commit a8007b9063
No known key found for this signature in database
4 changed files with 47 additions and 42 deletions

View File

@ -1,7 +1,7 @@
import { useEffect, useMemo, useRef } from "preact/hooks";
import { TypeWidgetProps } from "../type_widget";
import "./ReadOnlyText.css";
import { useNoteBlob, useNoteLabel } from "../../react/hooks";
import { useNoteBlob, useNoteLabel, useTriliumEvent } from "../../react/hooks";
import RawHtml from "../../react/RawHtml";
// we load CKEditor also for read only notes because they contain content styles required for correct rendering of even read only notes
@ -11,19 +11,28 @@ import "@triliumnext/ckeditor5";
import FNote from "../../../entities/fnote";
import { getLocaleById } from "../../../services/i18n";
import { getMermaidConfig } from "../../../services/mermaid";
import { loadIncludedNote, refreshIncludedNote } from "./utils";
export default function ReadOnlyText({ note }: TypeWidgetProps) {
const blob = useNoteBlob(note);
const contentRef = useRef<HTMLDivElement>(null);
const { isRtl } = useNoteLanguage(note);
// Apply necessary transforms.
useEffect(() => {
const container = contentRef.current;
if (!container) return;
applyInlineMermaid(container);
applyIncludedNotes(container);
}, [ blob ]);
// React to included note changes.
useTriliumEvent("refreshIncludedNote", ({ noteId }) => {
if (!contentRef.current) return;
refreshIncludedNote(contentRef.current, noteId);
});
return (
<div
className="note-detail-readonly-text note-detail-printable"
@ -67,3 +76,13 @@ async function applyInlineMermaid(container: HTMLDivElement) {
mermaid.initialize(getMermaidConfig());
mermaid.run({ nodes });
}
function applyIncludedNotes(container: HTMLDivElement) {
const includedNotes = container.querySelectorAll("section.include-note");
for (const includedNote of includedNotes) {
const noteId = (includedNote as HTMLElement).dataset.noteId;
if (!noteId) continue;
loadIncludedNote(noteId, $(includedNote as HTMLElement));
}
}

View File

@ -0,0 +1,27 @@
import content_renderer from "../../../services/content_renderer";
import froca from "../../../services/froca";
import link from "../../../services/link";
export async function loadIncludedNote(noteId: string, $el: JQuery<HTMLElement>) {
const note = await froca.getNote(noteId);
if (!note) return;
const $wrapper = $('<div class="include-note-wrapper">');
const $link = await link.createLink(note.noteId, {
showTooltip: false
});
$wrapper.empty().append($('<h4 class="include-note-title">').append($link));
const { $renderedContent, type } = await content_renderer.getRenderedContent(note);
$wrapper.append($(`<div class="include-note-content type-${type}">`).append($renderedContent));
$el.empty().append($wrapper);
}
export function refreshIncludedNote(container: HTMLDivElement, noteId: string) {
const includedNotes = container.querySelectorAll(`section[data-note-id="${noteId}"]`);
for (const includedNote of includedNotes) {
loadIncludedNote(noteId, $(includedNote as HTMLElement));
}
}

View File

@ -79,38 +79,10 @@ export default class AbstractTextTypeWidget extends TypeWidget {
return null;
}
async loadIncludedNote(noteId: string, $el: JQuery<HTMLElement>) {
const note = await froca.getNote(noteId);
if (note) {
const $wrapper = $('<div class="include-note-wrapper">');
const $link = await linkService.createLink(note.noteId, {
showTooltip: false
});
$wrapper.empty().append($('<h4 class="include-note-title">').append($link));
const { $renderedContent, type } = await contentRenderer.getRenderedContent(note);
$wrapper.append($(`<div class="include-note-content type-${type}">`).append($renderedContent));
$el.empty().append($wrapper);
}
}
async loadReferenceLinkTitle($el: JQuery<HTMLElement>, href: string | null = null) {
await linkService.loadReferenceLinkTitle($el, href);
}
refreshIncludedNote($container: JQuery<HTMLElement>, noteId: string) {
if ($container) {
$container.find(`section[data-note-id="${noteId}"]`).each((_, el) => {
this.loadIncludedNote(noteId, $(el));
});
}
}
refreshCodeBlockOptions() {
const wordWrap = options.is("codeBlockWordWrap");
this.$widget.toggleClass("word-wrap", wordWrap);

View File

@ -37,26 +37,13 @@ export default class ReadOnlyTextTypeWidget extends AbstractTextTypeWidget {
this.loadReferenceLinkTitle($(el));
});
this.$content.find("section").each((_, el) => {
const noteId = $(el).attr("data-note-id");
if (noteId) {
this.loadIncludedNote(noteId, $(el));
}
});
if (this.$content.find("span.math-tex").length > 0) {
renderMathInElement(this.$content[0], { trust: true });
}
await this.#applyInlineMermaid();
await formatCodeBlocks(this.$content);
}
async refreshIncludedNoteEvent({ noteId }: EventData<"refreshIncludedNote">) {
this.refreshIncludedNote(this.$content, noteId);
}
async executeWithContentElementEvent({ resolve, ntxId }: EventData<"executeWithContentElement">) {
if (!this.isNoteContext(ntxId)) {
return;