diff --git a/apps/client/src/widgets/type_widgets/text/ReadOnlyText.tsx b/apps/client/src/widgets/type_widgets/text/ReadOnlyText.tsx index 45e824d5a..8b916aae5 100644 --- a/apps/client/src/widgets/type_widgets/text/ReadOnlyText.tsx +++ b/apps/client/src/widgets/type_widgets/text/ReadOnlyText.tsx @@ -11,11 +11,12 @@ import "@triliumnext/ckeditor5"; import FNote from "../../../entities/fnote"; import { getLocaleById } from "../../../services/i18n"; import { getMermaidConfig } from "../../../services/mermaid"; -import { loadIncludedNote, refreshIncludedNote } from "./utils"; +import { loadIncludedNote, refreshIncludedNote, setupImageOpening } from "./utils"; import { renderMathInElement } from "../../../services/math"; import link from "../../../services/link"; +import { formatCodeBlocks } from "../../../services/syntax_highlight"; -export default function ReadOnlyText({ note }: TypeWidgetProps) { +export default function ReadOnlyText({ note, ntxId }: TypeWidgetProps) { const blob = useNoteBlob(note); const contentRef = useRef(null); const { isRtl } = useNoteLanguage(note); @@ -29,6 +30,8 @@ export default function ReadOnlyText({ note }: TypeWidgetProps) { applyIncludedNotes(container); applyMath(container); applyReferenceLinks(container); + formatCodeBlocks($(container)); + setupImageOpening(container, true); }, [ blob ]); // React to included note changes. @@ -37,6 +40,12 @@ export default function ReadOnlyText({ note }: TypeWidgetProps) { refreshIncludedNote(contentRef.current, noteId); }); + // Search integration. + useTriliumEvent("executeWithContentElement", ({ resolve, ntxId: eventNtxId }) => { + if (eventNtxId !== ntxId || !contentRef.current) return; + resolve($(contentRef.current)); + }); + return (
) { const note = await froca.getNote(noteId); @@ -25,3 +27,69 @@ export function refreshIncludedNote(container: HTMLDivElement, noteId: string) { loadIncludedNote(noteId, $(includedNote as HTMLElement)); } } + +export function setupImageOpening(container: HTMLDivElement, singleClickOpens: boolean) { + const $container = $(container); + $container.on("dblclick", "img", (e) => openImageInCurrentTab($(e.target))); + $container.on("click", "img", (e) => { + e.stopPropagation(); + const isLeftClick = e.which === 1; + const isMiddleClick = e.which === 2; + const ctrlKey = utils.isCtrlKey(e); + const activate = (isLeftClick && ctrlKey && e.shiftKey) || (isMiddleClick && e.shiftKey); + + if ((isLeftClick && ctrlKey) || isMiddleClick) { + openImageInNewTab($(e.target), activate); + } else if (isLeftClick && singleClickOpens) { + openImageInCurrentTab($(e.target)); + } + }); +} + +async function openImageInCurrentTab($img: JQuery) { + const parsedImage = await parseFromImage($img); + + if (parsedImage) { + appContext.tabManager.getActiveContext()?.setNote(parsedImage.noteId, { viewScope: parsedImage.viewScope }); + } else { + window.open($img.prop("src"), "_blank"); + } +} + +async function openImageInNewTab($img: JQuery, activate: boolean = false) { + const parsedImage = await parseFromImage($img); + + if (parsedImage) { + appContext.tabManager.openTabWithNoteWithHoisting(parsedImage.noteId, { activate, viewScope: parsedImage.viewScope }); + } else { + window.open($img.prop("src"), "_blank"); + } +} + +async function parseFromImage($img: JQuery) { + const imgSrc = $img.prop("src"); + + const imageNoteMatch = imgSrc.match(/\/api\/images\/([A-Za-z0-9_]+)\//); + if (imageNoteMatch) { + return { + noteId: imageNoteMatch[1], + viewScope: {} + }; + } + + const attachmentMatch = imgSrc.match(/\/api\/attachments\/([A-Za-z0-9_]+)\/image\//); + if (attachmentMatch) { + const attachmentId = attachmentMatch[1]; + const attachment = await froca.getAttachment(attachmentId); + + return { + noteId: attachment?.ownerId, + viewScope: { + viewMode: "attachments", + attachmentId: attachmentId + } + }; + } + + return null; +} 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 6b04f26df..8530bae9a 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 @@ -13,71 +13,6 @@ export default class AbstractTextTypeWidget extends TypeWidget { this.refreshCodeBlockOptions(); } - setupImageOpening(singleClickOpens: boolean) { - this.$widget.on("dblclick", "img", (e) => this.openImageInCurrentTab($(e.target))); - - this.$widget.on("click", "img", (e) => { - e.stopPropagation(); - const isLeftClick = e.which === 1; - const isMiddleClick = e.which === 2; - const ctrlKey = utils.isCtrlKey(e); - const activate = (isLeftClick && ctrlKey && e.shiftKey) || (isMiddleClick && e.shiftKey); - - if ((isLeftClick && ctrlKey) || isMiddleClick) { - this.openImageInNewTab($(e.target), activate); - } else if (isLeftClick && singleClickOpens) { - this.openImageInCurrentTab($(e.target)); - } - }); - } - - async openImageInCurrentTab($img: JQuery) { - const parsedImage = await this.parseFromImage($img); - - if (parsedImage) { - appContext.tabManager.getActiveContext()?.setNote(parsedImage.noteId, { viewScope: parsedImage.viewScope }); - } else { - window.open($img.prop("src"), "_blank"); - } - } - - async openImageInNewTab($img: JQuery, activate: boolean = false) { - const parsedImage = await this.parseFromImage($img); - - if (parsedImage) { - appContext.tabManager.openTabWithNoteWithHoisting(parsedImage.noteId, { activate, viewScope: parsedImage.viewScope }); - } else { - window.open($img.prop("src"), "_blank"); - } - } - - async parseFromImage($img: JQuery) { - const imgSrc = $img.prop("src"); - - const imageNoteMatch = imgSrc.match(/\/api\/images\/([A-Za-z0-9_]+)\//); - if (imageNoteMatch) { - return { - noteId: imageNoteMatch[1], - viewScope: {} - }; - } - - const attachmentMatch = imgSrc.match(/\/api\/attachments\/([A-Za-z0-9_]+)\/image\//); - if (attachmentMatch) { - const attachmentId = attachmentMatch[1]; - const attachment = await froca.getAttachment(attachmentId); - - return { - noteId: attachment?.ownerId, - viewScope: { - viewMode: "attachments", - attachmentId: attachmentId - } - }; - } - - return null; - } async loadReferenceLinkTitle($el: JQuery, href: string | null = null) { await linkService.loadReferenceLinkTitle($el, href); 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 5a4724f22..407083c43 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 @@ -5,39 +5,6 @@ import type { CommandListenerData, EventData } from "../../components/app_contex import appContext from "../../components/app_context.js"; export default class ReadOnlyTextTypeWidget extends AbstractTextTypeWidget { - - private $content!: JQuery; - - static getType() { - return "readOnlyText"; - } - - doRender() { - this.$content = this.$widget.find(".note-detail-readonly-text-content"); - - this.setupImageOpening(true); - - super.doRender(); - } - - cleanup() { - this.$content.html(""); - } - - async doRefresh(note: FNote) { - await formatCodeBlocks(this.$content); - } - - async executeWithContentElementEvent({ resolve, ntxId }: EventData<"executeWithContentElement">) { - if (!this.isNoteContext(ntxId)) { - return; - } - - await this.initialized; - - resolve(this.$content); - } - buildTouchBarCommand({ TouchBar, buildIcon }: CommandListenerData<"buildTouchBar">) { return [ new TouchBar.TouchBarSpacer({ size: "flexible" }),