2020-07-27 15:29:19 +03:00
|
|
|
import { loadLibraryFromBlob } from "./blob";
|
|
|
|
import { LibraryItems, LibraryItem } from "../types";
|
2020-10-30 21:01:41 +01:00
|
|
|
import { restoreElements } from "./restore";
|
|
|
|
import { STORAGE_KEYS } from "../constants";
|
2020-07-27 15:29:19 +03:00
|
|
|
|
|
|
|
export class Library {
|
2020-10-30 21:01:41 +01:00
|
|
|
private static libraryCache: LibraryItems | null = null;
|
|
|
|
|
|
|
|
static resetLibrary = () => {
|
|
|
|
Library.libraryCache = null;
|
|
|
|
localStorage.removeItem(STORAGE_KEYS.LOCAL_STORAGE_LIBRARY);
|
|
|
|
};
|
|
|
|
|
2020-07-27 15:29:19 +03:00
|
|
|
/** imports library (currently merges, removing duplicates) */
|
2020-10-19 10:53:37 +02:00
|
|
|
static async importLibrary(blob: Blob) {
|
2020-07-27 15:29:19 +03:00
|
|
|
const libraryFile = await loadLibraryFromBlob(blob);
|
|
|
|
if (!libraryFile || !libraryFile.library) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* checks if library item does not exist already in current library
|
|
|
|
*/
|
|
|
|
const isUniqueitem = (
|
|
|
|
existingLibraryItems: LibraryItems,
|
|
|
|
targetLibraryItem: LibraryItem,
|
|
|
|
) => {
|
|
|
|
return !existingLibraryItems.find((libraryItem) => {
|
|
|
|
if (libraryItem.length !== targetLibraryItem.length) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// detect z-index difference by checking the excalidraw elements
|
2020-11-05 19:06:18 +02:00
|
|
|
// are in order
|
2020-07-27 15:29:19 +03:00
|
|
|
return libraryItem.every((libItemExcalidrawItem, idx) => {
|
|
|
|
return (
|
|
|
|
libItemExcalidrawItem.id === targetLibraryItem[idx].id &&
|
|
|
|
libItemExcalidrawItem.versionNonce ===
|
|
|
|
targetLibraryItem[idx].versionNonce
|
|
|
|
);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
2020-10-30 21:01:41 +01:00
|
|
|
const existingLibraryItems = await Library.loadLibrary();
|
2020-07-27 15:29:19 +03:00
|
|
|
const filtered = libraryFile.library!.filter((libraryItem) =>
|
|
|
|
isUniqueitem(existingLibraryItems, libraryItem),
|
|
|
|
);
|
2020-10-30 21:01:41 +01:00
|
|
|
Library.saveLibrary([...existingLibraryItems, ...filtered]);
|
2020-07-27 15:29:19 +03:00
|
|
|
}
|
2020-10-30 21:01:41 +01:00
|
|
|
|
|
|
|
static loadLibrary = (): Promise<LibraryItems> => {
|
|
|
|
return new Promise(async (resolve) => {
|
|
|
|
if (Library.libraryCache) {
|
|
|
|
return resolve(JSON.parse(JSON.stringify(Library.libraryCache)));
|
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
|
|
|
const data = localStorage.getItem(STORAGE_KEYS.LOCAL_STORAGE_LIBRARY);
|
|
|
|
if (!data) {
|
|
|
|
return resolve([]);
|
|
|
|
}
|
|
|
|
|
|
|
|
const items = (JSON.parse(data) as LibraryItems).map((elements) =>
|
|
|
|
restoreElements(elements),
|
|
|
|
) as Mutable<LibraryItems>;
|
|
|
|
|
|
|
|
// clone to ensure we don't mutate the cached library elements in the app
|
|
|
|
Library.libraryCache = JSON.parse(JSON.stringify(items));
|
|
|
|
|
|
|
|
resolve(items);
|
2020-11-05 19:06:18 +02:00
|
|
|
} catch (error) {
|
|
|
|
console.error(error);
|
2020-10-30 21:01:41 +01:00
|
|
|
resolve([]);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
static saveLibrary = (items: LibraryItems) => {
|
|
|
|
const prevLibraryItems = Library.libraryCache;
|
|
|
|
try {
|
|
|
|
const serializedItems = JSON.stringify(items);
|
|
|
|
// cache optimistically so that consumers have access to the latest
|
2020-11-05 19:06:18 +02:00
|
|
|
// immediately
|
2020-10-30 21:01:41 +01:00
|
|
|
Library.libraryCache = JSON.parse(serializedItems);
|
|
|
|
localStorage.setItem(STORAGE_KEYS.LOCAL_STORAGE_LIBRARY, serializedItems);
|
2020-11-05 19:06:18 +02:00
|
|
|
} catch (error) {
|
2020-10-30 21:01:41 +01:00
|
|
|
Library.libraryCache = prevLibraryItems;
|
2020-11-05 19:06:18 +02:00
|
|
|
console.error(error);
|
2020-10-30 21:01:41 +01:00
|
|
|
}
|
|
|
|
};
|
2020-07-27 15:29:19 +03:00
|
|
|
}
|