2021-04-30 22:54:00 -04:00
|
|
|
// eslint-disable-next-line no-unused-vars
|
|
|
|
import Dexie, { Version } from "dexie";
|
|
|
|
import shortid from "shortid";
|
|
|
|
import { v4 as uuid } from "uuid";
|
|
|
|
import Case from "case";
|
2021-06-25 03:45:49 -04:00
|
|
|
import chunk from "lodash.chunk";
|
2021-04-30 22:54:00 -04:00
|
|
|
|
|
|
|
import blobToBuffer from "./helpers/blobToBuffer";
|
|
|
|
import { getGridDefaultInset } from "./helpers/grid";
|
2021-06-10 01:06:11 -04:00
|
|
|
import { createThumbnail, getImageOutline } from "./helpers/image";
|
2021-04-30 22:54:00 -04:00
|
|
|
import {
|
2021-07-16 00:55:33 -04:00
|
|
|
AddStatesAction,
|
|
|
|
EditStatesAction,
|
|
|
|
RemoveStatesAction,
|
|
|
|
SubtractFogAction,
|
|
|
|
CutFogAction,
|
2021-04-30 22:54:00 -04:00
|
|
|
} from "./actions";
|
|
|
|
import { getDefaultMaps } from "./maps";
|
|
|
|
import { getDefaultTokens } from "./tokens";
|
2021-07-16 00:55:33 -04:00
|
|
|
import { Outline } from "./types/Outline";
|
|
|
|
import { Group, GroupContainer } from "./types/Group";
|
2021-04-30 22:54:00 -04:00
|
|
|
|
2021-07-16 00:55:33 -04:00
|
|
|
export type UpgradeEventHandler = (versionNumber: number) => void;
|
2021-06-24 02:14:20 -04:00
|
|
|
|
2021-07-17 04:18:57 -04:00
|
|
|
type VersionCallback = (
|
|
|
|
version: Version,
|
|
|
|
onUpgrade?: UpgradeEventHandler
|
|
|
|
) => void;
|
2021-04-30 22:54:00 -04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Mapping of version number to their upgrade function
|
|
|
|
*/
|
2021-07-16 00:55:33 -04:00
|
|
|
export const versions: Record<number, VersionCallback> = {
|
2021-04-30 22:54:00 -04:00
|
|
|
// v1.2.0
|
|
|
|
1(v) {
|
|
|
|
v.stores({
|
|
|
|
maps: "id, owner",
|
|
|
|
states: "mapId",
|
|
|
|
tokens: "id, owner",
|
|
|
|
user: "key",
|
|
|
|
});
|
|
|
|
},
|
|
|
|
// v1.2.1 - Move from blob files to array buffers
|
2021-06-24 02:14:20 -04:00
|
|
|
2(v, onUpgrade) {
|
2021-04-30 22:54:00 -04:00
|
|
|
v.stores({}).upgrade(async (tx) => {
|
2021-06-24 02:14:20 -04:00
|
|
|
onUpgrade?.(2);
|
2021-04-30 22:54:00 -04:00
|
|
|
const maps = await Dexie.waitFor(tx.table("maps").toArray());
|
2021-07-16 00:55:33 -04:00
|
|
|
let mapBuffers: Record<string, ArrayBuffer> = {};
|
2021-04-30 22:54:00 -04:00
|
|
|
for (let map of maps) {
|
|
|
|
mapBuffers[map.id] = await Dexie.waitFor(blobToBuffer(map.file));
|
|
|
|
}
|
|
|
|
return tx
|
|
|
|
.table("maps")
|
|
|
|
.toCollection()
|
|
|
|
.modify((map) => {
|
|
|
|
map.file = mapBuffers[map.id];
|
|
|
|
});
|
|
|
|
});
|
|
|
|
},
|
|
|
|
// v1.3.0 - Added new default tokens
|
2021-06-24 02:14:20 -04:00
|
|
|
3(v, onUpgrade) {
|
2021-04-30 22:54:00 -04:00
|
|
|
v.stores({}).upgrade((tx) => {
|
2021-06-24 02:14:20 -04:00
|
|
|
onUpgrade?.(3);
|
2021-04-30 22:54:00 -04:00
|
|
|
return tx
|
|
|
|
.table("states")
|
|
|
|
.toCollection()
|
|
|
|
.modify((state) => {
|
2021-07-16 00:55:33 -04:00
|
|
|
function mapTokenId(id: string) {
|
2021-04-30 22:54:00 -04:00
|
|
|
switch (id) {
|
|
|
|
case "__default-Axes":
|
|
|
|
return "__default-Barbarian";
|
|
|
|
case "__default-Bird":
|
|
|
|
return "__default-Druid";
|
|
|
|
case "__default-Book":
|
|
|
|
return "__default-Wizard";
|
|
|
|
case "__default-Crown":
|
|
|
|
return "__default-Humanoid";
|
|
|
|
case "__default-Dragon":
|
|
|
|
return "__default-Dragon";
|
|
|
|
case "__default-Eye":
|
|
|
|
return "__default-Warlock";
|
|
|
|
case "__default-Fist":
|
|
|
|
return "__default-Monk";
|
|
|
|
case "__default-Horse":
|
|
|
|
return "__default-Fey";
|
|
|
|
case "__default-Leaf":
|
|
|
|
return "__default-Druid";
|
|
|
|
case "__default-Lion":
|
|
|
|
return "__default-Monstrosity";
|
|
|
|
case "__default-Money":
|
|
|
|
return "__default-Humanoid";
|
|
|
|
case "__default-Moon":
|
|
|
|
return "__default-Cleric";
|
|
|
|
case "__default-Potion":
|
|
|
|
return "__default-Sorcerer";
|
|
|
|
case "__default-Shield":
|
|
|
|
return "__default-Paladin";
|
|
|
|
case "__default-Skull":
|
|
|
|
return "__default-Undead";
|
|
|
|
case "__default-Snake":
|
|
|
|
return "__default-Beast";
|
|
|
|
case "__default-Sun":
|
|
|
|
return "__default-Cleric";
|
|
|
|
case "__default-Swords":
|
|
|
|
return "__default-Fighter";
|
|
|
|
case "__default-Tree":
|
|
|
|
return "__default-Plant";
|
|
|
|
case "__default-Triangle":
|
|
|
|
return "__default-Sorcerer";
|
|
|
|
default:
|
|
|
|
return "__default-Fighter";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for (let stateId in state.tokens) {
|
|
|
|
state.tokens[stateId].tokenId = mapTokenId(
|
|
|
|
state.tokens[stateId].tokenId
|
|
|
|
);
|
|
|
|
state.tokens[stateId].lastEditedBy = "";
|
|
|
|
state.tokens[stateId].rotation = 0;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
},
|
|
|
|
// v1.3.1 - Added show grid option
|
2021-06-24 02:14:20 -04:00
|
|
|
4(v, onUpgrade) {
|
2021-04-30 22:54:00 -04:00
|
|
|
v.stores({}).upgrade((tx) => {
|
2021-06-24 02:14:20 -04:00
|
|
|
onUpgrade?.(4);
|
2021-04-30 22:54:00 -04:00
|
|
|
return tx
|
|
|
|
.table("maps")
|
|
|
|
.toCollection()
|
|
|
|
.modify((map) => {
|
|
|
|
map.showGrid = false;
|
|
|
|
});
|
|
|
|
});
|
|
|
|
},
|
|
|
|
// v1.4.0 - Added fog subtraction
|
2021-06-24 02:14:20 -04:00
|
|
|
5(v, onUpgrade) {
|
2021-04-30 22:54:00 -04:00
|
|
|
v.stores({}).upgrade((tx) => {
|
2021-06-24 02:14:20 -04:00
|
|
|
onUpgrade?.(5);
|
2021-04-30 22:54:00 -04:00
|
|
|
return tx
|
|
|
|
.table("states")
|
|
|
|
.toCollection()
|
|
|
|
.modify((state) => {
|
|
|
|
for (let fogAction of state.fogDrawActions) {
|
|
|
|
if (fogAction.type === "add" || fogAction.type === "edit") {
|
|
|
|
for (let shape of fogAction.shapes) {
|
|
|
|
shape.data.holes = [];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
},
|
|
|
|
// v1.4.2 - Added map resolutions
|
2021-06-24 02:14:20 -04:00
|
|
|
6(v, onUpgrade) {
|
2021-04-30 22:54:00 -04:00
|
|
|
v.stores({}).upgrade((tx) => {
|
2021-06-24 02:14:20 -04:00
|
|
|
onUpgrade?.(6);
|
2021-04-30 22:54:00 -04:00
|
|
|
return tx
|
|
|
|
.table("maps")
|
|
|
|
.toCollection()
|
|
|
|
.modify((map) => {
|
|
|
|
map.resolutions = {};
|
|
|
|
map.quality = "original";
|
|
|
|
});
|
|
|
|
});
|
|
|
|
},
|
|
|
|
// v1.5.0 - Fixed default token rogue spelling
|
2021-06-24 02:14:20 -04:00
|
|
|
7(v, onUpgrade) {
|
2021-04-30 22:54:00 -04:00
|
|
|
v.stores({}).upgrade((tx) => {
|
2021-06-24 02:14:20 -04:00
|
|
|
onUpgrade?.(7);
|
2021-04-30 22:54:00 -04:00
|
|
|
return tx
|
|
|
|
.table("states")
|
|
|
|
.toCollection()
|
|
|
|
.modify((state) => {
|
|
|
|
for (let id in state.tokens) {
|
|
|
|
if (state.tokens[id].tokenId === "__default-Rouge") {
|
|
|
|
state.tokens[id].tokenId = "__default-Rogue";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
},
|
|
|
|
// v1.5.0 - Added map snap to grid option
|
2021-06-24 02:14:20 -04:00
|
|
|
8(v, onUpgrade) {
|
2021-04-30 22:54:00 -04:00
|
|
|
v.stores({}).upgrade((tx) => {
|
2021-06-24 02:14:20 -04:00
|
|
|
onUpgrade?.(8);
|
2021-04-30 22:54:00 -04:00
|
|
|
return tx
|
|
|
|
.table("maps")
|
|
|
|
.toCollection()
|
|
|
|
.modify((map) => {
|
|
|
|
map.snapToGrid = true;
|
|
|
|
});
|
|
|
|
});
|
|
|
|
},
|
|
|
|
// v1.5.1 - Added lock, visibility and modified to tokens
|
2021-06-24 02:14:20 -04:00
|
|
|
9(v, onUpgrade) {
|
2021-04-30 22:54:00 -04:00
|
|
|
v.stores({}).upgrade((tx) => {
|
2021-06-24 02:14:20 -04:00
|
|
|
onUpgrade?.(9);
|
2021-04-30 22:54:00 -04:00
|
|
|
return tx
|
|
|
|
.table("states")
|
|
|
|
.toCollection()
|
|
|
|
.modify((state) => {
|
|
|
|
for (let id in state.tokens) {
|
|
|
|
state.tokens[id].lastModifiedBy = state.tokens[id].lastEditedBy;
|
|
|
|
delete state.tokens[id].lastEditedBy;
|
|
|
|
state.tokens[id].lastModified = Date.now();
|
|
|
|
state.tokens[id].locked = false;
|
|
|
|
state.tokens[id].visible = true;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
},
|
|
|
|
// v1.5.1 - Added token prop category and remove isVehicle bool
|
2021-06-24 02:14:20 -04:00
|
|
|
10(v, onUpgrade) {
|
2021-04-30 22:54:00 -04:00
|
|
|
v.stores({}).upgrade((tx) => {
|
2021-06-24 02:14:20 -04:00
|
|
|
onUpgrade?.(10);
|
2021-04-30 22:54:00 -04:00
|
|
|
return tx
|
|
|
|
.table("tokens")
|
|
|
|
.toCollection()
|
|
|
|
.modify((token) => {
|
|
|
|
token.category = token.isVehicle ? "vehicle" : "character";
|
|
|
|
delete token.isVehicle;
|
|
|
|
});
|
|
|
|
});
|
|
|
|
},
|
|
|
|
// v1.5.2 - Added automatic cache invalidation to maps
|
2021-06-24 02:14:20 -04:00
|
|
|
11(v, onUpgrade) {
|
2021-04-30 22:54:00 -04:00
|
|
|
v.stores({}).upgrade((tx) => {
|
2021-06-24 02:14:20 -04:00
|
|
|
onUpgrade?.(11);
|
2021-04-30 22:54:00 -04:00
|
|
|
return tx
|
|
|
|
.table("maps")
|
|
|
|
.toCollection()
|
|
|
|
.modify((map) => {
|
|
|
|
map.lastUsed = map.lastModified;
|
|
|
|
});
|
|
|
|
});
|
|
|
|
},
|
|
|
|
// v1.5.2 - Added automatic cache invalidation to tokens
|
2021-06-24 02:14:20 -04:00
|
|
|
12(v, onUpgrade) {
|
2021-04-30 22:54:00 -04:00
|
|
|
v.stores({}).upgrade((tx) => {
|
2021-06-24 02:14:20 -04:00
|
|
|
onUpgrade?.(12);
|
2021-04-30 22:54:00 -04:00
|
|
|
return tx
|
|
|
|
.table("tokens")
|
|
|
|
.toCollection()
|
|
|
|
.modify((token) => {
|
|
|
|
token.lastUsed = token.lastModified;
|
|
|
|
});
|
|
|
|
});
|
|
|
|
},
|
|
|
|
// v1.6.0 - Added map grouping and grid scale and offset
|
2021-06-24 02:14:20 -04:00
|
|
|
13(v, onUpgrade) {
|
2021-04-30 22:54:00 -04:00
|
|
|
v.stores({}).upgrade((tx) => {
|
2021-06-24 02:14:20 -04:00
|
|
|
onUpgrade?.(13);
|
2021-04-30 22:54:00 -04:00
|
|
|
return tx
|
|
|
|
.table("maps")
|
|
|
|
.toCollection()
|
|
|
|
.modify((map) => {
|
|
|
|
map.group = "";
|
|
|
|
map.grid = {
|
|
|
|
size: { x: map.gridX, y: map.gridY },
|
|
|
|
inset: getGridDefaultInset(
|
|
|
|
{ size: { x: map.gridX, y: map.gridY }, type: "square" },
|
|
|
|
map.width,
|
|
|
|
map.height
|
|
|
|
),
|
|
|
|
type: "square",
|
|
|
|
};
|
|
|
|
delete map.gridX;
|
|
|
|
delete map.gridY;
|
|
|
|
delete map.gridType;
|
|
|
|
});
|
|
|
|
});
|
|
|
|
},
|
|
|
|
// v1.6.0 - Added token grouping
|
2021-06-24 02:14:20 -04:00
|
|
|
14(v, onUpgrade) {
|
2021-04-30 22:54:00 -04:00
|
|
|
v.stores({}).upgrade((tx) => {
|
2021-06-24 02:14:20 -04:00
|
|
|
onUpgrade?.(14);
|
2021-04-30 22:54:00 -04:00
|
|
|
return tx
|
|
|
|
.table("tokens")
|
|
|
|
.toCollection()
|
|
|
|
.modify((token) => {
|
|
|
|
token.group = "";
|
|
|
|
});
|
|
|
|
});
|
|
|
|
},
|
|
|
|
// v1.6.1 - Added width and height to tokens
|
2021-06-24 02:14:20 -04:00
|
|
|
15(v, onUpgrade) {
|
2021-04-30 22:54:00 -04:00
|
|
|
v.stores({}).upgrade(async (tx) => {
|
2021-06-24 02:14:20 -04:00
|
|
|
onUpgrade?.(15);
|
2021-04-30 22:54:00 -04:00
|
|
|
const tokens = await Dexie.waitFor(tx.table("tokens").toArray());
|
2021-07-17 04:18:57 -04:00
|
|
|
let tokenSizes: Record<string, { width: number; height: number }> = {};
|
2021-04-30 22:54:00 -04:00
|
|
|
for (let token of tokens) {
|
|
|
|
const url = URL.createObjectURL(new Blob([token.file]));
|
|
|
|
let image = new Image();
|
|
|
|
tokenSizes[token.id] = await Dexie.waitFor(
|
|
|
|
new Promise((resolve) => {
|
|
|
|
image.onload = () => {
|
|
|
|
resolve({ width: image.width, height: image.height });
|
|
|
|
};
|
|
|
|
image.src = url;
|
|
|
|
})
|
|
|
|
);
|
|
|
|
}
|
|
|
|
return tx
|
|
|
|
.table("tokens")
|
|
|
|
.toCollection()
|
|
|
|
.modify((token) => {
|
|
|
|
token.width = tokenSizes[token.id].width;
|
|
|
|
token.height = tokenSizes[token.id].height;
|
|
|
|
});
|
|
|
|
});
|
|
|
|
},
|
|
|
|
// v1.7.0 - Added note tool
|
2021-06-24 02:14:20 -04:00
|
|
|
16(v, onUpgrade) {
|
2021-04-30 22:54:00 -04:00
|
|
|
v.stores({}).upgrade((tx) => {
|
2021-06-24 02:14:20 -04:00
|
|
|
onUpgrade?.(16);
|
2021-04-30 22:54:00 -04:00
|
|
|
return tx
|
|
|
|
.table("states")
|
|
|
|
.toCollection()
|
|
|
|
.modify((state) => {
|
|
|
|
state.notes = {};
|
|
|
|
state.editFlags = [...state.editFlags, "notes"];
|
|
|
|
});
|
|
|
|
});
|
|
|
|
},
|
|
|
|
// 1.7.0 (hotfix) - Optimized fog shape edits to only include needed data
|
2021-06-24 02:14:20 -04:00
|
|
|
17(v, onUpgrade) {
|
2021-04-30 22:54:00 -04:00
|
|
|
v.stores({}).upgrade((tx) => {
|
2021-06-24 02:14:20 -04:00
|
|
|
onUpgrade?.(17);
|
2021-04-30 22:54:00 -04:00
|
|
|
return tx
|
|
|
|
.table("states")
|
|
|
|
.toCollection()
|
|
|
|
.modify((state) => {
|
|
|
|
for (let i = 0; i < state.fogDrawActions.length; i++) {
|
|
|
|
const action = state.fogDrawActions[i];
|
|
|
|
if (action && action.type === "edit") {
|
|
|
|
for (let j = 0; j < action.shapes.length; j++) {
|
|
|
|
const shape = action.shapes[j];
|
|
|
|
const temp = { ...shape };
|
|
|
|
state.fogDrawActions[i].shapes[j] = {
|
|
|
|
id: temp.id,
|
|
|
|
visible: temp.visible,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
},
|
|
|
|
// 1.8.0 - Added note text only mode, converted draw and fog representations
|
2021-06-24 02:14:20 -04:00
|
|
|
18(v, onUpgrade) {
|
2021-04-30 22:54:00 -04:00
|
|
|
v.stores({}).upgrade((tx) => {
|
2021-06-24 02:14:20 -04:00
|
|
|
onUpgrade?.(18);
|
2021-04-30 22:54:00 -04:00
|
|
|
return tx
|
|
|
|
.table("states")
|
|
|
|
.toCollection()
|
|
|
|
.modify((state) => {
|
|
|
|
for (let id in state.notes) {
|
|
|
|
state.notes[id].textOnly = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
state.drawShapes = convertOldActionsToShapes(
|
|
|
|
state.mapDrawActions,
|
|
|
|
state.mapDrawActionIndex
|
|
|
|
);
|
|
|
|
state.fogShapes = convertOldActionsToShapes(
|
|
|
|
state.fogDrawActions,
|
|
|
|
state.fogDrawActionIndex
|
|
|
|
);
|
|
|
|
|
|
|
|
delete state.mapDrawActions;
|
|
|
|
delete state.mapDrawActionIndex;
|
|
|
|
delete state.fogDrawActions;
|
|
|
|
delete state.fogDrawActionIndex;
|
|
|
|
});
|
|
|
|
});
|
|
|
|
},
|
|
|
|
// 1.8.0 - Add thumbnail to maps and add measurement to grid
|
2021-06-24 02:14:20 -04:00
|
|
|
19(v, onUpgrade) {
|
2021-04-30 22:54:00 -04:00
|
|
|
v.stores({}).upgrade(async (tx) => {
|
2021-06-24 02:14:20 -04:00
|
|
|
onUpgrade?.(19);
|
2021-04-30 22:54:00 -04:00
|
|
|
const userId = (await Dexie.waitFor(tx.table("user").get("userId")))
|
|
|
|
.value;
|
|
|
|
const maps = await Dexie.waitFor(tx.table("maps").toArray());
|
2021-07-16 00:55:33 -04:00
|
|
|
const thumbnails: Record<string, any> = {};
|
2021-04-30 22:54:00 -04:00
|
|
|
for (let map of maps) {
|
|
|
|
try {
|
|
|
|
if (map.owner === userId) {
|
|
|
|
thumbnails[map.id] = await createDataThumbnail(map);
|
|
|
|
}
|
|
|
|
} catch {}
|
|
|
|
}
|
|
|
|
return tx
|
|
|
|
.table("maps")
|
|
|
|
.toCollection()
|
|
|
|
.modify((map) => {
|
|
|
|
map.thumbnail = thumbnails[map.id];
|
|
|
|
map.grid.measurement = { type: "chebyshev", scale: "5ft" };
|
|
|
|
});
|
|
|
|
});
|
|
|
|
},
|
|
|
|
// 1.8.0 - Add thumbnail to tokens
|
2021-06-24 02:14:20 -04:00
|
|
|
20(v, onUpgrade) {
|
2021-04-30 22:54:00 -04:00
|
|
|
v.stores({}).upgrade(async (tx) => {
|
2021-06-24 02:14:20 -04:00
|
|
|
onUpgrade?.(20);
|
2021-04-30 22:54:00 -04:00
|
|
|
const userId = (await Dexie.waitFor(tx.table("user").get("userId")))
|
|
|
|
.value;
|
|
|
|
const tokens = await Dexie.waitFor(tx.table("tokens").toArray());
|
2021-07-16 00:55:33 -04:00
|
|
|
const thumbnails: Record<string, any> = {};
|
2021-04-30 22:54:00 -04:00
|
|
|
for (let token of tokens) {
|
|
|
|
try {
|
|
|
|
if (token.owner === userId) {
|
|
|
|
thumbnails[token.id] = await createDataThumbnail(token);
|
|
|
|
}
|
|
|
|
} catch {}
|
|
|
|
}
|
|
|
|
return tx
|
|
|
|
.table("tokens")
|
|
|
|
.toCollection()
|
|
|
|
.modify((token) => {
|
|
|
|
token.thumbnail = thumbnails[token.id];
|
|
|
|
});
|
|
|
|
});
|
|
|
|
},
|
|
|
|
// 1.8.0 - Upgrade for Dexie.Observable
|
|
|
|
21(v) {
|
|
|
|
v.stores({});
|
|
|
|
},
|
|
|
|
// v1.8.1 - Shorten fog shape ids
|
2021-06-24 02:14:20 -04:00
|
|
|
22(v, onUpgrade) {
|
2021-04-30 22:54:00 -04:00
|
|
|
v.stores({}).upgrade((tx) => {
|
2021-06-24 02:14:20 -04:00
|
|
|
onUpgrade?.(22);
|
2021-04-30 22:54:00 -04:00
|
|
|
return tx
|
|
|
|
.table("states")
|
|
|
|
.toCollection()
|
|
|
|
.modify((state) => {
|
|
|
|
for (let id of Object.keys(state.fogShapes)) {
|
|
|
|
const newId = shortid.generate();
|
|
|
|
state.fogShapes[newId] = state.fogShapes[id];
|
|
|
|
state.fogShapes[newId].id = newId;
|
|
|
|
delete state.fogShapes[id];
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
},
|
2021-06-10 01:06:11 -04:00
|
|
|
// v1.9.0 - Add outlines to tokens
|
2021-06-24 02:14:20 -04:00
|
|
|
23(v, onUpgrade) {
|
2021-06-10 01:06:11 -04:00
|
|
|
v.stores({}).upgrade(async (tx) => {
|
2021-06-24 02:14:20 -04:00
|
|
|
onUpgrade?.(23);
|
2021-06-10 01:06:11 -04:00
|
|
|
const tokens = await Dexie.waitFor(tx.table("tokens").toArray());
|
|
|
|
const tokenOutlines = await Dexie.waitFor(
|
|
|
|
Promise.all(tokens.map(createDataOutline))
|
|
|
|
);
|
|
|
|
|
|
|
|
return tx
|
|
|
|
.table("tokens")
|
|
|
|
.toCollection()
|
|
|
|
.modify((token) => {
|
|
|
|
const tokenOutline = tokenOutlines.find((el) => el.id === token.id);
|
|
|
|
if (tokenOutline) {
|
|
|
|
token.outline = tokenOutline.outline;
|
|
|
|
} else {
|
|
|
|
token.outline = {
|
|
|
|
type: "rect",
|
|
|
|
width: token.width,
|
|
|
|
height: token.height,
|
|
|
|
x: 0,
|
|
|
|
y: 0,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
},
|
|
|
|
// v1.9.0 - Move map assets into new table
|
2021-06-24 02:14:20 -04:00
|
|
|
24(v, onUpgrade) {
|
2021-06-25 03:45:49 -04:00
|
|
|
v.stores({ assets: "id, owner" }).upgrade(async (tx) => {
|
2021-06-24 02:14:20 -04:00
|
|
|
onUpgrade?.(24);
|
2021-04-30 22:54:00 -04:00
|
|
|
|
2021-06-25 03:45:49 -04:00
|
|
|
const primaryKeys = await Dexie.waitFor(
|
|
|
|
tx.table("maps").toCollection().primaryKeys()
|
|
|
|
);
|
|
|
|
const keyChunks = chunk(primaryKeys, 4);
|
|
|
|
|
|
|
|
for (let keys of keyChunks) {
|
|
|
|
let assets = [];
|
|
|
|
let maps = await Dexie.waitFor(tx.table("maps").bulkGet(keys));
|
|
|
|
while (maps.length > 0) {
|
|
|
|
const map = maps.pop();
|
2021-04-30 22:54:00 -04:00
|
|
|
assets.push({
|
|
|
|
id: uuid(),
|
2021-06-10 02:03:17 -04:00
|
|
|
owner: map.owner,
|
2021-06-25 03:45:49 -04:00
|
|
|
file: map.file,
|
|
|
|
width: map.width,
|
|
|
|
height: map.height,
|
2021-04-30 22:54:00 -04:00
|
|
|
mime: "",
|
|
|
|
prevId: map.id,
|
2021-06-25 03:45:49 -04:00
|
|
|
prevType: "map",
|
2021-04-30 22:54:00 -04:00
|
|
|
});
|
|
|
|
|
2021-06-25 03:45:49 -04:00
|
|
|
for (let resolution in map.resolutions) {
|
|
|
|
const mapRes = map.resolutions[resolution];
|
|
|
|
assets.push({
|
|
|
|
id: uuid(),
|
|
|
|
owner: map.owner,
|
|
|
|
file: mapRes.file,
|
|
|
|
width: mapRes.width,
|
|
|
|
height: mapRes.height,
|
|
|
|
mime: "",
|
|
|
|
prevId: map.id,
|
|
|
|
prevType: "mapResolution",
|
|
|
|
resolution,
|
|
|
|
});
|
|
|
|
}
|
2021-06-25 07:29:03 -04:00
|
|
|
if (map.thumbnail) {
|
|
|
|
assets.push({
|
|
|
|
id: uuid(),
|
|
|
|
owner: map.owner,
|
|
|
|
file: map.thumbnail.file,
|
|
|
|
width: map.thumbnail.width,
|
|
|
|
height: map.thumbnail.height,
|
|
|
|
mime: "",
|
|
|
|
prevId: map.id,
|
|
|
|
prevType: "mapThumbnail",
|
|
|
|
});
|
|
|
|
}
|
2021-06-25 03:45:49 -04:00
|
|
|
}
|
|
|
|
await tx.table("assets").bulkAdd(assets);
|
|
|
|
}
|
2021-04-30 22:54:00 -04:00
|
|
|
});
|
|
|
|
},
|
|
|
|
// v1.9.0 - Move token assets into new table
|
2021-06-24 02:14:20 -04:00
|
|
|
25(v, onUpgrade) {
|
2021-06-25 03:45:49 -04:00
|
|
|
v.stores({}).upgrade(async (tx) => {
|
2021-06-24 02:14:20 -04:00
|
|
|
onUpgrade?.(25);
|
2021-06-25 03:45:49 -04:00
|
|
|
|
|
|
|
const primaryKeys = await Dexie.waitFor(
|
|
|
|
tx.table("tokens").toCollection().primaryKeys()
|
|
|
|
);
|
|
|
|
const keyChunks = chunk(primaryKeys, 4);
|
|
|
|
|
|
|
|
for (let keys of keyChunks) {
|
2021-04-30 22:54:00 -04:00
|
|
|
let assets = [];
|
2021-06-25 03:45:49 -04:00
|
|
|
let tokens = await Dexie.waitFor(tx.table("tokens").bulkGet(keys));
|
|
|
|
while (tokens.length > 0) {
|
|
|
|
let token = tokens.pop();
|
|
|
|
assets.push({
|
|
|
|
id: uuid(),
|
|
|
|
owner: token.owner,
|
|
|
|
file: token.file,
|
|
|
|
width: token.width,
|
|
|
|
height: token.height,
|
|
|
|
mime: "",
|
|
|
|
prevId: token.id,
|
|
|
|
prevType: "token",
|
|
|
|
});
|
2021-06-25 07:29:03 -04:00
|
|
|
if (token.thumbnail) {
|
|
|
|
assets.push({
|
|
|
|
id: uuid(),
|
|
|
|
owner: token.owner,
|
|
|
|
file: token.thumbnail.file,
|
|
|
|
width: token.thumbnail.width,
|
|
|
|
height: token.thumbnail.height,
|
|
|
|
mime: "",
|
|
|
|
prevId: token.id,
|
|
|
|
prevType: "tokenThumbnail",
|
|
|
|
});
|
|
|
|
}
|
2021-06-25 03:45:49 -04:00
|
|
|
}
|
|
|
|
await tx.table("assets").bulkAdd(assets);
|
|
|
|
}
|
2021-04-30 22:54:00 -04:00
|
|
|
});
|
|
|
|
},
|
|
|
|
// v1.9.0 - Create foreign keys for assets
|
2021-06-24 02:14:20 -04:00
|
|
|
26(v, onUpgrade) {
|
2021-06-25 03:45:49 -04:00
|
|
|
v.stores({}).upgrade(async (tx) => {
|
2021-06-24 02:14:20 -04:00
|
|
|
onUpgrade?.(26);
|
2021-06-25 03:45:49 -04:00
|
|
|
|
2021-07-16 00:55:33 -04:00
|
|
|
let mapUpdates: Record<string, any> = {};
|
|
|
|
let tokenUpdates: Record<string, any> = {};
|
2021-06-25 03:45:49 -04:00
|
|
|
|
|
|
|
const primaryKeys = await Dexie.waitFor(
|
|
|
|
tx.table("assets").toCollection().primaryKeys()
|
|
|
|
);
|
|
|
|
const keyChunks = chunk(primaryKeys, 4);
|
|
|
|
|
|
|
|
for (let keys of keyChunks) {
|
|
|
|
let assets = await Dexie.waitFor(tx.table("assets").bulkGet(keys));
|
|
|
|
while (assets.length > 0) {
|
|
|
|
const asset = assets.pop();
|
|
|
|
const { prevId, id, prevType, resolution } = asset;
|
|
|
|
if (prevType === "token" || prevType === "tokenThumbnail") {
|
|
|
|
if (!(prevId in tokenUpdates)) {
|
|
|
|
tokenUpdates[prevId] = {};
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (!(prevId in mapUpdates)) {
|
|
|
|
mapUpdates[prevId] = {};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (prevType === "map") {
|
|
|
|
mapUpdates[prevId].file = id;
|
|
|
|
} else if (prevType === "token") {
|
|
|
|
tokenUpdates[prevId].file = id;
|
|
|
|
} else if (prevType === "mapThumbnail") {
|
|
|
|
mapUpdates[prevId].thumbnail = id;
|
|
|
|
} else if (prevType === "tokenThumbnail") {
|
|
|
|
tokenUpdates[prevId].thumbnail = id;
|
|
|
|
} else if (prevType === "mapResolution") {
|
|
|
|
mapUpdates[prevId][resolution] = id;
|
|
|
|
}
|
2021-04-30 22:54:00 -04:00
|
|
|
}
|
2021-06-25 03:45:49 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
await tx
|
|
|
|
.table("maps")
|
|
|
|
.toCollection()
|
|
|
|
.modify((map) => {
|
|
|
|
if (map.id in mapUpdates) {
|
|
|
|
for (let key in mapUpdates[map.id]) {
|
|
|
|
map[key] = mapUpdates[map.id][key];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
delete map.resolutions;
|
|
|
|
});
|
|
|
|
await tx
|
|
|
|
.table("tokens")
|
|
|
|
.toCollection()
|
|
|
|
.modify((token) => {
|
|
|
|
if (token.id in tokenUpdates) {
|
|
|
|
for (let key in tokenUpdates[token.id]) {
|
|
|
|
token[key] = tokenUpdates[token.id][key];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
2021-04-30 22:54:00 -04:00
|
|
|
});
|
|
|
|
},
|
|
|
|
// v1.9.0 - Remove asset migration helpers
|
2021-06-24 02:14:20 -04:00
|
|
|
27(v, onUpgrade) {
|
2021-04-30 22:54:00 -04:00
|
|
|
v.stores({}).upgrade((tx) => {
|
2021-06-24 02:14:20 -04:00
|
|
|
onUpgrade?.(27);
|
2021-06-25 03:45:49 -04:00
|
|
|
tx.table("assets").toCollection().modify({
|
|
|
|
prevId: undefined,
|
|
|
|
prevType: undefined,
|
|
|
|
resolution: undefined,
|
|
|
|
});
|
2021-04-30 22:54:00 -04:00
|
|
|
});
|
|
|
|
},
|
|
|
|
// v1.9.0 - Remap map resolution assets
|
2021-06-24 02:14:20 -04:00
|
|
|
28(v, onUpgrade) {
|
2021-04-30 22:54:00 -04:00
|
|
|
v.stores({}).upgrade((tx) => {
|
2021-06-24 02:14:20 -04:00
|
|
|
onUpgrade?.(28);
|
2021-04-30 22:54:00 -04:00
|
|
|
tx.table("maps")
|
|
|
|
.toCollection()
|
|
|
|
.modify((map) => {
|
|
|
|
const resolutions = ["low", "medium", "high", "ultra"];
|
|
|
|
map.resolutions = {};
|
|
|
|
for (let res of resolutions) {
|
|
|
|
if (res in map) {
|
|
|
|
map.resolutions[res] = map[res];
|
|
|
|
delete map[res];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
delete map.lastUsed;
|
|
|
|
});
|
|
|
|
});
|
|
|
|
},
|
2021-06-10 01:06:11 -04:00
|
|
|
// v1.9.0 - Move tokens to use more defaults
|
2021-06-24 02:14:20 -04:00
|
|
|
29(v, onUpgrade) {
|
2021-04-30 22:54:00 -04:00
|
|
|
v.stores({}).upgrade((tx) => {
|
2021-06-24 02:14:20 -04:00
|
|
|
onUpgrade?.(29);
|
2021-04-30 22:54:00 -04:00
|
|
|
tx.table("tokens")
|
|
|
|
.toCollection()
|
|
|
|
.modify(async (token) => {
|
|
|
|
token.defaultCategory = token.category;
|
|
|
|
delete token.category;
|
|
|
|
token.defaultLabel = "";
|
|
|
|
delete token.lastUsed;
|
|
|
|
});
|
|
|
|
});
|
|
|
|
},
|
|
|
|
// v1.9.0 - Move tokens to use more defaults and add token outline to token states
|
2021-06-24 02:14:20 -04:00
|
|
|
30(v, onUpgrade) {
|
2021-04-30 22:54:00 -04:00
|
|
|
v.stores({}).upgrade(async (tx) => {
|
2021-06-24 02:14:20 -04:00
|
|
|
onUpgrade?.(30);
|
2021-04-30 22:54:00 -04:00
|
|
|
const tokens = await Dexie.waitFor(tx.table("tokens").toArray());
|
|
|
|
tx.table("states")
|
|
|
|
.toCollection()
|
|
|
|
.modify((state) => {
|
|
|
|
for (let id in state.tokens) {
|
2021-06-24 05:14:15 -04:00
|
|
|
if (!state.tokens[id]?.tokenId) {
|
2021-06-24 07:45:13 -04:00
|
|
|
delete state.tokens[id];
|
2021-06-24 04:58:31 -04:00
|
|
|
continue;
|
|
|
|
}
|
2021-04-30 22:54:00 -04:00
|
|
|
if (!state.tokens[id].tokenId.startsWith("__default")) {
|
|
|
|
const token = tokens.find(
|
|
|
|
(token) => token.id === state.tokens[id].tokenId
|
|
|
|
);
|
|
|
|
if (token) {
|
|
|
|
state.tokens[id].category = token.defaultCategory;
|
|
|
|
state.tokens[id].file = token.file;
|
|
|
|
state.tokens[id].type = "file";
|
|
|
|
state.tokens[id].outline = token.outline;
|
|
|
|
state.tokens[id].width = token.width;
|
|
|
|
state.tokens[id].height = token.height;
|
2021-06-10 02:13:19 -04:00
|
|
|
state.tokens[id].owner = token.owner;
|
2021-04-30 22:54:00 -04:00
|
|
|
} else {
|
|
|
|
state.tokens[id].category = "character";
|
|
|
|
state.tokens[id].type = "file";
|
|
|
|
state.tokens[id].file = "";
|
2021-06-10 01:06:11 -04:00
|
|
|
state.tokens[id].outline = {
|
|
|
|
type: "rect",
|
|
|
|
width: 256,
|
|
|
|
height: 256,
|
|
|
|
x: 0,
|
|
|
|
y: 0,
|
|
|
|
};
|
2021-04-30 22:54:00 -04:00
|
|
|
state.tokens[id].width = 256;
|
|
|
|
state.tokens[id].height = 256;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
state.tokens[id].category = "character";
|
|
|
|
state.tokens[id].type = "default";
|
|
|
|
state.tokens[id].key = Case.camel(
|
|
|
|
state.tokens[id].tokenId.slice(10)
|
|
|
|
);
|
2021-06-10 01:06:11 -04:00
|
|
|
state.tokens[id].outline = {
|
|
|
|
type: "circle",
|
|
|
|
x: 128,
|
|
|
|
y: 128,
|
|
|
|
radius: 128,
|
|
|
|
};
|
2021-04-30 22:54:00 -04:00
|
|
|
state.tokens[id].width = 256;
|
|
|
|
state.tokens[id].height = 256;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
},
|
|
|
|
// v1.9.0 - Remove maps not owned by user as cache is now done on the asset level
|
2021-06-24 02:14:20 -04:00
|
|
|
31(v, onUpgrade) {
|
2021-04-30 22:54:00 -04:00
|
|
|
v.stores({}).upgrade(async (tx) => {
|
2021-06-24 02:14:20 -04:00
|
|
|
onUpgrade?.(31);
|
2021-04-30 22:54:00 -04:00
|
|
|
const userId = (await Dexie.waitFor(tx.table("user").get("userId")))
|
|
|
|
?.value;
|
|
|
|
if (userId) {
|
|
|
|
tx.table("maps").where("owner").notEqual(userId).delete();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
},
|
|
|
|
// v1.9.0 - Remove tokens not owned by user as cache is now done on the asset level
|
2021-06-24 02:14:20 -04:00
|
|
|
32(v, onUpgrade) {
|
2021-04-30 22:54:00 -04:00
|
|
|
v.stores({}).upgrade(async (tx) => {
|
2021-06-24 02:14:20 -04:00
|
|
|
onUpgrade?.(32);
|
2021-04-30 22:54:00 -04:00
|
|
|
const userId = (await Dexie.waitFor(tx.table("user").get("userId")))
|
|
|
|
?.value;
|
|
|
|
if (userId) {
|
|
|
|
tx.table("tokens").where("owner").notEqual(userId).delete();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
},
|
|
|
|
// v1.9.0 - Store default maps and tokens in db
|
2021-06-24 02:14:20 -04:00
|
|
|
33(v, onUpgrade) {
|
2021-04-30 22:54:00 -04:00
|
|
|
v.stores({}).upgrade(async (tx) => {
|
2021-06-24 02:14:20 -04:00
|
|
|
onUpgrade?.(33);
|
2021-04-30 22:54:00 -04:00
|
|
|
const userId = (await Dexie.waitFor(tx.table("user").get("userId")))
|
|
|
|
?.value;
|
|
|
|
if (!userId) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
const { maps } = getDefaultMaps(userId);
|
|
|
|
tx.table("maps").bulkAdd(maps);
|
|
|
|
const tokens = getDefaultTokens(userId);
|
|
|
|
tx.table("tokens").bulkAdd(tokens);
|
|
|
|
});
|
|
|
|
},
|
2021-05-14 04:02:50 -04:00
|
|
|
// v1.9.0 - Add new group table
|
2021-06-24 02:14:20 -04:00
|
|
|
34(v, onUpgrade) {
|
2021-05-08 22:04:31 -04:00
|
|
|
v.stores({ groups: "id" }).upgrade(async (tx) => {
|
2021-06-24 02:14:20 -04:00
|
|
|
onUpgrade?.(34);
|
2021-07-17 04:18:57 -04:00
|
|
|
function groupItems(items: { id: string; group: string }[]) {
|
2021-07-16 00:55:33 -04:00
|
|
|
let groups: Group[] = [];
|
|
|
|
let subGroups: Record<string, GroupContainer> = {};
|
2021-05-14 04:02:50 -04:00
|
|
|
for (let item of items) {
|
|
|
|
if (!item.group) {
|
|
|
|
groups.push({ id: item.id, type: "item" });
|
|
|
|
} else if (item.group in subGroups) {
|
|
|
|
subGroups[item.group].items.push({ id: item.id, type: "item" });
|
|
|
|
} else {
|
|
|
|
subGroups[item.group] = {
|
|
|
|
id: uuid(),
|
|
|
|
type: "group",
|
|
|
|
name: item.group,
|
|
|
|
items: [{ id: item.id, type: "item" }],
|
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
groups.push(...Object.values(subGroups));
|
|
|
|
return groups;
|
|
|
|
}
|
|
|
|
|
2021-05-08 22:04:31 -04:00
|
|
|
let maps = await Dexie.waitFor(tx.table("maps").toArray());
|
|
|
|
maps = maps.sort((a, b) => b.created - a.created);
|
2021-05-14 04:02:50 -04:00
|
|
|
const mapGroupItems = groupItems(maps);
|
|
|
|
tx.table("groups").add({ id: "maps", items: mapGroupItems });
|
2021-05-08 22:04:31 -04:00
|
|
|
|
|
|
|
let tokens = await Dexie.waitFor(tx.table("tokens").toArray());
|
|
|
|
tokens = tokens.sort((a, b) => b.created - a.created);
|
2021-05-14 04:02:50 -04:00
|
|
|
const tokenGroupItems = groupItems(tokens);
|
|
|
|
tx.table("groups").add({ id: "tokens", items: tokenGroupItems });
|
|
|
|
});
|
|
|
|
},
|
|
|
|
// v1.9.0 - Remove map and token group in respective tables
|
2021-06-24 02:14:20 -04:00
|
|
|
35(v, onUpgrade) {
|
2021-05-14 04:02:50 -04:00
|
|
|
v.stores({}).upgrade((tx) => {
|
2021-06-24 02:14:20 -04:00
|
|
|
onUpgrade?.(35);
|
2021-05-14 04:02:50 -04:00
|
|
|
tx.table("maps")
|
|
|
|
.toCollection()
|
|
|
|
.modify((map) => {
|
|
|
|
delete map.group;
|
|
|
|
});
|
|
|
|
tx.table("tokens")
|
|
|
|
.toCollection()
|
|
|
|
.modify((token) => {
|
|
|
|
delete token.group;
|
|
|
|
});
|
2021-05-08 22:04:31 -04:00
|
|
|
});
|
|
|
|
},
|
2021-06-25 03:45:49 -04:00
|
|
|
36(v) {
|
|
|
|
v.stores({
|
|
|
|
_changes: null,
|
|
|
|
_intercomm: null,
|
|
|
|
_syncNodes: null,
|
|
|
|
_uncommittedChanges: null,
|
|
|
|
});
|
|
|
|
},
|
2021-04-30 22:54:00 -04:00
|
|
|
};
|
|
|
|
|
2021-06-25 03:45:49 -04:00
|
|
|
export const latestVersion = 36;
|
2021-04-30 22:54:00 -04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Load versions onto a database up to a specific version number
|
|
|
|
* @param {Dexie} db
|
|
|
|
* @param {number=} upTo version number to load up to, latest version if undefined
|
2021-07-16 00:55:33 -04:00
|
|
|
* @param {UpgradeEventHandler=} onUpgrade
|
2021-04-30 22:54:00 -04:00
|
|
|
*/
|
2021-07-17 04:18:57 -04:00
|
|
|
export function loadVersions(
|
|
|
|
db: Dexie,
|
|
|
|
upTo: number | undefined = latestVersion,
|
|
|
|
onUpgrade: UpgradeEventHandler | undefined
|
|
|
|
) {
|
2021-04-30 22:54:00 -04:00
|
|
|
for (let versionNumber = 1; versionNumber <= upTo; versionNumber++) {
|
2021-06-24 02:14:20 -04:00
|
|
|
versions[versionNumber](db.version(versionNumber), onUpgrade);
|
2021-04-30 22:54:00 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Convert from the previous representation of actions (1.7.0) to the new representation (1.8.0)
|
|
|
|
* and combine into shapes
|
|
|
|
*/
|
2021-07-16 00:55:33 -04:00
|
|
|
function convertOldActionsToShapes(actions: any[], actionIndex: number) {
|
2021-04-30 22:54:00 -04:00
|
|
|
let newShapes = {};
|
|
|
|
for (let i = 0; i <= actionIndex; i++) {
|
|
|
|
const action = actions[i];
|
|
|
|
if (!action) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
let newAction;
|
|
|
|
if (action.shapes) {
|
|
|
|
if (action.type === "add") {
|
2021-07-16 00:55:33 -04:00
|
|
|
newAction = new AddStatesAction(action.shapes);
|
2021-04-30 22:54:00 -04:00
|
|
|
} else if (action.type === "edit") {
|
2021-07-16 00:55:33 -04:00
|
|
|
newAction = new EditStatesAction(action.shapes);
|
2021-04-30 22:54:00 -04:00
|
|
|
} else if (action.type === "remove") {
|
2021-07-16 00:55:33 -04:00
|
|
|
newAction = new RemoveStatesAction(action.shapes);
|
2021-04-30 22:54:00 -04:00
|
|
|
} else if (action.type === "subtract") {
|
2021-07-16 00:55:33 -04:00
|
|
|
newAction = new SubtractFogAction(action.shapes);
|
2021-04-30 22:54:00 -04:00
|
|
|
} else if (action.type === "cut") {
|
2021-07-16 00:55:33 -04:00
|
|
|
newAction = new CutFogAction(action.shapes);
|
2021-04-30 22:54:00 -04:00
|
|
|
}
|
|
|
|
} else if (action.type === "remove" && action.shapeIds) {
|
2021-07-16 00:55:33 -04:00
|
|
|
newAction = new RemoveStatesAction(action.shapeIds);
|
2021-04-30 22:54:00 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (newAction) {
|
|
|
|
newShapes = newAction.execute(newShapes);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return newShapes;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Helper to create a thumbnail for a file in a db
|
2021-07-17 04:18:57 -04:00
|
|
|
async function createDataThumbnail(data: any): Promise<{
|
|
|
|
file: Uint8Array;
|
|
|
|
width: number;
|
|
|
|
height: number;
|
|
|
|
type: "file";
|
|
|
|
id: "thumbnail";
|
2021-07-16 00:55:33 -04:00
|
|
|
}> {
|
|
|
|
let url: string;
|
2021-04-30 22:54:00 -04:00
|
|
|
if (data?.resolutions?.low?.file) {
|
|
|
|
url = URL.createObjectURL(new Blob([data.resolutions.low.file]));
|
|
|
|
} else {
|
|
|
|
url = URL.createObjectURL(new Blob([data.file]));
|
|
|
|
}
|
|
|
|
return await Dexie.waitFor(
|
|
|
|
new Promise((resolve) => {
|
|
|
|
let image = new Image();
|
|
|
|
image.onload = async () => {
|
2021-07-16 00:55:33 -04:00
|
|
|
const thumbnail = await createThumbnail(image, "");
|
|
|
|
if (thumbnail) {
|
|
|
|
resolve({
|
|
|
|
file: thumbnail.file,
|
|
|
|
width: thumbnail.width,
|
|
|
|
height: thumbnail.height,
|
|
|
|
type: "file",
|
|
|
|
id: "thumbnail",
|
|
|
|
});
|
|
|
|
}
|
2021-04-30 22:54:00 -04:00
|
|
|
};
|
|
|
|
image.src = url;
|
|
|
|
}),
|
|
|
|
60000 * 10 // 10 minute timeout
|
|
|
|
);
|
|
|
|
}
|
2021-06-10 01:06:11 -04:00
|
|
|
|
2021-07-17 04:18:57 -04:00
|
|
|
async function createDataOutline(
|
|
|
|
data: any
|
|
|
|
): Promise<{ id: string; outline: Outline }> {
|
2021-06-10 01:06:11 -04:00
|
|
|
const url = URL.createObjectURL(new Blob([data.file]));
|
|
|
|
return await Dexie.waitFor(
|
|
|
|
new Promise((resolve) => {
|
|
|
|
let image = new Image();
|
|
|
|
image.onload = async () => {
|
|
|
|
resolve({ id: data.id, outline: getImageOutline(image) });
|
|
|
|
};
|
|
|
|
image.onerror = () => {
|
|
|
|
resolve({
|
|
|
|
id: data.id,
|
|
|
|
outline: {
|
|
|
|
type: "rect",
|
|
|
|
width: data.width,
|
|
|
|
height: data.height,
|
|
|
|
x: 0,
|
|
|
|
y: 0,
|
|
|
|
},
|
|
|
|
});
|
|
|
|
};
|
|
|
|
image.src = url;
|
|
|
|
})
|
|
|
|
);
|
|
|
|
}
|