]> BookStack Code Mirror - bookstack/blob - resources/js/wysiwyg/utils/diagrams.ts
50d7d5b3f36e536dcbb2e28374e31794fe5f8ec8
[bookstack] / resources / js / wysiwyg / utils / diagrams.ts
1 import {LexicalEditor, LexicalNode} from "lexical";
2 import {HttpError} from "../../services/http";
3 import {EditorUiContext} from "../ui/framework/core";
4 import * as DrawIO from "../../services/drawio";
5 import {DiagramNode} from "../nodes/diagram";
6
7 export function $isDiagramNode(node: LexicalNode | null | undefined): node is DiagramNode {
8     return node instanceof DiagramNode;
9 }
10
11 function handleUploadError(error: HttpError, context: EditorUiContext): void {
12     if (error.status === 413) {
13         window.$events.emit('error', context.options.translations.serverUploadLimitText || '');
14     } else {
15         window.$events.emit('error', context.options.translations.imageUploadErrorText || '');
16     }
17     console.error(error);
18 }
19
20 async function loadDiagramIdFromNode(editor: LexicalEditor, node: DiagramNode): Promise<string> {
21     const drawingId = await new Promise<string>((res, rej) => {
22         editor.getEditorState().read(() => {
23             const {id: drawingId} = node.getDrawingIdAndUrl();
24             res(drawingId);
25         });
26     });
27
28     return drawingId || '';
29 }
30
31 async function updateDrawingNodeFromData(context: EditorUiContext, node: DiagramNode, pngData: string, isNew: boolean): Promise<void> {
32     DrawIO.close();
33
34     if (isNew) {
35         const loadingImage: string = window.baseUrl('/loading.gif');
36         context.editor.update(() => {
37             node.setDrawingIdAndUrl('', loadingImage);
38         });
39     }
40
41     try {
42         const img = await DrawIO.upload(pngData, context.options.pageId);
43         context.editor.update(() => {
44             node.setDrawingIdAndUrl(String(img.id), img.url);
45         });
46     } catch (err) {
47         if (err instanceof HttpError) {
48             handleUploadError(err, context);
49         }
50
51         if (isNew) {
52             context.editor.update(() => {
53                 node.remove();
54             });
55         }
56
57         throw new Error(`Failed to save image with error: ${err}`);
58     }
59 }
60
61 export function $openDrawingEditorForNode(context: EditorUiContext, node: DiagramNode): void {
62     let isNew = false;
63     DrawIO.show(context.options.drawioUrl, async () => {
64         const drawingId = await loadDiagramIdFromNode(context.editor, node);
65         isNew = !drawingId;
66         return isNew ? '' : DrawIO.load(drawingId);
67     }, async (pngData: string) => {
68         return updateDrawingNodeFromData(context, node, pngData, isNew);
69     });
70 }