mirror of
https://github.com/zadam/trilium.git
synced 2025-11-01 10:55:55 +01:00
chore(react/type_widgets): save if needed
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
import { useNoteContext, useTriliumEvent } from "./react/hooks"
|
import { useNoteContext, useTriliumEvent, useTriliumEvents } from "./react/hooks"
|
||||||
import FNote from "../entities/fnote";
|
import FNote from "../entities/fnote";
|
||||||
import protected_session_holder from "../services/protected_session_holder";
|
import protected_session_holder from "../services/protected_session_holder";
|
||||||
import { useEffect, useRef, useState } from "preact/hooks";
|
import { useEffect, useRef, useState } from "preact/hooks";
|
||||||
@@ -9,6 +9,7 @@ import "./NoteDetail.css";
|
|||||||
import attributes from "../services/attributes";
|
import attributes from "../services/attributes";
|
||||||
import { ExtendedNoteType, TYPE_MAPPINGS } from "./note_types";
|
import { ExtendedNoteType, TYPE_MAPPINGS } from "./note_types";
|
||||||
import { dynamicRequire, isMobile } from "../services/utils";
|
import { dynamicRequire, isMobile } from "../services/utils";
|
||||||
|
import { ReactWrappedWidget } from "./basic_widget";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The note detail is in charge of rendering the content of a note, by determining its type (e.g. text, code) and using the appropriate view widget.
|
* The note detail is in charge of rendering the content of a note, by determining its type (e.g. text, code) and using the appropriate view widget.
|
||||||
|
|||||||
@@ -13,18 +13,6 @@ export default class NoteDetailWidget extends NoteContextAwareWidget {
|
|||||||
appContext.addBeforeUnloadListener(this);
|
appContext.addBeforeUnloadListener(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
async beforeNoteSwitchEvent({ noteContext }: EventData<"beforeNoteSwitch">) {
|
|
||||||
if (this.isNoteContext(noteContext.ntxId)) {
|
|
||||||
await this.spacedUpdate.updateNowIfNecessary();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async beforeNoteContextRemoveEvent({ ntxIds }: EventData<"beforeNoteContextRemove">) {
|
|
||||||
if (this.isNoteContext(ntxIds)) {
|
|
||||||
await this.spacedUpdate.updateNowIfNecessary();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async runActiveNoteCommand(params: CommandListenerData<"runActiveNote">) {
|
async runActiveNoteCommand(params: CommandListenerData<"runActiveNote">) {
|
||||||
if (this.isNoteContext(params.ntxId)) {
|
if (this.isNoteContext(params.ntxId)) {
|
||||||
// make sure that script is saved before running it #4028
|
// make sure that script is saved before running it #4028
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import protected_session_holder from "../../services/protected_session_holder";
|
|||||||
import server from "../../services/server";
|
import server from "../../services/server";
|
||||||
import { removeIndividualBinding } from "../../services/shortcuts";
|
import { removeIndividualBinding } from "../../services/shortcuts";
|
||||||
import { ViewScope } from "../../services/link";
|
import { ViewScope } from "../../services/link";
|
||||||
|
import { VirtualConsolePrinter } from "happy-dom";
|
||||||
|
|
||||||
export function useTriliumEvent<T extends EventNames>(eventName: T, handler: (data: EventData<T>) => void) {
|
export function useTriliumEvent<T extends EventNames>(eventName: T, handler: (data: EventData<T>) => void) {
|
||||||
const parentComponent = useContext(ParentComponent);
|
const parentComponent = useContext(ParentComponent);
|
||||||
@@ -77,8 +78,9 @@ export function useSpacedUpdate(callback: () => void | Promise<void>, interval =
|
|||||||
return spacedUpdateRef.current;
|
return spacedUpdateRef.current;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useEditorSpacedUpdate({ note, getData, onContentChange, dataSaved, updateInterval }: {
|
export function useEditorSpacedUpdate({ note, noteContext, getData, onContentChange, dataSaved, updateInterval }: {
|
||||||
note: FNote,
|
note: FNote,
|
||||||
|
noteContext: NoteContext | null | undefined,
|
||||||
getData: () => Promise<object | undefined> | object | undefined,
|
getData: () => Promise<object | undefined> | object | undefined,
|
||||||
onContentChange: (newContent: string) => void,
|
onContentChange: (newContent: string) => void,
|
||||||
dataSaved?: () => void,
|
dataSaved?: () => void,
|
||||||
@@ -114,6 +116,18 @@ export function useEditorSpacedUpdate({ note, getData, onContentChange, dataSave
|
|||||||
spacedUpdate.setUpdateInterval(updateInterval);
|
spacedUpdate.setUpdateInterval(updateInterval);
|
||||||
}, [ updateInterval ]);
|
}, [ updateInterval ]);
|
||||||
|
|
||||||
|
// Save if needed upon switching tabs.
|
||||||
|
useTriliumEvent("beforeNoteSwitch", async ({ noteContext: eventNoteContext }) => {
|
||||||
|
if (eventNoteContext.ntxId !== noteContext?.ntxId) return;
|
||||||
|
await spacedUpdate.updateNowIfNecessary();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Save if needed upon tab closing.
|
||||||
|
useTriliumEvent("beforeNoteContextRemove", async ({ ntxIds }) => {
|
||||||
|
if (!noteContext?.ntxId || !ntxIds.includes(noteContext.ntxId)) return;
|
||||||
|
await spacedUpdate.updateNowIfNecessary();
|
||||||
|
})
|
||||||
|
|
||||||
return spacedUpdate;
|
return spacedUpdate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ export default function AiChat({ note, noteContext }: TypeWidgetProps) {
|
|||||||
const dataRef = useRef<object>();
|
const dataRef = useRef<object>();
|
||||||
const spacedUpdate = useEditorSpacedUpdate({
|
const spacedUpdate = useEditorSpacedUpdate({
|
||||||
note,
|
note,
|
||||||
|
noteContext,
|
||||||
getData: async () => ({
|
getData: async () => ({
|
||||||
content: JSON.stringify(dataRef.current)
|
content: JSON.stringify(dataRef.current)
|
||||||
}),
|
}),
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import { RefObject } from "preact";
|
|||||||
import server from "../../services/server";
|
import server from "../../services/server";
|
||||||
import { ExcalidrawElement, NonDeletedExcalidrawElement } from "@excalidraw/excalidraw/element/types";
|
import { ExcalidrawElement, NonDeletedExcalidrawElement } from "@excalidraw/excalidraw/element/types";
|
||||||
import { goToLinkExt } from "../../services/link";
|
import { goToLinkExt } from "../../services/link";
|
||||||
|
import NoteContext from "../../components/note_context";
|
||||||
|
|
||||||
// currently required by excalidraw, in order to allows self-hosting fonts locally.
|
// currently required by excalidraw, in order to allows self-hosting fonts locally.
|
||||||
// this avoids making excalidraw load the fonts from an external CDN.
|
// this avoids making excalidraw load the fonts from an external CDN.
|
||||||
@@ -27,14 +28,14 @@ interface CanvasContent {
|
|||||||
appState: Partial<AppState>;
|
appState: Partial<AppState>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function Canvas({ note }: TypeWidgetProps) {
|
export default function Canvas({ note, noteContext }: TypeWidgetProps) {
|
||||||
const apiRef = useRef<ExcalidrawImperativeAPI>(null);
|
const apiRef = useRef<ExcalidrawImperativeAPI>(null);
|
||||||
const [ isReadOnly ] = useNoteLabelBoolean(note, "readOnly");
|
const [ isReadOnly ] = useNoteLabelBoolean(note, "readOnly");
|
||||||
const themeStyle = useMemo(() => {
|
const themeStyle = useMemo(() => {
|
||||||
const documentStyle = window.getComputedStyle(document.documentElement);
|
const documentStyle = window.getComputedStyle(document.documentElement);
|
||||||
return documentStyle.getPropertyValue("--theme-style")?.trim() as AppState["theme"];
|
return documentStyle.getPropertyValue("--theme-style")?.trim() as AppState["theme"];
|
||||||
}, []);
|
}, []);
|
||||||
const persistence = usePersistence(note, apiRef, themeStyle, isReadOnly);
|
const persistence = usePersistence(note, noteContext, apiRef, themeStyle, isReadOnly);
|
||||||
|
|
||||||
/** Use excalidraw's native zoom instead of the global zoom. */
|
/** Use excalidraw's native zoom instead of the global zoom. */
|
||||||
const onWheel = useCallback((e: MouseEvent) => {
|
const onWheel = useCallback((e: MouseEvent) => {
|
||||||
@@ -85,7 +86,7 @@ export default function Canvas({ note }: TypeWidgetProps) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function usePersistence(note: FNote, apiRef: RefObject<ExcalidrawImperativeAPI>, theme: AppState["theme"], isReadOnly: boolean): Partial<ExcalidrawProps> {
|
function usePersistence(note: FNote, noteContext: NoteContext, apiRef: RefObject<ExcalidrawImperativeAPI>, theme: AppState["theme"], isReadOnly: boolean): Partial<ExcalidrawProps> {
|
||||||
const libraryChanged = useRef(false);
|
const libraryChanged = useRef(false);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -104,6 +105,7 @@ function usePersistence(note: FNote, apiRef: RefObject<ExcalidrawImperativeAPI>,
|
|||||||
|
|
||||||
const spacedUpdate = useEditorSpacedUpdate({
|
const spacedUpdate = useEditorSpacedUpdate({
|
||||||
note,
|
note,
|
||||||
|
noteContext,
|
||||||
onContentChange(newContent) {
|
onContentChange(newContent) {
|
||||||
const api = apiRef.current;
|
const api = apiRef.current;
|
||||||
if (!api) return;
|
if (!api) return;
|
||||||
|
|||||||
@@ -22,13 +22,14 @@ interface MindElixirProps {
|
|||||||
onChange?: () => void;
|
onChange?: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function MindMap({ note, ntxId }: TypeWidgetProps) {
|
export default function MindMap({ note, ntxId, noteContext }: TypeWidgetProps) {
|
||||||
const content = VanillaMindElixir.new(NEW_TOPIC_NAME);
|
const content = VanillaMindElixir.new(NEW_TOPIC_NAME);
|
||||||
const apiRef = useRef<MindElixirInstance>(null);
|
const apiRef = useRef<MindElixirInstance>(null);
|
||||||
const containerRef = useRef<HTMLDivElement>(null);
|
const containerRef = useRef<HTMLDivElement>(null);
|
||||||
const [ isReadOnly ] = useNoteLabelBoolean(note, "readOnly");
|
const [ isReadOnly ] = useNoteLabelBoolean(note, "readOnly");
|
||||||
const spacedUpdate = useEditorSpacedUpdate({
|
const spacedUpdate = useEditorSpacedUpdate({
|
||||||
note,
|
note,
|
||||||
|
noteContext,
|
||||||
getData: async () => {
|
getData: async () => {
|
||||||
if (!apiRef.current) return;
|
if (!apiRef.current) return;
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -70,12 +70,13 @@ function formatViewSource(note: FNote, content: string) {
|
|||||||
return content;
|
return content;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function EditableCode({ note, ntxId, debounceUpdate, parentComponent, updateInterval, onContentChanged, dataSaved, ...editorProps }: EditableCodeProps) {
|
export function EditableCode({ note, ntxId, noteContext, debounceUpdate, parentComponent, updateInterval, onContentChanged, dataSaved, ...editorProps }: EditableCodeProps) {
|
||||||
const editorRef = useRef<VanillaCodeMirror>(null);
|
const editorRef = useRef<VanillaCodeMirror>(null);
|
||||||
const containerRef = useRef<HTMLPreElement>(null);
|
const containerRef = useRef<HTMLPreElement>(null);
|
||||||
const [ vimKeymapEnabled ] = useTriliumOptionBool("vimKeymapEnabled");
|
const [ vimKeymapEnabled ] = useTriliumOptionBool("vimKeymapEnabled");
|
||||||
const spacedUpdate = useEditorSpacedUpdate({
|
const spacedUpdate = useEditorSpacedUpdate({
|
||||||
note,
|
note,
|
||||||
|
noteContext,
|
||||||
getData: () => ({ content: editorRef.current?.getText() }),
|
getData: () => ({ content: editorRef.current?.getText() }),
|
||||||
onContentChange: (content) => {
|
onContentChange: (content) => {
|
||||||
const codeEditor = editorRef.current;
|
const codeEditor = editorRef.current;
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ declare module "jsplumb" {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function RelationMap({ note, ntxId }: TypeWidgetProps) {
|
export default function RelationMap({ note, noteContext, ntxId }: TypeWidgetProps) {
|
||||||
const [ data, setData ] = useState<MapData>();
|
const [ data, setData ] = useState<MapData>();
|
||||||
const containerRef = useRef<HTMLDivElement>(null);
|
const containerRef = useRef<HTMLDivElement>(null);
|
||||||
const mapApiRef = useRef<RelationMapApi>(null);
|
const mapApiRef = useRef<RelationMapApi>(null);
|
||||||
@@ -51,6 +51,7 @@ export default function RelationMap({ note, ntxId }: TypeWidgetProps) {
|
|||||||
|
|
||||||
const spacedUpdate = useEditorSpacedUpdate({
|
const spacedUpdate = useEditorSpacedUpdate({
|
||||||
note,
|
note,
|
||||||
|
noteContext,
|
||||||
getData() {
|
getData() {
|
||||||
return {
|
return {
|
||||||
content: JSON.stringify(data),
|
content: JSON.stringify(data),
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ export default function EditableText({ note, parentComponent, ntxId, noteContext
|
|||||||
const initialized = useRef(deferred<void>());
|
const initialized = useRef(deferred<void>());
|
||||||
const spacedUpdate = useEditorSpacedUpdate({
|
const spacedUpdate = useEditorSpacedUpdate({
|
||||||
note,
|
note,
|
||||||
|
noteContext,
|
||||||
getData() {
|
getData() {
|
||||||
const editor = watchdogRef.current?.editor;
|
const editor = watchdogRef.current?.editor;
|
||||||
if (!editor) {
|
if (!editor) {
|
||||||
|
|||||||
Reference in New Issue
Block a user