mirror of
https://github.com/zadam/trilium.git
synced 2025-11-11 17:08:58 +01:00
chore(react/type_widget): add code block & image integration
This commit is contained in:
parent
fb46e09428
commit
2947682783
@ -11,11 +11,12 @@ import "@triliumnext/ckeditor5";
|
|||||||
import FNote from "../../../entities/fnote";
|
import FNote from "../../../entities/fnote";
|
||||||
import { getLocaleById } from "../../../services/i18n";
|
import { getLocaleById } from "../../../services/i18n";
|
||||||
import { getMermaidConfig } from "../../../services/mermaid";
|
import { getMermaidConfig } from "../../../services/mermaid";
|
||||||
import { loadIncludedNote, refreshIncludedNote } from "./utils";
|
import { loadIncludedNote, refreshIncludedNote, setupImageOpening } from "./utils";
|
||||||
import { renderMathInElement } from "../../../services/math";
|
import { renderMathInElement } from "../../../services/math";
|
||||||
import link from "../../../services/link";
|
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 blob = useNoteBlob(note);
|
||||||
const contentRef = useRef<HTMLDivElement>(null);
|
const contentRef = useRef<HTMLDivElement>(null);
|
||||||
const { isRtl } = useNoteLanguage(note);
|
const { isRtl } = useNoteLanguage(note);
|
||||||
@ -29,6 +30,8 @@ export default function ReadOnlyText({ note }: TypeWidgetProps) {
|
|||||||
applyIncludedNotes(container);
|
applyIncludedNotes(container);
|
||||||
applyMath(container);
|
applyMath(container);
|
||||||
applyReferenceLinks(container);
|
applyReferenceLinks(container);
|
||||||
|
formatCodeBlocks($(container));
|
||||||
|
setupImageOpening(container, true);
|
||||||
}, [ blob ]);
|
}, [ blob ]);
|
||||||
|
|
||||||
// React to included note changes.
|
// React to included note changes.
|
||||||
@ -37,6 +40,12 @@ export default function ReadOnlyText({ note }: TypeWidgetProps) {
|
|||||||
refreshIncludedNote(contentRef.current, noteId);
|
refreshIncludedNote(contentRef.current, noteId);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Search integration.
|
||||||
|
useTriliumEvent("executeWithContentElement", ({ resolve, ntxId: eventNtxId }) => {
|
||||||
|
if (eventNtxId !== ntxId || !contentRef.current) return;
|
||||||
|
resolve($(contentRef.current));
|
||||||
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className="note-detail-readonly-text note-detail-printable"
|
className="note-detail-readonly-text note-detail-printable"
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
|
import appContext from "../../../components/app_context";
|
||||||
import content_renderer from "../../../services/content_renderer";
|
import content_renderer from "../../../services/content_renderer";
|
||||||
import froca from "../../../services/froca";
|
import froca from "../../../services/froca";
|
||||||
import link from "../../../services/link";
|
import link from "../../../services/link";
|
||||||
|
import utils from "../../../services/utils";
|
||||||
|
|
||||||
export async function loadIncludedNote(noteId: string, $el: JQuery<HTMLElement>) {
|
export async function loadIncludedNote(noteId: string, $el: JQuery<HTMLElement>) {
|
||||||
const note = await froca.getNote(noteId);
|
const note = await froca.getNote(noteId);
|
||||||
@ -25,3 +27,69 @@ export function refreshIncludedNote(container: HTMLDivElement, noteId: string) {
|
|||||||
loadIncludedNote(noteId, $(includedNote as HTMLElement));
|
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<HTMLElement>) {
|
||||||
|
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<HTMLElement>, 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<HTMLElement>) {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|||||||
@ -13,71 +13,6 @@ export default class AbstractTextTypeWidget extends TypeWidget {
|
|||||||
this.refreshCodeBlockOptions();
|
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<HTMLElement>) {
|
|
||||||
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<HTMLElement>, 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<HTMLElement>) {
|
|
||||||
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<HTMLElement>, href: string | null = null) {
|
async loadReferenceLinkTitle($el: JQuery<HTMLElement>, href: string | null = null) {
|
||||||
await linkService.loadReferenceLinkTitle($el, href);
|
await linkService.loadReferenceLinkTitle($el, href);
|
||||||
|
|||||||
@ -5,39 +5,6 @@ import type { CommandListenerData, EventData } from "../../components/app_contex
|
|||||||
import appContext from "../../components/app_context.js";
|
import appContext from "../../components/app_context.js";
|
||||||
|
|
||||||
export default class ReadOnlyTextTypeWidget extends AbstractTextTypeWidget {
|
export default class ReadOnlyTextTypeWidget extends AbstractTextTypeWidget {
|
||||||
|
|
||||||
private $content!: JQuery<HTMLElement>;
|
|
||||||
|
|
||||||
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">) {
|
buildTouchBarCommand({ TouchBar, buildIcon }: CommandListenerData<"buildTouchBar">) {
|
||||||
return [
|
return [
|
||||||
new TouchBar.TouchBarSpacer({ size: "flexible" }),
|
new TouchBar.TouchBarSpacer({ size: "flexible" }),
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user