mirror of
https://github.com/zadam/trilium.git
synced 2025-11-11 17:08:58 +01:00
chore(react/type_widgets): react to snippet changes
This commit is contained in:
parent
3673162a48
commit
a975576214
@ -1,5 +1,5 @@
|
|||||||
import { HTMLProps, RefObject, useEffect, useImperativeHandle, useRef, useState } from "preact/compat";
|
import { HTMLProps, RefObject, useEffect, useImperativeHandle, useRef, useState } from "preact/compat";
|
||||||
import { PopupEditor, ClassicEditor, EditorWatchdog, type WatchdogConfig, CKTextEditor } from "@triliumnext/ckeditor5";
|
import { PopupEditor, ClassicEditor, EditorWatchdog, type WatchdogConfig, CKTextEditor, TemplateDefinition } from "@triliumnext/ckeditor5";
|
||||||
import { buildConfig, BuildEditorOptions } from "./config";
|
import { buildConfig, BuildEditorOptions } from "./config";
|
||||||
import { useLegacyImperativeHandlers } from "../../react/hooks";
|
import { useLegacyImperativeHandlers } from "../../react/hooks";
|
||||||
import link from "../../../services/link";
|
import link from "../../../services/link";
|
||||||
@ -29,9 +29,10 @@ interface CKEditorWithWatchdogProps extends Pick<HTMLProps<HTMLDivElement>, "cla
|
|||||||
/** Called upon whenever a new CKEditor instance is initialized, whether it's the first initialization, after a crash or after a config change that requires it (e.g. content language). */
|
/** Called upon whenever a new CKEditor instance is initialized, whether it's the first initialization, after a crash or after a config change that requires it (e.g. content language). */
|
||||||
onEditorInitialized?: (editor: CKTextEditor) => void;
|
onEditorInitialized?: (editor: CKTextEditor) => void;
|
||||||
editorApi: RefObject<CKEditorApi>;
|
editorApi: RefObject<CKEditorApi>;
|
||||||
|
templates: TemplateDefinition[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function CKEditorWithWatchdog({ content, contentLanguage, className, tabIndex, isClassicEditor, watchdogRef: externalWatchdogRef, watchdogConfig, onNotificationWarning, onWatchdogStateChange, onChange, onEditorInitialized, editorApi }: CKEditorWithWatchdogProps) {
|
export default function CKEditorWithWatchdog({ content, contentLanguage, className, tabIndex, isClassicEditor, watchdogRef: externalWatchdogRef, watchdogConfig, onNotificationWarning, onWatchdogStateChange, onChange, onEditorInitialized, editorApi, templates }: CKEditorWithWatchdogProps) {
|
||||||
const containerRef = useRef<HTMLDivElement>(null);
|
const containerRef = useRef<HTMLDivElement>(null);
|
||||||
const watchdogRef = useRef<EditorWatchdog>(null);
|
const watchdogRef = useRef<EditorWatchdog>(null);
|
||||||
const [ editor, setEditor ] = useState<CKTextEditor>();
|
const [ editor, setEditor ] = useState<CKTextEditor>();
|
||||||
@ -130,7 +131,8 @@ export default function CKEditorWithWatchdog({ content, contentLanguage, classNa
|
|||||||
const editor = await buildEditor(container, !!isClassicEditor, {
|
const editor = await buildEditor(container, !!isClassicEditor, {
|
||||||
forceGplLicense: false,
|
forceGplLicense: false,
|
||||||
isClassicEditor: !!isClassicEditor,
|
isClassicEditor: !!isClassicEditor,
|
||||||
contentLanguage: contentLanguage ?? null
|
contentLanguage: contentLanguage ?? null,
|
||||||
|
templates
|
||||||
});
|
});
|
||||||
|
|
||||||
setEditor(editor);
|
setEditor(editor);
|
||||||
@ -153,7 +155,7 @@ export default function CKEditorWithWatchdog({ content, contentLanguage, classNa
|
|||||||
watchdog.create(container);
|
watchdog.create(container);
|
||||||
|
|
||||||
return () => watchdog.destroy();
|
return () => watchdog.destroy();
|
||||||
}, [ contentLanguage ]);
|
}, [ contentLanguage, templates ]);
|
||||||
|
|
||||||
// React to content changes.
|
// React to content changes.
|
||||||
useEffect(() => editor?.setData(content ?? ""), [ editor, content ]);
|
useEffect(() => editor?.setData(content ?? ""), [ editor, content ]);
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { useRef, useState } from "preact/hooks";
|
import { useEffect, useRef, useState } from "preact/hooks";
|
||||||
import dialog from "../../../services/dialog";
|
import dialog from "../../../services/dialog";
|
||||||
import toast from "../../../services/toast";
|
import toast from "../../../services/toast";
|
||||||
import utils, { deferred, isMobile } from "../../../services/utils";
|
import utils, { deferred, isMobile } from "../../../services/utils";
|
||||||
@ -6,10 +6,11 @@ import { useEditorSpacedUpdate, useKeyboardShortcuts, useLegacyImperativeHandler
|
|||||||
import { TypeWidgetProps } from "../type_widget";
|
import { TypeWidgetProps } from "../type_widget";
|
||||||
import CKEditorWithWatchdog, { CKEditorApi } from "./CKEditorWithWatchdog";
|
import CKEditorWithWatchdog, { CKEditorApi } from "./CKEditorWithWatchdog";
|
||||||
import "./EditableText.css";
|
import "./EditableText.css";
|
||||||
import { CKTextEditor, ClassicEditor, EditorWatchdog } from "@triliumnext/ckeditor5";
|
import { CKTextEditor, ClassicEditor, EditorWatchdog, TemplateDefinition } from "@triliumnext/ckeditor5";
|
||||||
import Component from "../../../components/component";
|
import Component from "../../../components/component";
|
||||||
import options from "../../../services/options";
|
import options from "../../../services/options";
|
||||||
import { loadIncludedNote, refreshIncludedNote } from "./utils";
|
import { loadIncludedNote, refreshIncludedNote } from "./utils";
|
||||||
|
import getTemplates, { updateTemplateCache } from "./snippets.js";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The editor can operate into two distinct modes:
|
* The editor can operate into two distinct modes:
|
||||||
@ -47,7 +48,8 @@ export default function EditableText({ note, parentComponent, ntxId, noteContext
|
|||||||
onContentChange(newContent) {
|
onContentChange(newContent) {
|
||||||
setContent(newContent);
|
setContent(newContent);
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
const templates = useTemplates();
|
||||||
|
|
||||||
useTriliumEvent("scrollToEnd", () => {
|
useTriliumEvent("scrollToEnd", () => {
|
||||||
const editor = watchdogRef.current?.editor;
|
const editor = watchdogRef.current?.editor;
|
||||||
@ -127,7 +129,7 @@ export default function EditableText({ note, parentComponent, ntxId, noteContext
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div ref={containerRef} class={`note-detail-editable-text note-detail-printable ${codeBlockWordWrap ? "word-wrap" : ""}`}>
|
<div ref={containerRef} class={`note-detail-editable-text note-detail-printable ${codeBlockWordWrap ? "word-wrap" : ""}`}>
|
||||||
{note && <CKEditorWithWatchdog
|
{note && !!templates && <CKEditorWithWatchdog
|
||||||
className="note-detail-editable-text-editor use-tn-links"
|
className="note-detail-editable-text-editor use-tn-links"
|
||||||
tabIndex={300}
|
tabIndex={300}
|
||||||
content={content}
|
content={content}
|
||||||
@ -143,6 +145,7 @@ export default function EditableText({ note, parentComponent, ntxId, noteContext
|
|||||||
// A minimum number of milliseconds between saving the editor data internally (defaults to 5000). Note that for large documents, this might impact the editor performance.
|
// A minimum number of milliseconds between saving the editor data internally (defaults to 5000). Note that for large documents, this might impact the editor performance.
|
||||||
saveInterval: 5000
|
saveInterval: 5000
|
||||||
}}
|
}}
|
||||||
|
templates={templates}
|
||||||
onNotificationWarning={onNotificationWarning}
|
onNotificationWarning={onNotificationWarning}
|
||||||
onWatchdogStateChange={onWatchdogStateChange}
|
onWatchdogStateChange={onWatchdogStateChange}
|
||||||
onChange={() => spacedUpdate.scheduleUpdate()}
|
onChange={() => spacedUpdate.scheduleUpdate()}
|
||||||
@ -160,6 +163,25 @@ export default function EditableText({ note, parentComponent, ntxId, noteContext
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function useTemplates() {
|
||||||
|
const [ templates, setTemplates ] = useState<TemplateDefinition[]>();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
getTemplates().then(setTemplates);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useTriliumEvent("entitiesReloaded", async ({ loadResults }) => {
|
||||||
|
console.log("Reloaded ", loadResults);
|
||||||
|
const newTemplates = await updateTemplateCache(loadResults);
|
||||||
|
if (newTemplates) {
|
||||||
|
console.log("Got new templates!", newTemplates);
|
||||||
|
setTemplates(newTemplates);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return templates;
|
||||||
|
}
|
||||||
|
|
||||||
function onWatchdogStateChange(watchdog: EditorWatchdog) {
|
function onWatchdogStateChange(watchdog: EditorWatchdog) {
|
||||||
const currentState = watchdog.state;
|
const currentState = watchdog.state;
|
||||||
logInfo(`CKEditor state changed to ${currentState}`);
|
logInfo(`CKEditor state changed to ${currentState}`);
|
||||||
|
|||||||
@ -1,12 +1,11 @@
|
|||||||
import { ALLOWED_PROTOCOLS } from "../../../services/link.js";
|
import { ALLOWED_PROTOCOLS } from "../../../services/link.js";
|
||||||
import { MIME_TYPE_AUTO } from "@triliumnext/commons";
|
import { MIME_TYPE_AUTO } from "@triliumnext/commons";
|
||||||
import { buildExtraCommands, type EditorConfig, PREMIUM_PLUGINS } from "@triliumnext/ckeditor5";
|
import { buildExtraCommands, type EditorConfig, PREMIUM_PLUGINS, TemplateDefinition } from "@triliumnext/ckeditor5";
|
||||||
import { getHighlightJsNameForMime } from "../../../services/mime_types.js";
|
import { getHighlightJsNameForMime } from "../../../services/mime_types.js";
|
||||||
import options from "../../../services/options.js";
|
import options from "../../../services/options.js";
|
||||||
import { ensureMimeTypesForHighlighting, isSyntaxHighlightEnabled } from "../../../services/syntax_highlight.js";
|
import { ensureMimeTypesForHighlighting, isSyntaxHighlightEnabled } from "../../../services/syntax_highlight.js";
|
||||||
import emojiDefinitionsUrl from "@triliumnext/ckeditor5/src/emoji_definitions/en.json?url";
|
import emojiDefinitionsUrl from "@triliumnext/ckeditor5/src/emoji_definitions/en.json?url";
|
||||||
import { copyTextWithToast } from "../../../services/clipboard_ext.js";
|
import { copyTextWithToast } from "../../../services/clipboard_ext.js";
|
||||||
import getTemplates from "./snippets.js";
|
|
||||||
import { t } from "../../../services/i18n.js";
|
import { t } from "../../../services/i18n.js";
|
||||||
import { getMermaidConfig } from "../../../services/mermaid.js";
|
import { getMermaidConfig } from "../../../services/mermaid.js";
|
||||||
import noteAutocompleteService, { type Suggestion } from "../../../services/note_autocomplete.js";
|
import noteAutocompleteService, { type Suggestion } from "../../../services/note_autocomplete.js";
|
||||||
@ -20,6 +19,7 @@ export interface BuildEditorOptions {
|
|||||||
forceGplLicense: boolean;
|
forceGplLicense: boolean;
|
||||||
isClassicEditor: boolean;
|
isClassicEditor: boolean;
|
||||||
contentLanguage: string | null;
|
contentLanguage: string | null;
|
||||||
|
templates: TemplateDefinition[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function buildConfig(opts: BuildEditorOptions): Promise<EditorConfig> {
|
export async function buildConfig(opts: BuildEditorOptions): Promise<EditorConfig> {
|
||||||
@ -157,7 +157,7 @@ export async function buildConfig(opts: BuildEditorOptions): Promise<EditorConfi
|
|||||||
extraCommands: buildExtraCommands()
|
extraCommands: buildExtraCommands()
|
||||||
},
|
},
|
||||||
template: {
|
template: {
|
||||||
definitions: await getTemplates()
|
definitions: opts.templates
|
||||||
},
|
},
|
||||||
htmlSupport: {
|
htmlSupport: {
|
||||||
allow: JSON.parse(options.get("allowedHtmlTags"))
|
allow: JSON.parse(options.get("allowedHtmlTags"))
|
||||||
|
|||||||
@ -96,18 +96,22 @@ async function handleContentUpdate(affectedNoteIds: string[]) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function updateTemplateCache(loadResults: LoadResults): boolean {
|
export async function updateTemplateCache(loadResults: LoadResults): Promise<TemplateDefinition[] | null> {
|
||||||
const affectedNoteIds = loadResults.getNoteIds();
|
const affectedNoteIds = loadResults.getNoteIds();
|
||||||
|
|
||||||
// React to creation or deletion of text snippets.
|
// React to creation or deletion of text snippets.
|
||||||
if (loadResults.getAttributeRows().find((attr) =>
|
if (loadResults.getAttributeRows().find((attr) => {
|
||||||
attr.type === "label" &&
|
if (attr.type === "label") {
|
||||||
(attr.name === "textSnippet" || attr.name === "textSnippetDescription"))) {
|
return (attr.name === "textSnippet" || attr.name === "textSnippetDescription");
|
||||||
handleFullReload();
|
} else if (attr.type === "relation") {
|
||||||
|
return (attr.value === "_template_text_snippet");
|
||||||
|
}
|
||||||
|
})) {
|
||||||
|
return await getTemplates();
|
||||||
} else if (affectedNoteIds.length > 0) {
|
} else if (affectedNoteIds.length > 0) {
|
||||||
// Update content and titles if one of the template notes were updated.
|
// Update content and titles if one of the template notes were updated.
|
||||||
debouncedHandleContentUpdate(affectedNoteIds);
|
debouncedHandleContentUpdate(affectedNoteIds);
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -12,7 +12,6 @@ import { buildSelectedBackgroundColor } from "../../components/touch_bar.js";
|
|||||||
import { buildConfig, BuildEditorOptions, OPEN_SOURCE_LICENSE_KEY } from "./ckeditor/config.js";
|
import { buildConfig, BuildEditorOptions, OPEN_SOURCE_LICENSE_KEY } from "./ckeditor/config.js";
|
||||||
import type FNote from "../../entities/fnote.js";
|
import type FNote from "../../entities/fnote.js";
|
||||||
import { PopupEditor, ClassicEditor, EditorWatchdog, type CKTextEditor, type MentionFeed, type WatchdogConfig, EditorConfig } from "@triliumnext/ckeditor5";
|
import { PopupEditor, ClassicEditor, EditorWatchdog, type CKTextEditor, type MentionFeed, type WatchdogConfig, EditorConfig } from "@triliumnext/ckeditor5";
|
||||||
import { updateTemplateCache } from "./ckeditor/snippets.js";
|
|
||||||
|
|
||||||
|
|
||||||
export default class EditableTextTypeWidget extends AbstractTextTypeWidget {
|
export default class EditableTextTypeWidget extends AbstractTextTypeWidget {
|
||||||
@ -54,8 +53,6 @@ export default class EditableTextTypeWidget extends AbstractTextTypeWidget {
|
|||||||
return this.watchdog?.editor;
|
return this.watchdog?.editor;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
async executeWithTextEditorEvent({ callback, resolve, ntxId }: EventData<"executeWithTextEditor">) {
|
async executeWithTextEditorEvent({ callback, resolve, ntxId }: EventData<"executeWithTextEditor">) {
|
||||||
if (!this.isNoteContext(ntxId)) {
|
if (!this.isNoteContext(ntxId)) {
|
||||||
return;
|
return;
|
||||||
@ -130,14 +127,6 @@ export default class EditableTextTypeWidget extends AbstractTextTypeWidget {
|
|||||||
await this.reinitialize();
|
await this.reinitialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
async entitiesReloadedEvent(e: EventData<"entitiesReloaded">) {
|
|
||||||
await super.entitiesReloadedEvent(e);
|
|
||||||
|
|
||||||
if (updateTemplateCache(e.loadResults)) {
|
|
||||||
await this.reinitialize();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
buildTouchBarCommand(data: CommandListenerData<"buildTouchBar">) {
|
buildTouchBarCommand(data: CommandListenerData<"buildTouchBar">) {
|
||||||
const { TouchBar, buildIcon } = data;
|
const { TouchBar, buildIcon } = data;
|
||||||
const { TouchBarSegmentedControl, TouchBarGroup, TouchBarButton } = TouchBar;
|
const { TouchBarSegmentedControl, TouchBarGroup, TouchBarButton } = TouchBar;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user