Fix Preview button in jobs sidebar not opening modal
Root cause: inline onclick with JSON.stringify(title) broke when title contained quotes, special chars, or was empty. The HTML attribute parser got confused by mismatched quotes, so click handler never fired. Fix: - Replaced inline onclick handlers with data-action attributes - Added single delegated click listener at document level - Title stored in element dataset (no HTML quoting issues) - Added escapeHtml() helper for safe rendering of titles/errors Now clicking Preview in the right sidebar opens the fullscreen modal correctly, regardless of filename characters.
This commit is contained in:
parent
90cdad516b
commit
671b512917
@ -769,19 +769,19 @@
|
||||
|
||||
const actions = [];
|
||||
if (job.status === "done") {
|
||||
actions.push(`<button class="small" onclick="window.open('/api/download/${job.id}')">⬇ Download</button>`);
|
||||
actions.push(`<button class="small ghost" onclick="previewJob('${job.id}', ${JSON.stringify(title)})">▶ Preview</button>`);
|
||||
actions.push(`<button class="small" data-action="download" data-id="${job.id}">⬇ Download</button>`);
|
||||
actions.push(`<button class="small ghost" data-action="preview" data-id="${job.id}">▶ Preview</button>`);
|
||||
}
|
||||
actions.push(`<button class="small ghost" onclick="deleteJob('${job.id}')">✕</button>`);
|
||||
actions.push(`<button class="small ghost" data-action="delete" data-id="${job.id}">✕</button>`);
|
||||
|
||||
el.innerHTML = `
|
||||
<div class="job-head">
|
||||
<div class="job-title" title="${title}">${title}</div>
|
||||
<div class="job-title" title="${escapeHtml(title)}">${escapeHtml(title)}</div>
|
||||
<span class="badge ${job.status}">${statusLabel}</span>
|
||||
</div>
|
||||
${job.current_step ? `<div class="step">${job.current_step}</div>` : ""}
|
||||
${job.current_step ? `<div class="step">${escapeHtml(job.current_step)}</div>` : ""}
|
||||
${showBar}
|
||||
${job.error ? `<div class="error-text">⚠ ${job.error}</div>` : ""}
|
||||
${job.error ? `<div class="error-text">⚠ ${escapeHtml(job.error)}</div>` : ""}
|
||||
<div class="meta">
|
||||
<span>${job.source_type === "youtube" ? "YouTube" : "Upload"}</span>
|
||||
${sizeStr ? `<span>${sizeStr}</span>` : ""}
|
||||
@ -790,9 +790,40 @@
|
||||
</div>
|
||||
<div class="actions">${actions.join("")}</div>
|
||||
`;
|
||||
// Shrani naslov za preview modal
|
||||
el.dataset.title = title;
|
||||
return el;
|
||||
}
|
||||
|
||||
function escapeHtml(s) {
|
||||
if (s == null) return "";
|
||||
return String(s)
|
||||
.replaceAll("&", "&")
|
||||
.replaceAll("<", "<")
|
||||
.replaceAll(">", ">")
|
||||
.replaceAll('"', """)
|
||||
.replaceAll("'", "'");
|
||||
}
|
||||
|
||||
// Globalno delegirano poslušanje za action gumbe (Download / Preview / Delete)
|
||||
document.addEventListener("click", (e) => {
|
||||
const btn = e.target.closest("button[data-action]");
|
||||
if (!btn) return;
|
||||
const action = btn.dataset.action;
|
||||
const id = btn.dataset.id;
|
||||
if (!id) return;
|
||||
const card = btn.closest(".job");
|
||||
const title = card?.dataset.title || "";
|
||||
|
||||
if (action === "download") {
|
||||
window.open(`/api/download/${id}`);
|
||||
} else if (action === "preview") {
|
||||
previewJob(id, title);
|
||||
} else if (action === "delete") {
|
||||
deleteJob(id);
|
||||
}
|
||||
});
|
||||
|
||||
async function deleteJob(id) {
|
||||
if (!confirm("Izbrišem ta job?")) return;
|
||||
await fetch(`/api/jobs/${id}`, { method: "DELETE" });
|
||||
|
||||
Loading…
Reference in New Issue
Block a user