-
-
-
-
- {/* Share Modal (hidden by default) */}
-
Results
+Results
- + +
+
-
+ />
-
+
+
+
+
+ Job
++ #{job.id} • {job.filename} +
+
+
+
+ {isDone ? (
+
+
- Delete
+ + ) : ( + +Delete
+ + )} + + {isDone ? ( + +Tar
+ + ) : ( + +Tar
+ + )}All
| Converted File Name | -Status | -Actions | -
|---|---|---|
| - {file.output_file_name} - | -{file.status} | - -
-
- |
-
-
-
- <>
-
-
-
-
-
-
- {/* keep existing file */}
-
-
- {/* our override must also load */}
-
- >
-
- );
- },
- { auth: true },
- )
-
- .post(
- "/progress/:jobId",
- async ({ set, params, cookie: { job_id }, user }) => {
- if (job_id?.value) job_id.remove();
-
- const job = db
- .query("SELECT * FROM jobs WHERE user_id = ? AND id = ?")
- .as(Jobs)
- .get(user.id, params.jobId);
-
- if (!job) {
- set.status = 404;
- return { message: "Job not found." };
- }
-
- const outputPath = `${user.id}/${params.jobId}/`;
-
- const files = db
- .query("SELECT * FROM file_names WHERE job_id = ?")
- .as(Filename)
- .all(params.jobId);
-
- return ;
- },
- { auth: true },
- )
-
- .post(
- "/share-to-erugo/:jobId",
- async ({ params, body, user, set }) => {
- const job = db
- .query("SELECT * FROM jobs WHERE user_id = ? AND id = ?")
- .as(Jobs)
- .get(user.id, params.jobId);
-
- if (!job) {
- set.status = 404;
- return { message: "Job not found." };
- }
-
- const file = db
- .query(
- "SELECT * FROM file_names WHERE job_id = ? AND output_file_name = ?",
- )
- .as(Filename)
- .get(params.jobId, body.fileName);
-
- if (!file) {
- set.status = 404;
- return { message: "File not found." };
- }
-
- const fullPath = `${outputDir}${user.id}/${params.jobId}/${file.output_file_name}`;
-
- try {
- const payload = {
- fullPath,
- filename: file.output_file_name,
- shareName: body.shareName?.trim() || file.output_file_name,
- ...(body.description?.trim()
- ? { description: body.description.trim() }
- : {}),
- ...(body.recipientEmail?.trim()
- ? { recipientEmail: body.recipientEmail.trim() }
- : {}),
- };
-
- const result = await sendFileToErugo(payload);
- return result;
- } catch (err: any) {
- console.error(err);
- set.status = 500;
- return { message: "Failed to share with Erugo" };
- }
- },
- {
- auth: true,
- body: t.Object({
- fileName: t.String(),
- recipientEmail: t.Optional(t.String()),
- shareName: t.Optional(t.String()),
- description: t.Optional(t.String()),
- }),
- },
- );
-
-
+};
-
);
-}
-
-/**
- * IMPORTANT FIX:
- * Results HTML is re-rendered via /progress/:jobId and replaces the article + modal.
- * So we MUST NOT keep stale DOM references. We re-query elements on each action.
- */
-const shareJs = `
-(function () {
- const WEBROOT = ${JSON.stringify(WEBROOT)};
-
- function getEl(id) { return document.getElementById(id); }
-
- function getRefs() {
- return {
- modal: getEl("cxShareModal"),
- closeBtn: getEl("cxShareClose"),
- cancelBtn: getEl("cxShareCancel"),
- submitBtn: getEl("cxShareSubmit"),
- statusEl: getEl("cxShareStatus"),
- emailEl: getEl("cxShareEmail"),
- nameEl: getEl("cxShareName"),
- descEl: getEl("cxShareDescription"),
- linkBlock: getEl("cxShareLinkBlock"),
- linkEl: getEl("cxShareLink"),
- copyBtn: getEl("cxShareCopy"),
- };
- }
-
- let currentJobId = null;
- let currentFileName = null;
-
- function openModal(jobId, fileName) {
- const r = getRefs();
- if (!r.modal || !r.emailEl || !r.nameEl || !r.descEl || !r.statusEl || !r.linkBlock || !r.linkEl) {
- console.warn("[ConvertX] Share modal elements not found (DOM may be mid-refresh).");
- return;
- }
-
- currentJobId = jobId;
- currentFileName = fileName;
-
- r.nameEl.value = fileName || "";
- r.emailEl.value = "";
- r.descEl.value = "";
-
- r.linkBlock.classList.add("hidden");
- r.linkEl.value = "";
- r.statusEl.textContent = "";
-
- r.modal.classList.remove("hidden");
- r.modal.classList.add("flex");
- r.emailEl.focus();
- }
-
- function closeModal() {
- const r = getRefs();
- if (!r.modal) return;
-
- r.modal.classList.add("hidden");
- r.modal.classList.remove("flex");
- currentJobId = null;
- currentFileName = null;
- }
-
- // Delegated: always works even after /progress replaces the article
- document.addEventListener("click", (e) => {
- const t = e.target;
- const btn = t && (t.closest ? t.closest('[data-share="true"]') : null);
- if (!btn) return;
-
- // kill old handlers (e.g. alert() from older results.js)
- e.preventDefault();
- e.stopPropagation();
- if (e.stopImmediatePropagation) e.stopImmediatePropagation();
-
- const jobId = btn.getAttribute("data-job-id");
- const fileName = btn.getAttribute("data-file-name");
- openModal(jobId, fileName);
- }, true);
-
- // Delegated close (because modal DOM is replaced during progress polling)
- document.addEventListener("click", (e) => {
- const id = e.target && e.target.id;
- if (id === "cxShareClose" || id === "cxShareCancel") {
- e.preventDefault();
- closeModal();
- }
- if (id === "cxShareModal") {
- // click outside dialog closes
- closeModal();
- }
- }, true);
-
- document.addEventListener("keydown", (e) => {
- const r = getRefs();
- if (e.key === "Escape" && r.modal && !r.modal.classList.contains("hidden")) closeModal();
- });
-
- // Delegated copy
- document.addEventListener("click", async (e) => {
- const t = e.target;
- if (!t || t.id !== "cxShareCopy") return;
- e.preventDefault();
-
- const r = getRefs();
- if (!r.linkEl || !r.statusEl) return;
-
- try {
- await navigator.clipboard.writeText(r.linkEl.value || "");
- r.statusEl.textContent = "Copied.";
- } catch (err) {
- r.linkEl.focus();
- r.linkEl.select();
- r.statusEl.textContent = "Select + copy (Ctrl/Cmd+C).";
- }
- }, true);
-
- // Delegated submit
- document.addEventListener("click", async (e) => {
- const t = e.target;
- if (!t || t.id !== "cxShareSubmit") return;
- e.preventDefault();
-
- const r = getRefs();
- if (!r.submitBtn || !r.statusEl || !r.emailEl || !r.nameEl || !r.descEl || !r.linkBlock || !r.linkEl) return;
-
- if (!currentJobId || !currentFileName) return;
-
- r.submitBtn.disabled = true;
- r.submitBtn.setAttribute("aria-busy", "true");
- r.statusEl.textContent = "Sending...";
-
- try {
- const email = (r.emailEl.value || "").trim();
- const shareName = (r.nameEl.value || "").trim();
- const description = (r.descEl.value || "").trim();
-
- const payload = {
- fileName: currentFileName,
- ...(email ? { recipientEmail: email } : {}),
- ...(shareName ? { shareName } : {}),
- ...(description ? { description } : {}),
- };
-
- const res = await fetch(\`\${WEBROOT}/share-to-erugo/\${currentJobId}\`, {
- method: "POST",
- headers: { "Content-Type": "application/json" },
- body: JSON.stringify(payload),
- });
-
- const text = await res.text();
- let json;
- try { json = JSON.parse(text); } catch (_) { json = { raw: text }; }
-
- if (!res.ok) {
- console.error("[ConvertX] share-to-erugo error", res.status, json);
- r.statusEl.textContent = "Failed. See logs.";
- return;
- }
-
- const url =
- json?.share_url ||
- json?.share_link ||
- json?.data?.url ||
- json?.data?.share?.url ||
- null;
-
- if (url) {
- r.linkEl.value = url;
- r.linkBlock.classList.remove("hidden");
- }
-
- r.statusEl.textContent = email
- ? (url ? "Sent. Link also shown below." : "Sent. (No link returned.)")
- : (url ? "Created. Copy the link below." : "Created, but no link returned.");
- } catch (err) {
- console.error(err);
- r.statusEl.textContent = "Failed. See logs.";
- } finally {
- r.submitBtn.disabled = false;
- r.submitBtn.removeAttribute("aria-busy");
- }
- }, true);
-
- // Download All: delegated, because button is replaced during progress polling
- document.addEventListener("click", (e) => {
- const t = e.target;
- const btn = t && (t.closest ? t.closest("#cxDownloadAll") : null);
- if (!btn) return;
-
- e.preventDefault();
- try {
- if (typeof window.downloadAll === "function") {
- window.downloadAll();
- } else {
- console.warn("[ConvertX] downloadAll() not found. Ensure results.js is loaded.");
- }
- } catch (err) {
- console.error("[ConvertX] downloadAll() failed", err);
- }
- }, true);
-})();
-`.trim();
-
-export const results = new Elysia()
- .use(userService)
-
- .get(
- "/results-share.js",
- () =>
- new Response(shareJs, {
- headers: {
- "content-type": "text/javascript; charset=utf-8",
- "cache-control": "no-store",
- },
- }),
- { auth: true },
- )
-
- .get(
- "/results/:jobId",
- async ({ params, set, cookie: { job_id }, user }) => {
- if (job_id?.value) job_id.remove();
-
- const job = db
- .query("SELECT * FROM jobs WHERE user_id = ? AND id = ?")
- .as(Jobs)
- .get(user.id, params.jobId);
-
- if (!job) {
- set.status = 404;
- return { message: "Job not found." };
- }
-
- const outputPath = `${user.id}/${params.jobId}/`;
-
- const files = db
- .query("SELECT * FROM file_names WHERE job_id = ?")
- .as(Filename)
- .all(params.jobId);
-
- return (
-