2022-11-24 21:34:34 -06:00
|
|
|
const stampTool = () =>
|
|
|
|
toolbar.registerTool(
|
2022-12-18 17:50:40 -06:00
|
|
|
"./res/icons/file-up.svg",
|
2022-11-24 21:34:34 -06:00
|
|
|
"Stamp Image",
|
|
|
|
(state, opt) => {
|
2022-11-29 18:16:59 -06:00
|
|
|
state.loaded = true;
|
|
|
|
|
2022-11-24 21:34:34 -06:00
|
|
|
// Draw new cursor immediately
|
2022-12-16 19:57:28 -06:00
|
|
|
ovLayer.clear();
|
2022-11-29 14:55:25 -06:00
|
|
|
state.movecb({...mouse.coords.world.pos});
|
2022-11-24 21:34:34 -06:00
|
|
|
|
|
|
|
// Start Listeners
|
2022-11-29 14:55:25 -06:00
|
|
|
mouse.listen.world.onmousemove.on(state.movecb);
|
|
|
|
mouse.listen.world.btn.left.onclick.on(state.drawcb);
|
|
|
|
mouse.listen.world.btn.right.onclick.on(state.cancelcb);
|
2022-11-24 21:34:34 -06:00
|
|
|
|
|
|
|
// For calls from other tools to paste image
|
|
|
|
if (opt && opt.image) {
|
2022-11-25 12:22:16 -06:00
|
|
|
state.addResource(
|
2022-11-24 21:34:34 -06:00
|
|
|
opt.name || "Clipboard",
|
|
|
|
opt.image,
|
2022-12-02 04:22:47 -06:00
|
|
|
opt.temporary === undefined ? true : opt.temporary,
|
|
|
|
false
|
2022-11-24 21:34:34 -06:00
|
|
|
);
|
|
|
|
state.ctxmenu.uploadButton.disabled = true;
|
|
|
|
state.back = opt.back || null;
|
2022-11-24 21:55:16 -06:00
|
|
|
toolbar.lock();
|
2022-11-24 21:34:34 -06:00
|
|
|
} else if (opt) {
|
|
|
|
throw Error(
|
|
|
|
"Pasting from other tools must be in format {image, name?, temporary?, back?}"
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
state.ctxmenu.uploadButton.disabled = "";
|
|
|
|
}
|
|
|
|
},
|
|
|
|
(state, opt) => {
|
2022-11-29 18:16:59 -06:00
|
|
|
state.loaded = false;
|
|
|
|
|
2022-11-24 21:34:34 -06:00
|
|
|
// Clear Listeners
|
2022-11-29 14:55:25 -06:00
|
|
|
mouse.listen.world.onmousemove.clear(state.movecb);
|
|
|
|
mouse.listen.world.btn.left.onclick.clear(state.drawcb);
|
|
|
|
mouse.listen.world.btn.right.onclick.clear(state.cancelcb);
|
2022-11-24 22:46:49 -06:00
|
|
|
|
|
|
|
// Deselect
|
|
|
|
state.selected = null;
|
|
|
|
Array.from(state.ctxmenu.resourceList.children).forEach((child) => {
|
2022-12-11 17:54:38 -06:00
|
|
|
child.classList.remove("active");
|
2022-11-24 22:46:49 -06:00
|
|
|
});
|
2022-12-04 13:22:35 -06:00
|
|
|
|
2022-12-16 19:57:28 -06:00
|
|
|
ovLayer.clear();
|
2022-11-24 21:34:34 -06:00
|
|
|
},
|
|
|
|
{
|
|
|
|
init: (state) => {
|
2022-11-29 18:16:59 -06:00
|
|
|
state.loaded = false;
|
2022-11-24 21:34:34 -06:00
|
|
|
state.snapToGrid = true;
|
|
|
|
state.resources = [];
|
|
|
|
state.selected = null;
|
|
|
|
state.back = null;
|
|
|
|
|
2022-11-25 12:22:16 -06:00
|
|
|
state.lastMouseMove = {x: 0, y: 0};
|
2022-12-18 20:35:48 -06:00
|
|
|
state.block_res_change = true;
|
2022-11-25 12:22:16 -06:00
|
|
|
|
2022-12-02 04:22:47 -06:00
|
|
|
state.selectResource = (resource, nolock = true) => {
|
|
|
|
if (nolock && state.ctxmenu.uploadButton.disabled) return;
|
|
|
|
|
|
|
|
console.debug(
|
|
|
|
`[stamp] Selecting Resource '${resource && resource.name}'[${
|
|
|
|
resource && resource.id
|
|
|
|
}]`
|
|
|
|
);
|
2022-11-25 10:16:22 -06:00
|
|
|
|
2022-11-25 12:22:16 -06:00
|
|
|
const resourceWrapper = resource && resource.dom.wrapper;
|
2022-11-25 10:16:22 -06:00
|
|
|
|
2022-11-25 12:22:16 -06:00
|
|
|
const wasSelected =
|
2022-12-11 17:54:38 -06:00
|
|
|
resourceWrapper && resourceWrapper.classList.contains("active");
|
2022-11-25 10:16:22 -06:00
|
|
|
|
|
|
|
Array.from(state.ctxmenu.resourceList.children).forEach((child) => {
|
2022-12-11 17:54:38 -06:00
|
|
|
child.classList.remove("active");
|
2022-11-25 10:16:22 -06:00
|
|
|
});
|
|
|
|
|
|
|
|
// Select
|
|
|
|
if (!wasSelected) {
|
2022-12-11 17:54:38 -06:00
|
|
|
resourceWrapper && resourceWrapper.classList.add("active");
|
2022-11-25 10:16:22 -06:00
|
|
|
state.selected = resource;
|
|
|
|
}
|
|
|
|
// If already selected, clear selection
|
|
|
|
else {
|
2022-12-11 17:54:38 -06:00
|
|
|
resourceWrapper.classList.remove("active");
|
2022-11-25 10:16:22 -06:00
|
|
|
state.selected = null;
|
|
|
|
}
|
2022-11-25 12:22:16 -06:00
|
|
|
|
2022-12-16 19:57:28 -06:00
|
|
|
ovLayer.clear();
|
2022-11-29 18:16:59 -06:00
|
|
|
if (state.loaded) state.movecb(state.lastMouseMove);
|
2022-11-25 10:16:22 -06:00
|
|
|
};
|
|
|
|
|
2022-12-12 07:03:05 -06:00
|
|
|
// Open IndexedDB connection
|
|
|
|
const IDBOpenRequest = window.indexedDB.open("stamp", 1);
|
|
|
|
|
2022-12-03 07:48:05 -06:00
|
|
|
// Synchronizes resources array with the DOM and Local Storage
|
2022-11-24 21:34:34 -06:00
|
|
|
const syncResources = () => {
|
2022-12-12 07:03:05 -06:00
|
|
|
// Saves to IndexedDB
|
|
|
|
/** @type {IDBDatabase} */
|
|
|
|
const db = state.stampDB;
|
|
|
|
const resources = db
|
|
|
|
.transaction("resources", "readwrite")
|
|
|
|
.objectStore("resources");
|
2022-12-03 07:48:05 -06:00
|
|
|
try {
|
2022-12-12 07:03:05 -06:00
|
|
|
const FetchKeysQuery = resources.getAllKeys();
|
|
|
|
FetchKeysQuery.onsuccess = () => {
|
|
|
|
const keys = FetchKeysQuery.result;
|
|
|
|
keys.forEach((key) => {
|
|
|
|
if (!state.resources.find((resource) => resource.id === key))
|
|
|
|
resources.delete(key);
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
state.resources
|
|
|
|
.filter((resource) => !resource.temporary && resource.dirty)
|
|
|
|
.forEach((resource) => {
|
|
|
|
const canvas = document.createElement("canvas");
|
|
|
|
canvas.width = resource.image.width;
|
|
|
|
canvas.height = resource.image.height;
|
|
|
|
|
|
|
|
const ctx = canvas.getContext("2d");
|
|
|
|
ctx.drawImage(resource.image, 0, 0);
|
|
|
|
|
|
|
|
resources.put({
|
|
|
|
id: resource.id,
|
|
|
|
name: resource.name,
|
|
|
|
src: canvas.toDataURL(),
|
|
|
|
});
|
|
|
|
|
|
|
|
resource.dirty = false;
|
|
|
|
});
|
2022-12-03 07:48:05 -06:00
|
|
|
} catch (e) {
|
|
|
|
console.warn(
|
2022-12-12 07:03:05 -06:00
|
|
|
"[stamp] Failed to synchronize resources with IndexedDB"
|
2022-12-03 07:48:05 -06:00
|
|
|
);
|
|
|
|
console.warn(e);
|
|
|
|
}
|
|
|
|
|
2022-11-25 10:16:22 -06:00
|
|
|
// Creates DOM elements when needed
|
2022-11-24 21:34:34 -06:00
|
|
|
state.resources.forEach((resource) => {
|
2022-11-25 10:16:22 -06:00
|
|
|
if (
|
|
|
|
!state.ctxmenu.resourceList.querySelector(
|
|
|
|
`#resource-${resource.id}`
|
|
|
|
)
|
|
|
|
) {
|
|
|
|
console.debug(
|
2022-12-02 04:22:47 -06:00
|
|
|
`[stamp] Creating Resource Element [resource-${resource.id}]`
|
2022-11-25 10:16:22 -06:00
|
|
|
);
|
2022-11-24 21:34:34 -06:00
|
|
|
const resourceWrapper = document.createElement("div");
|
|
|
|
resourceWrapper.id = `resource-${resource.id}`;
|
2022-12-11 17:54:38 -06:00
|
|
|
resourceWrapper.classList.add("resource", "list-item");
|
|
|
|
const resourceTitle = document.createElement("input");
|
|
|
|
resourceTitle.value = resource.name;
|
|
|
|
resourceTitle.title = resource.name;
|
|
|
|
resourceTitle.style.pointerEvents = "none";
|
|
|
|
resourceTitle.addEventListener("change", () => {
|
|
|
|
resource.name = resourceTitle.value;
|
2022-12-12 07:03:05 -06:00
|
|
|
resource.dirty = true;
|
2022-12-11 17:54:38 -06:00
|
|
|
resourceTitle.title = resourceTitle.value;
|
|
|
|
|
|
|
|
syncResources();
|
|
|
|
});
|
|
|
|
|
|
|
|
resourceTitle.addEventListener("blur", () => {
|
|
|
|
resourceTitle.style.pointerEvents = "none";
|
|
|
|
});
|
|
|
|
resourceTitle.classList.add("resource-title", "title");
|
|
|
|
|
2022-12-02 11:31:49 -06:00
|
|
|
resourceWrapper.appendChild(resourceTitle);
|
2022-11-24 21:34:34 -06:00
|
|
|
|
2022-11-25 10:16:22 -06:00
|
|
|
resourceWrapper.addEventListener("click", () =>
|
2022-11-25 12:22:16 -06:00
|
|
|
state.selectResource(resource)
|
2022-11-25 10:16:22 -06:00
|
|
|
);
|
2022-11-24 21:34:34 -06:00
|
|
|
|
2022-12-11 17:54:38 -06:00
|
|
|
resourceWrapper.addEventListener("dblclick", () => {
|
|
|
|
resourceTitle.style.pointerEvents = "auto";
|
|
|
|
resourceTitle.focus();
|
|
|
|
resourceTitle.select();
|
|
|
|
});
|
|
|
|
|
2022-11-24 21:34:34 -06:00
|
|
|
resourceWrapper.addEventListener("mouseover", () => {
|
|
|
|
state.ctxmenu.previewPane.style.display = "block";
|
|
|
|
state.ctxmenu.previewPane.style.backgroundImage = `url(${resource.image.src})`;
|
|
|
|
});
|
|
|
|
resourceWrapper.addEventListener("mouseleave", () => {
|
|
|
|
state.ctxmenu.previewPane.style.display = "none";
|
|
|
|
});
|
|
|
|
|
2022-12-02 11:31:49 -06:00
|
|
|
// Add action buttons
|
|
|
|
const actionArray = document.createElement("div");
|
|
|
|
actionArray.classList.add("actions");
|
|
|
|
|
2022-12-11 17:54:38 -06:00
|
|
|
const saveButton = document.createElement("button");
|
|
|
|
saveButton.addEventListener(
|
2022-12-04 05:31:43 -06:00
|
|
|
"click",
|
|
|
|
(evn) => {
|
2022-12-11 21:50:25 -06:00
|
|
|
evn.stopPropagation();
|
2022-12-11 17:54:38 -06:00
|
|
|
const canvas = document.createElement("canvas");
|
|
|
|
canvas.width = resource.image.width;
|
|
|
|
canvas.height = resource.image.height;
|
|
|
|
canvas.getContext("2d").drawImage(resource.image, 0, 0);
|
|
|
|
|
|
|
|
downloadCanvas({
|
|
|
|
canvas,
|
|
|
|
filename: `openOutpaint - resource '${resource.name}'.png`,
|
|
|
|
});
|
2022-12-04 05:31:43 -06:00
|
|
|
},
|
|
|
|
{passive: false}
|
|
|
|
);
|
2022-12-11 17:54:38 -06:00
|
|
|
saveButton.title = "Download Resource";
|
|
|
|
saveButton.appendChild(document.createElement("div"));
|
|
|
|
saveButton.classList.add("download-btn");
|
2022-12-02 11:31:49 -06:00
|
|
|
|
|
|
|
const trashButton = document.createElement("button");
|
2022-12-03 08:05:43 -06:00
|
|
|
trashButton.addEventListener(
|
|
|
|
"click",
|
|
|
|
(evn) => {
|
|
|
|
evn.stopPropagation();
|
|
|
|
state.ctxmenu.previewPane.style.display = "none";
|
|
|
|
state.deleteResource(resource.id);
|
|
|
|
},
|
|
|
|
{passive: false}
|
|
|
|
);
|
2022-12-02 11:31:49 -06:00
|
|
|
trashButton.title = "Delete Resource";
|
|
|
|
trashButton.appendChild(document.createElement("div"));
|
|
|
|
trashButton.classList.add("delete-btn");
|
|
|
|
|
2022-12-11 17:54:38 -06:00
|
|
|
actionArray.appendChild(saveButton);
|
2022-12-02 11:31:49 -06:00
|
|
|
actionArray.appendChild(trashButton);
|
|
|
|
resourceWrapper.appendChild(actionArray);
|
2022-11-24 21:34:34 -06:00
|
|
|
state.ctxmenu.resourceList.appendChild(resourceWrapper);
|
2022-11-25 10:16:22 -06:00
|
|
|
resource.dom = {wrapper: resourceWrapper};
|
2022-11-24 21:34:34 -06:00
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2022-11-25 10:16:22 -06:00
|
|
|
// Removes DOM elements when needed
|
2022-11-24 21:34:34 -06:00
|
|
|
const elements = Array.from(state.ctxmenu.resourceList.children);
|
|
|
|
|
|
|
|
if (elements.length > state.resources.length)
|
|
|
|
elements.forEach((element) => {
|
2022-11-24 22:46:49 -06:00
|
|
|
let remove = true;
|
|
|
|
state.resources.some((resource) => {
|
2022-12-02 04:22:47 -06:00
|
|
|
if (element.id.endsWith(resource.id)) {
|
|
|
|
remove = false;
|
|
|
|
}
|
2022-11-24 22:46:49 -06:00
|
|
|
});
|
|
|
|
|
2022-12-02 04:22:47 -06:00
|
|
|
if (remove) {
|
|
|
|
console.debug(`[stamp] Sync Removing Element [${element.id}]`);
|
|
|
|
state.ctxmenu.resourceList.removeChild(element);
|
|
|
|
}
|
2022-11-24 21:34:34 -06:00
|
|
|
});
|
|
|
|
};
|
|
|
|
|
2022-11-25 10:16:22 -06:00
|
|
|
// Adds a image resource (temporary allows only one draw, used for pasting)
|
2022-12-02 04:22:47 -06:00
|
|
|
state.addResource = (name, image, temporary = false, nolock = true) => {
|
2022-11-24 21:34:34 -06:00
|
|
|
const id = guid();
|
|
|
|
const resource = {
|
|
|
|
id,
|
|
|
|
name,
|
|
|
|
image,
|
2022-12-12 07:03:05 -06:00
|
|
|
dirty: true,
|
2022-11-24 21:34:34 -06:00
|
|
|
temporary,
|
|
|
|
};
|
2022-12-02 04:22:47 -06:00
|
|
|
|
|
|
|
console.info(`[stamp] Adding Resource '${name}'[${id}]`);
|
|
|
|
|
2022-11-24 21:34:34 -06:00
|
|
|
state.resources.push(resource);
|
|
|
|
syncResources();
|
2022-11-25 10:16:22 -06:00
|
|
|
|
|
|
|
// Select this resource
|
2022-12-02 04:22:47 -06:00
|
|
|
state.selectResource(resource, nolock);
|
2022-11-25 10:16:22 -06:00
|
|
|
|
2022-11-24 21:34:34 -06:00
|
|
|
return resource;
|
|
|
|
};
|
2022-11-25 10:16:22 -06:00
|
|
|
|
|
|
|
// Used for temporary images too
|
2022-11-24 21:34:34 -06:00
|
|
|
state.deleteResource = (id) => {
|
2022-12-02 04:22:47 -06:00
|
|
|
const resourceIndex = state.resources.findIndex((v) => v.id === id);
|
|
|
|
const resource = state.resources[resourceIndex];
|
2022-12-03 08:05:43 -06:00
|
|
|
if (state.selected === resource) state.selected = null;
|
2022-12-02 04:22:47 -06:00
|
|
|
console.info(
|
|
|
|
`[stamp] Deleting Resource '${resource.name}'[${resource.id}]`
|
|
|
|
);
|
|
|
|
|
|
|
|
state.resources.splice(resourceIndex, 1);
|
2022-11-24 21:34:34 -06:00
|
|
|
|
|
|
|
syncResources();
|
|
|
|
};
|
|
|
|
|
|
|
|
state.movecb = (evn) => {
|
2022-11-29 14:55:25 -06:00
|
|
|
let x = evn.x;
|
|
|
|
let y = evn.y;
|
|
|
|
if (state.snapToGrid) {
|
2022-12-03 06:53:12 -06:00
|
|
|
x += snap(evn.x, 0, 64);
|
|
|
|
y += snap(evn.y, 0, 64);
|
2022-11-29 14:55:25 -06:00
|
|
|
}
|
2022-11-25 12:22:16 -06:00
|
|
|
|
2022-12-20 20:26:52 -06:00
|
|
|
const vpc = viewport.canvasToView(x, y);
|
|
|
|
uiCtx.clearRect(0, 0, uiCanvas.width, uiCanvas.height);
|
|
|
|
|
|
|
|
uiCtx.save();
|
|
|
|
|
2022-11-29 14:55:25 -06:00
|
|
|
state.lastMouseMove = evn;
|
2022-11-24 21:34:34 -06:00
|
|
|
|
2022-12-16 19:57:28 -06:00
|
|
|
ovLayer.clear();
|
2022-11-24 21:34:34 -06:00
|
|
|
|
2022-11-29 14:55:25 -06:00
|
|
|
// Draw selected image
|
|
|
|
if (state.selected) {
|
|
|
|
ovCtx.drawImage(state.selected.image, x, y);
|
2022-11-24 21:34:34 -06:00
|
|
|
}
|
2022-11-29 14:55:25 -06:00
|
|
|
|
|
|
|
// Draw current cursor location
|
2022-12-20 20:26:52 -06:00
|
|
|
uiCtx.lineWidth = 3;
|
|
|
|
uiCtx.strokeStyle = "#FFF";
|
|
|
|
|
|
|
|
uiCtx.beginPath();
|
|
|
|
uiCtx.moveTo(vpc.x, vpc.y + 10);
|
|
|
|
uiCtx.lineTo(vpc.x, vpc.y - 10);
|
|
|
|
uiCtx.moveTo(vpc.x + 10, vpc.y);
|
|
|
|
uiCtx.lineTo(vpc.x - 10, vpc.y);
|
|
|
|
uiCtx.stroke();
|
|
|
|
|
|
|
|
uiCtx.restore();
|
2022-11-24 21:34:34 -06:00
|
|
|
};
|
|
|
|
|
|
|
|
state.drawcb = (evn) => {
|
2022-11-29 14:55:25 -06:00
|
|
|
let x = evn.x;
|
|
|
|
let y = evn.y;
|
|
|
|
if (state.snapToGrid) {
|
2022-12-03 06:53:12 -06:00
|
|
|
x += snap(evn.x, 0, 64);
|
|
|
|
y += snap(evn.y, 0, 64);
|
2022-11-29 14:55:25 -06:00
|
|
|
}
|
2022-11-24 21:34:34 -06:00
|
|
|
|
2022-11-29 14:55:25 -06:00
|
|
|
const resource = state.selected;
|
2022-11-24 21:34:34 -06:00
|
|
|
|
2022-11-29 14:55:25 -06:00
|
|
|
if (resource) {
|
|
|
|
commands.runCommand("drawImage", "Image Stamp", {
|
|
|
|
image: resource.image,
|
|
|
|
x,
|
|
|
|
y,
|
|
|
|
});
|
2022-11-24 21:34:34 -06:00
|
|
|
|
2022-12-02 04:22:47 -06:00
|
|
|
if (resource.temporary) {
|
|
|
|
state.deleteResource(resource.id);
|
|
|
|
}
|
2022-11-29 14:55:25 -06:00
|
|
|
}
|
2022-11-24 21:34:34 -06:00
|
|
|
|
2022-11-29 14:55:25 -06:00
|
|
|
if (state.back) {
|
|
|
|
toolbar.unlock();
|
|
|
|
const backfn = state.back;
|
|
|
|
state.back = null;
|
|
|
|
backfn({message: "Returning from stamp", pasted: true});
|
2022-11-24 21:34:34 -06:00
|
|
|
}
|
|
|
|
};
|
|
|
|
state.cancelcb = (evn) => {
|
2022-11-29 14:55:25 -06:00
|
|
|
state.selectResource(null);
|
|
|
|
|
|
|
|
if (state.back) {
|
|
|
|
toolbar.unlock();
|
|
|
|
const backfn = state.back;
|
|
|
|
state.back = null;
|
|
|
|
backfn({message: "Returning from stamp", pasted: false});
|
2022-11-24 21:34:34 -06:00
|
|
|
}
|
|
|
|
};
|
2022-11-25 10:16:22 -06:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Creates context menu
|
|
|
|
*/
|
2022-11-24 21:34:34 -06:00
|
|
|
if (!state.ctxmenu) {
|
|
|
|
state.ctxmenu = {};
|
|
|
|
// Snap To Grid Checkbox
|
|
|
|
state.ctxmenu.snapToGridLabel = _toolbar_input.checkbox(
|
|
|
|
state,
|
|
|
|
"snapToGrid",
|
|
|
|
"Snap To Grid"
|
|
|
|
).label;
|
|
|
|
|
|
|
|
// Create resource list
|
|
|
|
const uploadButtonId = `upload-btn-${guid()}`;
|
|
|
|
|
|
|
|
const resourceManager = document.createElement("div");
|
|
|
|
resourceManager.classList.add("resource-manager");
|
|
|
|
const resourceList = document.createElement("div");
|
2022-12-11 17:54:38 -06:00
|
|
|
resourceList.classList.add("list");
|
2022-11-24 21:34:34 -06:00
|
|
|
|
|
|
|
const previewPane = document.createElement("div");
|
|
|
|
previewPane.classList.add("preview-pane");
|
|
|
|
|
|
|
|
const uploadLabel = document.createElement("label");
|
|
|
|
uploadLabel.classList.add("upload-button");
|
|
|
|
uploadLabel.classList.add("button");
|
|
|
|
uploadLabel.classList.add("tool");
|
|
|
|
uploadLabel.textContent = "Upload Image";
|
|
|
|
uploadLabel.htmlFor = uploadButtonId;
|
|
|
|
const uploadButton = document.createElement("input");
|
|
|
|
uploadButton.id = uploadButtonId;
|
|
|
|
uploadButton.type = "file";
|
|
|
|
uploadButton.accept = "image/*";
|
|
|
|
uploadButton.multiple = true;
|
|
|
|
uploadButton.style.display = "none";
|
|
|
|
|
|
|
|
uploadButton.addEventListener("change", (evn) => {
|
|
|
|
[...uploadButton.files].forEach((file) => {
|
|
|
|
if (file.type.startsWith("image/")) {
|
|
|
|
console.info("Uploading Image " + file.name);
|
|
|
|
const url = window.URL || window.webkitURL;
|
|
|
|
const image = document.createElement("img");
|
|
|
|
image.src = url.createObjectURL(file);
|
|
|
|
|
2022-12-03 10:08:29 -06:00
|
|
|
image.onload = () => state.addResource(file.name, image, false);
|
2022-11-24 21:34:34 -06:00
|
|
|
}
|
|
|
|
});
|
|
|
|
uploadButton.value = null;
|
|
|
|
});
|
|
|
|
|
|
|
|
uploadLabel.appendChild(uploadButton);
|
|
|
|
resourceManager.appendChild(resourceList);
|
|
|
|
resourceManager.appendChild(uploadLabel);
|
|
|
|
resourceManager.appendChild(previewPane);
|
|
|
|
|
|
|
|
resourceManager.addEventListener(
|
|
|
|
"drop",
|
|
|
|
(evn) => {
|
|
|
|
evn.preventDefault();
|
|
|
|
resourceManager.classList.remove("dragging");
|
|
|
|
|
|
|
|
if (evn.dataTransfer.items) {
|
|
|
|
Array.from(evn.dataTransfer.items).forEach((item) => {
|
|
|
|
if (item.kind === "file" && item.type.startsWith("image/")) {
|
|
|
|
const file = item.getAsFile();
|
|
|
|
const url = window.URL || window.webkitURL;
|
|
|
|
const image = document.createElement("img");
|
|
|
|
image.src = url.createObjectURL(file);
|
|
|
|
|
|
|
|
state.addResource(file.name, image, false);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
},
|
|
|
|
{passive: false}
|
|
|
|
);
|
|
|
|
resourceManager.addEventListener(
|
|
|
|
"dragover",
|
|
|
|
(evn) => {
|
|
|
|
evn.preventDefault();
|
|
|
|
},
|
|
|
|
{passive: false}
|
|
|
|
);
|
|
|
|
|
|
|
|
resourceManager.addEventListener("dragover", (evn) => {
|
|
|
|
resourceManager.classList.add("dragging");
|
|
|
|
});
|
|
|
|
|
|
|
|
resourceManager.addEventListener("dragover", (evn) => {
|
|
|
|
resourceManager.classList.remove("dragging");
|
|
|
|
});
|
|
|
|
|
|
|
|
state.ctxmenu.uploadButton = uploadButton;
|
|
|
|
state.ctxmenu.previewPane = previewPane;
|
|
|
|
state.ctxmenu.resourceManager = resourceManager;
|
|
|
|
state.ctxmenu.resourceList = resourceList;
|
2022-12-03 07:48:05 -06:00
|
|
|
|
2022-12-12 07:03:05 -06:00
|
|
|
// Performs resource fetch from IndexedDB
|
|
|
|
|
|
|
|
IDBOpenRequest.onerror = (e) => {
|
|
|
|
console.warn("[stamp] Failed to connect to IndexedDB");
|
|
|
|
console.warn(e);
|
|
|
|
};
|
|
|
|
|
|
|
|
IDBOpenRequest.onupgradeneeded = (e) => {
|
|
|
|
const db = e.target.result;
|
|
|
|
|
|
|
|
console.debug(`[stamp] Setting up database version ${db.version}`);
|
|
|
|
|
|
|
|
const resourcesStore = db.createObjectStore("resources", {
|
|
|
|
keyPath: "id",
|
|
|
|
});
|
|
|
|
resourcesStore.createIndex("name", "name", {unique: false});
|
|
|
|
};
|
|
|
|
|
|
|
|
IDBOpenRequest.onsuccess = async (e) => {
|
|
|
|
console.debug("[stamp] Connected to IndexedDB");
|
|
|
|
|
|
|
|
state.stampDB = e.target.result;
|
|
|
|
|
|
|
|
state.stampDB.onerror = (evn) => {
|
|
|
|
console.warn(`[stamp] Database Error:`);
|
|
|
|
console.warn(evn.target.errorCode);
|
|
|
|
};
|
|
|
|
|
|
|
|
/** @type {IDBDatabase} */
|
|
|
|
const db = state.stampDB;
|
|
|
|
/** @type {IDBRequest<{id: string, name: string, src: string}[]>} */
|
|
|
|
const FetchAllTransaction = db
|
|
|
|
.transaction("resources")
|
|
|
|
.objectStore("resources")
|
|
|
|
.getAll();
|
|
|
|
|
|
|
|
FetchAllTransaction.onsuccess = async () => {
|
|
|
|
const data = FetchAllTransaction.result;
|
|
|
|
|
2022-12-03 07:48:05 -06:00
|
|
|
state.resources.push(
|
2022-12-03 19:51:31 -06:00
|
|
|
...(await Promise.all(
|
2022-12-12 07:03:05 -06:00
|
|
|
data.map((resource) => {
|
2022-12-03 19:51:31 -06:00
|
|
|
const image = document.createElement("img");
|
|
|
|
image.src = resource.src;
|
|
|
|
|
|
|
|
return new Promise((resolve, reject) => {
|
|
|
|
image.onload = () =>
|
2022-12-12 07:03:05 -06:00
|
|
|
resolve({
|
|
|
|
id: resource.id,
|
|
|
|
name: resource.name,
|
|
|
|
image,
|
|
|
|
});
|
2022-12-03 19:51:31 -06:00
|
|
|
});
|
|
|
|
})
|
|
|
|
))
|
2022-12-03 07:48:05 -06:00
|
|
|
);
|
|
|
|
syncResources();
|
2022-12-12 07:03:05 -06:00
|
|
|
};
|
|
|
|
};
|
2022-11-24 21:34:34 -06:00
|
|
|
}
|
2022-11-25 10:16:22 -06:00
|
|
|
},
|
|
|
|
populateContextMenu: (menu, state) => {
|
2022-11-24 21:34:34 -06:00
|
|
|
menu.appendChild(state.ctxmenu.snapToGridLabel);
|
|
|
|
menu.appendChild(state.ctxmenu.resourceManager);
|
|
|
|
},
|
|
|
|
shortcut: "U",
|
|
|
|
}
|
|
|
|
);
|