2021-10-07 13:19:40 +02:00
|
|
|
import { fileOpen, fileSave } from "./filesystem";
|
2021-10-21 22:05:48 +02:00
|
|
|
import { cleanAppStateForExport, clearAppStateForDatabase } from "../appState";
|
2021-04-10 19:17:49 +02:00
|
|
|
import { EXPORT_DATA_TYPES, EXPORT_SOURCE, MIME_TYPES } from "../constants";
|
2021-10-21 22:05:48 +02:00
|
|
|
import { clearElementsForDatabase, clearElementsForExport } from "../element";
|
2020-03-07 10:20:38 -05:00
|
|
|
import { ExcalidrawElement } from "../element/types";
|
2021-11-17 23:53:43 +05:30
|
|
|
import { AppState, BinaryFiles, LibraryItems } from "../types";
|
2021-07-15 09:54:26 -04:00
|
|
|
import { isImageFileHandle, loadFromBlob } from "./blob";
|
2021-04-21 23:38:24 +05:30
|
|
|
|
2021-04-10 19:17:49 +02:00
|
|
|
import {
|
|
|
|
ExportedDataState,
|
|
|
|
ImportedDataState,
|
|
|
|
ExportedLibraryData,
|
|
|
|
} from "./types";
|
2021-04-21 23:38:24 +05:30
|
|
|
import Library from "./library";
|
2020-03-07 10:20:38 -05:00
|
|
|
|
2021-10-21 22:05:48 +02:00
|
|
|
/**
|
|
|
|
* Strips out files which are only referenced by deleted elements
|
|
|
|
*/
|
|
|
|
const filterOutDeletedFiles = (
|
|
|
|
elements: readonly ExcalidrawElement[],
|
|
|
|
files: BinaryFiles,
|
|
|
|
) => {
|
|
|
|
const nextFiles: BinaryFiles = {};
|
|
|
|
for (const element of elements) {
|
|
|
|
if (
|
|
|
|
!element.isDeleted &&
|
|
|
|
"fileId" in element &&
|
|
|
|
element.fileId &&
|
|
|
|
files[element.fileId]
|
|
|
|
) {
|
|
|
|
nextFiles[element.fileId] = files[element.fileId];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nextFiles;
|
|
|
|
};
|
|
|
|
|
2020-05-20 16:21:37 +03:00
|
|
|
export const serializeAsJSON = (
|
2020-03-07 10:20:38 -05:00
|
|
|
elements: readonly ExcalidrawElement[],
|
2021-07-03 02:07:01 +05:30
|
|
|
appState: Partial<AppState>,
|
2021-10-21 22:05:48 +02:00
|
|
|
files: BinaryFiles,
|
|
|
|
type: "local" | "database",
|
2021-04-10 19:17:49 +02:00
|
|
|
): string => {
|
|
|
|
const data: ExportedDataState = {
|
|
|
|
type: EXPORT_DATA_TYPES.excalidraw,
|
|
|
|
version: 2,
|
|
|
|
source: EXPORT_SOURCE,
|
2021-10-21 22:05:48 +02:00
|
|
|
elements:
|
|
|
|
type === "local"
|
|
|
|
? clearElementsForExport(elements)
|
|
|
|
: clearElementsForDatabase(elements),
|
|
|
|
appState:
|
|
|
|
type === "local"
|
|
|
|
? cleanAppStateForExport(appState)
|
|
|
|
: clearAppStateForDatabase(appState),
|
|
|
|
files:
|
|
|
|
type === "local"
|
|
|
|
? filterOutDeletedFiles(elements, files)
|
|
|
|
: // will be stripped from JSON
|
|
|
|
undefined,
|
2021-04-10 19:17:49 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
return JSON.stringify(data, null, 2);
|
|
|
|
};
|
2020-03-07 10:20:38 -05:00
|
|
|
|
2020-05-20 16:21:37 +03:00
|
|
|
export const saveAsJSON = async (
|
2020-03-07 10:20:38 -05:00
|
|
|
elements: readonly ExcalidrawElement[],
|
|
|
|
appState: AppState,
|
2021-10-21 22:05:48 +02:00
|
|
|
files: BinaryFiles,
|
2020-05-20 16:21:37 +03:00
|
|
|
) => {
|
2021-10-21 22:05:48 +02:00
|
|
|
const serialized = serializeAsJSON(elements, appState, files, "local");
|
2020-06-12 18:35:04 +02:00
|
|
|
const blob = new Blob([serialized], {
|
2021-03-14 03:12:54 +05:30
|
|
|
type: MIME_TYPES.excalidraw,
|
2020-06-12 18:35:04 +02:00
|
|
|
});
|
2020-10-19 10:53:37 +02:00
|
|
|
|
2021-10-07 13:19:40 +02:00
|
|
|
const fileHandle = await fileSave(blob, {
|
|
|
|
name: appState.name,
|
|
|
|
extension: "excalidraw",
|
|
|
|
description: "Excalidraw file",
|
|
|
|
fileHandle: isImageFileHandle(appState.fileHandle)
|
|
|
|
? null
|
|
|
|
: appState.fileHandle,
|
|
|
|
});
|
2020-10-19 10:53:37 +02:00
|
|
|
return { fileHandle };
|
2020-05-20 16:21:37 +03:00
|
|
|
};
|
2020-06-12 18:35:04 +02:00
|
|
|
|
2021-07-04 22:23:35 +02:00
|
|
|
export const loadFromJSON = async (
|
|
|
|
localAppState: AppState,
|
|
|
|
localElements: readonly ExcalidrawElement[] | null,
|
|
|
|
) => {
|
2020-03-07 10:20:38 -05:00
|
|
|
const blob = await fileOpen({
|
|
|
|
description: "Excalidraw files",
|
2021-03-14 03:12:54 +05:30
|
|
|
// ToDo: Be over-permissive until https://bugs.webkit.org/show_bug.cgi?id=34442
|
|
|
|
// gets resolved. Else, iOS users cannot open `.excalidraw` files.
|
2021-10-21 22:05:48 +02:00
|
|
|
// extensions: ["json", "excalidraw", "png", "svg"],
|
2020-03-07 10:20:38 -05:00
|
|
|
});
|
2021-07-04 22:23:35 +02:00
|
|
|
return loadFromBlob(blob, localAppState, localElements);
|
2020-05-20 16:21:37 +03:00
|
|
|
};
|
2020-07-27 15:29:19 +03:00
|
|
|
|
2021-03-08 16:37:26 +01:00
|
|
|
export const isValidExcalidrawData = (data?: {
|
|
|
|
type?: any;
|
|
|
|
elements?: any;
|
|
|
|
appState?: any;
|
|
|
|
}): data is ImportedDataState => {
|
|
|
|
return (
|
2021-03-20 20:20:47 +01:00
|
|
|
data?.type === EXPORT_DATA_TYPES.excalidraw &&
|
2021-03-08 16:37:26 +01:00
|
|
|
(!data.elements ||
|
|
|
|
(Array.isArray(data.elements) &&
|
|
|
|
(!data.appState || typeof data.appState === "object")))
|
|
|
|
);
|
|
|
|
};
|
|
|
|
|
2020-10-01 10:12:43 -07:00
|
|
|
export const isValidLibrary = (json: any) => {
|
|
|
|
return (
|
|
|
|
typeof json === "object" &&
|
|
|
|
json &&
|
2021-03-20 20:20:47 +01:00
|
|
|
json.type === EXPORT_DATA_TYPES.excalidrawLibrary &&
|
2021-11-17 23:53:43 +05:30
|
|
|
(json.version === 1 || json.version === 2)
|
2020-10-01 10:12:43 -07:00
|
|
|
);
|
|
|
|
};
|
|
|
|
|
2021-11-17 23:53:43 +05:30
|
|
|
export const saveLibraryAsJSON = async (libraryItems: LibraryItems) => {
|
2021-04-10 19:17:49 +02:00
|
|
|
const data: ExportedLibraryData = {
|
|
|
|
type: EXPORT_DATA_TYPES.excalidrawLibrary,
|
2021-11-17 23:53:43 +05:30
|
|
|
version: 2,
|
2021-04-10 19:17:49 +02:00
|
|
|
source: EXPORT_SOURCE,
|
2021-11-17 23:53:43 +05:30
|
|
|
libraryItems,
|
2021-04-10 19:17:49 +02:00
|
|
|
};
|
|
|
|
const serialized = JSON.stringify(data, null, 2);
|
2021-10-07 13:19:40 +02:00
|
|
|
await fileSave(
|
|
|
|
new Blob([serialized], {
|
|
|
|
type: MIME_TYPES.excalidrawlib,
|
|
|
|
}),
|
|
|
|
{
|
|
|
|
name: "library",
|
|
|
|
extension: "excalidrawlib",
|
|
|
|
description: "Excalidraw library file",
|
|
|
|
},
|
|
|
|
);
|
2020-07-27 15:29:19 +03:00
|
|
|
};
|
|
|
|
|
2021-04-21 23:38:24 +05:30
|
|
|
export const importLibraryFromJSON = async (library: Library) => {
|
2020-07-27 15:29:19 +03:00
|
|
|
const blob = await fileOpen({
|
|
|
|
description: "Excalidraw library files",
|
2021-03-14 03:12:54 +05:30
|
|
|
// ToDo: Be over-permissive until https://bugs.webkit.org/show_bug.cgi?id=34442
|
|
|
|
// gets resolved. Else, iOS users cannot open `.excalidraw` files.
|
|
|
|
/*
|
2020-09-10 12:00:18 +02:00
|
|
|
extensions: [".json", ".excalidrawlib"],
|
2021-03-14 03:12:54 +05:30
|
|
|
*/
|
2020-07-27 15:29:19 +03:00
|
|
|
});
|
2021-04-21 23:38:24 +05:30
|
|
|
await library.importLibrary(blob);
|
2020-07-27 15:29:19 +03:00
|
|
|
};
|