2020-09-22 21:51:49 +02:00
|
|
|
import { cleanAppStateForExport } from "../appState";
|
2020-03-07 10:20:38 -05:00
|
|
|
import { restore } from "./restore";
|
2020-04-03 12:50:51 +01:00
|
|
|
import { t } from "../i18n";
|
2020-07-11 13:09:40 +02:00
|
|
|
import { AppState } from "../types";
|
2020-09-22 21:51:49 +02:00
|
|
|
import { LibraryData, ImportedDataState } from "./types";
|
2020-07-27 17:18:49 +05:30
|
|
|
import { calculateScrollCenter } from "../scene";
|
2020-10-13 14:47:07 +02:00
|
|
|
import { MIME_TYPES } from "../constants";
|
|
|
|
import { base64ToString } from "../base64";
|
|
|
|
export const parseFileContents = async (blob: Blob | File) => {
|
2020-07-27 15:29:19 +03:00
|
|
|
let contents: string;
|
2020-10-13 14:47:07 +02:00
|
|
|
if (blob.type === "image/png") {
|
2020-10-13 16:55:08 +02:00
|
|
|
const metadata = await (await import("./png")).getTEXtChunk(blob);
|
|
|
|
if (metadata?.keyword === MIME_TYPES.excalidraw) {
|
|
|
|
return metadata.text;
|
2020-10-13 14:47:07 +02:00
|
|
|
}
|
2020-10-13 16:55:08 +02:00
|
|
|
throw new Error(t("alerts.imageDoesNotContainScene"));
|
2020-03-07 10:20:38 -05:00
|
|
|
} else {
|
2020-10-13 14:47:07 +02:00
|
|
|
if ("text" in Blob) {
|
|
|
|
contents = await blob.text();
|
|
|
|
} else {
|
|
|
|
contents = await new Promise((resolve) => {
|
|
|
|
const reader = new FileReader();
|
|
|
|
reader.readAsText(blob, "utf8");
|
|
|
|
reader.onloadend = () => {
|
|
|
|
if (reader.readyState === FileReader.DONE) {
|
|
|
|
resolve(reader.result as string);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
});
|
|
|
|
}
|
|
|
|
if (blob.type === "image/svg+xml") {
|
|
|
|
if (contents.includes(`payload-type:${MIME_TYPES.excalidraw}`)) {
|
|
|
|
const match = contents.match(
|
|
|
|
/<!-- payload-start -->(.+?)<!-- payload-end -->/,
|
|
|
|
);
|
|
|
|
if (!match) {
|
|
|
|
throw new Error(t("alerts.imageDoesNotContainScene"));
|
2020-03-07 10:20:38 -05:00
|
|
|
}
|
2020-10-13 14:47:07 +02:00
|
|
|
return base64ToString(match[1]);
|
|
|
|
}
|
|
|
|
throw new Error(t("alerts.imageDoesNotContainScene"));
|
|
|
|
}
|
2020-03-07 10:20:38 -05:00
|
|
|
}
|
2020-07-27 15:29:19 +03:00
|
|
|
return contents;
|
|
|
|
};
|
|
|
|
|
2020-10-13 13:46:52 +02:00
|
|
|
export const loadFromBlob = async (
|
|
|
|
blob: any,
|
|
|
|
/** @see restore.localAppState */
|
|
|
|
localAppState: AppState | null,
|
|
|
|
) => {
|
2020-07-27 15:29:19 +03:00
|
|
|
if (blob.handle) {
|
2020-09-22 15:21:22 +02:00
|
|
|
// TODO: Make this part of `AppState`.
|
2020-07-27 15:29:19 +03:00
|
|
|
(window as any).handle = blob.handle;
|
|
|
|
}
|
2020-04-10 10:58:09 +01:00
|
|
|
|
2020-10-13 14:47:07 +02:00
|
|
|
const contents = await parseFileContents(blob);
|
2020-07-27 17:18:49 +05:30
|
|
|
try {
|
2020-09-22 21:51:49 +02:00
|
|
|
const data: ImportedDataState = JSON.parse(contents);
|
2020-07-27 17:18:49 +05:30
|
|
|
if (data.type !== "excalidraw") {
|
|
|
|
throw new Error(t("alerts.couldNotLoadInvalidFile"));
|
|
|
|
}
|
2020-10-13 13:46:52 +02:00
|
|
|
return restore(
|
|
|
|
{
|
|
|
|
elements: data.elements,
|
|
|
|
appState: {
|
|
|
|
appearance: localAppState?.appearance,
|
|
|
|
...cleanAppStateForExport(data.appState || {}),
|
|
|
|
...(localAppState
|
|
|
|
? calculateScrollCenter(data.elements || [], localAppState, null)
|
|
|
|
: {}),
|
|
|
|
},
|
2020-09-22 21:51:49 +02:00
|
|
|
},
|
2020-10-13 13:46:52 +02:00
|
|
|
localAppState,
|
|
|
|
);
|
2020-07-27 17:18:49 +05:30
|
|
|
} catch {
|
|
|
|
throw new Error(t("alerts.couldNotLoadInvalidFile"));
|
|
|
|
}
|
2020-05-20 16:21:37 +03:00
|
|
|
};
|
2020-07-27 15:29:19 +03:00
|
|
|
|
2020-10-13 14:47:07 +02:00
|
|
|
export const loadLibraryFromBlob = async (blob: Blob) => {
|
|
|
|
const contents = await parseFileContents(blob);
|
2020-07-27 15:29:19 +03:00
|
|
|
const data: LibraryData = JSON.parse(contents);
|
|
|
|
if (data.type !== "excalidrawlib") {
|
|
|
|
throw new Error(t("alerts.couldNotLoadInvalidFile"));
|
|
|
|
}
|
|
|
|
return data;
|
|
|
|
};
|