|
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.<br><br><small>Please load new saved workflow json and double check linking and execution.</small>"); |
|
} |
|
} |
|
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; |
|
} |
|
} |
|
|