From a8007b9063de5cb6974cff8930f9416eb968949b Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sun, 21 Sep 2025 20:27:58 +0300 Subject: [PATCH] chore(react/type_widget): render included notes in read-only text --- .../type_widgets/text/ReadOnlyText.tsx | 21 +++++++++++++- .../src/widgets/type_widgets/text/utils.ts | 27 ++++++++++++++++++ .../abstract_text_type_widget.ts | 28 ------------------- .../type_widgets_old/read_only_text.ts | 13 --------- 4 files changed, 47 insertions(+), 42 deletions(-) create mode 100644 apps/client/src/widgets/type_widgets/text/utils.ts diff --git a/apps/client/src/widgets/type_widgets/text/ReadOnlyText.tsx b/apps/client/src/widgets/type_widgets/text/ReadOnlyText.tsx index 87eb2cc35..8e03b4218 100644 --- a/apps/client/src/widgets/type_widgets/text/ReadOnlyText.tsx +++ b/apps/client/src/widgets/type_widgets/text/ReadOnlyText.tsx @@ -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(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 (
) { + const note = await froca.getNote(noteId); + if (!note) return; + + const $wrapper = $('
'); + const $link = await link.createLink(note.noteId, { + showTooltip: false + }); + + $wrapper.empty().append($('

').append($link)); + + const { $renderedContent, type } = await content_renderer.getRenderedContent(note); + $wrapper.append($(`
`).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)); + } +} diff --git a/apps/client/src/widgets/type_widgets_old/abstract_text_type_widget.ts b/apps/client/src/widgets/type_widgets_old/abstract_text_type_widget.ts index 5061d3b57..6b04f26df 100644 --- a/apps/client/src/widgets/type_widgets_old/abstract_text_type_widget.ts +++ b/apps/client/src/widgets/type_widgets_old/abstract_text_type_widget.ts @@ -79,38 +79,10 @@ export default class AbstractTextTypeWidget extends TypeWidget { return null; } - async loadIncludedNote(noteId: string, $el: JQuery) { - const note = await froca.getNote(noteId); - - if (note) { - const $wrapper = $('
'); - - const $link = await linkService.createLink(note.noteId, { - showTooltip: false - }); - - $wrapper.empty().append($('

').append($link)); - - const { $renderedContent, type } = await contentRenderer.getRenderedContent(note); - - $wrapper.append($(`
`).append($renderedContent)); - - $el.empty().append($wrapper); - } - } - async loadReferenceLinkTitle($el: JQuery, href: string | null = null) { await linkService.loadReferenceLinkTitle($el, href); } - refreshIncludedNote($container: JQuery, 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); diff --git a/apps/client/src/widgets/type_widgets_old/read_only_text.ts b/apps/client/src/widgets/type_widgets_old/read_only_text.ts index e6a8006fb..8b36c15db 100644 --- a/apps/client/src/widgets/type_widgets_old/read_only_text.ts +++ b/apps/client/src/widgets/type_widgets_old/read_only_text.ts @@ -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;