mirror of
https://github.com/TriliumNext/Notes.git
synced 2025-07-28 10:32:27 +08:00
refactor(canvas): don't expose API directly
This commit is contained in:
parent
dab9b02990
commit
0da05a7dbe
@ -1,9 +1,8 @@
|
|||||||
import TypeWidget from "./type_widget.js";
|
import TypeWidget from "./type_widget.js";
|
||||||
import utils from "../../services/utils.js";
|
|
||||||
import server from "../../services/server.js";
|
import server from "../../services/server.js";
|
||||||
import type FNote from "../../entities/fnote.js";
|
import type FNote from "../../entities/fnote.js";
|
||||||
import options from "../../services/options.js";
|
import options from "../../services/options.js";
|
||||||
import type { AppState, BinaryFileData, ExcalidrawImperativeAPI, LibraryItem, SceneData } from "@excalidraw/excalidraw/types";
|
import type { AppState, BinaryFileData, LibraryItem } from "@excalidraw/excalidraw/types";
|
||||||
import type { ExcalidrawElement, Theme } from "@excalidraw/excalidraw/element/types";
|
import type { ExcalidrawElement, Theme } from "@excalidraw/excalidraw/element/types";
|
||||||
import type Canvas from "./canvas_el.js";
|
import type Canvas from "./canvas_el.js";
|
||||||
|
|
||||||
@ -109,8 +108,6 @@ export default class ExcalidrawTypeWidget extends TypeWidget {
|
|||||||
private librarycache: LibraryItem[];
|
private librarycache: LibraryItem[];
|
||||||
private attachmentMetadata: AttachmentMetadata[];
|
private attachmentMetadata: AttachmentMetadata[];
|
||||||
private themeStyle!: Theme;
|
private themeStyle!: Theme;
|
||||||
private excalidrawApi!: ExcalidrawImperativeAPI;
|
|
||||||
private excalidrawWrapperRef!: React.RefObject<HTMLElement | null>;
|
|
||||||
|
|
||||||
private $render!: JQuery<HTMLElement>;
|
private $render!: JQuery<HTMLElement>;
|
||||||
private reactHandlers!: JQuery<HTMLElement>;
|
private reactHandlers!: JQuery<HTMLElement>;
|
||||||
@ -209,11 +206,15 @@ export default class ExcalidrawTypeWidget extends TypeWidget {
|
|||||||
* called to populate the widget container with the note content
|
* called to populate the widget container with the note content
|
||||||
*/
|
*/
|
||||||
async doRefresh(note: FNote) {
|
async doRefresh(note: FNote) {
|
||||||
|
if (!this.canvasInstance) {
|
||||||
|
await this.#init();
|
||||||
|
}
|
||||||
|
|
||||||
// see if the note changed, since we do not get a new class for a new note
|
// see if the note changed, since we do not get a new class for a new note
|
||||||
const noteChanged = this.currentNoteId !== note.noteId;
|
const noteChanged = this.currentNoteId !== note.noteId;
|
||||||
if (noteChanged) {
|
if (noteChanged) {
|
||||||
// reset the scene to omit unnecessary onchange handler
|
// reset the scene to omit unnecessary onchange handler
|
||||||
this.canvasInstance?.resetSceneVersion();
|
this.canvasInstance.resetSceneVersion();
|
||||||
}
|
}
|
||||||
this.currentNoteId = note.noteId;
|
this.currentNoteId = note.noteId;
|
||||||
|
|
||||||
@ -221,10 +222,7 @@ export default class ExcalidrawTypeWidget extends TypeWidget {
|
|||||||
const blob = await note.getBlob();
|
const blob = await note.getBlob();
|
||||||
|
|
||||||
// before we load content into excalidraw, make sure excalidraw has loaded
|
// before we load content into excalidraw, make sure excalidraw has loaded
|
||||||
while (!this.canvasInstance?.excalidrawApi) {
|
await this.canvasInstance.waitForApiToBecomeAvailable();
|
||||||
console.log("excalidrawApi not yet loaded, sleep 200ms...");
|
|
||||||
await utils.sleep(200);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* new and empty note - make sure that canvas is empty.
|
* new and empty note - make sure that canvas is empty.
|
||||||
@ -233,15 +231,7 @@ export default class ExcalidrawTypeWidget extends TypeWidget {
|
|||||||
* newly instantiated?
|
* newly instantiated?
|
||||||
*/
|
*/
|
||||||
if (!blob?.content?.trim()) {
|
if (!blob?.content?.trim()) {
|
||||||
const sceneData: SceneData = {
|
this.canvasInstance.resetScene(this.themeStyle);
|
||||||
elements: [],
|
|
||||||
appState: {
|
|
||||||
theme: this.themeStyle
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// TODO: Props mismatch.
|
|
||||||
this.canvasInstance.excalidrawApi.updateScene(sceneData as any);
|
|
||||||
} else if (blob.content) {
|
} else if (blob.content) {
|
||||||
let content: CanvasContent;
|
let content: CanvasContent;
|
||||||
|
|
||||||
@ -285,7 +275,7 @@ export default class ExcalidrawTypeWidget extends TypeWidget {
|
|||||||
const metadata = results.map((result) => result.metadata);
|
const metadata = results.map((result) => result.metadata);
|
||||||
|
|
||||||
// Update the library and save to independent variables
|
// Update the library and save to independent variables
|
||||||
this.canvasInstance.excalidrawApi.updateLibrary({ libraryItems, merge: false });
|
this.canvasInstance.updateLibrary(libraryItems);
|
||||||
|
|
||||||
// save state of library to compare it to the new state later.
|
// save state of library to compare it to the new state later.
|
||||||
this.librarycache = libraryItems;
|
this.librarycache = libraryItems;
|
||||||
@ -313,12 +303,7 @@ export default class ExcalidrawTypeWidget extends TypeWidget {
|
|||||||
// this.libraryChanged is unset in dataSaved()
|
// this.libraryChanged is unset in dataSaved()
|
||||||
|
|
||||||
// there's no separate method to get library items, so have to abuse this one
|
// there's no separate method to get library items, so have to abuse this one
|
||||||
const libraryItems = await this.canvasInstance.excalidrawApi.updateLibrary({
|
const libraryItems = await this.canvasInstance.getLibraryItems();
|
||||||
libraryItems() {
|
|
||||||
return [];
|
|
||||||
},
|
|
||||||
merge: true
|
|
||||||
});
|
|
||||||
|
|
||||||
// excalidraw saves the library as a own state. the items are saved to libraryItems. then we compare the library right now with a libraryitemcache. The cache is filled when we first load the Library into the note.
|
// excalidraw saves the library as a own state. the items are saved to libraryItems. then we compare the library right now with a libraryitemcache. The cache is filled when we first load the Library into the note.
|
||||||
//We need the cache to delete old attachments later in the server.
|
//We need the cache to delete old attachments later in the server.
|
||||||
|
@ -1,19 +1,19 @@
|
|||||||
import "@excalidraw/excalidraw/index.css";
|
import "@excalidraw/excalidraw/index.css";
|
||||||
import { Excalidraw, getSceneVersion, exportToSvg } from "@excalidraw/excalidraw";
|
import { Excalidraw, getSceneVersion, exportToSvg } from "@excalidraw/excalidraw";
|
||||||
import { createElement, createRef, Fragment, RefObject, render, useEffect, useState } from "preact/compat";
|
import { createElement, render } from "preact/compat";
|
||||||
import { AppState, BinaryFileData, ExcalidrawImperativeAPI, ExcalidrawProps, SceneData } from "@excalidraw/excalidraw/types";
|
import { AppState, BinaryFileData, ExcalidrawImperativeAPI, ExcalidrawProps, LibraryItem, SceneData } from "@excalidraw/excalidraw/types";
|
||||||
import type { ComponentType, VNode } from "preact";
|
import type { ComponentType } from "preact";
|
||||||
|
import utils from "../../services/utils";
|
||||||
|
import { Theme } from "@excalidraw/excalidraw/element/types";
|
||||||
|
|
||||||
/** -1 indicates that it is fresh. excalidraw scene version is always >0 */
|
/** Indicates that it is fresh. excalidraw scene version is always >0 */
|
||||||
const SCENE_VERSION_INITIAL = -1;
|
const SCENE_VERSION_INITIAL = -1;
|
||||||
/** -2 indicates error */
|
|
||||||
const SCENE_VERSION_ERROR = -2;
|
|
||||||
|
|
||||||
export default class Canvas {
|
export default class Canvas {
|
||||||
|
|
||||||
private currentSceneVersion: number;
|
private currentSceneVersion: number;
|
||||||
private opts: ExcalidrawProps;
|
private opts: ExcalidrawProps;
|
||||||
excalidrawApi!: ExcalidrawImperativeAPI;
|
private excalidrawApi!: ExcalidrawImperativeAPI;
|
||||||
|
|
||||||
constructor(opts: ExcalidrawProps) {
|
constructor(opts: ExcalidrawProps) {
|
||||||
this.opts = opts;
|
this.opts = opts;
|
||||||
@ -29,6 +29,13 @@ export default class Canvas {
|
|||||||
}), targetEl);
|
}), targetEl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async waitForApiToBecomeAvailable() {
|
||||||
|
while (!this.excalidrawApi) {
|
||||||
|
console.log("excalidrawApi not yet loaded, sleep 200ms...");
|
||||||
|
await utils.sleep(200);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private createCanvasElement(opts: ExcalidrawProps) {
|
private createCanvasElement(opts: ExcalidrawProps) {
|
||||||
return createElement("div", { className: "excalidraw-wrapper", },
|
return createElement("div", { className: "excalidraw-wrapper", },
|
||||||
createElement(Excalidraw as ComponentType<ExcalidrawProps>, opts)
|
createElement(Excalidraw as ComponentType<ExcalidrawProps>, opts)
|
||||||
@ -68,6 +75,15 @@ export default class Canvas {
|
|||||||
return this.currentSceneVersion === SCENE_VERSION_INITIAL;
|
return this.currentSceneVersion === SCENE_VERSION_INITIAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
resetScene(theme: Theme) {
|
||||||
|
this.excalidrawApi.updateScene({
|
||||||
|
elements: [],
|
||||||
|
appState: {
|
||||||
|
theme
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
loadData(content: any, theme: any) {
|
loadData(content: any, theme: any) {
|
||||||
const { elements, files } = content;
|
const { elements, files } = content;
|
||||||
const appState: Partial<AppState> = content.appState ?? {};
|
const appState: Partial<AppState> = content.appState ?? {};
|
||||||
@ -143,4 +159,17 @@ export default class Canvas {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async getLibraryItems() {
|
||||||
|
return this.excalidrawApi.updateLibrary({
|
||||||
|
libraryItems() {
|
||||||
|
return [];
|
||||||
|
},
|
||||||
|
merge: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async updateLibrary(libraryItems: LibraryItem[]) {
|
||||||
|
this.excalidrawApi.updateLibrary({ libraryItems, merge: false });
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user