import { fixBadLinks } from "../common/link_fixer.js";
import { getPngMetadata } from "../../scripts/pnginfo.js";
function wait(ms = 16, value) {
return new Promise((resolve) => {
setTimeout(() => {
resolve(value);
}, ms);
});
}
const logger = {
logTo: console,
log: (...args) => {
logger.logTo === console
? console.log(...args)
: (logger.logTo.innerText += args.join(",") + "\n");
},
};
const findBadLinksLogger = {
log: async (...args) => {
logger.log(...args);
},
};
export class LinkPage {
constructor() {
this.containerEl = document.querySelector(".box");
this.figcaptionEl = document.querySelector("figcaption");
this.outputeMessageEl = document.querySelector(".output");
this.outputImageEl = document.querySelector(".output-image");
this.btnFix = document.querySelector(".btn-fix");
document.addEventListener("dragover", (e) => {
e.preventDefault();
}, false);
document.addEventListener("drop", (e) => {
this.onDrop(e);
});
this.btnFix.addEventListener("click", (e) => {
this.onFixClick(e);
});
}
async onFixClick(e) {
if (!this.graphResults || !this.graph) {
this.updateUi("⛔ Fix button click without results.");
return;
}
let graphFinalResults = fixBadLinks(this.graph, true);
graphFinalResults = fixBadLinks(graphFinalResults.graph, true);
if (graphFinalResults.patched || graphFinalResults.deleted) {
graphFinalResults = fixBadLinks(graphFinalResults.graph, true);
}
this.graphFinalResults = graphFinalResults;
await this.saveFixedWorkflow();
if (graphFinalResults.hasBadLinks) {
this.updateUi("⛔ Hmm... Still detecting bad links. Can you file an issue at https://github.com/rgthree/rgthree-comfy/issues with your image/workflow.");
}
else {
this.updateUi("✅ Workflow fixed.
Please load new saved workflow json and double check linking and execution.");
}
}
async onDrop(event) {
var _a, _b, _c, _d;
if (!event.dataTransfer) {
return;
}
this.reset();
event.preventDefault();
event.stopPropagation();
if (event.dataTransfer.files.length && ((_b = (_a = event.dataTransfer.files) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.type) !== "image/bmp") {
await this.handleFile(event.dataTransfer.files[0]);
return;
}
const validTypes = ["text/uri-list", "text/x-moz-url"];
const match = [...event.dataTransfer.types].find((t) => validTypes.find((v) => t === v));
if (match) {
const uri = (_d = (_c = event.dataTransfer.getData(match)) === null || _c === void 0 ? void 0 : _c.split("\n")) === null || _d === void 0 ? void 0 : _d[0];
if (uri) {
await this.handleFile(await (await fetch(uri)).blob());
}
}
}
reset() {
this.file = undefined;
this.graph = undefined;
this.graphResults = undefined;
this.graphFinalResults = undefined;
this.updateUi();
}
updateUi(msg) {
this.outputeMessageEl.innerHTML = "";
if (this.file && !this.containerEl.classList.contains("-has-file")) {
this.containerEl.classList.add("-has-file");
this.figcaptionEl.innerHTML = this.file.name || this.file.type;
if (this.file.type === "application/json") {
this.outputImageEl.src = "icon_file_json.png";
}
else {
const reader = new FileReader();
reader.onload = () => (this.outputImageEl.src = reader.result);
reader.readAsDataURL(this.file);
}
}
else if (!this.file && this.containerEl.classList.contains("-has-file")) {
this.containerEl.classList.remove("-has-file");
this.outputImageEl.src = "";
this.outputImageEl.removeAttribute("src");
}
if (this.graphResults) {
this.containerEl.classList.add("-has-results");
if (!this.graphResults.patched && !this.graphResults.deleted) {
this.outputeMessageEl.innerHTML = "✅ No bad links detected in the workflow.";
}
else {
this.containerEl.classList.add("-has-fixable-results");
this.outputeMessageEl.innerHTML = `⚠️ Found ${this.graphResults.patched} links to fix, and ${this.graphResults.deleted} to be removed.`;
}
}
else {
this.containerEl.classList.remove("-has-results");
this.containerEl.classList.remove("-has-fixable-results");
}
if (msg) {
this.outputeMessageEl.innerHTML = msg;
}
}
async handleFile(file) {
this.file = file;
this.updateUi();
let workflow = null;
if (file.type.startsWith("image/")) {
const pngInfo = await getPngMetadata(file);
workflow = pngInfo === null || pngInfo === void 0 ? void 0 : pngInfo.workflow;
}
else if (file.type === "application/json" ||
(file instanceof File && file.name.endsWith(".json"))) {
workflow = await new Promise((resolve) => {
const reader = new FileReader();
reader.onload = () => {
resolve(reader.result);
};
reader.readAsText(file);
});
}
if (!workflow) {
this.updateUi("⛔ No workflow found in dropped item.");
}
else {
try {
this.graph = JSON.parse(workflow);
}
catch (e) {
this.graph = undefined;
}
if (!this.graph) {
this.updateUi("⛔ Invalid workflow found in dropped item.");
}
else {
this.loadGraphData(this.graph);
}
}
}
async loadGraphData(graphData) {
this.graphResults = await fixBadLinks(graphData);
this.updateUi();
}
async saveFixedWorkflow() {
if (!this.graphFinalResults) {
this.updateUi("⛔ Save w/o final graph patched.");
return false;
}
let filename = this.file.name || "workflow.json";
let filenames = filename.split(".");
filenames.pop();
filename = filenames.join(".");
filename += "_fixed.json";
filename = prompt("Save workflow as:", filename);
if (!filename)
return false;
if (!filename.toLowerCase().endsWith(".json")) {
filename += ".json";
}
const json = JSON.stringify(this.graphFinalResults.graph, null, 2);
const blob = new Blob([json], { type: "application/json" });
const url = URL.createObjectURL(blob);
const anchor = document.createElement("a");
anchor.download = filename;
anchor.href = url;
anchor.style.display = "none";
document.body.appendChild(anchor);
await wait();
anchor.click();
await wait();
anchor.remove();
window.URL.revokeObjectURL(url);
return true;
}
}